From 9049bf196eec046206159e088b65605885387126 Mon Sep 17 00:00:00 2001 From: petarTxFusion Date: Sun, 18 Feb 2024 21:27:12 +0100 Subject: [PATCH 1/4] feat: paymster withdraw and transfer support --- scripts/setup.py | 120 ++++++++- tests/integration/test_wallet.py | 278 +++++++++++++++++++- zksync2/account/wallet.py | 3 + zksync2/account/wallet_l1.py | 157 +++++++++-- zksync2/account/wallet_l2.py | 142 +++++----- zksync2/core/types.py | 18 ++ zksync2/module/zksync_module.py | 17 +- zksync2/transaction/transaction_builders.py | 108 +++++++- 8 files changed, 720 insertions(+), 123 deletions(-) diff --git a/scripts/setup.py b/scripts/setup.py index 7cb14d3..d759020 100644 --- a/scripts/setup.py +++ b/scripts/setup.py @@ -8,11 +8,19 @@ from eth_account.signers.local import LocalAccount from web3 import Web3 +from zksync2.core.types import EthBlockParams, TransferTransaction +from zksync2.core.utils import to_bytes +from zksync2.manage_contracts.contract_encoder_base import JsonConfiguration, ContractEncoder +from zksync2.manage_contracts.deploy_addresses import ZkSyncAddresses +from zksync2.signer.eth_signer import PrivateKeyEthSigner +from zksync2.transaction.transaction_builders import TxCreate2Contract + def main(): current_directory = os.path.dirname(os.path.abspath(__file__)) parent_directory = os.path.join(current_directory, "..") sys.path.append(parent_directory) + SALT = "0x293328ad84b118194c65a0dc0defdb6483740d3163fd99b260907e15f2e2f642" from zksync2.account.wallet import Wallet from zksync2.manage_contracts.utils import zksync_abi_default @@ -23,6 +31,9 @@ def main(): account: LocalAccount = Account.from_key( "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110" ) + + chain_id = zksync.zksync.chain_id + signer = PrivateKeyEthSigner(account, chain_id) wallet = Wallet(zksync, eth_web3, account) zksync_contract = eth_web3.eth.contract( Web3.to_checksum_address(zksync.zksync.main_contract_address), @@ -30,6 +41,7 @@ def main(): ) deposit_token(wallet, eth_web3, zksync, zksync_contract) + setup_paymaster(eth_web3, zksync, wallet, signer, SALT) def deposit_token(wallet, eth_web3: Web3, zksync: Web3, zksync_contract): @@ -56,6 +68,112 @@ def deposit_token(wallet, eth_web3: Web3, zksync: Web3, zksync_contract): ) +def setup_paymaster(provider_l1, provider_l2, wallet, signer, salt): + directory = Path(__file__).parent.parent + path = directory / "tests/contracts/Token.json" + + token_contract = ContractEncoder.from_json( + provider_l2, path.resolve(), JsonConfiguration.STANDARD + ) + abi = token_contract.abi + + token_address = deploy_crown_token(provider_l2, wallet, signer, salt, token_contract) + token_contract = provider_l2.zksync.contract(token_address, abi=abi) + + mint_tx = token_contract.functions.mint( + wallet.address, 15 + ).build_transaction( + { + "nonce": provider_l2.zksync.get_transaction_count( + wallet.address, EthBlockParams.LATEST.value + ), + "from": wallet.address, + "maxPriorityFeePerGas": 1_000_000, + "maxFeePerGas": provider_l2.zksync.gas_price, + } + ) + + signed = wallet.sign_transaction(mint_tx) + tx_hash = provider_l2.eth.send_raw_transaction(signed.rawTransaction) + provider_l2.zksync.wait_for_transaction_receipt( + tx_hash, timeout=240, poll_latency=0.5 + ) + + paymaster_address = deploy_paymaster(provider_l2, wallet, token_address, signer, salt) + faucet_hash = wallet.transfer(TransferTransaction(to=paymaster_address, amount=provider_l2.to_wei(1, "ether"), token_address=ZkSyncAddresses.ETH_ADDRESS.value)) + + provider_l2.zksync.wait_for_transaction_receipt( + faucet_hash, timeout=240, poll_latency=0.5 + ) + +def deploy_crown_token(provider_l2, wallet, signer, salt, token_contract): + constructor_arguments = {"name_": "Ducat", "symbol_": "Ducat", "decimals_": 18} + chain_id = provider_l2.zksync.chain_id + nonce = provider_l2.zksync.get_transaction_count( + wallet.address, EthBlockParams.PENDING.value + ) + encoded_constructor = token_contract.encode_constructor(**constructor_arguments) + + gas_price = provider_l2.zksync.gas_price + create2_contract = TxCreate2Contract( + web3=provider_l2, + chain_id=chain_id, + nonce=nonce, + from_=wallet.address, + gas_limit=0, + gas_price=gas_price, + bytecode=token_contract.bytecode, + salt=to_bytes(salt), + call_data=encoded_constructor, + ) + estimate_gas = provider_l2.zksync.eth_estimate_gas(create2_contract.tx) + tx_712 = create2_contract.tx712(estimate_gas) + signed_message = signer.sign_typed_data(tx_712.to_eip712_struct()) + msg = tx_712.encode(signed_message) + tx_hash = provider_l2.zksync.send_raw_transaction(msg) + tx_receipt = provider_l2.zksync.wait_for_transaction_receipt( + tx_hash, timeout=240, poll_latency=0.5 + ) + + return tx_receipt["contractAddress"] + + +def deploy_paymaster(provider_l2: Web3, wallet, token_address, signer, salt): + directory = Path(__file__).parent.parent + path = directory / "tests/contracts/Paymaster.json" + token_address = provider_l2.to_checksum_address(token_address) + constructor_arguments = {"_erc20": token_address} + + chain_id = provider_l2.zksync.chain_id + nonce = provider_l2.zksync.get_transaction_count( + wallet.address, EthBlockParams.PENDING.value + ) + token_contract = ContractEncoder.from_json( + provider_l2, path.resolve(), JsonConfiguration.STANDARD + ) + encoded_constructor = token_contract.encode_constructor(**constructor_arguments) + gas_price = provider_l2.zksync.gas_price + create_account = TxCreate2Contract( + web3=provider_l2, + chain_id=chain_id, + gas_limit=0, + nonce=nonce, + from_=wallet.address, + gas_price=gas_price, + bytecode=token_contract.bytecode, + call_data=encoded_constructor, + salt=to_bytes(salt) + ) + estimate_gas = provider_l2.zksync.eth_estimate_gas(create_account.tx) + tx_712 = create_account.tx712(estimate_gas) + signed_message = signer.sign_typed_data(tx_712.to_eip712_struct()) + msg = tx_712.encode(signed_message) + tx_hash = provider_l2.zksync.send_raw_transaction(msg) + tx_receipt = provider_l2.zksync.wait_for_transaction_receipt( + tx_hash, timeout=240, poll_latency=0.5 + ) + return tx_receipt["contractAddress"] + def load_token(): directory = Path(__file__).parent.parent path = directory / "tests/integration/token.json" @@ -66,4 +184,4 @@ def load_token(): if __name__ == "__main__": - main() + main() \ No newline at end of file diff --git a/tests/integration/test_wallet.py b/tests/integration/test_wallet.py index 435b2e6..222015d 100644 --- a/tests/integration/test_wallet.py +++ b/tests/integration/test_wallet.py @@ -1,7 +1,8 @@ import json import os from pathlib import Path -from unittest import TestCase +from time import sleep +from unittest import TestCase, skip from eth_account import Account from eth_account.signers.local import LocalAccount @@ -10,7 +11,6 @@ from web3 import Web3 from tests.integration.test_config import LOCAL_ENV, EnvPrivateKey -from tests.integration.test_zksync_contract import generate_random_salt from zksync2.account.wallet import Wallet from zksync2.core.types import ( Token, @@ -21,23 +21,27 @@ TransactionOptions, TransferTransaction, WithdrawTransaction, - EthBlockParams, + EthBlockParams, PaymasterParams, ZkBlockParams, ) from zksync2.manage_contracts.contract_encoder_base import ( ContractEncoder, JsonConfiguration, ) +from zksync2.manage_contracts.deploy_addresses import ZkSyncAddresses +from zksync2.manage_contracts.paymaster_utils import PaymasterFlowEncoder from zksync2.manage_contracts.precompute_contract_deployer import ( PrecomputeContractDeployer, ) from zksync2.manage_contracts.utils import zksync_abi_default, get_erc20_abi from zksync2.module.module_builder import ZkSyncBuilder from zksync2.signer.eth_signer import PrivateKeyEthSigner -from zksync2.transaction.transaction_builders import TxCreate2Contract, TxCreateContract +from zksync2.transaction.transaction_builders import TxCreate2Contract, TxCreateContract, TxFunctionCall class TestWallet(TestCase): def setUp(self) -> None: + self.token_address = "0x0183Fe07a98bc036d6eb23C3943d823bcD66a90F" + self.paymaster_address = "0x594E77D36eB367b3AbAb98775c99eB383079F966" self.address2 = "0xa61464658AfeAf65CccaaFD3a512b69A83B77618" self.env = LOCAL_ENV env_key = EnvPrivateKey("ZKSYNC_KEY1") @@ -130,7 +134,7 @@ def test_prepare_deposit_transaction(self): ) tx = DepositTransaction( token=ADDRESS_DEFAULT, - amount=7_000_000, + amount=0.000000007, to=self.wallet.address, operator_tip=0, l2_gas_limit=int("0x8d1c0", 16), @@ -194,7 +198,7 @@ def test_deposit_eth(self): # @skip("Integration test, used for develop purposes only") def test_deposit_token(self): - amount = 5 + amount = 100 l1_address, l2_address = self.load_token() is_approved = self.wallet.approve_erc20( Web3.to_checksum_address(l1_address), amount @@ -251,7 +255,7 @@ def test_transfer_eth(self): TransferTransaction( to=Web3.to_checksum_address(self.address2), token_address=ADDRESS_DEFAULT, - amount=amount, + amount=amount ) ) @@ -264,12 +268,96 @@ def test_transfer_eth(self): self.assertEqual(balance_after_transfer - balance_before_transfer, amount) + def test_transfer_eth_paymaster(self): + amount = 1 + paymaster_address = self.zksync.to_checksum_address(self.paymaster_address) + token_address = self.zksync.to_checksum_address(self.token_address) + + paymaster_balance_before = self.zksync.zksync.zks_get_balance(paymaster_address) + paymaster_token_balance_before = self.zksync.zksync.zks_get_balance(paymaster_address, token_address=token_address) + + sender_balance_before = self.wallet.get_balance() + sender_approval_token_balance_before = self.wallet.get_balance(token_address=token_address) + reciever_balance_before = self.zksync.zksync.zks_get_balance(self.address2) + + paymaster_params = PaymasterParams( + **{ + "paymaster": paymaster_address, + "paymaster_input": self.eth_web3.to_bytes( + hexstr=PaymasterFlowEncoder(self.eth_web3).encode_approval_based( + token_address, 1, b"" + ) + ), + } + ) + + tx_hash = self.wallet.transfer( + TransferTransaction( + to=Web3.to_checksum_address(self.address2), + token_address=ADDRESS_DEFAULT, + amount=amount, + paymaster_params=paymaster_params + ) + ) + + self.zksync.zksync.wait_for_transaction_receipt( + tx_hash, timeout=240, poll_latency=0.5 + ) + + paymaster_balance_after = self.zksync.zksync.zks_get_balance(paymaster_address) + paymaster_token_balance_after = self.zksync.zksync.zks_get_balance(paymaster_address, token_address=token_address) + sender_balance_after = self.wallet.get_balance() + sender_approval_token_balance_after = self.wallet.get_balance(token_address=token_address) + reciever_balance_after = self.zksync.zksync.zks_get_balance(self.address2) + + self.assertGreaterEqual(paymaster_balance_before - paymaster_balance_after, 0) + self.assertGreaterEqual(paymaster_token_balance_after - paymaster_token_balance_before, 0) + self.assertGreaterEqual(sender_balance_before - sender_balance_after, 0) + self.assertGreater(sender_approval_token_balance_before - sender_approval_token_balance_after, 0) + self.assertGreaterEqual(reciever_balance_after - reciever_balance_before, 0) + + @skip("Used only for development purpose to refill paymaster") + def test_mint_paymaster(self): + directory = Path(__file__).parent + path = directory / Path("../contracts/Token.json") + + token_contract = ContractEncoder.from_json( + self.zksync, path.resolve(), JsonConfiguration.STANDARD + ) + abi = token_contract.abi + token_contract = self.zksync.zksync.contract(Web3.to_checksum_address(self.token_address), abi=abi) + + balance_before = self.wallet.get_balance(Web3.to_checksum_address(self.token_address)) + mint_tx = token_contract.functions.mint( + self.wallet.address, 15 + ).build_transaction( + { + "nonce": self.zksync.zksync.get_transaction_count( + self.wallet.address, EthBlockParams.LATEST.value + ), + "from": self.wallet.address, + "maxPriorityFeePerGas": 1_000_000, + "maxFeePerGas": self.zksync.zksync.gas_price, + } + ) + + signed = self.wallet.sign_transaction(mint_tx) + tx_hash = self.zksync.eth.send_raw_transaction(signed.rawTransaction) + self.zksync.zksync.wait_for_transaction_receipt( + tx_hash, timeout=240, poll_latency=0.5 + ) + balance_after = self.wallet.get_balance(Web3.to_checksum_address(self.token_address)) + + self.assertEqual(15, balance_after - balance_before) + + def test_transfer_token(self): amount = 5 l1_address, l2_address = self.load_token() + sender_before = self.wallet.get_balance(token_address=l2_address) balance_before = self.zksync.zksync.zks_get_balance( - self.address2, token_address=l2_address + self.address2, token_address=l2_address, block_tag=ZkBlockParams.LATEST.value ) tx_hash = self.wallet.transfer( TransferTransaction( @@ -279,18 +367,80 @@ def test_transfer_token(self): ) ) - self.zksync.zksync.wait_for_transaction_receipt( + result = self.zksync.zksync.wait_for_transaction_receipt( tx_hash, timeout=240, poll_latency=0.5 ) + self.assertIsNotNone(result) + sender_after = self.wallet.get_balance(token_address=l2_address) + balance_after = self.zksync.zksync.zks_get_balance( - self.address2, token_address=l2_address + self.address2, token_address=l2_address, block_tag=ZkBlockParams.LATEST.value + ) + + self.assertEqual(amount, sender_before - sender_after) + self.assertEqual(amount ,balance_after - balance_before) + + def test_transfer_token_paymaster(self): + amount = 5 + l1_address, l2_address = self.load_token() + + paymaster_address = self.zksync.to_checksum_address(self.paymaster_address) + token_address = self.zksync.to_checksum_address(self.token_address) + + paymaster_balance_before = self.zksync.zksync.zks_get_balance(paymaster_address) + paymaster_token_balance_before = self.zksync.zksync.zks_get_balance(paymaster_address, + token_address=token_address, + block_tag=ZkBlockParams.LATEST.value) + + sender_balance_before = self.wallet.get_balance(token_address=Web3.to_checksum_address(l2_address)) + sender_approval_token_balance_before = self.wallet.get_balance(token_address=token_address) + reciever_balance_before = self.zksync.zksync.zks_get_balance(self.address2, + token_address=Web3.to_checksum_address(l2_address), + block_tag=ZkBlockParams.LATEST.value) + + paymaster_params = PaymasterParams( + **{ + "paymaster": paymaster_address, + "paymaster_input": self.eth_web3.to_bytes( + hexstr=PaymasterFlowEncoder(self.eth_web3).encode_approval_based( + token_address, 1, b"" + ) + ), + } + ) + + tx_hash = self.wallet.transfer( + TransferTransaction( + to=Web3.to_checksum_address(self.address2), + token_address=Web3.to_checksum_address(l2_address), + amount=amount, + paymaster_params=paymaster_params + ) ) - self.assertEqual(balance_after - balance_before, amount) + self.zksync.zksync.wait_finalized( + tx_hash, timeout=240, poll_latency=0.5 + ) + paymaster_balance_after = self.zksync.zksync.zks_get_balance(paymaster_address) + paymaster_token_balance_after = self.zksync.zksync.zks_get_balance(paymaster_address, + token_address=token_address, + block_tag=ZkBlockParams.LATEST.value) + + sender_balance_after = self.wallet.get_balance(token_address=Web3.to_checksum_address(l2_address)) + sender_approval_token_balance_after = self.wallet.get_balance(token_address=token_address) + reciever_balance_after = self.zksync.zksync.zks_get_balance(self.address2, + token_address=Web3.to_checksum_address(l2_address), + block_tag=ZkBlockParams.LATEST.value) + + self.assertGreaterEqual(paymaster_balance_before - paymaster_balance_after, 0) + self.assertEqual(paymaster_token_balance_after - paymaster_token_balance_before, 1) + self.assertEqual(sender_balance_before - sender_balance_after, 5) + self.assertEqual(sender_approval_token_balance_before - sender_approval_token_balance_after, 1) + self.assertEqual(reciever_balance_after - reciever_balance_before, 5) def test_withdraw_eth(self): l2_balance_before = self.wallet.get_balance() - amount = 0.005 + amount = 1 withdraw_tx_hash = self.wallet.withdraw( WithdrawTransaction( @@ -310,6 +460,106 @@ def test_withdraw_eth(self): "L2 balance should be lower after withdrawal", ) + def test_withdraw_eth_paymaster(self): + amount = 1 + + paymaster_address = self.zksync.to_checksum_address(self.paymaster_address) + token_address = self.zksync.to_checksum_address(self.token_address) + + paymaster_balance_before = self.zksync.zksync.zks_get_balance(paymaster_address) + paymaster_token_balance_before = self.zksync.zksync.zks_get_balance(paymaster_address, + token_address=token_address) + + sender_balance_before = self.wallet.get_balance() + sender_approval_token_balance_before = self.wallet.get_balance(token_address=token_address) + + paymaster_params = PaymasterParams( + **{ + "paymaster": paymaster_address, + "paymaster_input": self.eth_web3.to_bytes( + hexstr=PaymasterFlowEncoder(self.eth_web3).encode_approval_based( + token_address, 1, b"" + ) + ), + } + ) + + withdraw_tx_hash = self.wallet.withdraw( + WithdrawTransaction( + token=Token.create_eth().l1_address, + amount=Web3.to_wei(amount, "ether"), + paymaster_params=paymaster_params + ) + ) + + withdraw_receipt = self.zksync.zksync.wait_finalized( + withdraw_tx_hash, timeout=240, poll_latency=0.5 + ) + self.assertFalse(self.wallet.is_withdrawal_finalized(withdraw_receipt["transactionHash"])) + + finalized_hash = self.wallet.finalize_withdrawal(withdraw_receipt["transactionHash"]) + self.eth_web3.eth.wait_for_transaction_receipt( + finalized_hash, timeout=240, poll_latency=0.5 + ) + paymaster_balance_after = self.zksync.zksync.zks_get_balance(paymaster_address) + paymaster_token_balance_after = self.zksync.zksync.zks_get_balance(paymaster_address, + token_address=token_address) + sender_balance_after = self.wallet.get_balance() + sender_approval_token_balance_after = self.wallet.get_balance(token_address=token_address) + + self.assertGreater(paymaster_balance_before - paymaster_balance_after, 0) + self.assertEqual(paymaster_token_balance_after - paymaster_token_balance_before, 1) + self.assertEqual(sender_balance_before - sender_balance_after, Web3.to_wei(amount, "ether")) + self.assertEqual(sender_approval_token_balance_after, sender_approval_token_balance_before - 1) + + def test_withdraw_token_paymaster(self): + l1_address, l2_address = self.load_token() + paymaster_address = self.zksync.to_checksum_address(self.paymaster_address) + token_address = self.zksync.to_checksum_address(self.token_address) + + paymaster_balance_before = self.zksync.zksync.zks_get_balance(paymaster_address) + paymaster_token_balance_before = self.zksync.zksync.zks_get_balance(paymaster_address, + token_address=token_address, + block_tag=ZkBlockParams.LATEST.value) + l2_balance_before = self.wallet.get_balance(token_address=Web3.to_checksum_address(l2_address)) + l2_approval_token_balance_before = self.wallet.get_balance(token_address=token_address) + + paymaster_params = PaymasterParams( + **{ + "paymaster": paymaster_address, + "paymaster_input": self.eth_web3.to_bytes( + hexstr=PaymasterFlowEncoder(self.eth_web3).encode_approval_based( + token_address, 1, b"" + ) + ), + } + ) + + withdraw_tx_hash = self.wallet.withdraw( + WithdrawTransaction(Web3.to_checksum_address(l2_address), 5, paymaster_params=paymaster_params) + ) + + receipt = self.zksync.zksync.wait_finalized( + withdraw_tx_hash, timeout=240, poll_latency=0.5 + ) + self.assertFalse(self.wallet.is_withdrawal_finalized(withdraw_tx_hash)) + finalized_hash = self.wallet.finalize_withdrawal(withdraw_tx_hash) + self.eth_web3.eth.wait_for_transaction_receipt(finalized_hash) + paymaster_balance_after = self.zksync.zksync.zks_get_balance(paymaster_address) + paymaster_token_balance_after = self.zksync.zksync.zks_get_balance(paymaster_address, + token_address=token_address, + block_tag=ZkBlockParams.LATEST.value) + l2_balance_after = self.wallet.get_balance( + token_address=Web3.to_checksum_address(l2_address) + ) + l2_approval_token_balance_after = self.wallet.get_balance(token_address=token_address) + + self.assertGreaterEqual(paymaster_balance_before - paymaster_balance_after, 0) + self.assertEqual(paymaster_token_balance_after - paymaster_token_balance_before, 1) + self.assertIsNotNone(receipt) + self.assertEqual(l2_approval_token_balance_before - l2_approval_token_balance_after, 1) + self.assertEqual(l2_balance_before - l2_balance_after, 5) + def test_withdraw_token(self): l1_address, l2_address = self.load_token() l2_balance_before = self.wallet.get_balance( @@ -357,7 +607,7 @@ def test_estimate_request_execute(self): self.assertGreater(result, 0) def test_request_execute(self): - amount = 7_000_000_000 + amount = 1 l2_balance_before = self.wallet.get_balance() tx_hash = self.wallet.request_execute( @@ -383,4 +633,4 @@ def test_request_execute(self): l2_balance_after - l2_balance_before, amount, "Balance on L2 should be increased", - ) + ) \ No newline at end of file diff --git a/zksync2/account/wallet.py b/zksync2/account/wallet.py index 8262b86..d31d9fe 100644 --- a/zksync2/account/wallet.py +++ b/zksync2/account/wallet.py @@ -13,3 +13,6 @@ def __init__(self, zksync_web3: Web3, eth_web3: Web3, l1_account: BaseAccount): self._l1_account = l1_account WalletL1.__init__(self, zksync_web3, eth_web3, l1_account) WalletL2.__init__(self, zksync_web3, eth_web3, l1_account) + + def sign_transaction(self, tx): + return self._l1_account.sign_transaction(tx) \ No newline at end of file diff --git a/zksync2/account/wallet_l1.py b/zksync2/account/wallet_l1.py index e3e681a..4cd42e3 100644 --- a/zksync2/account/wallet_l1.py +++ b/zksync2/account/wallet_l1.py @@ -1,17 +1,12 @@ -from pathlib import Path, PosixPath -from typing import Union, List, Type +from typing import Union, Type +from eth_account.signers.base import BaseAccount +from eth_typing import HexStr, Address +from eth_utils import event_signature_to_log_topic, add_0x_prefix from web3 import Web3 from web3.contract import Contract -from web3.types import TxReceipt, BlockIdentifier, LatestBlockParam -from web3._utils.contracts import encode_abi from web3.middleware import geth_poa_middleware - -from eth_typing import HexStr, Address -from eth_utils import event_signature_to_log_topic, add_0x_prefix, remove_0x_prefix -from eth_account import Account -from eth_account.signers.base import BaseAccount -from eth_abi import abi +from web3.types import TxReceipt from zksync2.account.utils import ( deposit_to_request_execute, @@ -19,7 +14,6 @@ ) from zksync2.core.types import ( BridgeAddresses, - Token, ZksMessageProof, EthBlockParams, DepositTransaction, @@ -40,10 +34,6 @@ undo_l1_to_l2_alias, DEPOSIT_GAS_PER_PUBDATA_LIMIT, ) -from zksync2.manage_contracts.contract_encoder_base import ( - ContractEncoder, - JsonConfiguration, -) from zksync2.manage_contracts.deploy_addresses import ZkSyncAddresses from zksync2.manage_contracts.utils import ( zksync_abi_default, @@ -52,7 +42,6 @@ l2_bridge_abi_default, ) from zksync2.module.request_types import EIP712Meta -from zksync2.transaction.transaction712 import Transaction712 from zksync2.transaction.transaction_builders import TxFunctionCall @@ -88,10 +77,12 @@ def __init__(self, zksync_web3: Web3, eth_web3: Web3, l1_account: BaseAccount): @property def main_contract(self) -> Union[Type[Contract], Contract]: + """Returns Contract wrapper of the zkSync smart contract.""" return self.contract @property def address(self): + """Returns the wallet address.""" return self._l1_account.address def _get_withdraw_log(self, tx_receipt: TxReceipt, index: int = 0): @@ -136,6 +127,7 @@ def _finalize_withdrawal_params(self, withdraw_hash, index: int) -> dict: } def get_l1_bridge_contracts(self) -> L1BridgeContracts: + """Returns L1 bridge contract wrappers.""" return L1BridgeContracts( erc20=self._eth_web3.eth.contract( address=Web3.to_checksum_address( @@ -154,6 +146,11 @@ def get_l1_balance( token: HexStr = ADDRESS_DEFAULT, block: EthBlockParams = EthBlockParams.LATEST, ) -> int: + """ + Returns the amount of the token the Wallet has on Ethereum. + :param token: Token address. ETH by default. + :param block: The block the balance should be checked on. committed, i.e. the latest processed one is the default option. + """ if is_eth(token): return self._eth_web3.eth.get_balance(self.address, block.value) else: @@ -165,6 +162,12 @@ def get_l1_balance( ) def get_allowance_l1(self, token: HexStr, bridge_address: Address = None): + """ + Returns the amount of approved tokens for a specific L1 bridge. + + :param token: The address of the token on L1. + :param bridge_address: The address of the bridge contract to be used. Defaults to the default zkSync bridge (either L1EthBridge or L1Erc20Bridge). + """ token_contract = self._eth_web3.eth.contract( address=Web3.to_checksum_address(token), abi=get_erc20_abi() ) @@ -190,6 +193,11 @@ def get_allowance_l1(self, token: HexStr, bridge_address: Address = None): ) def l2_token_address(self, address: HexStr) -> HexStr: + """ + Returns the L2 token address equivalent for a L1 token address as they are not equal. ETH's address is set to zero address. + + :param address: The address of the token on L1. + """ if is_eth(address): return ADDRESS_DEFAULT @@ -209,6 +217,14 @@ def approve_erc20( bridge_address: HexStr = None, gas_limit: int = None, ) -> TxReceipt: + """ + Bridging ERC20 tokens from Ethereum requires approving the tokens to the zkSync Ethereum smart contract. + + :param token: The Ethereum address of the token. + :param amount: The amount of the token to be approved. + :param bridge_address: The address of the bridge contract to be used. Defaults to the default zkSync bridge (either L1EthBridge or L1Erc20Bridge). + :param gas_limit: + """ if is_eth(token): raise RuntimeError( "ETH token can't be approved. The address of the token does not exist on L1" @@ -256,6 +272,13 @@ def get_base_cost( gas_per_pubdata_byte: int = DEPOSIT_GAS_PER_PUBDATA_LIMIT, gas_price: int = None, ): + """ + Returns base cost for L2 transaction. + + :param l2_gas_limit: The gasLimit for the L2 contract call. + :param gas_per_pubdata_byte: The L2 gas price for each published L1 calldata byte (optional). + :param gas_price: The L1 gas price of the L1 transaction that will send the request for an execute call (optional). + """ if gas_price is None: gas_price = self._eth_web3.eth.gas_price options = TransactionOptions( @@ -267,6 +290,11 @@ def get_base_cost( ).call(prepare_transaction_options(options, self.address)) def prepare_deposit_tx(self, transaction: DepositTransaction) -> DepositTransaction: + """ + Returns populated deposit transaction. + + :param transaction: DepositTransaction class. Not optional arguments are token(L1 token address) and amount. + """ if transaction.options is None: transaction.options = TransactionOptions() if transaction.to is None: @@ -357,7 +385,11 @@ def prepare_deposit_tx(self, transaction: DepositTransaction) -> DepositTransact def get_full_required_deposit_fee( self, transaction: DepositTransaction ) -> FullDepositFee: - # It is assumed that the L2 fee for the transaction does not depend on its value. + """ + Retrieves the full needed ETH fee for the deposit. Returns the L1 fee and the L2 fee FullDepositFee(core/types.py). + + :param transaction: DepositTransaction: DepositTransaction class. Not optional argument is amount. + """ dummy_amount = 1 if transaction.options is None: @@ -486,6 +518,16 @@ def get_full_required_deposit_fee( return full_cost def deposit(self, transaction: DepositTransaction): + """ + Transfers the specified token from the associated account on the L1 network to the target account on the L2 network. + The token can be either ETH or any ERC20 token. For ERC20 tokens, + enough approved tokens must be associated with the specified L1 bridge (default one or the one defined in transaction.bridgeAddress). + In this case, transaction.approveERC20 can be enabled to perform token approval. + If there are already enough approved tokens for the L1 bridge, token approval will be skipped. + To check the amount of approved tokens for a specific bridge, use the allowanceL1 method. + + :param transaction: DepositTransaction class. Not optional arguments are token(L1 token address) and amount. + """ transaction = self.prepare_deposit_tx(transaction) if is_eth(transaction.token): @@ -549,6 +591,12 @@ def deposit(self, transaction: DepositTransaction): return txn_hash def estimate_gas_deposit(self, transaction: DepositTransaction): + """ + Estimates the amount of gas required for a deposit transaction on L1 network. + Gas of approving ERC20 token is not included in estimation. + + :param transaction: DepositTransaction class. Not optional arguments are token(L1 token address) and amount. + """ transaction = self.prepare_deposit_tx(transaction) if is_eth(transaction.token): tx = self.contract.functions.requestL2Transaction( @@ -587,6 +635,14 @@ def estimate_gas_deposit(self, transaction: DepositTransaction): return self._eth_web3.eth.estimate_gas(tx) def claim_failed_deposit(self, deposit_hash: HexStr): + """ + The claimFailedDeposit method withdraws funds from the initiated deposit, which failed when finalizing on L2. + If the deposit L2 transaction has failed, + it sends an L1 transaction calling claimFailedDeposit method of the L1 bridge, + which results in returning L1 tokens back to the depositor, otherwise throws the error. + + :param deposit_hash: The L2 transaction hash of the failed deposit. + """ receipt = self._zksync_web3.zksync.eth_get_transaction_receipt(deposit_hash) success_log: L1ToL2Log success_log_index: int @@ -719,6 +775,12 @@ def get_erc_20_call_data( ) def finalize_withdrawal(self, withdraw_hash, index: int = 0): + """ + Proves the inclusion of the L2 -> L1 withdrawal message. + + :param withdraw_hash: Hash of the L2 transaction where the withdrawal was initiated. + :param index:nIn case there were multiple withdrawals in one transaction, you may pass an index of the withdrawal you want to finalize (defaults to 0). + """ params = self._finalize_withdrawal_params(withdraw_hash, index) merkle_proof = [] for proof in params["proof"]: @@ -758,25 +820,41 @@ def finalize_withdrawal(self, withdraw_hash, index: int = 0): return tx_hash else: l2_bridge = self._zksync_web3.zksync.contract( - address=params["sender"], abi=l2_bridge_abi_default() + address= Web3.to_checksum_address(params["sender"]), abi=l2_bridge_abi_default() ) l1_bridge = self._eth_web3.eth.contract( address=Web3.to_checksum_address(l2_bridge.functions.l1Bridge().call()), abi=l1_bridge_abi_default(), ) - return l1_bridge.functions.finalizeWithdrawal( + l1_batch_number = params["l1_batch_number"] + l2_message_index = params["l2_message_index"] + l2_tx_number_in_block = params["l2_tx_number_in_block"] + message = params["message"] + + tx = l1_bridge.functions.finalizeWithdrawal( params["l1_batch_number"], params["l2_message_index"], + params["l2_tx_number_in_block"], params["message"], merkle_proof, ).build_transaction(prepare_transaction_options(options, self.address)) + signed = self._l1_account.sign_transaction(tx) + tx_hash = self._eth_web3.eth.send_raw_transaction(signed.rawTransaction) + return tx_hash + def is_withdrawal_finalized(self, withdraw_hash, index: int = 0): + """ + Checks if withdraw is finalized from L2 -> L1 + + :param withdraw_hash: Hash of the L2 transaction where the withdrawal was initiated. + :param index:nIn case there were multiple withdrawals in one transaction, you may pass an index of the withdrawal you want to finalize (defaults to 0). + """ tx_receipt = self._zksync_web3.zksync.get_transaction_receipt(withdraw_hash) log, _ = self._get_withdraw_log(tx_receipt, index) - l2_to_l1_log_index = self._get_withdraw_l2_to_l1_log(tx_receipt, index) - sender = add_0x_prefix(HexStr(log.topics[1][12:].hex())) - hex_hash = withdraw_hash.hex() + l2_to_l1_log_index, _ = self._get_withdraw_l2_to_l1_log(tx_receipt, index) + sender = add_0x_prefix(HexStr(log["topics"][1][12:].hex())) + hex_hash = withdraw_hash proof: ZksMessageProof = self._zksync_web3.zksync.zks_get_log_proof( hex_hash, l2_to_l1_log_index ) @@ -788,10 +866,9 @@ def is_withdrawal_finalized(self, withdraw_hash, index: int = 0): ) if is_eth(sender): return self.contract.functions.isEthWithdrawalFinalized( - l2_block_number, proof.id + int(l2_block_number, 16), proof.id ).call(prepare_transaction_options(options, self.address)) else: - # TODO: check should it be different account for L1/L2 l1_bridge = self._eth_web3.eth.contract( address=Web3.to_checksum_address( self.bridge_addresses.erc20_l1_default_bridge @@ -799,10 +876,24 @@ def is_withdrawal_finalized(self, withdraw_hash, index: int = 0): abi=l1_bridge_abi_default(), ) return l1_bridge.functions.isWithdrawalFinalized( - l2_block_number, proof.id + int(l2_block_number, 16), proof.id ).call() def request_execute(self, transaction: RequestExecuteCallMsg): + """ + Request execution of L2 transaction from L1. + + :param transaction: RequestExecuteCallMsg class, required parameters are: + contract_address(L2 contract to be called) and call_data (the input of the L2 transaction). + Example: RequestExecuteCallMsg( + contract_address=Web3.to_checksum_address( + zksync.zksync.main_contract_address + ), + call_data=HexStr("0x"), + l2_value=amount, + l2_gas_limit=900_000, + ) + """ transaction = self.get_request_execute_transaction(transaction) tx = self.contract.functions.requestL2Transaction( transaction.contract_address, @@ -829,6 +920,12 @@ def check_if_l1_chain_is_london_ready(self): def get_request_execute_transaction( self, transaction: RequestExecuteCallMsg ) -> RequestExecuteCallMsg: + """ + Returns populated deposit transaction. + + :param transaction: RequestExecuteCallMsg class, required parameters are: + contract_address(L2 contract to be called) and call_data (the input of the L2 transaction). + """ if transaction.options is None: transaction.options = TransactionOptions() if transaction.factory_deps is None: @@ -863,7 +960,7 @@ def get_request_execute_transaction( if isReady: if transaction.options.max_priority_fee_per_gas is None: transaction.options.max_priority_fee_per_gas = ( - self._zksync_web3.zksync.max_priority_fee + self._eth_web3.eth.max_priority_fee ) transaction.options.max_fee_per_gas = int( ((head["baseFeePerGas"] * 3) / 2) @@ -894,6 +991,12 @@ def get_request_execute_transaction( return transaction def estimate_gas_request_execute(self, transaction: RequestExecuteCallMsg) -> int: + """ + Estimates the amount of gas required for a request execute transaction. + + :param transaction: RequestExecuteCallMsg class, required parameters are: + contract_address(L2 contract to be called) and call_data (the input of the L2 transaction). + """ transaction = self.get_request_execute_transaction(transaction) tx = self.contract.functions.requestL2Transaction( Web3.to_checksum_address(transaction.contract_address), @@ -907,4 +1010,4 @@ def estimate_gas_request_execute(self, transaction: RequestExecuteCallMsg) -> in prepare_transaction_options(transaction.options, self.address) ) - return self._eth_web3.eth.estimate_gas(tx) + return self._eth_web3.eth.estimate_gas(tx) \ No newline at end of file diff --git a/zksync2/account/wallet_l2.py b/zksync2/account/wallet_l2.py index 5c380d1..ef1d59d 100644 --- a/zksync2/account/wallet_l2.py +++ b/zksync2/account/wallet_l2.py @@ -21,8 +21,10 @@ l2_bridge_abi_default, get_erc20_abi, ) +from zksync2.module.request_types import EIP712Meta from zksync2.module.response_types import ZksAccountBalances from zksync2.signer.eth_signer import PrivateKeyEthSigner +from zksync2.transaction.transaction712 import Transaction712 from zksync2.transaction.transaction_builders import TxFunctionCall, TxWithdraw @@ -40,16 +42,28 @@ def __init__(self, zksync_web3: Web3, eth_web3: Web3, l1_account: BaseAccount): def get_balance( self, block_tag=ZkBlockParams.COMMITTED.value, token_address: HexStr = None ) -> int: + """ + Returns the balance of the account. + + :param block_tag: The block tag to get the balance at. Defaults to 'committed'. + :param token_address: The token address to query balance for. Defaults to the native token. + """ return self._zksync_web3.zksync.zks_get_balance( self._l1_account.address, block_tag, token_address ) def get_all_balances(self) -> ZksAccountBalances: + """ + Returns the balance of the account. + """ return self._zksync_web3.zksync.zks_get_all_account_balances( self._l1_account.address ) def get_deployment_nonce(self) -> int: + """ + Returns all token balances of the account. + """ nonce_holder = self._zksync_web3.zksync.contract( address=ZkSyncAddresses.NONCE_HOLDER_ADDRESS.value, abi=nonce_holder_abi_default(), @@ -60,6 +74,9 @@ def get_deployment_nonce(self) -> int: return deployment_nonce def get_l2_bridge_contracts(self) -> L2BridgeContracts: + """ + Returns L2 bridge contracts. + """ addresses = self._zksync_web3.zksync.zks_get_bridge_contracts() return L2BridgeContracts( erc20=self._zksync_web3.eth.contract( @@ -73,6 +90,14 @@ def get_l2_bridge_contracts(self) -> L2BridgeContracts: ) def transfer(self, tx: TransferTransaction) -> HexStr: + """ + Transfer ETH or any ERC20 token within the same interface. + + :param tx: TransferTransaction class. Required parameters are to and amount. + + Returns: + - Transaction hash. + """ tx_fun_call = self._zksync_web3.zksync.get_transfer_transaction( tx, self._l1_account.address ) @@ -80,34 +105,24 @@ def transfer(self, tx: TransferTransaction) -> HexStr: tx_712 = tx_fun_call.tx712( self._zksync_web3.zksync.zks_estimate_gas_transfer(tx_fun_call.tx) ) + signer = PrivateKeyEthSigner(self._l1_account, tx.options.chain_id) + signed_message = signer.sign_typed_data(tx_712.to_eip712_struct()) - if tx.token_address is None or is_eth(tx.token_address): - signer = PrivateKeyEthSigner(self._l1_account, tx.options.chain_id) - signed_message = signer.sign_typed_data(tx_712.to_eip712_struct()) + msg = tx_712.encode(signed_message) + tx_hash = self._zksync_web3.zksync.send_raw_transaction(msg) - msg = tx_712.encode(signed_message) - tx_hash = self._zksync_web3.zksync.send_raw_transaction(msg) + return tx_hash - return tx_hash - else: - token_contract = self._zksync_web3.zksync.contract( - tx.token_address, abi=get_erc20_abi() - ) - options = options_from_712(tx_712) - transaction = token_contract.functions.transfer( - tx.to, tx.amount - ).build_transaction( - prepare_transaction_options(options, self._l1_account.address) - ) - - signed = self._l1_account.sign_transaction(transaction) - tx_hash = self._zksync_web3.zksync.send_raw_transaction( - signed.rawTransaction - ) + def withdraw(self, tx: WithdrawTransaction): + """ + Initiates the withdrawal process which withdraws ETH or any ERC20 token + from the associated account on L2 network to the target account on L1 network. - return tx_hash + :param tx: WithdrawTransaction class. Required parameters are token(HexStr) and amount(int). - def withdraw(self, tx: WithdrawTransaction): + Returns: + - Withdrawal hash. + """ if tx.options is None: tx.options = TransactionOptions() if tx.options.chain_id is None: @@ -120,51 +135,40 @@ def withdraw(self, tx: WithdrawTransaction): if tx.options.gas_price is None: tx.options.gas_price = self._zksync_web3.zksync.gas_price - if is_eth(tx.token): - transaction = TxWithdraw( - web3=self._zksync_web3, - account=self._l1_account, - chain_id=tx.options.chain_id, - nonce=tx.options.nonce, - to=tx.to, - amount=tx.amount, - gas_limit=0 if tx.options.gas_limit is None else tx.options.gas_limit, - gas_price=tx.options.gas_price, - token=tx.token, - bridge_address=tx.bridge_address, - ) - - estimated_gas = self._zksync_web3.zksync.eth_estimate_gas(transaction.tx) - tx = transaction.estimated_gas(estimated_gas) - signed = self._l1_account.sign_transaction(tx) - - return self._zksync_web3.zksync.send_raw_transaction(signed.rawTransaction) - - if tx.bridge_address is None: - l2_weth_token = ADDRESS_DEFAULT - try: - l2_weth_token = ( - self.get_l2_bridge_contracts() - .weth.functions.l1TokenAddress(tx.token) - .call() - ) - except: - pass - if l2_weth_token == ADDRESS_DEFAULT: - tx.bridge_address = self.get_l2_bridge_contracts().erc20.address - else: - tx.bridge_address = self.get_l2_bridge_contracts().weth.address - bridge = self._zksync_web3.zksync.contract( - address=Web3.to_checksum_address( - Web3.to_checksum_address(Web3.to_checksum_address(tx.bridge_address)) - ), - abi=l2_bridge_abi_default(), - ) - transaction = bridge.functions.withdraw( - self._l1_account.address, tx.token, tx.amount - ).build_transaction( - prepare_transaction_options(tx.options, self._l1_account.address) + if not is_eth(tx.token): + if tx.bridge_address is None: + l2_weth_token = ADDRESS_DEFAULT + try: + l2_weth_token = ( + self.get_l2_bridge_contracts() + .weth.functions.l1TokenAddress(tx.token) + .call() + ) + except: + pass + if l2_weth_token == ADDRESS_DEFAULT: + tx.bridge_address = Web3.to_checksum_address(self.get_l2_bridge_contracts().erc20.address) + else: + tx.bridge_address = Web3.to_checksum_address(self.get_l2_bridge_contracts().weth.address) + + transaction = TxWithdraw( + web3=self._zksync_web3, + account=self._l1_account, + chain_id=tx.options.chain_id, + nonce=tx.options.nonce, + to=tx.to, + amount=tx.amount, + gas_limit=0 if tx.options.gas_limit is None else tx.options.gas_limit, + gas_price=tx.options.gas_price, + token=tx.token, + bridge_address=tx.bridge_address, + paymaster_params=tx.paymaster_params ) + signer = PrivateKeyEthSigner(self._l1_account, tx.options.chain_id) + estimated_gas = self._zksync_web3.zksync.eth_estimate_gas(transaction.tx) + tx_712 = transaction.tx712(estimated_gas) + signed_message = signer.sign_typed_data(tx_712.to_eip712_struct()) + + msg = tx_712.encode(signed_message) - signed_tx = self._l1_account.sign_transaction(transaction) - return self._zksync_web3.zksync.send_raw_transaction(signed_tx.rawTransaction) + return self._zksync_web3.zksync.send_raw_transaction(msg) \ No newline at end of file diff --git a/zksync2/core/types.py b/zksync2/core/types.py index 97353b6..af3abee 100644 --- a/zksync2/core/types.py +++ b/zksync2/core/types.py @@ -215,6 +215,7 @@ class WithdrawTransaction: to: HexStr = None bridge_address: HexStr = None options: TransactionOptions = None + paymaster_params: PaymasterParams = None @dataclass @@ -239,8 +240,13 @@ class TransferTransaction: amount: int = 0 token_address: HexStr = None gas_per_pub_data: int = 50000 + paymaster_params: PaymasterParams = None options: TransactionOptions = None +@dataclass +class PaymasterParams: + paymaster: HexStr + paymaster_input: bytes @dataclass class RequestExecuteCallMsg: @@ -289,3 +295,15 @@ class FullDepositFee: max_fee_per_gas: int = None max_priority_fee_per_gas: int = None gas_price: int = None + +@dataclass +class StorageProofData: + key: HexStr + value: HexStr + index: int + proof: List[HexStr] + +@dataclass +class StorageProof: + address: HexStr + storageProof: StorageProofData \ No newline at end of file diff --git a/zksync2/module/zksync_module.py b/zksync2/module/zksync_module.py index 01418a7..c2e88ff 100644 --- a/zksync2/module/zksync_module.py +++ b/zksync2/module/zksync_module.py @@ -68,7 +68,7 @@ from typing import Any, Callable, List, Union from zksync2.transaction.transaction712 import Transaction712 -from zksync2.transaction.transaction_builders import TxWithdraw, TxFunctionCall +from zksync2.transaction.transaction_builders import TxWithdraw, TxFunctionCall, TxTransfer zks_l1_batch_number_rpc = RPCEndpoint("zks_L1BatchNumber") zks_get_l1_batch_block_range_rpc = RPCEndpoint("zks_getL1BatchBlockRange") @@ -690,8 +690,8 @@ def get_withdraw_transaction( return transaction def get_transfer_transaction( - self, tx: TransferTransaction, from_: HexStr - ) -> TxFunctionCall: + self, tx: TransferTransaction, from_: HexStr + ) -> TxTransfer: if tx.options is None: tx.options = TransactionOptions() if tx.options.chain_id is None: @@ -714,7 +714,15 @@ def get_transfer_transaction( Web3.to_checksum_address(tx.token_address), abi=get_erc20_abi() ) call_data = contract.encodeABI("transfer", transfer_params) - transaction = TxFunctionCall( + paymaster_params = None + if tx.paymaster_params is not None: + paymaster_params = PaymasterParams(**{ + "paymaster": tx.paymaster_params.paymaster, + "paymaster_input": tx.paymaster_params.paymaster_input + }) + transaction = TxTransfer( + web3=self, + token=tx.token_address, chain_id=tx.options.chain_id, nonce=tx.options.nonce, from_=from_, @@ -725,6 +733,7 @@ def get_transfer_transaction( gas_price=tx.options.gas_price, max_priority_fee_per_gas=tx.options.max_priority_fee_per_gas, gas_per_pub_data=tx.gas_per_pub_data, + paymaster_params=paymaster_params ) return transaction diff --git a/zksync2/transaction/transaction_builders.py b/zksync2/transaction/transaction_builders.py index 12a6316..8c19c28 100644 --- a/zksync2/transaction/transaction_builders.py +++ b/zksync2/transaction/transaction_builders.py @@ -12,7 +12,7 @@ from zksync2.manage_contracts.precompute_contract_deployer import ( PrecomputeContractDeployer, ) -from zksync2.manage_contracts.utils import l2_bridge_abi_default, eth_token_abi_default +from zksync2.manage_contracts.utils import l2_bridge_abi_default, eth_token_abi_default, get_erc20_abi from zksync2.module.request_types import ( EIP712Meta, TransactionType, @@ -301,6 +301,7 @@ def __init__( bridge_address: HexStr = None, chain_id: int = None, nonce: int = None, + paymaster_params = None ): # INFO: send to self if to is None: @@ -310,9 +311,16 @@ def __init__( if nonce is None: web3.zksync.get_transaction_count(account.address) + eip712_meta = EIP712Meta( + gas_per_pub_data=50000, + custom_signature=None, + factory_deps=None, + paymaster_params=paymaster_params, + ) + if is_eth(token): if chain_id is None: - web3.zksync.chain_id + chain_id = web3.zksync.chain_id contract = web3.zksync.contract( Web3.to_checksum_address(L2_ETH_TOKEN_ADDRESS), abi=eth_token_abi_default(), @@ -328,24 +336,37 @@ def __init__( } ) else: - if bridge_address is None: - bridge_addresses: BridgeAddresses = ( - web3.zksync.zks_get_bridge_contracts() - ) - bridge_address = bridge_addresses.erc20_l2_default_bridge l2_bridge = web3.eth.contract( address=Web3.to_checksum_address(bridge_address), abi=l2_bridge_abi_default(), ) tx = l2_bridge.functions.withdraw(to, token, amount).build_transaction( { - "from": account.address, "nonce": nonce, + "chainId": chain_id, "gas": gas_limit, + "gasPrice": gas_price, + "value": 0, + "from": account.address, } ) + tx['eip712Meta'] = eip712_meta super(TxWithdraw, self).__init__(trans=tx) + def tx712(self, estimated_gas: int) -> Transaction712: + return Transaction712( + chain_id=self.tx["chainId"], + nonce=Nonce(self.tx["nonce"]), + gas_limit=estimated_gas, + to=self.tx["to"], + value=self.tx["value"], + data=self.tx["data"], + maxPriorityFeePerGas=0, + maxFeePerGas=self.tx["gasPrice"], + from_=self.tx["from"], + meta=self.tx["eip712Meta"], + ) + @property def tx(self) -> ZkTx: return self.tx_ @@ -353,3 +374,74 @@ def tx(self) -> ZkTx: def estimated_gas(self, estimated_gas: int) -> ZkTx: self.tx_["gas"] = estimated_gas return self.tx_ + +class TxTransfer(TxBase, ABC): + def __init__( + self, + from_: HexStr, + to: HexStr, + web3 = None, + token: HexStr = None, + value: int = 0, + chain_id: int = None, + nonce: int = None, + data: HexStr = HexStr("0x"), + gas_limit: int = 0, + gas_price: int = 0, + max_priority_fee_per_gas: int = MAX_PRIORITY_FEE_PER_GAS, + paymaster_params=None, + custom_signature=None, + gas_per_pub_data: int = EIP712Meta.GAS_PER_PUB_DATA_DEFAULT, + ): + eip712_meta = EIP712Meta( + gas_per_pub_data=gas_per_pub_data, + custom_signature=custom_signature, + factory_deps=None, + paymaster_params=paymaster_params, + ) + if is_eth(token): + super(TxTransfer, self).__init__( + trans={ + "chainId": chain_id, + "nonce": nonce, + "from": from_, + "to": to, + "gas": gas_limit, + "gasPrice": gas_price, + "maxPriorityFeePerGas": max_priority_fee_per_gas, + "value": value, + "data": data, + "transactionType": TransactionType.EIP_712_TX_TYPE.value, + "eip712Meta": eip712_meta, + } + ) + else: + token_contract = web3.contract( + address=Web3.to_checksum_address(token), + abi=get_erc20_abi(), + ) + tx = token_contract.functions.transfer(to, value).build_transaction( + { + "nonce": nonce, + "chainId": chain_id, + "gas": gas_limit, + "gasPrice": gas_price, + "from": from_, + } + ) + tx['eip712Meta'] = eip712_meta + super(TxTransfer, self).__init__(trans=tx) + + def tx712(self, estimated_gas: int) -> Transaction712: + return Transaction712( + chain_id=self.tx["chainId"], + nonce=Nonce(self.tx["nonce"]), + gas_limit=estimated_gas, + to=self.tx["to"], + value=self.tx["value"], + data=self.tx["data"], + maxPriorityFeePerGas=0, + maxFeePerGas=self.tx["gasPrice"], + from_=self.tx["from"], + meta=self.tx["eip712Meta"], + ) \ No newline at end of file From 7cfa5c22aa271976f8bf7c5789959c86a1f7bd2f Mon Sep 17 00:00:00 2001 From: petarTxFusion Date: Sun, 18 Feb 2024 21:29:29 +0100 Subject: [PATCH 2/4] chore: lint code --- scripts/setup.py | 31 ++- tests/integration/test_wallet.py | 210 ++++++++++++++------ zksync2/account/wallet.py | 2 +- zksync2/account/wallet_l1.py | 5 +- zksync2/account/wallet_l2.py | 18 +- zksync2/core/types.py | 6 +- zksync2/module/zksync_module.py | 20 +- zksync2/transaction/transaction_builders.py | 17 +- 8 files changed, 212 insertions(+), 97 deletions(-) diff --git a/scripts/setup.py b/scripts/setup.py index d759020..0d20574 100644 --- a/scripts/setup.py +++ b/scripts/setup.py @@ -10,7 +10,10 @@ from zksync2.core.types import EthBlockParams, TransferTransaction from zksync2.core.utils import to_bytes -from zksync2.manage_contracts.contract_encoder_base import JsonConfiguration, ContractEncoder +from zksync2.manage_contracts.contract_encoder_base import ( + JsonConfiguration, + ContractEncoder, +) from zksync2.manage_contracts.deploy_addresses import ZkSyncAddresses from zksync2.signer.eth_signer import PrivateKeyEthSigner from zksync2.transaction.transaction_builders import TxCreate2Contract @@ -77,12 +80,12 @@ def setup_paymaster(provider_l1, provider_l2, wallet, signer, salt): ) abi = token_contract.abi - token_address = deploy_crown_token(provider_l2, wallet, signer, salt, token_contract) + token_address = deploy_crown_token( + provider_l2, wallet, signer, salt, token_contract + ) token_contract = provider_l2.zksync.contract(token_address, abi=abi) - mint_tx = token_contract.functions.mint( - wallet.address, 15 - ).build_transaction( + mint_tx = token_contract.functions.mint(wallet.address, 15).build_transaction( { "nonce": provider_l2.zksync.get_transaction_count( wallet.address, EthBlockParams.LATEST.value @@ -99,13 +102,22 @@ def setup_paymaster(provider_l1, provider_l2, wallet, signer, salt): tx_hash, timeout=240, poll_latency=0.5 ) - paymaster_address = deploy_paymaster(provider_l2, wallet, token_address, signer, salt) - faucet_hash = wallet.transfer(TransferTransaction(to=paymaster_address, amount=provider_l2.to_wei(1, "ether"), token_address=ZkSyncAddresses.ETH_ADDRESS.value)) + paymaster_address = deploy_paymaster( + provider_l2, wallet, token_address, signer, salt + ) + faucet_hash = wallet.transfer( + TransferTransaction( + to=paymaster_address, + amount=provider_l2.to_wei(1, "ether"), + token_address=ZkSyncAddresses.ETH_ADDRESS.value, + ) + ) provider_l2.zksync.wait_for_transaction_receipt( faucet_hash, timeout=240, poll_latency=0.5 ) + def deploy_crown_token(provider_l2, wallet, signer, salt, token_contract): constructor_arguments = {"name_": "Ducat", "symbol_": "Ducat", "decimals_": 18} chain_id = provider_l2.zksync.chain_id @@ -162,7 +174,7 @@ def deploy_paymaster(provider_l2: Web3, wallet, token_address, signer, salt): gas_price=gas_price, bytecode=token_contract.bytecode, call_data=encoded_constructor, - salt=to_bytes(salt) + salt=to_bytes(salt), ) estimate_gas = provider_l2.zksync.eth_estimate_gas(create_account.tx) tx_712 = create_account.tx712(estimate_gas) @@ -174,6 +186,7 @@ def deploy_paymaster(provider_l2: Web3, wallet, token_address, signer, salt): ) return tx_receipt["contractAddress"] + def load_token(): directory = Path(__file__).parent.parent path = directory / "tests/integration/token.json" @@ -184,4 +197,4 @@ def load_token(): if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/tests/integration/test_wallet.py b/tests/integration/test_wallet.py index 222015d..a93654a 100644 --- a/tests/integration/test_wallet.py +++ b/tests/integration/test_wallet.py @@ -21,7 +21,9 @@ TransactionOptions, TransferTransaction, WithdrawTransaction, - EthBlockParams, PaymasterParams, ZkBlockParams, + EthBlockParams, + PaymasterParams, + ZkBlockParams, ) from zksync2.manage_contracts.contract_encoder_base import ( ContractEncoder, @@ -35,7 +37,11 @@ from zksync2.manage_contracts.utils import zksync_abi_default, get_erc20_abi from zksync2.module.module_builder import ZkSyncBuilder from zksync2.signer.eth_signer import PrivateKeyEthSigner -from zksync2.transaction.transaction_builders import TxCreate2Contract, TxCreateContract, TxFunctionCall +from zksync2.transaction.transaction_builders import ( + TxCreate2Contract, + TxCreateContract, + TxFunctionCall, +) class TestWallet(TestCase): @@ -255,7 +261,7 @@ def test_transfer_eth(self): TransferTransaction( to=Web3.to_checksum_address(self.address2), token_address=ADDRESS_DEFAULT, - amount=amount + amount=amount, ) ) @@ -274,10 +280,14 @@ def test_transfer_eth_paymaster(self): token_address = self.zksync.to_checksum_address(self.token_address) paymaster_balance_before = self.zksync.zksync.zks_get_balance(paymaster_address) - paymaster_token_balance_before = self.zksync.zksync.zks_get_balance(paymaster_address, token_address=token_address) + paymaster_token_balance_before = self.zksync.zksync.zks_get_balance( + paymaster_address, token_address=token_address + ) sender_balance_before = self.wallet.get_balance() - sender_approval_token_balance_before = self.wallet.get_balance(token_address=token_address) + sender_approval_token_balance_before = self.wallet.get_balance( + token_address=token_address + ) reciever_balance_before = self.zksync.zksync.zks_get_balance(self.address2) paymaster_params = PaymasterParams( @@ -296,7 +306,7 @@ def test_transfer_eth_paymaster(self): to=Web3.to_checksum_address(self.address2), token_address=ADDRESS_DEFAULT, amount=amount, - paymaster_params=paymaster_params + paymaster_params=paymaster_params, ) ) @@ -305,15 +315,24 @@ def test_transfer_eth_paymaster(self): ) paymaster_balance_after = self.zksync.zksync.zks_get_balance(paymaster_address) - paymaster_token_balance_after = self.zksync.zksync.zks_get_balance(paymaster_address, token_address=token_address) + paymaster_token_balance_after = self.zksync.zksync.zks_get_balance( + paymaster_address, token_address=token_address + ) sender_balance_after = self.wallet.get_balance() - sender_approval_token_balance_after = self.wallet.get_balance(token_address=token_address) + sender_approval_token_balance_after = self.wallet.get_balance( + token_address=token_address + ) reciever_balance_after = self.zksync.zksync.zks_get_balance(self.address2) self.assertGreaterEqual(paymaster_balance_before - paymaster_balance_after, 0) - self.assertGreaterEqual(paymaster_token_balance_after - paymaster_token_balance_before, 0) + self.assertGreaterEqual( + paymaster_token_balance_after - paymaster_token_balance_before, 0 + ) self.assertGreaterEqual(sender_balance_before - sender_balance_after, 0) - self.assertGreater(sender_approval_token_balance_before - sender_approval_token_balance_after, 0) + self.assertGreater( + sender_approval_token_balance_before - sender_approval_token_balance_after, + 0, + ) self.assertGreaterEqual(reciever_balance_after - reciever_balance_before, 0) @skip("Used only for development purpose to refill paymaster") @@ -325,9 +344,13 @@ def test_mint_paymaster(self): self.zksync, path.resolve(), JsonConfiguration.STANDARD ) abi = token_contract.abi - token_contract = self.zksync.zksync.contract(Web3.to_checksum_address(self.token_address), abi=abi) + token_contract = self.zksync.zksync.contract( + Web3.to_checksum_address(self.token_address), abi=abi + ) - balance_before = self.wallet.get_balance(Web3.to_checksum_address(self.token_address)) + balance_before = self.wallet.get_balance( + Web3.to_checksum_address(self.token_address) + ) mint_tx = token_contract.functions.mint( self.wallet.address, 15 ).build_transaction( @@ -346,18 +369,21 @@ def test_mint_paymaster(self): self.zksync.zksync.wait_for_transaction_receipt( tx_hash, timeout=240, poll_latency=0.5 ) - balance_after = self.wallet.get_balance(Web3.to_checksum_address(self.token_address)) + balance_after = self.wallet.get_balance( + Web3.to_checksum_address(self.token_address) + ) self.assertEqual(15, balance_after - balance_before) - def test_transfer_token(self): amount = 5 l1_address, l2_address = self.load_token() sender_before = self.wallet.get_balance(token_address=l2_address) balance_before = self.zksync.zksync.zks_get_balance( - self.address2, token_address=l2_address, block_tag=ZkBlockParams.LATEST.value + self.address2, + token_address=l2_address, + block_tag=ZkBlockParams.LATEST.value, ) tx_hash = self.wallet.transfer( TransferTransaction( @@ -374,11 +400,13 @@ def test_transfer_token(self): sender_after = self.wallet.get_balance(token_address=l2_address) balance_after = self.zksync.zksync.zks_get_balance( - self.address2, token_address=l2_address, block_tag=ZkBlockParams.LATEST.value + self.address2, + token_address=l2_address, + block_tag=ZkBlockParams.LATEST.value, ) self.assertEqual(amount, sender_before - sender_after) - self.assertEqual(amount ,balance_after - balance_before) + self.assertEqual(amount, balance_after - balance_before) def test_transfer_token_paymaster(self): amount = 5 @@ -388,15 +416,23 @@ def test_transfer_token_paymaster(self): token_address = self.zksync.to_checksum_address(self.token_address) paymaster_balance_before = self.zksync.zksync.zks_get_balance(paymaster_address) - paymaster_token_balance_before = self.zksync.zksync.zks_get_balance(paymaster_address, - token_address=token_address, - block_tag=ZkBlockParams.LATEST.value) + paymaster_token_balance_before = self.zksync.zksync.zks_get_balance( + paymaster_address, + token_address=token_address, + block_tag=ZkBlockParams.LATEST.value, + ) - sender_balance_before = self.wallet.get_balance(token_address=Web3.to_checksum_address(l2_address)) - sender_approval_token_balance_before = self.wallet.get_balance(token_address=token_address) - reciever_balance_before = self.zksync.zksync.zks_get_balance(self.address2, - token_address=Web3.to_checksum_address(l2_address), - block_tag=ZkBlockParams.LATEST.value) + sender_balance_before = self.wallet.get_balance( + token_address=Web3.to_checksum_address(l2_address) + ) + sender_approval_token_balance_before = self.wallet.get_balance( + token_address=token_address + ) + reciever_balance_before = self.zksync.zksync.zks_get_balance( + self.address2, + token_address=Web3.to_checksum_address(l2_address), + block_tag=ZkBlockParams.LATEST.value, + ) paymaster_params = PaymasterParams( **{ @@ -414,28 +450,39 @@ def test_transfer_token_paymaster(self): to=Web3.to_checksum_address(self.address2), token_address=Web3.to_checksum_address(l2_address), amount=amount, - paymaster_params=paymaster_params + paymaster_params=paymaster_params, ) ) - self.zksync.zksync.wait_finalized( - tx_hash, timeout=240, poll_latency=0.5 - ) + self.zksync.zksync.wait_finalized(tx_hash, timeout=240, poll_latency=0.5) paymaster_balance_after = self.zksync.zksync.zks_get_balance(paymaster_address) - paymaster_token_balance_after = self.zksync.zksync.zks_get_balance(paymaster_address, - token_address=token_address, - block_tag=ZkBlockParams.LATEST.value) + paymaster_token_balance_after = self.zksync.zksync.zks_get_balance( + paymaster_address, + token_address=token_address, + block_tag=ZkBlockParams.LATEST.value, + ) - sender_balance_after = self.wallet.get_balance(token_address=Web3.to_checksum_address(l2_address)) - sender_approval_token_balance_after = self.wallet.get_balance(token_address=token_address) - reciever_balance_after = self.zksync.zksync.zks_get_balance(self.address2, - token_address=Web3.to_checksum_address(l2_address), - block_tag=ZkBlockParams.LATEST.value) + sender_balance_after = self.wallet.get_balance( + token_address=Web3.to_checksum_address(l2_address) + ) + sender_approval_token_balance_after = self.wallet.get_balance( + token_address=token_address + ) + reciever_balance_after = self.zksync.zksync.zks_get_balance( + self.address2, + token_address=Web3.to_checksum_address(l2_address), + block_tag=ZkBlockParams.LATEST.value, + ) self.assertGreaterEqual(paymaster_balance_before - paymaster_balance_after, 0) - self.assertEqual(paymaster_token_balance_after - paymaster_token_balance_before, 1) + self.assertEqual( + paymaster_token_balance_after - paymaster_token_balance_before, 1 + ) self.assertEqual(sender_balance_before - sender_balance_after, 5) - self.assertEqual(sender_approval_token_balance_before - sender_approval_token_balance_after, 1) + self.assertEqual( + sender_approval_token_balance_before - sender_approval_token_balance_after, + 1, + ) self.assertEqual(reciever_balance_after - reciever_balance_before, 5) def test_withdraw_eth(self): @@ -467,11 +514,14 @@ def test_withdraw_eth_paymaster(self): token_address = self.zksync.to_checksum_address(self.token_address) paymaster_balance_before = self.zksync.zksync.zks_get_balance(paymaster_address) - paymaster_token_balance_before = self.zksync.zksync.zks_get_balance(paymaster_address, - token_address=token_address) + paymaster_token_balance_before = self.zksync.zksync.zks_get_balance( + paymaster_address, token_address=token_address + ) sender_balance_before = self.wallet.get_balance() - sender_approval_token_balance_before = self.wallet.get_balance(token_address=token_address) + sender_approval_token_balance_before = self.wallet.get_balance( + token_address=token_address + ) paymaster_params = PaymasterParams( **{ @@ -488,29 +538,43 @@ def test_withdraw_eth_paymaster(self): WithdrawTransaction( token=Token.create_eth().l1_address, amount=Web3.to_wei(amount, "ether"), - paymaster_params=paymaster_params + paymaster_params=paymaster_params, ) ) withdraw_receipt = self.zksync.zksync.wait_finalized( withdraw_tx_hash, timeout=240, poll_latency=0.5 ) - self.assertFalse(self.wallet.is_withdrawal_finalized(withdraw_receipt["transactionHash"])) + self.assertFalse( + self.wallet.is_withdrawal_finalized(withdraw_receipt["transactionHash"]) + ) - finalized_hash = self.wallet.finalize_withdrawal(withdraw_receipt["transactionHash"]) + finalized_hash = self.wallet.finalize_withdrawal( + withdraw_receipt["transactionHash"] + ) self.eth_web3.eth.wait_for_transaction_receipt( finalized_hash, timeout=240, poll_latency=0.5 ) paymaster_balance_after = self.zksync.zksync.zks_get_balance(paymaster_address) - paymaster_token_balance_after = self.zksync.zksync.zks_get_balance(paymaster_address, - token_address=token_address) + paymaster_token_balance_after = self.zksync.zksync.zks_get_balance( + paymaster_address, token_address=token_address + ) sender_balance_after = self.wallet.get_balance() - sender_approval_token_balance_after = self.wallet.get_balance(token_address=token_address) + sender_approval_token_balance_after = self.wallet.get_balance( + token_address=token_address + ) self.assertGreater(paymaster_balance_before - paymaster_balance_after, 0) - self.assertEqual(paymaster_token_balance_after - paymaster_token_balance_before, 1) - self.assertEqual(sender_balance_before - sender_balance_after, Web3.to_wei(amount, "ether")) - self.assertEqual(sender_approval_token_balance_after, sender_approval_token_balance_before - 1) + self.assertEqual( + paymaster_token_balance_after - paymaster_token_balance_before, 1 + ) + self.assertEqual( + sender_balance_before - sender_balance_after, Web3.to_wei(amount, "ether") + ) + self.assertEqual( + sender_approval_token_balance_after, + sender_approval_token_balance_before - 1, + ) def test_withdraw_token_paymaster(self): l1_address, l2_address = self.load_token() @@ -518,11 +582,17 @@ def test_withdraw_token_paymaster(self): token_address = self.zksync.to_checksum_address(self.token_address) paymaster_balance_before = self.zksync.zksync.zks_get_balance(paymaster_address) - paymaster_token_balance_before = self.zksync.zksync.zks_get_balance(paymaster_address, - token_address=token_address, - block_tag=ZkBlockParams.LATEST.value) - l2_balance_before = self.wallet.get_balance(token_address=Web3.to_checksum_address(l2_address)) - l2_approval_token_balance_before = self.wallet.get_balance(token_address=token_address) + paymaster_token_balance_before = self.zksync.zksync.zks_get_balance( + paymaster_address, + token_address=token_address, + block_tag=ZkBlockParams.LATEST.value, + ) + l2_balance_before = self.wallet.get_balance( + token_address=Web3.to_checksum_address(l2_address) + ) + l2_approval_token_balance_before = self.wallet.get_balance( + token_address=token_address + ) paymaster_params = PaymasterParams( **{ @@ -536,7 +606,11 @@ def test_withdraw_token_paymaster(self): ) withdraw_tx_hash = self.wallet.withdraw( - WithdrawTransaction(Web3.to_checksum_address(l2_address), 5, paymaster_params=paymaster_params) + WithdrawTransaction( + Web3.to_checksum_address(l2_address), + 5, + paymaster_params=paymaster_params, + ) ) receipt = self.zksync.zksync.wait_finalized( @@ -546,18 +620,26 @@ def test_withdraw_token_paymaster(self): finalized_hash = self.wallet.finalize_withdrawal(withdraw_tx_hash) self.eth_web3.eth.wait_for_transaction_receipt(finalized_hash) paymaster_balance_after = self.zksync.zksync.zks_get_balance(paymaster_address) - paymaster_token_balance_after = self.zksync.zksync.zks_get_balance(paymaster_address, - token_address=token_address, - block_tag=ZkBlockParams.LATEST.value) + paymaster_token_balance_after = self.zksync.zksync.zks_get_balance( + paymaster_address, + token_address=token_address, + block_tag=ZkBlockParams.LATEST.value, + ) l2_balance_after = self.wallet.get_balance( token_address=Web3.to_checksum_address(l2_address) ) - l2_approval_token_balance_after = self.wallet.get_balance(token_address=token_address) + l2_approval_token_balance_after = self.wallet.get_balance( + token_address=token_address + ) self.assertGreaterEqual(paymaster_balance_before - paymaster_balance_after, 0) - self.assertEqual(paymaster_token_balance_after - paymaster_token_balance_before, 1) + self.assertEqual( + paymaster_token_balance_after - paymaster_token_balance_before, 1 + ) self.assertIsNotNone(receipt) - self.assertEqual(l2_approval_token_balance_before - l2_approval_token_balance_after, 1) + self.assertEqual( + l2_approval_token_balance_before - l2_approval_token_balance_after, 1 + ) self.assertEqual(l2_balance_before - l2_balance_after, 5) def test_withdraw_token(self): @@ -633,4 +715,4 @@ def test_request_execute(self): l2_balance_after - l2_balance_before, amount, "Balance on L2 should be increased", - ) \ No newline at end of file + ) diff --git a/zksync2/account/wallet.py b/zksync2/account/wallet.py index d31d9fe..a8f5cdf 100644 --- a/zksync2/account/wallet.py +++ b/zksync2/account/wallet.py @@ -15,4 +15,4 @@ def __init__(self, zksync_web3: Web3, eth_web3: Web3, l1_account: BaseAccount): WalletL2.__init__(self, zksync_web3, eth_web3, l1_account) def sign_transaction(self, tx): - return self._l1_account.sign_transaction(tx) \ No newline at end of file + return self._l1_account.sign_transaction(tx) diff --git a/zksync2/account/wallet_l1.py b/zksync2/account/wallet_l1.py index 4cd42e3..a709fb1 100644 --- a/zksync2/account/wallet_l1.py +++ b/zksync2/account/wallet_l1.py @@ -820,7 +820,8 @@ def finalize_withdrawal(self, withdraw_hash, index: int = 0): return tx_hash else: l2_bridge = self._zksync_web3.zksync.contract( - address= Web3.to_checksum_address(params["sender"]), abi=l2_bridge_abi_default() + address=Web3.to_checksum_address(params["sender"]), + abi=l2_bridge_abi_default(), ) l1_bridge = self._eth_web3.eth.contract( address=Web3.to_checksum_address(l2_bridge.functions.l1Bridge().call()), @@ -1010,4 +1011,4 @@ def estimate_gas_request_execute(self, transaction: RequestExecuteCallMsg) -> in prepare_transaction_options(transaction.options, self.address) ) - return self._eth_web3.eth.estimate_gas(tx) \ No newline at end of file + return self._eth_web3.eth.estimate_gas(tx) diff --git a/zksync2/account/wallet_l2.py b/zksync2/account/wallet_l2.py index ef1d59d..09f9fa9 100644 --- a/zksync2/account/wallet_l2.py +++ b/zksync2/account/wallet_l2.py @@ -43,10 +43,10 @@ def get_balance( self, block_tag=ZkBlockParams.COMMITTED.value, token_address: HexStr = None ) -> int: """ - Returns the balance of the account. + Returns the balance of the account. - :param block_tag: The block tag to get the balance at. Defaults to 'committed'. - :param token_address: The token address to query balance for. Defaults to the native token. + :param block_tag: The block tag to get the balance at. Defaults to 'committed'. + :param token_address: The token address to query balance for. Defaults to the native token. """ return self._zksync_web3.zksync.zks_get_balance( self._l1_account.address, block_tag, token_address @@ -147,9 +147,13 @@ def withdraw(self, tx: WithdrawTransaction): except: pass if l2_weth_token == ADDRESS_DEFAULT: - tx.bridge_address = Web3.to_checksum_address(self.get_l2_bridge_contracts().erc20.address) + tx.bridge_address = Web3.to_checksum_address( + self.get_l2_bridge_contracts().erc20.address + ) else: - tx.bridge_address = Web3.to_checksum_address(self.get_l2_bridge_contracts().weth.address) + tx.bridge_address = Web3.to_checksum_address( + self.get_l2_bridge_contracts().weth.address + ) transaction = TxWithdraw( web3=self._zksync_web3, @@ -162,7 +166,7 @@ def withdraw(self, tx: WithdrawTransaction): gas_price=tx.options.gas_price, token=tx.token, bridge_address=tx.bridge_address, - paymaster_params=tx.paymaster_params + paymaster_params=tx.paymaster_params, ) signer = PrivateKeyEthSigner(self._l1_account, tx.options.chain_id) estimated_gas = self._zksync_web3.zksync.eth_estimate_gas(transaction.tx) @@ -171,4 +175,4 @@ def withdraw(self, tx: WithdrawTransaction): msg = tx_712.encode(signed_message) - return self._zksync_web3.zksync.send_raw_transaction(msg) \ No newline at end of file + return self._zksync_web3.zksync.send_raw_transaction(msg) diff --git a/zksync2/core/types.py b/zksync2/core/types.py index af3abee..e34c947 100644 --- a/zksync2/core/types.py +++ b/zksync2/core/types.py @@ -243,11 +243,13 @@ class TransferTransaction: paymaster_params: PaymasterParams = None options: TransactionOptions = None + @dataclass class PaymasterParams: paymaster: HexStr paymaster_input: bytes + @dataclass class RequestExecuteCallMsg: contract_address: HexStr @@ -296,6 +298,7 @@ class FullDepositFee: max_priority_fee_per_gas: int = None gas_price: int = None + @dataclass class StorageProofData: key: HexStr @@ -303,7 +306,8 @@ class StorageProofData: index: int proof: List[HexStr] + @dataclass class StorageProof: address: HexStr - storageProof: StorageProofData \ No newline at end of file + storageProof: StorageProofData diff --git a/zksync2/module/zksync_module.py b/zksync2/module/zksync_module.py index c2e88ff..82221d9 100644 --- a/zksync2/module/zksync_module.py +++ b/zksync2/module/zksync_module.py @@ -68,7 +68,11 @@ from typing import Any, Callable, List, Union from zksync2.transaction.transaction712 import Transaction712 -from zksync2.transaction.transaction_builders import TxWithdraw, TxFunctionCall, TxTransfer +from zksync2.transaction.transaction_builders import ( + TxWithdraw, + TxFunctionCall, + TxTransfer, +) zks_l1_batch_number_rpc = RPCEndpoint("zks_L1BatchNumber") zks_get_l1_batch_block_range_rpc = RPCEndpoint("zks_getL1BatchBlockRange") @@ -690,7 +694,7 @@ def get_withdraw_transaction( return transaction def get_transfer_transaction( - self, tx: TransferTransaction, from_: HexStr + self, tx: TransferTransaction, from_: HexStr ) -> TxTransfer: if tx.options is None: tx.options = TransactionOptions() @@ -716,10 +720,12 @@ def get_transfer_transaction( call_data = contract.encodeABI("transfer", transfer_params) paymaster_params = None if tx.paymaster_params is not None: - paymaster_params = PaymasterParams(**{ - "paymaster": tx.paymaster_params.paymaster, - "paymaster_input": tx.paymaster_params.paymaster_input - }) + paymaster_params = PaymasterParams( + **{ + "paymaster": tx.paymaster_params.paymaster, + "paymaster_input": tx.paymaster_params.paymaster_input, + } + ) transaction = TxTransfer( web3=self, token=tx.token_address, @@ -733,7 +739,7 @@ def get_transfer_transaction( gas_price=tx.options.gas_price, max_priority_fee_per_gas=tx.options.max_priority_fee_per_gas, gas_per_pub_data=tx.gas_per_pub_data, - paymaster_params=paymaster_params + paymaster_params=paymaster_params, ) return transaction diff --git a/zksync2/transaction/transaction_builders.py b/zksync2/transaction/transaction_builders.py index 8c19c28..48d35b4 100644 --- a/zksync2/transaction/transaction_builders.py +++ b/zksync2/transaction/transaction_builders.py @@ -12,7 +12,11 @@ from zksync2.manage_contracts.precompute_contract_deployer import ( PrecomputeContractDeployer, ) -from zksync2.manage_contracts.utils import l2_bridge_abi_default, eth_token_abi_default, get_erc20_abi +from zksync2.manage_contracts.utils import ( + l2_bridge_abi_default, + eth_token_abi_default, + get_erc20_abi, +) from zksync2.module.request_types import ( EIP712Meta, TransactionType, @@ -301,7 +305,7 @@ def __init__( bridge_address: HexStr = None, chain_id: int = None, nonce: int = None, - paymaster_params = None + paymaster_params=None, ): # INFO: send to self if to is None: @@ -350,7 +354,7 @@ def __init__( "from": account.address, } ) - tx['eip712Meta'] = eip712_meta + tx["eip712Meta"] = eip712_meta super(TxWithdraw, self).__init__(trans=tx) def tx712(self, estimated_gas: int) -> Transaction712: @@ -375,12 +379,13 @@ def estimated_gas(self, estimated_gas: int) -> ZkTx: self.tx_["gas"] = estimated_gas return self.tx_ + class TxTransfer(TxBase, ABC): def __init__( self, from_: HexStr, to: HexStr, - web3 = None, + web3=None, token: HexStr = None, value: int = 0, chain_id: int = None, @@ -429,7 +434,7 @@ def __init__( "from": from_, } ) - tx['eip712Meta'] = eip712_meta + tx["eip712Meta"] = eip712_meta super(TxTransfer, self).__init__(trans=tx) def tx712(self, estimated_gas: int) -> Transaction712: @@ -444,4 +449,4 @@ def tx712(self, estimated_gas: int) -> Transaction712: maxFeePerGas=self.tx["gasPrice"], from_=self.tx["from"], meta=self.tx["eip712Meta"], - ) \ No newline at end of file + ) From 6414f0b710db605eaf24fd7008c66d4ce930a2d1 Mon Sep 17 00:00:00 2001 From: petarTxFusion Date: Sun, 18 Feb 2024 21:41:36 +0100 Subject: [PATCH 3/4] test: fix tests setup --- scripts/setup.py | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/scripts/setup.py b/scripts/setup.py index 0d20574..ff7eeb8 100644 --- a/scripts/setup.py +++ b/scripts/setup.py @@ -1,4 +1,5 @@ # Deposits token to l2 so that tests can run +# Creates paymaster and crown token import json import os import sys @@ -8,18 +9,10 @@ from eth_account.signers.local import LocalAccount from web3 import Web3 -from zksync2.core.types import EthBlockParams, TransferTransaction -from zksync2.core.utils import to_bytes -from zksync2.manage_contracts.contract_encoder_base import ( - JsonConfiguration, - ContractEncoder, -) -from zksync2.manage_contracts.deploy_addresses import ZkSyncAddresses -from zksync2.signer.eth_signer import PrivateKeyEthSigner -from zksync2.transaction.transaction_builders import TxCreate2Contract - def main(): + from zksync2.signer.eth_signer import PrivateKeyEthSigner + current_directory = os.path.dirname(os.path.abspath(__file__)) parent_directory = os.path.join(current_directory, "..") sys.path.append(parent_directory) @@ -72,6 +65,13 @@ def deposit_token(wallet, eth_web3: Web3, zksync: Web3, zksync_contract): def setup_paymaster(provider_l1, provider_l2, wallet, signer, salt): + from zksync2.core.types import EthBlockParams, TransferTransaction + from zksync2.manage_contracts.contract_encoder_base import ( + JsonConfiguration, + ContractEncoder, + ) + from zksync2.manage_contracts.deploy_addresses import ZkSyncAddresses + directory = Path(__file__).parent.parent path = directory / "tests/contracts/Token.json" @@ -119,6 +119,10 @@ def setup_paymaster(provider_l1, provider_l2, wallet, signer, salt): def deploy_crown_token(provider_l2, wallet, signer, salt, token_contract): + from zksync2.core.types import EthBlockParams + from zksync2.core.utils import to_bytes + from zksync2.transaction.transaction_builders import TxCreate2Contract + constructor_arguments = {"name_": "Ducat", "symbol_": "Ducat", "decimals_": 18} chain_id = provider_l2.zksync.chain_id nonce = provider_l2.zksync.get_transaction_count( @@ -151,6 +155,14 @@ def deploy_crown_token(provider_l2, wallet, signer, salt, token_contract): def deploy_paymaster(provider_l2: Web3, wallet, token_address, signer, salt): + from zksync2.core.types import EthBlockParams + from zksync2.core.utils import to_bytes + from zksync2.manage_contracts.contract_encoder_base import ( + JsonConfiguration, + ContractEncoder, + ) + from zksync2.transaction.transaction_builders import TxCreate2Contract + directory = Path(__file__).parent.parent path = directory / "tests/contracts/Paymaster.json" token_address = provider_l2.to_checksum_address(token_address) From 55d6e632a1b6866091cd165725833cef56b3cbb4 Mon Sep 17 00:00:00 2001 From: petarTxFusion Date: Sun, 18 Feb 2024 21:50:59 +0100 Subject: [PATCH 4/4] test: fix tests setup --- scripts/setup.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/setup.py b/scripts/setup.py index ff7eeb8..305fc50 100644 --- a/scripts/setup.py +++ b/scripts/setup.py @@ -11,8 +11,6 @@ def main(): - from zksync2.signer.eth_signer import PrivateKeyEthSigner - current_directory = os.path.dirname(os.path.abspath(__file__)) parent_directory = os.path.join(current_directory, "..") sys.path.append(parent_directory) @@ -21,6 +19,7 @@ def main(): from zksync2.account.wallet import Wallet from zksync2.manage_contracts.utils import zksync_abi_default from zksync2.module.module_builder import ZkSyncBuilder + from zksync2.signer.eth_signer import PrivateKeyEthSigner zksync = ZkSyncBuilder.build("http://127.0.0.1:3050") eth_web3 = Web3(Web3.HTTPProvider("http://127.0.0.1:8545"))