From 04b156eec0c928884c675fbf2a056bc5ccfee2a1 Mon Sep 17 00:00:00 2001 From: petarTxFusion Date: Sat, 8 Jun 2024 15:35:03 +0200 Subject: [PATCH] refactor: update `Withdraw` and `Transfer` to use `L2_BASE_TOKEN_ADDRESS` --- Sources/ZkSync2/Accounts/Adapter.swift | 2 +- Sources/ZkSync2/Accounts/WalletL1.swift | 30 ++++----- Sources/ZkSync2/Accounts/WalletL2.swift | 6 +- Sources/ZkSync2/Clients/BaseClient.swift | 62 ++++++++++++------- Sources/ZkSync2/Clients/ZkSyncClient.swift | 2 + .../ZkSyncWalletIntegrationTests.swift | 8 +-- 6 files changed, 67 insertions(+), 43 deletions(-) diff --git a/Sources/ZkSync2/Accounts/Adapter.swift b/Sources/ZkSync2/Accounts/Adapter.swift index cb10952..0d51578 100644 --- a/Sources/ZkSync2/Accounts/Adapter.swift +++ b/Sources/ZkSync2/Accounts/Adapter.swift @@ -67,7 +67,7 @@ public protocol AdapterL2 { // Balance returns the balance of the specified token that can be either ETH or any ERC20 token. // The block number can be nil, in which case the balance is taken from the latest known block. - func balance(token: String, blockNumber: BlockNumber) async throws -> BigUInt + func balance(token: String?, blockNumber: BlockNumber) async throws -> BigUInt // AllBalances returns all balances for confirmed tokens given by an associated // account. func allBalances(_ address: String) async throws -> Dictionary diff --git a/Sources/ZkSync2/Accounts/WalletL1.swift b/Sources/ZkSync2/Accounts/WalletL1.swift index b162876..24b8560 100644 --- a/Sources/ZkSync2/Accounts/WalletL1.swift +++ b/Sources/ZkSync2/Accounts/WalletL1.swift @@ -131,7 +131,7 @@ extension WalletL1 { let params = await _finalizeWithdrawalParams(withdrawHash: withdrawalHash, index: index) let transaction = CodableTransaction(type: .eip1559, to: EthereumAddress(signer.address)!) - let l1Bridge = ethClient.web3.contract(Web3Utils.IL1Bridge, at: EthereumAddress(try await getL1BridgeContracts().l1SharedDefaultBridge), transaction: transaction) + let l1Bridge = ethClient.web3.contract(Web3Utils.IL1SharedBridge, at: EthereumAddress(try await getL1BridgeContracts().l1SharedDefaultBridge), transaction: transaction) let writeOperation = l1Bridge!.createWriteOperation("finalizeWithdrawal", parameters: [params]) if var tx = writeOperation?.transaction{ @@ -151,29 +151,31 @@ extension WalletL1 { let hexHash = withdrawHash let proof = try! await zkSync.logProof(txHash: hexHash, logIndex: l2ToL1LogIndex) let l2BlockNumber = receipt.l1BatchNumber + let chainId = try! await zkSync.chainID() - if sender.lowercased() == EthereumAddress.L2EthTokenAddress.address.lowercased() - || sender.lowercased() == EthereumAddress.Default.address.lowercased() { - let mainContract = try! await mainContract() - return try! await mainContract.createReadOperation("isEthWithdrawalFinalized", parameters: [l2BlockNumber!, proof.id])?.callContractMethod()["0"] as! Bool - } + var l1Bridge: Web3.Contract - let l2Bridge = zkSync.web3.contract(Web3Utils.IL2Bridge, at: EthereumAddress(sender)!) - let l1BridgeAddress = try! await l2Bridge?.createReadOperation("l1Bridge", parameters: [])?.callContractMethod()["0"] as! EthereumAddress - let l1Bridge = ethClient.web3.contract(Web3Utils.IL1Bridge, at: l1BridgeAddress) + if try! await zkSync.isBaseToken(tokenAddress: sender) { + l1Bridge = ethClient.web3.contract(Web3Utils.IL1SharedBridge, at: EthereumAddress(from: try! await zkSync.bridgeContracts().l1SharedDefaultBridge)!)! + }else{ + let l2Bridge = zkSync.web3.contract(Web3Utils.IL2SharedBridge, at: EthereumAddress(sender)!) + let l1BridgeAddress = try! await l2Bridge?.createReadOperation("l1SharedBridge", parameters: [])?.callContractMethod()["0"] as! EthereumAddress + l1Bridge = ethClient.web3.contract(Web3Utils.IL1Bridge, at: l1BridgeAddress)! + + } - return try! await l1Bridge!.createReadOperation("isWithdrawalFinalized", parameters: [l2BlockNumber!, proof.id])?.callContractMethod()["0"] as! Bool + return try! await l1Bridge.createReadOperation("isWithdrawalFinalized", parameters: [chainId, l2BlockNumber!, proof.id])?.callContractMethod()["0"] as! Bool } - func _finalizeWithdrawalParams(withdrawHash: String, index: Int) async -> (BigUInt, Int, UInt, Data, String?, [String]) { + func _finalizeWithdrawalParams(withdrawHash: String, index: Int) async -> (BigUInt, BigUInt, Int, UInt, Data, String?, [String]) { let receipt = try! await zkSync.web3.eth.transactionReceipt(Data(hex: withdrawHash)) let (log, _) = _getWithdrawalLog(receipt: receipt, index: UInt(index))! let (l2ToL1LogIndex, _) = _getWithdrawL2ToL1Log(txReceipt: receipt, index: index)! let sender = log.topics[1].suffix(from: 12).toHexString().addHexPrefix() let proof = try! await zkSync.logProof(txHash: withdrawHash, logIndex: l2ToL1LogIndex) let msg = ABIDecoder.decodeSingleType(type: ABI.Element.ParameterType.dynamicBytes, data: log.data).value as! Data - - return (receipt.l1BatchNumber!, proof.id, receipt.l1BatchTxIndex!, msg, sender, proof.proof) + let chainId = try! await zkSync.chainID() + return (chainId ,receipt.l1BatchNumber!, proof.id, receipt.l1BatchTxIndex!, msg, sender, proof.proof) } func _getWithdrawalLog(receipt: TransactionReceipt, index: UInt = 0) -> (EventLog, Int)?{ @@ -217,7 +219,7 @@ extension WalletL1 { let address = try await self.zkSync.mainContract() let zkSyncContract = self.web.contract( - Web3.Utils.IZkSync, + Web3.Utils.IZkSyncHyperchain, at: EthereumAddress(address), transaction: transaction )! diff --git a/Sources/ZkSync2/Accounts/WalletL2.swift b/Sources/ZkSync2/Accounts/WalletL2.swift index b164c6b..dcd4f3d 100644 --- a/Sources/ZkSync2/Accounts/WalletL2.swift +++ b/Sources/ZkSync2/Accounts/WalletL2.swift @@ -31,7 +31,7 @@ } extension WalletL2 { - public func balance(token: String = ZkSyncAddresses.EthAddress, blockNumber: BlockNumber = .latest) async -> BigUInt { + public func balance(token: String? = nil, blockNumber: BlockNumber = .latest) async -> BigUInt { try! await zkSync.getBalance(address: signer.address, blockNumber: blockNumber, token: token) } @@ -40,6 +40,10 @@ } public func withdraw(_ amount: BigUInt, to: String?, token: String? = nil, options: TransactionOption? = nil, paymasterParams: PaymasterParams? = nil) async throws -> TransactionSendingResult? { + return try await withdraw(amount, to: to, token: token, options: options, paymasterParams: paymasterParams, bridgeAddress: nil) + } + + public func withdraw(_ amount: BigUInt, to: String?, token: String? = nil, options: TransactionOption? = nil, paymasterParams: PaymasterParams? = nil, bridgeAddress: String? = nil) async throws -> TransactionSendingResult? { var transaction = try await zkSync.getWithdrawTx(amount, from: signer.address, to: to, token: token, options: options, paymasterParams: paymasterParams) await populateTransaction(&transaction) let signed = signTransaction(transaction) diff --git a/Sources/ZkSync2/Clients/BaseClient.swift b/Sources/ZkSync2/Clients/BaseClient.swift index 60ad2ef..57f13d2 100644 --- a/Sources/ZkSync2/Clients/BaseClient.swift +++ b/Sources/ZkSync2/Clients/BaseClient.swift @@ -50,7 +50,15 @@ public class BaseClient: ZkSyncClient { } public func getBalance(address: String, blockNumber: BlockNumber = .latest, token: String?) async throws -> BigUInt { - if token == nil || token == ZkSyncAddresses.EthAddress { + var token = token + if token == nil { + token = ZkSyncAddresses.L2_BASE_TOKEN_ADDRESS + }else if ZkSyncAddresses.isAddressEq(a: token!, b: ZkSyncAddresses.ETH_ADDRESS_IN_CONTRACTS) || + ZkSyncAddresses.isAddressEq(a: token!, b: ZkSyncAddresses.LEGACY_ETH_ADDRESS){ + token = try! await l2TokenAddress(address: ZkSyncAddresses.ETH_ADDRESS_IN_CONTRACTS) + } + + if token == ZkSyncAddresses.L2_BASE_TOKEN_ADDRESS { return try await web3.eth.getBalance(for: EthereumAddress(address)!, onBlock: blockNumber) } @@ -69,10 +77,17 @@ public class BaseClient: ZkSyncClient { } public func l2TokenAddress(address: String) async throws -> String { - if address == ZkSyncAddresses.EthAddress { - return address + var address = address + if address == ZkSyncAddresses.LEGACY_ETH_ADDRESS { + address = ZkSyncAddresses.ETH_ADDRESS_IN_CONTRACTS + } + + let baseToken = try await getBaseTokenContractAddress() + if ZkSyncAddresses.isAddressEq(a: baseToken, b: address){ + return ZkSyncAddresses.L2_BASE_TOKEN_ADDRESS } - let bridgeAddress = try await bridgeContracts().l2Erc20DefaultBridge + + let bridgeAddress = try await bridgeContracts().l2SharedDefaultBridge let bridge = web3.contract(Web3Utils.IL2Bridge, at: EthereumAddress(bridgeAddress)!) let result = try await bridge?.createReadOperation("l2TokenAddress", parameters: [address])?.callContractMethod()["0"] as! EthereumAddress return result.address @@ -273,15 +288,16 @@ public class BaseClient: ZkSyncClient { } public func getWithdrawTx(_ amount: BigUInt, from: String, to: String?, token: String? = nil, options: TransactionOption? = nil, paymasterParams: PaymasterParams? = nil) async throws -> CodableTransaction{ - let isEthChain = try! await isEthBasedChain() - var token = token != nil && ZkSyncAddresses.isAddressEq(a: token!, b: ZkSyncAddresses.LEGACY_ETH_ADDRESS) ? ZkSyncAddresses.ETH_ADDRESS_IN_CONTRACTS : token - let isBaseToken = token != nil ? try! await isBaseToken(tokenAddress: token!) : true - - if token != nil && - ZkSyncAddresses.isAddressEq(a: token!, b: ZkSyncAddresses.LEGACY_ETH_ADDRESS) && !isEthChain { - token = try! await l2TokenAddress(address: ZkSyncAddresses.ETH_ADDRESS_IN_CONTRACTS) - } else if token == nil || (isBaseToken){ + return try await getWithdrawTx(amount, from: from, to: to, token: token, options: options, paymasterParams: paymasterParams, bridgeAddress: nil) + } + + public func getWithdrawTx(_ amount: BigUInt, from: String, to: String?, token: String? = nil, options: TransactionOption? = nil, paymasterParams: PaymasterParams? = nil, bridgeAddress: String? = nil) async throws -> CodableTransaction{ + var token = token + if token == nil { token = ZkSyncAddresses.L2_BASE_TOKEN_ADDRESS + }else if ZkSyncAddresses.isAddressEq(a: token!, b: ZkSyncAddresses.ETH_ADDRESS_IN_CONTRACTS) || + ZkSyncAddresses.isAddressEq(a: token!, b: ZkSyncAddresses.LEGACY_ETH_ADDRESS){ + token = try await l2TokenAddress(address: ZkSyncAddresses.ETH_ADDRESS_IN_CONTRACTS) } let to = to ?? from @@ -293,7 +309,7 @@ public class BaseClient: ZkSyncClient { nonce = try await web3.eth.getTransactionCount(for: EthereumAddress(from)!) } let prepared = CodableTransaction.createEtherTransaction(from: EthereumAddress(from)!, to: EthereumAddress(to)!, value: amount, nonce: nonce, paymasterParams: paymasterParams) - if isBaseToken { + if ZkSyncAddresses.isAddressEq(a: token!, b: ZkSyncAddresses.L2_BASE_TOKEN_ADDRESS) { if options?.value == nil { options?.value = amount } @@ -303,8 +319,12 @@ public class BaseClient: ZkSyncClient { transaction.chainID = try await chainID() return transaction } + var bridgeAddress = bridgeAddress + if bridgeAddress == nil{ + bridgeAddress = try await bridgeContracts().l2SharedDefaultBridge + } let bridgeAddresses = try await bridgeContracts() - let bridge = web3.contract(Web3Utils.IL2Bridge, at: EthereumAddress(bridgeAddresses.l2Erc20DefaultBridge), transaction: prepared) + let bridge = web3.contract(Web3Utils.IL2Bridge, at: EthereumAddress(bridgeAddress!), transaction: prepared) var transaction = (bridge?.createWriteOperation("withdraw", parameters: [to, token!, amount])!.transaction)! transaction.chainID = try await chainID() transaction.value = BigUInt.zero @@ -318,22 +338,18 @@ public class BaseClient: ZkSyncClient { } public func getTransferTx(_ to: String, amount: BigUInt, from:String, token: String? = nil, options: TransactionOption? = nil, paymasterParams: PaymasterParams? = nil) async -> CodableTransaction { - let isEthChain = try! await isEthBasedChain() var token = token - let isBaseToken = token != nil ? try! await isBaseToken(tokenAddress: token!) : true - - if token != nil && - ZkSyncAddresses.isAddressEq(a: token!, b: ZkSyncAddresses.LEGACY_ETH_ADDRESS) && - !isEthChain { - token = try! await l2TokenAddress(address: token!) - } else if token == nil || (isBaseToken){ + if token == nil { token = ZkSyncAddresses.L2_BASE_TOKEN_ADDRESS + }else if ZkSyncAddresses.isAddressEq(a: token!, b: ZkSyncAddresses.ETH_ADDRESS_IN_CONTRACTS) || + ZkSyncAddresses.isAddressEq(a: token!, b: ZkSyncAddresses.LEGACY_ETH_ADDRESS){ + token = try! await l2TokenAddress(address: ZkSyncAddresses.ETH_ADDRESS_IN_CONTRACTS) } let nonce = try! await web3.eth.getTransactionCount(for: EthereumAddress(from)!) let prepared = CodableTransaction.createEtherTransaction(from: EthereumAddress(from)!, to: EthereumAddress(to)!, value: amount, nonce: nonce, paymasterParams: paymasterParams) - if isBaseToken{ + if ZkSyncAddresses.isAddressEq(a: token!, b: ZkSyncAddresses.L2_BASE_TOKEN_ADDRESS){ return prepared } let tokenContract = web3.contract(Web3Utils.IERC20, at: EthereumAddress(token!)!, transaction: prepared) diff --git a/Sources/ZkSync2/Clients/ZkSyncClient.swift b/Sources/ZkSync2/Clients/ZkSyncClient.swift index f8a7774..4978ea9 100644 --- a/Sources/ZkSync2/Clients/ZkSyncClient.swift +++ b/Sources/ZkSync2/Clients/ZkSyncClient.swift @@ -84,6 +84,8 @@ public protocol ZkSyncClient { func getProof(address: String, keys: [String], l1BatchNumber: BigUInt) async throws -> Proof func getWithdrawTx(_ amount: BigUInt, from: String, to: String?, token: String?, options: TransactionOption?, paymasterParams: PaymasterParams?) async throws -> CodableTransaction + + func getWithdrawTx(_ amount: BigUInt, from: String, to: String?, token: String?, options: TransactionOption?, paymasterParams: PaymasterParams?, bridgeAddress: String?) async throws -> CodableTransaction // EstimateGasWithdraw estimates the amount of gas required for a withdrawal // transaction. func estimateGasWithdraw(_ amount: BigUInt, from: String, to: String?, token: String?, options: TransactionOption?, paymasterParams: PaymasterParams?) async throws -> BigUInt? diff --git a/Tests/ZkSync2Tests/Integration/Account/ZkSyncWalletIntegrationTests.swift b/Tests/ZkSync2Tests/Integration/Account/ZkSyncWalletIntegrationTests.swift index 28e0faa..7646b48 100644 --- a/Tests/ZkSync2Tests/Integration/Account/ZkSyncWalletIntegrationTests.swift +++ b/Tests/ZkSync2Tests/Integration/Account/ZkSyncWalletIntegrationTests.swift @@ -383,9 +383,9 @@ class ZkSyncWalletIntegrationTests: XCTestCase { let result = try! await wallet.walletL2.withdraw(amount, to: nil, token: ZkSyncAddresses.EthAddress) let receipt = await ZkSyncTransactionReceiptProcessor(zkSync: zkSync).waitForTransactionReceipt(hash: result!.hash) XCTAssertNotNil(receipt) - //let isFinalized = await wallet.walletL1.isWithdrawalFinalized(withdrawHash: result!.hash) + let isFinalized = await wallet.walletL1.isWithdrawalFinalized(withdrawHash: result!.hash) sleep(10) - //XCTAssertFalse(isFinalized) + XCTAssertFalse(isFinalized) _ = try! await wallet.walletL1.finalizeWithdrawal(withdrawalHash: result!.hash) let l2BalanceAfter = await wallet.walletL2.balance() @@ -440,8 +440,8 @@ class ZkSyncWalletIntegrationTests: XCTestCase { let receipt = await ZkSyncTransactionReceiptProcessor(zkSync: zkSync).waitForTransactionReceipt(hash: result!.hash) XCTAssertNotNil(receipt) sleep(10) - //let isFinalized = await wallet.walletL1.isWithdrawalFinalized(withdrawHash: result!.hash) - //XCTAssertFalse(isFinalized) + let isFinalized = await wallet.walletL1.isWithdrawalFinalized(withdrawHash: result!.hash) + XCTAssertFalse(isFinalized) _ = try! await wallet.walletL1.finalizeWithdrawal(withdrawalHash: result!.hash) let l2BalanceAfter = await wallet.walletL2.balance(token: l2DAI)