Support JSON-configured per-offer entitlement seeding
This commit is contained in:
parent
16a1c5836c
commit
7300612b71
@ -59,6 +59,11 @@ Copy `.env.example` values into your shell/session before deploy:
|
||||
9. `PAYMENT_TOKEN_ADDRESS`
|
||||
10. `OFFER_PRICE_ATOMIC`
|
||||
11. `ENTITLEMENT_DEPLOY_OUTPUT_PATH` (optional)
|
||||
12. `OFFERS_JSON` (optional path to per-offer seed config JSON)
|
||||
13. `OFFERS_INLINE_JSON` (optional inline JSON array alternative to `OFFERS_JSON`)
|
||||
|
||||
If no offer override JSON is provided, deploy script seeds default offers at `OFFER_PRICE_ATOMIC`.
|
||||
Use `deploy/offers.template.json` to define per-offer prices and policy flags.
|
||||
|
||||
Example (Sepolia):
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@ Template:
|
||||
|
||||
- `membership-deploy.template.json`
|
||||
- `entitlement-deploy.template.json`
|
||||
- `offers.template.json`
|
||||
|
||||
Recommended process:
|
||||
|
||||
@ -19,3 +20,4 @@ Recommended process:
|
||||
`npm run deploy:entitlement:sepolia` / `npm run deploy:entitlement:mainnet` for offer entitlements.
|
||||
2. Copy the matching template to a dated file (for example `membership-base-sepolia-2026-02-18.json`).
|
||||
3. Fill all deployment fields from script output and explorer links.
|
||||
4. If you need per-offer pricing, copy `offers.template.json`, edit values, and pass it via `OFFERS_JSON=/path/to/file.json`.
|
||||
|
||||
32
deploy/offers.template.json
Normal file
32
deploy/offers.template.json
Normal file
@ -0,0 +1,32 @@
|
||||
[
|
||||
{
|
||||
"offer_id": "edut.solo.core",
|
||||
"price_atomic": "1000000000",
|
||||
"active": true,
|
||||
"membership_required": true
|
||||
},
|
||||
{
|
||||
"offer_id": "edut.workspace.core",
|
||||
"price_atomic": "1000000000",
|
||||
"active": true,
|
||||
"membership_required": true
|
||||
},
|
||||
{
|
||||
"offer_id": "edut.workspace.ai",
|
||||
"price_atomic": "1000000000",
|
||||
"active": true,
|
||||
"membership_required": true
|
||||
},
|
||||
{
|
||||
"offer_id": "edut.workspace.lane24",
|
||||
"price_atomic": "1000000000",
|
||||
"active": true,
|
||||
"membership_required": true
|
||||
},
|
||||
{
|
||||
"offer_id": "edut.workspace.sovereign",
|
||||
"price_atomic": "1000000000",
|
||||
"active": true,
|
||||
"membership_required": true
|
||||
}
|
||||
]
|
||||
@ -40,6 +40,62 @@ function parseUint(name, value) {
|
||||
}
|
||||
}
|
||||
|
||||
function readOfferOverrides() {
|
||||
const inlineRaw = (process.env.OFFERS_INLINE_JSON || "").trim();
|
||||
if (inlineRaw) {
|
||||
try {
|
||||
return JSON.parse(inlineRaw);
|
||||
} catch (err) {
|
||||
throw new Error(`Invalid OFFERS_INLINE_JSON (${err.message})`);
|
||||
}
|
||||
}
|
||||
|
||||
const filePath = (process.env.OFFERS_JSON || "").trim();
|
||||
if (!filePath) {
|
||||
return null;
|
||||
}
|
||||
const absolute = path.resolve(filePath);
|
||||
const raw = fs.readFileSync(absolute, "utf8");
|
||||
try {
|
||||
return JSON.parse(raw);
|
||||
} catch (err) {
|
||||
throw new Error(`Invalid OFFERS_JSON at ${absolute} (${err.message})`);
|
||||
}
|
||||
}
|
||||
|
||||
function buildOfferPlan(defaultPriceAtomic) {
|
||||
const overrides = readOfferOverrides();
|
||||
if (!overrides) {
|
||||
return DEFAULT_OFFERS.map((offerID) => ({
|
||||
offerID,
|
||||
priceAtomic: defaultPriceAtomic,
|
||||
active: true,
|
||||
membershipRequired: true,
|
||||
}));
|
||||
}
|
||||
if (!Array.isArray(overrides) || overrides.length === 0) {
|
||||
throw new Error("Offer override list must be a non-empty JSON array");
|
||||
}
|
||||
|
||||
return overrides.map((entry, index) => {
|
||||
if (!entry || typeof entry !== "object") {
|
||||
throw new Error(`Offer override at index ${index} must be an object`);
|
||||
}
|
||||
const offerID = String(entry.offer_id || "").trim();
|
||||
if (!offerID) {
|
||||
throw new Error(`Offer override at index ${index} missing offer_id`);
|
||||
}
|
||||
const rawPrice = String(
|
||||
entry.price_atomic !== undefined ? entry.price_atomic : defaultPriceAtomic.toString()
|
||||
).trim();
|
||||
const priceAtomic = parseUint(`offer[${offerID}].price_atomic`, rawPrice);
|
||||
const active = entry.active !== undefined ? Boolean(entry.active) : true;
|
||||
const membershipRequired =
|
||||
entry.membership_required !== undefined ? Boolean(entry.membership_required) : true;
|
||||
return { offerID, priceAtomic, active, membershipRequired };
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const treasury = requireAddress(
|
||||
"ENTITLEMENT_TREASURY_WALLET",
|
||||
@ -72,12 +128,31 @@ async function main() {
|
||||
await contract.deployed();
|
||||
console.log("entitlement_contract:", contract.address);
|
||||
|
||||
const offerPlan = buildOfferPlan(offerPriceAtomic);
|
||||
const seededOffers = [];
|
||||
for (const offerID of DEFAULT_OFFERS) {
|
||||
const tx = await contract.upsertOffer(offerID, offerPriceAtomic, true, true);
|
||||
for (const offer of offerPlan) {
|
||||
const tx = await contract.upsertOffer(
|
||||
offer.offerID,
|
||||
offer.priceAtomic,
|
||||
offer.active,
|
||||
offer.membershipRequired
|
||||
);
|
||||
const receipt = await tx.wait();
|
||||
seededOffers.push({ offerID, txHash: receipt.transactionHash });
|
||||
console.log("offer_seeded:", offerID, receipt.transactionHash);
|
||||
seededOffers.push({
|
||||
offerID: offer.offerID,
|
||||
priceAtomic: offer.priceAtomic.toString(),
|
||||
active: offer.active,
|
||||
membershipRequired: offer.membershipRequired,
|
||||
txHash: receipt.transactionHash,
|
||||
});
|
||||
console.log(
|
||||
"offer_seeded:",
|
||||
offer.offerID,
|
||||
offer.priceAtomic.toString(),
|
||||
offer.active,
|
||||
offer.membershipRequired,
|
||||
receipt.transactionHash
|
||||
);
|
||||
}
|
||||
|
||||
const output = {
|
||||
@ -88,6 +163,7 @@ async function main() {
|
||||
paymentToken,
|
||||
membershipContract,
|
||||
offerPriceAtomic: offerPriceAtomic.toString(),
|
||||
defaultOfferPriceAtomic: offerPriceAtomic.toString(),
|
||||
entitlementContract: contract.address,
|
||||
txHash: contract.deployTransaction.hash,
|
||||
seededOffers,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user