diff --git a/src/constants.ts b/src/constants.ts index dbfd0f86..1d6a30ae 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -3,4 +3,3 @@ import { parseEther } from 'viem'; export const createRollupDefaultRetryablesFees = parseEther('0.125'); export const createTokenBridgeDefaultRetryablesFees = parseEther('0.02'); -export const createTokenBridgeDefaultGasLimit = 5_000_000n; diff --git a/src/createRollupEnoughCustomFeeTokenAllowance.ts b/src/createRollupEnoughCustomFeeTokenAllowance.ts index 2d49dd7a..6aa1891d 100644 --- a/src/createRollupEnoughCustomFeeTokenAllowance.ts +++ b/src/createRollupEnoughCustomFeeTokenAllowance.ts @@ -5,16 +5,22 @@ import { validParentChainId } from './types/ParentChain'; import { fetchAllowance } from './utils/erc20'; import { createRollupDefaultRetryablesFees } from './constants'; -export type CreateRollupEnoughCustomFeeTokenAllowanceParams = { - nativeToken: Address; - account: Address; - publicClient: PublicClient; -}; +import { Prettify } from './types/utils'; +import { WithRollupCreatorAddressOverride } from './types/createRollupTypes'; + +export type CreateRollupEnoughCustomFeeTokenAllowanceParams = Prettify< + WithRollupCreatorAddressOverride<{ + nativeToken: Address; + account: Address; + publicClient: PublicClient; + }> +>; export async function createRollupEnoughCustomFeeTokenAllowance({ nativeToken, account, publicClient, + rollupCreatorAddressOverride, }: CreateRollupEnoughCustomFeeTokenAllowanceParams) { const chainId = publicClient.chain?.id; @@ -25,7 +31,7 @@ export async function createRollupEnoughCustomFeeTokenAllowance({ const allowance = await fetchAllowance({ address: nativeToken, owner: account, - spender: rollupCreator.address[chainId], + spender: rollupCreatorAddressOverride ?? rollupCreator.address[chainId], publicClient, }); diff --git a/src/createRollupPrepareCustomFeeTokenApprovalTransactionRequest.ts b/src/createRollupPrepareCustomFeeTokenApprovalTransactionRequest.ts index 3933ed25..e3e1e390 100644 --- a/src/createRollupPrepareCustomFeeTokenApprovalTransactionRequest.ts +++ b/src/createRollupPrepareCustomFeeTokenApprovalTransactionRequest.ts @@ -5,18 +5,24 @@ import { validParentChainId } from './types/ParentChain'; import { rollupCreator } from './contracts'; import { createRollupDefaultRetryablesFees } from './constants'; -export type CreateRollupPrepareCustomFeeTokenApprovalTransactionRequestParams = { - amount?: bigint; - nativeToken: Address; - account: Address; - publicClient: PublicClient; -}; +import { Prettify } from './types/utils'; +import { WithRollupCreatorAddressOverride } from './types/createRollupTypes'; + +export type CreateRollupPrepareCustomFeeTokenApprovalTransactionRequestParams = Prettify< + WithRollupCreatorAddressOverride<{ + amount?: bigint; + nativeToken: Address; + account: Address; + publicClient: PublicClient; + }> +>; export async function createRollupPrepareCustomFeeTokenApprovalTransactionRequest({ amount = createRollupDefaultRetryablesFees, nativeToken, account, publicClient, + rollupCreatorAddressOverride, }: CreateRollupPrepareCustomFeeTokenApprovalTransactionRequestParams) { const chainId = publicClient.chain?.id; @@ -27,7 +33,7 @@ export async function createRollupPrepareCustomFeeTokenApprovalTransactionReques const request = await approvePrepareTransactionRequest({ address: nativeToken, owner: account, - spender: rollupCreator.address[chainId], + spender: rollupCreatorAddressOverride ?? rollupCreator.address[chainId], amount, publicClient, }); diff --git a/src/createRollupPrepareTransactionRequest.ts b/src/createRollupPrepareTransactionRequest.ts index ed1f1125..ea04e70f 100644 --- a/src/createRollupPrepareTransactionRequest.ts +++ b/src/createRollupPrepareTransactionRequest.ts @@ -1,6 +1,5 @@ import { Address, PublicClient, encodeFunctionData, zeroAddress } from 'viem'; -import { CreateRollupFunctionInputs, CreateRollupParams } from './types/createRollupTypes'; import { defaults } from './createRollupDefaults'; import { createRollupGetCallValue } from './createRollupGetCallValue'; import { createRollupGetMaxDataSize } from './createRollupGetMaxDataSize'; @@ -10,6 +9,14 @@ import { isCustomFeeTokenAddress } from './utils/isCustomFeeTokenAddress'; import { ChainConfig } from './types/ChainConfig'; import { isAnyTrustChainConfig } from './utils/isAnyTrustChainConfig'; import { fetchDecimals } from './utils/erc20'; +import { TransactionRequestGasOverrides, applyPercentIncrease } from './utils/gasOverrides'; + +import { Prettify } from './types/utils'; +import { + CreateRollupFunctionInputs, + CreateRollupParams, + WithRollupCreatorAddressOverride, +} from './types/createRollupTypes'; function createRollupEncodeFunctionData(args: CreateRollupFunctionInputs) { return encodeFunctionData({ @@ -19,15 +26,22 @@ function createRollupEncodeFunctionData(args: CreateRollupFunctionInputs) { }); } +export type CreateRollupPrepareTransactionRequestParams = Prettify< + WithRollupCreatorAddressOverride<{ + params: CreateRollupParams; + account: Address; + publicClient: PublicClient; + gasOverrides?: TransactionRequestGasOverrides; + }> +>; + export async function createRollupPrepareTransactionRequest({ params, account, publicClient, -}: { - params: CreateRollupParams; - account: Address; - publicClient: PublicClient; -}) { + gasOverrides, + rollupCreatorAddressOverride, +}: CreateRollupPrepareTransactionRequestParams) { const chainId = publicClient.chain?.id; if (!validParentChainId(chainId)) { @@ -65,11 +79,23 @@ export async function createRollupPrepareTransactionRequest({ const request = await publicClient.prepareTransactionRequest({ chain: publicClient.chain, - to: rollupCreator.address[chainId], + to: rollupCreatorAddressOverride ?? rollupCreator.address[chainId], data: createRollupEncodeFunctionData([paramsWithDefaults]), value: createRollupGetCallValue(paramsWithDefaults), account, + // if the base gas limit override was provided, hardcode gas to 0 to skip estimation + // we'll set the actual value in the code below + gas: typeof gasOverrides?.gasLimit?.base !== 'undefined' ? 0n : undefined, }); + // potential gas overrides (gas limit) + if (gasOverrides && gasOverrides.gasLimit) { + request.gas = applyPercentIncrease({ + // the ! is here because we should let it error in case we don't have the estimated gas + base: gasOverrides.gasLimit.base ?? request.gas!, + percentIncrease: gasOverrides.gasLimit.percentIncrease, + }); + } + return { ...request, chainId }; } diff --git a/src/createRollupPrepareTransactionRequest.unit.test.ts b/src/createRollupPrepareTransactionRequest.unit.test.ts index 099250c4..48ba7ff8 100644 --- a/src/createRollupPrepareTransactionRequest.unit.test.ts +++ b/src/createRollupPrepareTransactionRequest.unit.test.ts @@ -6,6 +6,7 @@ import { generateChainId } from './utils'; import { prepareChainConfig } from './prepareChainConfig'; import { createRollupPrepareConfig } from './createRollupPrepareConfig'; import { createRollupPrepareTransactionRequest } from './createRollupPrepareTransactionRequest'; +import { rollupCreator } from './contracts'; import { getNitroTestnodePrivateKeyAccounts } from './testHelpers'; @@ -137,11 +138,6 @@ it(`fails to prepare transaction request if "params.nativeToken" is custom and c }); it(`fails to prepare transaction request if "params.nativeToken" doesn't use 18 decimals`, async () => { - const arbitrumSepoliaPublicClient = createPublicClient({ - chain: arbitrumSepolia, - transport: http(), - }); - // generate a random chain id const chainId = generateChainId(); @@ -172,3 +168,68 @@ it(`fails to prepare transaction request if "params.nativeToken" doesn't use 18 `"params.nativeToken" can only be configured with a token that uses 18 decimals.`, ); }); + +it(`successfully prepares a transaction request with the default rollup creator and a gas limit override`, async () => { + // generate a random chain id + const chainId = generateChainId(); + + // create the chain config + const chainConfig = prepareChainConfig({ + chainId, + arbitrum: { InitialChainOwner: deployer.address, DataAvailabilityCommittee: true }, + }); + + const txRequest = await createRollupPrepareTransactionRequest({ + params: { + config: createRollupPrepareConfig({ + chainId: BigInt(chainId), + owner: deployer.address, + chainConfig, + }), + batchPoster: deployer.address, + validators: [deployer.address], + }, + account: deployer.address, + publicClient, + gasOverrides: { gasLimit: { base: 1_000n } }, + }); + + expect(txRequest.account).toEqual(deployer.address); + expect(txRequest.from).toEqual(deployer.address); + expect(txRequest.to).toEqual(rollupCreator.address[arbitrumSepolia.id]); + expect(txRequest.chainId).toEqual(arbitrumSepolia.id); + expect(txRequest.gas).toEqual(1_000n); +}); + +it(`successfully prepares a transaction request with a custom rollup creator and a gas limit override`, async () => { + // generate a random chain id + const chainId = generateChainId(); + + // create the chain config + const chainConfig = prepareChainConfig({ + chainId, + arbitrum: { InitialChainOwner: deployer.address, DataAvailabilityCommittee: true }, + }); + + const txRequest = await createRollupPrepareTransactionRequest({ + params: { + config: createRollupPrepareConfig({ + chainId: BigInt(chainId), + owner: deployer.address, + chainConfig, + }), + batchPoster: deployer.address, + validators: [deployer.address], + }, + account: deployer.address, + publicClient, + gasOverrides: { gasLimit: { base: 1_000n, percentIncrease: 20n } }, + rollupCreatorAddressOverride: '0x31421C442c422BD16aef6ae44D3b11F404eeaBd9', + }); + + expect(txRequest.account).toEqual(deployer.address); + expect(txRequest.from).toEqual(deployer.address); + expect(txRequest.to).toEqual('0x31421C442c422BD16aef6ae44D3b11F404eeaBd9'); + expect(txRequest.chainId).toEqual(arbitrumSepolia.id); + expect(txRequest.gas).toEqual(1_200n); +}); diff --git a/src/createTokenBridge.integration.test.ts b/src/createTokenBridge.integration.test.ts index 379f8f41..dbadeb21 100644 --- a/src/createTokenBridge.integration.test.ts +++ b/src/createTokenBridge.integration.test.ts @@ -14,7 +14,10 @@ import { getNitroTestnodePrivateKeyAccounts } from './testHelpers'; import { createTokenBridgePrepareTransactionRequest } from './createTokenBridgePrepareTransactionRequest'; import { createTokenBridgePrepareTransactionReceipt } from './createTokenBridgePrepareTransactionReceipt'; import { deployTokenBridgeCreator } from './createTokenBridge-testHelpers'; -import { createTokenBridgeEnoughCustomFeeTokenAllowance } from './createTokenBridgeEnoughCustomFeeTokenAllowance'; +import { + CreateTokenBridgeEnoughCustomFeeTokenAllowanceParams, + createTokenBridgeEnoughCustomFeeTokenAllowance, +} from './createTokenBridgeEnoughCustomFeeTokenAllowance'; import { createTokenBridgePrepareCustomFeeTokenApprovalTransactionRequest } from './createTokenBridgePrepareCustomFeeTokenApprovalTransactionRequest'; import { erc20 } from './contracts'; @@ -110,14 +113,12 @@ it(`successfully deploys token bridge contracts through token bridge creator`, a base: 4_000_000_000_000n, }, }, + tokenBridgeCreatorAddressOverride: tokenBridgeCreator, }); - // update the transaction request to use the fresh token bridge creator - const txRequestToFreshTokenBridgeCreator = { ...txRequest, to: tokenBridgeCreator }; - // sign and send the transaction const txHash = await nitroTestnodeL1Client.sendRawTransaction({ - serializedTransaction: await l2RollupOwner.signTransaction(txRequestToFreshTokenBridgeCreator), + serializedTransaction: await l2RollupOwner.signTransaction(txRequest), }); // get the transaction receipt after waiting for the transaction to complete @@ -197,59 +198,25 @@ it(`successfully deploys token bridge contracts with a custom fee token through expect(fundTxReceipt.status).toEqual('success'); // ----------------------------- - // 2. check the new token bridge creator allowance - // NOTE: We will estimate the token bridge creation through the canonical TokenBridgeCreator - // and we will later change the destination address to the new deployed TokenBridgeCreator. - // Thus, we need to give allowance to both TokenBridgeCreators - const allowanceParams = { + // 2. approve custom fee token to be spent by the TokenBridgeCreator + const allowanceParams: CreateTokenBridgeEnoughCustomFeeTokenAllowanceParams = { nativeToken: testnodeInformation.l3NativeToken, owner: l3RollupOwner.address, publicClient: nitroTestnodeL2Client, + tokenBridgeCreatorAddressOverride: tokenBridgeCreator, }; - // 2.a. Approval for canonical TokenBridgeCreator (gas estimation is still done through it, so we need allowance) - if (!(await createTokenBridgeEnoughCustomFeeTokenAllowance(allowanceParams))) { - const approvalTxRequest = - await createTokenBridgePrepareCustomFeeTokenApprovalTransactionRequest(allowanceParams); - - // sign and send the transaction - const approvalTxHash = await nitroTestnodeL2Client.sendRawTransaction({ - serializedTransaction: await l3RollupOwner.signTransaction(approvalTxRequest), - }); - - // get the transaction receipt after waiting for the transaction to complete - const approvalTxReceipt = await nitroTestnodeL2Client.waitForTransactionReceipt({ - hash: approvalTxHash, - }); - expect(approvalTxReceipt.status).toEqual('success'); - } - - // 2.b. Approval for the new TokenBridgeCreator - const approvalForNewTokenBridgeCreatorTxRequest = - await createTokenBridgePrepareCustomFeeTokenApprovalTransactionRequest(allowanceParams); - - // update the transaction request to use the fresh token bridge creator - approvalForNewTokenBridgeCreatorTxRequest.data = encodeFunctionData({ - abi: erc20.abi, - functionName: 'approve', - args: [tokenBridgeCreator, maxInt256], - }); - // also update the gas used since we estimated an update of the mapping of allowances (to the canonical TokenBridgeCreator), - // but we will now be adding a new element to that mapping (hence the extra cost of gas) - approvalForNewTokenBridgeCreatorTxRequest.gas = - approvalForNewTokenBridgeCreatorTxRequest.gas! * 2n; - // sign and send the transaction - const approvalForNewTokenBridgeCreatorTxHash = await nitroTestnodeL2Client.sendRawTransaction({ + const approvalForTokenBridgeCreatorTxHash = await nitroTestnodeL2Client.sendRawTransaction({ serializedTransaction: await l3RollupOwner.signTransaction( - approvalForNewTokenBridgeCreatorTxRequest, + await createTokenBridgePrepareCustomFeeTokenApprovalTransactionRequest(allowanceParams), ), }); // get the transaction receipt after waiting for the transaction to complete const approvalForNewTokenBridgeCreatorTxReceipt = await nitroTestnodeL2Client.waitForTransactionReceipt({ - hash: approvalForNewTokenBridgeCreatorTxHash, + hash: approvalForTokenBridgeCreatorTxHash, }); expect(approvalForNewTokenBridgeCreatorTxReceipt.status).toEqual('success'); @@ -282,14 +249,12 @@ it(`successfully deploys token bridge contracts with a custom fee token through base: 4_000_000_000_000n, }, }, + tokenBridgeCreatorAddressOverride: tokenBridgeCreator, }); - // update the transaction request to use the fresh token bridge creator - const txRequestToFreshTokenBridgeCreator = { ...txRequest, to: tokenBridgeCreator }; - // sign and send the transaction const txHash = await nitroTestnodeL2Client.sendRawTransaction({ - serializedTransaction: await l3RollupOwner.signTransaction(txRequestToFreshTokenBridgeCreator), + serializedTransaction: await l3RollupOwner.signTransaction(txRequest), }); // get the transaction receipt after waiting for the transaction to complete diff --git a/src/createTokenBridgeEnoughCustomFeeTokenAllowance.ts b/src/createTokenBridgeEnoughCustomFeeTokenAllowance.ts index 4052b4bb..870e4227 100644 --- a/src/createTokenBridgeEnoughCustomFeeTokenAllowance.ts +++ b/src/createTokenBridgeEnoughCustomFeeTokenAllowance.ts @@ -5,16 +5,22 @@ import { validParentChainId } from './types/ParentChain'; import { fetchAllowance } from './utils/erc20'; import { createTokenBridgeDefaultRetryablesFees } from './constants'; -export type CreateTokenBridgeEnoughCustomFeeTokenAllowanceParams = { - nativeToken: Address; - owner: Address; - publicClient: PublicClient; -}; +import { Prettify } from './types/utils'; +import { WithTokenBridgeCreatorAddressOverride } from './types/createTokenBridgeTypes'; + +export type CreateTokenBridgeEnoughCustomFeeTokenAllowanceParams = Prettify< + WithTokenBridgeCreatorAddressOverride<{ + nativeToken: Address; + owner: Address; + publicClient: PublicClient; + }> +>; export async function createTokenBridgeEnoughCustomFeeTokenAllowance({ nativeToken, owner, publicClient, + tokenBridgeCreatorAddressOverride, }: CreateTokenBridgeEnoughCustomFeeTokenAllowanceParams) { const chainId = publicClient.chain?.id; @@ -25,7 +31,7 @@ export async function createTokenBridgeEnoughCustomFeeTokenAllowance({ const allowance = await fetchAllowance({ address: nativeToken, owner, - spender: tokenBridgeCreator.address[chainId], + spender: tokenBridgeCreatorAddressOverride ?? tokenBridgeCreator.address[chainId], publicClient, }); diff --git a/src/createTokenBridgeFetchTokenBridgeContracts.ts b/src/createTokenBridgeFetchTokenBridgeContracts.ts index 1c3cccd6..9a81d711 100644 --- a/src/createTokenBridgeFetchTokenBridgeContracts.ts +++ b/src/createTokenBridgeFetchTokenBridgeContracts.ts @@ -1,16 +1,23 @@ import { Address, PublicClient } from 'viem'; -import { validParentChainId } from './types/ParentChain'; + import { tokenBridgeCreator } from './contracts'; + +import { Prettify } from './types/utils'; +import { WithTokenBridgeCreatorAddressOverride } from './types/createTokenBridgeTypes'; +import { validParentChainId } from './types/ParentChain'; import { TokenBridgeContracts } from './types/TokenBridgeContracts'; -export type CreateTokenBridgeFetchTokenBridgeContractsParams = { - inbox: Address; - parentChainPublicClient: PublicClient; -}; +export type CreateTokenBridgeFetchTokenBridgeContractsParams = Prettify< + WithTokenBridgeCreatorAddressOverride<{ + inbox: Address; + parentChainPublicClient: PublicClient; + }> +>; export async function createTokenBridgeFetchTokenBridgeContracts({ inbox, parentChainPublicClient, + tokenBridgeCreatorAddressOverride, }: CreateTokenBridgeFetchTokenBridgeContractsParams): Promise { const chainId = parentChainPublicClient.chain?.id; @@ -18,6 +25,9 @@ export async function createTokenBridgeFetchTokenBridgeContracts({ throw new Error('chainId is undefined'); } + const tokenBridgeCreatorAddress = + tokenBridgeCreatorAddressOverride ?? tokenBridgeCreator.address[chainId]; + // getting parent chain addresses const [ parentChainRouter, @@ -26,14 +36,14 @@ export async function createTokenBridgeFetchTokenBridgeContracts({ parentChainWethGateway, parentChainWeth, ] = await parentChainPublicClient.readContract({ - address: tokenBridgeCreator.address[chainId], + address: tokenBridgeCreatorAddress, abi: tokenBridgeCreator.abi, functionName: 'inboxToL1Deployment', args: [inbox], }); const parentChainMulticall = await parentChainPublicClient.readContract({ - address: tokenBridgeCreator.address[chainId], + address: tokenBridgeCreatorAddress, abi: tokenBridgeCreator.abi, functionName: 'l1Multicall', }); @@ -59,7 +69,7 @@ export async function createTokenBridgeFetchTokenBridgeContracts({ orbitChainUpgradeExecutor, orbitChainMulticall, ] = await parentChainPublicClient.readContract({ - address: tokenBridgeCreator.address[chainId], + address: tokenBridgeCreatorAddress, abi: tokenBridgeCreator.abi, functionName: 'inboxToL2Deployment', args: [inbox], diff --git a/src/createTokenBridgePrepareCustomFeeTokenApprovalTransactionRequest.ts b/src/createTokenBridgePrepareCustomFeeTokenApprovalTransactionRequest.ts index dff4bbde..566ac671 100644 --- a/src/createTokenBridgePrepareCustomFeeTokenApprovalTransactionRequest.ts +++ b/src/createTokenBridgePrepareCustomFeeTokenApprovalTransactionRequest.ts @@ -4,18 +4,24 @@ import { approvePrepareTransactionRequest } from './utils/erc20'; import { validParentChainId } from './types/ParentChain'; import { tokenBridgeCreator } from './contracts'; -export type CreateTokenBridgePrepareCustomFeeTokenApprovalTransactionRequestParams = { - amount?: bigint; - nativeToken: Address; - owner: Address; - publicClient: PublicClient; -}; +import { Prettify } from './types/utils'; +import { WithTokenBridgeCreatorAddressOverride } from './types/createTokenBridgeTypes'; + +export type CreateTokenBridgePrepareCustomFeeTokenApprovalTransactionRequestParams = Prettify< + WithTokenBridgeCreatorAddressOverride<{ + amount?: bigint; + nativeToken: Address; + owner: Address; + publicClient: PublicClient; + }> +>; export async function createTokenBridgePrepareCustomFeeTokenApprovalTransactionRequest({ amount = maxInt256, nativeToken, owner, publicClient, + tokenBridgeCreatorAddressOverride, }: CreateTokenBridgePrepareCustomFeeTokenApprovalTransactionRequestParams) { const chainId = publicClient.chain?.id; @@ -26,7 +32,7 @@ export async function createTokenBridgePrepareCustomFeeTokenApprovalTransactionR const request = await approvePrepareTransactionRequest({ address: nativeToken, owner, - spender: tokenBridgeCreator.address[chainId], + spender: tokenBridgeCreatorAddressOverride ?? tokenBridgeCreator.address[chainId], amount, publicClient, }); diff --git a/src/createTokenBridgePrepareTransactionRequest.ts b/src/createTokenBridgePrepareTransactionRequest.ts index 431cbda3..9f102dd0 100644 --- a/src/createTokenBridgePrepareTransactionRequest.ts +++ b/src/createTokenBridgePrepareTransactionRequest.ts @@ -1,10 +1,6 @@ import { Address, PublicClient, encodeFunctionData } from 'viem'; import { tokenBridgeCreator } from './contracts'; -import { - createTokenBridgeDefaultGasLimit, - createTokenBridgeDefaultRetryablesFees, -} from './constants'; import { validParentChainId } from './types/ParentChain'; import { createTokenBridgeGetInputs } from './createTokenBridge-ethers'; import { publicClientToProvider } from './ethers-compat/publicClientToProvider'; @@ -15,6 +11,9 @@ import { applyPercentIncrease, } from './utils/gasOverrides'; +import { Prettify } from './types/utils'; +import { WithTokenBridgeCreatorAddressOverride } from './types/createTokenBridgeTypes'; + export type TransactionRequestRetryableGasOverrides = { maxSubmissionCostForFactory?: GasOverrideOptions; maxGasForFactory?: GasOverrideOptions; @@ -23,6 +22,17 @@ export type TransactionRequestRetryableGasOverrides = { maxGasPrice?: bigint; }; +export type CreateTokenBridgePrepareTransactionRequestParams = Prettify< + WithTokenBridgeCreatorAddressOverride<{ + params: { rollup: Address; rollupOwner: Address }; + parentChainPublicClient: PublicClient; + orbitChainPublicClient: PublicClient; + account: Address; + gasOverrides?: TransactionRequestGasOverrides; + retryableGasOverrides?: TransactionRequestRetryableGasOverrides; + }> +>; + export async function createTokenBridgePrepareTransactionRequest({ params, parentChainPublicClient, @@ -30,20 +40,17 @@ export async function createTokenBridgePrepareTransactionRequest({ account, gasOverrides, retryableGasOverrides, -}: { - params: { rollup: Address; rollupOwner: Address }; - parentChainPublicClient: PublicClient; - orbitChainPublicClient: PublicClient; - account: Address; - gasOverrides?: TransactionRequestGasOverrides; - retryableGasOverrides?: TransactionRequestRetryableGasOverrides; -}) { + tokenBridgeCreatorAddressOverride, +}: CreateTokenBridgePrepareTransactionRequestParams) { const chainId = parentChainPublicClient.chain?.id; if (!validParentChainId(chainId)) { throw new Error('chainId is undefined'); } + const tokenBridgeCreatorAddress = + tokenBridgeCreatorAddressOverride ?? tokenBridgeCreator.address[chainId]; + const parentChainProvider = publicClientToProvider(parentChainPublicClient); const orbitChainProvider = publicClientToProvider(orbitChainPublicClient); @@ -51,7 +58,7 @@ export async function createTokenBridgePrepareTransactionRequest({ account, parentChainProvider, orbitChainProvider, - tokenBridgeCreator.address[chainId], + tokenBridgeCreatorAddress, params.rollup, retryableGasOverrides, ); @@ -63,7 +70,7 @@ export async function createTokenBridgePrepareTransactionRequest({ const request = await parentChainPublicClient.prepareTransactionRequest({ chain: parentChainPublicClient.chain, - to: tokenBridgeCreator.address[chainId], + to: tokenBridgeCreatorAddress, data: encodeFunctionData({ abi: tokenBridgeCreator.abi, functionName: 'createTokenBridge', @@ -71,12 +78,16 @@ export async function createTokenBridgePrepareTransactionRequest({ }), value: chainUsesCustomFee ? 0n : retryableFee, account: account, + // if the base gas limit override was provided, hardcode gas to 0 to skip estimation + // we'll set the actual value in the code below + gas: typeof gasOverrides?.gasLimit?.base !== 'undefined' ? 0n : undefined, }); // potential gas overrides (gas limit) if (gasOverrides && gasOverrides.gasLimit) { request.gas = applyPercentIncrease({ - base: gasOverrides.gasLimit.base ?? request.gas ?? createTokenBridgeDefaultGasLimit, + // the ! is here because we should let it error in case we don't have the estimated gas + base: gasOverrides.gasLimit.base ?? request.gas!, percentIncrease: gasOverrides.gasLimit.percentIncrease, }); } diff --git a/src/index.ts b/src/index.ts index 4f78545e..c18b0ba9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,7 +13,10 @@ import { CreateRollupPrepareCustomFeeTokenApprovalTransactionRequestParams, } from './createRollupPrepareCustomFeeTokenApprovalTransactionRequest'; import { CreateRollupFunctionInputs, CreateRollupParams } from './types/createRollupTypes'; -import { createRollupPrepareTransactionRequest } from './createRollupPrepareTransactionRequest'; +import { + createRollupPrepareTransactionRequest, + CreateRollupPrepareTransactionRequestParams, +} from './createRollupPrepareTransactionRequest'; import { createRollupPrepareTransaction, CreateRollupTransaction, @@ -52,7 +55,10 @@ import { createTokenBridgePrepareCustomFeeTokenApprovalTransactionRequest, CreateTokenBridgePrepareCustomFeeTokenApprovalTransactionRequestParams, } from './createTokenBridgePrepareCustomFeeTokenApprovalTransactionRequest'; -import { createTokenBridgePrepareTransactionRequest } from './createTokenBridgePrepareTransactionRequest'; +import { + createTokenBridgePrepareTransactionRequest, + CreateTokenBridgePrepareTransactionRequestParams, +} from './createTokenBridgePrepareTransactionRequest'; import { createTokenBridgePrepareTransactionReceipt } from './createTokenBridgePrepareTransactionReceipt'; import { createTokenBridgeFetchTokenBridgeContracts } from './createTokenBridgeFetchTokenBridgeContracts'; import { prepareKeyset } from './prepareKeyset'; @@ -60,6 +66,7 @@ import * as utils from './utils'; export { createRollupPrepareTransactionRequest, + CreateRollupPrepareTransactionRequestParams, CreateRollupFunctionInputs, CreateRollupParams, createRollupPrepareConfig, @@ -103,6 +110,7 @@ export { createTokenBridgePrepareCustomFeeTokenApprovalTransactionRequest, CreateTokenBridgePrepareCustomFeeTokenApprovalTransactionRequestParams, createTokenBridgePrepareTransactionRequest, + CreateTokenBridgePrepareTransactionRequestParams, createTokenBridgePrepareTransactionReceipt, createTokenBridgeFetchTokenBridgeContracts, }; diff --git a/src/types/createRollupTypes.ts b/src/types/createRollupTypes.ts index 99bef990..966e6879 100644 --- a/src/types/createRollupTypes.ts +++ b/src/types/createRollupTypes.ts @@ -1,4 +1,4 @@ -import { GetFunctionArgs } from 'viem'; +import { Address, GetFunctionArgs } from 'viem'; import { rollupCreator } from '../contracts'; @@ -11,3 +11,10 @@ type RequiredKeys = 'config' | 'batchPoster' | 'validators'; export type CreateRollupParams = Pick & Partial>; + +export type WithRollupCreatorAddressOverride = T & { + /** + * Specifies a custom address for the RollupCreator. By default, the address will be automatically detected based on the provided chain. + */ + rollupCreatorAddressOverride?: Address; +}; diff --git a/src/types/createTokenBridgeTypes.ts b/src/types/createTokenBridgeTypes.ts new file mode 100644 index 00000000..b2bba1f1 --- /dev/null +++ b/src/types/createTokenBridgeTypes.ts @@ -0,0 +1,8 @@ +import { Address } from 'viem'; + +export type WithTokenBridgeCreatorAddressOverride = T & { + /** + * Specifies a custom address for the TokenBridgeCreator. By default, the address will be automatically detected based on the provided chain. + */ + tokenBridgeCreatorAddressOverride?: Address; +};