feat: add guarded Base Sepolia encore

This commit is contained in:
golem
2026-08-21 16:01:35 -06:00
parent 94f2ad6e09
commit 90b0a11b8a
16 changed files with 784 additions and 25 deletions
+15 -3
View File
@@ -137,6 +137,8 @@ export async function finalizeUpgrade({ root = process.cwd(), rpc }) {
if (matching.length !== 1) throw new Error(`expected exactly one live upgrade transaction to proxy, found ${matching.length}`);
const receipt = await rpc("eth_getTransactionReceipt", [matching[0].hash]);
if (!receipt || !isSuccessfulReceipt(receipt.status)) throw new Error("upgrade receipt was not successful");
const upgradeBlock = parseRpcQuantity(receipt.blockNumber, "upgrade receipt block number");
if (upgradeBlock === 0) throw new Error("upgrade receipt block number must be nonzero");
if (!Array.isArray(receipt.logs) || !receipt.logs.some((log) => isUpgradeLog(log, active.proxy, pending.implementation))) {
throw new Error("successful upgrade receipt is missing the expected Upgraded event");
}
@@ -148,7 +150,7 @@ export async function finalizeUpgrade({ root = process.cwd(), rpc }) {
await atomicWriteJson(canonicalPath, updated);
await atomicWriteJson(activePath, updated);
await rm(pendingPath);
return { mode: "upgrade", path: canonicalPath, manifest: updated };
return { mode: "upgrade", path: canonicalPath, manifest: updated, upgradeBlock };
}
function validateNoopMarker(marker, active) {
@@ -377,6 +379,11 @@ function assertPublicUrl(value, field) {
if ((url.protocol !== "https:" && url.protocol !== "http:") || url.username || url.password) {
throw new Error(`manifest ${field} must be a public URL without credentials`);
}
for (const key of url.searchParams.keys()) {
if (/(key|token|secret|password|credential)/i.test(key)) {
throw new Error(`manifest ${field} must not contain credential query parameters`);
}
}
}
function assertActorConfiguration(manifest) {
@@ -390,8 +397,13 @@ function assertActorConfiguration(manifest) {
if (actors.length !== expected.length || actors.some((actor, index) => actor.label !== expected[index][0] || actor.address.toLowerCase() !== expected[index][1].toLowerCase())) {
throw new Error("manifest anvil actors must match the documented local actor configuration");
}
} else if (actors.length !== 1 || actors[0].label !== "owner") {
throw new Error("manifest baseSepolia must contain only the owner actor");
} else {
const configured = actors.length === 2 && actors[0].label === "Presenter" && actors[1].label === "Recipient";
const legacy = actors.length === 1 && actors[0].label === "owner"
&& !Object.hasOwn(manifest, "rpcUrl") && !Object.hasOwn(manifest, "explorerBaseUrl");
if (!configured && !legacy) {
throw new Error("manifest baseSepolia actors must be Presenter and Recipient");
}
}
if (actors[0].address.toLowerCase() !== owner.toLowerCase()) throw new Error("manifest owner must be actor zero");
}