contracts/scripts/verify-offer-config-readback.cjs
Joshua 60d7cbc5e1
Some checks are pending
check / contracts (push) Waiting to run
Add deploy artifact validators and offer readback verification
2026-02-19 12:59:08 -08:00

147 lines
4.3 KiB
JavaScript

const fs = require("fs");
const path = require("path");
const { ethers } = require("ethers");
const DEFAULT_OFFERS_PATH = path.resolve(__dirname, "../deploy/offers.template.json");
const DEFAULT_RUNTIME_PATH = path.resolve(__dirname, "../deploy/runtime-addresses.base-sepolia.json");
const DEFAULT_ENTITLEMENT_PATH = path.resolve(__dirname, "../deploy/entitlement-deploy.sepolia.json");
const OFFER_ABI = [
"function offerConfig(string offerId) view returns (uint256 priceAtomic, bool active, bool membershipRequired, bool exists)",
];
function required(name, value) {
if (!String(value || "").trim()) {
throw new Error(`missing required env: ${name}`);
}
return String(value).trim();
}
function readJSON(filePath) {
return JSON.parse(fs.readFileSync(filePath, "utf8"));
}
function resolveEntitlementAddress() {
const envAddress = String(process.env.ENTITLEMENT_CONTRACT_ADDRESS || "").trim();
if (envAddress) {
return envAddress;
}
if (fs.existsSync(DEFAULT_RUNTIME_PATH)) {
const runtime = readJSON(DEFAULT_RUNTIME_PATH);
if (runtime.entitlement_contract) {
return String(runtime.entitlement_contract).trim();
}
}
if (fs.existsSync(DEFAULT_ENTITLEMENT_PATH)) {
const deploy = readJSON(DEFAULT_ENTITLEMENT_PATH);
if (deploy.entitlementContract) {
return String(deploy.entitlementContract).trim();
}
}
return "";
}
function loadExpectedOffers() {
const offersPath = String(process.env.OFFERS_JSON || "").trim() || DEFAULT_OFFERS_PATH;
if (!fs.existsSync(offersPath)) {
throw new Error(`offers file missing: ${offersPath}`);
}
const raw = readJSON(offersPath);
if (!Array.isArray(raw) || raw.length === 0) {
throw new Error("offers json must be a non-empty array");
}
return raw.map((entry, idx) => {
if (!entry || typeof entry !== "object") {
throw new Error(`offers[${idx}] must be an object`);
}
const offerId = String(entry.offer_id || "").trim();
if (!offerId) {
throw new Error(`offers[${idx}] missing offer_id`);
}
const priceAtomic = String(entry.price_atomic || "").trim();
if (!/^[0-9]+$/.test(priceAtomic)) {
throw new Error(`offers[${offerId}] invalid price_atomic`);
}
return {
offerId,
priceAtomic,
active: entry.active === undefined ? true : Boolean(entry.active),
membershipRequired:
entry.membership_required === undefined ? true : Boolean(entry.membership_required),
};
});
}
async function main() {
const rpcURL = required("BASE_SEPOLIA_RPC_URL", process.env.BASE_SEPOLIA_RPC_URL);
const entitlementAddress = resolveEntitlementAddress();
if (!ethers.utils.isAddress(entitlementAddress)) {
throw new Error(`invalid/missing entitlement contract address: ${entitlementAddress}`);
}
const expectedOffers = loadExpectedOffers();
const provider = new ethers.providers.JsonRpcProvider(rpcURL);
const contract = new ethers.Contract(entitlementAddress, OFFER_ABI, provider);
const mismatches = [];
for (const offer of expectedOffers) {
const cfg = await contract.offerConfig(offer.offerId);
const got = {
exists: Boolean(cfg.exists),
priceAtomic: cfg.priceAtomic.toString(),
active: Boolean(cfg.active),
membershipRequired: Boolean(cfg.membershipRequired),
};
const expected = {
exists: true,
priceAtomic: offer.priceAtomic,
active: offer.active,
membershipRequired: offer.membershipRequired,
};
const match =
got.exists === expected.exists &&
got.priceAtomic === expected.priceAtomic &&
got.active === expected.active &&
got.membershipRequired === expected.membershipRequired;
if (!match) {
mismatches.push({
offer_id: offer.offerId,
expected,
got,
});
}
}
if (mismatches.length > 0) {
console.error(
JSON.stringify(
{
status: "FAIL",
entitlement_contract: entitlementAddress,
mismatches,
},
null,
2
)
);
process.exit(1);
}
console.log(
JSON.stringify(
{
status: "PASS",
entitlement_contract: entitlementAddress,
offers_checked: expectedOffers.length,
},
null,
2
)
);
}
main().catch((err) => {
console.error(`FAIL: ${err.message || err}`);
process.exit(1);
});