diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml
index 8624ee7a07..ae50d87f53 100644
--- a/.github/workflows/e2e-tests.yml
+++ b/.github/workflows/e2e-tests.yml
@@ -33,7 +33,7 @@ jobs:
secrets: inherit
test-e2e:
- name: "${{ matrix.test.name }}${{ matrix.test.type == 'orbit-eth' && ' with L3' || matrix.test.type == 'orbit-custom' && ' with custom fee token' || ''}}"
+ name: "Test E2E - ${{ matrix.test.name }} ${{ matrix.test.typeName }}"
needs: [build, load-e2e-files]
runs-on: ubuntu-latest
strategy:
@@ -100,16 +100,25 @@ jobs:
nitro-testnode-ref: badbcbea9b43d46e115da4d7c9f2f57c31af8431
l3-node: ${{ matrix.test.type != 'regular' }}
no-l3-token-bridge: ${{ matrix.test.type == 'regular' }}
- args: ${{ matrix.test.type == 'orbit-custom' && '--l3-fee-token' || '' }}
+ args: >-
+ ${{
+ (matrix.test.type == 'orbit-eth') && '--l3node --l3-token-bridge' ||
+ (matrix.test.type == 'orbit-custom-6dec' && '--l3-fee-token --l3-fee-token-decimals 6') ||
+ (matrix.test.type == 'orbit-custom-18dec' && '--l3-fee-token') ||
+ (matrix.test.type == 'orbit-custom-20dec' && '--l3-fee-token --l3-fee-token-decimals 20') ||
+ ''
+ }}
- name: Run e2e tests via cypress-io/github-action
uses: cypress-io/github-action@0da3c06ed8217b912deea9d8ee69630baed1737e # pin@v6.7.6
with:
start: yarn start
command: >-
- ${{
+ ${{
(matrix.test.type == 'orbit-eth') && 'yarn test:e2e:orbit --browser chrome' ||
- (matrix.test.type == 'orbit-custom' && 'yarn test:e2e:orbit:custom-gas-token --browser chrome') ||
+ (matrix.test.type == 'orbit-custom-6dec' && 'yarn test:e2e:orbit:custom-gas-token --browser chrome') ||
+ (matrix.test.type == 'orbit-custom-18dec' && 'yarn test:e2e:orbit:custom-gas-token --browser chrome') ||
+ (matrix.test.type == 'orbit-custom-20dec' && 'yarn test:e2e:orbit:custom-gas-token --browser chrome') ||
(matrix.test.type == 'cctp' && 'yarn test:e2e:cctp --browser chrome') ||
'yarn test:e2e --browser chrome'
}}
@@ -134,7 +143,7 @@ jobs:
uses: actions/upload-artifact@v4
if: always()
with:
- name: e2e-artifacts-${{ github.sha }}-${{ matrix.test.name }}-${{ (matrix.test.type == 'cctp' && 'cctp') || (matrix.test.type == 'orbit-eth' && 'l3') || (matrix.test.type == 'orbit-custom' && 'custom-fee-token') || 'regular'}}
+ name: e2e-artifacts-${{ github.sha }}-${{ matrix.test.name }}-${{ matrix.test.type }}
path: |
./packages/arb-token-bridge-ui/cypress/videos
./packages/arb-token-bridge-ui/cypress/screenshots
diff --git a/.github/workflows/formatSpecfiles.js b/.github/workflows/formatSpecfiles.js
index bb6b23e1ef..3d1976daae 100644
--- a/.github/workflows/formatSpecfiles.js
+++ b/.github/workflows/formatSpecfiles.js
@@ -11,14 +11,27 @@ switch (testType) {
tests.push({
...spec,
type: "regular",
+ typeName: "",
});
tests.push({
...spec,
type: "orbit-eth",
+ typeName: "with L3 (ETH)",
});
tests.push({
...spec,
- type: "orbit-custom",
+ type: "orbit-custom-6dec",
+ typeName: "with L3 (6 decimals custom)",
+ });
+ tests.push({
+ ...spec,
+ type: "orbit-custom-18dec",
+ typeName: "with L3 (18 decimals custom)",
+ });
+ tests.push({
+ ...spec,
+ type: "orbit-custom-20dec",
+ typeName: "with L3 (20 decimals custom)",
});
});
break;
@@ -27,6 +40,7 @@ switch (testType) {
// Running CCTP tests in parallel cause nonce issues, we're running the two tests sequentially
tests.push({
name: "cctp",
+ typeName: "",
file: "tests/e2e/specs/**/*Cctp.cy.{js,jsx,ts,tsx}",
recordVideo: false,
type: "cctp",
diff --git a/packages/arb-token-bridge-ui/package.json b/packages/arb-token-bridge-ui/package.json
index 6e272c5df7..e8d292c70b 100644
--- a/packages/arb-token-bridge-ui/package.json
+++ b/packages/arb-token-bridge-ui/package.json
@@ -5,7 +5,7 @@
"private": true,
"dependencies": {
"@apollo/client": "^3.7.11",
- "@arbitrum/sdk": "^4.0.1",
+ "@arbitrum/sdk": "^4.0.2-beta.1",
"@ethersproject/providers": "^5.7.0",
"@headlessui/react": "^1.7.8",
"@headlessui/tailwindcss": "^0.1.2",
diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenRow.tsx b/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenRow.tsx
index 6017331763..3cc1bbe3d2 100644
--- a/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenRow.tsx
+++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/TokenRow.tsx
@@ -32,6 +32,7 @@ import { useNetworks } from '../../hooks/useNetworks'
import { useNetworksRelationship } from '../../hooks/useNetworksRelationship'
import { TokenLogoFallback } from './TokenInfo'
import { useBalanceOnSourceChain } from '../../hooks/useBalanceOnSourceChain'
+import { useNativeCurrencyDecimalsOnSourceChain } from '../../hooks/useNativeCurrencyDecimalsOnSourceChain'
function tokenListIdsToNames(ids: number[]): string {
return ids
@@ -244,6 +245,8 @@ function TokenBalance({ token }: { token: ERC20BridgeToken | null }) {
} = useAppState()
const { isLoading: isLoadingAccountType } = useAccountType()
const { balance, symbol } = useTokenInfo(token)
+ const nativeCurrencyDecimalsOnSourceChain =
+ useNativeCurrencyDecimalsOnSourceChain()
const isArbitrumNativeUSDC =
isTokenArbitrumOneNativeUSDC(token?.address) ||
@@ -266,6 +269,13 @@ function TokenBalance({ token }: { token: ERC20BridgeToken | null }) {
return typeof bridgeTokens[token.address] !== 'undefined'
}, [bridgeTokens, isArbitrumNativeUSDC, token])
+ const decimals = useMemo(() => {
+ if (token) {
+ return token.decimals
+ }
+ return nativeCurrencyDecimalsOnSourceChain
+ }, [nativeCurrencyDecimalsOnSourceChain, token])
+
if (!tokenIsAddedToTheBridge) {
return Import
}
@@ -279,7 +289,7 @@ function TokenBalance({ token }: { token: ERC20BridgeToken | null }) {
{balance ? (
formatAmount(balance, {
- decimals: token?.decimals,
+ decimals,
symbol
})
) : (
diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanel.tsx b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanel.tsx
index 74c4a4c788..a631d602f7 100644
--- a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanel.tsx
+++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanel.tsx
@@ -6,6 +6,7 @@ import { useLatest } from 'react-use'
import { useAccount, useNetwork, useSigner } from 'wagmi'
import { TransactionResponse } from '@ethersproject/providers'
import { twMerge } from 'tailwind-merge'
+import { scaleFrom18DecimalsToNativeTokenDecimals } from '@arbitrum/sdk'
import { useAppState } from '../../state'
import { getNetworkName, isNetwork } from '../../util/networks'
@@ -77,6 +78,7 @@ import { useIsTransferAllowed } from './hooks/useIsTransferAllowed'
import { MoveFundsButton } from './MoveFundsButton'
import { ProjectsListing } from '../common/ProjectsListing'
import { useAmountBigNumber } from './hooks/useAmountBigNumber'
+import { useNativeCurrencyDecimalsOnSourceChain } from '../../hooks/useNativeCurrencyDecimalsOnSourceChain'
const signerUndefinedError = 'Signer is undefined'
const transferNotAllowedError = 'Transfer not allowed'
@@ -131,6 +133,8 @@ export function TransferPanel() {
}
} = useLatest(useNetworksRelationship(latestNetworks.current))
const isBatchTransferSupported = useIsBatchTransferSupported()
+ const nativeCurrencyDecimalsOnSourceChain =
+ useNativeCurrencyDecimalsOnSourceChain()
const nativeCurrency = useNativeCurrency({ provider: childChainProvider })
@@ -616,7 +620,7 @@ export function TransferPanel() {
amount: amountBigNumber,
options: {
approvalAmountIncrease: isCustomNativeTokenAmount2
- ? utils.parseUnits(amount2, nativeCurrency.decimals)
+ ? utils.parseUnits(amount2, nativeCurrencyDecimalsOnSourceChain)
: undefined
}
})
@@ -631,7 +635,7 @@ export function TransferPanel() {
amount: amountBigNumber,
options: {
approvalAmountIncrease: isCustomNativeTokenAmount2
- ? utils.parseUnits(amount2, nativeCurrency.decimals)
+ ? utils.parseUnits(amount2, nativeCurrencyDecimalsOnSourceChain)
: undefined
}
})
@@ -744,6 +748,7 @@ export function TransferPanel() {
}
overrides.maxSubmissionCost = utils
+ // we are not scaling these to native decimals because arbitrum-sdk does it for us
.parseEther(amount2)
.add(gasEstimates.estimatedChildChainSubmissionCost)
overrides.excessFeeRefundAddress = destinationAddress
@@ -798,6 +803,20 @@ export function TransferPanel() {
const timestampCreated = String(normalizeTimestamp(Date.now()))
+ const { isOrbitChain: isSourceOrbitChain } = isNetwork(
+ latestNetworks.current.sourceChain.id
+ )
+
+ const scaledAmount =
+ // only scale for native tokens, and
+ // only scale if sent from Orbit, because it's always 18 decimals there but the UI needs scaled amount
+ selectedToken || !isSourceOrbitChain
+ ? amountBigNumber
+ : scaleFrom18DecimalsToNativeTokenDecimals({
+ amount: amountBigNumber,
+ decimals: nativeCurrency.decimals
+ })
+
const txHistoryCompatibleObject = convertBridgeSdkToMergedTransaction({
bridgeTransfer,
parentChainId: parentChain.id,
@@ -806,7 +825,7 @@ export function TransferPanel() {
walletAddress,
destinationAddress,
nativeCurrency,
- amount: amountBigNumber,
+ amount: scaledAmount,
amount2: isBatchTransfer ? utils.parseEther(amount2) : undefined,
timestampCreated
})
@@ -825,7 +844,7 @@ export function TransferPanel() {
walletAddress,
destinationAddress,
nativeCurrency,
- amount: amountBigNumber,
+ amount: scaledAmount,
amount2: isBatchTransfer ? utils.parseEther(amount2) : undefined,
timestampCreated
})
diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelMain/SourceNetworkBox.tsx b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelMain/SourceNetworkBox.tsx
index 48d493e25c..36f858e22d 100644
--- a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelMain/SourceNetworkBox.tsx
+++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelMain/SourceNetworkBox.tsx
@@ -33,6 +33,7 @@ import { Button } from '../../common/Button'
import { useSelectedTokenDecimals } from '../../../hooks/TransferPanel/useSelectedTokenDecimals'
import { useNativeCurrencyBalances } from './useNativeCurrencyBalances'
import { useIsCctpTransfer } from '../hooks/useIsCctpTransfer'
+import { useNativeCurrencyDecimalsOnSourceChain } from '../../../hooks/useNativeCurrencyDecimalsOnSourceChain'
function Amount2ToggleButton({
onClick
@@ -92,6 +93,8 @@ export function SourceNetworkBox() {
const decimals = useSelectedTokenDecimals()
const { errorMessages } = useTransferReadiness()
const nativeCurrencyBalances = useNativeCurrencyBalances()
+ const nativeCurrencyDecimalsOnSourceChain =
+ useNativeCurrencyDecimalsOnSourceChain()
const isCctpTransfer = useIsCctpTransfer()
@@ -145,10 +148,19 @@ export function SourceNetworkBox() {
symbol: nativeCurrency.symbol,
disabled: true,
balance: nativeCurrencyBalances.sourceBalance
- ? Number(utils.formatEther(nativeCurrencyBalances.sourceBalance))
+ ? Number(
+ utils.formatUnits(
+ nativeCurrencyBalances.sourceBalance,
+ nativeCurrencyDecimalsOnSourceChain
+ )
+ )
: undefined
}),
- [nativeCurrencyBalances, nativeCurrency.symbol]
+ [
+ nativeCurrencyBalances,
+ nativeCurrency.symbol,
+ nativeCurrencyDecimalsOnSourceChain
+ ]
)
return (
diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelMain/TokenBalance.tsx b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelMain/TokenBalance.tsx
index 1e56d31e81..24f66b7437 100644
--- a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelMain/TokenBalance.tsx
+++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelMain/TokenBalance.tsx
@@ -1,12 +1,18 @@
+import { useMemo } from 'react'
import { BigNumber } from 'ethers'
import { ERC20BridgeToken } from '../../../hooks/arbTokenBridge.types'
-import { NativeCurrencyErc20 } from '../../../hooks/useNativeCurrency'
+import {
+ NativeCurrencyErc20,
+ useNativeCurrency
+} from '../../../hooks/useNativeCurrency'
import { Loader } from '../../common/atoms/Loader'
import { TokenSymbolWithExplorerLink } from '../../common/TokenSymbolWithExplorerLink'
import { formatAmount } from '../../../util/NumberUtils'
import { NetworkType } from './utils'
+import { useNetworks } from '../../../hooks/useNetworks'
+import { useNetworksRelationship } from '../../../hooks/useNetworksRelationship'
export function TokenBalance({
forToken,
@@ -22,6 +28,23 @@ export function TokenBalance({
tokenSymbolOverride?: string
}) {
const isParentChain = on === NetworkType.parentChain
+ const [networks] = useNetworks()
+ const { childChainProvider } = useNetworksRelationship(networks)
+ const nativeCurrency = useNativeCurrency({
+ provider: childChainProvider
+ })
+
+ const isCustomNativeCurrency =
+ nativeCurrency.isCustom &&
+ forToken?.address.toLowerCase() === nativeCurrency.address.toLowerCase()
+
+ const decimals = useMemo(() => {
+ if (!isParentChain && isCustomNativeCurrency) {
+ // Native currency on Orbit chain, always 18 decimals
+ return 18
+ }
+ return forToken?.decimals
+ }, [forToken?.decimals, isCustomNativeCurrency, isParentChain])
if (!forToken) {
return null
@@ -43,7 +66,7 @@ export function TokenBalance({
{prefix}
{formatAmount(balance, {
- decimals: forToken.decimals
+ decimals
})}
{' '}
{
diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelMainInput.tsx b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelMainInput.tsx
index 414dc3303f..e6365719d6 100644
--- a/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelMainInput.tsx
+++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/TransferPanelMainInput.tsx
@@ -21,6 +21,7 @@ import { Loader } from '../common/atoms/Loader'
import { sanitizeAmountQueryParam } from '../../hooks/useArbQueryParams'
import { truncateExtraDecimals } from '../../util/NumberUtils'
import { useNativeCurrencyBalances } from './TransferPanelMain/useNativeCurrencyBalances'
+import { useSelectedTokenDecimals } from '../../hooks/TransferPanel/useSelectedTokenDecimals'
function MaxButton({
className = '',
@@ -86,6 +87,7 @@ function SourceChainTokenBalance({
const [networks] = useNetworks()
const { isDepositMode, childChainProvider } =
useNetworksRelationship(networks)
+ const selectedTokenDecimals = useSelectedTokenDecimals()
const nativeCurrencyBalances = useNativeCurrencyBalances()
const selectedTokenBalances = useSelectedTokenBalances()
@@ -103,7 +105,7 @@ function SourceChainTokenBalance({
const formattedBalance =
balance !== null
? formatAmount(balance, {
- decimals: selectedToken?.decimals ?? nativeCurrency.decimals
+ decimals: selectedTokenDecimals
})
: null
diff --git a/packages/arb-token-bridge-ui/src/components/TransferPanel/hooks/useAmountBigNumber.ts b/packages/arb-token-bridge-ui/src/components/TransferPanel/hooks/useAmountBigNumber.ts
index eb25a1680e..d578996588 100644
--- a/packages/arb-token-bridge-ui/src/components/TransferPanel/hooks/useAmountBigNumber.ts
+++ b/packages/arb-token-bridge-ui/src/components/TransferPanel/hooks/useAmountBigNumber.ts
@@ -2,18 +2,15 @@ import { useMemo } from 'react'
import { useArbQueryParams } from '../../../hooks/useArbQueryParams'
import { useAppState } from '../../../state'
import { constants, utils } from 'ethers'
-import { useNetworks } from '../../../hooks/useNetworks'
-import { useNetworksRelationship } from '../../../hooks/useNetworksRelationship'
-import { useNativeCurrency } from '../../../hooks/useNativeCurrency'
+import { useNativeCurrencyDecimalsOnSourceChain } from '../../../hooks/useNativeCurrencyDecimalsOnSourceChain'
export function useAmountBigNumber() {
const {
app: { selectedToken }
} = useAppState()
const [{ amount }] = useArbQueryParams()
- const [networks] = useNetworks()
- const { childChainProvider } = useNetworksRelationship(networks)
- const nativeCurrency = useNativeCurrency({ provider: childChainProvider })
+ const nativeCurrencyDecimalsOnSourceChain =
+ useNativeCurrencyDecimalsOnSourceChain()
return useMemo(() => {
try {
@@ -23,9 +20,9 @@ export function useAmountBigNumber() {
return utils.parseUnits(amountSafe, selectedToken.decimals)
}
- return utils.parseUnits(amountSafe, nativeCurrency.decimals)
+ return utils.parseUnits(amountSafe, nativeCurrencyDecimalsOnSourceChain)
} catch (error) {
return constants.Zero
}
- }, [amount, selectedToken, nativeCurrency])
+ }, [amount, selectedToken, nativeCurrencyDecimalsOnSourceChain])
}
diff --git a/packages/arb-token-bridge-ui/src/hooks/TransferPanel/useSelectedTokenDecimals.ts b/packages/arb-token-bridge-ui/src/hooks/TransferPanel/useSelectedTokenDecimals.ts
index 13a59dd41f..c17b8fa1cd 100644
--- a/packages/arb-token-bridge-ui/src/hooks/TransferPanel/useSelectedTokenDecimals.ts
+++ b/packages/arb-token-bridge-ui/src/hooks/TransferPanel/useSelectedTokenDecimals.ts
@@ -1,16 +1,14 @@
import { useAppState } from '../../state'
-import { useNativeCurrency } from '../useNativeCurrency'
-import { useNetworksRelationship } from '../useNetworksRelationship'
-import { useNetworks } from '../useNetworks'
+import { useNativeCurrencyDecimalsOnSourceChain } from '../useNativeCurrencyDecimalsOnSourceChain'
export function useSelectedTokenDecimals() {
const {
app: { selectedToken }
} = useAppState()
- const [networks] = useNetworks()
- const { childChainProvider } = useNetworksRelationship(networks)
+ const nativeCurrencyDecimalsOnSourceChain =
+ useNativeCurrencyDecimalsOnSourceChain()
- const nativeCurrency = useNativeCurrency({ provider: childChainProvider })
-
- return selectedToken ? selectedToken.decimals : nativeCurrency.decimals
+ return selectedToken
+ ? selectedToken.decimals
+ : nativeCurrencyDecimalsOnSourceChain
}
diff --git a/packages/arb-token-bridge-ui/src/hooks/useNativeCurrencyDecimalsOnSourceChain.ts b/packages/arb-token-bridge-ui/src/hooks/useNativeCurrencyDecimalsOnSourceChain.ts
new file mode 100644
index 0000000000..d03aba45ea
--- /dev/null
+++ b/packages/arb-token-bridge-ui/src/hooks/useNativeCurrencyDecimalsOnSourceChain.ts
@@ -0,0 +1,21 @@
+import { isNetwork } from '../util/networks'
+import { useNativeCurrency } from './useNativeCurrency'
+import { useNetworks } from './useNetworks'
+import { useNetworksRelationship } from './useNetworksRelationship'
+
+export const useNativeCurrencyDecimalsOnSourceChain = () => {
+ const [networks] = useNetworks()
+ const { childChainProvider } = useNetworksRelationship(networks)
+ const nativeCurrency = useNativeCurrency({
+ provider: childChainProvider
+ })
+ const { isOrbitChain: isSourceChainOrbit } = isNetwork(
+ networks.sourceChain.id
+ )
+
+ if (isSourceChainOrbit) {
+ return 18
+ }
+
+ return nativeCurrency.decimals
+}
diff --git a/packages/arb-token-bridge-ui/src/token-bridge-sdk/Erc20DepositStarter.ts b/packages/arb-token-bridge-ui/src/token-bridge-sdk/Erc20DepositStarter.ts
index 3934103f21..a5f5200cbe 100644
--- a/packages/arb-token-bridge-ui/src/token-bridge-sdk/Erc20DepositStarter.ts
+++ b/packages/arb-token-bridge-ui/src/token-bridge-sdk/Erc20DepositStarter.ts
@@ -1,4 +1,7 @@
-import { Erc20Bridger } from '@arbitrum/sdk'
+import {
+ Erc20Bridger,
+ scaleFrom18DecimalsToNativeTokenDecimals
+} from '@arbitrum/sdk'
import { BigNumber, constants, utils } from 'ethers'
import { ERC20__factory } from '@arbitrum/sdk/dist/lib/abi/factories/ERC20__factory'
import {
@@ -121,10 +124,12 @@ export class Erc20DepositStarter extends BridgeTransferStarter {
.add(gasEstimates.estimatedChildChainSubmissionCost)
)
)
- const estimatedDestinationChainGasFee = utils.parseUnits(
- String(estimatedDestinationChainGasFeeEth),
- await nativeCurrency.decimals()
- )
+
+ const estimatedDestinationChainGasFee =
+ scaleFrom18DecimalsToNativeTokenDecimals({
+ amount: utils.parseEther(String(estimatedDestinationChainGasFeeEth)),
+ decimals: await nativeCurrency.decimals()
+ })
// We want to bridge a certain amount of an ERC-20 token, but the Retryable fees on the destination chain will be paid in the custom fee token
// We have to check if the native-token spending allowance is enough to cover the fees
@@ -194,10 +199,11 @@ export class Erc20DepositStarter extends BridgeTransferStarter {
)
)
- const estimatedDestinationChainGasFee = utils.parseUnits(
- String(estimatedDestinationChainGasFeeEth),
- await nativeCurrency.decimals()
- )
+ const estimatedDestinationChainGasFee =
+ scaleFrom18DecimalsToNativeTokenDecimals({
+ amount: utils.parseEther(String(estimatedDestinationChainGasFeeEth)),
+ decimals: await nativeCurrency.decimals()
+ })
return erc20Bridger.approveGasToken({
erc20ParentAddress: this.sourceChainErc20Address,
diff --git a/packages/arb-token-bridge-ui/src/util/withdrawals/helpers.ts b/packages/arb-token-bridge-ui/src/util/withdrawals/helpers.ts
index 82e7706695..89ab0369be 100644
--- a/packages/arb-token-bridge-ui/src/util/withdrawals/helpers.ts
+++ b/packages/arb-token-bridge-ui/src/util/withdrawals/helpers.ts
@@ -3,7 +3,8 @@ import { Provider } from '@ethersproject/providers'
import { BigNumber } from '@ethersproject/bignumber'
import {
ChildToParentMessageReader,
- ChildTransactionReceipt
+ ChildTransactionReceipt,
+ scaleFrom18DecimalsToNativeTokenDecimals
} from '@arbitrum/sdk'
import { FetchWithdrawalsFromSubgraphResult } from './fetchWithdrawalsFromSubgraph'
import { fetchErc20Data } from '../TokenUtils'
@@ -87,7 +88,10 @@ export async function mapETHWithdrawalToL2ToL1EventResult({
sender: event.caller,
destinationAddress: event.destination,
type: AssetType.ETH,
- value: callvalue,
+ value: scaleFrom18DecimalsToNativeTokenDecimals({
+ amount: callvalue,
+ decimals: nativeCurrency.decimals
+ }),
symbol: nativeCurrency.symbol,
outgoingMessageState,
l2TxHash: event.l2TxHash || event.transactionHash,
@@ -314,7 +318,10 @@ export async function mapWithdrawalToL2ToL1EventResult({
sender: withdrawal.sender,
destinationAddress: withdrawal.receiver,
type: AssetType.ETH,
- value: BigNumber.from(withdrawal.ethValue),
+ value: scaleFrom18DecimalsToNativeTokenDecimals({
+ amount: BigNumber.from(withdrawal.ethValue),
+ decimals: nativeCurrency.decimals
+ }),
outgoingMessageState,
l2TxHash: l2TxReceipt.transactionHash,
symbol: nativeCurrency.symbol,
diff --git a/packages/arb-token-bridge-ui/synpress.config.ts b/packages/arb-token-bridge-ui/synpress.config.ts
index 2150d747e3..84a332c1b0 100644
--- a/packages/arb-token-bridge-ui/synpress.config.ts
+++ b/packages/arb-token-bridge-ui/synpress.config.ts
@@ -25,7 +25,8 @@ import {
getCustomDestinationAddress,
ERC20TokenSymbol,
ERC20TokenDecimals,
- ERC20TokenName
+ ERC20TokenName,
+ getNativeTokenDecimals
} from './tests/support/common'
import {
@@ -200,6 +201,10 @@ export default defineConfig({
config.env.ORBIT_TEST = isOrbitTest ? '1' : '0'
config.env.NATIVE_TOKEN_SYMBOL = isCustomFeeToken ? 'TN' : 'ETH'
config.env.NATIVE_TOKEN_ADDRESS = ethBridger.nativeToken
+ config.env.NATIVE_TOKEN_DECIMALS = await getNativeTokenDecimals({
+ parentProvider,
+ childProvider
+ })
config.env.CUSTOM_DESTINATION_ADDRESS =
await getCustomDestinationAddress()
@@ -297,6 +302,10 @@ async function approveCustomFeeToken({
async function fundUserWalletNativeCurrency() {
const childEthBridger = await EthBridger.fromProvider(childProvider)
+ const decimals = await getNativeTokenDecimals({
+ parentProvider,
+ childProvider
+ })
const address = await userWallet.getAddress()
@@ -306,18 +315,21 @@ async function fundUserWalletNativeCurrency() {
)
const userBalance = await tokenContract.balanceOf(address)
- const shouldFund = userBalance.lt(utils.parseEther('0.3'))
+ const shouldFund = userBalance.lt(utils.parseUnits('0.3', decimals))
if (!shouldFund) {
console.log(
- `User wallet has enough L3 native currency for testing, skip funding...`
+ `User wallet has enough custom native currency for testing, skip funding...`
)
return
}
console.log(`Funding native currency to user wallet on L2...`)
- const tx = await tokenContract.transfer(address, utils.parseEther('3'))
+ const tx = await tokenContract.transfer(
+ address,
+ utils.parseUnits('3', decimals)
+ )
await tx.wait()
}
diff --git a/packages/arb-token-bridge-ui/tests/e2e/specs/login.cy.ts b/packages/arb-token-bridge-ui/tests/e2e/specs/login.cy.ts
index 5c627e2344..ce8413b0cc 100644
--- a/packages/arb-token-bridge-ui/tests/e2e/specs/login.cy.ts
+++ b/packages/arb-token-bridge-ui/tests/e2e/specs/login.cy.ts
@@ -16,6 +16,7 @@ describe('Login Account', () => {
let l2ETHbal
const nativeTokenSymbol = Cypress.env('NATIVE_TOKEN_SYMBOL')
+ const nativeTokenDecimals = Cypress.env('NATIVE_TOKEN_DECIMALS')
const isCustomFeeToken = nativeTokenSymbol !== 'ETH'
before(() => {
@@ -25,7 +26,9 @@ describe('Login Account', () => {
multiCallerAddress: getL1NetworkConfig().multiCall,
address: Cypress.env('ADDRESS'),
rpcURL: Cypress.env('ETH_RPC_URL')
- }).then(val => (l1ETHbal = formatAmount(val)))
+ }).then(
+ val => (l1ETHbal = formatAmount(val, { decimals: nativeTokenDecimals }))
+ )
} else {
getInitialETHBalance(Cypress.env('ETH_RPC_URL')).then(
val => (l1ETHbal = formatAmount(val))
diff --git a/packages/arb-token-bridge-ui/tests/support/common.ts b/packages/arb-token-bridge-ui/tests/support/common.ts
index 76664a8e91..874000ada9 100644
--- a/packages/arb-token-bridge-ui/tests/support/common.ts
+++ b/packages/arb-token-bridge-ui/tests/support/common.ts
@@ -4,7 +4,7 @@
import { Provider, StaticJsonRpcProvider } from '@ethersproject/providers'
import { BigNumber, Signer, Wallet, ethers, utils } from 'ethers'
-import { MultiCaller } from '@arbitrum/sdk'
+import { EthBridger, MultiCaller } from '@arbitrum/sdk'
import { MULTICALL_TESTNET_ADDRESS } from '../../src/constants'
import {
defaultL2Network,
@@ -112,7 +112,7 @@ export function getZeroToLessThanOneToken(symbol: string) {
export const importTokenThroughUI = (address: string) => {
// Click on the ETH dropdown (Select token button)
- cy.findSelectTokenButton('ETH').click()
+ cy.findSelectTokenButton(Cypress.env('NATIVE_TOKEN_SYMBOL') ?? 'ETH').click()
// open the Select Token popup
cy.findByPlaceholderText(/Search by token name/i)
@@ -183,6 +183,28 @@ export const startWebApp = (url = '/', qs: { [s: string]: string } = {}) => {
})
}
+export async function getNativeTokenDecimals({
+ parentProvider,
+ childProvider
+}: {
+ parentProvider: Provider
+ childProvider: Provider
+}) {
+ const multiCaller = await MultiCaller.fromProvider(parentProvider)
+ const ethBridger = await EthBridger.fromProvider(childProvider)
+ const isCustomFeeToken = typeof ethBridger.nativeToken !== 'undefined'
+
+ const nativeToken = isCustomFeeToken
+ ? (
+ await multiCaller.getTokenData([ethBridger.nativeToken!], {
+ decimals: true
+ })
+ )[0]
+ : undefined
+
+ return nativeToken?.decimals ?? 18
+}
+
export const visitAfterSomeDelay = (
url: string,
options?: Partial
@@ -221,20 +243,29 @@ export async function generateActivityOnChains({
// whilst waiting for status we mine on both parentChain and childChain
console.log('Generating activity on parentChain...')
const minerParent = Wallet.createRandom().connect(parentProvider)
+
+ const decimals = await getNativeTokenDecimals({
+ parentProvider,
+ childProvider
+ })
+
await fundEth({
address: await minerParent.getAddress(),
provider: parentProvider,
sourceWallet: wallet,
- networkType: 'parentChain'
+ networkType: 'parentChain',
+ amount: utils.parseUnits('0.2', decimals)
})
console.log('Generating activity on childChain...')
const minerChild = Wallet.createRandom().connect(childProvider)
+
await fundEth({
address: await minerChild.getAddress(),
provider: childProvider,
sourceWallet: wallet,
- networkType: 'childChain'
+ networkType: 'childChain',
+ amount: utils.parseEther('0.2')
})
await Promise.allSettled([keepMining(minerParent), keepMining(minerChild)])
@@ -293,13 +324,13 @@ export async function fundEth({
provider,
sourceWallet, // source wallet that will fund the `address`,
networkType,
- amount = utils.parseEther('2')
+ amount
}: {
address: string
provider: Provider
sourceWallet: Wallet
networkType: NetworkType
- amount?: BigNumber
+ amount: BigNumber
}) {
console.log(`Funding ETH ${address} on ${networkType}...`)
const balance = await provider.getBalance(address)
diff --git a/yarn.lock b/yarn.lock
index df809f5989..eba2169b8c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -89,6 +89,17 @@
async-mutex "^0.4.0"
ethers "^5.1.0"
+"@arbitrum/sdk@^4.0.2-beta.1":
+ version "4.0.2-beta.1"
+ resolved "https://registry.yarnpkg.com/@arbitrum/sdk/-/sdk-4.0.2-beta.1.tgz#c6c6c5784a8eaa6a4edab3600f765e9f82ce5988"
+ integrity sha512-a5DG6+Ld3X4L8H3CTUl3gc27Bj/Pqjo+5UZiCI97SM2mHtHKWF1BgQ+FCk/8bgFUP5nS9dXBl5tPJRtCFfOe0A==
+ dependencies:
+ "@ethersproject/address" "^5.0.8"
+ "@ethersproject/bignumber" "^5.1.1"
+ "@ethersproject/bytes" "^5.0.8"
+ async-mutex "^0.4.0"
+ ethers "^5.1.0"
+
"@babel/code-frame@7.12.11":
version "7.12.11"
resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz"