Skip to content

Commit 7eb6a94

Browse files
authored
Fix snap Hardhat tasks (#2954)
* fix(tasks): restore staking snapshots and fork-aware beacon decoding * Fix resolving OUSD and OETH symbols in HH tasks
1 parent d248009 commit 7eb6a94

5 files changed

Lines changed: 71 additions & 28 deletions

File tree

contracts/tasks/lib/contracts.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,10 @@ function readDeployment(
5858
// Resolve an ABI by contract/interface name: curated abi/<name>.json first
5959
// (interfaces like IVault), then the deployment artifact's abi.
6060
function readAbiByName(chainId: number, name: string): unknown[] {
61-
const curated = join(CONTRACTS_ROOT, "abi", `${name}.json`);
61+
// IERC20Metadata is a strict superset of IERC20 and is the curated ERC-20
62+
// interface shipped with the standalone actions image.
63+
const curatedName = name === "IERC20" ? "IERC20Metadata" : name;
64+
const curated = join(CONTRACTS_ROOT, "abi", `${curatedName}.json`);
6265
if (existsSync(curated)) return JSON.parse(readFileSync(curated, "utf8"));
6366
const dep = join(
6467
CONTRACTS_ROOT,

contracts/tasks/lib/network.ts

Lines changed: 57 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { ethers } from "ethers";
2-
import { resolveChain, getRpcEnvVar } from "@oplabs/talos-client";
32

43
/**
54
* Ambient network context for the standalone (hardhat-free) action runtime.
@@ -19,36 +18,71 @@ export const CHAIN_NAMES: Record<number, string> = {
1918
98866: "plume",
2019
};
2120

21+
const CHAIN_IDS: Record<string, number> = Object.fromEntries(
22+
Object.entries(CHAIN_NAMES).map(([id, name]) => [name, Number(id)])
23+
);
24+
25+
const RPC_ENV_VARS: Record<number, string> = {
26+
1: "MAINNET_PROVIDER_URL",
27+
8453: "BASE_PROVIDER_URL",
28+
146: "SONIC_PROVIDER_URL",
29+
560048: "HOODI_PROVIDER_URL",
30+
999: "HYPEREVM_PROVIDER_URL",
31+
17000: "HOLESKY_PROVIDER_URL",
32+
42161: "ARBITRUM_PROVIDER_URL",
33+
98866: "PLUME_PROVIDER_URL",
34+
};
35+
2236
let _chainId: number | undefined;
2337
let _networkName: string | undefined;
2438
let _provider: ethers.providers.JsonRpcProvider | undefined;
2539
let _signer: ethers.Signer | undefined;
2640

41+
type HardhatGlobal = {
42+
hre?: {
43+
ethers?: { provider?: ethers.providers.JsonRpcProvider };
44+
network?: { name?: string; config?: { chainId?: number } };
45+
};
46+
};
47+
48+
function hardhatRuntime() {
49+
return (globalThis as typeof globalThis & HardhatGlobal).hre;
50+
}
51+
2752
/** Resolve the RPC URL for a chain: LOCAL_PROVIDER_URL on a fork, else the
28-
* `*_PROVIDER_URL` env var (via Talos getRpcEnvVar, matching the repo's names). */
53+
* matching `*_PROVIDER_URL` env var. */
2954
export function rpcUrlFor(nameOrId: string | number): {
3055
chainId: number;
3156
networkName: string;
3257
url: string;
3358
} {
34-
const chain = resolveChain(nameOrId);
59+
const chainId =
60+
typeof nameOrId === "number"
61+
? nameOrId
62+
: /^\d+$/.test(nameOrId)
63+
? Number(nameOrId)
64+
: CHAIN_IDS[nameOrId.toLowerCase()];
65+
const networkName = CHAIN_NAMES[chainId];
66+
if (!networkName) {
67+
throw new Error(`Unsupported chain: ${nameOrId}`);
68+
}
3569
let url: string | undefined;
3670
if (process.env.FORK === "true" && process.env.LOCAL_PROVIDER_URL) {
3771
url = process.env.LOCAL_PROVIDER_URL;
3872
} else {
39-
const envVar = getRpcEnvVar(chain);
73+
const envVar = RPC_ENV_VARS[chainId];
4074
url = process.env[envVar];
4175
// Back-compat: mainnet historically used the bare PROVIDER_URL.
42-
if (!url && chain.id === 1) url = process.env.PROVIDER_URL;
76+
if (!url && chainId === 1) url = process.env.PROVIDER_URL;
4377
if (!url) {
4478
throw new Error(
45-
`Missing RPC URL env var ${envVar} for chain ${chain.name} (${chain.id})`
79+
`Missing RPC URL env var ${envVar} for chain ${networkName} (${chainId})`
4680
);
4781
}
4882
}
4983
return {
50-
chainId: chain.id,
51-
networkName: CHAIN_NAMES[chain.id] ?? chain.name,
84+
chainId,
85+
networkName,
5286
url,
5387
};
5488
}
@@ -69,19 +103,28 @@ export function initNetwork(nameOrId: string | number): {
69103
}
70104

71105
export function getProvider(): ethers.providers.JsonRpcProvider {
72-
if (!_provider)
106+
const provider = _provider ?? hardhatRuntime()?.ethers?.provider;
107+
if (!provider)
73108
throw new Error("Network not initialized — call initNetwork() first");
74-
return _provider;
109+
return provider;
75110
}
76111

77112
export function getChainId(): number {
78-
if (_chainId == null) throw new Error("Network not initialized");
79-
return _chainId;
113+
const hardhatNetwork = hardhatRuntime()?.network;
114+
const chainId =
115+
_chainId ??
116+
hardhatNetwork?.config?.chainId ??
117+
(hardhatNetwork?.name
118+
? CHAIN_IDS[hardhatNetwork.name.toLowerCase()]
119+
: undefined);
120+
if (chainId == null) throw new Error("Network not initialized");
121+
return chainId;
80122
}
81123

82124
export function getNetworkName(): string {
83-
if (!_networkName) throw new Error("Network not initialized");
84-
return _networkName;
125+
const networkName = _networkName ?? hardhatRuntime()?.network?.name;
126+
if (!networkName) throw new Error("Network not initialized");
127+
return networkName;
85128
}
86129

87130
export function setSigner(signer: ethers.Signer): void {

contracts/tasks/tasks.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1534,8 +1534,7 @@ subtask(
15341534
types.int
15351535
)
15361536
.setAction(async (taskArgs) => {
1537-
const signer = await getSigner();
1538-
await snapStaking({ ...taskArgs, signer });
1537+
await snapStaking(taskArgs);
15391538
});
15401539
task("snapStaking").setAction(async (_, __, runSuper) => {
15411540
return runSuper();

contracts/tasks/vault.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,13 @@ async function getContracts(hre, symbol, assetSymbol) {
1313
const networkName = await getNetworkName();
1414

1515
// If no symbol is provided, set to OSonic if Sonic network, else default to OETH
16-
symbol = symbol ? symbol : networkName === "sonic" ? "OSonic" : "OETH";
16+
symbol = symbol
17+
? symbol.toUpperCase()
18+
: networkName === "sonic"
19+
? "OSonic"
20+
: "OETH";
1721
// Convert OS to OSonic
18-
symbol = symbol === "OS" ? "OSonic" : symbol;
22+
symbol = symbol === "OS" || symbol === "OSONIC" ? "OSonic" : symbol;
1923
const contractPrefix = symbol === "OUSD" ? "" : symbol;
2024

2125
const networkPrefix = networkName === "base" ? "Base" : "";

contracts/utils/beacon.js

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -133,15 +133,6 @@ const getBeaconBlock = async (slot = "head", networkName = "mainnet") => {
133133
const client = await configClient();
134134

135135
const { ssz } = await import("@lodestar/types");
136-
// Mainnet fixed-slot proof generation currently decodes against Electra-era beacon data.
137-
const BeaconBlock =
138-
networkName === "mainnet"
139-
? ssz.electra.BeaconBlock
140-
: ssz.electra.BeaconBlock;
141-
const BeaconState =
142-
networkName === "mainnet"
143-
? ssz.electra.BeaconState
144-
: ssz.electra.BeaconState;
145136

146137
// Get the beacon block for the slot from the beacon node.
147138
log(`Fetching block for slot ${slot} from the beacon node`);
@@ -153,6 +144,9 @@ const getBeaconBlock = async (slot = "head", networkName = "mainnet") => {
153144
);
154145
}
155146

147+
const fork = blockRes.meta().version;
148+
const BeaconBlock = ssz[fork].BeaconBlock;
149+
const BeaconState = ssz[fork].BeaconState;
156150
const blockView = BeaconBlock.toView(blockRes.value().message);
157151

158152
const stateFilename = `./cache/state_${blockView.slot}.ssz`;

0 commit comments

Comments
 (0)