UNPKG

@biconomy/abstractjs

Version:

SDK for Biconomy integration with support for account abstraction, smart accounts, ERC-4337.

136 lines 5.13 kB
import { encodeFunctionData } from "viem"; export const LARGE_DEFAULT_GAS_LIMIT = 700000n; function createChainSpecificContract(abi, chainId, address) { return new Proxy({}, { get: (_, prop) => { if (!abi.some((item) => item.type === "function" && item.name === prop)) { throw new Error(`Function ${prop} not found in ABI`); } return ({ args, gasLimit = LARGE_DEFAULT_GAS_LIMIT, value = 0n }) => { const params = { abi, functionName: prop, args }; const data = encodeFunctionData(params); const call = { to: address, gasLimit, value, data }; return { calls: [call], chainId }; }; } }); } /** * Creates a contract instance that can encode function calls across multiple chains * * @template TAbi - The contract ABI type * @param config - Configuration for the multichain contract * @param config.abi - {@link Abi} The contract's ABI * @param config.deployments - Array of tuples containing [address, chainId] for each deployment * * @returns {@link MultichainContract} A contract instance that works across multiple chains * * @throws Error if attempting to access contract on an unsupported chain * @throws Error if attempting to call a non-existent function * @throws Error if attempting to read a non-view/pure function * * @example * const mcUSDC = getMultichainContract({ * abi: erc20ABI, * deployments: [ * ["0x7F5c764cBc14f9669B88837ca1490cCa17c31607", optimism.id], // Optimism USDC * ["0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", base.id] // Base USDC * ] * }); * * // Encode a transfer on Optimism * const transferOp = mcUSDC.on(optimism.id).transfer({ * args: ["0x123...", BigInt("1000000")], // 1 USDC * gasLimit: 100000n * }); * * // Read balances across multiple chains * const balances = await mcUSDC.read({ * onChains: [optimism, base], * functionName: "balanceOf", * args: ["0x123..."], * account: myMultichainAccount * }); */ export function getMultichainContract(config) { const deployments = new Map(config.deployments.map((deployment) => { const [address, chainId] = deployment; return [chainId, address]; })); return { abi: config.abi, deployments, on: (chainId) => { const address = deployments.get(chainId); if (!address) { throw new Error(`No deployment found for chain ${chainId}`); } return createChainSpecificContract(config.abi, chainId, address); }, build: async (params) => { const { data: { chainId, args: args_, gasLimit }, type: functionName } = params; const address = deployments.get(chainId); if (!address) { throw new Error(`No deployment found for chain ${chainId}`); } const result = createChainSpecificContract(config.abi, chainId, address)[functionName]({ args: args_, ...(gasLimit ? { gasLimit } : {}) }); return { chainId: chainId, calls: result.calls }; }, addressOn: (chainId) => { const address = deployments.get(chainId); if (!address) { throw new Error(`No deployment found for chain ${chainId}`); } return address; }, read: async (params) => { const abiFunction = config.abi.find((item) => item.type === "function" && item.name === params.functionName && (item.stateMutability === "view" || item.stateMutability === "pure")); if (!abiFunction) { throw new Error(`Function ${params.functionName} not found in ABI or is not a read function`); } const results = await Promise.all(params.onChains.map(async (chain) => { const address = deployments.get(chain.id); if (!address) { throw new Error(`No deployment found for chain ${chain.id}`); } const deployment = params.account.deploymentOn(chain.id); if (!deployment) { throw new Error(`No deployment found for chain ${chain.id}`); } const client = deployment.client; const result = await client.readContract({ address, abi: config.abi, functionName: params.functionName, args: params.args }); return { chainId: chain.id, result: result }; })); return results; } }; } //# sourceMappingURL=getMultichainContract.js.map