zonder
Version:
Ergonomic multi-chain indexing framework with dual runtime support for Ponder and Envio.
91 lines (90 loc) • 2.99 kB
JavaScript
import { factory } from 'ponder';
import { resolveStartBlock } from '../zonder/resolveStartBlock.js';
export function buildChains(chains) {
return Object.fromEntries(Object.entries(chains).map(([chainName, chain]) => {
const rpcKey = `PONDER_RPC_URL_${chain.id}`;
const rpcValue = process.env[rpcKey];
if (!rpcValue) {
throw new Error(`${rpcKey} is not set`);
}
const rpc = rpcValue.split(',');
if (rpc.length === 0) {
throw new Error(`${rpcKey} is empty`);
}
rpc.forEach((r) => {
try {
new URL(r);
}
catch (e) {
throw new Error(`${rpcKey} contains invalid URL: "${r}"`);
}
});
return [
chainName,
{
id: chain.id,
rpc,
},
];
}));
}
export function buildContractChainAddressConfig(config, chainName, contract) {
const { factoryDeployed, addresses } = config;
const address = addresses[chainName][contract];
const factoryConfig = factoryDeployed?.[contract];
if (!!address && !!factoryConfig) {
throw new Error(`Contract ${String(contract)} is configured both as a singleton and a factory on chain ${String(chainName)}`);
}
if (address) {
return { address };
}
if (factoryConfig) {
const { event, parameter, deployedBy } = factoryConfig;
const factoryAddress = addresses[chainName][deployedBy];
if (!factoryAddress) {
// Factory not configured on this chain - factory-deployed contract can't exist here
return null;
}
return {
address: factory({
address: factoryAddress,
event,
parameter,
}),
};
}
// Contract not configured on this chain - this is acceptable
return null;
}
export function buildContractConfig(config, contract) {
const { chains, contracts, startBlocks } = config;
const ponderChain = Object.fromEntries(Object.entries(chains)
.map(([chainName]) => {
const addressConfig = buildContractChainAddressConfig(config, chainName, contract);
if (!addressConfig) {
// Contract not configured on this chain, skip it
return null;
}
return [
chainName,
{
...addressConfig,
startBlock: resolveStartBlock(startBlocks, chainName, String(contract)),
},
];
})
.filter((entry) => entry !== null));
return {
abi: contracts[contract],
chain: ponderChain,
};
}
export function buildConfig(config) {
return {
chains: buildChains(config.chains),
contracts: Object.fromEntries(Object.keys(config.contracts).map((contract) => [
contract,
buildContractConfig(config, contract),
])),
};
}