Skip to content

Commit 19bccc9

Browse files
committed
fix: resolve ens addresses before initializing contract
1 parent efbb7f5 commit 19bccc9

4 files changed

Lines changed: 54 additions & 16 deletions

File tree

src/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import "dotenv/config";
22
import { handleUplinks } from "./services/mqtt";
33
import { Request, Response } from "express";
4-
import { app } from "./services/context";
4+
import { app, contractsReady } from "./services/context";
55
import {
66
loadExtensionsFromConfig,
77
loadUIExtensionsFromConfig,
@@ -24,6 +24,9 @@ async function initializeApp() {
2424
await loadUIExtensionsFromConfig();
2525
console.log("[info] UI extensions loaded successfully");
2626

27+
await contractsReady;
28+
console.log("[info] resolved contract addresses");
29+
2730
runHook("onBeforeInit");
2831

2932
// Initialize database tables and jobs

src/lib/sync.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
import {
1010
provider,
1111
rollup as rollupContract,
12+
contractsReady,
1213
ccipRevenueReader as ccipRevenueReaderContract,
1314
priceContext as priceContextContract,
1415
} from "../services/context";
@@ -101,6 +102,8 @@ export function getCachedVerifiersCount(): number {
101102
}
102103

103104
export async function pruneAndSyncOnchain(meterIdentifier: number | string): Promise<number> {
105+
await contractsReady;
106+
104107
const meter =
105108
typeof meterIdentifier === "number" ? getMeterByTokenId(meterIdentifier) : getMeterByPublicKey(meterIdentifier);
106109

@@ -124,6 +127,8 @@ export async function pruneAndSyncOnchain(meterIdentifier: number | string): Pro
124127
}
125128

126129
export async function getLatestTransactionNonce(meterIdentifier: number): Promise<number> {
130+
await contractsReady;
131+
127132
// get latest nonce from chain
128133
let latestNonce = Number(await rollupContract.nonce(meterIdentifier));
129134

src/services/context.ts

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -126,19 +126,47 @@ server.listen(port, () => {
126126
console.log("[info] Starting application initialization...");
127127

128128
// ETHERS JS CONTRACT CONFIG
129-
export const provider = new JsonRpcProvider(process.env.MAINNET_RPC, undefined, { staticNetwork: true });
130-
131-
export const m3ter = new Contract(
132-
process.env.M3TER_CONTRACT_ADDRESS || "heads.m3ter.eth",
133-
["function publicKey(uint256) view returns (bytes32)", "function tokenID(bytes32) view returns (uint256)"],
134-
provider,
135-
);
136-
137-
export const rollup = new Contract(
138-
process.env.ROLLUP_CONTRACT_ADDRESS || "rollup.m3ter.eth",
139-
["function nonce(uint256) external view returns (bytes6)"],
140-
provider,
141-
);
129+
const rpcUrl = process.env.MAINNET_RPC;
130+
console.log("[info] using RPC", rpcUrl)
131+
export const provider = new JsonRpcProvider(rpcUrl);
132+
133+
const m3terRef = process.env.M3TER_CONTRACT_ADDRESS || "heads.m3ter.eth";
134+
const rollupRef = process.env.ROLLUP_CONTRACT_ADDRESS || "rollup.m3ter.eth";
135+
136+
const m3terAbi = ["function publicKey(uint256) view returns (bytes32)", "function tokenID(bytes32) view returns (uint256)"];
137+
const rollupAbi = ["function nonce(uint256) external view returns (bytes6)"];
138+
139+
function isHexAddress(value: string): boolean {
140+
return /^0x[a-fA-F0-9]{40}$/.test(value);
141+
}
142+
143+
async function resolveContractAddress(contractName: string, ref: string): Promise<string> {
144+
if (isHexAddress(ref)) {
145+
console.log(`[ethers] ${contractName}: using address ${ref}`);
146+
return ref;
147+
}
148+
149+
const resolved = await provider.resolveName(ref);
150+
if (!resolved) {
151+
throw new Error(`[ethers] ${contractName}: failed to resolve ENS ${ref}`);
152+
}
153+
154+
console.log(`[ethers] ${contractName}: resolved ENS ${ref} -> ${resolved}`);
155+
return resolved;
156+
}
157+
158+
export let m3ter!: Contract;
159+
export let rollup!: Contract;
160+
161+
export const contractsReady = (async () => {
162+
const [m3terAddress, rollupAddress] = await Promise.all([
163+
resolveContractAddress("m3ter", m3terRef),
164+
resolveContractAddress("rollup", rollupRef),
165+
]);
166+
167+
m3ter = new Contract(m3terAddress, m3terAbi, provider);
168+
rollup = new Contract(rollupAddress, rollupAbi, provider);
169+
})();
142170

143171
export const ccipRevenueReader = new Contract(
144172
process.env.CCIP_REVENUE_READER_ADDRESS || "0xD648cdF47e9534B2FCfb18C1E94CA9AAff07BA0E",

src/services/mqtt.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { connect } from "mqtt";
22
import { enqueue } from "./grpc";
33
import { encode } from "../lib/encode";
4-
import { app, m3ter as m3terContract } from "./context";
4+
import { app, m3ter as m3terContract, contractsReady } from "./context";
55
import {
66
deleteMeterByPublicKey,
77
getAllTransactionRecords,
@@ -27,7 +27,9 @@ import { createMeterLogger } from "../utils/logger";
2727
const CHIRPSTACK_HOST = process.env.CHIRPSTACK_HOST;
2828
const deviceLocks = new Map<string, boolean>(); // Lock per devEUI to prevent concurrent message processing
2929

30-
export function handleUplinks(): Promise<boolean> {
30+
export async function handleUplinks(): Promise<boolean> {
31+
await contractsReady;
32+
3133
return new Promise(function (resolve, reject) {
3234
const client = connect({
3335
host: CHIRPSTACK_HOST,

0 commit comments

Comments
 (0)