Skip to content

Commit

Permalink
fix: ensure networks are registered before SDK calls (#65)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrstph-dvx authored Mar 20, 2024
1 parent fc6e3c7 commit 1d5f3e8
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 108 deletions.
109 changes: 19 additions & 90 deletions src/createTokenBridge-ethers.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
/* eslint-disable no-empty */
import { Address } from 'viem';
import { Address, PublicClient } from 'viem';
import { BigNumber, ContractFactory, ethers } from 'ethers';
import { JsonRpcProvider } from '@ethersproject/providers';
import {
L1Network,
L1ToL2MessageGasEstimator,
L2Network,
addCustomNetwork,
constants as arbitrumSdkConstants,
} from '@arbitrum/sdk';
import { L1ToL2MessageGasEstimator } from '@arbitrum/sdk';
import { getBaseFee } from '@arbitrum/sdk/dist/lib/utils/lib';
import { RollupAdminLogic__factory } from '@arbitrum/sdk/dist/lib/abi/factories/RollupAdminLogic__factory';
import L1AtomicTokenBridgeCreator from '@arbitrum/token-bridge-contracts/build/contracts/contracts/tokenbridge/ethereum/L1AtomicTokenBridgeCreator.sol/L1AtomicTokenBridgeCreator.json';
import L2AtomicTokenBridgeFactory from '@arbitrum/token-bridge-contracts/build/contracts/contracts/tokenbridge/arbitrum/L2AtomicTokenBridgeFactory.sol/L2AtomicTokenBridgeFactory.json';
import { applyPercentIncrease } from './utils/gasOverrides';
import { TransactionRequestRetryableGasOverrides } from './createTokenBridgePrepareTransactionRequest';
import { registerNewNetwork } from './utils/registerNewNetwork';
import { publicClientToProvider } from './ethers-compat/publicClientToProvider';

type NamedFactory = ContractFactory & { contractName: string };
const NamedFactoryInstance = (contractJson: {
Expand All @@ -39,12 +34,15 @@ export type CreateTokenBridgeGetInputsResult = {

export const createTokenBridgeGetInputs = async (
l1DeployerAddress: string,
l1Provider: ethers.providers.JsonRpcProvider,
l2Provider: ethers.providers.JsonRpcProvider,
l1PublicClient: PublicClient,
l2PublicClient: PublicClient,
l1TokenBridgeCreatorAddress: string,
rollupAddress: string,
retryableGasOverrides?: TransactionRequestRetryableGasOverrides,
): Promise<CreateTokenBridgeGetInputsResult> => {
const l1Provider = publicClientToProvider(l1PublicClient);
const l2Provider = publicClientToProvider(l2PublicClient);

await registerNewNetwork(l1Provider, l2Provider, rollupAddress);

const L1AtomicTokenBridgeCreator__factory = new ethers.Contract(
Expand Down Expand Up @@ -197,11 +195,15 @@ export const getEstimateForSettingGateway = async (
l1UpgradeExecutorAddress: Address,
l1GatewayRouterAddress: Address,
setGatewaysCalldata: `0x${string}`,
l1Provider: ethers.providers.Provider,
l2Provider: ethers.providers.Provider,
parentChainPublicClient: PublicClient,
orbitChainPublicClient: PublicClient,
) => {
//// run retryable estimate for setting a token gateway in the router
const l1ToL2MsgGasEstimate = new L1ToL2MessageGasEstimator(l2Provider);
// ethers providers
const parentChainProvider = publicClientToProvider(parentChainPublicClient);
const orbitChainProvider = publicClientToProvider(orbitChainPublicClient);

// run retryable estimate for setting a token gateway in the router
const l1ToL2MsgGasEstimate = new L1ToL2MessageGasEstimator(orbitChainProvider);

const setGatewaysGasParams = await l1ToL2MsgGasEstimate.estimateAll(
{
Expand All @@ -212,8 +214,8 @@ export const getEstimateForSettingGateway = async (
callValueRefundAddress: l1ChainOwnerAddress,
data: setGatewaysCalldata,
},
await getBaseFee(l1Provider),
l1Provider,
await getBaseFee(parentChainProvider),
parentChainProvider,
);

return {
Expand All @@ -223,76 +225,3 @@ export const getEstimateForSettingGateway = async (
deposit: setGatewaysGasParams.deposit.toBigInt(),
};
};

const registerNewNetwork = async (
l1Provider: JsonRpcProvider,
l2Provider: JsonRpcProvider,
rollupAddress: string,
): Promise<{
l1Network: L1Network;
l2Network: Omit<L2Network, 'tokenBridge'>;
}> => {
const l1NetworkInfo = await l1Provider.getNetwork();
const l2NetworkInfo = await l2Provider.getNetwork();

const l1Network: L1Network = {
blockTime: 10,
chainID: l1NetworkInfo.chainId,
explorerUrl: '',
isCustom: true,
name: l1NetworkInfo.name,
partnerChainIDs: [l2NetworkInfo.chainId],
isArbitrum: false,
};

const rollup = RollupAdminLogic__factory.connect(rollupAddress, l1Provider);
const l2Network: L2Network = {
chainID: l2NetworkInfo.chainId,
confirmPeriodBlocks: (await rollup.confirmPeriodBlocks()).toNumber(),
ethBridge: {
bridge: await rollup.bridge(),
inbox: await rollup.inbox(),
outbox: await rollup.outbox(),
rollup: rollup.address,
sequencerInbox: await rollup.sequencerInbox(),
},
explorerUrl: '',
isArbitrum: true,
isCustom: true,
name: 'OrbitChain',
partnerChainID: l1NetworkInfo.chainId,
partnerChainIDs: [],
retryableLifetimeSeconds: 7 * 24 * 60 * 60,
nitroGenesisBlock: 0,
nitroGenesisL1Block: 0,
depositTimeout: 900000,
tokenBridge: {
l1CustomGateway: '',
l1ERC20Gateway: '',
l1GatewayRouter: '',
l1MultiCall: '',
l1ProxyAdmin: '',
l1Weth: '',
l1WethGateway: '',
l2CustomGateway: '',
l2ERC20Gateway: '',
l2GatewayRouter: '',
l2Multicall: '',
l2ProxyAdmin: '',
l2Weth: '',
l2WethGateway: '',
},
blockTime: arbitrumSdkConstants.ARB_MINIMUM_BLOCK_TIME_IN_SECONDS,
};

// register - needed for retryables
addCustomNetwork({
customL1Network: l1Network,
customL2Network: l2Network,
});

return {
l1Network,
l2Network,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { isCustomFeeTokenChain } from './utils/isCustomFeeTokenChain';
import { upgradeExecutorEncodeFunctionData } from './upgradeExecutor';
import { createTokenBridgeFetchTokenBridgeContracts } from './createTokenBridgeFetchTokenBridgeContracts';
import { createRollupFetchCoreContracts } from './createRollupFetchCoreContracts';
import { publicClientToProvider } from './ethers-compat/publicClientToProvider';
import { getEstimateForSettingGateway } from './createTokenBridge-ethers';
import { GasOverrideOptions, applyPercentIncrease } from './utils/gasOverrides';
import { Prettify } from './types/utils';
Expand Down Expand Up @@ -138,10 +137,6 @@ export async function createTokenBridgePrepareSetWethGatewayTransactionRequest({
publicClient: parentChainPublicClient,
});

// ethers providers
const parentChainProvider = publicClientToProvider(parentChainPublicClient);
const orbitChainProvider = publicClientToProvider(orbitChainPublicClient);

// encode data for the setGateways call
// (we first encode dummy data, to get the retryable message estimates)
const setGatewaysDummyCalldata = encodeFunctionData({
Expand All @@ -160,8 +155,8 @@ export async function createTokenBridgePrepareSetWethGatewayTransactionRequest({
rollupCoreContracts.upgradeExecutor,
tokenBridgeContracts.parentChainContracts.router,
setGatewaysDummyCalldata,
parentChainProvider,
orbitChainProvider,
parentChainPublicClient,
orbitChainPublicClient,
);

//// apply gas overrides
Expand Down
8 changes: 2 additions & 6 deletions src/createTokenBridgePrepareTransactionRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { Address, PublicClient, encodeFunctionData } from 'viem';
import { tokenBridgeCreator } from './contracts';
import { validateParentChain } from './types/ParentChain';
import { createTokenBridgeGetInputs } from './createTokenBridge-ethers';
import { publicClientToProvider } from './ethers-compat/publicClientToProvider';
import { isCustomFeeTokenChain } from './utils/isCustomFeeTokenChain';
import {
GasOverrideOptions,
Expand Down Expand Up @@ -48,13 +47,10 @@ export async function createTokenBridgePrepareTransactionRequest({
const tokenBridgeCreatorAddress =
tokenBridgeCreatorAddressOverride ?? getTokenBridgeCreatorAddress(parentChainPublicClient);

const parentChainProvider = publicClientToProvider(parentChainPublicClient);
const orbitChainProvider = publicClientToProvider(orbitChainPublicClient);

const { inbox, maxGasForContracts, gasPrice, retryableFee } = await createTokenBridgeGetInputs(
account,
parentChainProvider,
orbitChainProvider,
parentChainPublicClient,
orbitChainPublicClient,
tokenBridgeCreatorAddress,
params.rollup,
retryableGasOverrides,
Expand Down
2 changes: 1 addition & 1 deletion src/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"viem": "^1.20.0"
},
"dependencies": {
"@arbitrum/sdk": "^3.2.0",
"@arbitrum/sdk": "^3.3.2",
"@arbitrum/token-bridge-contracts": "^1.2.1",
"ethers": "^5.7.2"
}
Expand Down
111 changes: 111 additions & 0 deletions src/utils/registerNewNetwork.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { JsonRpcProvider } from '@ethersproject/providers';
import {
L1Network,
L2Network,
addCustomNetwork,
constants as arbitrumSdkConstants,
} from '@arbitrum/sdk';
import {
getL1Network,
getL2Network,
l1Networks,
l2Networks,
} from '@arbitrum/sdk/dist/lib/dataEntities/networks';
import { RollupAdminLogic__factory } from '@arbitrum/sdk/dist/lib/abi/factories/RollupAdminLogic__factory';

export const registerNewNetwork = async (
l1Provider: JsonRpcProvider,
l2Provider: JsonRpcProvider,
rollupAddress: string,
): Promise<{
l1Network: L1Network;
l2Network: Omit<L2Network, 'tokenBridge'>;
}> => {
const l1NetworkInfo = await l1Provider.getNetwork();
const l2NetworkInfo = await l2Provider.getNetwork();

const l1Network: L1Network = {
blockTime: 10,
chainID: l1NetworkInfo.chainId,
explorerUrl: '',
isCustom: true,
name: l1NetworkInfo.name,
partnerChainIDs: [l2NetworkInfo.chainId],
isArbitrum: false,
};

const rollup = RollupAdminLogic__factory.connect(rollupAddress, l1Provider);
const l2Network: L2Network = {
chainID: l2NetworkInfo.chainId,
confirmPeriodBlocks: (await rollup.confirmPeriodBlocks()).toNumber(),
ethBridge: {
bridge: await rollup.bridge(),
inbox: await rollup.inbox(),
outbox: await rollup.outbox(),
rollup: rollup.address,
sequencerInbox: await rollup.sequencerInbox(),
},
explorerUrl: '',
isArbitrum: true,
isCustom: true,
name: 'OrbitChain',
partnerChainID: l1NetworkInfo.chainId,
partnerChainIDs: [],
retryableLifetimeSeconds: 7 * 24 * 60 * 60,
nitroGenesisBlock: 0,
nitroGenesisL1Block: 0,
depositTimeout: 900000,
tokenBridge: {
l1CustomGateway: '',
l1ERC20Gateway: '',
l1GatewayRouter: '',
l1MultiCall: '',
l1ProxyAdmin: '',
l1Weth: '',
l1WethGateway: '',
l2CustomGateway: '',
l2ERC20Gateway: '',
l2GatewayRouter: '',
l2Multicall: '',
l2ProxyAdmin: '',
l2Weth: '',
l2WethGateway: '',
},
blockTime: arbitrumSdkConstants.ARB_MINIMUM_BLOCK_TIME_IN_SECONDS,
};

let isL1NetworkRegistered = false;
try {
await getL1Network(l1Provider);
isL1NetworkRegistered = true;
} catch {
isL1NetworkRegistered = false;
}

let isL2NetworkRegistered = false;
try {
await getL2Network(l2Provider);
isL2NetworkRegistered = true;
} catch {
isL2NetworkRegistered = false;
}

// both networks are already registered, do nothing
if (isL1NetworkRegistered && isL2NetworkRegistered) {
return { l1Network, l2Network };
}

if (!isL1NetworkRegistered) {
// we can assume if parent is not registered, that means the child isn't either, because of this check:
// https://github.com/OffchainLabs/arbitrum-sdk/blob/main/src/lib/dataEntities/networks.ts#L519
addCustomNetwork({ customL1Network: l1Network, customL2Network: l2Network });
} else if (!isL2NetworkRegistered) {
// parent is already registered, only register the child
addCustomNetwork({ customL2Network: l2Network });
}

return {
l1Network,
l2Network,
};
};
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
"@openzeppelin/contracts-upgradeable" "4.5.2"
patch-package "^6.4.7"

"@arbitrum/sdk@^3.2.0":
version "3.2.0"
resolved "https://registry.yarnpkg.com/@arbitrum/sdk/-/sdk-3.2.0.tgz#9cc2d2d1df929c7a1702f366a444d1439d17dc08"
integrity sha512-Y8NyL1EgWE8SGRFFxtqYIedQzKe7pMS9P9j0iDQ3eL1xvOf0t0WKb8vcta0cP2TcAOOpRZ3TWKPVfpBtwMsXCg==
"@arbitrum/sdk@^3.3.2":
version "3.3.2"
resolved "https://registry.yarnpkg.com/@arbitrum/sdk/-/sdk-3.3.2.tgz#7560548c144bdefec9831502ccc6fdc1bb8eecfa"
integrity sha512-kK7Kt8yrSe/ArOBOawdiXWKhtsrGE70svAPLkQ8aouzwALkjbF0Gs/KpQxeQpq8k6kyuIRYfgv+yS0zjnghALQ==
dependencies:
"@ethersproject/address" "^5.0.8"
"@ethersproject/bignumber" "^5.1.1"
Expand Down

0 comments on commit 1d5f3e8

Please sign in to comment.