From b802cecd59f321e63a571aa02e123dd3de24ebb6 Mon Sep 17 00:00:00 2001 From: MickWang <1244134672@qq.com> Date: Mon, 8 Apr 2024 20:58:24 +0800 Subject: [PATCH 01/40] update for auto wrap MNT to WMNT when depost --- data/networks.ts | 2 +- store/zksync/ethereumBalance.ts | 7 ++ views/transactions/Deposit.vue | 1 + zksync-web3-nova/abi/WrappedMNT.json | 161 +++++++++++++++++++++++++++ zksync-web3-nova/src/adapters.ts | 35 +++++- zksync-web3-nova/src/utils.ts | 5 + 6 files changed, 207 insertions(+), 4 deletions(-) create mode 100644 zksync-web3-nova/abi/WrappedMNT.json diff --git a/data/networks.ts b/data/networks.ts index 0f66ecf3f..0f46966c1 100644 --- a/data/networks.ts +++ b/data/networks.ts @@ -228,7 +228,7 @@ export const nexusNode: ZkSyncNetwork[] = [ erc20BridgeL1: "0x62351b47e060c61868Ab7E05920Cb42bD9A5f2B2", erc20BridgeL2: "0x321Ce902eDFC6466B224ce5D9A7Bc16858855272", l1Gateway: "0xdE1Ce751405Fe6D836349226EEdCDFFE1C3BE269", - isEthGasToken: false, + isEthGasToken: true, l1Network: l1Networks.mantle, }, { diff --git a/store/zksync/ethereumBalance.ts b/store/zksync/ethereumBalance.ts index d1f5eef01..ae8716ebd 100644 --- a/store/zksync/ethereumBalance.ts +++ b/store/zksync/ethereumBalance.ts @@ -55,6 +55,13 @@ export const useZkSyncEthereumBalanceStore = defineStore("zkSyncEthereumBalances const filterL1tokens = Object.values(l1Tokens.value ?? []).filter( (e) => e.networkKey === selectedNetwork.value.key || e.address === ETH_TOKEN.l1Address ); + if (selectedNetwork.value.key === "mantle") { + const nativeToken = filterL1tokens.find((e) => e.address === ETH_TOKEN.l1Address); + const wmntToken = filterL1tokens.find((e) => e.symbol === "WMNT"); + nativeToken!.symbol = "MNT"; + nativeToken!.price = wmntToken?.price ?? 0; + nativeToken!.iconUrl = "/img/mantle.svg"; + } return await Promise.all([ ...filterL1tokens.map(async (token) => { const amount = await getBalance(wagmiConfig as Config, { diff --git a/views/transactions/Deposit.vue b/views/transactions/Deposit.vue index d59f37509..0bf884f6a 100644 --- a/views/transactions/Deposit.vue +++ b/views/transactions/Deposit.vue @@ -777,6 +777,7 @@ const makeTransaction = async () => { }, 2000); }) .catch((err) => { + console.log(err) transactionError.value = err as Error; transactionStatus.value = "not-started"; }); diff --git a/zksync-web3-nova/abi/WrappedMNT.json b/zksync-web3-nova/abi/WrappedMNT.json new file mode 100644 index 000000000..97ad5a4a7 --- /dev/null +++ b/zksync-web3-nova/abi/WrappedMNT.json @@ -0,0 +1,161 @@ +[ + { "type": "constructor", "inputs": [] }, + { + "type": "function", + "stateMutability": "view", + "outputs": [{ "type": "uint256", "name": "", "internalType": "uint256" }], + "name": "allowance", + "inputs": [ + { "type": "address", "name": "owner", "internalType": "address" }, + { "type": "address", "name": "spender", "internalType": "address" } + ] + }, + { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [{ "type": "bool", "name": "", "internalType": "bool" }], + "name": "approve", + "inputs": [ + { "type": "address", "name": "spender", "internalType": "address" }, + { "type": "uint256", "name": "amount", "internalType": "uint256" } + ] + }, + { + "type": "function", + "stateMutability": "view", + "outputs": [{ "type": "uint256", "name": "", "internalType": "uint256" }], + "name": "balanceOf", + "inputs": [ + { "type": "address", "name": "account", "internalType": "address" } + ] + }, + { + "type": "function", + "stateMutability": "view", + "outputs": [{ "type": "uint8", "name": "", "internalType": "uint8" }], + "name": "decimals", + "inputs": [] + }, + { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [{ "type": "bool", "name": "", "internalType": "bool" }], + "name": "decreaseAllowance", + "inputs": [ + { "type": "address", "name": "spender", "internalType": "address" }, + { + "type": "uint256", + "name": "subtractedValue", + "internalType": "uint256" + } + ] + }, + { + "type": "function", + "stateMutability": "payable", + "outputs": [], + "name": "deposit", + "inputs": [] + }, + { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [{ "type": "bool", "name": "", "internalType": "bool" }], + "name": "increaseAllowance", + "inputs": [ + { "type": "address", "name": "spender", "internalType": "address" }, + { "type": "uint256", "name": "addedValue", "internalType": "uint256" } + ] + }, + { + "type": "function", + "stateMutability": "view", + "outputs": [{ "type": "string", "name": "", "internalType": "string" }], + "name": "name", + "inputs": [] + }, + { + "type": "function", + "stateMutability": "view", + "outputs": [{ "type": "string", "name": "", "internalType": "string" }], + "name": "symbol", + "inputs": [] + }, + { + "type": "function", + "stateMutability": "view", + "outputs": [{ "type": "uint256", "name": "", "internalType": "uint256" }], + "name": "totalSupply", + "inputs": [] + }, + { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [{ "type": "bool", "name": "", "internalType": "bool" }], + "name": "transfer", + "inputs": [ + { "type": "address", "name": "recipient", "internalType": "address" }, + { "type": "uint256", "name": "amount", "internalType": "uint256" } + ] + }, + { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [{ "type": "bool", "name": "", "internalType": "bool" }], + "name": "transferFrom", + "inputs": [ + { "type": "address", "name": "sender", "internalType": "address" }, + { "type": "address", "name": "recipient", "internalType": "address" }, + { "type": "uint256", "name": "amount", "internalType": "uint256" } + ] + }, + { + "type": "function", + "stateMutability": "nonpayable", + "outputs": [], + "name": "withdraw", + "inputs": [ + { "type": "uint256", "name": "_amount", "internalType": "uint256" } + ] + }, + { + "type": "event", + "name": "Approval", + "inputs": [ + { "type": "address", "name": "owner", "indexed": true }, + { "type": "address", "name": "spender", "indexed": true }, + { "type": "uint256", "name": "value", "indexed": false } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Deposit", + "inputs": [ + { "type": "address", "name": "dst", "indexed": true }, + { "type": "uint256", "name": "wad", "indexed": false } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Transfer", + "inputs": [ + { "type": "address", "name": "from", "indexed": true }, + { "type": "address", "name": "to", "indexed": true }, + { "type": "uint256", "name": "value", "indexed": false } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Withdrawal", + "inputs": [ + { "type": "address", "name": "src", "indexed": true }, + { "type": "uint256", "name": "wad", "indexed": false } + ], + "anonymous": false + }, + { "type": "receive" }, + { "type": "fallback" } +] diff --git a/zksync-web3-nova/src/adapters.ts b/zksync-web3-nova/src/adapters.ts index d0a001caf..a242fbeae 100644 --- a/zksync-web3-nova/src/adapters.ts +++ b/zksync-web3-nova/src/adapters.ts @@ -23,13 +23,14 @@ import { undoL1ToL2Alias, estimateDefaultBridgeDepositL2Gas, scaleGasLimit, + WMNT_CONTRACT, } from "./utils"; import { Hash } from "~/types"; import { Interface } from "ethers/lib/utils"; import { abi as primaryGetterAbi } from "../abi/GettersFacet.json"; import { l1EthDepositAbi } from "./abi"; import { Fee, LineaProvider, zkSyncProvider } from "./zkSyncProvider"; //TODO the filename is not accurate - +import WrappedMNTAbi from "../abi/WrappedMNT.json"; type Constructor = new (...args: any[]) => T; interface TxSender { @@ -156,6 +157,13 @@ export function AdapterL1>(Base: TBase) { ); } + async depositMNT(amount: BigNumberish) { + const wmntContract = new ethers.Contract(WMNT_CONTRACT, WrappedMNTAbi, this._signerL1()); + const { hash } = await wmntContract.deposit({ value: amount }); + const res = await this._providerL1().waitForTransaction(hash); + console.log("approve mnt res: ", res); + } + async deposit(transaction: { token: Address; amount: BigNumberish; @@ -168,7 +176,16 @@ export function AdapterL1>(Base: TBase) { overrides?: ethers.PayableOverrides; approveOverrides?: ethers.Overrides; }): Promise { + // handle mnt deposit + let isMntDeposit = false; + if (this._providerL2().isMantleChain() && transaction.token == ETH_ADDRESS) { + isMntDeposit = true; + await this.depositMNT(transaction.amount); + transaction.token = WMNT_CONTRACT; + transaction.approveERC20 = true; + } const depositTx = await this.getDepositTx(transaction); + if (transaction.token == ETH_ADDRESS) { depositTx.overrides ??= {}; console.log("depositTx.overrides", depositTx.overrides); @@ -195,6 +212,9 @@ export function AdapterL1>(Base: TBase) { const gasLimit = scaleGasLimit(baseGasLimit); depositTx.gasLimit = gasLimit; } + if (depositTx.gasLimit && isMntDeposit) { + depositTx.gasLimit = depositTx.gasLimit.mul(2); // or the tx would fail + } if (this._providerL2().isZkSyncChain()) { const fee = await zkSyncProvider.attachEstimateFee()({ @@ -517,7 +537,11 @@ export function AdapterL1>(Base: TBase) { //for mantle and manta async getL1FeeForOp(calldata: string): Promise { - if (!this._providerL2().isMantleChain() && !this._providerL2().isMantaChain() && !this._providerL2().isBlastChain()) { + if ( + !this._providerL2().isMantleChain() && + !this._providerL2().isMantaChain() && + !this._providerL2().isBlastChain() + ) { return BigNumber.from(0); } const abi = [ @@ -846,7 +870,12 @@ async function insertGasPrice( overrides: ethers.PayableOverrides ) { if (!overrides.gasPrice && !overrides.maxFeePerGas) { - if (l2Provider.isArbitrumChain() || l2Provider.isMantaChain() || l2Provider.isMantleChain() || l2Provider.isBlastChain()) { + if ( + l2Provider.isArbitrumChain() || + l2Provider.isMantaChain() || + l2Provider.isMantleChain() || + l2Provider.isBlastChain() + ) { //if arbitrum console.log("arbitrum chain"); console.log("manta chain, mantle chain, arbitrum chain, only support gasPrice"); diff --git a/zksync-web3-nova/src/utils.ts b/zksync-web3-nova/src/utils.ts index 844530a4c..54448f41c 100644 --- a/zksync-web3-nova/src/utils.ts +++ b/zksync-web3-nova/src/utils.ts @@ -37,6 +37,11 @@ export const L2_ETH_TOKEN_ADDRESS = "0x000000000000000000000000000000000000800a" export const L1_TO_L2_ALIAS_OFFSET = "0x1111000000000000000000000000000000001111"; +export const WMNT_CONTRACT = + process.env.NODE_TYPE === "nexus-goerli" + ? "0xEa12Be2389c2254bAaD383c6eD1fa1e15202b52A" + : "0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8"; + export const EIP1271_MAGIC_VALUE = "0x1626ba7e"; export const EIP712_TX_TYPE = 0x71; From 4d9cd13cc0b57b2c1f9d7b143070c5559aa1d16e Mon Sep 17 00:00:00 2001 From: MickWang <1244134672@qq.com> Date: Mon, 8 Apr 2024 21:44:23 +0800 Subject: [PATCH 02/40] unwrap weth when deposit --- .../zksync/useWithdrawalFinalization.ts | 1 + data/networks.ts | 3 + store/zksync/provider.ts | 2 + store/zksync/transactionStatus.ts | 1 + store/zksync/withdrawals.ts | 2 + zksync-web3-nova/abi/weth.json | 213 ++++++++++++++++++ zksync-web3-nova/src/adapters.ts | 13 ++ zksync-web3-nova/src/provider.ts | 14 +- zksync-web3-nova/src/utils.ts | 4 + 9 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 zksync-web3-nova/abi/weth.json diff --git a/composables/zksync/useWithdrawalFinalization.ts b/composables/zksync/useWithdrawalFinalization.ts index db42272eb..b0a8bea57 100644 --- a/composables/zksync/useWithdrawalFinalization.ts +++ b/composables/zksync/useWithdrawalFinalization.ts @@ -48,6 +48,7 @@ export default (transactionInfo: ComputedRef) => { erc20BridgeL1: eraNetwork.erc20BridgeL1, erc20BridgeL2: eraNetwork.erc20BridgeL2, l1Gateway: eraNetwork.l1Gateway, + wethContract: eraNetwork.wethContract }); provider.setIsEthGasToken(eraNetwork.isEthGasToken ?? true); return provider; diff --git a/data/networks.ts b/data/networks.ts index 0f46966c1..e993f6662 100644 --- a/data/networks.ts +++ b/data/networks.ts @@ -149,6 +149,7 @@ export type ZkSyncNetwork = { l1Gateway?: Address; isEthGasToken?: boolean; getTokens?: () => Token[] | Promise; // If blockExplorerApi is specified, tokens will be fetched from there. Otherwise, this function will be used. + wethContract?: Address; }; export const nexusNode: ZkSyncNetwork[] = [ @@ -167,6 +168,7 @@ export const nexusNode: ZkSyncNetwork[] = [ l1Gateway: "0x83Bc7394738A7A084081aF22EEC0051908c0055c", isEthGasToken: true, l1Network: l1Networks.mainnet, + wethContract: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", }, { id: 810180, @@ -214,6 +216,7 @@ export const nexusNode: ZkSyncNetwork[] = [ l1Gateway: "0x273D59aed2d793167c162E64b9162154B07583C0", isEthGasToken: true, l1Network: l1Networks.arbitrum, + wethContract: "0x82af49447d8a07e3bd95bd0d56f35241523fbab1", }, { id: 810180, diff --git a/store/zksync/provider.ts b/store/zksync/provider.ts index c1ff258b3..a17210ca3 100644 --- a/store/zksync/provider.ts +++ b/store/zksync/provider.ts @@ -19,6 +19,7 @@ export const useZkSyncProviderStore = defineStore("zkSyncProvider", () => { erc20BridgeL1: eraNetwork.erc20BridgeL1, erc20BridgeL2: eraNetwork.erc20BridgeL2, l1Gateway: eraNetwork.l1Gateway, + wethContract: eraNetwork.wethContract }); provider.setIsEthGasToken(eraNetwork.isEthGasToken ?? true); return provider; @@ -33,6 +34,7 @@ export const useZkSyncProviderStore = defineStore("zkSyncProvider", () => { erc20BridgeL1: primaryNetwork.erc20BridgeL1, erc20BridgeL2: primaryNetwork.erc20BridgeL2, l1Gateway: primaryNetwork.l1Gateway, + wethContract: primaryNetwork.wethContract }); primaryProvider.setIsEthGasToken(primaryNetwork.isEthGasToken ?? true); return primaryProvider; diff --git a/store/zksync/transactionStatus.ts b/store/zksync/transactionStatus.ts index 1e845dfcd..9fa764e7a 100644 --- a/store/zksync/transactionStatus.ts +++ b/store/zksync/transactionStatus.ts @@ -207,6 +207,7 @@ export const useZkSyncTransactionStatusStore = defineStore("zkSyncTransactionSta erc20BridgeL1: eraNetwork.erc20BridgeL1, erc20BridgeL2: eraNetwork.erc20BridgeL2, l1Gateway: eraNetwork.l1Gateway, + wethContract: eraNetwork.wethContract }); provider.setIsEthGasToken(eraNetwork.isEthGasToken ?? true); return provider; diff --git a/store/zksync/withdrawals.ts b/store/zksync/withdrawals.ts index ceef5023b..cec81ad32 100644 --- a/store/zksync/withdrawals.ts +++ b/store/zksync/withdrawals.ts @@ -56,6 +56,7 @@ export const useZkSyncWithdrawalsStore = defineStore("zkSyncWithdrawals", () => erc20BridgeL1: eraNetwork.erc20BridgeL1, erc20BridgeL2: eraNetwork.erc20BridgeL2, l1Gateway: eraNetwork.l1Gateway, + wethContract: eraNetwork.wethContract }); provider.setIsEthGasToken(eraNetwork.isEthGasToken ?? true); return provider; @@ -141,6 +142,7 @@ export const useZkSyncWithdrawalsStore = defineStore("zkSyncWithdrawals", () => erc20BridgeL1: eraNetworks.erc20BridgeL1, erc20BridgeL2: eraNetworks.erc20BridgeL2, l1Gateway: eraNetworks.l1Gateway, + wethContract: eraNetworks.wethContract, }); provider.setIsEthGasToken(eraNetworks.isEthGasToken ?? true); return provider; diff --git a/zksync-web3-nova/abi/weth.json b/zksync-web3-nova/abi/weth.json new file mode 100644 index 000000000..06190c86a --- /dev/null +++ b/zksync-web3-nova/abi/weth.json @@ -0,0 +1,213 @@ +[{ + "constant": true, + "inputs": [], + "name": "name", + "outputs": [{ + "name": "", + "type": "string" + }], + "payable": false, + "stateMutability": "view", + "type": "function" +}, { + "constant": false, + "inputs": [{ + "name": "guy", + "type": "address" + }, { + "name": "wad", + "type": "uint256" + }], + "name": "approve", + "outputs": [{ + "name": "", + "type": "bool" + }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" +}, { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [{ + "name": "", + "type": "uint256" + }], + "payable": false, + "stateMutability": "view", + "type": "function" +}, { + "constant": false, + "inputs": [{ + "name": "src", + "type": "address" + }, { + "name": "dst", + "type": "address" + }, { + "name": "wad", + "type": "uint256" + }], + "name": "transferFrom", + "outputs": [{ + "name": "", + "type": "bool" + }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" +}, { + "constant": false, + "inputs": [{ + "name": "wad", + "type": "uint256" + }], + "name": "withdraw", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" +}, { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [{ + "name": "", + "type": "uint8" + }], + "payable": false, + "stateMutability": "view", + "type": "function" +}, { + "constant": true, + "inputs": [{ + "name": "", + "type": "address" + }], + "name": "balanceOf", + "outputs": [{ + "name": "", + "type": "uint256" + }], + "payable": false, + "stateMutability": "view", + "type": "function" +}, { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [{ + "name": "", + "type": "string" + }], + "payable": false, + "stateMutability": "view", + "type": "function" +}, { + "constant": false, + "inputs": [{ + "name": "dst", + "type": "address" + }, { + "name": "wad", + "type": "uint256" + }], + "name": "transfer", + "outputs": [{ + "name": "", + "type": "bool" + }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" +}, { + "constant": false, + "inputs": [], + "name": "deposit", + "outputs": [], + "payable": true, + "stateMutability": "payable", + "type": "function" +}, { + "constant": true, + "inputs": [{ + "name": "", + "type": "address" + }, { + "name": "", + "type": "address" + }], + "name": "allowance", + "outputs": [{ + "name": "", + "type": "uint256" + }], + "payable": false, + "stateMutability": "view", + "type": "function" +}, { + "payable": true, + "stateMutability": "payable", + "type": "fallback" +}, { + "anonymous": false, + "inputs": [{ + "indexed": true, + "name": "src", + "type": "address" + }, { + "indexed": true, + "name": "guy", + "type": "address" + }, { + "indexed": false, + "name": "wad", + "type": "uint256" + }], + "name": "Approval", + "type": "event" +}, { + "anonymous": false, + "inputs": [{ + "indexed": true, + "name": "src", + "type": "address" + }, { + "indexed": true, + "name": "dst", + "type": "address" + }, { + "indexed": false, + "name": "wad", + "type": "uint256" + }], + "name": "Transfer", + "type": "event" +}, { + "anonymous": false, + "inputs": [{ + "indexed": true, + "name": "dst", + "type": "address" + }, { + "indexed": false, + "name": "wad", + "type": "uint256" + }], + "name": "Deposit", + "type": "event" +}, { + "anonymous": false, + "inputs": [{ + "indexed": true, + "name": "src", + "type": "address" + }, { + "indexed": false, + "name": "wad", + "type": "uint256" + }], + "name": "Withdrawal", + "type": "event" +}] \ No newline at end of file diff --git a/zksync-web3-nova/src/adapters.ts b/zksync-web3-nova/src/adapters.ts index a242fbeae..3870331a4 100644 --- a/zksync-web3-nova/src/adapters.ts +++ b/zksync-web3-nova/src/adapters.ts @@ -24,6 +24,7 @@ import { estimateDefaultBridgeDepositL2Gas, scaleGasLimit, WMNT_CONTRACT, + isSameAddress, } from "./utils"; import { Hash } from "~/types"; import { Interface } from "ethers/lib/utils"; @@ -31,6 +32,7 @@ import { abi as primaryGetterAbi } from "../abi/GettersFacet.json"; import { l1EthDepositAbi } from "./abi"; import { Fee, LineaProvider, zkSyncProvider } from "./zkSyncProvider"; //TODO the filename is not accurate import WrappedMNTAbi from "../abi/WrappedMNT.json"; +import WethAbi from "../abi/weth.json"; type Constructor = new (...args: any[]) => T; interface TxSender { @@ -164,6 +166,13 @@ export function AdapterL1>(Base: TBase) { console.log("approve mnt res: ", res); } + async unwrapWETH(amount: BigNumberish) { + const weth = await this._providerL2().getWETHContractAddress(); + const wethContract = new ethers.Contract(weth, WethAbi, this._signerL1()); + const { hash } = await wethContract.withdraw(amount); + await this._providerL1().waitForTransaction(hash); + } + async deposit(transaction: { token: Address; amount: BigNumberish; @@ -184,6 +193,10 @@ export function AdapterL1>(Base: TBase) { transaction.token = WMNT_CONTRACT; transaction.approveERC20 = true; } + if (isSameAddress(transaction.token, await this._providerL2().getWETHContractAddress())) { + await this.unwrapWETH(transaction.amount); + transaction.token = ETH_ADDRESS; + } const depositTx = await this.getDepositTx(transaction); if (transaction.token == ETH_ADDRESS) { diff --git a/zksync-web3-nova/src/provider.ts b/zksync-web3-nova/src/provider.ts index a10216c03..82805de17 100644 --- a/zksync-web3-nova/src/provider.ts +++ b/zksync-web3-nova/src/provider.ts @@ -43,6 +43,7 @@ export type ContractAddresses = { erc20BridgeL1?: Address; erc20BridgeL2?: Address; l1Gateway?: Address; + wethContract?: Address; }; export class Provider extends ethers.providers.JsonRpcProvider { protected contractAddressesMap: Map; @@ -311,7 +312,7 @@ export class Provider extends ethers.providers.JsonRpcProvider { return this.networkKey === "blast"; } isLineaChain(): boolean { - return this.isPrimaryChain() + return this.isPrimaryChain(); } isZkSyncChain(): boolean { return this.networkKey === "zksync"; @@ -377,6 +378,17 @@ export class Provider extends ethers.providers.JsonRpcProvider { return contractAddresses.mainContract!; } + async getWETHContractAddress(): Promise
{ + let contractAddresses = this.contractAddressesMap.get(this.networkKey); + if (!contractAddresses) { + throw new Error("networkKey: " + this.networkKey + " is undefined"); + } + // if (!contractAddresses.mainContract) { + // contractAddresses.mainContract = await this.send("zks_getMainContract", []); + // } + return contractAddresses.wethContract!; + } + async getTestnetPaymasterAddress(): Promise
{ // Unlike contract's addresses, the testnet paymaster is not cached, since it can be trivially changed // on the fly by the server and should not be relied to be constant diff --git a/zksync-web3-nova/src/utils.ts b/zksync-web3-nova/src/utils.ts index 54448f41c..988336e02 100644 --- a/zksync-web3-nova/src/utils.ts +++ b/zksync-web3-nova/src/utils.ts @@ -582,3 +582,7 @@ export async function fetchErc20( decimals: decimals, } as TokenAmount; } + +export function isSameAddress(a: Address, b: Address) { + return a && b && a.toLowerCase() === b.toLowerCase(); +} \ No newline at end of file From e965cb93ac8e6ade98a728aa19d46582c4dab6c5 Mon Sep 17 00:00:00 2001 From: MickWang <1244134672@qq.com> Date: Tue, 9 Apr 2024 14:04:56 +0800 Subject: [PATCH 03/40] add weth contracts --- data/networks.ts | 13 ++++++++++--- store/zksync/wallet.ts | 2 +- zksync-web3-nova/src/adapters.ts | 14 +++++++++----- zksync-web3-nova/src/provider.ts | 4 ++-- 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/data/networks.ts b/data/networks.ts index e993f6662..f03019719 100644 --- a/data/networks.ts +++ b/data/networks.ts @@ -149,7 +149,7 @@ export type ZkSyncNetwork = { l1Gateway?: Address; isEthGasToken?: boolean; getTokens?: () => Token[] | Promise; // If blockExplorerApi is specified, tokens will be fetched from there. Otherwise, this function will be used. - wethContract?: Address; + wethContract?: Address[]; }; export const nexusNode: ZkSyncNetwork[] = [ @@ -168,7 +168,7 @@ export const nexusNode: ZkSyncNetwork[] = [ l1Gateway: "0x83Bc7394738A7A084081aF22EEC0051908c0055c", isEthGasToken: true, l1Network: l1Networks.mainnet, - wethContract: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + wethContract: ["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"], }, { id: 810180, @@ -184,6 +184,7 @@ export const nexusNode: ZkSyncNetwork[] = [ erc20BridgeL2: "0x01c3f51294494e350AD69B999Db6B382b3B510b9", isEthGasToken: true, l1Network: l1Networks.linea, + wethContract: ["0xe5d7c2a44ffddf6b295a15c148167daaaf5cf34f"], }, { id: 810180, @@ -200,6 +201,7 @@ export const nexusNode: ZkSyncNetwork[] = [ l1Gateway: "0xeCD189e0f390826E137496a4e4a23ACf76c942Ab", isEthGasToken: true, l1Network: l1Networks.zkSync, + wethContract: ["0x5aea5775959fbc2557cc8789bc1bf90a239d9a91", "0x8Ebe4A94740515945ad826238Fc4D56c6B8b0e60"], }, { id: 810180, @@ -216,7 +218,7 @@ export const nexusNode: ZkSyncNetwork[] = [ l1Gateway: "0x273D59aed2d793167c162E64b9162154B07583C0", isEthGasToken: true, l1Network: l1Networks.arbitrum, - wethContract: "0x82af49447d8a07e3bd95bd0d56f35241523fbab1", + wethContract: ["0x82af49447d8a07e3bd95bd0d56f35241523fbab1"], }, { id: 810180, @@ -233,6 +235,7 @@ export const nexusNode: ZkSyncNetwork[] = [ l1Gateway: "0xdE1Ce751405Fe6D836349226EEdCDFFE1C3BE269", isEthGasToken: true, l1Network: l1Networks.mantle, + wethContract: ["0xdEAddEaDdeadDEadDEADDEAddEADDEAddead1111"], }, { id: 810180, @@ -249,6 +252,7 @@ export const nexusNode: ZkSyncNetwork[] = [ l1Gateway: "0x649Dfa2c4d09D877419fA1eDC4005BfbEF7CD82D", isEthGasToken: true, l1Network: l1Networks.manta, + wethContract: ["0x0Dc808adcE2099A9F62AA87D9670745AbA741746"], }, { id: 810180, @@ -265,6 +269,7 @@ export const nexusNode: ZkSyncNetwork[] = [ l1Gateway: "0x41FaF46Ca4Dfd912B65B66D29BdD432782BB1158", isEthGasToken: true, l1Network: l1Networks.blast, + wethContract: ["0x4300000000000000000000000000000000000004"], }, { id: 810180, @@ -281,6 +286,7 @@ export const nexusNode: ZkSyncNetwork[] = [ l1Gateway: "0x668e8F67adB8219e1816C2E5bBEa055A78AF3026", isEthGasToken: true, l1Network: l1Networks.optimism, + wethContract: ["0x4200000000000000000000000000000000000006"], }, { id: 810180, @@ -297,6 +303,7 @@ export const nexusNode: ZkSyncNetwork[] = [ l1Gateway: "0x4eEA93966AA5cd658225E0D43b665A5a491d2b7E", isEthGasToken: true, l1Network: l1Networks.base, + wethContract: ["0x4200000000000000000000000000000000000006"], }, ]; diff --git a/store/zksync/wallet.ts b/store/zksync/wallet.ts index 1258766fc..1516c96ce 100644 --- a/store/zksync/wallet.ts +++ b/store/zksync/wallet.ts @@ -69,7 +69,7 @@ export const useZkSyncWalletStore = defineStore("zkSyncWallet", () => { const getPrimaryL1VoidSigner = () => { const web3Provider = new ethers.providers.Web3Provider( - getPublicClient({ chainId: primaryNetwork.l1Network?.id }) as any, + onboardStore.getPublicClient(primaryNetwork.l1Network?.id) as any, "any" ); const voidSigner = new VoidSigner(account.value.address || ETH_TOKEN.address, web3Provider); diff --git a/zksync-web3-nova/src/adapters.ts b/zksync-web3-nova/src/adapters.ts index 3870331a4..842e68b27 100644 --- a/zksync-web3-nova/src/adapters.ts +++ b/zksync-web3-nova/src/adapters.ts @@ -166,9 +166,12 @@ export function AdapterL1>(Base: TBase) { console.log("approve mnt res: ", res); } - async unwrapWETH(amount: BigNumberish) { - const weth = await this._providerL2().getWETHContractAddress(); - const wethContract = new ethers.Contract(weth, WethAbi, this._signerL1()); + async unwrapWETH(token: Address, amount: BigNumberish) { + const weths = await this._providerL2().getWETHContractAddress(); + if (!weths.map((item) => item.toLowerCase().includes(token.toLowerCase()))) { + return; + } + const wethContract = new ethers.Contract(token, WethAbi, this._signerL1()); const { hash } = await wethContract.withdraw(amount); await this._providerL1().waitForTransaction(hash); } @@ -193,8 +196,9 @@ export function AdapterL1>(Base: TBase) { transaction.token = WMNT_CONTRACT; transaction.approveERC20 = true; } - if (isSameAddress(transaction.token, await this._providerL2().getWETHContractAddress())) { - await this.unwrapWETH(transaction.amount); + const weths = await this._providerL2().getWETHContractAddress(); + if (weths.map((item) => item.toLowerCase()).includes(transaction.token.toLowerCase())) { + await this.unwrapWETH(transaction.token, transaction.amount); transaction.token = ETH_ADDRESS; } const depositTx = await this.getDepositTx(transaction); diff --git a/zksync-web3-nova/src/provider.ts b/zksync-web3-nova/src/provider.ts index 82805de17..a9c2f614d 100644 --- a/zksync-web3-nova/src/provider.ts +++ b/zksync-web3-nova/src/provider.ts @@ -43,7 +43,7 @@ export type ContractAddresses = { erc20BridgeL1?: Address; erc20BridgeL2?: Address; l1Gateway?: Address; - wethContract?: Address; + wethContract?: Address[]; }; export class Provider extends ethers.providers.JsonRpcProvider { protected contractAddressesMap: Map; @@ -378,7 +378,7 @@ export class Provider extends ethers.providers.JsonRpcProvider { return contractAddresses.mainContract!; } - async getWETHContractAddress(): Promise
{ + async getWETHContractAddress(): Promise { let contractAddresses = this.contractAddressesMap.get(this.networkKey); if (!contractAddresses) { throw new Error("networkKey: " + this.networkKey + " is undefined"); From 26e0260fd5dd485c71ea0e2c7bd598a7cd7773b9 Mon Sep 17 00:00:00 2001 From: MickWang <1244134672@qq.com> Date: Wed, 10 Apr 2024 11:49:49 +0800 Subject: [PATCH 04/40] fix lint issues --- components/common/Timer.vue | 2 +- components/common/button/Dropdown.vue | 8 +- components/common/input/TransactionSend.vue | 16 +- .../common/input/TransactionWithdraw.vue | 19 +- components/destination/DestinationItem.vue | 14 +- components/header/AccountDropdownButton.vue | 2 +- components/header/Header.vue | 32 +- components/header/MobileMainNavigation.vue | 4 + components/header/NetworkDropdown.vue | 4 +- components/network/NetworkSelectModal.vue | 56 +-- components/token/TokenLine.vue | 2 +- components/token/TokenSelectModal.vue | 38 +- components/token/TokenSelectModalSend.vue | 9 +- components/transaction/TransactionFooter.vue | 2 +- components/transaction/TransferLineItem.vue | 5 +- .../TransferWithdrawalLineItem.vue | 7 +- .../transaction/summary/AddressEntry.vue | 6 +- composables/transaction/useAllowance.ts | 2 +- composables/transaction/useMergeToken.ts | 3 +- composables/useNetworks.ts | 2 +- composables/zksync/deposit/useFee.ts | 15 +- composables/zksync/deposit/useTransaction.ts | 2 +- composables/zksync/useFee.ts | 2 +- .../zksync/useWithdrawalFinalization.ts | 9 +- data/customBridgeTokens.ts | 3 +- data/iconlists.ts | 3 +- nuxt.config.ts | 22 +- pages/assets.vue | 2 +- pages/transfers.vue | 6 +- store/searchToken.ts | 6 +- store/zksync/ethereumBalance.ts | 7 +- store/zksync/provider.ts | 8 +- store/zksync/tokens.ts | 2 +- store/zksync/transactionStatus.ts | 20 +- store/zksync/withdrawals.ts | 2 +- tests/e2e/src/helpers/helper.ts | 3 +- views/transactions/Deposit.vue | 41 +- views/transactions/DepositSubmitted.vue | 2 + views/transactions/Send.vue | 8 +- views/transactions/Withdraw.vue | 57 +-- views/transactions/WithdrawalSubmitted.vue | 4 +- zksync-web3-nova/src/adapters.ts | 64 +-- zksync-web3-nova/src/calldata.ts | 138 +++---- zksync-web3-nova/src/contract.ts | 150 +++---- zksync-web3-nova/src/index.ts | 12 +- zksync-web3-nova/src/paymaster-utils.ts | 48 ++- zksync-web3-nova/src/provider.ts | 90 ++-- zksync-web3-nova/src/signer.ts | 385 +++++++++--------- zksync-web3-nova/src/types.ts | 218 +++++----- zksync-web3-nova/src/utils.ts | 43 +- zksync-web3-nova/src/wallet.ts | 246 ++++++----- zksync-web3-nova/src/zkSyncProvider.ts | 5 +- zksync-web3-nova/typechain/index.ts | 25 +- 53 files changed, 988 insertions(+), 893 deletions(-) diff --git a/components/common/Timer.vue b/components/common/Timer.vue index 1e063c3a6..546b901a9 100644 --- a/components/common/Timer.vue +++ b/components/common/Timer.vue @@ -39,7 +39,7 @@ let intervalId: ReturnType | undefined = undefined; const formatTimeDiff = (diff: number): string => { const day = Math.floor(diff / (1000 * 60 * 60 * 24)); - const hours = Math.floor(diff % (1000 * 60 * 60 * 24) / (1000 * 60 * 60)); + const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)); const seconds = Math.floor((diff % (1000 * 60)) / 1000); diff --git a/components/common/button/Dropdown.vue b/components/common/button/Dropdown.vue index 53dce1c62..91cc07810 100644 --- a/components/common/button/Dropdown.vue +++ b/components/common/button/Dropdown.vue @@ -1,5 +1,5 @@ + { query: { network: eraNetwork.value.key }, }).href ); + setTokenAllowance() waitForCompletion(transactionInfo.value) .then(async (completedTransaction) => { transactionInfo.value = completedTransaction; @@ -1104,6 +1114,13 @@ onBeforeUnmount(() => { color: #0bc48f; } } +.warnNote { + color: #f29914; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: normal; +} .warnBox { display: inline-flex; padding: 0 0 16px 0; From b9068ff9761db08c2945a30f7f5688a6df456a5f Mon Sep 17 00:00:00 2001 From: MickWang <1244134672@qq.com> Date: Mon, 15 Apr 2024 23:13:37 +0800 Subject: [PATCH 10/40] update estimate withdraw left time --- components/common/Timer.vue | 11 ++++-- .../transaction/TransactionProgress.vue | 36 +++++++++++++++++-- views/transactions/WithdrawalSubmitted.vue | 1 + 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/components/common/Timer.vue b/components/common/Timer.vue index 1e063c3a6..95021ecc3 100644 --- a/components/common/Timer.vue +++ b/components/common/Timer.vue @@ -16,6 +16,10 @@ const props = defineProps({ type: String, default: "hh:mm:ss", // 'hh:mm:ss' for "00:00:00", 'human-readable' for "1 hour 30 minutes" }, + onlyDays: { + type: Boolean, + default: false, + }, }); const emit = defineEmits<{ (eventName: "finish"): void; @@ -37,13 +41,16 @@ watch( let intervalId: ReturnType | undefined = undefined; -const formatTimeDiff = (diff: number): string => { +const formatTimeDiff = (diff: number, onlyDays = false): string => { const day = Math.floor(diff / (1000 * 60 * 60 * 24)); const hours = Math.floor(diff % (1000 * 60 * 60 * 24) / (1000 * 60 * 60)); const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)); const seconds = Math.floor((diff % (1000 * 60)) / 1000); if (props.format === "human-readable") { + if (onlyDays) { + return `~ ${day} day${day !== 1 ? "s" : ""}` + } let formattedString = ""; if (hours > 0) formattedString += `${day} day ${hours} hour${hours > 1 ? "s" : ""} `; if (minutes > 0) formattedString += `${minutes} minute${minutes > 1 ? "s" : ""} `; @@ -61,7 +68,7 @@ const updateTimer = () => { const currentTime = new Date().getTime(); const targetTime = new Date(props.futureDate).getTime(); diff.value = Math.max(targetTime - currentTime, 0); - timer.value = formatTimeDiff(diff.value); + timer.value = formatTimeDiff(diff.value, props.onlyDays); if (diff.value === 0) { clearInterval(intervalId); diff --git a/components/transaction/TransactionProgress.vue b/components/transaction/TransactionProgress.vue index cc0b7bc1d..2c7351364 100644 --- a/components/transaction/TransactionProgress.vue +++ b/components/transaction/TransactionProgress.vue @@ -89,12 +89,18 @@
- Time: - + Time{{ !isWithdraw ? "" : " left" }}: + @@ -162,6 +168,10 @@ const props = defineProps({ animationState: { type: String as PropType, }, + isWithdraw: { + type: Boolean, + default: false, + } }); const isSameAddress = computed(() => props.fromAddress === props.toAddress); @@ -220,4 +230,24 @@ const isSameAddressDifferentDestination = computed( } } } +.showTip:hover { + .tooltip { + display: block; + z-index: 100; + } +} +.tooltip { + display: none; + position: absolute; + padding: 12px 20px 12px 24px; + bottom: 105%; + width: 30rem; + left: -15rem; + border-radius: 8px; + background: #1f2127; + color: #ffffff; + font-size: 14px; + font-weight: 400; + transition: all .5s linear; +} diff --git a/views/transactions/WithdrawalSubmitted.vue b/views/transactions/WithdrawalSubmitted.vue index 66b07f959..b79ccd9b0 100644 --- a/views/transactions/WithdrawalSubmitted.vue +++ b/views/transactions/WithdrawalSubmitted.vue @@ -52,6 +52,7 @@ :expected-complete-timestamp=" withdrawalFinalizationAvailable ? undefined : transaction.info.expectedCompleteTimestamp " + :is-withdraw="true" >