From 47471d09da7ed11d6baf2430ec3d579354500a8a Mon Sep 17 00:00:00 2001 From: Nikola Pavlov <nikola@txfusion.io> Date: Fri, 5 Apr 2024 12:35:38 +0200 Subject: [PATCH 1/3] feat: integrate wstETH bridge addresses --- composables/zksync/deposit/useTransaction.ts | 8 ++++++-- composables/zksync/useTransaction.ts | 10 ++++++---- data/customBridgeTokens.ts | 12 +----------- utils/constants.ts | 15 +++++++++++++++ utils/helpers.ts | 8 +++++++- utils/mappers.ts | 6 ++++++ views/transactions/Deposit.vue | 15 +++++++++++++-- views/transactions/Transfer.vue | 2 +- 8 files changed, 55 insertions(+), 21 deletions(-) diff --git a/composables/zksync/deposit/useTransaction.ts b/composables/zksync/deposit/useTransaction.ts index 1b8811878..c9bd2d382 100644 --- a/composables/zksync/deposit/useTransaction.ts +++ b/composables/zksync/deposit/useTransaction.ts @@ -1,4 +1,5 @@ import type { DepositFeeValues } from "@/composables/zksync/deposit/useFee"; +import type { Token } from "@/types"; import type { BigNumberish } from "ethers"; import type { L1Signer } from "zksync-ethers"; @@ -13,7 +14,7 @@ export default (getL1Signer: () => Promise<L1Signer | undefined>) => { const commitTransaction = async ( transaction: { to: string; - tokenAddress: string; + token: Token; amount: BigNumberish; }, fee: DepositFeeValues @@ -39,11 +40,14 @@ export default (getL1Signer: () => Promise<L1Signer | undefined>) => { } status.value = "waiting-for-signature"; + const isCustomBridge = isExternalBridgeToken(transaction.token); + const bridgeAddress = isCustomBridge ? EXTERNAL_BRIDGES[transaction.token.address] : ""; const depositResponse = await wallet.deposit({ to: transaction.to, - token: transaction.tokenAddress, + token: transaction.token.address, amount: transaction.amount, l2GasLimit: fee.l2GasLimit, + ...(isCustomBridge ? { bridgeAddress } : {}), overrides, }); diff --git a/composables/zksync/useTransaction.ts b/composables/zksync/useTransaction.ts index 19ca672aa..82ba4a59c 100644 --- a/composables/zksync/useTransaction.ts +++ b/composables/zksync/useTransaction.ts @@ -3,13 +3,13 @@ import { type BigNumberish } from "ethers"; import { isCustomNode } from "@/data/networks"; -import type { TokenAmount } from "@/types"; +import type { Token, TokenAmount } from "@/types"; import type { Provider, Signer } from "zksync-ethers"; type TransactionParams = { type: "transfer" | "withdrawal"; to: string; - tokenAddress: string; + token: Token; amount: BigNumberish; }; @@ -38,7 +38,9 @@ export default (getSigner: () => Promise<Signer | undefined>, getProvider: () => if (!signer) throw new Error("zkSync Signer is not available"); const getRequiredBridgeAddress = async () => { - if (transaction.tokenAddress === ETH_TOKEN.address) return undefined; + if (transaction.token.address === ETH_TOKEN.address) return undefined; + const isCustomBridge = isExternalBridgeToken(transaction.token); + if (isCustomBridge) return EXTERNAL_BRIDGES[transaction.token.address]; const bridgeAddresses = await retrieveBridgeAddresses(); return bridgeAddresses.erc20L2; }; @@ -50,7 +52,7 @@ export default (getSigner: () => Promise<Signer | undefined>, getProvider: () => status.value = "waiting-for-signature"; const tx = await signer[transaction.type === "transfer" ? "transfer" : "withdraw"]({ to: transaction.to, - token: transaction.tokenAddress === ETH_TOKEN.address ? ETH_TOKEN.l1Address! : transaction.tokenAddress, + token: transaction.token.address === ETH_TOKEN.address ? ETH_TOKEN.l1Address! : transaction.token.address, amount: transaction.amount, bridgeAddress, overrides: { diff --git a/data/customBridgeTokens.ts b/data/customBridgeTokens.ts index b70f507ad..da1794a93 100644 --- a/data/customBridgeTokens.ts +++ b/data/customBridgeTokens.ts @@ -8,14 +8,4 @@ type CustomBridgeToken = { symbol: string; }; -export const customBridgeTokens: CustomBridgeToken[] = [ - { - chainId: 1, - l1Address: "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0", - l2Address: "0x703b52F2b28fEbcB60E1372858AF5b18849FE867", - bridgeName: "txSync Bridge", - bridgeUrlDeposit: "https://portal.txsync.io/bridge/?token=0x703b52F2b28fEbcB60E1372858AF5b18849FE867", - bridgeUrlWithdraw: "https://portal.txsync.io/bridge/withdraw/?token=0x703b52F2b28fEbcB60E1372858AF5b18849FE867", - symbol: "wstETH", - }, -]; +export const customBridgeTokens: CustomBridgeToken[] = []; diff --git a/utils/constants.ts b/utils/constants.ts index f87ca221d..ca62636d3 100644 --- a/utils/constants.ts +++ b/utils/constants.ts @@ -8,3 +8,18 @@ export const ETH_TOKEN: Token = { decimals: 18, iconUrl: "/img/eth.svg", }; + +export const WST_ETH_TOKEN: Token = { + address: "0x703b52F2b28fEbcB60E1372858AF5b18849FE867", + l1Address: "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0", + symbol: "wstETH", + name: "Wrapped liquid staked Ether 2.0", + decimals: 18, + iconUrl: "https://assets.coingecko.com/coins/images/18834/large/wstETH.png", +}; + +// External non-native bridge addresses: +export const EXTERNAL_BRIDGES = { + [WST_ETH_TOKEN.l1Address!]: "0x41527B2d03844dB6b0945f25702cB958b6d55989", + [WST_ETH_TOKEN.address]: "0xE1D6A50E7101c8f8db77352897Ee3f1AC53f782B", +}; diff --git a/utils/helpers.ts b/utils/helpers.ts index 447191211..392f885cf 100644 --- a/utils/helpers.ts +++ b/utils/helpers.ts @@ -1,7 +1,9 @@ import { BigNumber } from "ethers"; +import { EXTERNAL_BRIDGES } from "./constants"; + import type { ZkSyncNetwork } from "@/data/networks"; -import type { TokenAmount } from "@/types"; +import type { Token, TokenAmount } from "@/types"; import type { BigNumberish } from "ethers"; export function isOnlyZeroes(value: string) { @@ -52,3 +54,7 @@ export async function retry<T>(func: () => Promise<T>, options: RetryOptions = { } } } + +export const isExternalBridgeToken = (token: Token) => { + return Object.hasOwn(EXTERNAL_BRIDGES, token.address); +}; diff --git a/utils/mappers.ts b/utils/mappers.ts index 6b2e69d05..968cde277 100644 --- a/utils/mappers.ts +++ b/utils/mappers.ts @@ -40,6 +40,12 @@ export const mapApiToken = (token: Api.Response.Token): Token => { }; } + // TODO: Update the address on the Block explorer API side + // Update the old wstETH address with new one + if (token.l1Address === WST_ETH_TOKEN.l1Address) { + token.l2Address = WST_ETH_TOKEN.address; + } + return { l1Address: token.l1Address || undefined, address: token.l2Address, diff --git a/views/transactions/Deposit.vue b/views/transactions/Deposit.vue index 2ba75be52..895ed7915 100644 --- a/views/transactions/Deposit.vue +++ b/views/transactions/Deposit.vue @@ -461,6 +461,17 @@ const tokenBalance = computed<BigNumberish | undefined>(() => { return balance.value?.find((e) => e.address === selectedToken.value?.address)?.amount; }); +const getContractAddress = async () => { + if (selectedToken.value) { + const isExternalBridge = isExternalBridgeToken(selectedToken.value); + if (isExternalBridge) { + return EXTERNAL_BRIDGES[selectedToken.value.address]; + } else { + return (await providerStore.requestProvider().getDefaultBridgeAddresses()).erc20L1; + } + } +}; + const { result: allowance, inProgress: allowanceRequestInProgress, @@ -477,7 +488,7 @@ const { } = useAllowance( computed(() => account.value.address), computed(() => selectedToken.value?.address), - async () => (await providerStore.requestProvider().getDefaultBridgeAddresses()).erc20L1 + getContractAddress ); const enoughAllowance = computed(() => { if (!allowance.value || !selectedToken.value) { @@ -681,7 +692,7 @@ const makeTransaction = async () => { const tx = await commitTransaction( { to: transaction.value!.to.address, - tokenAddress: transaction.value!.token.address, + token: transaction.value!.token, amount: transaction.value!.token.amount, }, feeValues.value! diff --git a/views/transactions/Transfer.vue b/views/transactions/Transfer.vue index f412ba126..6417ed613 100644 --- a/views/transactions/Transfer.vue +++ b/views/transactions/Transfer.vue @@ -606,7 +606,7 @@ const makeTransaction = async () => { { type: props.type, to: transaction.value!.to.address, - tokenAddress: transaction.value!.token.address, + token: transaction.value!.token, amount: transaction.value!.token.amount, }, { From b7dabc8fe8b510491bc5f485562ac0afce634e0f Mon Sep 17 00:00:00 2001 From: Nikola Pavlov <nikola@txfusion.io> Date: Fri, 5 Apr 2024 14:08:37 +0200 Subject: [PATCH 2/3] feat: add custom bridge address for fee estimation --- composables/zksync/useFee.ts | 9 ++++++--- views/transactions/Transfer.vue | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/composables/zksync/useFee.ts b/composables/zksync/useFee.ts index eb8690202..17a94689c 100644 --- a/composables/zksync/useFee.ts +++ b/composables/zksync/useFee.ts @@ -8,7 +8,7 @@ export type FeeEstimationParams = { type: "transfer" | "withdrawal"; from: string; to: string; - tokenAddress: string; + token: Token; }; export default ( @@ -51,15 +51,18 @@ export default ( if (!params) throw new Error("Params are not available"); const provider = getProvider(); - const tokenBalance = balances.value.find((e) => e.address === params!.tokenAddress)?.amount || "1"; + const tokenBalance = balances.value.find((e) => e.address === params!.token.address)?.amount || "1"; const [price, limit] = await Promise.all([ retry(() => provider.getGasPrice()), retry(() => { + const isCustomBridge = isExternalBridgeToken(params!.token); + const bridgeAddress = isCustomBridge ? EXTERNAL_BRIDGES[params!.token.address] : ""; return provider[params!.type === "transfer" ? "estimateGasTransfer" : "estimateGasWithdraw"]({ from: params!.from, to: params!.to, - token: params!.tokenAddress === ETH_TOKEN.address ? ETH_TOKEN.l1Address! : params!.tokenAddress, + token: params!.token.address === ETH_TOKEN.address ? ETH_TOKEN.l1Address! : params!.token.address, amount: tokenBalance, + ...(isCustomBridge ? { bridgeAddress } : {}), }); }), ]); diff --git a/views/transactions/Transfer.vue b/views/transactions/Transfer.vue index 6417ed613..fa09e43e7 100644 --- a/views/transactions/Transfer.vue +++ b/views/transactions/Transfer.vue @@ -522,7 +522,7 @@ const estimate = async () => { type: props.type, from: transaction.value.from.address, to: transaction.value.to.address, - tokenAddress: selectedToken.value.address, + token: selectedToken.value, }); }; watch( From 2acf66bd6ff0bbf72a45b5b7c4c1af4ff5075997 Mon Sep 17 00:00:00 2001 From: Nikola Pavlov <nikola@txfusion.io> Date: Fri, 5 Apr 2024 15:14:43 +0200 Subject: [PATCH 3/3] feat: add custom bridge for useWithdrawalFinalization hook --- composables/zksync/useWithdrawalFinalization.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/composables/zksync/useWithdrawalFinalization.ts b/composables/zksync/useWithdrawalFinalization.ts index 64dc508e1..2ad3de3ad 100644 --- a/composables/zksync/useWithdrawalFinalization.ts +++ b/composables/zksync/useWithdrawalFinalization.ts @@ -16,12 +16,16 @@ export default (transactionInfo: ComputedRef<TransactionInfo>) => { const { isCorrectNetworkSet } = storeToRefs(onboardStore); const { tokens } = storeToRefs(tokensStore); - const retrieveBridgeAddress = useMemoize(() => - providerStore + const retrieveBridgeAddress = useMemoize(() => { + const isCustomBridge = isExternalBridgeToken(transactionInfo.value.token); + if (isCustomBridge) { + return EXTERNAL_BRIDGES[transactionInfo.value.token.address]; + } + return providerStore .requestProvider() .getDefaultBridgeAddresses() - .then((e) => e.erc20L1) - ); + .then((e) => e.erc20L1); + }); const retrieveMainContractAddress = useMemoize(() => providerStore.requestProvider().getMainContractAddress()); const gasLimit = ref<BigNumberish | undefined>();