UNPKG

@arbitrum/sdk

Version:

Typescript library client-side interactions with Arbitrum

538 lines (537 loc) 20.2 kB
import { Provider, TransactionRequest } from '@ethersproject/abstract-provider'; import { BigNumber, BigNumberish, Overrides, PayableOverrides, Signer, ethers } from 'ethers'; import { IERC20 } from '../abi/IERC20'; import { L2GatewayToken } from '../abi/L2GatewayToken'; import { IL1Teleporter } from '../abi/IL1Teleporter'; import { ArbitrumNetwork, Teleporter } from '../dataEntities/networks'; import { SignerOrProvider } from '../dataEntities/signerOrProvider'; import { ParentToChildTransactionRequest } from '../dataEntities/transactionRequest'; import { ParentToChildMessageReader } from '../message/ParentToChildMessage'; import { GasOverrides, PercentIncrease } from '../message/ParentToChildMessageGasEstimator'; import { ParentContractCallTransaction, ParentContractCallTransactionReceipt } from '../message/ParentTransaction'; import { Erc20Bridger } from './erc20Bridger'; import { OmitTyped } from '../utils/types'; import { IL2Forwarder } from '../abi/IL2Forwarder'; import { RetryableMessageParams } from '../dataEntities/message'; type PickedTransactionRequest = Required<Pick<TransactionRequest, 'to' | 'data' | 'value'>>; export declare enum TeleportationType { /** * Teleporting to an ETH fee L3 */ Standard = 0, /** * Teleporting the fee token to a custom fee L3 */ OnlyGasToken = 1, /** * Teleporting a non-fee token to a custom fee L3 */ NonGasTokenToCustomGas = 2 } export type TxRequestParams = { txRequest: PickedTransactionRequest; l1Signer: Signer; overrides?: PayableOverrides; }; type RetryableGasValues = { gasLimit: BigNumber; maxSubmissionFee: BigNumber; }; export type DepositRequestResult = { txRequest: PickedTransactionRequest; gasTokenAmount: BigNumber; }; export type TeleporterRetryableGasOverride = { gasLimit?: PercentIncrease & { /** * Set a minimum max gas */ min?: BigNumber; }; maxSubmissionFee?: PercentIncrease; }; export type TokenApproveParams = { /** * L1 address of the ERC20 token contract */ erc20L1Address: string; /** * Amount to approve. Defaults to max int. */ amount?: BigNumber; }; export type Erc20L1L3DepositRequestRetryableOverrides = { /** * Optional L1 gas price override. Used to estimate submission fees. */ l1GasPrice?: PercentIncrease; /** * Optional L2 gas price override */ l2GasPrice?: PercentIncrease; /** * Optional L3 gas price override */ l3GasPrice?: PercentIncrease; /** * L2ForwarderFactory retryable gas override */ l2ForwarderFactoryRetryableGas?: TeleporterRetryableGasOverride; /** * L1 to L2 fee token bridge retryable gas override */ l1l2GasTokenBridgeRetryableGas?: TeleporterRetryableGasOverride; /** * L1 to L2 token bridge retryable gas override */ l1l2TokenBridgeRetryableGas?: TeleporterRetryableGasOverride; /** * L2 to L3 token bridge retryable gas override */ l2l3TokenBridgeRetryableGas?: TeleporterRetryableGasOverride; }; export type Erc20L1L3DepositRequestParams = { /** * Address of L1 token */ erc20L1Address: string; /** * Amount of L1 token to send to L3 */ amount: BigNumber; /** * L2 provider */ l2Provider: Provider; /** * L3 provider */ l3Provider: Provider; /** * If the L3 uses a custom fee token, skip payment for L2 to L3 retryable even if the fee token is available on L1 * * If payment is skipped, the teleportation will not be completed until the L2 to L3 retryable is manually redeemed * * Defaults to false */ skipGasToken?: boolean; /** * Optional recipient on L3, defaults to signer's address */ destinationAddress?: string; /** * Optional overrides for retryable gas parameters */ retryableOverrides?: Erc20L1L3DepositRequestRetryableOverrides; }; export type TxReference = { txHash: string; } | { tx: ParentContractCallTransaction; } | { txReceipt: ParentContractCallTransactionReceipt; }; export type GetL1L3DepositStatusParams = { l1Provider: Provider; l2Provider: Provider; l3Provider: Provider; } & TxReference; export type Erc20L1L3DepositStatus = { /** * L1 to L2 token bridge message */ l1l2TokenBridgeRetryable: ParentToChildMessageReader; /** * L1 to L2 fee token bridge message */ l1l2GasTokenBridgeRetryable: ParentToChildMessageReader | undefined; /** * L2ForwarderFactory message */ l2ForwarderFactoryRetryable: ParentToChildMessageReader; /** * L2 to L3 token bridge message */ l2l3TokenBridgeRetryable: ParentToChildMessageReader | undefined; /** * Indicates that the L2ForwarderFactory call was front ran by another teleportation. * * This is true if: * - l1l2TokenBridgeRetryable status is REDEEMED; AND * - l2ForwarderFactoryRetryable status is FUNDS_DEPOSITED_ON_CHILD; AND * - L2Forwarder token balance is 0 * * The first teleportation with l2ForwarderFactoryRetryable redemption *after* this teleportation's l1l2TokenBridgeRetryable redemption * is the one that completes this teleportation. * * If that subsequent teleportation is complete, this one is considered complete as well. */ l2ForwarderFactoryRetryableFrontRan: boolean; /** * Whether the teleportation has completed. */ completed: boolean; }; export type EthL1L3DepositRequestParams = { /** * Amount of ETH to send to L3 */ amount: BigNumberish; /** * L2 provider */ l2Provider: Provider; /** * L3 provider */ l3Provider: Provider; /** * Optional recipient on L3, defaults to signer's address */ destinationAddress?: string; /** * Optional fee refund address on L2, defaults to signer's address */ l2RefundAddress?: string; /** * Optional gas overrides for L1 to L2 message */ l2TicketGasOverrides?: Omit<GasOverrides, 'deposit'>; /** * Optional gas overrides for L2 to L3 message */ l3TicketGasOverrides?: Omit<GasOverrides, 'deposit'>; }; export type EthL1L3DepositStatus = { /** * L1 to L2 message */ l2Retryable: ParentToChildMessageReader; /** * L2 to L3 message */ l3Retryable: ParentToChildMessageReader | undefined; /** * Whether the teleportation has completed */ completed: boolean; }; /** * Base functionality for L1 to L3 bridging. */ declare class BaseL1L3Bridger { readonly l1Network: { chainId: number; }; readonly l2Network: ArbitrumNetwork; readonly l3Network: ArbitrumNetwork; readonly defaultGasPricePercentIncrease: BigNumber; readonly defaultGasLimitPercentIncrease: BigNumber; constructor(l3Network: ArbitrumNetwork); /** * Check the signer/provider matches the l1Network, throws if not * @param sop */ protected _checkL1Network(sop: SignerOrProvider): Promise<void>; /** * Check the signer/provider matches the l2Network, throws if not * @param sop */ protected _checkL2Network(sop: SignerOrProvider): Promise<void>; /** * Check the signer/provider matches the l3Network, throws if not * @param sop */ protected _checkL3Network(sop: SignerOrProvider): Promise<void>; protected _percentIncrease(num: BigNumber, increase: BigNumber): BigNumber; protected _getTxHashFromTxRef(txRef: TxReference): string; protected _getTxFromTxRef(txRef: TxReference, provider: Provider): Promise<ParentContractCallTransaction>; protected _getTxReceiptFromTxRef(txRef: TxReference, provider: Provider): Promise<ParentContractCallTransactionReceipt>; } /** * Bridger for moving ERC20 tokens from L1 to L3 */ export declare class Erc20L1L3Bridger extends BaseL1L3Bridger { /** * Addresses of teleporter contracts on L2 */ readonly teleporter: Teleporter; /** * Default gas limit for L2ForwarderFactory.callForwarder of 1,000,000 * * Measured Standard: 361746 * * Measured OnlyGasToken: 220416 * * Measured NonGasTokenToCustomGas: 373449 */ readonly l2ForwarderFactoryDefaultGasLimit: BigNumber; readonly skipL1GasTokenMagic: string; /** * If the L3 network uses a custom (non-eth) fee token, this is the address of that token on L2 */ readonly l2GasTokenAddress: string | undefined; protected readonly l2Erc20Bridger: Erc20Bridger; protected readonly l3Erc20Bridger: Erc20Bridger; /** * If the L3 network uses a custom fee token, this is the address of that token on L1 */ protected _l1FeeTokenAddress: string | undefined; constructor(l3Network: ArbitrumNetwork); /** * If the L3 network uses a custom gas token, return the address of that token on L1. * If the fee token is not available on L1, does not use 18 decimals on L1 and L2, or the L3 network uses ETH for fees, throw. */ getGasTokenOnL1(l1Provider: Provider, l2Provider: Provider): Promise<string>; /** * Get the corresponding L2 token address for the provided L1 token */ getL2Erc20Address(erc20L1Address: string, l1Provider: Provider): Promise<string>; /** * Get the corresponding L3 token address for the provided L1 token */ getL3Erc20Address(erc20L1Address: string, l1Provider: Provider, l2Provider: Provider): Promise<string>; /** * Given an L1 token's address, get the address of the token's L1 <-> L2 gateway on L1 */ getL1L2GatewayAddress(erc20L1Address: string, l1Provider: Provider): Promise<string>; /** * Get the address of the L2 <-> L3 gateway on L2 given an L1 token address */ getL2L3GatewayAddress(erc20L1Address: string, l1Provider: Provider, l2Provider: Provider): Promise<string>; /** * Get the L1 token contract at the provided address * Note: This function just returns a typed ethers object for the provided address, it doesn't * check the underlying form of the contract bytecode to see if it's an erc20, and doesn't ensure the validity * of any of the underlying functions on that contract. */ getL1TokenContract(l1TokenAddr: string, l1Provider: Provider): IERC20; /** * Get the L2 token contract at the provided address * Note: This function just returns a typed ethers object for the provided address, it doesn't * check the underlying form of the contract bytecode to see if it's an erc20, and doesn't ensure the validity * of any of the underlying functions on that contract. */ getL2TokenContract(l2TokenAddr: string, l2Provider: Provider): L2GatewayToken; /** * Get the L3 token contract at the provided address * Note: This function just returns a typed ethers object for the provided address, it doesn't * check the underlying form of the contract bytecode to see if it's an erc20, and doesn't ensure the validity * of any of the underlying functions on that contract. */ getL3TokenContract(l3TokenAddr: string, l3Provider: Provider): L2GatewayToken; /** * Whether the L1 token has been disabled on the L1 <-> L2 router given an L1 token address */ l1TokenIsDisabled(l1TokenAddress: string, l1Provider: Provider): Promise<boolean>; /** * Whether the L2 token has been disabled on the L2 <-> L3 router given an L2 token address */ l2TokenIsDisabled(l2TokenAddress: string, l2Provider: Provider): Promise<boolean>; /** * Given some L2Forwarder parameters, get the address of the L2Forwarder contract */ l2ForwarderAddress(owner: string, routerOrInbox: string, destinationAddress: string, l1OrL2Provider: Provider): Promise<string>; /** * Get a tx request to approve tokens for teleportation. * The tokens will be approved for L1Teleporter. */ getApproveTokenRequest(params: TokenApproveParams): Promise<PickedTransactionRequest>; /** * Approve tokens for teleportation. * The tokens will be approved for L1Teleporter. */ approveToken(params: (TokenApproveParams & { l1Signer: Signer; overrides?: Overrides; }) | TxRequestParams): Promise<ethers.ContractTransaction>; /** * Get a tx request to approve the L3's fee token for teleportation. * The tokens will be approved for L1Teleporter. * Will throw if the L3 network uses ETH for fees or the fee token doesn't exist on L1. */ getApproveGasTokenRequest(params: { l1Provider: Provider; l2Provider: Provider; amount?: BigNumber; }): Promise<PickedTransactionRequest>; /** * Approve the L3's fee token for teleportation. * The tokens will be approved for L1Teleporter. * Will throw if the L3 network uses ETH for fees or the fee token doesn't exist on L1. */ approveGasToken(params: { l1Signer: Signer; l2Provider: Provider; amount?: BigNumber; overrides?: Overrides; } | TxRequestParams): Promise<ethers.ContractTransaction>; /** * Get a tx request for teleporting some tokens from L1 to L3. * Also returns the amount of fee tokens required for teleportation. */ getDepositRequest(params: Erc20L1L3DepositRequestParams & ({ from: string; l1Provider: Provider; } | { l1Signer: Signer; })): Promise<DepositRequestResult>; /** * Execute a teleportation of some tokens from L1 to L3. */ deposit(params: (Erc20L1L3DepositRequestParams & { l1Signer: Signer; overrides?: PayableOverrides; }) | TxRequestParams): Promise<ParentContractCallTransaction>; /** * Given a teleportation tx, get the L1Teleporter parameters, L2Forwarder parameters, and L2Forwarder address */ getDepositParameters(params: { l1Provider: Provider; l2Provider: Provider; } & TxReference): Promise<{ teleportParams: IL1Teleporter.TeleportParamsStruct; l2ForwarderParams: IL2Forwarder.L2ForwarderParamsStruct; l2ForwarderAddress: Promise<string>; }>; /** * Fetch the cross chain messages and their status * * Can provide either the txHash, the tx, or the txReceipt */ getDepositStatus(params: GetL1L3DepositStatusParams): Promise<Erc20L1L3DepositStatus>; /** * Get the type of teleportation from the l1Token and l3FeeTokenL1Addr teleport parameters */ teleportationType(partialTeleportParams: Pick<IL1Teleporter.TeleportParamsStruct, 'l3FeeTokenL1Addr' | 'l1Token'>): TeleportationType; /** * Estimate the gasLimit and maxSubmissionFee for a token bridge retryable */ protected _getTokenBridgeGasEstimates(params: { parentProvider: Provider; childProvider: Provider; parentGasPrice: BigNumber; parentErc20Address: string; parentGatewayAddress: string; from: string; to: string; amount: BigNumber; isWeth: boolean; }): Promise<RetryableGasValues>; /** * Estimate the gasLimit and maxSubmissionFee for the L1 to L2 token bridge leg of a teleportation */ protected _getL1L2TokenBridgeGasEstimates(params: { l1Token: string; amount: BigNumberish; l1GasPrice: BigNumber; l2ForwarderAddress: string; l1Provider: Provider; l2Provider: Provider; }): Promise<RetryableGasValues>; /** * Estimate the gasLimit and maxSubmissionFee for the L1 to L2 fee token bridge leg of a teleportation */ protected _getL1L2FeeTokenBridgeGasEstimates(params: { l1GasPrice: BigNumber; feeTokenAmount: BigNumber; l3FeeTokenL1Addr: string; l2ForwarderAddress: string; l1Provider: Provider; l2Provider: Provider; }): Promise<RetryableGasValues>; /** * Estimate the gasLimit and maxSubmissionFee for L2ForwarderFactory.callForwarder leg of a teleportation. * Gas limit is hardcoded to 1,000,000 */ protected _getL2ForwarderFactoryGasEstimates(l1GasPrice: BigNumber, l1Provider: Provider): Promise<RetryableGasValues>; /** * Estimate the gasLimit and maxSubmissionFee for the L2 -> L3 leg of a teleportation. */ protected _getL2L3BridgeGasEstimates(params: { partialTeleportParams: OmitTyped<IL1Teleporter.TeleportParamsStruct, 'gasParams'>; l2GasPrice: BigNumber; l1Provider: Provider; l2Provider: Provider; l3Provider: Provider; l2ForwarderAddress: string; }): Promise<RetryableGasValues>; /** * Given TeleportParams without the gas parameters, return TeleportParams with gas parameters populated. * Does not modify the input parameters. */ protected _fillPartialTeleportParams(partialTeleportParams: OmitTyped<IL1Teleporter.TeleportParamsStruct, 'gasParams'>, retryableOverrides: Erc20L1L3DepositRequestRetryableOverrides, l1Provider: Provider, l2Provider: Provider, l3Provider: Provider): Promise<{ teleportParams: { gasParams: IL1Teleporter.RetryableGasParamsStruct; to: string; amount: BigNumberish; l1Token: string; l3FeeTokenL1Addr: string; l1l2Router: string; l2l3RouterOrInbox: string; }; costs: [BigNumber, BigNumber, number, IL1Teleporter.RetryableGasCostsStructOutput] & { ethAmount: BigNumber; feeTokenAmount: BigNumber; teleportationType: number; costs: IL1Teleporter.RetryableGasCostsStructOutput; }; }>; /** * @returns The size of the calldata for a call to L2ForwarderFactory.callForwarder */ protected _l2ForwarderFactoryCalldataSize(): number; /** * Given raw calldata for a teleport tx, decode the teleport parameters */ protected _decodeTeleportCalldata(data: string): IL1Teleporter.TeleportParamsStruct; /** * Given raw calldata for a callForwarder call, decode the parameters */ protected _decodeCallForwarderCalldata(data: string): IL2Forwarder.L2ForwarderParamsStruct; protected _getL1ToL2Messages(l1TxReceipt: ParentContractCallTransactionReceipt, l2Provider: Provider): Promise<{ l1l2TokenBridgeRetryable: ParentToChildMessageReader; l1l2GasTokenBridgeRetryable: ParentToChildMessageReader | undefined; l2ForwarderFactoryRetryable: ParentToChildMessageReader; }>; } /** * Bridge ETH from L1 to L3 using a double retryable ticket */ export declare class EthL1L3Bridger extends BaseL1L3Bridger { constructor(l3Network: ArbitrumNetwork); /** * Get a tx request to deposit ETH to L3 via a double retryable ticket */ getDepositRequest(params: EthL1L3DepositRequestParams & ({ from: string; l1Provider: Provider; } | { l1Signer: Signer; })): Promise<ParentToChildTransactionRequest>; /** * Deposit ETH to L3 via a double retryable ticket */ deposit(params: (EthL1L3DepositRequestParams & { l1Signer: Signer; overrides?: PayableOverrides; }) | TxRequestParams): Promise<ParentContractCallTransaction>; /** * Given an L1 transaction, get the retryable parameters for both l2 and l3 tickets */ getDepositParameters(params: { l1Provider: Provider; } & TxReference): Promise<{ l1l2TicketData: RetryableMessageParams; l2l3TicketData: RetryableMessageParams; }>; /** * Get the status of a deposit given an L1 tx receipt. Does not check if the tx is actually a deposit tx. * * @return Information regarding each step of the deposit * and `EthL1L3DepositStatus.completed` which indicates whether the deposit has fully completed. */ getDepositStatus(params: GetL1L3DepositStatusParams): Promise<EthL1L3DepositStatus>; protected _decodeCreateRetryableTicket(data: string): OmitTyped<RetryableMessageParams, 'l1Value'>; } export {};