Skip to content

Commit

Permalink
Merge branch 'v3'
Browse files Browse the repository at this point in the history
  • Loading branch information
spsjvc committed Oct 15, 2024
2 parents 792a7ee + 647d341 commit 9a30062
Show file tree
Hide file tree
Showing 12 changed files with 529 additions and 85 deletions.
38 changes: 30 additions & 8 deletions .github/workflows/build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -124,25 +124,47 @@ jobs:
run: CI=true yarn test:unit

test-integration:
name: Test (Integration) on Node.js v${{ matrix.node-version }}${{ matrix.orbit-test == '1' && ' with L3' || '' }}${{ matrix.custom-fee == '1' && ' with custom gas token' || '' }}
name: Test (Integration) on Node.js v${{ matrix.node-version }}${{ matrix.orbit-test == '1' && ' with L3' || '' }}${{ matrix.decimals == '16' && ' with custom gas token (16 decimals)' || matrix.decimals == '20' && ' with custom gas token (20 decimals)' || matrix.decimals == '18' && ' with custom gas token (18 decimals)' || '' }}
runs-on: ubuntu-latest
strategy:
fail-fast: false # runs all tests to completion even if one fails
matrix:
node-version: [18, 20]
orbit-test: ['0', '1']
custom-fee: ['0']
include:
- orbit-test: '0'
node-version: 18
- orbit-test: '0'
node-version: 20

- orbit-test: '1'
node-version: 18
- orbit-test: '1'
node-version: 20

- orbit-test: '1'
decimals: 16
node-version: 18
- orbit-test: '1'
decimals: 16
node-version: 20

- orbit-test: '1'
decimals: 18
node-version: 18
- orbit-test: '1'
decimals: 18
node-version: 20

- orbit-test: '1'
custom-fee: '1'
decimals: 20
node-version: 18
- orbit-test: '1'
custom-fee: '1'
decimals: 20
node-version: 20

needs: install
env:
ORBIT_TEST: ${{ matrix.orbit-test }}
DECIMALS: ${{ matrix.decimals || '18' }}
steps:
- name: Checkout
uses: actions/checkout@v3
Expand All @@ -158,9 +180,9 @@ jobs:
- name: Set up the local node
uses: OffchainLabs/actions/run-nitro-test-node@main
with:
nitro-testnode-ref: ed3cda65c4723b58a2f8be0fbc0c41f4ff2609cd
nitro-testnode-ref: adapt-bridge-amount
l3-node: ${{ matrix.orbit-test == '1' }}
args: ${{ matrix.custom-fee == '1' && '--l3-fee-token' || '' }}
args: ${{ matrix.decimals == 16 && '--l3-fee-token --l3-fee-token-decimals 16' || matrix.decimals == 20 && '--l3-fee-token --l3-fee-token-decimals 20' || matrix.decimals == 18 && '--l3-fee-token' || '' }}

- name: Copy .env
run: cp ./.env-sample ./.env
Expand Down
48 changes: 38 additions & 10 deletions src/lib/assetBridger/erc20Bridger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,11 @@ import { OmitTyped, RequiredPick } from '../utils/types'
import { RetryableDataTools } from '../dataEntities/retryableData'
import { EventArgs } from '../dataEntities/event'
import { ParentToChildMessageGasParams } from '../message/ParentToChildMessageCreator'
import { isArbitrumChain } from '../utils/lib'
import {
getNativeTokenDecimals,
isArbitrumChain,
scaleToNativeTokenDecimals,
} from '../utils/lib'
import { L2ERC20Gateway__factory } from '../abi/factories/L2ERC20Gateway__factory'
import { getErc20ParentAddressFromParentToChildTxRequest } from '../utils/calldata'

Expand Down Expand Up @@ -610,7 +614,8 @@ export class Erc20Bridger extends AssetBridger<
* @returns
*/
private getDepositRequestOutboundTransferInnerData(
depositParams: OmitTyped<ParentToChildMessageGasParams, 'deposit'>
depositParams: OmitTyped<ParentToChildMessageGasParams, 'deposit'>,
decimals: number
) {
if (!this.nativeTokenIsEth) {
return defaultAbiCoder.encode(
Expand All @@ -621,9 +626,12 @@ export class Erc20Bridger extends AssetBridger<
// callHookData
'0x',
// nativeTokenTotalFee
depositParams.gasLimit
.mul(depositParams.maxFeePerGas)
.add(depositParams.maxSubmissionCost), // will be zero
scaleToNativeTokenDecimals({
amount: depositParams.gasLimit
.mul(depositParams.maxFeePerGas)
.add(depositParams.maxSubmissionCost), // will be zero
decimals,
}),
]
)
}
Expand Down Expand Up @@ -676,15 +684,22 @@ export class Erc20Bridger extends AssetBridger<
}
}

const decimals = await getNativeTokenDecimals({
l1Provider: parentProvider,
l2Network: this.childNetwork,
})

const depositFunc = (
depositParams: OmitTyped<ParentToChildMessageGasParams, 'deposit'>
) => {
depositParams.maxSubmissionCost =
params.maxSubmissionCost || depositParams.maxSubmissionCost

const iGatewayRouter = L1GatewayRouter__factory.createInterface()
const innerData =
this.getDepositRequestOutboundTransferInnerData(depositParams)
const innerData = this.getDepositRequestOutboundTransferInnerData(
depositParams,
decimals
)

const functionData =
defaultedParams.excessFeeRefundAddress !== defaultedParams.from
Expand Down Expand Up @@ -1080,6 +1095,11 @@ export class AdminErc20Bridger extends Erc20Bridger {
)
}

const nativeTokenDecimals = await getNativeTokenDecimals({
l1Provider: parentProvider,
l2Network: this.childNetwork,
})

type GasParams = {
maxSubmissionCost: BigNumber
gasLimit: BigNumber
Expand Down Expand Up @@ -1114,15 +1134,23 @@ export class AdminErc20Bridger extends Erc20Bridger {
setTokenGas.gasLimit,
setGatewayGas.gasLimit,
doubleFeePerGas,
setTokenDeposit,
setGatewayDeposit,
scaleToNativeTokenDecimals({
amount: setTokenDeposit,
decimals: nativeTokenDecimals,
}),
scaleToNativeTokenDecimals({
amount: setGatewayDeposit,
decimals: nativeTokenDecimals,
}),
parentSenderAddress,
]
)

return {
data,
value: setTokenDeposit.add(setGatewayDeposit),
value: this.nativeTokenIsEth
? setTokenDeposit.add(setGatewayDeposit)
: BigNumber.from(0),
to: parentToken.address,
from,
}
Expand Down
18 changes: 16 additions & 2 deletions src/lib/assetBridger/ethBridger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@ import { SignerProviderUtils } from '../dataEntities/signerOrProvider'
import { MissingProviderArbSdkError } from '../dataEntities/errors'
import { getArbitrumNetwork } from '../dataEntities/networks'
import { ERC20__factory } from '../abi/factories/ERC20__factory'
import { isArbitrumChain } from '../utils/lib'
import {
getNativeTokenDecimals,
isArbitrumChain,
nativeTokenDecimalsTo18Decimals,
} from '../utils/lib'

export type ApproveGasTokenParams = {
/**
Expand Down Expand Up @@ -312,10 +316,20 @@ export class EthBridger extends AssetBridger<
public async getDepositToRequest(
params: EthDepositToRequestParams
): Promise<ParentToChildTransactionRequest> {
const decimals = await getNativeTokenDecimals({
l1Provider: params.parentProvider,
l2Network: this.childNetwork,
})

const amountToBeMintedOnChildChain = nativeTokenDecimalsTo18Decimals({
amount: params.amount,
decimals,
})

const requestParams = {
...params,
to: params.destinationAddress,
l2CallValue: params.amount,
l2CallValue: amountToBeMintedOnChildChain,
callValueRefundAddress: params.destinationAddress,
data: '0x',
}
Expand Down
24 changes: 19 additions & 5 deletions src/lib/message/ParentToChildMessageGasEstimator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ import {
RetryableDataTools,
} from '../dataEntities/retryableData'
import { ParentToChildTransactionRequest } from '../dataEntities/transactionRequest'
import { getBaseFee, isDefined } from '../utils/lib'
import {
getBaseFee,
getNativeTokenDecimals,
isDefined,
scaleToNativeTokenDecimals,
} from '../utils/lib'
import { OmitTyped } from '../utils/types'
import {
ParentToChildMessageGasParams,
Expand Down Expand Up @@ -226,6 +231,12 @@ export class ParentToChildMessageGasEstimator {
const { data } = retryableEstimateData
const gasLimitDefaults = this.applyGasLimitDefaults(options?.gasLimit)

const l2Network = await getArbitrumNetwork(this.childProvider)
const decimals = await getNativeTokenDecimals({
l1Provider: parentProvider,
l2Network,
})

// estimate the child gas price
const maxFeePerGasPromise = this.estimateMaxFeePerGas(options?.maxFeePerGas)

Expand Down Expand Up @@ -260,10 +271,13 @@ export class ParentToChildMessageGasEstimator {

const deposit =
options?.deposit?.base ||
gasLimit
.mul(maxFeePerGas)
.add(maxSubmissionFee)
.add(retryableEstimateData.l2CallValue)
scaleToNativeTokenDecimals({
amount: gasLimit
.mul(maxFeePerGas)
.add(maxSubmissionFee)
.add(retryableEstimateData.l2CallValue),
decimals,
})

return {
gasLimit,
Expand Down
77 changes: 75 additions & 2 deletions src/lib/utils/lib.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { BigNumber, constants } from 'ethers'
import { Provider } from '@ethersproject/abstract-provider'
import { TransactionReceipt, JsonRpcProvider } from '@ethersproject/providers'
import { ArbSdkError } from '../dataEntities/errors'
import { ArbitrumProvider } from './arbProvider'
import { ArbSys__factory } from '../abi/factories/ArbSys__factory'
import { ARB_SYS_ADDRESS } from '../dataEntities/constants'
import { getNitroGenesisBlock } from '../dataEntities/networks'
import { BigNumber } from 'ethers'
import { ArbitrumNetwork, getNitroGenesisBlock } from '../dataEntities/networks'
import { ERC20__factory } from '../abi/factories/ERC20__factory'

export const wait = (ms: number): Promise<void> =>
new Promise(res => setTimeout(res, ms))
Expand Down Expand Up @@ -195,3 +196,75 @@ export const getBlockRangesForL1Block = async (

return [result[0], props.maxArbitrumBlock]
}

export async function getNativeTokenDecimals({
l1Provider,
l2Network,
}: {
l1Provider: Provider
l2Network: ArbitrumNetwork
}) {
const nativeTokenAddress = l2Network.nativeToken

if (!nativeTokenAddress || nativeTokenAddress === constants.AddressZero) {
return 18
}

const nativeTokenContract = ERC20__factory.connect(
nativeTokenAddress,
l1Provider
)

try {
return await nativeTokenContract.decimals()
} catch {
return 0
}
}

export function scaleToNativeTokenDecimals({
amount,
decimals,
}: {
amount: BigNumber
decimals: number
}) {
// do nothing for 18 decimals
if (decimals === 18) {
return amount
}

if (decimals < 18) {
const scaledAmount = amount.div(
BigNumber.from(10).pow(BigNumber.from(18 - decimals))
)
// round up if necessary
if (
scaledAmount
.mul(BigNumber.from(10).pow(BigNumber.from(18 - decimals)))
.lt(amount)
) {
return scaledAmount.add(BigNumber.from(1))
}
return scaledAmount
}

// decimals > 18
return amount.mul(BigNumber.from(10).pow(BigNumber.from(decimals - 18)))
}

export function nativeTokenDecimalsTo18Decimals({
amount,
decimals,
}: {
amount: BigNumber
decimals: number
}) {
if (decimals < 18) {
return amount.mul(BigNumber.from(10).pow(18 - decimals))
} else if (decimals > 18) {
return amount.div(BigNumber.from(10).pow(decimals - 18))
}

return amount
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { expect } from 'chai'
import { ethers, constants, Wallet } from 'ethers'
import dotenv from 'dotenv'

import { parseEther } from '@ethersproject/units'
import { parseEther, parseUnits } from '@ethersproject/units'

import {
fundParentSigner as fundParentSignerEther,
Expand All @@ -32,6 +32,7 @@ import {
import { describeOnlyWhenCustomGasToken } from './mochaExtensions'
import { ChildToParentMessageStatus } from '../../../src'
import { ChildToParentMessage } from '../../../src/lib/message/ChildToParentMessage'
import { getNativeTokenDecimals } from '../../../src/lib/utils/lib'

dotenv.config()

Expand All @@ -50,9 +51,18 @@ describeOnlyWhenCustomGasToken(
})

it('approves the custom fee token to be spent by the Inbox on the parent chain (arbitrary amount, using params)', async function () {
const { ethBridger, nativeTokenContract, parentSigner } =
await testSetup()
const amount = ethers.utils.parseEther('1')
const {
ethBridger,
nativeTokenContract,
parentSigner,
parentProvider,
childChain,
} = await testSetup()
const decimals = await getNativeTokenDecimals({
l1Provider: parentProvider,
l2Network: childChain,
})
const amount = ethers.utils.parseUnits('1', decimals)

await fundParentSignerEther(parentSigner)
await fundParentCustomFeeToken(parentSigner)
Expand Down Expand Up @@ -164,11 +174,17 @@ describeOnlyWhenCustomGasToken(
parentProvider,
childSigner,
childProvider,
childChain,
ethBridger,
nativeTokenContract,
} = await testSetup()
const decimals = await getNativeTokenDecimals({
l1Provider: parentProvider,
l2Network: childChain,
})

const bridge = ethBridger.childNetwork.ethBridge.bridge
const amount = parseEther('0.2')
const amount = parseUnits('0.2', decimals)

await fundParentSignerEther(parentSigner)
await fundChildCustomFeeToken(childSigner)
Expand Down
Loading

0 comments on commit 9a30062

Please sign in to comment.