UNPKG

@arbitrum/sdk

Version:

Typescript library client-side interactions with Arbitrum

357 lines (356 loc) 16 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.resetNetworksToDefault = exports.getChildrenForNetwork = exports.isParentNetwork = void 0; exports.getArbitrumNetwork = getArbitrumNetwork; exports.getArbitrumNetworks = getArbitrumNetworks; exports.getArbitrumNetworkInformationFromRollup = getArbitrumNetworkInformationFromRollup; exports.registerCustomArbitrumNetwork = registerCustomArbitrumNetwork; exports.getNitroGenesisBlock = getNitroGenesisBlock; exports.getMulticallAddress = getMulticallAddress; exports.mapL2NetworkTokenBridgeToTokenBridge = mapL2NetworkTokenBridgeToTokenBridge; exports.mapL2NetworkToArbitrumNetwork = mapL2NetworkToArbitrumNetwork; exports.assertArbitrumNetworkHasTokenBridge = assertArbitrumNetworkHasTokenBridge; exports.isArbitrumNetworkNativeTokenEther = isArbitrumNetworkNativeTokenEther; /* * Copyright 2021, Offchain Labs, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* eslint-env node */ ; ('use strict'); const ethers_1 = require("ethers"); const signerOrProvider_1 = require("./signerOrProvider"); const errors_1 = require("../dataEntities/errors"); const constants_1 = require("./constants"); const RollupAdminLogic__factory_1 = require("../abi/factories/RollupAdminLogic__factory"); const IERC20Bridge__factory_1 = require("../abi/factories/IERC20Bridge__factory"); const mainnetTokenBridge = { parentGatewayRouter: '0x72Ce9c846789fdB6fC1f34aC4AD25Dd9ef7031ef', childGatewayRouter: '0x5288c571Fd7aD117beA99bF60FE0846C4E84F933', parentErc20Gateway: '0xa3A7B6F88361F48403514059F1F16C8E78d60EeC', childErc20Gateway: '0x09e9222E96E7B4AE2a407B98d48e330053351EEe', parentCustomGateway: '0xcEe284F754E854890e311e3280b767F80797180d', childCustomGateway: '0x096760F208390250649E3e8763348E783AEF5562', parentWethGateway: '0xd92023E9d9911199a6711321D1277285e6d4e2db', childWethGateway: '0x6c411aD3E74De3E7Bd422b94A27770f5B86C623B', childWeth: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1', parentWeth: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', parentProxyAdmin: '0x9aD46fac0Cf7f790E5be05A0F15223935A0c0aDa', childProxyAdmin: '0xd570aCE65C43af47101fC6250FD6fC63D1c22a86', parentMultiCall: '0x5ba1e12693dc8f9c48aad8770482f4739beed696', childMultiCall: '0x842eC2c7D803033Edf55E478F461FC547Bc54EB2', }; const mainnetETHBridge = { bridge: '0x8315177aB297bA92A06054cE80a67Ed4DBd7ed3a', inbox: '0x4Dbd4fc535Ac27206064B68FfCf827b0A60BAB3f', sequencerInbox: '0x1c479675ad559DC151F6Ec7ed3FbF8ceE79582B6', outbox: '0x0B9857ae2D4A3DBe74ffE1d7DF045bb7F96E4840', rollup: '0x4DCeB440657f21083db8aDd07665f8ddBe1DCfc0', classicOutboxes: { '0x667e23ABd27E623c11d4CC00ca3EC4d0bD63337a': 0, '0x760723CD2e632826c38Fef8CD438A4CC7E7E1A40': 30, }, }; /** * Storage for all Arbitrum networks, either L2 or L3. */ const networks = { 42161: { chainId: 42161, name: 'Arbitrum One', parentChainId: 1, tokenBridge: mainnetTokenBridge, ethBridge: mainnetETHBridge, teleporter: { l1Teleporter: '0xCBd9c6e310D6AaDeF9F025f716284162F0158992', l2ForwarderFactory: '0x791d2AbC6c3A459E13B9AdF54Fb5e97B7Af38f87', }, confirmPeriodBlocks: 45818, isBold: true, isCustom: false, isTestnet: false, }, 42170: { chainId: 42170, confirmPeriodBlocks: 45818, ethBridge: { bridge: '0xC1Ebd02f738644983b6C4B2d440b8e77DdE276Bd', inbox: '0xc4448b71118c9071Bcb9734A0EAc55D18A153949', outbox: '0xD4B80C3D7240325D18E645B49e6535A3Bf95cc58', rollup: '0xE7E8cCC7c381809BDC4b213CE44016300707B7Bd', sequencerInbox: '0x211E1c4c7f1bF5351Ac850Ed10FD68CFfCF6c21b', }, isBold: true, isCustom: false, isTestnet: false, name: 'Arbitrum Nova', parentChainId: 1, tokenBridge: { parentCustomGateway: '0x23122da8C581AA7E0d07A36Ff1f16F799650232f', parentErc20Gateway: '0xB2535b988dcE19f9D71dfB22dB6da744aCac21bf', parentGatewayRouter: '0xC840838Bc438d73C16c2f8b22D2Ce3669963cD48', parentMultiCall: '0x8896D23AfEA159a5e9b72C9Eb3DC4E2684A38EA3', parentProxyAdmin: '0xa8f7DdEd54a726eB873E98bFF2C95ABF2d03e560', parentWeth: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', parentWethGateway: '0xE4E2121b479017955Be0b175305B35f312330BaE', childCustomGateway: '0xbf544970E6BD77b21C6492C281AB60d0770451F4', childErc20Gateway: '0xcF9bAb7e53DDe48A6DC4f286CB14e05298799257', childGatewayRouter: '0x21903d3F8176b1a0c17E953Cd896610Be9fFDFa8', childMultiCall: '0x5e1eE626420A354BbC9a95FeA1BAd4492e3bcB86', childProxyAdmin: '0xada790b026097BfB36a5ed696859b97a96CEd92C', childWeth: '0x722E8BdD2ce80A4422E880164f2079488e115365', childWethGateway: '0x7626841cB6113412F9c88D3ADC720C9FAC88D9eD', }, teleporter: { l1Teleporter: '0xCBd9c6e310D6AaDeF9F025f716284162F0158992', l2ForwarderFactory: '0x791d2AbC6c3A459E13B9AdF54Fb5e97B7Af38f87', }, }, 421614: { chainId: 421614, confirmPeriodBlocks: 20, ethBridge: { bridge: '0x38f918D0E9F1b721EDaA41302E399fa1B79333a9', inbox: '0xaAe29B0366299461418F5324a79Afc425BE5ae21', outbox: '0x65f07C7D521164a4d5DaC6eB8Fac8DA067A3B78F', rollup: '0xd80810638dbDF9081b72C1B33c65375e807281C8', sequencerInbox: '0x6c97864CE4bEf387dE0b3310A44230f7E3F1be0D', }, isCustom: false, isTestnet: true, name: 'Arbitrum Rollup Sepolia Testnet', parentChainId: 11155111, tokenBridge: { parentCustomGateway: '0xba2F7B6eAe1F9d174199C5E4867b563E0eaC40F3', parentErc20Gateway: '0x902b3E5f8F19571859F4AB1003B960a5dF693aFF', parentGatewayRouter: '0xcE18836b233C83325Cc8848CA4487e94C6288264', parentMultiCall: '0xded9AD2E65F3c4315745dD915Dbe0A4Df61b2320', parentProxyAdmin: '0xDBFC2FfB44A5D841aB42b0882711ed6e5A9244b0', parentWeth: '0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9', parentWethGateway: '0xA8aD8d7e13cbf556eE75CB0324c13535d8100e1E', childCustomGateway: '0x8Ca1e1AC0f260BC4dA7Dd60aCA6CA66208E642C5', childErc20Gateway: '0x6e244cD02BBB8a6dbd7F626f05B2ef82151Ab502', childGatewayRouter: '0x9fDD1C4E4AA24EEc1d913FABea925594a20d43C7', childMultiCall: '0xA115146782b7143fAdB3065D86eACB54c169d092', childProxyAdmin: '0x715D99480b77A8d9D603638e593a539E21345FdF', childWeth: '0x980B62Da83eFf3D4576C647993b0c1D7faf17c73', childWethGateway: '0xCFB1f08A4852699a979909e22c30263ca249556D', }, teleporter: { l1Teleporter: '0x9E86BbF020594D7FFe05bF32EEDE5b973579A968', l2ForwarderFactory: '0x88feBaFBb4E36A4E7E8874E4c9Fd73A9D59C2E7c', }, }, }; /** * Determines if a chain is a parent of *any* other chain. Could be an L1 or an L2 chain. */ const isParentNetwork = (parentChainOrChainId) => { const parentChainId = typeof parentChainOrChainId === 'number' ? parentChainOrChainId : parentChainOrChainId.chainId; // Check if there are any chains that have this chain as its parent chain return getArbitrumNetworks().some(c => c.parentChainId === parentChainId); }; exports.isParentNetwork = isParentNetwork; /** * Returns a list of children chains for the given chain or chain id. */ const getChildrenForNetwork = (parentChainOrChainId) => { const parentChainId = typeof parentChainOrChainId === 'number' ? parentChainOrChainId : parentChainOrChainId.chainId; return getArbitrumNetworks().filter(arbitrumChain => arbitrumChain.parentChainId === parentChainId); }; exports.getChildrenForNetwork = getChildrenForNetwork; function getArbitrumNetwork(signerOrProviderOrChainId) { if (typeof signerOrProviderOrChainId === 'number') { return getArbitrumNetworkByChainId(signerOrProviderOrChainId); } return getArbitrumNetworkBySignerOrProvider(signerOrProviderOrChainId); } function getArbitrumNetworkByChainId(chainId) { const network = getArbitrumNetworks().find(n => n.chainId === chainId); if (!network) { throw new errors_1.ArbSdkError(`Unrecognized network ${chainId}.`); } return network; } async function getArbitrumNetworkBySignerOrProvider(signerOrProvider) { const provider = signerOrProvider_1.SignerProviderUtils.getProviderOrThrow(signerOrProvider); const { chainId } = await provider.getNetwork(); return getArbitrumNetworkByChainId(chainId); } async function getNativeToken(bridge, provider) { try { return await IERC20Bridge__factory_1.IERC20Bridge__factory.connect(bridge, provider).nativeToken(); } catch (err) { return ethers_1.constants.AddressZero; } } /** * Returns all Arbitrum networks registered in the SDK, both default and custom. */ function getArbitrumNetworks() { return Object.values(networks); } /** * Returns all the information about an Arbitrum network that can be fetched from its Rollup contract. * * @param rollupAddress Address of the Rollup contract on the parent chain * @param parentProvider Provider for the parent chain * * @returns An {@link ArbitrumNetworkInformationFromRollup} object */ async function getArbitrumNetworkInformationFromRollup(rollupAddress, parentProvider) { const rollup = RollupAdminLogic__factory_1.RollupAdminLogic__factory.connect(rollupAddress, parentProvider); const [bridge, inbox, sequencerInbox, outbox, confirmPeriodBlocks] = await Promise.all([ rollup.bridge(), rollup.inbox(), rollup.sequencerInbox(), rollup.outbox(), rollup.confirmPeriodBlocks(), ]); return { parentChainId: (await parentProvider.getNetwork()).chainId, confirmPeriodBlocks: confirmPeriodBlocks.toNumber(), ethBridge: { bridge, inbox, sequencerInbox, outbox, rollup: rollupAddress, }, nativeToken: await getNativeToken(bridge, parentProvider), }; } /** * Registers a custom Arbitrum network. * * @param network {@link ArbitrumNetwork} to be registered * @param options Additional options * @param options.throwIfAlreadyRegistered Whether or not the function should throw if the network is already registered, defaults to `false` */ function registerCustomArbitrumNetwork(network, options) { var _a; const throwIfAlreadyRegistered = (_a = options === null || options === void 0 ? void 0 : options.throwIfAlreadyRegistered) !== null && _a !== void 0 ? _a : false; if (!network.isCustom) { throw new errors_1.ArbSdkError(`Custom network ${network.chainId} must have isCustom flag set to true`); } if (typeof networks[network.chainId] !== 'undefined') { const message = `Network ${network.chainId} already included`; if (throwIfAlreadyRegistered) { throw new errors_1.ArbSdkError(message); } console.warn(message); } // store the network with the rest of the networks networks[network.chainId] = network; return network; } /** * Creates a function that resets the networks index to default. Useful in development. */ const createNetworkStateHandler = () => { const initialState = JSON.parse(JSON.stringify(networks)); return { resetNetworksToDefault: () => { Object.keys(networks).forEach(key => delete networks[key]); Object.assign(networks, JSON.parse(JSON.stringify(initialState))); }, }; }; function getNitroGenesisBlock(arbitrumChainOrChainId) { const arbitrumChainId = typeof arbitrumChainOrChainId === 'number' ? arbitrumChainOrChainId : arbitrumChainOrChainId.chainId; // all networks except Arbitrum One started off with Nitro if (arbitrumChainId === 42161) { return constants_1.ARB1_NITRO_GENESIS_L2_BLOCK; } return 0; } async function getMulticallAddress(providerOrChainId) { const chains = getArbitrumNetworks(); const chainId = typeof providerOrChainId === 'number' ? providerOrChainId : (await providerOrChainId.getNetwork()).chainId; const chain = chains.find(c => c.chainId === chainId); // The provided chain is found in the list if (typeof chain !== 'undefined') { assertArbitrumNetworkHasTokenBridge(chain); // Return the address of Multicall on the chain return chain.tokenBridge.childMultiCall; } // The provided chain is not found in the list // Try to find a chain that references this chain as its parent const childChain = chains.find(c => c.parentChainId === chainId); // No chains reference this chain as its parent if (typeof childChain === 'undefined') { throw new Error(`Failed to retrieve Multicall address for chain: ${chainId}`); } assertArbitrumNetworkHasTokenBridge(childChain); // Return the address of Multicall on the parent chain return childChain.tokenBridge.parentMultiCall; } /** * Maps the old {@link L2Network.tokenBridge} (from SDK v3) to {@link ArbitrumNetwork.tokenBridge} (from SDK v4). */ function mapL2NetworkTokenBridgeToTokenBridge(input) { return { parentGatewayRouter: input.l1GatewayRouter, childGatewayRouter: input.l2GatewayRouter, parentErc20Gateway: input.l1ERC20Gateway, childErc20Gateway: input.l2ERC20Gateway, parentCustomGateway: input.l1CustomGateway, childCustomGateway: input.l2CustomGateway, parentWethGateway: input.l1WethGateway, childWethGateway: input.l2WethGateway, parentWeth: input.l1Weth, childWeth: input.l2Weth, parentProxyAdmin: input.l1ProxyAdmin, childProxyAdmin: input.l2ProxyAdmin, parentMultiCall: input.l1MultiCall, childMultiCall: input.l2Multicall, }; } /** * Maps the old {@link L2Network} (from SDK v3) to {@link ArbitrumNetwork} (from SDK v4). */ function mapL2NetworkToArbitrumNetwork(l2Network) { return Object.assign(Object.assign({}, l2Network), { // Map properties that were changed chainId: l2Network.chainID, parentChainId: l2Network.partnerChainID, tokenBridge: mapL2NetworkTokenBridgeToTokenBridge(l2Network.tokenBridge) }); } /** * Asserts that the given object has a token bridge. This is useful because not all Arbitrum network * operations require a token bridge. * * @param network {@link ArbitrumNetwork} object * @throws ArbSdkError if the object does not have a token bridge */ function assertArbitrumNetworkHasTokenBridge(network) { if (typeof network === 'undefined' || !('tokenBridge' in network) || typeof network.tokenBridge === 'undefined') { throw new errors_1.ArbSdkError(`The ArbitrumNetwork object with chainId ${network.chainId} is missing the token bridge contracts addresses. Please add them in the "tokenBridge" property.`); } } function isArbitrumNetworkNativeTokenEther(network) { return (typeof network.nativeToken === 'undefined' || network.nativeToken === ethers_1.constants.AddressZero); } const { resetNetworksToDefault } = createNetworkStateHandler(); exports.resetNetworksToDefault = resetNetworksToDefault;