Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: release v1.666.0 #7631

Merged
merged 7 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
}
},
"dependencies": {
"@arbitrum/sdk": "^3.7.0",
"@arbitrum/sdk": "^4.0.1",
"@chakra-ui/icons": "^2.1.1",
"@chakra-ui/react": "^2.8.2",
"@chakra-ui/system": "^2.6.2",
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

74 changes: 37 additions & 37 deletions packages/swapper/src/swappers/ArbitrumBridgeSwapper/endpoints.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { L1ToL2MessageReader, L1ToL2MessageReaderClassic } from '@arbitrum/sdk'
import { L1ToL2MessageStatus, L1TransactionReceipt } from '@arbitrum/sdk'
import type { ParentToChildMessageReader, ParentToChildMessageReaderClassic } from '@arbitrum/sdk'
import { ParentToChildMessageStatus, ParentTransactionReceipt } from '@arbitrum/sdk'
import type { Provider } from '@ethersproject/providers'
import type { AssetId } from '@shapeshiftoss/caip'
import { arbitrumChainId, fromChainId } from '@shapeshiftoss/caip'
Expand Down Expand Up @@ -28,49 +28,49 @@ import { assertValidTrade } from './utils/helpers'
const tradeQuoteMetadata: Map<string, { sellAssetId: AssetId; chainId: EvmChainId }> = new Map()

// https://github.com/OffchainLabs/arbitrum-token-bridge/blob/d17c88ef3eef3f4ffc61a04d34d50406039f045d/packages/arb-token-bridge-ui/src/util/deposits/helpers.ts#L268
export const getL1ToL2MessageDataFromL1TxHash = async ({
export const getParentToChildMessageDataFromParentTxHash = async ({
depositTxId,
l1Provider,
l2Provider,
parentProvider,
childProvider,
isClassic, // optional: if we already know if tx is classic (eg. through subgraph) then no need to re-check in this fn
}: {
depositTxId: string
l1Provider: Provider
l2Provider: Provider
parentProvider: Provider
childProvider: Provider
isClassic?: boolean
}): Promise<
| {
isClassic?: boolean
l1ToL2Msg?: L1ToL2MessageReaderClassic | L1ToL2MessageReader
parentToChildMsg?: ParentToChildMessageReaderClassic | ParentToChildMessageReader
}
| undefined
> => {
// fetch L1 transaction receipt
const depositTxReceipt = await l1Provider.getTransactionReceipt(depositTxId)
// fetch Parent transaction receipt
const depositTxReceipt = await parentProvider.getTransactionReceipt(depositTxId)
if (!depositTxReceipt) return

const l1TxReceipt = new L1TransactionReceipt(depositTxReceipt)
const parentTxReceipt = new ParentTransactionReceipt(depositTxReceipt)

// classic (pre-nitro) handling
const getClassicDepositMessage = async () => {
const [l1ToL2Msg] = await l1TxReceipt.getL1ToL2MessagesClassic(l2Provider)
const [parentToChildMsg] = await parentTxReceipt.getParentToChildMessagesClassic(childProvider)
return {
isClassic: true,
l1ToL2Msg,
parentToChildMsg,
}
}

// post-nitro handling
const getNitroDepositMessage = async () => {
const [l1ToL2Msg] = await l1TxReceipt.getL1ToL2Messages(l2Provider)
const [parentToChildMsg] = await parentTxReceipt.getParentToChildMessages(childProvider)
return {
isClassic: false,
l1ToL2Msg,
parentToChildMsg,
}
}

// if it is unknown whether the transaction isClassic or not, fetch the result
const safeIsClassic = isClassic ?? (await l1TxReceipt.isClassic(l2Provider))
const safeIsClassic = isClassic ?? (await parentTxReceipt.isClassic(childProvider))

if (safeIsClassic) {
// classic (pre-nitro) deposit - both eth + token
Expand Down Expand Up @@ -174,8 +174,8 @@ export const arbitrumBridgeApi: SwapperApi = {
const isWithdraw = chainId === arbitrumChainId

if (isWithdraw) {
// We don't want to be polling for 7 days for Arb L2 -> L1, that's not very realistic for users.
// We simply return success when the L2 Tx is confirmed, meaning the trade will show "complete" almost instantly
// We don't want to be polling for 7 days for Arb Child -> Parent, that's not very realistic for users.
// We simply return success when the Child Tx is confirmed, meaning the trade will show "complete" almost instantly
// and will handle the whole 7 days thing (that the user should've already been warned about with an ack before previewing)
// at confirm step
return {
Expand All @@ -189,54 +189,54 @@ export const arbitrumBridgeApi: SwapperApi = {
return {
status: TxStatus.Pending,
buyTxHash: undefined,
message: 'L1 Tx Pending',
message: 'Parent Tx Pending',
}
}

const l1Provider = getEthersV5Provider(KnownChainIds.EthereumMainnet)
const l2Provider = getEthersV5Provider(KnownChainIds.ArbitrumMainnet)
const maybeL1ToL2MessageData = await getL1ToL2MessageDataFromL1TxHash({
const parentProvider = getEthersV5Provider(KnownChainIds.EthereumMainnet)
const childProvider = getEthersV5Provider(KnownChainIds.ArbitrumMainnet)
const maybeParentToChildMessageData = await getParentToChildMessageDataFromParentTxHash({
depositTxId: txHash,
l1Provider,
l2Provider,
parentProvider,
childProvider,
})
const maybeL1ToL2Msg = maybeL1ToL2MessageData?.l1ToL2Msg
const maybeParentToChildMsg = maybeParentToChildMessageData?.parentToChildMsg
const maybeBuyTxHash = await (async () => {
if (!maybeL1ToL2Msg) return
if (!maybeParentToChildMsg) return

if (maybeL1ToL2MessageData?.isClassic) {
const msg = maybeL1ToL2Msg as L1ToL2MessageReaderClassic
if (maybeParentToChildMessageData?.isClassic) {
const msg = maybeParentToChildMsg as ParentToChildMessageReaderClassic
const receipt = await msg.getRetryableCreationReceipt()
if (receipt?.status !== L1ToL2MessageStatus.REDEEMED) return
if (receipt?.status !== ParentToChildMessageStatus.REDEEMED) return
return receipt.transactionHash
} else {
const msg = maybeL1ToL2Msg as L1ToL2MessageReader
const msg = maybeParentToChildMsg as ParentToChildMessageReader
const successfulRedeem = await msg.getSuccessfulRedeem()
if (successfulRedeem.status !== L1ToL2MessageStatus.REDEEMED) return
return successfulRedeem.l2TxReceipt.transactionHash
if (successfulRedeem.status !== ParentToChildMessageStatus.REDEEMED) return
return successfulRedeem.childTxReceipt.transactionHash
}
})()

if (!maybeBuyTxHash) {
return {
status: TxStatus.Pending,
buyTxHash: maybeBuyTxHash,
message: 'L1 Tx confirmed, waiting for L2',
message: 'Parent Tx confirmed, waiting for Child',
}
}

const l2TxStatus = await checkEvmSwapStatus({
const childTxStatus = await checkEvmSwapStatus({
txHash: maybeBuyTxHash,
chainId: arbitrumChainId,
assertGetEvmChainAdapter,
})

// i.e Unknown is perfectly valid since ETH deposits L2 Txids are available immediately deterministically, but will only be in the mempool after ~10mn
if (l2TxStatus.status === TxStatus.Pending || l2TxStatus.status === TxStatus.Unknown) {
// i.e Unknown is perfectly valid since ETH deposits Child Txids are available immediately deterministically, but will only be in the mempool after ~10mn
if (childTxStatus.status === TxStatus.Pending || childTxStatus.status === TxStatus.Unknown) {
return {
status: TxStatus.Pending,
buyTxHash: maybeBuyTxHash,
message: 'L2 Tx Pending',
message: 'Child Tx Pending',
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { L2Network } from '@arbitrum/sdk'
import { Erc20Bridger, EthBridger } from '@arbitrum/sdk'
import { ethAssetId, ethChainId } from '@shapeshiftoss/caip'
import { type EvmChainAdapter } from '@shapeshiftoss/chain-adapters'
Expand All @@ -12,7 +11,7 @@ import { getTradeQuote } from './getTradeQuote'
vi.mock('@arbitrum/sdk', () => ({
Erc20Bridger: vi.fn(),
EthBridger: vi.fn(),
getL2Network: vi.fn().mockResolvedValue({ chainID: 42161 } as L2Network),
getArbitrumNetwork: vi.fn().mockResolvedValue({ chainID: 42161 }),
}))

vi.mock('@shapeshiftoss/utils/dist/evm', () => ({
Expand Down Expand Up @@ -111,9 +110,13 @@ describe('getTradeQuote', () => {
from: '0x',
},
}),
getL2ERC20Address: vi.fn().mockResolvedValue('0xf929de51d91c77e42f5090069e0ad7a09e513c73'),
getL1ERC20Address: vi.fn().mockResolvedValue('0xc770eefad204b5180df6a14ee197d99d808ee52d'),
getL1GatewayAddress: vi.fn().mockResolvedValue('0x0c66f315542fdec1d312c415b14eef614b0910ef'),
getChildErc20Address: vi.fn().mockResolvedValue('0xf929de51d91c77e42f5090069e0ad7a09e513c73'),
getParentErc20Address: vi
.fn()
.mockResolvedValue('0xc770eefad204b5180df6a14ee197d99d808ee52d'),
getParentGatewayAddress: vi
.fn()
.mockResolvedValue('0x0c66f315542fdec1d312c415b14eef614b0910ef'),
}
vi.mocked(Erc20Bridger).mockReturnValue(Erc20BridgerMock as unknown as Erc20Bridger)

Expand Down Expand Up @@ -146,9 +149,13 @@ describe('getTradeQuote', () => {
from: '0x',
},
}),
getL2ERC20Address: vi.fn().mockResolvedValue('0xf929de51d91c77e42f5090069e0ad7a09e513c73'),
getL1ERC20Address: vi.fn().mockResolvedValue('0xc770eefad204b5180df6a14ee197d99d808ee52d'),
getL1GatewayAddress: vi.fn().mockResolvedValue('0x0c66f315542fdec1d312c415b14eef614b0910ef'),
getChildErc20Address: vi.fn().mockResolvedValue('0xf929de51d91c77e42f5090069e0ad7a09e513c73'),
getParentErc20Address: vi
.fn()
.mockResolvedValue('0xc770eefad204b5180df6a14ee197d99d808ee52d'),
getParentGatewayAddress: vi
.fn()
.mockResolvedValue('0x0c66f315542fdec1d312c415b14eef614b0910ef'),
}
vi.mocked(Erc20Bridger).mockReturnValue(Erc20BridgerMock as unknown as Erc20Bridger)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Erc20Bridger, EthBridger, getL2Network } from '@arbitrum/sdk'
import { Erc20Bridger, EthBridger, getArbitrumNetwork } from '@arbitrum/sdk'
import type {
L1ToL2TransactionRequest,
L2ToL1TransactionRequest,
ChildToParentTransactionRequest,
ParentToChildTransactionRequest,
} from '@arbitrum/sdk/dist/lib/dataEntities/transactionRequest'
import type { ChainId } from '@shapeshiftoss/caip'
import { ethAssetId, ethChainId, fromAssetId } from '@shapeshiftoss/caip'
Expand Down Expand Up @@ -43,13 +43,15 @@ export const fetchArbitrumBridgeSwap = async ({
assertGetEvmChainAdapter,
getEthersV5Provider,
}: FetchArbitrumBridgeSwapInput): Promise<{
request: Omit<L1ToL2TransactionRequest | L2ToL1TransactionRequest, 'retryableData'> | undefined
request:
| Omit<ParentToChildTransactionRequest | ChildToParentTransactionRequest, 'retryableData'>
| undefined
allowanceContract: string
networkFeeCryptoBaseUnit: string
}> => {
const adapter = assertGetEvmChainAdapter(chainId)

const l2Network = await getL2Network(arbitrum.id)
const l2Network = await getArbitrumNetwork(arbitrum.id)
const isDeposit = sellAsset.chainId === ethChainId
const isEthBridge = isDeposit ? sellAsset.assetId === ethAssetId : buyAsset.assetId === ethAssetId

Expand All @@ -60,16 +62,16 @@ export const fetchArbitrumBridgeSwap = async ({
return isEthBridge ? BRIDGE_TYPE.ETH_WITHDRAWAL : BRIDGE_TYPE.ERC20_WITHDRAWAL
})()

const l1Provider = getEthersV5Provider(KnownChainIds.EthereumMainnet)
const l2Provider = getEthersV5Provider(KnownChainIds.ArbitrumMainnet)
const parentProvider = getEthersV5Provider(KnownChainIds.EthereumMainnet)
const childProvider = getEthersV5Provider(KnownChainIds.ArbitrumMainnet)

switch (bridgeType) {
case BRIDGE_TYPE.ETH_DEPOSIT: {
const bridger = new EthBridger(l2Network)

const request = await bridger.getDepositToRequest({
l1Provider,
l2Provider,
parentProvider,
childProvider,
amount: BigNumber.from(sellAmountIncludingProtocolFeesCryptoBaseUnit),
from: sendAddress ?? '',
destinationAddress: receiveAddress,
Expand Down Expand Up @@ -108,15 +110,18 @@ export const fetchArbitrumBridgeSwap = async ({
}
case BRIDGE_TYPE.ERC20_DEPOSIT: {
const bridger = new Erc20Bridger(l2Network)
const erc20L1Address = fromAssetId(sellAsset.assetId).assetReference
const allowanceContract = await bridger.getL1GatewayAddress(erc20L1Address, l1Provider)
const erc20ParentAddress = fromAssetId(sellAsset.assetId).assetReference
const allowanceContract = await bridger.getParentGatewayAddress(
erc20ParentAddress,
parentProvider,
)

const maybeRequest = await bridger
.getDepositRequest({
amount: BigNumber.from(sellAmountIncludingProtocolFeesCryptoBaseUnit),
l1Provider,
l2Provider,
erc20L1Address,
parentProvider,
childProvider,
erc20ParentAddress,
from: sendAddress ?? '',
destinationAddress: receiveAddress,
retryableGasOverrides: {
Expand Down Expand Up @@ -163,12 +168,11 @@ export const fetchArbitrumBridgeSwap = async ({
}
case BRIDGE_TYPE.ERC20_WITHDRAWAL: {
const bridger = new Erc20Bridger(l2Network)
const erc20L1Address = fromAssetId(buyAsset.assetId).assetReference
const erc20ParentAddress = fromAssetId(buyAsset.assetId).assetReference

const request = await bridger.getWithdrawalRequest({
amount: BigNumber.from(sellAmountIncludingProtocolFeesCryptoBaseUnit),
// This isn't a typo - https://github.com/OffchainLabs/arbitrum-sdk/pull/474
erc20l1Address: erc20L1Address,
erc20ParentAddress,
from: sendAddress ?? '',
destinationAddress: receiveAddress,
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Erc20Bridger, getL2Network } from '@arbitrum/sdk'
import { Erc20Bridger, getArbitrumNetwork } from '@arbitrum/sdk'
import { arbitrumAssetId, ethAssetId, ethChainId, fromAssetId } from '@shapeshiftoss/caip'
import type { EvmChainId } from '@shapeshiftoss/chain-adapters'
import { type Asset, KnownChainIds } from '@shapeshiftoss/types'
Expand Down Expand Up @@ -70,30 +70,42 @@ export const assertValidTrade = async ({
}
}
if (isTokenBridge) {
const l2Network = await getL2Network(arbitrum.id)
const bridger = new Erc20Bridger(l2Network)
const erc20L1Address = fromAssetId((isDeposit ? sellAsset : buyAsset).assetId).assetReference
const erc20L2Address = fromAssetId((isDeposit ? buyAsset : sellAsset).assetId).assetReference
const l1Provider = getEthersV5Provider(KnownChainIds.EthereumMainnet)
const l2Provider = getEthersV5Provider(KnownChainIds.ArbitrumMainnet)
const childNetwork = await getArbitrumNetwork(arbitrum.id)
const bridger = new Erc20Bridger(childNetwork)
const erc20ParentAddress = fromAssetId(
(isDeposit ? sellAsset : buyAsset).assetId,
).assetReference
const erc20ChildAddress = fromAssetId((isDeposit ? buyAsset : sellAsset).assetId).assetReference
const parentProvider = getEthersV5Provider(KnownChainIds.EthereumMainnet)
const childProvider = getEthersV5Provider(KnownChainIds.ArbitrumMainnet)

// Since our related assets list isn't exhaustive and won't cut it to determine the L1 <-> L2 mapping, we double check that the bridge is valid
// Since our related assets list isn't exhaustive and won't cut it to determine the Parent <-> Child mapping, we double check that the bridge is valid
// by checking against Arbitrum bridge's own mappings, which uses different sources (Coingecko, Gemini, Uni and its own lists at the time of writing)
const arbitrumBridgeErc20L2Address = await bridger.getL2ERC20Address(erc20L1Address, l1Provider)
const arbitrumBridgeErc20L1Address = await bridger.getL1ERC20Address(erc20L2Address, l2Provider)
const arbitrumBridgeErc20ChildAddress = await bridger.getChildErc20Address(
erc20ParentAddress,
parentProvider,
)
const arbitrumBridgeErc20ParentAddress = await bridger.getParentErc20Address(
erc20ChildAddress,
childProvider,
)

if (!isAddressEqual(getAddress(arbitrumBridgeErc20L1Address), getAddress(erc20L1Address))) {
if (
!isAddressEqual(getAddress(arbitrumBridgeErc20ParentAddress), getAddress(erc20ParentAddress))
) {
return Err(
makeSwapErrorRight({
message: `[ArbitrumBridge: tradeQuote] - Invalid L1 ERC20 address: ${erc20L1Address}`,
message: `[ArbitrumBridge: tradeQuote] - Invalid Parent ERC20 address: ${erc20ParentAddress}`,
code: TradeQuoteError.UnsupportedTradePair,
}),
)
}
if (!isAddressEqual(getAddress(arbitrumBridgeErc20L2Address), getAddress(erc20L2Address))) {
if (
!isAddressEqual(getAddress(arbitrumBridgeErc20ChildAddress), getAddress(erc20ChildAddress))
) {
return Err(
makeSwapErrorRight({
message: `[ArbitrumBridge: tradeQuote] - Invalid L2 ERC20 address: ${erc20L2Address}`,
message: `[ArbitrumBridge: tradeQuote] - Invalid Child ERC20 address: ${erc20ChildAddress}`,
code: TradeQuoteError.UnsupportedTradePair,
}),
)
Expand Down
Loading
Loading