diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 2bb8bcf..ae0d67d 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -49,7 +49,7 @@ We follow basic coding style guidelines. Before committing, ensure your code is ## Need Assistance? -If you're unsure about something or have questions, don't hesitate to open an issue or initiate a discussion in our [zkSync Community Hub](https://github.com/zkSync-Community-Hub/zkSync-developers/discussions). We're here to assist! +If you're unsure about something or have questions, don't hesitate to open an issue or initiate a discussion in our [ZKsync Community Hub](https://github.com/zkSync-Community-Hub/zkSync-developers/discussions). We're here to assist! ## What's Next? diff --git a/pyproject.toml b/pyproject.toml index 7ccc846..eab7e60 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ version = "1.2.0" authors = [ { name="Matter Labs", email= "hello@matterlabs.io" }, ] -description = "zkSync2 python client sdk" +description = "ZKsync python client sdk" readme = "README.md" requires-python = ">=3.8" classifiers = [ diff --git a/requirements.txt b/requirements.txt index f8791af..2f865e8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -web3>=6.10.0 +web3>=7.3.0 eth-tester black \ No newline at end of file diff --git a/scripts/setup.py b/scripts/setup.py index 23ccbca..d6a19fa 100644 --- a/scripts/setup.py +++ b/scripts/setup.py @@ -7,6 +7,7 @@ from eth_account import Account from eth_account.signers.local import LocalAccount +from eth_typing import HexStr from web3 import Web3 @@ -15,17 +16,27 @@ def main(): parent_directory = os.path.join(current_directory, "..") sys.path.append(parent_directory) SALT = "0x293328ad84b118194c65a0dc0defdb6483740d3163fd99b260907e15f2e2f642" + private_key_1 = HexStr( + "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110" + ) + private_key_2 = HexStr( + "0xac1e735be8536c6534bb4f17f06f6afc73b2b5ba84ac2cfb12f7461b20c0bbe3" + ) + approval_token = HexStr("0x0183Fe07a98bc036d6eb23C3943d823bcD66a90F") + dai_l1 = Web3.to_checksum_address("0x70a0F165d6f8054d0d0CF8dFd4DD2005f0AF6B55") from zksync2.account.wallet import Wallet from zksync2.manage_contracts.utils import get_zksync_hyperchain from zksync2.module.module_builder import ZkSyncBuilder from zksync2.signer.eth_signer import PrivateKeyEthSigner + from zksync2.core.utils import LEGACY_ETH_ADDRESS + from tests.integration.test_config import EnvURL - zksync = ZkSyncBuilder.build("http://127.0.0.1:15100") - eth_web3 = Web3(Web3.HTTPProvider("http://127.0.0.1:15045")) - account: LocalAccount = Account.from_key( - "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110" - ) + env = EnvURL() + zksync = ZkSyncBuilder.build(env.env.zksync_server) + eth_web3 = Web3(Web3.HTTPProvider(env.env.eth_server)) + + account: LocalAccount = Account.from_key(private_key_1) chain_id = zksync.zksync.chain_id signer = PrivateKeyEthSigner(account, chain_id) @@ -35,22 +46,50 @@ def main(): abi=get_zksync_hyperchain(), ) - deposit_token(wallet, eth_web3, zksync, zksync_contract) + if not wallet.is_eth_based_chain(): + base_token = wallet.get_base_token() + print("L1 base token balance before: ", wallet.get_l1_balance(token=base_token)) + print("L2 base token balance before: ", wallet.get_balance()) + deposit_token(wallet, base_token, eth_web3, zksync, zksync_contract) + print("L1 base token balance after: ", wallet.get_l1_balance(token=base_token)) + print("L2 base token balance after: ", wallet.get_balance()) + + print("L1 eth balance before: ", wallet.get_l1_balance()) + print( + "L2 eth balance before: ", + wallet.get_balance(token_address=LEGACY_ETH_ADDRESS), + ) + deposit_token(wallet, LEGACY_ETH_ADDRESS, eth_web3, zksync, zksync_contract) + print("L1 eth balance after: ", wallet.get_l1_balance()) + print( + "L2 eth balance after: ", + wallet.get_balance(token_address=LEGACY_ETH_ADDRESS), + ) + + dai_l2 = wallet.l2_token_address(address=dai_l1) + print("L1 DAI token balance before: ", wallet.get_l1_balance(token=dai_l1)) + print("L2 DAI token balance before: ", wallet.get_balance(token_address=dai_l2)) + deposit_token(wallet, dai_l1, eth_web3, zksync, zksync_contract) + print("L1 DAI token balance after: ", wallet.get_l1_balance(token=dai_l1)) + print("L2 DAI token balance after: ", wallet.get_balance(token_address=dai_l2)) + setup_paymaster(eth_web3, zksync, wallet, signer, SALT) + deploy_multisig_contract( + wallet, zksync, private_key_1, private_key_2, dai_l1, approval_token, SALT + ) -def deposit_token(wallet, eth_web3: Web3, zksync: Web3, zksync_contract): - from zksync2.core.types import DepositTransaction +def deposit_token(wallet, token_address, eth_web3: Web3, zksync: Web3, zksync_contract): from zksync2.manage_contracts.utils import get_test_net_erc20_token from zksync2.core.types import EthBlockParams - - amount = 100 - l1_address = load_token() + from zksync2.core.types import DepositTransaction token_contract = eth_web3.eth.contract( - Web3.to_checksum_address(l1_address), abi=get_test_net_erc20_token() + Web3.to_checksum_address(token_address), abi=get_test_net_erc20_token() ) - mint_tx = token_contract.functions.mint(wallet.address, 10000).build_transaction( + mint_tx = token_contract.functions.mint( + wallet.address, Web3.to_wei(20000, "ether") + ).build_transaction( { "nonce": eth_web3.eth.get_transaction_count( wallet.address, EthBlockParams.LATEST.value @@ -62,13 +101,13 @@ def deposit_token(wallet, eth_web3: Web3, zksync: Web3, zksync_contract): ) signed = wallet.sign_transaction(mint_tx) - tx_hash = eth_web3.eth.send_raw_transaction(signed.rawTransaction) + tx_hash = eth_web3.eth.send_raw_transaction(signed.raw_transaction) eth_web3.eth.wait_for_transaction_receipt(tx_hash, timeout=240, poll_latency=0.5) tx_hash = wallet.deposit( DepositTransaction( - Web3.to_checksum_address(l1_address), - amount, + Web3.to_checksum_address(token_address), + Web3.to_wei(10000, "ether"), wallet.address, approve_erc20=True, approve_base_erc20=True, @@ -105,7 +144,7 @@ def setup_paymaster(provider_l1, provider_l2, wallet, signer, salt): ) 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, 1000).build_transaction( { "nonce": provider_l2.zksync.get_transaction_count( wallet.address, EthBlockParams.LATEST.value @@ -117,7 +156,7 @@ def setup_paymaster(provider_l1, provider_l2, wallet, signer, salt): ) signed = wallet.sign_transaction(mint_tx) - tx_hash = provider_l2.eth.send_raw_transaction(signed.rawTransaction) + tx_hash = provider_l2.eth.send_raw_transaction(signed.raw_transaction) provider_l2.zksync.wait_for_transaction_receipt( tx_hash, timeout=240, poll_latency=0.5 ) @@ -126,11 +165,7 @@ def setup_paymaster(provider_l1, provider_l2, wallet, signer, salt): 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, - ) + TransferTransaction(to=paymaster_address, amount=provider_l2.to_wei(1, "ether")) ) provider_l2.zksync.wait_for_transaction_receipt( @@ -171,6 +206,8 @@ def deploy_crown_token(provider_l2, wallet, signer, salt, token_contract): tx_hash, timeout=240, poll_latency=0.5 ) + print("Approval token contract address: ", tx_receipt["contractAddress"]) + return tx_receipt["contractAddress"] @@ -182,41 +219,136 @@ def deploy_paymaster(provider_l2: Web3, wallet, token_address, signer, salt): ContractEncoder, ) from zksync2.transaction.transaction_builders import TxCreate2Contract + from zksync2.manage_contracts.contract_factory import LegacyContractFactory + from zksync2.manage_contracts.contract_factory import DeploymentType 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 + deployer = LegacyContractFactory.from_json( + zksync=provider_l2, + compiled_contract=path.resolve(), + account=signer, + signer=signer, + deployment_type=DeploymentType.CREATE2_ACCOUNT, ) - token_contract = ContractEncoder.from_json( - provider_l2, path.resolve(), JsonConfiguration.STANDARD + contract = deployer.deploy(salt=to_bytes(salt), **constructor_arguments) + + # 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 + # ) + print("Paymaster contract address: ", contract.address) + + return contract.address + + +def deploy_multisig_contract( + wallet, zksync, private_key_1, private_key_2, dai_l1, approval_token_l1, salt +): + from zksync2.manage_contracts.contract_encoder_base import ContractEncoder + from zksync2.manage_contracts.contract_encoder_base import JsonConfiguration + from zksync2.core.types import EthBlockParams + from zksync2.transaction.transaction_builders import TxCreate2Account + from zksync2.signer.eth_signer import PrivateKeyEthSigner + from zksync2.core.types import TransferTransaction + from zksync2.core.utils import LEGACY_ETH_ADDRESS + from zksync2.core.utils import to_bytes + + directory = Path(__file__).parent.parent + contract_path = directory / "tests/contracts/TwoUserMultisig.json" + owner_1 = Account.from_key(private_key_1) + owner_2 = Account.from_key(private_key_2) + + multisig_contract = ContractEncoder.from_json( + zksync, contract_path, 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, + constructor = multisig_contract.encode_constructor( + **{"_owner1": owner_1.address, "_owner2": owner_2.address} + ) + nonce = zksync.zksync.get_transaction_count( + owner_1.address, EthBlockParams.PENDING.value + ) + gas_price = zksync.zksync.gas_price + + create2_contract = TxCreate2Account( + web3=zksync, + chain_id=zksync.eth.chain_id, nonce=nonce, - from_=wallet.address, + from_=owner_1.address, + gas_limit=0, gas_price=gas_price, - bytecode=token_contract.bytecode, - call_data=encoded_constructor, + bytecode=multisig_contract.bytecode, + call_data=constructor, salt=to_bytes(salt), ) - estimate_gas = provider_l2.zksync.eth_estimate_gas(create_account.tx) - tx_712 = create_account.tx712(estimate_gas) + estimate_gas = zksync.zksync.eth_estimate_gas(create2_contract.tx) + tx_712 = create2_contract.tx712(estimate_gas) + signer = PrivateKeyEthSigner(owner_1, zksync.eth.chain_id) 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 = zksync.zksync.send_raw_transaction(msg) + deploy_tx = zksync.zksync.wait_for_transaction_receipt( tx_hash, timeout=240, poll_latency=0.5 ) - return tx_receipt["contractAddress"] + multisig_address = deploy_tx["contractAddress"] + print("Multisig contract address: ", multisig_address) + + hash = wallet.transfer( + TransferTransaction(to=multisig_address, amount=Web3.to_wei(100, "ether")) + ) + zksync.zksync.wait_finalized(hash, timeout=240, poll_latency=0.5) + + hash = wallet.transfer( + TransferTransaction( + to=multisig_address, amount=100, token_address=approval_token_l1 + ) + ) + zksync.zksync.wait_finalized(hash, timeout=240, poll_latency=0.5) + + hash = wallet.transfer( + TransferTransaction( + to=multisig_address, + amount=200, + token_address=wallet.l2_token_address(dai_l1), + ) + ) + zksync.zksync.wait_finalized(hash, timeout=240, poll_latency=0.5) + + if not wallet.is_eth_based_chain(): + wallet.transfer( + TransferTransaction( + to=multisig_address, + amount=Web3.to_wei(100, "ether"), + token_address=LEGACY_ETH_ADDRESS, + ) + ) def load_token(): diff --git a/setup.cfg b/setup.cfg index facbc0b..b1d4b86 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = zksync2 -description = zkSync2 python client sdk +description = ZKsync python client sdk long_description = file: README.md author = Danijel Radakovic url = https://zksync.io diff --git a/tests/contracts/TwoUserMultisig.json b/tests/contracts/TwoUserMultisig.json new file mode 100644 index 0000000..aa6ef07 --- /dev/null +++ b/tests/contracts/TwoUserMultisig.json @@ -0,0 +1,607 @@ +{ + "_format": "hh-zksolc-artifact-1", + "contractName": "TwoUserMultisig", + "sourceName": "contracts/TwoUserMultisig.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_owner1", + "type": "address" + }, + { + "internalType": "address", + "name": "_owner2", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "stateMutability": "nonpayable", + "type": "fallback" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "txType", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "from", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "to", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "gasLimit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "gasPerPubdataByteLimit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxFeePerGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxPriorityFeePerGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "paymaster", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256[4]", + "name": "reserved", + "type": "uint256[4]" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + }, + { + "internalType": "bytes32[]", + "name": "factoryDeps", + "type": "bytes32[]" + }, + { + "internalType": "bytes", + "name": "paymasterInput", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "reservedDynamic", + "type": "bytes" + } + ], + "internalType": "struct Transaction", + "name": "_transaction", + "type": "tuple" + } + ], + "name": "executeTransaction", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "txType", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "from", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "to", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "gasLimit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "gasPerPubdataByteLimit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxFeePerGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxPriorityFeePerGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "paymaster", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256[4]", + "name": "reserved", + "type": "uint256[4]" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + }, + { + "internalType": "bytes32[]", + "name": "factoryDeps", + "type": "bytes32[]" + }, + { + "internalType": "bytes", + "name": "paymasterInput", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "reservedDynamic", + "type": "bytes" + } + ], + "internalType": "struct Transaction", + "name": "_transaction", + "type": "tuple" + } + ], + "name": "executeTransactionFromOutside", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "_hash", + "type": "bytes32" + }, + { + "internalType": "bytes", + "name": "_signature", + "type": "bytes" + } + ], + "name": "isValidSignature", + "outputs": [ + { + "internalType": "bytes4", + "name": "magic", + "type": "bytes4" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner1", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner2", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "txType", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "from", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "to", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "gasLimit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "gasPerPubdataByteLimit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxFeePerGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxPriorityFeePerGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "paymaster", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256[4]", + "name": "reserved", + "type": "uint256[4]" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + }, + { + "internalType": "bytes32[]", + "name": "factoryDeps", + "type": "bytes32[]" + }, + { + "internalType": "bytes", + "name": "paymasterInput", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "reservedDynamic", + "type": "bytes" + } + ], + "internalType": "struct Transaction", + "name": "_transaction", + "type": "tuple" + } + ], + "name": "payForTransaction", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "txType", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "from", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "to", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "gasLimit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "gasPerPubdataByteLimit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxFeePerGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxPriorityFeePerGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "paymaster", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256[4]", + "name": "reserved", + "type": "uint256[4]" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + }, + { + "internalType": "bytes32[]", + "name": "factoryDeps", + "type": "bytes32[]" + }, + { + "internalType": "bytes", + "name": "paymasterInput", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "reservedDynamic", + "type": "bytes" + } + ], + "internalType": "struct Transaction", + "name": "_transaction", + "type": "tuple" + } + ], + "name": "prepareForPaymaster", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "_suggestedSignedHash", + "type": "bytes32" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "txType", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "from", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "to", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "gasLimit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "gasPerPubdataByteLimit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxFeePerGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxPriorityFeePerGas", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "paymaster", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256[4]", + "name": "reserved", + "type": "uint256[4]" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "signature", + "type": "bytes" + }, + { + "internalType": "bytes32[]", + "name": "factoryDeps", + "type": "bytes32[]" + }, + { + "internalType": "bytes", + "name": "paymasterInput", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "reservedDynamic", + "type": "bytes" + } + ], + "internalType": "struct Transaction", + "name": "_transaction", + "type": "tuple" + } + ], + "name": "validateTransaction", + "outputs": [ + { + "internalType": "bytes4", + "name": "magic", + "type": "bytes4" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "bytecode": "0x0004000000000002000e00000000000200000000030100190000006003300270000005d30030019d000005d303300197000300000031035500020000000103550000000102200190000000b20000c13d000000800b0000390000004000b0043f000000040230008c000000e90000413d000000000201043b000000e002200270000005d80420009c000000f70000213d000005de0420009c000001090000213d000005e10420009c000001580000613d000005e20220009c000000eb0000c13d000000040230008a000000600220008c000002c00000413d0000004402100370000000000602043b000005e30260009c000002c00000213d00000004076000390000000002730049000005e403000041000002600420008c00000000040000190000000004034019000005e402200197000000000502004b000000000300a019000005e40220009c000000000304c019000000000203004b000002c00000c13d0000002402100370000000000302043b0000000002000411000080010220008c000001f80000c13d000a00000003001d000900000007001d0000000002000414000005e503000041000000a00030043f000800000006001d0000010403600039000000000131034f000000000101043b000000a40010043f0000002401000039000000800010043f000000e001000039000000400010043f000000c0012002100000060a011001970000060b011001c700008003020000390000000003000019000000000400001900000000050000190000000006000019174717380000040f000300000001035500000000030100190000006003300270000105d30030019d000005d3053001970000003f03500039000005d406300197000000400300043d0000000004360019000000000664004b00000000060000190000000106004039000005e30740009c0000041a0000213d00000001066001900000041a0000c13d000000400040043f00000000045304360000001f065000390000000506600272000000680000613d0000000007000031000000020770036700000000080000190000000509800210000000000a940019000000000997034f000000000909043b00000000009a04350000000108800039000000000968004b000000600000413d000000000600004b0000006a0000613d0000001f0650018f0000000505500272000000760000613d000000000700001900000005087002100000000009840019000000000881034f000000000808043b00000000008904350000000107700039000000000857004b0000006e0000413d000000000706004b000000850000613d0000000505500210000000000151034f00000000055400190000000306600210000000000705043300000000076701cf000000000767022f000000000101043b0000010006600089000000000161022f00000000016101cf000000000171019f00000000001504350000000101200190000002390000613d0000000a01000029000000000201004b0000008c0000c13d0000000901000029174706190000040f000a00000001001d0000000901000029174714420000040f0000000002000410000e00000002001d000700000001001d0000800a01000039000000240300003900000000040004150000000e0440008a00000020044000c9000005e602000041174717200000040f000000070110006b0000000001000019000000010100a039174705620000040f0000000801000029000001e40210003900000009010000291747057a0000040f0000000003000031174704ed0000040f00000000020100190000000a01000029174715670000040f000005ee011001970000060c020000410000060d0110009c000000000200c019000000400100043d0000000000210435000005d302000041000005d30310009c000000000102801900000040011002100000060e011001c7000017480001042e0000000002000416000000000202004b000002c00000c13d0000009f02300039000005d402200197000000400020043f0000001f0230018f0000000504300272000000c40000613d00000000050000190000000506500210000000000761034f000000000707043b000000800660003900000000007604350000000105500039000000000645004b000000bc0000413d000000000502004b000000d30000613d0000000504400210000000000141034f00000003022002100000008004400039000000000504043300000000052501cf000000000525022f000000000101043b0000010002200089000000000121022f00000000012101cf000000000151019f0000000000140435000000400130008c000002c00000413d000000800100043d000005d50210009c000002c00000213d000000a00200043d000005d50320009c000002c00000213d000000000300041a000005d603300197000000000113019f000000000010041b0000000101000039000000000301041a000005d603300197000000000223019f000000000021041b000000200100003900000100001004430000012000000443000005d701000041000017480001042e000000000103004b0000021e0000613d0000000001000416000000000101004b000002c00000c13d0000000001000411000080010110008c0000021e0000c13d000005e70100004100000000001004350000000101000039000000040010043f000005e8010000410000174900010430000005d90420009c000001120000213d000005dc0420009c000001830000613d000005dd0120009c000000eb0000c13d0000000001030019174705280000040f000a00000001001d0000000001000411000080010110008c000000000100001900000001010060391747054a0000040f0000000a01000029174714680000040f0000000001000019000017480001042e000005df0120009c000001cb0000613d000005e00120009c000000eb0000c13d0000000001000416000000000101004b000002c00000c13d000000000100041a000001d00000013d000005da0420009c000001d40000613d000005db0220009c000000eb0000c13d000000040230008a000000200220008c000002c00000413d0000000402100370000000000702043b000005e30270009c000002c00000213d00000004067000390000000002630049000005e403000041000002600420008c00000000040000190000000004034019000005e402200197000000000502004b000000000300a019000005e40220009c000000000304c019000000000203004b000002c00000c13d0000000002000414000005e503000041000000a00030043f0000010403700039000000000131034f000000000101043b000000a40010043f0000002401000039000700000001001d000000800010043f000000e001000039000000400010043f000005d3012001970000008002000039000a00000006001d000800000007001d174705a40000040f0000000a01000029174706190000040f000900000001001d0000000a01000029174714420000040f0000000002000410000b00000002001d000600000001001d0000800a0100003900000000040004150000000b0440008a00000020044000c9000005e6020000410000000703000029174717200000040f000000060110006b0000000001000019000000010100a039174705620000040f0000000801000029000001e4021000390000000a010000291747057a0000040f0000000003000031174704ed0000040f00000000020100190000000901000029174715670000040f000001050000013d0000000002000416000000000202004b000002c00000c13d000000040230008a000000400220008c000002c00000413d0000002402100370000000000402043b000005e30240009c000002c00000213d0000002302400039000005e405000041000000000632004b00000000060000190000000006058019000005e402200197000000000702004b0000000005008019000005e40220009c000000000506c019000000000205004b000002c00000c13d0000000402400039000000000121034f000000000201043b0000002401400039174704ed0000040f00000004020000390000000202200367000000000202043b000000000301001900000000010200190000000002030019174715670000040f000005ee01100197000000400200043d0000000000120435000005d301000041000005d30320009c000000000201801900000040012002100000060e011001c7000017480001042e000000040230008a000000600220008c000002c00000413d0000004402100370000000000202043b000005e30420009c000002c00000213d00000004042000390000000005430049000005e406000041000002600750008c00000000070000190000000007064019000005e408500197000000000908004b000000000600a019000005e40880009c000000000607c019000000000606004b000002c00000c13d0000000006000411000080010660008c000001f80000c13d0000022402200039000000000621034f000000000606043b0000001f0550008a000005e407000041000000000856004b00000000080000190000000008078019000005e405500197000005e409600197000000000a59004b0000000007008019000000000559013f000005e40550009c000000000708c019000000000507004b000002c00000c13d0000000005460019000000000451034f000000000404043b000005e30640009c000002c00000213d00000000064300490000002005500039000005e407000041000000000865004b00000000080000190000000008072019000005e406600197000005e409500197000000000a69004b0000000007008019000000000669013f000005e40660009c000000000708c019000000000607004b000002c00000c13d000000030640008c000002500000213d000005ec01000041000000800010043f0000002001000039000000840010043f0000003a01000039000000a40010043f0000060501000041000000c40010043f0000060601000041000002010000013d0000000001000416000000000101004b000002c00000c13d0000000101000039000000000101041a000005d501100197000000800010043f0000060701000041000017480001042e000000040330008a000000600230008c000002c00000413d0000004402100370000000000202043b000005e30420009c000002c00000213d0000000003230049000005e404000041000002600530008c00000000050000190000000005044019000005e403300197000000000603004b000000000400a019000005e40330009c000000000405c019000000000304004b000002c00000c13d0000000003000411000080010330008c000001f80000c13d000000a403200039000000000331034f0000006402200039000000000121034f000000000101043b000000000203043b000000000302004b000002040000c13d00000000040004150000000d0440008a00000020044000c90000000001000414000d00000000001d0000020f0000013d000005ec01000041000000800010043f0000002001000039000000840010043f0000002401000039000000a40010043f0000060801000041000000c40010043f0000060901000041000000e40010043f0000060201000041000017490001043000000000431200a900000000422300d9000000000112004b000002350000c13d00000000040004150000000c0440008a00000020044000c90000000001000414000c00000000001d000000000203004b000002430000c13d000a00000004001d000005d302000041000005d30310009c0000000001028019000000c0011002100000800102000039174717380000040f0000000a0300002900030000000103550000006001100270000105d30010019d000000050130027000000001012001950000000101200190000002200000613d0000000001000019000017480001042e000000400100043d0000006402100039000005ea0300004100000000003204350000004402100039000005eb030000410000000000320435000000240210003900000025030000390000000000320435000005ec020000410000000000210435000000040210003900000020030000390000000000320435000005d302000041000005d30310009c00000000010280190000004001100210000005ed011001c70000174900010430000005e70100004100000000001004350000001101000039000000f40000013d0000000001030433000005d302000041000005d30310009c0000000001028019000005d30340009c000000000402801900000040024002100000006001100210000000000121019f0000174900010430000005d302000041000005d30410009c0000000001028019000000c001100210000005e9011001c7000080090200003900008001040000390000000005000019174717380000040f00000000030004150000000c0330008a00000020033000c9000002170000013d000a0000000b001d000000000651034f000000000606043b000005ee06600197000005ef0760009c000002620000613d000005f00160009c0000021e0000613d000005ec01000041000000800010043f0000002001000039000000840010043f0000001a01000039000000a40010043f0000060301000041000000c40010043f00000604010000410000174900010430000000430440008c0000026e0000213d000005ec01000041000000800010043f0000002001000039000000840010043f0000004001000039000000a40010043f0000060001000041000000c40010043f0000060101000041000002010000013d0000000404500039000000000541034f000000000505043b000900000005001d000005d50550009c000002c00000213d000001400220008a000000000221034f0000002004400039000000000441034f000000000404043b000800000004001d000000000202043b000005f104000041000000800040043f0000000004000410000005d504400197000600000004001d000000840040043f000005d502200197000700000002001d000000a40020043f00000000020004140000000904000029000000040440008c0000028e0000c13d000000000131034f0000000103000031000000200230008c00000000040300190000002004008039000002ba0000013d000005d301000041000005d30320009c0000000002018019000000c001200210000005f2011001c700000009020000291747173d0000040f00000000030100190000006003300270000005d303300197000000200430008c000000000403001900000020040080390000001f0540018f0000000506400272000002a70000613d00000000070000190000000508700210000000000981034f000000000909043b000000800880003900000000009804350000000107700039000000000867004b0000029f0000413d000000000705004b000002b60000613d0000000506600210000000000761034f00000003055002100000008006600039000000000806043300000000085801cf000000000858022f000000000707043b0000010005500089000000000757022f00000000055701cf000000000585019f0000000000560435000100000003001f00030000000103550000000102200190000002e40000613d0000001f02400039000000600520018f00000080025001bf000000400020043f000000200430008c000002c20000813d00000000010000190000174900010430000000800400043d000000080440006c0000021e0000813d000000a004500039000005f3060000410000000000640435000000a40650003900000007070000290000000000760435000000c40650003900000000000604350000004406000039000100000006001d00000000006204350000014006500039000000400060043f0000012007500039000005f406000041000300000007001d000000000067043500000100065001bf0000002005000039000400000005001d000200000006001d0000000000560435000000000502043300000000020004140000000906000029000000040660008c000003070000c13d0000000102000039000005e30430009c0000041a0000213d0000031b0000013d000000400200043d0000001f0430018f0000000505300272000002f10000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000002e90000413d000000000604004b000003000000613d0000000505500210000000000151034f00000000055200190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f0000000000150435000005d301000041000005d30420009c000000000201801900000040012002100000006002300210000000000121019f0000174900010430000005d301000041000005d30350009c000000000501801900000060035002100000004004400210000000000343019f000005d30420009c0000000002018019000000c001200210000000000113019f0000000902000029174717380000040f000500600000003d000000010220018f000300000001035500000000030100190000006003300270000105d30030019d000005d303300198000003470000613d0000003f04300039000000200500008a000000000454016f000000400500043d0000000004450019000500000005001d000000000554004b00000000050000190000000105004039000005e30640009c0000041a0000213d00000001055001900000041a0000c13d000000400040043f0000001f0430018f000000050500002900000000083504360000000503300272000003370000613d000000000500001900000005065002100000000007680019000000000661034f000000000606043b00000000006704350000000105500039000000000635004b0000032f0000413d000a00000008001d000000000504004b000003470000613d0000000503300210000000000131034f0000000a033000290000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f000000000013043500000005010000290000000001010433000000000202004b000003660000c13d000000000201004b000003610000c13d000000400400043d000a00000004001d000005ec01000041000000000014043500000004014000390000000402000029000000000021043500000002010000290000000003010433000900000003001d0000002401400039000000000031043500000044024000390000000301000029174714350000040f00000009010000290000001f01100039000000200200008a000000000121016f0000004401100039000005d302000041000005d30310009c00000000010280190000000a040000290000023d0000013d000000000201004b0000038f0000c13d000005f501000041000000000010043900000009010000290000000400100443000005d3010000410000000002000414000005d30320009c0000000002018019000000c001200210000005f6011001c700008002020000391747173d0000040f0000000102200190000004e70000613d000000000101043b000000000101004b0000038b0000c13d000000400100043d0000004402100039000005fe03000041000000000032043500000024021000390000001d030000390000000000320435000005ec020000410000000000210435000000040210003900000004030000290000000000320435000005d302000041000005d30310009c00000000010280190000004001100210000005ff011001c7000017490001043000000005010000290000000001010433000000000201004b000003b20000613d000005e402000041000000200310008c00000000030000190000000003024019000005e401100197000000000401004b000000000200a019000005e40110009c000000000203c019000000000102004b0000000a01000029000002c00000c13d0000000001010433000000000201004b0000000002000019000000010200c039000000000221004b000002c00000c13d000000000101004b000003b20000c13d000000400100043d0000006402100039000005fc0300004100000000003204350000004402100039000005fd03000041000000000032043500000024021000390000002a030000390000000000320435000005ec020000410000000000210435000000040210003900000004030000290000022e0000013d000000400300043d000000240130003900000007020000290000000000210435000005f1010000410000000000130435000a00000003001d00000004013000390000000602000029000000000021043500000000010004140000000902000029000000040220008c000003c50000c13d0000000103000031000000200130008c00000000040300190000002004008039000003f70000013d000005d302000041000005d30310009c00000000010280190000000a04000029000005d30340009c00000000020440190000004002200210000000c001100210000000000121019f000005f7011001c700000009020000291747173d0000040f0000000a0a00002900000000030100190000006003300270000005d303300197000000200430008c000000000403001900000020040080390000001f0540018f0000000506400272000003e40000613d0000000007000019000000050870021000000000098a0019000000000881034f000000000808043b00000000008904350000000107700039000000000867004b000003dc0000413d000000000705004b000003f30000613d0000000506600210000000000761034f0000000a066000290000000305500210000000000806043300000000085801cf000000000858022f000000000707043b0000010005500089000000000757022f00000000055701cf000000000585019f0000000000560435000100000003001f000300000001035500000001022001900000041e0000613d0000001f01400039000000600210018f0000000a01200029000000000221004b00000000020000190000000102004039000005e30410009c0000041a0000213d00000001022001900000041a0000c13d000000400010043f000000200230008c000002c00000413d000000440410003900000024051000390000000a020000290000000002020433000000000202004b0000043b0000c13d0000002002100039000005f3060000410000000000620435000000070600002900000000006504350000000805000029000000000054043500000001040000290000000000410435000005fa0410009c0000041a0000213d0000008004100039000a00000004001d000000400040043f000005fb0410009c000004470000a13d000005e70100004100000000001004350000004101000039000000f40000013d000000400200043d0000001f0430018f00000005053002720000042b0000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000004230000413d000000000604004b0000043a0000613d0000000505500210000000000151034f00000000055200190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f0000000000150435000003000000013d000005ec02000041000000000021043500000004021000390000000403000029000000000032043500000036020000390000000000250435000005f80200004100000000002404350000006402100039000005f9030000410000022e0000013d000000c004100039000000400040043f00000004040000290000000a050000290000000000450435000000a005100039000005f404000041000700000005001d0000000000450435000000000401043300000000010004140000000905000029000000040550008c000004590000c13d0000000102000039000005e30130009c0000041a0000213d0000046f0000013d000005d303000041000005d30520009c00000000020380190000004002200210000005d30540009c00000000040380190000006004400210000000000224019f000005d30410009c0000000001038019000000c001100210000000000112019f0000000902000029174717380000040f000800600000003d000600800000003d000000010220018f00030000000103550000006001100270000105d30010019d000005d3031001980000049c0000613d0000003f01300039000000200400008a000000000141016f000000400400043d0000000001140019000800000004001d000000000441004b00000000040000190000000104004039000005e30510009c0000041a0000213d00000001044001900000041a0000c13d000000400010043f0000001f0130018f00000008040000290000000008340436000000030400036700000005033002720000048c0000613d000000000500001900000005065002100000000007680019000000000664034f000000000606043b00000000006704350000000105500039000000000635004b000004840000413d000600000008001d000000000501004b0000049c0000613d0000000503300210000000000434034f00000006033000290000000301100210000000000503043300000000051501cf000000000515022f000000000404043b0000010001100089000000000414022f00000000011401cf000000000151019f000000000013043500000008010000290000000001010433000000000202004b000004bb0000c13d000000000201004b000004e80000c13d000000400400043d000900000004001d000005ec0100004100000000001404350000000401400039000000040200002900000000002104350000000a010000290000000003010433000a00000003001d0000002401400039000000000031043500000044024000390000000701000029174714350000040f0000000a010000290000001f01100039000000200200008a000000000121016f0000004401100039000005d302000041000005d30310009c000000000102801900000009040000290000023d0000013d000000000201004b000004d20000c13d000005f501000041000000000010043900000009010000290000000400100443000005d3010000410000000002000414000005d30320009c0000000002018019000000c001200210000005f6011001c700008002020000391747173d0000040f0000000102200190000004e70000613d000000000101043b000000000101004b000003790000613d00000008010000290000000001010433000000000201004b0000021e0000613d000005e402000041000000200310008c00000000030000190000000003024019000005e401100197000000000401004b000000000200a019000005e40110009c000000000203c019000000000102004b000002c00000c13d00000006010000290000000001010433000000000201004b0000000002000019000000010200c039000000000221004b000002c00000c13d000000000101004b0000021e0000c13d000003a30000013d000000000001042f000005d302000041000005d30310009c000000000102801900000006040000290000023d0000013d00000000040100190000060f0120009c000005200000813d0000003f01200039000000200500008a000000000551016f000000400100043d0000000005510019000000000615004b00000000060000190000000106004039000005e30750009c000005200000213d0000000106600190000005200000c13d000000400050043f00000000052104360000000006420019000000000336004b000005260000213d0000001f0320018f000000020440036700000005062002720000050e0000613d000000000700001900000005087002100000000009850019000000000884034f000000000808043b00000000008904350000000107700039000000000867004b000005060000413d000000000703004b0000051d0000613d0000000506600210000000000464034f00000000066500190000000303300210000000000706043300000000073701cf000000000737022f000000000404043b0000010003300089000000000434022f00000000033401cf000000000373019f000000000036043500000000022500190000000000020435000000000001042d000005e70100004100000000001004350000004101000039000000040010043f000005e801000041000017490001043000000000010000190000174900010430000000040210008a000005e4030000410000005f0420008c00000000040000190000000004032019000005e402200197000000000502004b0000000003008019000005e40220009c000000000304c019000000000203004b000005480000613d00000044020000390000000202200367000000000202043b000005e30320009c000005480000213d00000004022000390000000001210049000005e403000041000002600410008c00000000040000190000000004034019000005e401100197000000000501004b000000000300a019000005e40110009c000000000304c019000000000103004b000005480000c13d0000000001020019000000000001042d00000000010000190000174900010430000000000101004b0000054d0000613d000000000001042d000000400100043d000000640210003900000609030000410000000000320435000000440210003900000608030000410000000000320435000000240210003900000024030000390000000000320435000005ec020000410000000000210435000000040210003900000020030000390000000000320435000005d302000041000005d30310009c00000000010280190000004001100210000005ed011001c70000174900010430000000000101004b000005650000613d000000000001042d000000400100043d000000640210003900000610030000410000000000320435000000440210003900000611030000410000000000320435000000240210003900000022030000390000000000320435000005ec020000410000000000210435000000040210003900000020030000390000000000320435000005d302000041000005d30310009c00000000010280190000004001100210000005ed011001c70000174900010430000000000300003100000000041300490000001f0540008a0000000204000367000000000224034f000000000202043b000005e406000041000000000752004b00000000070000190000000007064019000005e405500197000005e408200197000000000958004b000000000600a019000000000558013f000005e40550009c000000000607c019000000000506004b000005a20000613d0000000001120019000000000214034f000000000202043b000005e30420009c000005a20000213d00000000032300490000002001100039000005e404000041000000000531004b00000000050000190000000005042019000005e403300197000005e406100197000000000736004b0000000004008019000000000336013f000005e40330009c000000000405c019000000000304004b000005a20000c13d000000000001042d000000000100001900001749000104300000000003020433000006120430009c000005f70000813d000000c0011002100000060a01100197000000400220021000000613022000410000061402200197000000000121019f00000060023002100000061502200197000000000121019f00000616011001c700008003020000390000000003000019000000000400001900000000050000190000000006000019174717380000040f000300000001035500000000030100190000006003300270000105d30030019d000005d3053001970000003f03500039000005d406300197000000400300043d0000000004360019000000000664004b00000000060000190000000106004039000005e30740009c000006090000213d0000000106600190000006090000c13d000000400040043f00000000045304360000001f065000390000000506600272000005d70000613d0000000007000031000000020770036700000000080000190000000509800210000000000a940019000000000997034f000000000909043b00000000009a04350000000108800039000000000968004b000005cf0000413d000000000600004b000005d90000613d0000001f0650018f0000000505500272000005e50000613d000000000700001900000005087002100000000009840019000000000881034f000000000808043b00000000008904350000000107700039000000000857004b000005dd0000413d000000000706004b000005f40000613d0000000505500210000000000151034f00000000055400190000000306600210000000000705043300000000076701cf000000000767022f000000000101043b0000010006600089000000000161022f00000000016101cf000000000171019f000000000015043500000001012001900000060f0000613d000000000001042d000000400100043d000000440210003900000617030000410000000000320435000000240210003900000008030000390000000000320435000005ec020000410000000000210435000000040210003900000020030000390000000000320435000005d302000041000005d30310009c00000000010280190000004001100210000005ff011001c70000174900010430000005e70100004100000000001004350000004101000039000000040010043f000005e80100004100001749000104300000000001030433000005d302000041000005d30310009c0000000001028019000005d30340009c000000000402801900000040024002100000006001100210000000000121019f00001749000104300007000000000002000000020d00036700000000021d034f000000000202043b000000010320008c000700000001001d0000067e0000213d000000000302004b000008900000613d000000010120008c000013ed0000c13d00000618010000410000000000100439000005d3010000410000000002000414000005d30320009c0000000002018019000000c00120021000000619011001c70000800b020000391747173d0000040f0000000102200190000013da0000613d000000400400043d000000000101043b000000800210008c0000099c0000413d00000080021002700000061c0310009c000000000201a0190000061c0310009c0000000003000019000000100300203900000008053001bf000005e30620009c000000000503a0190000004003200270000005e30620009c000000000302a01900000004025001bf000005d30630009c000000000205a0190000002006300270000005d30530009c000000000603a01900000002052001bf0000ffff0360008c000000000502a0190000001002600270000000000206a019000000ff0220008c0000000105502039000000200200008a0000004103500039000000000223016f0000000002240019000000000342004b00000000030000190000000103004039000005e30620009c000000070f000029000013ce0000213d0000000103300190000013ce0000c13d000000400020043f0000000202500039000000000624043600000002020003670000000003000031000000210750003900000005077002720000066b0000613d000000000832034f0000000009000019000000050a900210000000000ba60019000000000aa8034f000000000a0a043b0000000000ab04350000000109900039000000000a79004b000006630000413d000600000003001d000000000300004b0000066e0000613d0000000007040433000000000707004b000013d40000613d00000000070604330000061b07700197000000f808500210000000000778019f0000061d0770004100000000007604350000000305500210000000f80550008900000000015101cf000000ff0550008c00000000010020190000002105400039000009b00000013d000000020320008c000008e10000613d000000710220008c000013ed0000c13d000001c00210003900000000032d034f000000000200003100000000041200490000001f0440008a000000000303043b000005e405000041000000000643004b00000000060000190000000006058019000005e404400197000005e407300197000000000847004b0000000005008019000000000447013f000005e40440009c000000000506c019000000000405004b000013d20000c13d000000000313001900000000043d034f000000000504043b000005e30450009c000013d20000213d00000000045200490000002003300039000005e406000041000000000743004b00000000070000190000000007062019000005e404400197000005e408300197000000000948004b0000000006008019000000000448013f000005e40440009c000000000607c019000000000406004b000013d20000c13d0000000004000414000000000605004b000006b70000613d0000000006350019000000000556004b000000000500001900000001050040390000000105500190000013e90000c13d000000000562004b000013e90000413d0000000002620049000005d303300197000000000d3d034f000006120340009c000013db0000813d000005d30220019700000000012d03df000000c0024002100000060a0220019700000622022001c700000000012103af0000801002000039174717420000040f00000000030100190000006003300270000105d30030019d000005d30530019700030000000103550000000102200190000013ff0000613d0000003f02500039000005d402200197000000400600043d0000000002260019000000000362004b00000000030000190000000103004039000005e30420009c000000070c000029000013ce0000213d0000000103300190000013ce0000c13d000000400020043f0000000004560436000000020200036700000000030000310000001f075000390000000507700272000006e50000613d000000000832034f0000000009000019000000050a900210000000000ba40019000000000aa8034f000000000a0a043b0000000000ab04350000000109900039000000000a79004b000006dd0000413d000000000700004b000006e70000613d0000001f0750018f0000000505500272000006f30000613d00000000080000190000000509800210000000000a940019000000000991034f000000000909043b00000000009a04350000000108800039000000000958004b000006eb0000413d000000000807004b000007020000613d0000000505500210000000000151034f00000000055400190000000307700210000000000805043300000000087801cf000000000878022f000000000101043b0000010007700089000000000171022f00000000017101cf000000000181019f00000000001504350000000001060433000000200110008c000013e20000c13d0000000001c300490000001f0510008a000002000ac000390000000001a2034f000000000101043b000005e406000041000000000751004b00000000070000190000000007068019000005e405500197000005e408100197000000000958004b0000000006008019000000000558013f000005e40550009c000000000607c019000000000506004b000013d20000c13d0000000004040433000500000004001d0000000001c10019000000000412034f000000000504043b000005e30450009c000013d20000213d000000050450021000000000034300490000002006100039000005e401000041000000000736004b00000000070000190000000007012019000005e403300197000005e408600197000000000938004b0000000001008019000000000338013f000005e40330009c000000000107c019000000000101004b000013d20000c13d000000400100043d000000200310003900000623055001980000073c0000613d000000000262034f000000000600001900000005076002100000000008730019000000000772034f000000000707043b00000000007804350000000106600039000000000756004b000007340000413d00060000000a001d000000000200004b0000073f0000613d00000000004104350000003f02400039000000200400008a000000000242016f0000000002210019000000000412004b00000000040000190000000104004039000005e30520009c000013ce0000213d0000000104400190000013ce0000c13d000000400020043f000005d302000041000005d30430009c000000000302801900000040033002100000000001010433000005d30410009c00000000010280190000006001100210000000000131019f0000000003000414000005d30430009c0000000003028019000000c002300210000000000112019f000005e9011001c700008010020000391747173d0000040f000000070a00002900000001022001900000000604000029000013d20000613d00000000020000310000000003a200490000001f0530008a00000020044000390000000203000367000000000443034f000000000404043b000005e406000041000000000754004b00000000070000190000000007068019000005e405500197000005e408400197000000000958004b0000000006008019000000000558013f000005e40550009c000000000607c019000000000b01043b000000000106004b000013d20000c13d0000000001a40019000000000413034f000000000504043b000005e30450009c000013d20000213d00000000045200490000002001100039000005e406000041000000000741004b00000000070000190000000007062019000005e404400197000005e408100197000000000948004b0000000006008019000000000448013f000005e40440009c000000000607c019000000000406004b000013d20000c13d0000000004000414000000000605004b000007980000613d0000000006150019000000000556004b000000000500001900000001050040390000000105500190000013e90000c13d000000000562004b000013e90000413d0000000002620049000005d301100197000000000313034f00060000000b001d000005d30140009c000013db0000213d000005d30120019700000000011303df000000c0024002100000060a0220019700000622022001c700000000012103af0000801002000039174717420000040f00000000030100190000006003300270000105d30030019d000005d304300197000300000001035500000001022001900000141a0000613d0000003f02400039000005d402200197000000400500043d0000000002250019000000000352004b00000000030000190000000103004039000005e30620009c000000070c000029000013ce0000213d0000000103300190000013ce0000c13d000000400020043f000000000245043600000002030003670000001f064000390000000506600272000007c60000613d000000000730036800000000080000190000000509800210000000000a920019000000000997034f000000000909043b00000000009a04350000000108800039000000000968004b000007be0000413d000000000600004b000007c80000613d0000001f0640018f0000000504400272000007d40000613d000000000700001900000005087002100000000009820019000000000881034f000000000808043b00000000008904350000000107700039000000000847004b000007cc0000413d000000000706004b000007e30000613d0000000504400210000000000141034f00000000044200190000000306600210000000000704043300000000076701cf000000000767022f000000000101043b0000010006600089000000000161022f00000000016101cf000000000171019f00000000001404350000000001050433000000200110008c000013e20000c13d0000006001c00039000000000113034f0000004004c00039000000000543034f0000002004c00039000000000443034f0000012006c00039000000000663034f0000010007c00039000000000773034f000000e008c00039000000000883034f000000c009c00039000000000993034f000000a00ac00039000000000aa3034f000000800bc00039000000000bb3034f0000000003c3034f000000000303043b000000000404043b000000000505043b000000000c01043b000000000b0b043b000000000a0a043b000000000909043b000000000808043b000000000707043b000000000606043b0000000002020433000000400100043d000001c00d10003900000000002d0435000001a002100039000000060d0000290000000000d204350000018002100039000000050d0000290000000000d2043500000160021000390000000000620435000001400210003900000000007204350000012002100039000000000082043500000100021000390000000000920435000000e0021000390000000000a20435000000c0021000390000000000b20435000000a0021000390000000000c20435000000800210003900000000005204350000006002100039000000000042043500000040021000390000000000320435000000200210003900000625030000410000000000320435000001c0030000390000000000310435000006260310009c000013ce0000213d000001e003100039000000400030043f000005d304000041000005d30320009c000000000204801900000040022002100000000001010433000005d30310009c00000000010480190000006001100210000000000121019f0000000002000414000005d30320009c0000000002048019000000c002200210000000000112019f000005e9011001c700008010020000391747173d0000040f0000000102200190000013d20000613d000000000101043b000600000001001d000000400100043d000700000001001d000006180100004100000000001004390000000001000414000005d30210009c000005d301008041000000c00110021000000619011001c70000800b020000391747173d0000040f0000000102200190000013da0000613d00000007040000290000002002400039000000000101043b0000062703000041000000000032043500000080034000390000000000130435000000600140003900000628030000410000000000310435000000400140003900000629030000410000000000310435000000800100003900000000001404350000062a0140009c000013ce0000213d000000a001400039000000400010043f000005d301000041000005d30320009c000000000201801900000040022002100000000003040433000005d30430009c00000000030180190000006003300210000000000223019f0000000003000414000005d30430009c0000000003018019000000c001300210000000000121019f000005e9011001c700008010020000391747173d0000040f0000000102200190000013d20000613d000000000301043b000000400100043d00000042021000390000000604000029000000000042043500000020021000390000062b0400004100000000004204350000002204100039000000000034043500000042030000390000000000310435000005fa0310009c000013ce0000213d0000008003100039000000400030043f000005d303000041000005d30420009c000000000203801900000040022002100000000001010433000005d30410009c00000000010380190000006001100210000000000121019f0000000002000414000005d30420009c0000000002038019000000c002200210000013c60000013d000000400200043d000600000002001d000001000410003900000000024d034f000000000302043b000000800230008c0000093b0000413d00000080023002700000061c0530009c000000000203a0190000061c0530009c0000000005000019000000100500203900000008065001bf000005e30720009c000000000605a0190000004005200270000005e30720009c000000000502a01900000004026001bf000005d30750009c000000000206a0190000002006500270000005d30750009c000000000605a01900000002052001bf0000ffff0760008c000000000502a0190000001002600270000000000206a019000000ff0220008c0000000105502039000000200200008a0000004106500039000000000226016f0000000602200029000000060620006c00000000060000190000000106004039000005e30720009c000013ce0000213d0000000106600190000013ce0000c13d000000400020043f000000020250003900000006060000290000000006260436000000000e00003100000021075000390000000507700272000008cd0000613d0000000008ed034f0000000009000019000000050a900210000000000ba60019000000000aa8034f000000000a0a043b0000000000ab04350000000109900039000000000a79004b000008c50000413d000000000700004b000008cf0000613d00000006020000290000000007020433000000000707004b000013d40000613d00000000070604330000061b07700197000000f808500210000000000778019f0000061d0770004100000000007604350000000305500210000000f80550008900000000035301cf000000ff0550008c0000000003002019000000060200002900000021052000390000094f0000013d00000618010000410000000000100439000005d3010000410000000002000414000005d30320009c0000000002018019000000c00120021000000619011001c70000800b020000391747173d0000040f0000000102200190000013da0000613d000000400400043d000000000101043b000000800210008c000009fd0000413d00000080021002700000061c0310009c000000000201a0190000061c0310009c0000000003000019000000100300203900000008053001bf000005e30620009c000000000503a0190000004003200270000005e30620009c000000000302a01900000004025001bf000005d30630009c000000000205a0190000002006300270000005d30530009c000000000603a01900000002052001bf0000ffff0360008c000000000502a0190000001002600270000000000206a019000000ff0220008c0000000105502039000000200200008a0000004103500039000000000223016f0000000002240019000000000342004b00000000030000190000000103004039000005e30620009c000000070f000029000013ce0000213d0000000103300190000013ce0000c13d000000400020043f00000002025000390000000006240436000600020000036b000000000300003100000021075000390000000507700272000009280000613d000000060830035f0000000009000019000000050a900210000000000ba60019000000000aa8034f000000000a0a043b0000000000ab04350000000109900039000000000a79004b000009200000413d000500000003001d000000000200004b0000092b0000613d0000000007040433000000000707004b000013d40000613d00000000070604330000061b07700197000000f808500210000000000778019f0000061d0770004100000000007604350000000305500210000000f80550008900000000015101cf000000ff0550008c0000000001002019000000210540003900000a120000013d00000006020000290000061a0220009c000013ce0000213d00000006050000290000004002500039000000400020043f000000010200003a0000000005250436000000000e0000310000000006ed034f0000000006600350000000000606043b0000000000650435000013d40000613d000000f807300210000005e408000041000000000303004b000000000807c0190000061b03600197000000000383019f0000000000350435000000400300043d000000600440008a00000000054d034f000000000505043b000000800650008c00000a600000413d00000080065002700000061c0750009c000000000605a0190000061c0750009c0000000007000019000000100700203900000008087001bf000005e30960009c000000000807a0190000004007600270000005e30960009c000000000706a01900000004098001bf000005d30670009c000000000908a0190000002008700270000005d30670009c000000000807a01900000002069001bf0000ffff0780008c000000000609a0190000001007800270000000000708a019000000ff0770008c0000000106602039000000200700008a0000004108600039000000000778016f0000000007730019000000000837004b00000000080000190000000108004039000005e30970009c000013ce0000213d0000000108800190000013ce0000c13d000000400070043f00000002076000390000000007730436000000210860003900000005088002720000098a0000613d0000000009ed034f000000000a000019000000050ba00210000000000cb70019000000000bb9034f000000000b0b043b0000000000bc0435000000010aa00039000000000b8a004b000009820000413d000000000800004b0000098c0000613d0000000008030433000000000808004b000013d40000613d00000000080704330000061b08800197000000f809600210000000000889019f0000061d0880004100000000008704350000000306600210000000f80660008900000000056501cf000000ff0660008c0000000005002019000000210630003900000a710000013d0000061a0240009c000000070f000029000013ce0000213d0000004002400039000000400020043f000000010200003a00000000052404360000000202000367000600000000003500000000062003680000000006600350000000000606043b0000000000650435000013d40000613d000000f807100210000005e408000041000000000101004b000000000807c0190000061b01600197000000000181019f0000000000150435000000400500043d0000010007f00039000000000172034f000000000601043b000000800160008c000000060120036000000abe0000413d00000080086002700000061c0960009c000000000806a0190000061c0960009c00000000090000190000001009002039000000080a9001bf000005e30b80009c000000000a09a0190000004009800270000005e30b80009c000000000908a019000000040ba001bf000005d30890009c000000000b0aa019000000200a900270000005d30890009c000000000a09a0190000000208b001bf0000ffff09a0008c00000000080ba0190000001009a0027000000000090aa019000000ff0990008c0000000108802039000000200900008a000000410a80003900000000099a016f0000000009950019000000000a59004b000000000a000019000000010a004039000005e30b90009c000013ce0000213d000000010aa00190000013ce0000c13d000000400090043f00000002098000390000000009950436000000210a800039000000050aa00272000009eb0000613d000000000b000019000000050cb00210000000000dc90019000000000cc1034f000000000c0c043b0000000000cd0435000000010bb00039000000000cab004b000009e30000413d000000000300004b000009ed0000613d000000000a050433000000000a0a004b000013d40000613d000000000a0904330000061b0aa00197000000f80b800210000000000aab019f0000061d0aa000410000000000a904350000000308800210000000f80880008900000000068601cf000000ff0880008c0000000006002019000000210850003900000ace0000013d0000061a0240009c000000070f000029000013ce0000213d0000004002400039000000400020043f000000010200003a000000000524043600000002020003670006000000020353000500000000003500000000062003680000000006600350000000000606043b0000000000650435000013d40000613d000000f807100210000005e408000041000000000101004b000000000807c0190000061b01600197000000000181019f0000000000150435000000400500043d0000010007f00039000000060170035f000000000601043b000000800160008c0000000501000029000000060110035f00000b1a0000413d00000080086002700000061c0960009c000000000806a0190000061c0960009c00000000090000190000001009002039000000080a9001bf000005e30b80009c000000000a09a0190000004009800270000005e30b80009c000000000908a019000000040ba001bf000005d30890009c000000000b0aa019000000200a900270000005d30890009c000000000a09a0190000000208b001bf0000ffff09a0008c00000000080ba0190000001009a0027000000000090aa019000000ff0990008c0000000108802039000000200900008a000000410a80003900000000099a016f0000000009950019000000000a59004b000000000a000019000000010a004039000005e30b90009c000013ce0000213d000000010aa00190000013ce0000c13d000000400090043f00000002098000390000000009950436000000210a800039000000050aa0027200000a4e0000613d000000000b000019000000050cb00210000000000dc90019000000000cc1034f000000000c0c043b0000000000cd0435000000010bb00039000000000cab004b00000a460000413d000000000200004b00000a500000613d000000000a050433000000000a0a004b000013d40000613d000000000a0904330000061b0aa00197000000f80b800210000000000aab019f0000061d0aa000410000000000a904350000000308800210000000f80880008900000000068601cf000000ff0880008c0000000006002019000000210850003900000b2a0000013d0000061a0630009c000013ce0000213d0000004006300039000000400060043f0000000007ed034f000000010600003a00000000066304360000000007700350000000000707043b0000000000760435000013d40000613d000000f808500210000005e409000041000000000505004b000000000908c0190000061b05700197000000000595019f0000000000560435000000400440008a00000000054d034f000000400400043d000000000505043b000000800650008c00000b760000413d00000080065002700000061c0750009c000000000605a0190000061c0750009c0000000007000019000000100700203900000008087001bf000005e30960009c000000000807a0190000004007600270000005e30960009c000000000706a01900000004098001bf000005d30670009c000000000908a0190000002008700270000005d30670009c000000000807a01900000002069001bf0000ffff0780008c000000000609a0190000001007800270000000000708a019000000ff0770008c0000000106602039000000200700008a0000004108600039000000000778016f0000000007740019000000000847004b00000000080000190000000108004039000005e30970009c000013ce0000213d0000000108800190000013ce0000c13d000000400070043f000000020760003900000000077404360000002108600039000000050880027200000aac0000613d0000000009ed034f000000000a000019000000050ba00210000000000cb70019000000000bb9034f000000000b0b043b0000000000bc0435000000010aa00039000000000b8a004b00000aa40000413d000000000800004b00000aae0000613d0000000008040433000000000808004b000013d40000613d00000000080704330000061b08800197000000f809600210000000000889019f0000061d0880004100000000008704350000000306600210000000f80660008900000000056501cf000000ff0660008c0000000005002019000000210640003900000b870000013d0000061a0850009c000013ce0000213d0000004008500039000000400080043f000000010800003a00000000088504360000000009100350000000000909043b0000000000980435000013d40000613d000000f80a600210000005e40b000041000000000606004b000000000b0ac0190000061b069001970000000006b6019f0000000000680435000000400600043d000000600770008a000000000872034f000000000808043b000000800980008c00000c150000413d00000080098002700000061c0a80009c000000000908a0190000061c0a80009c000000000a000019000000100a002039000000080ba001bf000005e30c90009c000000000b0aa019000000400a900270000005e30c90009c000000000a09a019000000040cb001bf000005d309a0009c000000000c0ba019000000200ba00270000005d309a0009c000000000b0aa0190000000209c001bf0000ffff0ab0008c00000000090ca019000000100ab00270000000000a0ba019000000ff0aa0008c0000000109902039000000200a00008a000000410b900039000000000aab016f000000000aa60019000000000b6a004b000000000b000019000000010b004039000005e30ca0009c000013ce0000213d000000010bb00190000013ce0000c13d0000004000a0043f000000020a900039000000000aa60436000000210b900039000000050bb0027200000b080000613d000000000c000019000000050dc00210000000000eda0019000000000dd1034f000000000d0d043b0000000000de0435000000010cc00039000000000dbc004b00000b000000413d000000000300004b00000b0a0000613d000000000b060433000000000b0b004b000013d40000613d000000000b0a04330000061b0bb00197000000f80c900210000000000bbc019f0000061d0bb000410000000000ba04350000000309900210000000f80990008900000000089801cf000000ff0990008c0000000008002019000000210960003900000c250000013d0000061a0850009c000013ce0000213d0000004008500039000000400080043f000000010800003a00000000088504360000000009100350000000000909043b0000000000980435000013d40000613d000000f80a600210000005e40b000041000000000606004b000000000b0ac0190000061b069001970000000006b6019f0000000000680435000000400600043d000000400870008a000000060780035f000000000707043b000000800970008c00000c720000413d00000080097002700000061c0a70009c000000000907a0190000061c0a70009c000000000a000019000000100a002039000000080ba001bf000005e30c90009c000000000b0aa019000000400a900270000005e30c90009c000000000a09a019000000040cb001bf000005d309a0009c000000000c0ba019000000200ba00270000005d309a0009c000000000b0aa0190000000209c001bf0000ffff0ab0008c00000000090ca019000000100ab00270000000000a0ba019000000ff0aa0008c0000000109902039000000200a00008a000000410b900039000000000aab016f000000000aa60019000000000b6a004b000000000b000019000000010b004039000005e30ca0009c000013ce0000213d000000010bb00190000013ce0000c13d0000004000a0043f000000020a900039000000000aa60436000000210b900039000000050bb0027200000b640000613d000000000c000019000000050dc00210000000000eda0019000000000dd1034f000000000d0d043b0000000000de0435000000010cc00039000000000dbc004b00000b5c0000413d000000000200004b00000b660000613d000000000b060433000000000b0b004b000013d40000613d000000000b0a04330000061b0bb00197000000f80c900210000000000bbc019f0000061d0bb000410000000000ba04350000000309900210000000f80990008900000000079701cf000000ff0990008c0000000007002019000000210960003900000c820000013d0000061a0640009c000013ce0000213d0000004006400039000000400060043f0000000007ed034f000000010600003a00000000066404360000000007700350000000000707043b0000000000760435000013d40000613d000000f808500210000005e409000041000000000505004b000000000908c0190000061b05700197000000000595019f0000000000560435000000400500043d000200000005001d00000020065000390000000005030433000000000705004b00000b960000613d000000000700001900000000086700190000002007700039000000000937001900000000090904330000000000980435000000000857004b00000b8f0000413d000000000365001900000000000304350000000006040433000000000706004b00000ba30000613d000000000700001900000000083700190000002007700039000000000947001900000000090904330000000000980435000000000867004b00000b9c0000413d000000000336001900000000000304350000000003560019000000020400002900000000003404350000003f03300039000000200200008a000000000323016f0000000004430019000000000334004b00000000030000190000000103004039000500000004001d000005e30440009c000013ce0000213d0000000103300190000013ce0000c13d0000000503000029000000400030043f0000061a0330009c000013ce0000213d000000400310003900000000033d034f000000000303043b00000005060000290000004004600039000000400040043f00000020046000390000061e05000041000000000054043500000015040000390000000000460435000000600330021000000021046000390000000000340435000001200310003900000000043d034f000000400900043d000000000404043b000000800540008c000400000009001d00000d9b0000413d00000080054002700000061c0640009c000000000504a0190000061c0640009c0000000006000019000000100600203900000008076001bf000005e30850009c000000000706a0190000004006500270000005e30850009c000000000605a01900000004087001bf000005d30560009c000000000807a0190000002007600270000005d30560009c000000000706a01900000002058001bf0000ffff0670008c000000000508a0190000001006700270000000000607a019000000ff0660008c00000001055020390000004106500039000000000626016f0000000006690019000000000796004b00000000070000190000000107004039000005e30860009c000013ce0000213d0000000107700190000013ce0000c13d000000400060043f0000000206500039000000040700002900000000066704360000002107500039000000050770027200000c010000613d0000000008ed034f0000000009000019000000050a900210000000000ba60019000000000aa8034f000000000a0a043b0000000000ab04350000000109900039000000000a79004b00000bf90000413d000000000700004b00000c030000613d00000004070000290000000007070433000000000707004b000013d40000613d00000000070604330000061b07700197000000f808500210000000000778019f0000061d0770004100000000007604350000000305500210000000f80550008900000000045401cf000000ff0550008c00000000040020190000000405000029000000210550003900000dad0000013d0000061a0960009c000013ce0000213d0000004009600039000000400090043f000000010900003a0000000009960436000000000a100350000000000a0a043b0000000000a90435000013d40000613d000000f80b800210000005e40c000041000000000808004b000000000c0bc0190000061b08a001970000000008c8019f0000000000890435000000400800043d000000400770008a000000000972034f000000000909043b000000800a90008c00000ccf0000413d000000800a9002700000061c0b90009c000000000a09a0190000061c0b90009c000000000b000019000000100b002039000000080cb001bf000005e30da0009c000000000c0ba019000000400ba00270000005e30da0009c000000000b0aa019000000040dc001bf000005d30ab0009c000000000d0ca019000000200cb00270000005d30ab0009c000000000c0ba019000000020ad001bf0000ffff0bc0008c000000000a0da019000000100bc00270000000000b0ca019000000ff0bb0008c000000010aa02039000000200b00008a000000410ca00039000000000bbc016f000000000bb80019000000000c8b004b000000000c000019000000010c004039000005e30db0009c000013ce0000213d000000010cc00190000013ce0000c13d0000004000b0043f000000020ba00039000000000bb80436000000210ca00039000000050cc0027200000c5f0000613d000000000d000019000000050ed00210000000000feb0019000000000ee1034f000000000e0e043b0000000000ef0435000000010dd00039000000000ecd004b00000c570000413d000000000300004b00000c610000613d000000000c080433000000000c0c004b000000070f000029000013d40000613d000000000c0b04330000061b0cc00197000000f80da00210000000000ccd019f0000061d0cc000410000000000cb0435000000030aa00210000000f80aa000890000000009a901cf000000ff0aa0008c0000000009002019000000210a80003900000cdf0000013d0000061a0960009c000013ce0000213d0000004009600039000000400090043f000000010900003a0000000009960436000000000a100350000000000a0a043b0000000000a90435000013d40000613d000000f80b700210000005e40c000041000000000707004b000000000c0bc0190000061b07a001970000000007c7019f0000000000790435000000400700043d000000200880008a000000060980035f000000000909043b000000800a90008c00000d3d0000413d000000800a9002700000061c0b90009c000000000a09a0190000061c0b90009c000000000b000019000000100b002039000000080cb001bf000005e30da0009c000000000c0ba019000000400ba00270000005e30da0009c000000000b0aa019000000040dc001bf000005d30ab0009c000000000d0ca019000000200cb00270000005d30ab0009c000000000c0ba019000000020ad001bf0000ffff0bc0008c000000000a0da019000000100bc00270000000000b0ca019000000ff0bb0008c000000010aa02039000000200b00008a000000410ca00039000000000bbc016f000000000bb70019000000000c7b004b000000000c000019000000010c004039000005e30db0009c000013ce0000213d000000010cc00190000013ce0000c13d0000004000b0043f000000020ba00039000000000bb70436000000210ca00039000000050cc0027200000cbc0000613d000000000d000019000000050ed00210000000000feb0019000000000ee1034f000000000e0e043b0000000000ef0435000000010dd00039000000000ecd004b00000cb40000413d000000000200004b00000cbe0000613d000000000c070433000000000c0c004b000000070f000029000013d40000613d000000000c0b04330000061b0cc00197000000f80da00210000000000ccd019f0000061d0cc000410000000000cb0435000000030aa00210000000f80aa000890000000009a901cf000000ff0aa0008c0000000009002019000000210a70003900000d4d0000013d0000061a0a80009c000013ce0000213d000000400a8000390000004000a0043f000000010a00003a000000000aa80436000000000b100350000000000b0b043b0000000000ba0435000013d40000613d000000f80c900210000005e40d000041000000000909004b000000000d0cc0190000061b09b001970000000009d9019f00000000009a0435000000400a00043d0000061a09a0009c000013ce0000213d000000200970008a000000000992034f000000000909043b000000400ba000390000004000b0043f000000200ba000390000061e0c0000410000000000cb0435000000150b0000390000000000ba04350000006009900210000000210ba0003900000000009b0435000000c007700039000000000772034f000000400900043d000000000707043b000000800b70008c00000e630000413d000000800b7002700000061c0c70009c000000000b07a0190000061c0c70009c000000000c000019000000100c002039000000080dc001bf000005e30eb0009c000000000d0ca019000000400cb00270000005e30eb0009c000000000c0ba019000000040ed001bf000005d30bc0009c000000000e0da019000000200dc00270000005d30bc0009c000000000d0ca019000000020be001bf0000ffff0cd0008c000000000b0ea019000000100cd00270000000000c0da019000000ff0cc0008c000000010bb02039000000200c00008a000000410db00039000000000ccd016f000000000cc90019000000000d9c004b000000000d000019000000010d004039000005e30ec0009c000013ce0000213d000000010dd00190000013ce0000c13d0000004000c0043f000000020cb00039000000000cc90436000000210db00039000000050dd0027200000d290000613d000000000e000019000000050fe002100000000003fc0019000000000ff1034f000000000f0f043b0000000000f30435000000010ee000390000000003de004b00000d210000413d000000000300004b00000d2b0000613d0000000003090433000000000303004b000000070f000029000013d40000613d00000000030c04330000061b03300197000000f80db0021000000000033d019f0000061d0330004100000000003c04350000000303b00210000000f80330008900000000073701cf000000ff0330008c00000000070020190000002103900039000000000073043500000e740000013d0000061a0a70009c000013ce0000213d000000400a7000390000004000a0043f000000010a00003a000000000aa70436000000000b100350000000000b0b043b0000000000ba0435000013d40000613d000000f80c900210000005e40d000041000000000909004b000000000d0cc0190000061b09b001970000000009d9019f00000000009a0435000000400900043d000000400880008a000000060a80035f000000000a0a043b000000800ba0008c00000df50000413d000000800ba002700000061c0ca0009c000000000b0aa0190000061c0ca0009c000000000c000019000000100c002039000000080dc001bf000005e30eb0009c000000000d0ca019000000400cb00270000005e30eb0009c000000000c0ba019000000040ed001bf000005d30bc0009c000000000e0da019000000200dc00270000005d30bc0009c000000000d0ca019000000020be001bf0000ffff0cd0008c000000000b0ea019000000100cd00270000000000c0da019000000ff0cc0008c000000010bb02039000000200c00008a000000410db00039000000000ccd016f000000000cc90019000000000d9c004b000000000d000019000000010d004039000005e30ec0009c000013ce0000213d000000010dd00190000013ce0000c13d0000004000c0043f000000020cb00039000000000cc90436000000210db00039000000050dd0027200000d870000613d000000000e000019000000050fe002100000000003fc0019000000000ff1034f000000000f0f043b0000000000f30435000000010ee000390000000003de004b00000d7f0000413d000000000200004b00000d890000613d0000000003090433000000000303004b000000070f000029000013d40000613d00000000030c04330000061b03300197000000f80db0021000000000033d019f0000061d0330004100000000003c04350000000303b00210000000f803300089000000000a3a01cf000000ff0330008c000000000a00201900000021039000390000000000a3043500000e060000013d0000061a0590009c000013ce0000213d00000004070000290000004005700039000000400050043f0000000006ed034f000000010500003a00000000055704360000000006600350000000000606043b0000000000650435000013d40000613d000000f807400210000005e408000041000000000404004b000000000807c0190000061b04600197000000000484019f0000000000450435000000a00330003900000000043d034f000000000404043b000000000f0e001900000000051e00490000001f0550008a000005e406500197000005e407400197000005e408000041000000000967004b00000000090000190000000009084019000000000667013f000000000754004b0000000008004019000005e40660009c000000000908c019000000000609004b000013d20000c13d000000000714001900000000067d034f000000000606043b000005e30860009c000013d20000213d00000000086f00490000002007700039000005e409000041000000000a87004b000000000a000019000000000a092019000005e408800197000005e40b700197000000000c8b004b000000000900801900000000088b013f000005e40880009c00000000090ac019000000000809004b000013d20000c13d000000010860008c000000000c02001900000fee0000c13d00000000067d034f000000000606043b000000010700008a000005e408000041000000000776004b00000000070000190000000007082019000005e406600197000005e40960009c0000000008008019000005e406600167000005e40660009c000000000807c019000300600000003d000000000608004b000010780000c13d000000400600043d000300000006001d0000061a0660009c000013ce0000213d00000003080000290000004006800039000000400060043f00000020068000390000061d07000041000000000076043500000001060000390000000000680435000010780000013d0000061a0390009c000013ce0000213d0000004003900039000000400030043f000000010300003a000000000b3904360000000003100350000000000c03043b0000000000cb0435000013d40000613d000000f803a00210000005e40d000041000000000a0a004b000000000d03c0190000061b03c001970000000003d3019f00000000003b0435000000400b00043d0000061a03b0009c000013ce0000213d000000200380008a000000060330035f000000000303043b000000400ab000390000004000a0043f000000200ab000390000061e0c0000410000000000ca0435000000150a0000390000000000ab04350000006003300210000000210ab0003900000000003a0435000000c003800039000000060330035f000000400a00043d000000000803043b000000800380008c00000f210000413d00000080038002700000061c0c80009c000000000308a0190000061c0c80009c000000000c000019000000100c002039000000080dc001bf000005e30e30009c000000000d0ca019000000400c300270000005e30e30009c000000000c03a0190000000403d001bf000005d30ec0009c00000000030da019000000200dc00270000005d30ec0009c000000000d0ca019000000020c3001bf0000ffff0ed0008c000000000c03a0190000001003d0027000000000030da019000000ff0330008c000000010cc02039000000200300008a000000410dc0003900000000033d016f000000000d3a00190000000003ad004b000000000e000019000000010e004039000005e303d0009c000013ce0000213d0000000103e00190000013ce0000c13d0000004000d0043f0000000203c00039000000000d3a04360000002103c00039000000050e30027200000e4f0000613d000000000f0000190000000503f0021000000000023d0019000000000331034f000000000303043b0000000000320435000000010ff000390000000002ef004b00000e470000413d000000000200004b00000e510000613d00000000020a0433000000000202004b000000070f000029000013d40000613d00000000020d04330000061b02200197000000f803c00210000000000223019f0000061d0220004100000000002d04350000000302c00210000000f80220008900000000032801cf000000ff0220008c00000000030020190000002102a00039000000000032043500000f320000013d0000061a0390009c000013ce0000213d0000004003900039000000400030043f000000010300003a000000000b3904360000000003100350000000000c03043b0000000000cb0435000013d40000613d000000f803700210000005e40d000041000000000707004b000000000d03c0190000061b03c001970000000003d3019f00000000003b0435000000400700043d000000200c700039000000000b04043300000000030b004b00000e810000613d000000000d0000190000000003cd0019000000200dd00039000000000e4d0019000000000e0e04330000000000e304350000000003bd004b00000e7a0000413d0000000003cb0019000000000003043500000000047b0019000000200c400039000000000b05043300000000030b004b00000e900000613d000000000d0000190000000003cd0019000000200dd00039000000000e5d0019000000000e0e04330000000000e304350000000003bd004b00000e890000413d0000000003cb0019000000000003043500000000044b0019000000200b4000390000000005060433000000000305004b00000e9f0000613d000000000c0000190000000003bc0019000000200cc00039000000000d6c0019000000000d0d04330000000000d3043500000000035c004b00000e980000413d0000000003b500190000000000030435000000000445001900000020064000390000000005080433000000000305004b00000eae0000613d000000000b00001900000000036b0019000000200bb00039000000000c8b0019000000000c0c04330000000000c3043500000000035b004b00000ea70000413d000000000365001900000000000304350000000004450019000000200640003900000000050a0433000000000305004b00000ebd0000613d000000000800001900000000036800190000002008800039000000000ba80019000000000b0b04330000000000b30435000000000358004b00000eb60000413d00000000036500190000000000030435000000000445001900000020064000390000000005090433000000000305004b00000ecc0000613d000000000800001900000000036800190000002008800039000000000a980019000000000a0a04330000000000a30435000000000358004b00000ec50000413d000000000365001900000000000304350000000003740049000000000335001900000000003704350000003f03300039000000200400008a000000000343016f0000000008730019000000000338004b00000000050000190000000105004039000005e30380009c000013ce0000213d0000000103500190000013ce0000c13d000000400080043f000001c003f00039000000000332034f000000060c0000290000000005fc00490000001f0650008a000000000503043b000005e403000041000000000965004b00000000090000190000000009034019000005e406600197000005e40a500197000000000b6a004b000000000300a01900000000066a013f000005e40660009c000000000309c019000000000303004b000013d20000613d0000000006f50019000000000362034f000000000503043b000005e30350009c000013d20000213d00000000095c00490000002003600039000005e406000041000000000a93004b000000000a000019000000000a062019000005e409900197000005e40b300197000000000c9b004b000000000600801900000000099b013f000005e40990009c00000000060ac019000000000606004b000013d20000c13d000000010650008c000000000232034f000010190000c13d000000000302043b000000010600008a000005e409000041000000000663004b00000000060000190000000006092019000005e403300197000005e40a30009c0000000009008019000005e403300167000005e40330009c000000000906c0190000006006000039000000000309004b0000123e0000c13d0000061a0380009c000013ce0000213d0000004003800039000000400030043f00000020038000390000061d0600004100000000006304350000000103000039000000000038043500000000060800190000123e0000013d0000061a02a0009c000013ce0000213d0000004002a00039000000400020043f000000010200003a000000000c2a04360000000002100350000000000d02043b0000000000dc0435000013d40000613d000000f802800210000005e403000041000000000808004b000000000302c0190000061b02d00197000000000232019f00000000002c0435000000400800043d000000200d800039000000000c04043300000000020c004b00000f3f0000613d000000000e0000190000000002de0019000000200ee0003900000000034e0019000000000303043300000000003204350000000002ce004b00000f380000413d0000000002dc0019000000000002043500000000048c0019000000200d400039000000000c05043300000000020c004b00000f4e0000613d000000000e0000190000000002de0019000000200ee0003900000000035e0019000000000303043300000000003204350000000002ce004b00000f470000413d0000000002dc0019000000000002043500000000044c0019000000200c4000390000000005060433000000000205004b00000f5d0000613d000000000d0000190000000002cd0019000000200dd0003900000000036d00190000000003030433000000000032043500000000025d004b00000f560000413d0000000002c500190000000000020435000000000445001900000020064000390000000005070433000000000205004b00000f6c0000613d000000000c00001900000000026c0019000000200cc0003900000000037c00190000000003030433000000000032043500000000025c004b00000f650000413d00000000026500190000000000020435000000000445001900000020064000390000000005090433000000000205004b00000f7b0000613d000000000700001900000000026700190000002007700039000000000397001900000000030304330000000000320435000000000257004b00000f740000413d000000000265001900000000000204350000000004450019000000200640003900000000050b0433000000000205004b00000f8a0000613d0000000007000019000000000267001900000020077000390000000003b7001900000000030304330000000000320435000000000257004b00000f830000413d000000000265001900000000000204350000000004450019000000200640003900000000050a0433000000000205004b00000f990000613d0000000007000019000000000267001900000020077000390000000003a7001900000000030304330000000000320435000000000257004b00000f920000413d000000000265001900000000000204350000000002840049000000000225001900000000002804350000003f02200039000000200400008a000000000242016f0000000007820019000000000227004b00000000050000190000000105004039000005e30270009c000013ce0000213d0000000102500190000013ce0000c13d000000400070043f000001c002f00039000000060220035f000000050b0000290000000003fb00490000001f0330008a000000000502043b000005e402000041000000000635004b00000000060000190000000006028019000005e403300197000005e409500197000000000a39004b0000000002008019000000000339013f000005e40330009c000000000206c019000000000202004b000013d20000c13d0000000006f50019000000060260035f000000000502043b000005e30250009c000013d20000213d00000000025b00490000002003600039000005e406000041000000000923004b00000000090000190000000009062019000005e402200197000005e40a300197000000000b2a004b000000000600801900000000022a013f000005e40220009c000000000609c019000000000206004b000013d20000c13d000000010250008c000000060230035f000010400000c13d000000000302043b000000010600008a000005e409000041000000000663004b00000000060000190000000006092019000005e403300197000005e40a30009c0000000009008019000005e403300167000005e40330009c000000000906c0190000006006000039000000000309004b000013060000c13d0000061a0370009c000013ce0000213d0000004003700039000000400030043f00000020037000390000061d060000410000000000630435000000010300003900000000003704350000000006070019000013060000013d000000400b00043d000000380760008c00030000000b001d000010670000413d0000002008600270000005d30760009c000000000806a019000005d30760009c0000000009000019000000040900203900000002079001bf0000ffff0a80008c000000000709a0190000001009800270000000000908a019000000ff0890008c000000000800001900000001080020390000061a09b0009c000013ce0000213d000000000787019f000000030a0000290000004008a00039000000400080043f0000000009fd034f000000020870003a00000000088a04360000000009900350000000000909043b0000000000980435000013d40000613d0000061b09900197000000f80a70021000000000099a019f0000061f099001c700000000009804350000000307700210000000f80770015f00000000067601cf000000030700002900000021077000390000000000670435000010780000013d000000380350008c0000122e0000413d0000002006500270000005d30350009c000000000605a019000005d30350009c0000000009000019000000040900203900000002039001bf0000ffff0a60008c000000000309a0190000001009600270000000000906a019000000ff0690008c000000000600001900000001060020390000061a0980009c000013ce0000213d000000000363019f0000004006800039000000400060043f000000020630003a00000000066804360000000009100350000000000909043b0000000000960435000013d40000613d0000061b09900197000000f80a30021000000000099a019f0000061f099001c700000000009604350000000303300210000000f80330015f00000000033501cf0000002106800039000000000036043500000000060800190000123e0000013d000000380350008c000012f60000413d0000002006500270000005d30350009c000000000605a019000005d30350009c0000000009000019000000040900203900000002039001bf0000ffff0a60008c000000000309a0190000001009600270000000000906a019000000ff0690008c000000000600001900000001060020390000061a0970009c000013ce0000213d000000000363019f0000004006700039000000400060043f000000020630003a00000000066704360000000009100350000000000909043b0000000000960435000013d40000613d0000061b09900197000000f80a30021000000000099a019f0000061f099001c700000000009604350000000303300210000000f80330015f00000000033501cf000000210670003900000000003604350000000006070019000013060000013d0000061a07b0009c000013ce0000213d00000003090000290000004007900039000000400070043f0000000008fd034f000000010700003a00000000077904360000000008800350000000000808043b0000000000870435000013d40000613d000000f8066002100000061b08800197000000000668019f000005e4066001670000000000670435000000800330008a00000000063d034f0000006003000039000000000606043b000000000606004b0000110f0000613d00010000000c001d00000618010000410000000000100439000005d3010000410000000002000414000005d30320009c0000000002018019000000c00120021000000619011001c70000800b020000391747173d0000040f0000000102200190000013da0000613d000000400400043d000000000301043b000000800130008c000000010c000029000010d80000413d00000080013002700000061c0230009c000000000103a0190000061c0230009c0000000002000019000000100200203900000008052001bf000005e30610009c000000000502a0190000004002100270000005e30610009c000000000201a01900000004015001bf000005d30620009c000000000105a0190000002006200270000005d30520009c000000000602a01900000002051001bf0000ffff0260008c000000000501a0190000001001600270000000000106a019000000ff0110008c000000010550203900000041015000390000000001c1016f0000000007140019000000000247004b00000000020000190000000102004039000005e30670009c0000000701000029000013ce0000213d0000000102200190000013ce0000c13d000000400070043f00000002025000390000000006240436000000020d000367000000000f00003100000021075000390000000507700272000010c60000613d0000000008fd034f0000000009000019000000050a900210000000000ba60019000000000aa8034f000000000a0a043b0000000000ab04350000000109900039000000000a79004b000010be0000413d000000000700004b000010c80000613d0000000007040433000000000707004b000013d40000613d00000000070604330000061b07700197000000f808500210000000000778019f0000061d0770004100000000007604350000000305500210000000f80550008900000000035301cf000000ff0550008c00000000030020190000002105400039000010ec0000013d0000061a0140009c0000000701000029000013ce0000213d0000004002400039000000400020043f000000010200003a0000000005240436000000000f000031000000020d0003670000000006fd034f0000000006600350000000000606043b0000000000650435000013d40000613d000000f807300210000005e408000041000000000303004b000000000807c0190000061b03600197000000000383019f0000000000350435000000400300043d00000020063000390000000005040433000000000705004b000010fa0000613d000000000700001900000000086700190000002007700039000000000947001900000000090904330000000000980435000000000857004b000010f30000413d00000000046500190000062c0600004100000000006404350000000204500039000000000043043500000041045000390000000005c4016f0000000004350019000000000554004b00000000050000190000000105004039000005e30640009c000013ce0000213d0000000105500190000013ce0000c13d000001c005100039000000400040043f00000000045d034f00000000051f00490000001f0550008a000000000404043b00000000020f0019000000000f0c0019000005e406000041000000000754004b00000000070000190000000007068019000005e405500197000005e408400197000000000958004b0000000006008019000000000558013f000005e40550009c000000000607c019000000000506004b000013d20000c13d000000060500002900000000060504330000000205000029000000000705043300000005050000290000000008050433000000040500002900000000090504330000000305000029000000000a050433000000000114001900000000041d034f000000000404043b000005e30b40009c000013d20000213d0000000005020019000000000b450049000000200e100039000005e40c00004100000000010d034f000000000dbe004b000000000d000019000000000d0c2019000005e40bb0019700010000000e001d000005e40ee00197000700000004001d00000000040f0019000000000fbe004b000000000f0400190000000704000029000000000c008019000000000bbe013f000000060e000029000005e40bb0009c000000000c0dc019000000000b0c004b000013d20000c13d0000000006670019000000000686001900000000069600190000000006a60019000000000646001900000000070304330000000006760019000000400700043d000005e306600197000000380860008c000011740000413d0000002009600270000005d30860009c000000000906a019000005d30860009c000000000a000019000000040a0020390000000208a001bf0000ffff0b90008c00000000080aa019000000100a900270000000000a09a019000000ff09a0008c000000000900001900000001090020390000061a0a70009c000013ce0000213d000000000898019f0000004009700039000000400090043f000000000951034f000000020280003a00000000022704360000000009900350000000000909043b0000000000920435000013d40000613d0000061b09900197000000f80a80021000000000099a019f00000621099001c700000000009204350000000302800210000000f80220015f00000000022601cf00000021067000390000000000260435000011840000013d0000061a0870009c000013ce0000213d0000004008700039000000400080043f000000000851034f000000010200003a00000000022704360000000008800350000000000808043b0000000000820435000013d40000613d0000061b08800197000000f806600210000000000686019f00000620066000410000000000620435000000400200043d00000020062000390000000008070433000000000908004b00000002040000290000000505000029000011930000613d0000000009000019000000000a6900190000002009900039000000000b790019000000000b0b04330000000000ba0435000000000a89004b0000118c0000413d000000000768001900000000000704350000000007280019000000200970003900000000080e0433000000000a08004b000011a20000613d000000000a000019000000000b9a0019000000200aa00039000000000cea0019000000000c0c04330000000000cb0435000000000b8a004b0000119b0000413d00000000099800190000000000090435000000000778001900000020097000390000000008040433000000000a08004b000011b10000613d000000000a000019000000000b9a0019000000200aa00039000000000c4a0019000000000c0c04330000000000cb0435000000000b8a004b000011aa0000413d00000000099800190000000000090435000000000778001900000020097000390000000008050433000000000a08004b000011c00000613d000000000a000019000000000b9a0019000000200aa00039000000000c5a0019000000000c0c04330000000000cb0435000000000b8a004b000011b90000413d000000000998001900000000000904350000000007780019000000200970003900000004040000290000000008040433000000000a08004b000011d00000613d000000000a000019000000000b9a0019000000200aa00039000000000c4a0019000000000c0c04330000000000cb0435000000000b8a004b000011c90000413d000000000998001900000000000904350000000007780019000000200970003900000003040000290000000008040433000000000a08004b000011e00000613d000000000a000019000000000b9a0019000000200aa00039000000000c4a0019000000000c0c04330000000000cb0435000000000b8a004b000011d90000413d000000000998001900000000000904350000000105100360000000000178001900000007040000290000001f0740018f00000020081000390000000509400272000011f20000613d000000000a000019000000050ba00210000000000cb80019000000000bb5034f000000000b0b043b0000000000bc0435000000010aa00039000000000b9a004b000011ea0000413d000000000a07004b000012010000613d0000000509900210000000000595034f00000000089800190000000307700210000000000908043300000000097901cf000000000979022f000000000505043b0000010007700089000000000575022f00000000057501cf000000000595019f00000000005804350000000001410019000000200510003900000000000504350000000004030433000000000704004b0000120f0000613d000000000700001900000000085700190000002007700039000000000937001900000000090904330000000000980435000000000847004b000012080000413d000000000354001900000000000304350000000001210049000000000114001900000000001204350000003f011000390000000003f1016f0000000001230019000000000331004b00000000030000190000000103004039000005e30410009c000013ce0000213d0000000103300190000013ce0000c13d000000400010043f000005d301000041000005d30360009c000000000601801900000040036002100000000002020433000005d30420009c00000000020180190000006002200210000000000232019f0000000003000414000005d30430009c0000000003018019000000c001300210000000000121019f000013c70000013d0000061a0380009c000013ce0000213d0000004003800039000000400030043f000000010300003a00000000033804360000000006100350000000000606043b0000000000630435000013d40000613d000000f8095002100000061b06600197000000000696019f000005e40660016700000000006304350000000006080019000000400300043d0000061a0830009c000013ce0000213d0000004008300039000000400080043f000000010b00003a0000000008b304360000000001100350000000000a01043b0000000000a80435000013d40000613d0000061b01a0019700000620091001c70000000000980435000000000807043300000000085800190000000009060433000000000898001900000000090304330000000008980019000000400900043d000005e308800197000000380c80008c000012780000413d000000200c800270000005d30b80009c000000000c08a019000005d30b80009c000000000d000019000000040d002039000000020bd001bf0000ffff0ec0008c000000000b0da019000000100dc00270000000000d0ca019000000ff0cd0008c000000000c000019000000010c0020390000061a0d90009c000013ce0000213d000000000bcb019f000000400c9000390000004000c0043f000000200c9000390000000000ac0435000000020ab0003a0000000000a90435000013d40000613d000000f80ab0021000000000011a019f00000621011001c700000000001c04350000000301b00210000000f80110015f00000000011801cf00000021089000390000000000180435000012850000013d0000061a0c90009c000013ce0000213d000000400c9000390000004000c0043f000000200c9000390000000000ac04350000000000b90435000000000a0b004b000013d40000613d000000f808800210000000000118019f000006200110004100000000001c0435000000400100043d0000002008100039000006160a0000410000000000a80435000000210b100039000000000a090433000000000c0a004b000012950000613d000000000c000019000000000dbc0019000000200cc00039000000000e9c0019000000000e0e04330000000000ed0435000000000dac004b0000128e0000413d0000000009ba0019000000000009043500000000091a0019000000210b900039000000000a070433000000000c0a004b000012a40000613d000000000c000019000000000dbc0019000000200cc00039000000000e7c0019000000000e0e04330000000000ed0435000000000dac004b0000129d0000413d0000000007ba0019000000000007043500000000079a0019000000210a7000390000000009060433000000000b09004b000012b30000613d000000000b000019000000000cab0019000000200bb00039000000000d6b0019000000000d0d04330000000000dc0435000000000c9b004b000012ac0000413d0000000006a90019000000000006043500000000067900190000001f0750018f0000002109600039000000050a500272000012c30000613d000000000b000019000000050cb00210000000000dc90019000000000cc2034f000000000c0c043b0000000000cd0435000000010bb00039000000000cab004b000012bb0000413d000000000b07004b000012d20000613d000000050aa002100000000002a2034f0000000009a900190000000307700210000000000a090433000000000a7a01cf000000000a7a022f000000000202043b0000010007700089000000000272022f00000000027201cf0000000002a2019f00000000002904350000000002560019000000210620003900000000000604350000000005030433000000000705004b000012e00000613d000000000700001900000000096700190000002007700039000000000a370019000000000a0a04330000000000a90435000000000957004b000012d90000413d0000000003650019000000000003043500000000021200490000000002250019000000010320003900000000003104350000004002200039000000000342016f0000000002130019000000000332004b00000000030000190000000103004039000005e30420009c000013ce0000213d0000000103300190000013ce0000c13d000000400020043f000005d302000041000005d30380009c00000000080280190000004003800210000013bd0000013d0000061a0370009c000013ce0000213d0000004003700039000000400030043f000000010300003a00000000033704360000000006100350000000000606043b0000000000630435000013d40000613d000000f8095002100000061b06600197000000000696019f000005e40660016700000000006304350000000006070019000000400300043d0000061a0730009c000013ce0000213d0000004007300039000000400070043f000000010b00003a0000000007b304360000000001100350000000000a01043b0000000000a70435000013d40000613d0000061b01a0019700000620091001c70000000000970435000000000708043300000000075700190000000009060433000000000797001900000000090304330000000007970019000000400900043d000005e307700197000000380c70008c000013400000413d000000200c700270000005d30b70009c000000000c07a019000005d30b70009c000000000d000019000000040d002039000000020bd001bf0000ffff0ec0008c000000000b0da019000000100dc00270000000000d0ca019000000ff0cd0008c000000000c000019000000010c0020390000061a0d90009c000013ce0000213d000000000bcb019f000000400c9000390000004000c0043f000000200c9000390000000000ac0435000000020ab0003a0000000000a90435000013d40000613d000000f80ab0021000000000011a019f00000621011001c700000000001c04350000000301b00210000000f80110015f00000000011701cf000000210790003900000000001704350000134d0000013d0000061a0c90009c000013ce0000213d000000400c9000390000004000c0043f000000200c9000390000000000ac04350000000000b90435000000000a0b004b000013d40000613d000000f807700210000000000117019f000006200110004100000000001c0435000000400100043d0000002007100039000005e90a0000410000000000a70435000000210b100039000000000a090433000000000c0a004b0000135d0000613d000000000c000019000000000dbc0019000000200cc00039000000000e9c0019000000000e0e04330000000000ed0435000000000dac004b000013560000413d0000000009ba0019000000000009043500000000091a0019000000210b900039000000000a080433000000000c0a004b0000136c0000613d000000000c000019000000000dbc0019000000200cc00039000000000e8c0019000000000e0e04330000000000ed0435000000000dac004b000013650000413d0000000008ba0019000000000008043500000000089a0019000000210a8000390000000009060433000000000b09004b0000137b0000613d000000000b000019000000000cab0019000000200bb00039000000000d6b0019000000000d0d04330000000000dc0435000000000c9b004b000013740000413d0000000006a90019000000000006043500000000068900190000001f0850018f0000002109600039000000050a5002720000138b0000613d000000000b000019000000050cb00210000000000dc90019000000000cc2034f000000000c0c043b0000000000cd0435000000010bb00039000000000cab004b000013830000413d000000000b08004b0000139a0000613d000000050aa002100000000002a2034f0000000009a900190000000308800210000000000a090433000000000a8a01cf000000000a8a022f000000000202043b0000010008800089000000000282022f00000000028201cf0000000002a2019f00000000002904350000000002560019000000210620003900000000000604350000000005030433000000000805004b000013a80000613d000000000800001900000000096800190000002008800039000000000a380019000000000a0a04330000000000a90435000000000958004b000013a10000413d0000000003650019000000000003043500000000021200490000000002250019000000010320003900000000003104350000004002200039000000000342016f0000000002130019000000000332004b00000000030000190000000103004039000005e30420009c000013ce0000213d0000000103300190000013ce0000c13d000000400020043f000005d302000041000005d30370009c000000000702801900000040037002100000000001010433000005d30410009c00000000010280190000006001100210000000000131019f0000000003000414000005d30430009c0000000003028019000000c002300210000000000112019f000005e9011001c700008010020000391747173d0000040f0000000102200190000013d20000613d000000000101043b000000000001042d000005e70100004100000000001004350000004101000039000013d70000013d00000000010000190000174900010430000005e70100004100000000001004350000003201000039000000040010043f000005e8010000410000174900010430000000000001042f000000400100043d00000044021000390000061703000041000000000032043500000024021000390000000803000039000013f30000013d000000400100043d00000044021000390000062403000041000000000032043500000024021000390000001f03000039000013f30000013d000005e70100004100000000001004350000001101000039000013d70000013d000000400100043d00000044021000390000062d030000410000000000320435000000240210003900000017030000390000000000320435000005ec020000410000000000210435000000040210003900000020030000390000000000320435000005d302000041000005d30310009c00000000010280190000004001100210000005ff011001c700001749000104300000001f0350018f00000005025002720000140a0000613d00000000040000190000000506400210000000000761034f000000000707043b00000000007604350000000104400039000000000624004b000014030000413d000000000403004b000014180000613d00000003033002100000000502200210000000000402043300000000043401cf000000000434022f000000000121034f000000000101043b0000010003300089000000000131022f00000000013101cf000000000141019f0000000000120435000000600150021000001749000104300000001f0340018f0000000502400272000014250000613d00000000050000190000000506500210000000000761034f000000000707043b00000000007604350000000105500039000000000625004b0000141e0000413d000000000503004b000014330000613d00000003033002100000000502200210000000000502043300000000053501cf000000000535022f000000000121034f000000000101043b0000010003300089000000000131022f00000000013101cf000000000151019f000000000012043500000060014002100000174900010430000000000403004b0000143f0000613d000000000400001900000000052400190000000006140019000000000606043300000000006504350000002004400039000000000534004b000014380000413d00000000012300190000000000010435000000000001042d000000e0021000390000000201000367000000000321034f000000000303043b000005d5033001980000144c0000613d0000004002200039000000000121034f000000000101043b000014610000013d000000800320008a000000000331034f000000400220008a000000000521034f000000000403043b000000000505043b00000000634500a9000000000605004b000014580000613d00000000655300d9000000000445004b000014620000c13d0000008002200039000000000121034f000000000201043b0000000001320019000000000221004b000000000200001900000001020040390000000102200190000014620000c13d000000000001042d000005e70100004100000000001004350000001101000039000000040010043f000005e801000041000017490001043000000040031000390000000202000367000000000332034f0000012005100039000000000652034f000000000303043b000005d504300197000000000306043b0000062e0630009c0000154f0000813d000000a005500039000000000552034f000000000700003100000000061700490000001f0660008a000000000505043b000005e408000041000000000965004b00000000090000190000000009084019000005e406600197000005e40a500197000000000b6a004b000000000800a01900000000066a013f000005e40660009c000000000809c019000000000608004b0000154d0000613d0000000005150019000000000152034f000000000101043b000005e30610009c0000154d0000213d00000000061700490000002008500039000005e405000041000000000968004b00000000090000190000000009052019000005e406600197000005e40a800197000000000b6a004b000000000500801900000000066a013f000005e40660009c000000000509c019000000000505004b0000154d0000c13d0000003f05100039000000200600008a000000000565016f000000400600043d0000000005560019000000000965004b00000000090000190000000109004039000005e30a50009c000015610000213d0000000109900190000015610000c13d000000400050043f00000000051604360000000009810019000000000779004b0000154d0000213d000000000782034f0000001f0210018f0000000508100272000014b70000613d0000000009000019000000050a900210000000000ba50019000000000aa7034f000000000a0a043b0000000000ab04350000000109900039000000000a89004b000014af0000413d000000000902004b000014c60000613d0000000508800210000000000787034f00000000088500190000000302200210000000000908043300000000092901cf000000000929022f000000000707043b0000010002200089000000000727022f00000000022701cf000000000292019f000000000028043500000000011500190000000000010435000080060140008c000014df0000c13d0000000001000414000005d30210009c0000154f0000213d0000000002060433000005d30420009c0000154f0000213d000000c0011002100000060a0110019700000040045002100000061404400197000000000114019f00000060022002100000061502200197000000000121019f00000616011001c7000000000203004b000014f60000613d000080090200003900008006040000390000000105000039000014fa0000013d00000000020604330000000001000414000000040640008c0000154c0000613d000005d306000041000005d30750009c00000000050680190000004005500210000005d30720009c00000000020680190000006002200210000000000252019f000005d30510009c0000000001068019000000c001100210000000000112019f000000000203004b000015450000613d000005e9011001c700008009020000390000000005000019174717380000040f000015470000013d00008006020000390000000003000019000000000400001900000000050000190000000006000019174717380000040f000300000001035500000000030100190000006003300270000105d30030019d000005d3053001970000003f03500039000005d406300197000000400300043d0000000004360019000000000664004b00000000060000190000000106004039000005e30740009c000015610000213d0000000106600190000015610000c13d000000400040043f00000000045304360000001f0650003900000005066002720000151c0000613d0000000007000031000000020770036700000000080000190000000509800210000000000a940019000000000997034f000000000909043b00000000009a04350000000108800039000000000968004b000015140000413d000000000600004b0000151e0000613d0000001f0650018f00000005055002720000152a0000613d000000000700001900000005087002100000000009840019000000000881034f000000000808043b00000000008904350000000107700039000000000857004b000015220000413d000000000706004b000015390000613d0000000505500210000000000151034f00000000055400190000000306600210000000000705043300000000076701cf000000000767022f000000000101043b0000010006600089000000000161022f00000000016101cf000000000171019f000000000015043500000001012001900000154c0000c13d0000000001030433000005d302000041000005d30310009c0000000001028019000005d30340009c000000000402801900000040024002100000006001100210000000000121019f00001749000104300000000002040019174717380000040f00030000000103550000006001100270000105d30010019d00000001012001900000154d0000613d000000000001042d00000000010000190000174900010430000000400100043d000000440210003900000617030000410000000000320435000000240210003900000008030000390000000000320435000005ec020000410000000000210435000000040210003900000020030000390000000000320435000005d302000041000005d30310009c00000000010280190000004001100210000005ff011001c70000174900010430000005e70100004100000000001004350000004101000039000000040010043f000005e80100004100001749000104300009000000000002000000400600043d0000000003020433000000820330008c0000000003060019000015920000613d0000062f0260009c000016960000813d000000c002600039000000400020043f000000820200003900000000022604360000000003000031000000020330036700000000040000190000000505400210000000000553034f000000000505043b00000000025204360000000104400039000000050540008c000015760000413d0000000002060433000000400220008c000016c80000a13d000000600260003900000000030204330000061b0330019700000630033001c700000000003204350000000002060433000000820220008c000016c80000413d000000a10260003900000000030204330000061b0330019700000630033001c70000000000320435000000400300043d0000000002060433000000820220008c00000000020600190000170e0000c13d000005fa0430009c000016960000213d0000008004300039000000400040043f0000004105000039000000000953043600000000040000310000000204400367000000000600001900000000070900190000000508600210000000000884034f000000000808043b00000000078704360000000106600039000000030860008c0000159c0000413d000000400a00043d000005fa06a0009c000016960000213d0000008006a00039000000400060043f00000000085a0436000000000500001900000000060800190000000507500210000000000774034f000000000707043b00000000067604360000000105500039000000030750008c000015ab0000413d000000410420003900000000040404330000004005200039000000000605043300000020052000390000000005050433000000000059043500000040053000390000000000650435000000f806400210000000600430003900000000070404330000061b07700197000000000667019f00000000006404350000006106200039000000810720003900000082022000390000000002020433000000000707043300000000060604330000000000680435000000400ba0003900000000007b04350000006007a00039000000f80220021000000000060704330000061b06600197000000000226019f000200000007001d00000000002704350000000002030433000000410220008c0000169a0000c13d0000000006000415000000090660008a00000020066000c9000000000205043300000041033000390000000003030433000000ff0330018f0000001b0330008a000000010330008c0000000005000019000015f50000213d000006320320009c000015f10000213d00000000030a0433000000410330008c000015f10000c13d0000004103a000390000000003030433000000ff0330018f0000001b0330008a000000010330008c000015f10000213d0000060d050000410000000006000415000000080660008a00000020066000c900000000030b0433000006330330009c000015f50000413d0000000006000415000000080660008a00000020066000c90000000005000019000300000006001d00060000000b001d00070000000a001d000100000005001d000006320320009c000016a10000213d000400000008001d00000000030404330000000006090433000000400400043d0000006005400039000000000025043500000040024000390000000000620435000000f80330027000000020024000390000000000320435000500000001001d00000000001404350000000000000435000005d3010000410000000002000414000005d30320009c0000000002018019000005d30340009c00000000040180190000004001400210000000c002200210000000000112019f00000634011001c700000001020000391747173d0000040f00000000030100190000006003300270000005d303300197000000200430008c000000000403001900000020040080390000001f0540018f0000000504400272000016260000613d00000000060000190000000507600210000000000871034f000000000808043b00000000008704350000000106600039000000000746004b0000161f0000413d000000000605004b000016340000613d00000003055002100000000504400210000000000604043300000000065601cf000000000656022f000000000741034f000000000707043b0000010005500089000000000757022f00000000055701cf000000000565019f0000000000540435000100000003001f000300000001035500000001022001900000000506000029000000040400002900000007050000290000000607000029000016ce0000613d0000000001000433000005d503100198000016b60000613d00000003020000290000000502200270000000000201001f0000000001050433000000410110008c0000169a0000c13d000700000003001d0000000001070433000006320210009c000016a10000213d000000020200002900000000020204330000000003040433000000400400043d0000006005400039000000000015043500000040014000390000000000310435000000f8012002700000002002400039000000000012043500000000006404350000000000000435000005d3010000410000000002000414000005d30320009c0000000002018019000005d30340009c00000000040180190000004001400210000000c002200210000000000112019f00000634011001c70000000102000039000600000002001d1747173d0000040f00000000030100190000006003300270000005d303300197000000200430008c000000000403001900000020040080390000001f0540018f0000000504400272000016740000613d00000000060000190000000507600210000000000871034f000000000808043b00000000008704350000000106600039000000000746004b0000166d0000413d000000000605004b000016820000613d00000003055002100000000504400210000000000604043300000000065601cf000000000656022f000000000741034f000000000707043b0000010005500089000000000757022f00000000055701cf000000000565019f0000000000540435000100000003001f00030000000103550000000102200190000016eb0000613d0000000001000433000005d5021001980000000703000029000016b60000613d000000000100041a000005d501100197000000000113004b0000000001000019000016950000c13d0000000601000029000000000101041a000005d501100197000000000112004b00000000010000190000000101006029000000000001042d000005e70100004100000000001004350000004101000039000016cb0000013d000000400100043d00000044021000390000063503000041000000000032043500000024021000390000001f03000039000016bc0000013d000000400100043d000000640210003900000610030000410000000000320435000000440210003900000637030000410000000000320435000000240210003900000022030000390000000000320435000005ec020000410000000000210435000000040210003900000020030000390000000000320435000005d302000041000005d30310009c00000000010280190000004001100210000005ed011001c70000174900010430000000400100043d000000440210003900000636030000410000000000320435000000240210003900000018030000390000000000320435000005ec020000410000000000210435000000040210003900000020030000390000000000320435000005d302000041000005d30310009c00000000010280190000004001100210000005ff011001c70000174900010430000005e70100004100000000001004350000003201000039000000040010043f000005e8010000410000174900010430000000400200043d0000001f0430018f0000000505300272000016db0000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000016d30000413d000000000604004b000017070000613d0000000505500210000000000151034f00000000055200190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f0000000000150435000017070000013d000000400200043d0000001f0430018f0000000505300272000016f80000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000016f00000413d000000000604004b000017070000613d0000000505500210000000000151034f00000000055200190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f0000000000150435000005d301000041000005d30420009c000000000201801900000040012002100000006002300210000000000121019f000017490001043000000044013000390000063102000041000000000021043500000024013000390000000e020000390000000000210435000005ec010000410000000000130435000000040130003900000020020000390000000000210435000005d301000041000005d30230009c00000000030180190000004001300210000005ff011001c70000174900010430000000000001042f00000000050100190000000000200439000000040130008c000017270000a13d000000050140027000000000010100310000000400100443000005d3010000410000000002000414000005d30420009c0000000002018019000005d30430009c00000000030180190000006001300210000000c002200210000000000112019f00000638011001c700000000020500191747173d0000040f0000000102200190000017370000613d000000000101043b000000000001042d000000000001042f0000173b002104210000000102000039000000000001042d0000000002000019000000000001042d00001740002104230000000102000039000000000001042d0000000002000019000000000001042d00001745002104230000000102000039000000000001042d0000000002000019000000000001042d0000174700000432000017480001042e00001749000104300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000001ffffffe0000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000020000000000000000000000000000004000000100000000000000000000000000000000000000000000000000000000000000000000000000a28c1aed00000000000000000000000000000000000000000000000000000000e2f318e200000000000000000000000000000000000000000000000000000000e2f318e300000000000000000000000000000000000000000000000000000000eeb8cb0900000000000000000000000000000000000000000000000000000000a28c1aee00000000000000000000000000000000000000000000000000000000df9c1589000000000000000000000000000000000000000000000000000000005270972400000000000000000000000000000000000000000000000000000000527097250000000000000000000000000000000000000000000000000000000073688914000000000000000000000000000000000000000000000000000000001626ba7e00000000000000000000000000000000000000000000000000000000202bcce7000000000000000000000000000000000000000000000000ffffffffffffffff8000000000000000000000000000000000000000000000000000000000000000e1239cd8000000000000000000000000000000000000000000000000000000009cc7f708afc65944829bd487b90b72536b1951864fbfc14e125fc972a6507f394e487b7100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002400000000000000000000000002000000000000000000000000000000000000000000000000000000000000007261746f720000000000000000000000000000000000000000000000000000004661696c656420746f20706179207468652066656520746f20746865206f706508c379a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000084000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000000949431dc000000000000000000000000000000000000000000000000000000008c5a344500000000000000000000000000000000000000000000000000000000dd62ed3e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044000000800000000000000000095ea7b3000000000000000000000000000000000000000000000000000000005361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65641806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b83020000020000000000000000000000000000002400000000000000000000000000000000000000000000000000000000000000440000000000000000000000005361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f20746f206e6f6e2d7a65726f20616c6c6f77616e636500000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff7f000000000000000000000000000000000000000000000000ffffffffffffff3f6f742073756363656564000000000000000000000000000000000000000000005361666545524332303a204552433230206f7065726174696f6e20646964206e416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000000000000000000000000000000000000000006400000000000000000000000054686520617070726f76616c4261736564207061796d617374657220696e707574206d757374206265206174206c65617374203638206279746573206c6f6e670000000000000000000000000000000000000084000000800000000000000000556e737570706f72746564207061796d617374657220666c6f770000000000000000000000000000000000000000000000000064000000800000000000000000546865207374616e64617264207061796d617374657220696e707574206d757374206265206174206c656173742034206279746573206c6f6e6700000000000000000000000000000000000000000000000000200000008000000000000000004f6e6c7920626f6f746c6f616465722063616e2063616c6c2074686973206d6574686f640000000000000000000000000000000000000000000000000000000000000000ffffffff0000000000000000000000000000000000000000000000000100000000000000000000000000000000000024000000a00000000000000000202bcce7000000000000000000000000000000000000000000000000000000001626ba7e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000001000000000000000075650000000000000000000000000000000000000000000000000000000000004e6f7420656e6f7567682062616c616e636520666f7220666565202b2076616c000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000ffffffff000000000000000000000000000000000000000000000000ffffffff00000000000000000000000001000000000000000000000000000000000000000000000000000000000000004f766572666c6f770000000000000000000000000000000000000000000000009a8a0592ac89c5ad3bc6df8224c17b485976f597df104ee20d0df415241f670b0200000200000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffbf00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000ffffffffffffffffffffffffffffffff81000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000f800000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6b656363616b3235362072657475726e656420696e76616c6964206461746100848e1bfa1ac4e3576b728bda6721b215c70a7799a5b4866282a71bab954baac8000000000000000000000000000000000000000000000000fffffffffffffe1fc2f8787176b8ac6bf7215b4adcc1e069bf4ab82d9ab1df05a57a91d425935b6ead7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a519b453ce45aaaaf3a300f5a9ec95869b4f28ab10430b572ee218c3a6a5e07d6f000000000000000000000000000000000000000000000000ffffffffffffff5f19010000000000000000000000000000000000000000000000000000000000008080000000000000000000000000000000000000000000000000000000000000456e636f64696e6720756e737570706f727465642074780000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff401b00000000000000000000000000000000000000000000000000000000000000496e76616c6964206c656e6774680000000000000000000000000000000000007fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a07fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1000000000000000000000000000000000000008000000000000000000000000045434453413a20696e76616c6964207369676e6174757265206c656e6774680045434453413a20696e76616c6964207369676e6174757265000000000000000045434453413a20696e76616c6964207369676e6174757265202773272076616c020000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d448c295e929e696b285e58d46eeef7df7814594a3c50b601ee9abfe479ae5d", + "deployedBytecode": "0x0004000000000002000e00000000000200000000030100190000006003300270000005d30030019d000005d303300197000300000031035500020000000103550000000102200190000000b20000c13d000000800b0000390000004000b0043f000000040230008c000000e90000413d000000000201043b000000e002200270000005d80420009c000000f70000213d000005de0420009c000001090000213d000005e10420009c000001580000613d000005e20220009c000000eb0000c13d000000040230008a000000600220008c000002c00000413d0000004402100370000000000602043b000005e30260009c000002c00000213d00000004076000390000000002730049000005e403000041000002600420008c00000000040000190000000004034019000005e402200197000000000502004b000000000300a019000005e40220009c000000000304c019000000000203004b000002c00000c13d0000002402100370000000000302043b0000000002000411000080010220008c000001f80000c13d000a00000003001d000900000007001d0000000002000414000005e503000041000000a00030043f000800000006001d0000010403600039000000000131034f000000000101043b000000a40010043f0000002401000039000000800010043f000000e001000039000000400010043f000000c0012002100000060a011001970000060b011001c700008003020000390000000003000019000000000400001900000000050000190000000006000019174717380000040f000300000001035500000000030100190000006003300270000105d30030019d000005d3053001970000003f03500039000005d406300197000000400300043d0000000004360019000000000664004b00000000060000190000000106004039000005e30740009c0000041a0000213d00000001066001900000041a0000c13d000000400040043f00000000045304360000001f065000390000000506600272000000680000613d0000000007000031000000020770036700000000080000190000000509800210000000000a940019000000000997034f000000000909043b00000000009a04350000000108800039000000000968004b000000600000413d000000000600004b0000006a0000613d0000001f0650018f0000000505500272000000760000613d000000000700001900000005087002100000000009840019000000000881034f000000000808043b00000000008904350000000107700039000000000857004b0000006e0000413d000000000706004b000000850000613d0000000505500210000000000151034f00000000055400190000000306600210000000000705043300000000076701cf000000000767022f000000000101043b0000010006600089000000000161022f00000000016101cf000000000171019f00000000001504350000000101200190000002390000613d0000000a01000029000000000201004b0000008c0000c13d0000000901000029174706190000040f000a00000001001d0000000901000029174714420000040f0000000002000410000e00000002001d000700000001001d0000800a01000039000000240300003900000000040004150000000e0440008a00000020044000c9000005e602000041174717200000040f000000070110006b0000000001000019000000010100a039174705620000040f0000000801000029000001e40210003900000009010000291747057a0000040f0000000003000031174704ed0000040f00000000020100190000000a01000029174715670000040f000005ee011001970000060c020000410000060d0110009c000000000200c019000000400100043d0000000000210435000005d302000041000005d30310009c000000000102801900000040011002100000060e011001c7000017480001042e0000000002000416000000000202004b000002c00000c13d0000009f02300039000005d402200197000000400020043f0000001f0230018f0000000504300272000000c40000613d00000000050000190000000506500210000000000761034f000000000707043b000000800660003900000000007604350000000105500039000000000645004b000000bc0000413d000000000502004b000000d30000613d0000000504400210000000000141034f00000003022002100000008004400039000000000504043300000000052501cf000000000525022f000000000101043b0000010002200089000000000121022f00000000012101cf000000000151019f0000000000140435000000400130008c000002c00000413d000000800100043d000005d50210009c000002c00000213d000000a00200043d000005d50320009c000002c00000213d000000000300041a000005d603300197000000000113019f000000000010041b0000000101000039000000000301041a000005d603300197000000000223019f000000000021041b000000200100003900000100001004430000012000000443000005d701000041000017480001042e000000000103004b0000021e0000613d0000000001000416000000000101004b000002c00000c13d0000000001000411000080010110008c0000021e0000c13d000005e70100004100000000001004350000000101000039000000040010043f000005e8010000410000174900010430000005d90420009c000001120000213d000005dc0420009c000001830000613d000005dd0120009c000000eb0000c13d0000000001030019174705280000040f000a00000001001d0000000001000411000080010110008c000000000100001900000001010060391747054a0000040f0000000a01000029174714680000040f0000000001000019000017480001042e000005df0120009c000001cb0000613d000005e00120009c000000eb0000c13d0000000001000416000000000101004b000002c00000c13d000000000100041a000001d00000013d000005da0420009c000001d40000613d000005db0220009c000000eb0000c13d000000040230008a000000200220008c000002c00000413d0000000402100370000000000702043b000005e30270009c000002c00000213d00000004067000390000000002630049000005e403000041000002600420008c00000000040000190000000004034019000005e402200197000000000502004b000000000300a019000005e40220009c000000000304c019000000000203004b000002c00000c13d0000000002000414000005e503000041000000a00030043f0000010403700039000000000131034f000000000101043b000000a40010043f0000002401000039000700000001001d000000800010043f000000e001000039000000400010043f000005d3012001970000008002000039000a00000006001d000800000007001d174705a40000040f0000000a01000029174706190000040f000900000001001d0000000a01000029174714420000040f0000000002000410000b00000002001d000600000001001d0000800a0100003900000000040004150000000b0440008a00000020044000c9000005e6020000410000000703000029174717200000040f000000060110006b0000000001000019000000010100a039174705620000040f0000000801000029000001e4021000390000000a010000291747057a0000040f0000000003000031174704ed0000040f00000000020100190000000901000029174715670000040f000001050000013d0000000002000416000000000202004b000002c00000c13d000000040230008a000000400220008c000002c00000413d0000002402100370000000000402043b000005e30240009c000002c00000213d0000002302400039000005e405000041000000000632004b00000000060000190000000006058019000005e402200197000000000702004b0000000005008019000005e40220009c000000000506c019000000000205004b000002c00000c13d0000000402400039000000000121034f000000000201043b0000002401400039174704ed0000040f00000004020000390000000202200367000000000202043b000000000301001900000000010200190000000002030019174715670000040f000005ee01100197000000400200043d0000000000120435000005d301000041000005d30320009c000000000201801900000040012002100000060e011001c7000017480001042e000000040230008a000000600220008c000002c00000413d0000004402100370000000000202043b000005e30420009c000002c00000213d00000004042000390000000005430049000005e406000041000002600750008c00000000070000190000000007064019000005e408500197000000000908004b000000000600a019000005e40880009c000000000607c019000000000606004b000002c00000c13d0000000006000411000080010660008c000001f80000c13d0000022402200039000000000621034f000000000606043b0000001f0550008a000005e407000041000000000856004b00000000080000190000000008078019000005e405500197000005e409600197000000000a59004b0000000007008019000000000559013f000005e40550009c000000000708c019000000000507004b000002c00000c13d0000000005460019000000000451034f000000000404043b000005e30640009c000002c00000213d00000000064300490000002005500039000005e407000041000000000865004b00000000080000190000000008072019000005e406600197000005e409500197000000000a69004b0000000007008019000000000669013f000005e40660009c000000000708c019000000000607004b000002c00000c13d000000030640008c000002500000213d000005ec01000041000000800010043f0000002001000039000000840010043f0000003a01000039000000a40010043f0000060501000041000000c40010043f0000060601000041000002010000013d0000000001000416000000000101004b000002c00000c13d0000000101000039000000000101041a000005d501100197000000800010043f0000060701000041000017480001042e000000040330008a000000600230008c000002c00000413d0000004402100370000000000202043b000005e30420009c000002c00000213d0000000003230049000005e404000041000002600530008c00000000050000190000000005044019000005e403300197000000000603004b000000000400a019000005e40330009c000000000405c019000000000304004b000002c00000c13d0000000003000411000080010330008c000001f80000c13d000000a403200039000000000331034f0000006402200039000000000121034f000000000101043b000000000203043b000000000302004b000002040000c13d00000000040004150000000d0440008a00000020044000c90000000001000414000d00000000001d0000020f0000013d000005ec01000041000000800010043f0000002001000039000000840010043f0000002401000039000000a40010043f0000060801000041000000c40010043f0000060901000041000000e40010043f0000060201000041000017490001043000000000431200a900000000422300d9000000000112004b000002350000c13d00000000040004150000000c0440008a00000020044000c90000000001000414000c00000000001d000000000203004b000002430000c13d000a00000004001d000005d302000041000005d30310009c0000000001028019000000c0011002100000800102000039174717380000040f0000000a0300002900030000000103550000006001100270000105d30010019d000000050130027000000001012001950000000101200190000002200000613d0000000001000019000017480001042e000000400100043d0000006402100039000005ea0300004100000000003204350000004402100039000005eb030000410000000000320435000000240210003900000025030000390000000000320435000005ec020000410000000000210435000000040210003900000020030000390000000000320435000005d302000041000005d30310009c00000000010280190000004001100210000005ed011001c70000174900010430000005e70100004100000000001004350000001101000039000000f40000013d0000000001030433000005d302000041000005d30310009c0000000001028019000005d30340009c000000000402801900000040024002100000006001100210000000000121019f0000174900010430000005d302000041000005d30410009c0000000001028019000000c001100210000005e9011001c7000080090200003900008001040000390000000005000019174717380000040f00000000030004150000000c0330008a00000020033000c9000002170000013d000a0000000b001d000000000651034f000000000606043b000005ee06600197000005ef0760009c000002620000613d000005f00160009c0000021e0000613d000005ec01000041000000800010043f0000002001000039000000840010043f0000001a01000039000000a40010043f0000060301000041000000c40010043f00000604010000410000174900010430000000430440008c0000026e0000213d000005ec01000041000000800010043f0000002001000039000000840010043f0000004001000039000000a40010043f0000060001000041000000c40010043f0000060101000041000002010000013d0000000404500039000000000541034f000000000505043b000900000005001d000005d50550009c000002c00000213d000001400220008a000000000221034f0000002004400039000000000441034f000000000404043b000800000004001d000000000202043b000005f104000041000000800040043f0000000004000410000005d504400197000600000004001d000000840040043f000005d502200197000700000002001d000000a40020043f00000000020004140000000904000029000000040440008c0000028e0000c13d000000000131034f0000000103000031000000200230008c00000000040300190000002004008039000002ba0000013d000005d301000041000005d30320009c0000000002018019000000c001200210000005f2011001c700000009020000291747173d0000040f00000000030100190000006003300270000005d303300197000000200430008c000000000403001900000020040080390000001f0540018f0000000506400272000002a70000613d00000000070000190000000508700210000000000981034f000000000909043b000000800880003900000000009804350000000107700039000000000867004b0000029f0000413d000000000705004b000002b60000613d0000000506600210000000000761034f00000003055002100000008006600039000000000806043300000000085801cf000000000858022f000000000707043b0000010005500089000000000757022f00000000055701cf000000000585019f0000000000560435000100000003001f00030000000103550000000102200190000002e40000613d0000001f02400039000000600520018f00000080025001bf000000400020043f000000200430008c000002c20000813d00000000010000190000174900010430000000800400043d000000080440006c0000021e0000813d000000a004500039000005f3060000410000000000640435000000a40650003900000007070000290000000000760435000000c40650003900000000000604350000004406000039000100000006001d00000000006204350000014006500039000000400060043f0000012007500039000005f406000041000300000007001d000000000067043500000100065001bf0000002005000039000400000005001d000200000006001d0000000000560435000000000502043300000000020004140000000906000029000000040660008c000003070000c13d0000000102000039000005e30430009c0000041a0000213d0000031b0000013d000000400200043d0000001f0430018f0000000505300272000002f10000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000002e90000413d000000000604004b000003000000613d0000000505500210000000000151034f00000000055200190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f0000000000150435000005d301000041000005d30420009c000000000201801900000040012002100000006002300210000000000121019f0000174900010430000005d301000041000005d30350009c000000000501801900000060035002100000004004400210000000000343019f000005d30420009c0000000002018019000000c001200210000000000113019f0000000902000029174717380000040f000500600000003d000000010220018f000300000001035500000000030100190000006003300270000105d30030019d000005d303300198000003470000613d0000003f04300039000000200500008a000000000454016f000000400500043d0000000004450019000500000005001d000000000554004b00000000050000190000000105004039000005e30640009c0000041a0000213d00000001055001900000041a0000c13d000000400040043f0000001f0430018f000000050500002900000000083504360000000503300272000003370000613d000000000500001900000005065002100000000007680019000000000661034f000000000606043b00000000006704350000000105500039000000000635004b0000032f0000413d000a00000008001d000000000504004b000003470000613d0000000503300210000000000131034f0000000a033000290000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f000000000013043500000005010000290000000001010433000000000202004b000003660000c13d000000000201004b000003610000c13d000000400400043d000a00000004001d000005ec01000041000000000014043500000004014000390000000402000029000000000021043500000002010000290000000003010433000900000003001d0000002401400039000000000031043500000044024000390000000301000029174714350000040f00000009010000290000001f01100039000000200200008a000000000121016f0000004401100039000005d302000041000005d30310009c00000000010280190000000a040000290000023d0000013d000000000201004b0000038f0000c13d000005f501000041000000000010043900000009010000290000000400100443000005d3010000410000000002000414000005d30320009c0000000002018019000000c001200210000005f6011001c700008002020000391747173d0000040f0000000102200190000004e70000613d000000000101043b000000000101004b0000038b0000c13d000000400100043d0000004402100039000005fe03000041000000000032043500000024021000390000001d030000390000000000320435000005ec020000410000000000210435000000040210003900000004030000290000000000320435000005d302000041000005d30310009c00000000010280190000004001100210000005ff011001c7000017490001043000000005010000290000000001010433000000000201004b000003b20000613d000005e402000041000000200310008c00000000030000190000000003024019000005e401100197000000000401004b000000000200a019000005e40110009c000000000203c019000000000102004b0000000a01000029000002c00000c13d0000000001010433000000000201004b0000000002000019000000010200c039000000000221004b000002c00000c13d000000000101004b000003b20000c13d000000400100043d0000006402100039000005fc0300004100000000003204350000004402100039000005fd03000041000000000032043500000024021000390000002a030000390000000000320435000005ec020000410000000000210435000000040210003900000004030000290000022e0000013d000000400300043d000000240130003900000007020000290000000000210435000005f1010000410000000000130435000a00000003001d00000004013000390000000602000029000000000021043500000000010004140000000902000029000000040220008c000003c50000c13d0000000103000031000000200130008c00000000040300190000002004008039000003f70000013d000005d302000041000005d30310009c00000000010280190000000a04000029000005d30340009c00000000020440190000004002200210000000c001100210000000000121019f000005f7011001c700000009020000291747173d0000040f0000000a0a00002900000000030100190000006003300270000005d303300197000000200430008c000000000403001900000020040080390000001f0540018f0000000506400272000003e40000613d0000000007000019000000050870021000000000098a0019000000000881034f000000000808043b00000000008904350000000107700039000000000867004b000003dc0000413d000000000705004b000003f30000613d0000000506600210000000000761034f0000000a066000290000000305500210000000000806043300000000085801cf000000000858022f000000000707043b0000010005500089000000000757022f00000000055701cf000000000585019f0000000000560435000100000003001f000300000001035500000001022001900000041e0000613d0000001f01400039000000600210018f0000000a01200029000000000221004b00000000020000190000000102004039000005e30410009c0000041a0000213d00000001022001900000041a0000c13d000000400010043f000000200230008c000002c00000413d000000440410003900000024051000390000000a020000290000000002020433000000000202004b0000043b0000c13d0000002002100039000005f3060000410000000000620435000000070600002900000000006504350000000805000029000000000054043500000001040000290000000000410435000005fa0410009c0000041a0000213d0000008004100039000a00000004001d000000400040043f000005fb0410009c000004470000a13d000005e70100004100000000001004350000004101000039000000f40000013d000000400200043d0000001f0430018f00000005053002720000042b0000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000004230000413d000000000604004b0000043a0000613d0000000505500210000000000151034f00000000055200190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f0000000000150435000003000000013d000005ec02000041000000000021043500000004021000390000000403000029000000000032043500000036020000390000000000250435000005f80200004100000000002404350000006402100039000005f9030000410000022e0000013d000000c004100039000000400040043f00000004040000290000000a050000290000000000450435000000a005100039000005f404000041000700000005001d0000000000450435000000000401043300000000010004140000000905000029000000040550008c000004590000c13d0000000102000039000005e30130009c0000041a0000213d0000046f0000013d000005d303000041000005d30520009c00000000020380190000004002200210000005d30540009c00000000040380190000006004400210000000000224019f000005d30410009c0000000001038019000000c001100210000000000112019f0000000902000029174717380000040f000800600000003d000600800000003d000000010220018f00030000000103550000006001100270000105d30010019d000005d3031001980000049c0000613d0000003f01300039000000200400008a000000000141016f000000400400043d0000000001140019000800000004001d000000000441004b00000000040000190000000104004039000005e30510009c0000041a0000213d00000001044001900000041a0000c13d000000400010043f0000001f0130018f00000008040000290000000008340436000000030400036700000005033002720000048c0000613d000000000500001900000005065002100000000007680019000000000664034f000000000606043b00000000006704350000000105500039000000000635004b000004840000413d000600000008001d000000000501004b0000049c0000613d0000000503300210000000000434034f00000006033000290000000301100210000000000503043300000000051501cf000000000515022f000000000404043b0000010001100089000000000414022f00000000011401cf000000000151019f000000000013043500000008010000290000000001010433000000000202004b000004bb0000c13d000000000201004b000004e80000c13d000000400400043d000900000004001d000005ec0100004100000000001404350000000401400039000000040200002900000000002104350000000a010000290000000003010433000a00000003001d0000002401400039000000000031043500000044024000390000000701000029174714350000040f0000000a010000290000001f01100039000000200200008a000000000121016f0000004401100039000005d302000041000005d30310009c000000000102801900000009040000290000023d0000013d000000000201004b000004d20000c13d000005f501000041000000000010043900000009010000290000000400100443000005d3010000410000000002000414000005d30320009c0000000002018019000000c001200210000005f6011001c700008002020000391747173d0000040f0000000102200190000004e70000613d000000000101043b000000000101004b000003790000613d00000008010000290000000001010433000000000201004b0000021e0000613d000005e402000041000000200310008c00000000030000190000000003024019000005e401100197000000000401004b000000000200a019000005e40110009c000000000203c019000000000102004b000002c00000c13d00000006010000290000000001010433000000000201004b0000000002000019000000010200c039000000000221004b000002c00000c13d000000000101004b0000021e0000c13d000003a30000013d000000000001042f000005d302000041000005d30310009c000000000102801900000006040000290000023d0000013d00000000040100190000060f0120009c000005200000813d0000003f01200039000000200500008a000000000551016f000000400100043d0000000005510019000000000615004b00000000060000190000000106004039000005e30750009c000005200000213d0000000106600190000005200000c13d000000400050043f00000000052104360000000006420019000000000336004b000005260000213d0000001f0320018f000000020440036700000005062002720000050e0000613d000000000700001900000005087002100000000009850019000000000884034f000000000808043b00000000008904350000000107700039000000000867004b000005060000413d000000000703004b0000051d0000613d0000000506600210000000000464034f00000000066500190000000303300210000000000706043300000000073701cf000000000737022f000000000404043b0000010003300089000000000434022f00000000033401cf000000000373019f000000000036043500000000022500190000000000020435000000000001042d000005e70100004100000000001004350000004101000039000000040010043f000005e801000041000017490001043000000000010000190000174900010430000000040210008a000005e4030000410000005f0420008c00000000040000190000000004032019000005e402200197000000000502004b0000000003008019000005e40220009c000000000304c019000000000203004b000005480000613d00000044020000390000000202200367000000000202043b000005e30320009c000005480000213d00000004022000390000000001210049000005e403000041000002600410008c00000000040000190000000004034019000005e401100197000000000501004b000000000300a019000005e40110009c000000000304c019000000000103004b000005480000c13d0000000001020019000000000001042d00000000010000190000174900010430000000000101004b0000054d0000613d000000000001042d000000400100043d000000640210003900000609030000410000000000320435000000440210003900000608030000410000000000320435000000240210003900000024030000390000000000320435000005ec020000410000000000210435000000040210003900000020030000390000000000320435000005d302000041000005d30310009c00000000010280190000004001100210000005ed011001c70000174900010430000000000101004b000005650000613d000000000001042d000000400100043d000000640210003900000610030000410000000000320435000000440210003900000611030000410000000000320435000000240210003900000022030000390000000000320435000005ec020000410000000000210435000000040210003900000020030000390000000000320435000005d302000041000005d30310009c00000000010280190000004001100210000005ed011001c70000174900010430000000000300003100000000041300490000001f0540008a0000000204000367000000000224034f000000000202043b000005e406000041000000000752004b00000000070000190000000007064019000005e405500197000005e408200197000000000958004b000000000600a019000000000558013f000005e40550009c000000000607c019000000000506004b000005a20000613d0000000001120019000000000214034f000000000202043b000005e30420009c000005a20000213d00000000032300490000002001100039000005e404000041000000000531004b00000000050000190000000005042019000005e403300197000005e406100197000000000736004b0000000004008019000000000336013f000005e40330009c000000000405c019000000000304004b000005a20000c13d000000000001042d000000000100001900001749000104300000000003020433000006120430009c000005f70000813d000000c0011002100000060a01100197000000400220021000000613022000410000061402200197000000000121019f00000060023002100000061502200197000000000121019f00000616011001c700008003020000390000000003000019000000000400001900000000050000190000000006000019174717380000040f000300000001035500000000030100190000006003300270000105d30030019d000005d3053001970000003f03500039000005d406300197000000400300043d0000000004360019000000000664004b00000000060000190000000106004039000005e30740009c000006090000213d0000000106600190000006090000c13d000000400040043f00000000045304360000001f065000390000000506600272000005d70000613d0000000007000031000000020770036700000000080000190000000509800210000000000a940019000000000997034f000000000909043b00000000009a04350000000108800039000000000968004b000005cf0000413d000000000600004b000005d90000613d0000001f0650018f0000000505500272000005e50000613d000000000700001900000005087002100000000009840019000000000881034f000000000808043b00000000008904350000000107700039000000000857004b000005dd0000413d000000000706004b000005f40000613d0000000505500210000000000151034f00000000055400190000000306600210000000000705043300000000076701cf000000000767022f000000000101043b0000010006600089000000000161022f00000000016101cf000000000171019f000000000015043500000001012001900000060f0000613d000000000001042d000000400100043d000000440210003900000617030000410000000000320435000000240210003900000008030000390000000000320435000005ec020000410000000000210435000000040210003900000020030000390000000000320435000005d302000041000005d30310009c00000000010280190000004001100210000005ff011001c70000174900010430000005e70100004100000000001004350000004101000039000000040010043f000005e80100004100001749000104300000000001030433000005d302000041000005d30310009c0000000001028019000005d30340009c000000000402801900000040024002100000006001100210000000000121019f00001749000104300007000000000002000000020d00036700000000021d034f000000000202043b000000010320008c000700000001001d0000067e0000213d000000000302004b000008900000613d000000010120008c000013ed0000c13d00000618010000410000000000100439000005d3010000410000000002000414000005d30320009c0000000002018019000000c00120021000000619011001c70000800b020000391747173d0000040f0000000102200190000013da0000613d000000400400043d000000000101043b000000800210008c0000099c0000413d00000080021002700000061c0310009c000000000201a0190000061c0310009c0000000003000019000000100300203900000008053001bf000005e30620009c000000000503a0190000004003200270000005e30620009c000000000302a01900000004025001bf000005d30630009c000000000205a0190000002006300270000005d30530009c000000000603a01900000002052001bf0000ffff0360008c000000000502a0190000001002600270000000000206a019000000ff0220008c0000000105502039000000200200008a0000004103500039000000000223016f0000000002240019000000000342004b00000000030000190000000103004039000005e30620009c000000070f000029000013ce0000213d0000000103300190000013ce0000c13d000000400020043f0000000202500039000000000624043600000002020003670000000003000031000000210750003900000005077002720000066b0000613d000000000832034f0000000009000019000000050a900210000000000ba60019000000000aa8034f000000000a0a043b0000000000ab04350000000109900039000000000a79004b000006630000413d000600000003001d000000000300004b0000066e0000613d0000000007040433000000000707004b000013d40000613d00000000070604330000061b07700197000000f808500210000000000778019f0000061d0770004100000000007604350000000305500210000000f80550008900000000015101cf000000ff0550008c00000000010020190000002105400039000009b00000013d000000020320008c000008e10000613d000000710220008c000013ed0000c13d000001c00210003900000000032d034f000000000200003100000000041200490000001f0440008a000000000303043b000005e405000041000000000643004b00000000060000190000000006058019000005e404400197000005e407300197000000000847004b0000000005008019000000000447013f000005e40440009c000000000506c019000000000405004b000013d20000c13d000000000313001900000000043d034f000000000504043b000005e30450009c000013d20000213d00000000045200490000002003300039000005e406000041000000000743004b00000000070000190000000007062019000005e404400197000005e408300197000000000948004b0000000006008019000000000448013f000005e40440009c000000000607c019000000000406004b000013d20000c13d0000000004000414000000000605004b000006b70000613d0000000006350019000000000556004b000000000500001900000001050040390000000105500190000013e90000c13d000000000562004b000013e90000413d0000000002620049000005d303300197000000000d3d034f000006120340009c000013db0000813d000005d30220019700000000012d03df000000c0024002100000060a0220019700000622022001c700000000012103af0000801002000039174717420000040f00000000030100190000006003300270000105d30030019d000005d30530019700030000000103550000000102200190000013ff0000613d0000003f02500039000005d402200197000000400600043d0000000002260019000000000362004b00000000030000190000000103004039000005e30420009c000000070c000029000013ce0000213d0000000103300190000013ce0000c13d000000400020043f0000000004560436000000020200036700000000030000310000001f075000390000000507700272000006e50000613d000000000832034f0000000009000019000000050a900210000000000ba40019000000000aa8034f000000000a0a043b0000000000ab04350000000109900039000000000a79004b000006dd0000413d000000000700004b000006e70000613d0000001f0750018f0000000505500272000006f30000613d00000000080000190000000509800210000000000a940019000000000991034f000000000909043b00000000009a04350000000108800039000000000958004b000006eb0000413d000000000807004b000007020000613d0000000505500210000000000151034f00000000055400190000000307700210000000000805043300000000087801cf000000000878022f000000000101043b0000010007700089000000000171022f00000000017101cf000000000181019f00000000001504350000000001060433000000200110008c000013e20000c13d0000000001c300490000001f0510008a000002000ac000390000000001a2034f000000000101043b000005e406000041000000000751004b00000000070000190000000007068019000005e405500197000005e408100197000000000958004b0000000006008019000000000558013f000005e40550009c000000000607c019000000000506004b000013d20000c13d0000000004040433000500000004001d0000000001c10019000000000412034f000000000504043b000005e30450009c000013d20000213d000000050450021000000000034300490000002006100039000005e401000041000000000736004b00000000070000190000000007012019000005e403300197000005e408600197000000000938004b0000000001008019000000000338013f000005e40330009c000000000107c019000000000101004b000013d20000c13d000000400100043d000000200310003900000623055001980000073c0000613d000000000262034f000000000600001900000005076002100000000008730019000000000772034f000000000707043b00000000007804350000000106600039000000000756004b000007340000413d00060000000a001d000000000200004b0000073f0000613d00000000004104350000003f02400039000000200400008a000000000242016f0000000002210019000000000412004b00000000040000190000000104004039000005e30520009c000013ce0000213d0000000104400190000013ce0000c13d000000400020043f000005d302000041000005d30430009c000000000302801900000040033002100000000001010433000005d30410009c00000000010280190000006001100210000000000131019f0000000003000414000005d30430009c0000000003028019000000c002300210000000000112019f000005e9011001c700008010020000391747173d0000040f000000070a00002900000001022001900000000604000029000013d20000613d00000000020000310000000003a200490000001f0530008a00000020044000390000000203000367000000000443034f000000000404043b000005e406000041000000000754004b00000000070000190000000007068019000005e405500197000005e408400197000000000958004b0000000006008019000000000558013f000005e40550009c000000000607c019000000000b01043b000000000106004b000013d20000c13d0000000001a40019000000000413034f000000000504043b000005e30450009c000013d20000213d00000000045200490000002001100039000005e406000041000000000741004b00000000070000190000000007062019000005e404400197000005e408100197000000000948004b0000000006008019000000000448013f000005e40440009c000000000607c019000000000406004b000013d20000c13d0000000004000414000000000605004b000007980000613d0000000006150019000000000556004b000000000500001900000001050040390000000105500190000013e90000c13d000000000562004b000013e90000413d0000000002620049000005d301100197000000000313034f00060000000b001d000005d30140009c000013db0000213d000005d30120019700000000011303df000000c0024002100000060a0220019700000622022001c700000000012103af0000801002000039174717420000040f00000000030100190000006003300270000105d30030019d000005d304300197000300000001035500000001022001900000141a0000613d0000003f02400039000005d402200197000000400500043d0000000002250019000000000352004b00000000030000190000000103004039000005e30620009c000000070c000029000013ce0000213d0000000103300190000013ce0000c13d000000400020043f000000000245043600000002030003670000001f064000390000000506600272000007c60000613d000000000730036800000000080000190000000509800210000000000a920019000000000997034f000000000909043b00000000009a04350000000108800039000000000968004b000007be0000413d000000000600004b000007c80000613d0000001f0640018f0000000504400272000007d40000613d000000000700001900000005087002100000000009820019000000000881034f000000000808043b00000000008904350000000107700039000000000847004b000007cc0000413d000000000706004b000007e30000613d0000000504400210000000000141034f00000000044200190000000306600210000000000704043300000000076701cf000000000767022f000000000101043b0000010006600089000000000161022f00000000016101cf000000000171019f00000000001404350000000001050433000000200110008c000013e20000c13d0000006001c00039000000000113034f0000004004c00039000000000543034f0000002004c00039000000000443034f0000012006c00039000000000663034f0000010007c00039000000000773034f000000e008c00039000000000883034f000000c009c00039000000000993034f000000a00ac00039000000000aa3034f000000800bc00039000000000bb3034f0000000003c3034f000000000303043b000000000404043b000000000505043b000000000c01043b000000000b0b043b000000000a0a043b000000000909043b000000000808043b000000000707043b000000000606043b0000000002020433000000400100043d000001c00d10003900000000002d0435000001a002100039000000060d0000290000000000d204350000018002100039000000050d0000290000000000d2043500000160021000390000000000620435000001400210003900000000007204350000012002100039000000000082043500000100021000390000000000920435000000e0021000390000000000a20435000000c0021000390000000000b20435000000a0021000390000000000c20435000000800210003900000000005204350000006002100039000000000042043500000040021000390000000000320435000000200210003900000625030000410000000000320435000001c0030000390000000000310435000006260310009c000013ce0000213d000001e003100039000000400030043f000005d304000041000005d30320009c000000000204801900000040022002100000000001010433000005d30310009c00000000010480190000006001100210000000000121019f0000000002000414000005d30320009c0000000002048019000000c002200210000000000112019f000005e9011001c700008010020000391747173d0000040f0000000102200190000013d20000613d000000000101043b000600000001001d000000400100043d000700000001001d000006180100004100000000001004390000000001000414000005d30210009c000005d301008041000000c00110021000000619011001c70000800b020000391747173d0000040f0000000102200190000013da0000613d00000007040000290000002002400039000000000101043b0000062703000041000000000032043500000080034000390000000000130435000000600140003900000628030000410000000000310435000000400140003900000629030000410000000000310435000000800100003900000000001404350000062a0140009c000013ce0000213d000000a001400039000000400010043f000005d301000041000005d30320009c000000000201801900000040022002100000000003040433000005d30430009c00000000030180190000006003300210000000000223019f0000000003000414000005d30430009c0000000003018019000000c001300210000000000121019f000005e9011001c700008010020000391747173d0000040f0000000102200190000013d20000613d000000000301043b000000400100043d00000042021000390000000604000029000000000042043500000020021000390000062b0400004100000000004204350000002204100039000000000034043500000042030000390000000000310435000005fa0310009c000013ce0000213d0000008003100039000000400030043f000005d303000041000005d30420009c000000000203801900000040022002100000000001010433000005d30410009c00000000010380190000006001100210000000000121019f0000000002000414000005d30420009c0000000002038019000000c002200210000013c60000013d000000400200043d000600000002001d000001000410003900000000024d034f000000000302043b000000800230008c0000093b0000413d00000080023002700000061c0530009c000000000203a0190000061c0530009c0000000005000019000000100500203900000008065001bf000005e30720009c000000000605a0190000004005200270000005e30720009c000000000502a01900000004026001bf000005d30750009c000000000206a0190000002006500270000005d30750009c000000000605a01900000002052001bf0000ffff0760008c000000000502a0190000001002600270000000000206a019000000ff0220008c0000000105502039000000200200008a0000004106500039000000000226016f0000000602200029000000060620006c00000000060000190000000106004039000005e30720009c000013ce0000213d0000000106600190000013ce0000c13d000000400020043f000000020250003900000006060000290000000006260436000000000e00003100000021075000390000000507700272000008cd0000613d0000000008ed034f0000000009000019000000050a900210000000000ba60019000000000aa8034f000000000a0a043b0000000000ab04350000000109900039000000000a79004b000008c50000413d000000000700004b000008cf0000613d00000006020000290000000007020433000000000707004b000013d40000613d00000000070604330000061b07700197000000f808500210000000000778019f0000061d0770004100000000007604350000000305500210000000f80550008900000000035301cf000000ff0550008c0000000003002019000000060200002900000021052000390000094f0000013d00000618010000410000000000100439000005d3010000410000000002000414000005d30320009c0000000002018019000000c00120021000000619011001c70000800b020000391747173d0000040f0000000102200190000013da0000613d000000400400043d000000000101043b000000800210008c000009fd0000413d00000080021002700000061c0310009c000000000201a0190000061c0310009c0000000003000019000000100300203900000008053001bf000005e30620009c000000000503a0190000004003200270000005e30620009c000000000302a01900000004025001bf000005d30630009c000000000205a0190000002006300270000005d30530009c000000000603a01900000002052001bf0000ffff0360008c000000000502a0190000001002600270000000000206a019000000ff0220008c0000000105502039000000200200008a0000004103500039000000000223016f0000000002240019000000000342004b00000000030000190000000103004039000005e30620009c000000070f000029000013ce0000213d0000000103300190000013ce0000c13d000000400020043f00000002025000390000000006240436000600020000036b000000000300003100000021075000390000000507700272000009280000613d000000060830035f0000000009000019000000050a900210000000000ba60019000000000aa8034f000000000a0a043b0000000000ab04350000000109900039000000000a79004b000009200000413d000500000003001d000000000200004b0000092b0000613d0000000007040433000000000707004b000013d40000613d00000000070604330000061b07700197000000f808500210000000000778019f0000061d0770004100000000007604350000000305500210000000f80550008900000000015101cf000000ff0550008c0000000001002019000000210540003900000a120000013d00000006020000290000061a0220009c000013ce0000213d00000006050000290000004002500039000000400020043f000000010200003a0000000005250436000000000e0000310000000006ed034f0000000006600350000000000606043b0000000000650435000013d40000613d000000f807300210000005e408000041000000000303004b000000000807c0190000061b03600197000000000383019f0000000000350435000000400300043d000000600440008a00000000054d034f000000000505043b000000800650008c00000a600000413d00000080065002700000061c0750009c000000000605a0190000061c0750009c0000000007000019000000100700203900000008087001bf000005e30960009c000000000807a0190000004007600270000005e30960009c000000000706a01900000004098001bf000005d30670009c000000000908a0190000002008700270000005d30670009c000000000807a01900000002069001bf0000ffff0780008c000000000609a0190000001007800270000000000708a019000000ff0770008c0000000106602039000000200700008a0000004108600039000000000778016f0000000007730019000000000837004b00000000080000190000000108004039000005e30970009c000013ce0000213d0000000108800190000013ce0000c13d000000400070043f00000002076000390000000007730436000000210860003900000005088002720000098a0000613d0000000009ed034f000000000a000019000000050ba00210000000000cb70019000000000bb9034f000000000b0b043b0000000000bc0435000000010aa00039000000000b8a004b000009820000413d000000000800004b0000098c0000613d0000000008030433000000000808004b000013d40000613d00000000080704330000061b08800197000000f809600210000000000889019f0000061d0880004100000000008704350000000306600210000000f80660008900000000056501cf000000ff0660008c0000000005002019000000210630003900000a710000013d0000061a0240009c000000070f000029000013ce0000213d0000004002400039000000400020043f000000010200003a00000000052404360000000202000367000600000000003500000000062003680000000006600350000000000606043b0000000000650435000013d40000613d000000f807100210000005e408000041000000000101004b000000000807c0190000061b01600197000000000181019f0000000000150435000000400500043d0000010007f00039000000000172034f000000000601043b000000800160008c000000060120036000000abe0000413d00000080086002700000061c0960009c000000000806a0190000061c0960009c00000000090000190000001009002039000000080a9001bf000005e30b80009c000000000a09a0190000004009800270000005e30b80009c000000000908a019000000040ba001bf000005d30890009c000000000b0aa019000000200a900270000005d30890009c000000000a09a0190000000208b001bf0000ffff09a0008c00000000080ba0190000001009a0027000000000090aa019000000ff0990008c0000000108802039000000200900008a000000410a80003900000000099a016f0000000009950019000000000a59004b000000000a000019000000010a004039000005e30b90009c000013ce0000213d000000010aa00190000013ce0000c13d000000400090043f00000002098000390000000009950436000000210a800039000000050aa00272000009eb0000613d000000000b000019000000050cb00210000000000dc90019000000000cc1034f000000000c0c043b0000000000cd0435000000010bb00039000000000cab004b000009e30000413d000000000300004b000009ed0000613d000000000a050433000000000a0a004b000013d40000613d000000000a0904330000061b0aa00197000000f80b800210000000000aab019f0000061d0aa000410000000000a904350000000308800210000000f80880008900000000068601cf000000ff0880008c0000000006002019000000210850003900000ace0000013d0000061a0240009c000000070f000029000013ce0000213d0000004002400039000000400020043f000000010200003a000000000524043600000002020003670006000000020353000500000000003500000000062003680000000006600350000000000606043b0000000000650435000013d40000613d000000f807100210000005e408000041000000000101004b000000000807c0190000061b01600197000000000181019f0000000000150435000000400500043d0000010007f00039000000060170035f000000000601043b000000800160008c0000000501000029000000060110035f00000b1a0000413d00000080086002700000061c0960009c000000000806a0190000061c0960009c00000000090000190000001009002039000000080a9001bf000005e30b80009c000000000a09a0190000004009800270000005e30b80009c000000000908a019000000040ba001bf000005d30890009c000000000b0aa019000000200a900270000005d30890009c000000000a09a0190000000208b001bf0000ffff09a0008c00000000080ba0190000001009a0027000000000090aa019000000ff0990008c0000000108802039000000200900008a000000410a80003900000000099a016f0000000009950019000000000a59004b000000000a000019000000010a004039000005e30b90009c000013ce0000213d000000010aa00190000013ce0000c13d000000400090043f00000002098000390000000009950436000000210a800039000000050aa0027200000a4e0000613d000000000b000019000000050cb00210000000000dc90019000000000cc1034f000000000c0c043b0000000000cd0435000000010bb00039000000000cab004b00000a460000413d000000000200004b00000a500000613d000000000a050433000000000a0a004b000013d40000613d000000000a0904330000061b0aa00197000000f80b800210000000000aab019f0000061d0aa000410000000000a904350000000308800210000000f80880008900000000068601cf000000ff0880008c0000000006002019000000210850003900000b2a0000013d0000061a0630009c000013ce0000213d0000004006300039000000400060043f0000000007ed034f000000010600003a00000000066304360000000007700350000000000707043b0000000000760435000013d40000613d000000f808500210000005e409000041000000000505004b000000000908c0190000061b05700197000000000595019f0000000000560435000000400440008a00000000054d034f000000400400043d000000000505043b000000800650008c00000b760000413d00000080065002700000061c0750009c000000000605a0190000061c0750009c0000000007000019000000100700203900000008087001bf000005e30960009c000000000807a0190000004007600270000005e30960009c000000000706a01900000004098001bf000005d30670009c000000000908a0190000002008700270000005d30670009c000000000807a01900000002069001bf0000ffff0780008c000000000609a0190000001007800270000000000708a019000000ff0770008c0000000106602039000000200700008a0000004108600039000000000778016f0000000007740019000000000847004b00000000080000190000000108004039000005e30970009c000013ce0000213d0000000108800190000013ce0000c13d000000400070043f000000020760003900000000077404360000002108600039000000050880027200000aac0000613d0000000009ed034f000000000a000019000000050ba00210000000000cb70019000000000bb9034f000000000b0b043b0000000000bc0435000000010aa00039000000000b8a004b00000aa40000413d000000000800004b00000aae0000613d0000000008040433000000000808004b000013d40000613d00000000080704330000061b08800197000000f809600210000000000889019f0000061d0880004100000000008704350000000306600210000000f80660008900000000056501cf000000ff0660008c0000000005002019000000210640003900000b870000013d0000061a0850009c000013ce0000213d0000004008500039000000400080043f000000010800003a00000000088504360000000009100350000000000909043b0000000000980435000013d40000613d000000f80a600210000005e40b000041000000000606004b000000000b0ac0190000061b069001970000000006b6019f0000000000680435000000400600043d000000600770008a000000000872034f000000000808043b000000800980008c00000c150000413d00000080098002700000061c0a80009c000000000908a0190000061c0a80009c000000000a000019000000100a002039000000080ba001bf000005e30c90009c000000000b0aa019000000400a900270000005e30c90009c000000000a09a019000000040cb001bf000005d309a0009c000000000c0ba019000000200ba00270000005d309a0009c000000000b0aa0190000000209c001bf0000ffff0ab0008c00000000090ca019000000100ab00270000000000a0ba019000000ff0aa0008c0000000109902039000000200a00008a000000410b900039000000000aab016f000000000aa60019000000000b6a004b000000000b000019000000010b004039000005e30ca0009c000013ce0000213d000000010bb00190000013ce0000c13d0000004000a0043f000000020a900039000000000aa60436000000210b900039000000050bb0027200000b080000613d000000000c000019000000050dc00210000000000eda0019000000000dd1034f000000000d0d043b0000000000de0435000000010cc00039000000000dbc004b00000b000000413d000000000300004b00000b0a0000613d000000000b060433000000000b0b004b000013d40000613d000000000b0a04330000061b0bb00197000000f80c900210000000000bbc019f0000061d0bb000410000000000ba04350000000309900210000000f80990008900000000089801cf000000ff0990008c0000000008002019000000210960003900000c250000013d0000061a0850009c000013ce0000213d0000004008500039000000400080043f000000010800003a00000000088504360000000009100350000000000909043b0000000000980435000013d40000613d000000f80a600210000005e40b000041000000000606004b000000000b0ac0190000061b069001970000000006b6019f0000000000680435000000400600043d000000400870008a000000060780035f000000000707043b000000800970008c00000c720000413d00000080097002700000061c0a70009c000000000907a0190000061c0a70009c000000000a000019000000100a002039000000080ba001bf000005e30c90009c000000000b0aa019000000400a900270000005e30c90009c000000000a09a019000000040cb001bf000005d309a0009c000000000c0ba019000000200ba00270000005d309a0009c000000000b0aa0190000000209c001bf0000ffff0ab0008c00000000090ca019000000100ab00270000000000a0ba019000000ff0aa0008c0000000109902039000000200a00008a000000410b900039000000000aab016f000000000aa60019000000000b6a004b000000000b000019000000010b004039000005e30ca0009c000013ce0000213d000000010bb00190000013ce0000c13d0000004000a0043f000000020a900039000000000aa60436000000210b900039000000050bb0027200000b640000613d000000000c000019000000050dc00210000000000eda0019000000000dd1034f000000000d0d043b0000000000de0435000000010cc00039000000000dbc004b00000b5c0000413d000000000200004b00000b660000613d000000000b060433000000000b0b004b000013d40000613d000000000b0a04330000061b0bb00197000000f80c900210000000000bbc019f0000061d0bb000410000000000ba04350000000309900210000000f80990008900000000079701cf000000ff0990008c0000000007002019000000210960003900000c820000013d0000061a0640009c000013ce0000213d0000004006400039000000400060043f0000000007ed034f000000010600003a00000000066404360000000007700350000000000707043b0000000000760435000013d40000613d000000f808500210000005e409000041000000000505004b000000000908c0190000061b05700197000000000595019f0000000000560435000000400500043d000200000005001d00000020065000390000000005030433000000000705004b00000b960000613d000000000700001900000000086700190000002007700039000000000937001900000000090904330000000000980435000000000857004b00000b8f0000413d000000000365001900000000000304350000000006040433000000000706004b00000ba30000613d000000000700001900000000083700190000002007700039000000000947001900000000090904330000000000980435000000000867004b00000b9c0000413d000000000336001900000000000304350000000003560019000000020400002900000000003404350000003f03300039000000200200008a000000000323016f0000000004430019000000000334004b00000000030000190000000103004039000500000004001d000005e30440009c000013ce0000213d0000000103300190000013ce0000c13d0000000503000029000000400030043f0000061a0330009c000013ce0000213d000000400310003900000000033d034f000000000303043b00000005060000290000004004600039000000400040043f00000020046000390000061e05000041000000000054043500000015040000390000000000460435000000600330021000000021046000390000000000340435000001200310003900000000043d034f000000400900043d000000000404043b000000800540008c000400000009001d00000d9b0000413d00000080054002700000061c0640009c000000000504a0190000061c0640009c0000000006000019000000100600203900000008076001bf000005e30850009c000000000706a0190000004006500270000005e30850009c000000000605a01900000004087001bf000005d30560009c000000000807a0190000002007600270000005d30560009c000000000706a01900000002058001bf0000ffff0670008c000000000508a0190000001006700270000000000607a019000000ff0660008c00000001055020390000004106500039000000000626016f0000000006690019000000000796004b00000000070000190000000107004039000005e30860009c000013ce0000213d0000000107700190000013ce0000c13d000000400060043f0000000206500039000000040700002900000000066704360000002107500039000000050770027200000c010000613d0000000008ed034f0000000009000019000000050a900210000000000ba60019000000000aa8034f000000000a0a043b0000000000ab04350000000109900039000000000a79004b00000bf90000413d000000000700004b00000c030000613d00000004070000290000000007070433000000000707004b000013d40000613d00000000070604330000061b07700197000000f808500210000000000778019f0000061d0770004100000000007604350000000305500210000000f80550008900000000045401cf000000ff0550008c00000000040020190000000405000029000000210550003900000dad0000013d0000061a0960009c000013ce0000213d0000004009600039000000400090043f000000010900003a0000000009960436000000000a100350000000000a0a043b0000000000a90435000013d40000613d000000f80b800210000005e40c000041000000000808004b000000000c0bc0190000061b08a001970000000008c8019f0000000000890435000000400800043d000000400770008a000000000972034f000000000909043b000000800a90008c00000ccf0000413d000000800a9002700000061c0b90009c000000000a09a0190000061c0b90009c000000000b000019000000100b002039000000080cb001bf000005e30da0009c000000000c0ba019000000400ba00270000005e30da0009c000000000b0aa019000000040dc001bf000005d30ab0009c000000000d0ca019000000200cb00270000005d30ab0009c000000000c0ba019000000020ad001bf0000ffff0bc0008c000000000a0da019000000100bc00270000000000b0ca019000000ff0bb0008c000000010aa02039000000200b00008a000000410ca00039000000000bbc016f000000000bb80019000000000c8b004b000000000c000019000000010c004039000005e30db0009c000013ce0000213d000000010cc00190000013ce0000c13d0000004000b0043f000000020ba00039000000000bb80436000000210ca00039000000050cc0027200000c5f0000613d000000000d000019000000050ed00210000000000feb0019000000000ee1034f000000000e0e043b0000000000ef0435000000010dd00039000000000ecd004b00000c570000413d000000000300004b00000c610000613d000000000c080433000000000c0c004b000000070f000029000013d40000613d000000000c0b04330000061b0cc00197000000f80da00210000000000ccd019f0000061d0cc000410000000000cb0435000000030aa00210000000f80aa000890000000009a901cf000000ff0aa0008c0000000009002019000000210a80003900000cdf0000013d0000061a0960009c000013ce0000213d0000004009600039000000400090043f000000010900003a0000000009960436000000000a100350000000000a0a043b0000000000a90435000013d40000613d000000f80b700210000005e40c000041000000000707004b000000000c0bc0190000061b07a001970000000007c7019f0000000000790435000000400700043d000000200880008a000000060980035f000000000909043b000000800a90008c00000d3d0000413d000000800a9002700000061c0b90009c000000000a09a0190000061c0b90009c000000000b000019000000100b002039000000080cb001bf000005e30da0009c000000000c0ba019000000400ba00270000005e30da0009c000000000b0aa019000000040dc001bf000005d30ab0009c000000000d0ca019000000200cb00270000005d30ab0009c000000000c0ba019000000020ad001bf0000ffff0bc0008c000000000a0da019000000100bc00270000000000b0ca019000000ff0bb0008c000000010aa02039000000200b00008a000000410ca00039000000000bbc016f000000000bb70019000000000c7b004b000000000c000019000000010c004039000005e30db0009c000013ce0000213d000000010cc00190000013ce0000c13d0000004000b0043f000000020ba00039000000000bb70436000000210ca00039000000050cc0027200000cbc0000613d000000000d000019000000050ed00210000000000feb0019000000000ee1034f000000000e0e043b0000000000ef0435000000010dd00039000000000ecd004b00000cb40000413d000000000200004b00000cbe0000613d000000000c070433000000000c0c004b000000070f000029000013d40000613d000000000c0b04330000061b0cc00197000000f80da00210000000000ccd019f0000061d0cc000410000000000cb0435000000030aa00210000000f80aa000890000000009a901cf000000ff0aa0008c0000000009002019000000210a70003900000d4d0000013d0000061a0a80009c000013ce0000213d000000400a8000390000004000a0043f000000010a00003a000000000aa80436000000000b100350000000000b0b043b0000000000ba0435000013d40000613d000000f80c900210000005e40d000041000000000909004b000000000d0cc0190000061b09b001970000000009d9019f00000000009a0435000000400a00043d0000061a09a0009c000013ce0000213d000000200970008a000000000992034f000000000909043b000000400ba000390000004000b0043f000000200ba000390000061e0c0000410000000000cb0435000000150b0000390000000000ba04350000006009900210000000210ba0003900000000009b0435000000c007700039000000000772034f000000400900043d000000000707043b000000800b70008c00000e630000413d000000800b7002700000061c0c70009c000000000b07a0190000061c0c70009c000000000c000019000000100c002039000000080dc001bf000005e30eb0009c000000000d0ca019000000400cb00270000005e30eb0009c000000000c0ba019000000040ed001bf000005d30bc0009c000000000e0da019000000200dc00270000005d30bc0009c000000000d0ca019000000020be001bf0000ffff0cd0008c000000000b0ea019000000100cd00270000000000c0da019000000ff0cc0008c000000010bb02039000000200c00008a000000410db00039000000000ccd016f000000000cc90019000000000d9c004b000000000d000019000000010d004039000005e30ec0009c000013ce0000213d000000010dd00190000013ce0000c13d0000004000c0043f000000020cb00039000000000cc90436000000210db00039000000050dd0027200000d290000613d000000000e000019000000050fe002100000000003fc0019000000000ff1034f000000000f0f043b0000000000f30435000000010ee000390000000003de004b00000d210000413d000000000300004b00000d2b0000613d0000000003090433000000000303004b000000070f000029000013d40000613d00000000030c04330000061b03300197000000f80db0021000000000033d019f0000061d0330004100000000003c04350000000303b00210000000f80330008900000000073701cf000000ff0330008c00000000070020190000002103900039000000000073043500000e740000013d0000061a0a70009c000013ce0000213d000000400a7000390000004000a0043f000000010a00003a000000000aa70436000000000b100350000000000b0b043b0000000000ba0435000013d40000613d000000f80c900210000005e40d000041000000000909004b000000000d0cc0190000061b09b001970000000009d9019f00000000009a0435000000400900043d000000400880008a000000060a80035f000000000a0a043b000000800ba0008c00000df50000413d000000800ba002700000061c0ca0009c000000000b0aa0190000061c0ca0009c000000000c000019000000100c002039000000080dc001bf000005e30eb0009c000000000d0ca019000000400cb00270000005e30eb0009c000000000c0ba019000000040ed001bf000005d30bc0009c000000000e0da019000000200dc00270000005d30bc0009c000000000d0ca019000000020be001bf0000ffff0cd0008c000000000b0ea019000000100cd00270000000000c0da019000000ff0cc0008c000000010bb02039000000200c00008a000000410db00039000000000ccd016f000000000cc90019000000000d9c004b000000000d000019000000010d004039000005e30ec0009c000013ce0000213d000000010dd00190000013ce0000c13d0000004000c0043f000000020cb00039000000000cc90436000000210db00039000000050dd0027200000d870000613d000000000e000019000000050fe002100000000003fc0019000000000ff1034f000000000f0f043b0000000000f30435000000010ee000390000000003de004b00000d7f0000413d000000000200004b00000d890000613d0000000003090433000000000303004b000000070f000029000013d40000613d00000000030c04330000061b03300197000000f80db0021000000000033d019f0000061d0330004100000000003c04350000000303b00210000000f803300089000000000a3a01cf000000ff0330008c000000000a00201900000021039000390000000000a3043500000e060000013d0000061a0590009c000013ce0000213d00000004070000290000004005700039000000400050043f0000000006ed034f000000010500003a00000000055704360000000006600350000000000606043b0000000000650435000013d40000613d000000f807400210000005e408000041000000000404004b000000000807c0190000061b04600197000000000484019f0000000000450435000000a00330003900000000043d034f000000000404043b000000000f0e001900000000051e00490000001f0550008a000005e406500197000005e407400197000005e408000041000000000967004b00000000090000190000000009084019000000000667013f000000000754004b0000000008004019000005e40660009c000000000908c019000000000609004b000013d20000c13d000000000714001900000000067d034f000000000606043b000005e30860009c000013d20000213d00000000086f00490000002007700039000005e409000041000000000a87004b000000000a000019000000000a092019000005e408800197000005e40b700197000000000c8b004b000000000900801900000000088b013f000005e40880009c00000000090ac019000000000809004b000013d20000c13d000000010860008c000000000c02001900000fee0000c13d00000000067d034f000000000606043b000000010700008a000005e408000041000000000776004b00000000070000190000000007082019000005e406600197000005e40960009c0000000008008019000005e406600167000005e40660009c000000000807c019000300600000003d000000000608004b000010780000c13d000000400600043d000300000006001d0000061a0660009c000013ce0000213d00000003080000290000004006800039000000400060043f00000020068000390000061d07000041000000000076043500000001060000390000000000680435000010780000013d0000061a0390009c000013ce0000213d0000004003900039000000400030043f000000010300003a000000000b3904360000000003100350000000000c03043b0000000000cb0435000013d40000613d000000f803a00210000005e40d000041000000000a0a004b000000000d03c0190000061b03c001970000000003d3019f00000000003b0435000000400b00043d0000061a03b0009c000013ce0000213d000000200380008a000000060330035f000000000303043b000000400ab000390000004000a0043f000000200ab000390000061e0c0000410000000000ca0435000000150a0000390000000000ab04350000006003300210000000210ab0003900000000003a0435000000c003800039000000060330035f000000400a00043d000000000803043b000000800380008c00000f210000413d00000080038002700000061c0c80009c000000000308a0190000061c0c80009c000000000c000019000000100c002039000000080dc001bf000005e30e30009c000000000d0ca019000000400c300270000005e30e30009c000000000c03a0190000000403d001bf000005d30ec0009c00000000030da019000000200dc00270000005d30ec0009c000000000d0ca019000000020c3001bf0000ffff0ed0008c000000000c03a0190000001003d0027000000000030da019000000ff0330008c000000010cc02039000000200300008a000000410dc0003900000000033d016f000000000d3a00190000000003ad004b000000000e000019000000010e004039000005e303d0009c000013ce0000213d0000000103e00190000013ce0000c13d0000004000d0043f0000000203c00039000000000d3a04360000002103c00039000000050e30027200000e4f0000613d000000000f0000190000000503f0021000000000023d0019000000000331034f000000000303043b0000000000320435000000010ff000390000000002ef004b00000e470000413d000000000200004b00000e510000613d00000000020a0433000000000202004b000000070f000029000013d40000613d00000000020d04330000061b02200197000000f803c00210000000000223019f0000061d0220004100000000002d04350000000302c00210000000f80220008900000000032801cf000000ff0220008c00000000030020190000002102a00039000000000032043500000f320000013d0000061a0390009c000013ce0000213d0000004003900039000000400030043f000000010300003a000000000b3904360000000003100350000000000c03043b0000000000cb0435000013d40000613d000000f803700210000005e40d000041000000000707004b000000000d03c0190000061b03c001970000000003d3019f00000000003b0435000000400700043d000000200c700039000000000b04043300000000030b004b00000e810000613d000000000d0000190000000003cd0019000000200dd00039000000000e4d0019000000000e0e04330000000000e304350000000003bd004b00000e7a0000413d0000000003cb0019000000000003043500000000047b0019000000200c400039000000000b05043300000000030b004b00000e900000613d000000000d0000190000000003cd0019000000200dd00039000000000e5d0019000000000e0e04330000000000e304350000000003bd004b00000e890000413d0000000003cb0019000000000003043500000000044b0019000000200b4000390000000005060433000000000305004b00000e9f0000613d000000000c0000190000000003bc0019000000200cc00039000000000d6c0019000000000d0d04330000000000d3043500000000035c004b00000e980000413d0000000003b500190000000000030435000000000445001900000020064000390000000005080433000000000305004b00000eae0000613d000000000b00001900000000036b0019000000200bb00039000000000c8b0019000000000c0c04330000000000c3043500000000035b004b00000ea70000413d000000000365001900000000000304350000000004450019000000200640003900000000050a0433000000000305004b00000ebd0000613d000000000800001900000000036800190000002008800039000000000ba80019000000000b0b04330000000000b30435000000000358004b00000eb60000413d00000000036500190000000000030435000000000445001900000020064000390000000005090433000000000305004b00000ecc0000613d000000000800001900000000036800190000002008800039000000000a980019000000000a0a04330000000000a30435000000000358004b00000ec50000413d000000000365001900000000000304350000000003740049000000000335001900000000003704350000003f03300039000000200400008a000000000343016f0000000008730019000000000338004b00000000050000190000000105004039000005e30380009c000013ce0000213d0000000103500190000013ce0000c13d000000400080043f000001c003f00039000000000332034f000000060c0000290000000005fc00490000001f0650008a000000000503043b000005e403000041000000000965004b00000000090000190000000009034019000005e406600197000005e40a500197000000000b6a004b000000000300a01900000000066a013f000005e40660009c000000000309c019000000000303004b000013d20000613d0000000006f50019000000000362034f000000000503043b000005e30350009c000013d20000213d00000000095c00490000002003600039000005e406000041000000000a93004b000000000a000019000000000a062019000005e409900197000005e40b300197000000000c9b004b000000000600801900000000099b013f000005e40990009c00000000060ac019000000000606004b000013d20000c13d000000010650008c000000000232034f000010190000c13d000000000302043b000000010600008a000005e409000041000000000663004b00000000060000190000000006092019000005e403300197000005e40a30009c0000000009008019000005e403300167000005e40330009c000000000906c0190000006006000039000000000309004b0000123e0000c13d0000061a0380009c000013ce0000213d0000004003800039000000400030043f00000020038000390000061d0600004100000000006304350000000103000039000000000038043500000000060800190000123e0000013d0000061a02a0009c000013ce0000213d0000004002a00039000000400020043f000000010200003a000000000c2a04360000000002100350000000000d02043b0000000000dc0435000013d40000613d000000f802800210000005e403000041000000000808004b000000000302c0190000061b02d00197000000000232019f00000000002c0435000000400800043d000000200d800039000000000c04043300000000020c004b00000f3f0000613d000000000e0000190000000002de0019000000200ee0003900000000034e0019000000000303043300000000003204350000000002ce004b00000f380000413d0000000002dc0019000000000002043500000000048c0019000000200d400039000000000c05043300000000020c004b00000f4e0000613d000000000e0000190000000002de0019000000200ee0003900000000035e0019000000000303043300000000003204350000000002ce004b00000f470000413d0000000002dc0019000000000002043500000000044c0019000000200c4000390000000005060433000000000205004b00000f5d0000613d000000000d0000190000000002cd0019000000200dd0003900000000036d00190000000003030433000000000032043500000000025d004b00000f560000413d0000000002c500190000000000020435000000000445001900000020064000390000000005070433000000000205004b00000f6c0000613d000000000c00001900000000026c0019000000200cc0003900000000037c00190000000003030433000000000032043500000000025c004b00000f650000413d00000000026500190000000000020435000000000445001900000020064000390000000005090433000000000205004b00000f7b0000613d000000000700001900000000026700190000002007700039000000000397001900000000030304330000000000320435000000000257004b00000f740000413d000000000265001900000000000204350000000004450019000000200640003900000000050b0433000000000205004b00000f8a0000613d0000000007000019000000000267001900000020077000390000000003b7001900000000030304330000000000320435000000000257004b00000f830000413d000000000265001900000000000204350000000004450019000000200640003900000000050a0433000000000205004b00000f990000613d0000000007000019000000000267001900000020077000390000000003a7001900000000030304330000000000320435000000000257004b00000f920000413d000000000265001900000000000204350000000002840049000000000225001900000000002804350000003f02200039000000200400008a000000000242016f0000000007820019000000000227004b00000000050000190000000105004039000005e30270009c000013ce0000213d0000000102500190000013ce0000c13d000000400070043f000001c002f00039000000060220035f000000050b0000290000000003fb00490000001f0330008a000000000502043b000005e402000041000000000635004b00000000060000190000000006028019000005e403300197000005e409500197000000000a39004b0000000002008019000000000339013f000005e40330009c000000000206c019000000000202004b000013d20000c13d0000000006f50019000000060260035f000000000502043b000005e30250009c000013d20000213d00000000025b00490000002003600039000005e406000041000000000923004b00000000090000190000000009062019000005e402200197000005e40a300197000000000b2a004b000000000600801900000000022a013f000005e40220009c000000000609c019000000000206004b000013d20000c13d000000010250008c000000060230035f000010400000c13d000000000302043b000000010600008a000005e409000041000000000663004b00000000060000190000000006092019000005e403300197000005e40a30009c0000000009008019000005e403300167000005e40330009c000000000906c0190000006006000039000000000309004b000013060000c13d0000061a0370009c000013ce0000213d0000004003700039000000400030043f00000020037000390000061d060000410000000000630435000000010300003900000000003704350000000006070019000013060000013d000000400b00043d000000380760008c00030000000b001d000010670000413d0000002008600270000005d30760009c000000000806a019000005d30760009c0000000009000019000000040900203900000002079001bf0000ffff0a80008c000000000709a0190000001009800270000000000908a019000000ff0890008c000000000800001900000001080020390000061a09b0009c000013ce0000213d000000000787019f000000030a0000290000004008a00039000000400080043f0000000009fd034f000000020870003a00000000088a04360000000009900350000000000909043b0000000000980435000013d40000613d0000061b09900197000000f80a70021000000000099a019f0000061f099001c700000000009804350000000307700210000000f80770015f00000000067601cf000000030700002900000021077000390000000000670435000010780000013d000000380350008c0000122e0000413d0000002006500270000005d30350009c000000000605a019000005d30350009c0000000009000019000000040900203900000002039001bf0000ffff0a60008c000000000309a0190000001009600270000000000906a019000000ff0690008c000000000600001900000001060020390000061a0980009c000013ce0000213d000000000363019f0000004006800039000000400060043f000000020630003a00000000066804360000000009100350000000000909043b0000000000960435000013d40000613d0000061b09900197000000f80a30021000000000099a019f0000061f099001c700000000009604350000000303300210000000f80330015f00000000033501cf0000002106800039000000000036043500000000060800190000123e0000013d000000380350008c000012f60000413d0000002006500270000005d30350009c000000000605a019000005d30350009c0000000009000019000000040900203900000002039001bf0000ffff0a60008c000000000309a0190000001009600270000000000906a019000000ff0690008c000000000600001900000001060020390000061a0970009c000013ce0000213d000000000363019f0000004006700039000000400060043f000000020630003a00000000066704360000000009100350000000000909043b0000000000960435000013d40000613d0000061b09900197000000f80a30021000000000099a019f0000061f099001c700000000009604350000000303300210000000f80330015f00000000033501cf000000210670003900000000003604350000000006070019000013060000013d0000061a07b0009c000013ce0000213d00000003090000290000004007900039000000400070043f0000000008fd034f000000010700003a00000000077904360000000008800350000000000808043b0000000000870435000013d40000613d000000f8066002100000061b08800197000000000668019f000005e4066001670000000000670435000000800330008a00000000063d034f0000006003000039000000000606043b000000000606004b0000110f0000613d00010000000c001d00000618010000410000000000100439000005d3010000410000000002000414000005d30320009c0000000002018019000000c00120021000000619011001c70000800b020000391747173d0000040f0000000102200190000013da0000613d000000400400043d000000000301043b000000800130008c000000010c000029000010d80000413d00000080013002700000061c0230009c000000000103a0190000061c0230009c0000000002000019000000100200203900000008052001bf000005e30610009c000000000502a0190000004002100270000005e30610009c000000000201a01900000004015001bf000005d30620009c000000000105a0190000002006200270000005d30520009c000000000602a01900000002051001bf0000ffff0260008c000000000501a0190000001001600270000000000106a019000000ff0110008c000000010550203900000041015000390000000001c1016f0000000007140019000000000247004b00000000020000190000000102004039000005e30670009c0000000701000029000013ce0000213d0000000102200190000013ce0000c13d000000400070043f00000002025000390000000006240436000000020d000367000000000f00003100000021075000390000000507700272000010c60000613d0000000008fd034f0000000009000019000000050a900210000000000ba60019000000000aa8034f000000000a0a043b0000000000ab04350000000109900039000000000a79004b000010be0000413d000000000700004b000010c80000613d0000000007040433000000000707004b000013d40000613d00000000070604330000061b07700197000000f808500210000000000778019f0000061d0770004100000000007604350000000305500210000000f80550008900000000035301cf000000ff0550008c00000000030020190000002105400039000010ec0000013d0000061a0140009c0000000701000029000013ce0000213d0000004002400039000000400020043f000000010200003a0000000005240436000000000f000031000000020d0003670000000006fd034f0000000006600350000000000606043b0000000000650435000013d40000613d000000f807300210000005e408000041000000000303004b000000000807c0190000061b03600197000000000383019f0000000000350435000000400300043d00000020063000390000000005040433000000000705004b000010fa0000613d000000000700001900000000086700190000002007700039000000000947001900000000090904330000000000980435000000000857004b000010f30000413d00000000046500190000062c0600004100000000006404350000000204500039000000000043043500000041045000390000000005c4016f0000000004350019000000000554004b00000000050000190000000105004039000005e30640009c000013ce0000213d0000000105500190000013ce0000c13d000001c005100039000000400040043f00000000045d034f00000000051f00490000001f0550008a000000000404043b00000000020f0019000000000f0c0019000005e406000041000000000754004b00000000070000190000000007068019000005e405500197000005e408400197000000000958004b0000000006008019000000000558013f000005e40550009c000000000607c019000000000506004b000013d20000c13d000000060500002900000000060504330000000205000029000000000705043300000005050000290000000008050433000000040500002900000000090504330000000305000029000000000a050433000000000114001900000000041d034f000000000404043b000005e30b40009c000013d20000213d0000000005020019000000000b450049000000200e100039000005e40c00004100000000010d034f000000000dbe004b000000000d000019000000000d0c2019000005e40bb0019700010000000e001d000005e40ee00197000700000004001d00000000040f0019000000000fbe004b000000000f0400190000000704000029000000000c008019000000000bbe013f000000060e000029000005e40bb0009c000000000c0dc019000000000b0c004b000013d20000c13d0000000006670019000000000686001900000000069600190000000006a60019000000000646001900000000070304330000000006760019000000400700043d000005e306600197000000380860008c000011740000413d0000002009600270000005d30860009c000000000906a019000005d30860009c000000000a000019000000040a0020390000000208a001bf0000ffff0b90008c00000000080aa019000000100a900270000000000a09a019000000ff09a0008c000000000900001900000001090020390000061a0a70009c000013ce0000213d000000000898019f0000004009700039000000400090043f000000000951034f000000020280003a00000000022704360000000009900350000000000909043b0000000000920435000013d40000613d0000061b09900197000000f80a80021000000000099a019f00000621099001c700000000009204350000000302800210000000f80220015f00000000022601cf00000021067000390000000000260435000011840000013d0000061a0870009c000013ce0000213d0000004008700039000000400080043f000000000851034f000000010200003a00000000022704360000000008800350000000000808043b0000000000820435000013d40000613d0000061b08800197000000f806600210000000000686019f00000620066000410000000000620435000000400200043d00000020062000390000000008070433000000000908004b00000002040000290000000505000029000011930000613d0000000009000019000000000a6900190000002009900039000000000b790019000000000b0b04330000000000ba0435000000000a89004b0000118c0000413d000000000768001900000000000704350000000007280019000000200970003900000000080e0433000000000a08004b000011a20000613d000000000a000019000000000b9a0019000000200aa00039000000000cea0019000000000c0c04330000000000cb0435000000000b8a004b0000119b0000413d00000000099800190000000000090435000000000778001900000020097000390000000008040433000000000a08004b000011b10000613d000000000a000019000000000b9a0019000000200aa00039000000000c4a0019000000000c0c04330000000000cb0435000000000b8a004b000011aa0000413d00000000099800190000000000090435000000000778001900000020097000390000000008050433000000000a08004b000011c00000613d000000000a000019000000000b9a0019000000200aa00039000000000c5a0019000000000c0c04330000000000cb0435000000000b8a004b000011b90000413d000000000998001900000000000904350000000007780019000000200970003900000004040000290000000008040433000000000a08004b000011d00000613d000000000a000019000000000b9a0019000000200aa00039000000000c4a0019000000000c0c04330000000000cb0435000000000b8a004b000011c90000413d000000000998001900000000000904350000000007780019000000200970003900000003040000290000000008040433000000000a08004b000011e00000613d000000000a000019000000000b9a0019000000200aa00039000000000c4a0019000000000c0c04330000000000cb0435000000000b8a004b000011d90000413d000000000998001900000000000904350000000105100360000000000178001900000007040000290000001f0740018f00000020081000390000000509400272000011f20000613d000000000a000019000000050ba00210000000000cb80019000000000bb5034f000000000b0b043b0000000000bc0435000000010aa00039000000000b9a004b000011ea0000413d000000000a07004b000012010000613d0000000509900210000000000595034f00000000089800190000000307700210000000000908043300000000097901cf000000000979022f000000000505043b0000010007700089000000000575022f00000000057501cf000000000595019f00000000005804350000000001410019000000200510003900000000000504350000000004030433000000000704004b0000120f0000613d000000000700001900000000085700190000002007700039000000000937001900000000090904330000000000980435000000000847004b000012080000413d000000000354001900000000000304350000000001210049000000000114001900000000001204350000003f011000390000000003f1016f0000000001230019000000000331004b00000000030000190000000103004039000005e30410009c000013ce0000213d0000000103300190000013ce0000c13d000000400010043f000005d301000041000005d30360009c000000000601801900000040036002100000000002020433000005d30420009c00000000020180190000006002200210000000000232019f0000000003000414000005d30430009c0000000003018019000000c001300210000000000121019f000013c70000013d0000061a0380009c000013ce0000213d0000004003800039000000400030043f000000010300003a00000000033804360000000006100350000000000606043b0000000000630435000013d40000613d000000f8095002100000061b06600197000000000696019f000005e40660016700000000006304350000000006080019000000400300043d0000061a0830009c000013ce0000213d0000004008300039000000400080043f000000010b00003a0000000008b304360000000001100350000000000a01043b0000000000a80435000013d40000613d0000061b01a0019700000620091001c70000000000980435000000000807043300000000085800190000000009060433000000000898001900000000090304330000000008980019000000400900043d000005e308800197000000380c80008c000012780000413d000000200c800270000005d30b80009c000000000c08a019000005d30b80009c000000000d000019000000040d002039000000020bd001bf0000ffff0ec0008c000000000b0da019000000100dc00270000000000d0ca019000000ff0cd0008c000000000c000019000000010c0020390000061a0d90009c000013ce0000213d000000000bcb019f000000400c9000390000004000c0043f000000200c9000390000000000ac0435000000020ab0003a0000000000a90435000013d40000613d000000f80ab0021000000000011a019f00000621011001c700000000001c04350000000301b00210000000f80110015f00000000011801cf00000021089000390000000000180435000012850000013d0000061a0c90009c000013ce0000213d000000400c9000390000004000c0043f000000200c9000390000000000ac04350000000000b90435000000000a0b004b000013d40000613d000000f808800210000000000118019f000006200110004100000000001c0435000000400100043d0000002008100039000006160a0000410000000000a80435000000210b100039000000000a090433000000000c0a004b000012950000613d000000000c000019000000000dbc0019000000200cc00039000000000e9c0019000000000e0e04330000000000ed0435000000000dac004b0000128e0000413d0000000009ba0019000000000009043500000000091a0019000000210b900039000000000a070433000000000c0a004b000012a40000613d000000000c000019000000000dbc0019000000200cc00039000000000e7c0019000000000e0e04330000000000ed0435000000000dac004b0000129d0000413d0000000007ba0019000000000007043500000000079a0019000000210a7000390000000009060433000000000b09004b000012b30000613d000000000b000019000000000cab0019000000200bb00039000000000d6b0019000000000d0d04330000000000dc0435000000000c9b004b000012ac0000413d0000000006a90019000000000006043500000000067900190000001f0750018f0000002109600039000000050a500272000012c30000613d000000000b000019000000050cb00210000000000dc90019000000000cc2034f000000000c0c043b0000000000cd0435000000010bb00039000000000cab004b000012bb0000413d000000000b07004b000012d20000613d000000050aa002100000000002a2034f0000000009a900190000000307700210000000000a090433000000000a7a01cf000000000a7a022f000000000202043b0000010007700089000000000272022f00000000027201cf0000000002a2019f00000000002904350000000002560019000000210620003900000000000604350000000005030433000000000705004b000012e00000613d000000000700001900000000096700190000002007700039000000000a370019000000000a0a04330000000000a90435000000000957004b000012d90000413d0000000003650019000000000003043500000000021200490000000002250019000000010320003900000000003104350000004002200039000000000342016f0000000002130019000000000332004b00000000030000190000000103004039000005e30420009c000013ce0000213d0000000103300190000013ce0000c13d000000400020043f000005d302000041000005d30380009c00000000080280190000004003800210000013bd0000013d0000061a0370009c000013ce0000213d0000004003700039000000400030043f000000010300003a00000000033704360000000006100350000000000606043b0000000000630435000013d40000613d000000f8095002100000061b06600197000000000696019f000005e40660016700000000006304350000000006070019000000400300043d0000061a0730009c000013ce0000213d0000004007300039000000400070043f000000010b00003a0000000007b304360000000001100350000000000a01043b0000000000a70435000013d40000613d0000061b01a0019700000620091001c70000000000970435000000000708043300000000075700190000000009060433000000000797001900000000090304330000000007970019000000400900043d000005e307700197000000380c70008c000013400000413d000000200c700270000005d30b70009c000000000c07a019000005d30b70009c000000000d000019000000040d002039000000020bd001bf0000ffff0ec0008c000000000b0da019000000100dc00270000000000d0ca019000000ff0cd0008c000000000c000019000000010c0020390000061a0d90009c000013ce0000213d000000000bcb019f000000400c9000390000004000c0043f000000200c9000390000000000ac0435000000020ab0003a0000000000a90435000013d40000613d000000f80ab0021000000000011a019f00000621011001c700000000001c04350000000301b00210000000f80110015f00000000011701cf000000210790003900000000001704350000134d0000013d0000061a0c90009c000013ce0000213d000000400c9000390000004000c0043f000000200c9000390000000000ac04350000000000b90435000000000a0b004b000013d40000613d000000f807700210000000000117019f000006200110004100000000001c0435000000400100043d0000002007100039000005e90a0000410000000000a70435000000210b100039000000000a090433000000000c0a004b0000135d0000613d000000000c000019000000000dbc0019000000200cc00039000000000e9c0019000000000e0e04330000000000ed0435000000000dac004b000013560000413d0000000009ba0019000000000009043500000000091a0019000000210b900039000000000a080433000000000c0a004b0000136c0000613d000000000c000019000000000dbc0019000000200cc00039000000000e8c0019000000000e0e04330000000000ed0435000000000dac004b000013650000413d0000000008ba0019000000000008043500000000089a0019000000210a8000390000000009060433000000000b09004b0000137b0000613d000000000b000019000000000cab0019000000200bb00039000000000d6b0019000000000d0d04330000000000dc0435000000000c9b004b000013740000413d0000000006a90019000000000006043500000000068900190000001f0850018f0000002109600039000000050a5002720000138b0000613d000000000b000019000000050cb00210000000000dc90019000000000cc2034f000000000c0c043b0000000000cd0435000000010bb00039000000000cab004b000013830000413d000000000b08004b0000139a0000613d000000050aa002100000000002a2034f0000000009a900190000000308800210000000000a090433000000000a8a01cf000000000a8a022f000000000202043b0000010008800089000000000282022f00000000028201cf0000000002a2019f00000000002904350000000002560019000000210620003900000000000604350000000005030433000000000805004b000013a80000613d000000000800001900000000096800190000002008800039000000000a380019000000000a0a04330000000000a90435000000000958004b000013a10000413d0000000003650019000000000003043500000000021200490000000002250019000000010320003900000000003104350000004002200039000000000342016f0000000002130019000000000332004b00000000030000190000000103004039000005e30420009c000013ce0000213d0000000103300190000013ce0000c13d000000400020043f000005d302000041000005d30370009c000000000702801900000040037002100000000001010433000005d30410009c00000000010280190000006001100210000000000131019f0000000003000414000005d30430009c0000000003028019000000c002300210000000000112019f000005e9011001c700008010020000391747173d0000040f0000000102200190000013d20000613d000000000101043b000000000001042d000005e70100004100000000001004350000004101000039000013d70000013d00000000010000190000174900010430000005e70100004100000000001004350000003201000039000000040010043f000005e8010000410000174900010430000000000001042f000000400100043d00000044021000390000061703000041000000000032043500000024021000390000000803000039000013f30000013d000000400100043d00000044021000390000062403000041000000000032043500000024021000390000001f03000039000013f30000013d000005e70100004100000000001004350000001101000039000013d70000013d000000400100043d00000044021000390000062d030000410000000000320435000000240210003900000017030000390000000000320435000005ec020000410000000000210435000000040210003900000020030000390000000000320435000005d302000041000005d30310009c00000000010280190000004001100210000005ff011001c700001749000104300000001f0350018f00000005025002720000140a0000613d00000000040000190000000506400210000000000761034f000000000707043b00000000007604350000000104400039000000000624004b000014030000413d000000000403004b000014180000613d00000003033002100000000502200210000000000402043300000000043401cf000000000434022f000000000121034f000000000101043b0000010003300089000000000131022f00000000013101cf000000000141019f0000000000120435000000600150021000001749000104300000001f0340018f0000000502400272000014250000613d00000000050000190000000506500210000000000761034f000000000707043b00000000007604350000000105500039000000000625004b0000141e0000413d000000000503004b000014330000613d00000003033002100000000502200210000000000502043300000000053501cf000000000535022f000000000121034f000000000101043b0000010003300089000000000131022f00000000013101cf000000000151019f000000000012043500000060014002100000174900010430000000000403004b0000143f0000613d000000000400001900000000052400190000000006140019000000000606043300000000006504350000002004400039000000000534004b000014380000413d00000000012300190000000000010435000000000001042d000000e0021000390000000201000367000000000321034f000000000303043b000005d5033001980000144c0000613d0000004002200039000000000121034f000000000101043b000014610000013d000000800320008a000000000331034f000000400220008a000000000521034f000000000403043b000000000505043b00000000634500a9000000000605004b000014580000613d00000000655300d9000000000445004b000014620000c13d0000008002200039000000000121034f000000000201043b0000000001320019000000000221004b000000000200001900000001020040390000000102200190000014620000c13d000000000001042d000005e70100004100000000001004350000001101000039000000040010043f000005e801000041000017490001043000000040031000390000000202000367000000000332034f0000012005100039000000000652034f000000000303043b000005d504300197000000000306043b0000062e0630009c0000154f0000813d000000a005500039000000000552034f000000000700003100000000061700490000001f0660008a000000000505043b000005e408000041000000000965004b00000000090000190000000009084019000005e406600197000005e40a500197000000000b6a004b000000000800a01900000000066a013f000005e40660009c000000000809c019000000000608004b0000154d0000613d0000000005150019000000000152034f000000000101043b000005e30610009c0000154d0000213d00000000061700490000002008500039000005e405000041000000000968004b00000000090000190000000009052019000005e406600197000005e40a800197000000000b6a004b000000000500801900000000066a013f000005e40660009c000000000509c019000000000505004b0000154d0000c13d0000003f05100039000000200600008a000000000565016f000000400600043d0000000005560019000000000965004b00000000090000190000000109004039000005e30a50009c000015610000213d0000000109900190000015610000c13d000000400050043f00000000051604360000000009810019000000000779004b0000154d0000213d000000000782034f0000001f0210018f0000000508100272000014b70000613d0000000009000019000000050a900210000000000ba50019000000000aa7034f000000000a0a043b0000000000ab04350000000109900039000000000a89004b000014af0000413d000000000902004b000014c60000613d0000000508800210000000000787034f00000000088500190000000302200210000000000908043300000000092901cf000000000929022f000000000707043b0000010002200089000000000727022f00000000022701cf000000000292019f000000000028043500000000011500190000000000010435000080060140008c000014df0000c13d0000000001000414000005d30210009c0000154f0000213d0000000002060433000005d30420009c0000154f0000213d000000c0011002100000060a0110019700000040045002100000061404400197000000000114019f00000060022002100000061502200197000000000121019f00000616011001c7000000000203004b000014f60000613d000080090200003900008006040000390000000105000039000014fa0000013d00000000020604330000000001000414000000040640008c0000154c0000613d000005d306000041000005d30750009c00000000050680190000004005500210000005d30720009c00000000020680190000006002200210000000000252019f000005d30510009c0000000001068019000000c001100210000000000112019f000000000203004b000015450000613d000005e9011001c700008009020000390000000005000019174717380000040f000015470000013d00008006020000390000000003000019000000000400001900000000050000190000000006000019174717380000040f000300000001035500000000030100190000006003300270000105d30030019d000005d3053001970000003f03500039000005d406300197000000400300043d0000000004360019000000000664004b00000000060000190000000106004039000005e30740009c000015610000213d0000000106600190000015610000c13d000000400040043f00000000045304360000001f0650003900000005066002720000151c0000613d0000000007000031000000020770036700000000080000190000000509800210000000000a940019000000000997034f000000000909043b00000000009a04350000000108800039000000000968004b000015140000413d000000000600004b0000151e0000613d0000001f0650018f00000005055002720000152a0000613d000000000700001900000005087002100000000009840019000000000881034f000000000808043b00000000008904350000000107700039000000000857004b000015220000413d000000000706004b000015390000613d0000000505500210000000000151034f00000000055400190000000306600210000000000705043300000000076701cf000000000767022f000000000101043b0000010006600089000000000161022f00000000016101cf000000000171019f000000000015043500000001012001900000154c0000c13d0000000001030433000005d302000041000005d30310009c0000000001028019000005d30340009c000000000402801900000040024002100000006001100210000000000121019f00001749000104300000000002040019174717380000040f00030000000103550000006001100270000105d30010019d00000001012001900000154d0000613d000000000001042d00000000010000190000174900010430000000400100043d000000440210003900000617030000410000000000320435000000240210003900000008030000390000000000320435000005ec020000410000000000210435000000040210003900000020030000390000000000320435000005d302000041000005d30310009c00000000010280190000004001100210000005ff011001c70000174900010430000005e70100004100000000001004350000004101000039000000040010043f000005e80100004100001749000104300009000000000002000000400600043d0000000003020433000000820330008c0000000003060019000015920000613d0000062f0260009c000016960000813d000000c002600039000000400020043f000000820200003900000000022604360000000003000031000000020330036700000000040000190000000505400210000000000553034f000000000505043b00000000025204360000000104400039000000050540008c000015760000413d0000000002060433000000400220008c000016c80000a13d000000600260003900000000030204330000061b0330019700000630033001c700000000003204350000000002060433000000820220008c000016c80000413d000000a10260003900000000030204330000061b0330019700000630033001c70000000000320435000000400300043d0000000002060433000000820220008c00000000020600190000170e0000c13d000005fa0430009c000016960000213d0000008004300039000000400040043f0000004105000039000000000953043600000000040000310000000204400367000000000600001900000000070900190000000508600210000000000884034f000000000808043b00000000078704360000000106600039000000030860008c0000159c0000413d000000400a00043d000005fa06a0009c000016960000213d0000008006a00039000000400060043f00000000085a0436000000000500001900000000060800190000000507500210000000000774034f000000000707043b00000000067604360000000105500039000000030750008c000015ab0000413d000000410420003900000000040404330000004005200039000000000605043300000020052000390000000005050433000000000059043500000040053000390000000000650435000000f806400210000000600430003900000000070404330000061b07700197000000000667019f00000000006404350000006106200039000000810720003900000082022000390000000002020433000000000707043300000000060604330000000000680435000000400ba0003900000000007b04350000006007a00039000000f80220021000000000060704330000061b06600197000000000226019f000200000007001d00000000002704350000000002030433000000410220008c0000169a0000c13d0000000006000415000000090660008a00000020066000c9000000000205043300000041033000390000000003030433000000ff0330018f0000001b0330008a000000010330008c0000000005000019000015f50000213d000006320320009c000015f10000213d00000000030a0433000000410330008c000015f10000c13d0000004103a000390000000003030433000000ff0330018f0000001b0330008a000000010330008c000015f10000213d0000060d050000410000000006000415000000080660008a00000020066000c900000000030b0433000006330330009c000015f50000413d0000000006000415000000080660008a00000020066000c90000000005000019000300000006001d00060000000b001d00070000000a001d000100000005001d000006320320009c000016a10000213d000400000008001d00000000030404330000000006090433000000400400043d0000006005400039000000000025043500000040024000390000000000620435000000f80330027000000020024000390000000000320435000500000001001d00000000001404350000000000000435000005d3010000410000000002000414000005d30320009c0000000002018019000005d30340009c00000000040180190000004001400210000000c002200210000000000112019f00000634011001c700000001020000391747173d0000040f00000000030100190000006003300270000005d303300197000000200430008c000000000403001900000020040080390000001f0540018f0000000504400272000016260000613d00000000060000190000000507600210000000000871034f000000000808043b00000000008704350000000106600039000000000746004b0000161f0000413d000000000605004b000016340000613d00000003055002100000000504400210000000000604043300000000065601cf000000000656022f000000000741034f000000000707043b0000010005500089000000000757022f00000000055701cf000000000565019f0000000000540435000100000003001f000300000001035500000001022001900000000506000029000000040400002900000007050000290000000607000029000016ce0000613d0000000001000433000005d503100198000016b60000613d00000003020000290000000502200270000000000201001f0000000001050433000000410110008c0000169a0000c13d000700000003001d0000000001070433000006320210009c000016a10000213d000000020200002900000000020204330000000003040433000000400400043d0000006005400039000000000015043500000040014000390000000000310435000000f8012002700000002002400039000000000012043500000000006404350000000000000435000005d3010000410000000002000414000005d30320009c0000000002018019000005d30340009c00000000040180190000004001400210000000c002200210000000000112019f00000634011001c70000000102000039000600000002001d1747173d0000040f00000000030100190000006003300270000005d303300197000000200430008c000000000403001900000020040080390000001f0540018f0000000504400272000016740000613d00000000060000190000000507600210000000000871034f000000000808043b00000000008704350000000106600039000000000746004b0000166d0000413d000000000605004b000016820000613d00000003055002100000000504400210000000000604043300000000065601cf000000000656022f000000000741034f000000000707043b0000010005500089000000000757022f00000000055701cf000000000565019f0000000000540435000100000003001f00030000000103550000000102200190000016eb0000613d0000000001000433000005d5021001980000000703000029000016b60000613d000000000100041a000005d501100197000000000113004b0000000001000019000016950000c13d0000000601000029000000000101041a000005d501100197000000000112004b00000000010000190000000101006029000000000001042d000005e70100004100000000001004350000004101000039000016cb0000013d000000400100043d00000044021000390000063503000041000000000032043500000024021000390000001f03000039000016bc0000013d000000400100043d000000640210003900000610030000410000000000320435000000440210003900000637030000410000000000320435000000240210003900000022030000390000000000320435000005ec020000410000000000210435000000040210003900000020030000390000000000320435000005d302000041000005d30310009c00000000010280190000004001100210000005ed011001c70000174900010430000000400100043d000000440210003900000636030000410000000000320435000000240210003900000018030000390000000000320435000005ec020000410000000000210435000000040210003900000020030000390000000000320435000005d302000041000005d30310009c00000000010280190000004001100210000005ff011001c70000174900010430000005e70100004100000000001004350000003201000039000000040010043f000005e8010000410000174900010430000000400200043d0000001f0430018f0000000505300272000016db0000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000016d30000413d000000000604004b000017070000613d0000000505500210000000000151034f00000000055200190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f0000000000150435000017070000013d000000400200043d0000001f0430018f0000000505300272000016f80000613d000000000600001900000005076002100000000008720019000000000771034f000000000707043b00000000007804350000000106600039000000000756004b000016f00000413d000000000604004b000017070000613d0000000505500210000000000151034f00000000055200190000000304400210000000000605043300000000064601cf000000000646022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000161019f0000000000150435000005d301000041000005d30420009c000000000201801900000040012002100000006002300210000000000121019f000017490001043000000044013000390000063102000041000000000021043500000024013000390000000e020000390000000000210435000005ec010000410000000000130435000000040130003900000020020000390000000000210435000005d301000041000005d30230009c00000000030180190000004001300210000005ff011001c70000174900010430000000000001042f00000000050100190000000000200439000000040130008c000017270000a13d000000050140027000000000010100310000000400100443000005d3010000410000000002000414000005d30420009c0000000002018019000005d30430009c00000000030180190000006001300210000000c002200210000000000112019f00000638011001c700000000020500191747173d0000040f0000000102200190000017370000613d000000000101043b000000000001042d000000000001042f0000173b002104210000000102000039000000000001042d0000000002000019000000000001042d00001740002104230000000102000039000000000001042d0000000002000019000000000001042d00001745002104230000000102000039000000000001042d0000000002000019000000000001042d0000174700000432000017480001042e00001749000104300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000001ffffffe0000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000020000000000000000000000000000004000000100000000000000000000000000000000000000000000000000000000000000000000000000a28c1aed00000000000000000000000000000000000000000000000000000000e2f318e200000000000000000000000000000000000000000000000000000000e2f318e300000000000000000000000000000000000000000000000000000000eeb8cb0900000000000000000000000000000000000000000000000000000000a28c1aee00000000000000000000000000000000000000000000000000000000df9c1589000000000000000000000000000000000000000000000000000000005270972400000000000000000000000000000000000000000000000000000000527097250000000000000000000000000000000000000000000000000000000073688914000000000000000000000000000000000000000000000000000000001626ba7e00000000000000000000000000000000000000000000000000000000202bcce7000000000000000000000000000000000000000000000000ffffffffffffffff8000000000000000000000000000000000000000000000000000000000000000e1239cd8000000000000000000000000000000000000000000000000000000009cc7f708afc65944829bd487b90b72536b1951864fbfc14e125fc972a6507f394e487b7100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002400000000000000000000000002000000000000000000000000000000000000000000000000000000000000007261746f720000000000000000000000000000000000000000000000000000004661696c656420746f20706179207468652066656520746f20746865206f706508c379a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000084000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000000949431dc000000000000000000000000000000000000000000000000000000008c5a344500000000000000000000000000000000000000000000000000000000dd62ed3e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044000000800000000000000000095ea7b3000000000000000000000000000000000000000000000000000000005361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65641806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b83020000020000000000000000000000000000002400000000000000000000000000000000000000000000000000000000000000440000000000000000000000005361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f20746f206e6f6e2d7a65726f20616c6c6f77616e636500000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff7f000000000000000000000000000000000000000000000000ffffffffffffff3f6f742073756363656564000000000000000000000000000000000000000000005361666545524332303a204552433230206f7065726174696f6e20646964206e416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000000000000000000000000000000000000000006400000000000000000000000054686520617070726f76616c4261736564207061796d617374657220696e707574206d757374206265206174206c65617374203638206279746573206c6f6e670000000000000000000000000000000000000084000000800000000000000000556e737570706f72746564207061796d617374657220666c6f770000000000000000000000000000000000000000000000000064000000800000000000000000546865207374616e64617264207061796d617374657220696e707574206d757374206265206174206c656173742034206279746573206c6f6e6700000000000000000000000000000000000000000000000000200000008000000000000000004f6e6c7920626f6f746c6f616465722063616e2063616c6c2074686973206d6574686f640000000000000000000000000000000000000000000000000000000000000000ffffffff0000000000000000000000000000000000000000000000000100000000000000000000000000000000000024000000a00000000000000000202bcce7000000000000000000000000000000000000000000000000000000001626ba7e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000001000000000000000075650000000000000000000000000000000000000000000000000000000000004e6f7420656e6f7567682062616c616e636520666f7220666565202b2076616c000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000ffffffff000000000000000000000000000000000000000000000000ffffffff00000000000000000000000001000000000000000000000000000000000000000000000000000000000000004f766572666c6f770000000000000000000000000000000000000000000000009a8a0592ac89c5ad3bc6df8224c17b485976f597df104ee20d0df415241f670b0200000200000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffbf00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000ffffffffffffffffffffffffffffffff81000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000b800000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000f800000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6b656363616b3235362072657475726e656420696e76616c6964206461746100848e1bfa1ac4e3576b728bda6721b215c70a7799a5b4866282a71bab954baac8000000000000000000000000000000000000000000000000fffffffffffffe1fc2f8787176b8ac6bf7215b4adcc1e069bf4ab82d9ab1df05a57a91d425935b6ead7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a519b453ce45aaaaf3a300f5a9ec95869b4f28ab10430b572ee218c3a6a5e07d6f000000000000000000000000000000000000000000000000ffffffffffffff5f19010000000000000000000000000000000000000000000000000000000000008080000000000000000000000000000000000000000000000000000000000000456e636f64696e6720756e737570706f727465642074780000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff401b00000000000000000000000000000000000000000000000000000000000000496e76616c6964206c656e6774680000000000000000000000000000000000007fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a07fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a1000000000000000000000000000000000000008000000000000000000000000045434453413a20696e76616c6964207369676e6174757265206c656e6774680045434453413a20696e76616c6964207369676e6174757265000000000000000045434453413a20696e76616c6964207369676e6174757265202773272076616c020000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d448c295e929e696b285e58d46eeef7df7814594a3c50b601ee9abfe479ae5d", + "linkReferences": {}, + "deployedLinkReferences": {}, + "factoryDeps": {} +} \ No newline at end of file diff --git a/tests/integration/test_config.py b/tests/integration/test_config.py index ba0bd00..c4421f8 100644 --- a/tests/integration/test_config.py +++ b/tests/integration/test_config.py @@ -3,6 +3,22 @@ from enum import IntEnum, auto from eth_typing import HexStr from eth_utils import remove_0x_prefix +from web3 import Web3 + +from tests.unit.test_config import TestEnvironment + +DAI_L1 = Web3.to_checksum_address("0x70a0F165d6f8054d0d0CF8dFd4DD2005f0AF6B55") +approval_token = Web3.to_checksum_address("0x0183Fe07a98bc036d6eb23C3943d823bcD66a90F") +paymaster_address = Web3.to_checksum_address( + "0x594E77D36eB367b3AbAb98775c99eB383079F966" +) +multisig_address = Web3.to_checksum_address( + "0xe56070305f425AC6F19aa319fAe11BaD25cF19A9" +) +address_1 = Web3.to_checksum_address("0x36615Cf349d7F6344891B1e7CA7C72883F5dc049") +address_2 = Web3.to_checksum_address("0xa61464658AfeAf65CccaaFD3a512b69A83B77618") +private_key_1 = "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110" +private_key_2 = "0xac1e735be8536c6534bb4f17f06f6afc73b2b5ba84ac2cfb12f7461b20c0bbe3" class EnvPrivateKey: @@ -17,6 +33,19 @@ def key(self) -> bytes: return self._key +class EnvURL: + def __init__(self): + env: bool = os.getenv("IS_ETH_CHAIN", False) + if env: + self._env = LOCAL_ETH_ENV + else: + self._env = LOCAL_NON_ETH_ENV + + @property + def env(self) -> TestEnvironment: + return self._env + + class EnvType(IntEnum): LOCAL_HOST = auto() TESTNET = auto() @@ -30,6 +59,9 @@ class TestEnvironment: eth_server: str -LOCAL_ENV = TestEnvironment( - EnvType.LOCAL_HOST, "http://localhost:15100", "http://127.0.0.1:15045" +LOCAL_ETH_ENV = TestEnvironment( + EnvType.LOCAL_HOST, "http://127.0.0.1:15100", "http://127.0.0.1:15045" +) +LOCAL_NON_ETH_ENV = TestEnvironment( + EnvType.LOCAL_HOST, "http://127.0.0.1:15200", "http://127.0.0.1:15045" ) diff --git a/tests/integration/test_contract_factory.py b/tests/integration/test_contract_factory.py new file mode 100644 index 0000000..cb9a129 --- /dev/null +++ b/tests/integration/test_contract_factory.py @@ -0,0 +1,94 @@ +import os +from pathlib import Path +from unittest import TestCase + +from eth_account import Account +from eth_account.signers.local import LocalAccount +from eth_typing import HexStr + +from tests.integration.test_config import EnvURL, private_key_1 +from zksync2.core.types import EthBlockParams +from zksync2.manage_contracts.contract_factory import ( + LegacyContractFactory, + DeploymentType, +) +from zksync2.module.module_builder import ZkSyncBuilder +from zksync2.signer.eth_signer import PrivateKeyEthSigner + + +def generate_random_salt() -> bytes: + return os.urandom(32) + + +class ContractFactoryTest(TestCase): + + def setUp(self) -> None: + self.env = EnvURL() + self.provider = ZkSyncBuilder.build(self.env.env.zksync_server) + self.account: LocalAccount = Account.from_key(private_key_1) + self.chain_id = self.provider.zksync.chain_id + self.signer = PrivateKeyEthSigner(self.account, self.chain_id) + self.counter_address = None + self.test_tx_hash = None + self.some_erc20_address = None + + def test_contract_factory_create(self): + directory = Path(__file__).parent + path = directory / Path("../contracts/Counter.json") + deployer = LegacyContractFactory.from_json( + zksync=self.provider, + compiled_contract=path.resolve(), + account=self.account, + signer=self.signer, + ) + contract = deployer.deploy() + self.assertIsNotNone(self.provider.zksync.get_code(contract.address)) + + def test_contract_factory_crete2(self): + salt = generate_random_salt() + directory = Path(__file__).parent + path = directory / Path("../contracts/Counter.json") + deployer = LegacyContractFactory.from_json( + zksync=self.provider, + compiled_contract=path.resolve(), + account=self.account, + signer=self.signer, + deployment_type=DeploymentType.CREATE2, + ) + contract = deployer.deploy(salt=salt) + self.assertIsNotNone(self.provider.zksync.get_code(contract.address)) + + def test_contract_factory_crete2_with_args(self): + salt = generate_random_salt() + directory = Path(__file__).parent + path = directory / Path("../contracts/Token.json") + + constructor_arguments = {"name_": "Ducat", "symbol_": "Ducat", "decimals_": 18} + deployer = LegacyContractFactory.from_json( + zksync=self.provider, + compiled_contract=path.resolve(), + account=self.account, + signer=self.signer, + deployment_type=DeploymentType.CREATE2, + ) + contract = deployer.deploy(salt=salt, **constructor_arguments) + self.assertIsNotNone(self.provider.zksync.get_code(contract.address)) + + def test_deploy_paymaster(self): + salt = generate_random_salt() + directory = Path(__file__).parent + path = directory / "../contracts/Paymaster.json" + token_address = self.provider.to_checksum_address( + "0x0183Fe07a98bc036d6eb23C3943d823bcD66a90F" + ) + constructor_arguments = {"_erc20": token_address} + + deployer = LegacyContractFactory.from_json( + zksync=self.provider, + compiled_contract=path.resolve(), + account=self.account, + signer=self.signer, + deployment_type=DeploymentType.CREATE2_ACCOUNT, + ) + contract = deployer.deploy(salt=salt, **constructor_arguments) + self.assertIsNotNone(self.provider.zksync.get_code(contract.address)) diff --git a/tests/integration/test_paymaster.py b/tests/integration/test_paymaster.py index 5b56865..d6d70b8 100644 --- a/tests/integration/test_paymaster.py +++ b/tests/integration/test_paymaster.py @@ -1,12 +1,16 @@ from decimal import Decimal from pathlib import Path -from unittest import TestCase, skip +from unittest import TestCase + +from eth_account import Account +from eth_account.signers.local import LocalAccount from eth_typing import HexStr -from eth_utils import keccak, remove_0x_prefix +from eth_utils import keccak from web3 import Web3 -from tests.integration.test_config import LOCAL_ENV +from tests.integration.test_config import EnvURL, private_key_1 from tests.integration.test_zksync_contract import generate_random_salt +from zksync2.core.types import Token, EthBlockParams, PaymasterParams from zksync2.manage_contracts.contract_encoder_base import ( ContractEncoder, JsonConfiguration, @@ -18,11 +22,7 @@ ) from zksync2.manage_contracts.utils import nonce_holder_abi_default from zksync2.module.module_builder import ZkSyncBuilder -from zksync2.core.types import Token, EthBlockParams, ZkBlockParams, PaymasterParams -from eth_account import Account -from eth_account.signers.local import LocalAccount from zksync2.signer.eth_signer import PrivateKeyEthSigner -from tests.contracts.utils import contract_path from zksync2.transaction.transaction_builders import ( TxFunctionCall, TxCreate2Contract, @@ -30,10 +30,6 @@ ) -# mint tx hash of Test coins: -# https://goerli.explorer.zksync.io/address/0xFC174650BDEbE4D94736442307D4D7fdBe799EeC#contract - - class PaymasterTests(TestCase): ETH_TOKEN = Token.create_eth() PRIVATE_KEY = bytes.fromhex( @@ -43,20 +39,21 @@ class PaymasterTests(TestCase): ETH_TEST_NET_AMOUNT_BALANCE = Decimal(1) SERC20_TOKEN = Token( - Web3.to_checksum_address("0x" + "0" * 40), - Web3.to_checksum_address("0xFC174650BDEbE4D94736442307D4D7fdBe799EeC"), - "SERC20", - 18, + l1_address=Web3.to_checksum_address("0x" + "0" * 40), + l2_address=Web3.to_checksum_address( + "0xFC174650BDEbE4D94736442307D4D7fdBe799EeC" + ), + name="SERC20", + symbol="SERC20", + decimals=18, ) SALT = keccak(text="TestPaymaster") def setUp(self) -> None: - self.env = LOCAL_ENV - self.web3 = ZkSyncBuilder.build(self.env.zksync_server) - self.account: LocalAccount = Account.from_key( - "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110" - ) + self.env = EnvURL() + self.web3 = ZkSyncBuilder.build(self.env.env.zksync_server) + self.account: LocalAccount = Account.from_key(private_key_1) self.chain_id = self.web3.zksync.chain_id self.signer = PrivateKeyEthSigner(self.account, self.chain_id) # self.custom_paymaster = ContractEncoder.from_json(self.web3, contract_path("CustomPaymaster.json")) @@ -166,7 +163,7 @@ def test_paymaster(self): ) signed = self.account.sign_transaction(mint_tx) - tx_hash = self.web3.zksync.send_raw_transaction(signed.rawTransaction) + tx_hash = self.web3.zksync.send_raw_transaction(signed.raw_transaction) self.web3.zksync.wait_for_transaction_receipt( tx_hash, timeout=240, poll_latency=0.5 ) @@ -195,9 +192,7 @@ def test_paymaster(self): tx_hash, timeout=240, poll_latency=0.5 ) - calladata = token_contract.encodeABI( - fn_name="mint", args=[self.account.address, 7] - ) + calladata = token_contract.encode_abi("mint", args=[self.account.address, 7]) paymaster_params = PaymasterParams( **{ diff --git a/tests/integration/test_smart_account.py b/tests/integration/test_smart_account.py new file mode 100644 index 0000000..46d47f7 --- /dev/null +++ b/tests/integration/test_smart_account.py @@ -0,0 +1,247 @@ +from unittest import TestCase + +from eth_account import Account +from eth_typing import HexStr +from web3 import Web3 + +from tests.integration.test_config import ( + address_1, + address_2, + DAI_L1, + EnvURL, + private_key_1, +) +from zksync2.account.smart_account import SmartAccount +from zksync2.account.smart_account_utils import ( + sign_payload_with_ecdsa, + populate_transaction_ecdsa, +) +from zksync2.account.wallet import Wallet +from zksync2.core.types import ( + TransferTransaction, + ADDRESS_DEFAULT, + ZkBlockParams, + WithdrawTransaction, + ETH_ADDRESS_IN_CONTRACTS, +) +from zksync2.module.module_builder import ZkSyncBuilder +from zksync2.transaction.transaction_builders import TxTransfer + + +class TestSmartAccount(TestCase): + + def setUp(self) -> None: + env = EnvURL() + self.zksync = ZkSyncBuilder.build(env.env.zksync_server) + self.eth_web3 = Web3(Web3.HTTPProvider(env.env.eth_server)) + self.wallet = Wallet( + self.zksync, self.eth_web3, Account.from_key(private_key_1) + ) + self.account = SmartAccount( + address_1, + HexStr(private_key_1), + self.zksync, + populate_transaction_ecdsa, + sign_payload_with_ecdsa, + ) + + def test_get_address(self): + result = self.account.get_address + self.assertEqual(address_1, result) + + def test_get_balance(self): + result = self.account.get_balance() + self.assertGreater(result, 0) + + def test_get_all_balances(self): + result = self.account.get_all_balances() + expected = 2 if self.wallet.is_eth_based_chain() else 3 + self.assertEqual(len(result), expected) + + def test_get_deployment_nonce(self): + result = self.account.get_deployment_nonce() + self.assertIsNotNone(result) + + def test_populate_transaction(self): + result = self.account.populate_transaction( + TxTransfer( + from_=address_1, + to=address_2, + value=7_000_000_000, + token=ADDRESS_DEFAULT, + ) + ) + self.assertIsNotNone(result) + + def test_transfer_eth(self): + if self.wallet.is_eth_based_chain(): + amount = 7_000_000_000 + balance_before_transfer = self.zksync.zksync.zks_get_balance( + Web3.to_checksum_address(address_2), token_address=ADDRESS_DEFAULT + ) + tx_hash = self.account.transfer( + TransferTransaction( + to=Web3.to_checksum_address(address_2), + token_address=ADDRESS_DEFAULT, + amount=amount, + ) + ) + + self.zksync.zksync.wait_for_transaction_receipt( + tx_hash, timeout=240, poll_latency=0.5 + ) + balance_after_transfer = self.zksync.zksync.zks_get_balance( + Web3.to_checksum_address(address_2), token_address=ADDRESS_DEFAULT + ) + + self.assertEqual(balance_after_transfer - balance_before_transfer, amount) + else: + amount = 7_000_000_000 + l2_token = self.wallet.l2_token_address(ETH_ADDRESS_IN_CONTRACTS) + balance_before_transfer = self.zksync.zksync.zks_get_balance( + Web3.to_checksum_address(address_2), token_address=l2_token + ) + tx_hash = self.account.transfer( + TransferTransaction( + to=Web3.to_checksum_address(address_2), + token_address=ADDRESS_DEFAULT, + amount=amount, + ) + ) + + self.zksync.zksync.wait_for_transaction_receipt( + tx_hash, timeout=240, poll_latency=0.5 + ) + balance_after_transfer = self.zksync.zksync.zks_get_balance( + Web3.to_checksum_address(address_2), token_address=l2_token + ) + + self.assertEqual(balance_after_transfer - balance_before_transfer, amount) + + def test_transfer_token(self): + amount = 5 + l2_address = self.wallet.l2_token_address(DAI_L1) + + sender_before = self.wallet.get_balance(token_address=l2_address) + balance_before = self.zksync.zksync.zks_get_balance( + address_2, + token_address=l2_address, + block_tag=ZkBlockParams.LATEST.value, + ) + tx_hash = self.account.transfer( + TransferTransaction( + to=Web3.to_checksum_address(address_2), + token_address=Web3.to_checksum_address(l2_address), + amount=amount, + ) + ) + + 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( + address_2, + 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_withdraw_eth(self): + if self.wallet.is_eth_based_chain(): + l2_balance_before = self.wallet.get_balance(token_address=ADDRESS_DEFAULT) + amount = 7_000_000_000 + + withdraw_tx_hash = self.account.withdraw( + WithdrawTransaction(token=ADDRESS_DEFAULT, amount=amount) + ) + + 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"] + ) + result = self.eth_web3.eth.wait_for_transaction_receipt( + finalized_hash, timeout=240, poll_latency=0.5 + ) + + l2_balance_after = self.account.get_balance(token_address=ADDRESS_DEFAULT) + + self.assertIsNotNone(result) + self.assertGreater( + l2_balance_before, + l2_balance_after, + "L2 balance should be lower after withdrawal", + ) + else: + l2_token = self.wallet.l2_token_address(ETH_ADDRESS_IN_CONTRACTS) + l2_balance_before = self.wallet.get_balance(token_address=l2_token) + amount = 7_000_000_000 + + withdraw_tx_hash = self.wallet.withdraw( + WithdrawTransaction(token=ADDRESS_DEFAULT, amount=amount) + ) + + 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"] + ) + result = self.eth_web3.eth.wait_for_transaction_receipt( + finalized_hash, timeout=240, poll_latency=0.5 + ) + + l2_balance_after = self.account.get_balance(token_address=l2_token) + + self.assertIsNotNone(result) + self.assertGreater( + l2_balance_before, + l2_balance_after, + "L2 balance should be lower after withdrawal", + ) + + def test_withdraw_token(self): + l2_address = self.wallet.l2_token_address(DAI_L1) + l2_balance_before = self.wallet.get_balance( + token_address=Web3.to_checksum_address(l2_address) + ) + + withdraw_tx_hash = self.account.withdraw( + WithdrawTransaction(Web3.to_checksum_address(l2_address), 5) + ) + 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"] + ) + result = self.eth_web3.eth.wait_for_transaction_receipt( + finalized_hash, timeout=240, poll_latency=0.5 + ) + + l2_balance_after = self.wallet.get_balance( + token_address=Web3.to_checksum_address(l2_address) + ) + + self.assertIsNotNone(result) + self.assertGreater( + l2_balance_before, + l2_balance_after, + "L2 balance should be lower after withdrawal", + ) diff --git a/tests/integration/test_smart_account_multisig.py b/tests/integration/test_smart_account_multisig.py new file mode 100644 index 0000000..dd13c37 --- /dev/null +++ b/tests/integration/test_smart_account_multisig.py @@ -0,0 +1,242 @@ +from unittest import TestCase + +from eth_account import Account +from eth_typing import HexStr +from web3 import Web3 + +from tests.integration.test_config import ( + EnvURL, + address_1, + address_2, + DAI_L1, + private_key_1, + multisig_address, + private_key_2, +) +from zksync2.account.smart_account import SmartAccount, MultisigECDSASmartAccount +from zksync2.account.wallet import Wallet +from zksync2.core.types import ( + TransferTransaction, + ADDRESS_DEFAULT, + ZkBlockParams, + WithdrawTransaction, + ETH_ADDRESS_IN_CONTRACTS, +) +from zksync2.module.module_builder import ZkSyncBuilder +from zksync2.transaction.transaction_builders import TxTransfer + + +class TestSmartAccount(TestCase): + + def setUp(self) -> None: + self.env = EnvURL() + self.zksync = ZkSyncBuilder.build(self.env.env.zksync_server) + self.eth_web3 = Web3(Web3.HTTPProvider(self.env.env.eth_server)) + self.wallet = Wallet( + self.zksync, self.eth_web3, Account.from_key(private_key_1) + ) + self.base_account = Account.from_key(private_key_1) + self.account: SmartAccount = MultisigECDSASmartAccount.create( + multisig_address, [private_key_1, private_key_2], self.zksync + ) + + def test_get_address(self): + result = self.account.get_address + self.assertEqual(multisig_address, result) + + def test_get_balance(self): + result = self.account.get_balance() + self.assertGreater(result, 0) + + def test_get_all_balances(self): + result = self.account.get_all_balances() + expected = 2 if self.wallet.is_eth_based_chain() else 3 + self.assertEqual(len(result), expected) + + def test_get_deployment_nonce(self): + result = self.account.get_deployment_nonce() + self.assertIsNotNone(result) + + def test_populate_transaction(self): + result = self.account.populate_transaction( + TxTransfer( + from_=multisig_address, + to=address_2, + value=7_000_000_000, + token=ADDRESS_DEFAULT, + ) + ) + self.assertIsNotNone(result) + + def test_transfer_eth(self): + if self.wallet.is_eth_based_chain(): + amount = 7_000_000 + balance_before_transfer = self.zksync.zksync.zks_get_balance( + Web3.to_checksum_address(address_2), token_address=ADDRESS_DEFAULT + ) + tx_hash = self.account.transfer( + TransferTransaction( + to=Web3.to_checksum_address(address_2), + token_address=ADDRESS_DEFAULT, + amount=amount, + ) + ) + + self.zksync.zksync.wait_for_transaction_receipt( + tx_hash, timeout=240, poll_latency=0.5 + ) + balance_after_transfer = self.zksync.zksync.zks_get_balance( + Web3.to_checksum_address(address_2), token_address=ADDRESS_DEFAULT + ) + + self.assertEqual(balance_after_transfer - balance_before_transfer, amount) + else: + amount = 7_000_000_000 + l2_token = self.wallet.l2_token_address(ETH_ADDRESS_IN_CONTRACTS) + balance_before_transfer = self.zksync.zksync.zks_get_balance( + Web3.to_checksum_address(address_2), token_address=l2_token + ) + tx_hash = self.account.transfer( + TransferTransaction( + to=Web3.to_checksum_address(address_2), + token_address=ADDRESS_DEFAULT, + amount=amount, + ) + ) + + self.zksync.zksync.wait_for_transaction_receipt( + tx_hash, timeout=240, poll_latency=0.5 + ) + balance_after_transfer = self.zksync.zksync.zks_get_balance( + Web3.to_checksum_address(address_2), token_address=l2_token + ) + + self.assertEqual(balance_after_transfer - balance_before_transfer, amount) + + def test_transfer_token(self): + amount = 5 + l2_address = self.wallet.l2_token_address(DAI_L1) + + sender_before = self.account.get_balance(token_address=l2_address) + balance_before = self.zksync.zksync.zks_get_balance( + address_2, + token_address=l2_address, + block_tag=ZkBlockParams.LATEST.value, + ) + tx_hash = self.account.transfer( + TransferTransaction( + to=Web3.to_checksum_address(address_2), + token_address=Web3.to_checksum_address(l2_address), + amount=amount, + ) + ) + + result = self.zksync.zksync.wait_finalized( + tx_hash, timeout=240, poll_latency=0.5 + ) + self.assertIsNotNone(result) + sender_after = self.account.get_balance(token_address=l2_address) + + balance_after = self.zksync.zksync.zks_get_balance( + address_2, + 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_withdraw_eth(self): + if self.wallet.is_eth_based_chain(): + l2_balance_before = self.wallet.get_balance(token_address=ADDRESS_DEFAULT) + amount = 7_000_000 + + withdraw_tx_hash = self.account.withdraw( + WithdrawTransaction(token=ADDRESS_DEFAULT, amount=amount, to=address_2) + ) + + 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"] + ) + result = self.eth_web3.eth.wait_for_transaction_receipt( + finalized_hash, timeout=240, poll_latency=0.5 + ) + + l2_balance_after = self.account.get_balance(token_address=ADDRESS_DEFAULT) + + self.assertIsNotNone(result) + self.assertGreater( + l2_balance_before, + l2_balance_after, + "L2 balance should be lower after withdrawal", + ) + else: + l2_token = self.wallet.l2_token_address(ETH_ADDRESS_IN_CONTRACTS) + l2_balance_before = self.wallet.get_balance(token_address=l2_token) + amount = 7_000_000_000 + + withdraw_tx_hash = self.wallet.withdraw( + WithdrawTransaction(token=ADDRESS_DEFAULT, amount=amount) + ) + + 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"] + ) + result = self.eth_web3.eth.wait_for_transaction_receipt( + finalized_hash, timeout=240, poll_latency=0.5 + ) + + l2_balance_after = self.account.get_balance(token_address=l2_token) + + self.assertIsNotNone(result) + self.assertGreater( + l2_balance_before, + l2_balance_after, + "L2 balance should be lower after withdrawal", + ) + + def test_withdraw_token(self): + l2_address = self.wallet.l2_token_address(DAI_L1) + l2_balance_before = self.account.get_balance( + token_address=Web3.to_checksum_address(l2_address) + ) + + withdraw_tx_hash = self.account.withdraw( + WithdrawTransaction(Web3.to_checksum_address(l2_address), 5) + ) + 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"] + ) + result = self.eth_web3.eth.wait_for_transaction_receipt( + finalized_hash, timeout=240, poll_latency=0.5 + ) + + l2_balance_after = self.account.get_balance( + token_address=Web3.to_checksum_address(l2_address) + ) + + self.assertIsNotNone(result) + self.assertGreater( + l2_balance_before, + l2_balance_after, + "L2 balance should be lower after withdrawal", + ) diff --git a/tests/integration/test_wallet.py b/tests/integration/test_wallet.py index ab1bd3e..2e43243 100644 --- a/tests/integration/test_wallet.py +++ b/tests/integration/test_wallet.py @@ -1,22 +1,27 @@ import json -from asyncio import sleep from pathlib import Path -from unittest import TestCase, skip +from unittest import TestCase from eth_account import Account from eth_account.signers.local import LocalAccount from eth_typing import HexStr -from hexbytes import HexBytes from web3 import Web3 -from tests.integration.test_config import LOCAL_ENV, EnvPrivateKey +from tests.integration.test_config import ( + EnvURL, + private_key_1, + address_1, + paymaster_address, + approval_token, + DAI_L1, + address_2, +) from zksync2.account.wallet import Wallet from zksync2.core.types import ( Token, DepositTransaction, ADDRESS_DEFAULT, RequestExecuteCallMsg, - TransactionOptions, TransferTransaction, WithdrawTransaction, EthBlockParams, @@ -25,7 +30,6 @@ ) from zksync2.core.utils import ( LEGACY_ETH_ADDRESS, - ETH_ADDRESS_IN_CONTRACTS, L2_BASE_TOKEN_ADDRESS, ) from zksync2.manage_contracts.contract_encoder_base import ( @@ -35,29 +39,20 @@ from zksync2.manage_contracts.paymaster_utils import PaymasterFlowEncoder from zksync2.manage_contracts.utils import ( get_zksync_hyperchain, - get_erc20_abi, - get_test_net_erc20_token, ) from zksync2.module.module_builder import ZkSyncBuilder class TestWallet(TestCase): def setUp(self) -> None: - self.DAI_L1 = Web3.to_checksum_address( - "0x70a0F165d6f8054d0d0CF8dFd4DD2005f0AF6B55" - ) - self.token_address = "0x0183Fe07a98bc036d6eb23C3943d823bcD66a90F" - self.paymaster_address = "0x594E77D36eB367b3AbAb98775c99eB383079F966" - self.address2 = "0xa61464658AfeAf65CccaaFD3a512b69A83B77618" - self.CONTRACT_ADDRESS = "0x36615Cf349d7F6344891B1e7CA7C72883F5dc049" - self.env = LOCAL_ENV - env_key = EnvPrivateKey("ZKSYNC_KEY1") - self.zksync = ZkSyncBuilder.build("http://127.0.0.1:15100") - self.eth_web3 = Web3(Web3.HTTPProvider("http://127.0.0.1:15045")) - self.account: LocalAccount = Account.from_key(env_key.key) + self.env = EnvURL() + # self.w3 = Web3(Web3.HTTPProvider('YOUR_ZKSYNC_RPC_URL')) + self.zksync = ZkSyncBuilder.build(self.env.env.zksync_server) + self.eth_web3 = Web3(Web3.HTTPProvider(self.env.env.eth_server)) + self.account: LocalAccount = Account.from_key(private_key_1) self.wallet = Wallet(self.zksync, self.eth_web3, self.account) self.zksync_contract = self.eth_web3.eth.contract( - Web3.to_checksum_address(self.zksync.zksync.main_contract_address), + Web3.to_checksum_address(self.zksync.zksync.zks_main_contract()), abi=get_zksync_hyperchain(), ) self.is_eth_based_chain = self.wallet.is_eth_based_chain() @@ -105,7 +100,7 @@ def test_get_l2_token_address(self): ) def test_get_l2_token_address_dai(self): - address = self.wallet.l2_token_address(self.DAI_L1) + address = self.wallet.l2_token_address(DAI_L1) self.assertIsNotNone(address) def test_approve_erc20(self): @@ -113,6 +108,7 @@ def test_approve_erc20(self): Web3.to_checksum_address("0xd35cceead182dcee0f148ebac9447da2c4d449c4"), Web3.to_checksum_address("0x852a4599217e76aa725f0ada8bf832a1f57a8a91"), "USDC", + "USDC", 6, ) @@ -149,54 +145,101 @@ def test_get_deployment_nonce(self): self.assertIsNotNone(nonce, "Should return deployment nonce") def test_prepare_deposit_transaction(self): - tx = RequestExecuteCallMsg( - contract_address=self.CONTRACT_ADDRESS, - call_data="0x", - operator_tip=0, - l2_value=7_000_000, - gas_per_pubdata_byte=800, - refund_recipient=self.wallet.address, - ) - transaction = self.wallet.prepare_deposit_tx( - DepositTransaction( - token=LEGACY_ETH_ADDRESS, - amount=7_000_000, + if self.wallet.is_eth_based_chain(): + tx = RequestExecuteCallMsg( + contract_address=address_1, + call_data=HexStr("0x"), + operator_tip=0, + l2_value=7_000_000, + gas_per_pubdata_byte=800, refund_recipient=self.wallet.address, ) - ) - self.assertGreater(transaction.l2_gas_limit, 0) - self.assertGreater(transaction.mint_value, 0) - self.assertGreater(transaction.options.max_fee_per_gas, 0) - self.assertGreater(transaction.options.max_priority_fee_per_gas, 0) - self.assertGreater(transaction.options.value, 0) + transaction = self.wallet.prepare_deposit_tx( + DepositTransaction( + token=LEGACY_ETH_ADDRESS, + amount=7_000_000, + refund_recipient=self.wallet.address, + ) + ) + self.assertGreater(transaction.l2_gas_limit, 0) + self.assertGreater(transaction.mint_value, 0) + self.assertGreater(transaction.options.max_fee_per_gas, 0) + self.assertGreater(transaction.options.max_priority_fee_per_gas, 0) + self.assertGreater(transaction.options.value, 0) + + del transaction.l2_gas_limit + del transaction.mint_value + del transaction.options + + del tx.l2_gas_limit + del tx.mint_value + del tx.options + + self.assertEqual(tx, transaction) + else: + basse_token = self.wallet.get_base_token() + tx = RequestExecuteCallMsg( + contract_address=address_1, + call_data=HexStr("0x"), + operator_tip=0, + l2_value=7_000_000, + gas_per_pubdata_byte=800, + refund_recipient=self.wallet.address, + ) + transaction = self.wallet.prepare_deposit_tx( + DepositTransaction( + token=basse_token, + amount=7_000_000, + refund_recipient=self.wallet.address, + ) + ) + self.assertGreater(transaction.l2_gas_limit, 0) + self.assertGreater(transaction.mint_value, 0) + self.assertGreater(transaction.options.max_fee_per_gas, 0) + self.assertGreater(transaction.options.max_priority_fee_per_gas, 0) + self.assertEqual(transaction.options.value, 0) - del transaction.l2_gas_limit - del transaction.mint_value - del transaction.options + del transaction.l2_gas_limit + del transaction.mint_value + del transaction.options - del tx.l2_gas_limit - del tx.mint_value - del tx.options + del tx.l2_gas_limit + del tx.mint_value + del tx.options - self.assertEqual(tx, transaction) + self.assertEqual(tx, transaction) def test_prepare_deposit_transaction_token(self): - l1_address, l2_address = self.load_token() + if self.wallet.is_eth_based_chain(): + l1_address, l2_address = self.load_token() - print(self.wallet.get_l1_balance(l1_address)) + transaction = self.wallet.prepare_deposit_tx( + DepositTransaction( + token=l1_address, + amount=5, + refund_recipient=self.wallet.address, + approve_erc20=True, + ) + ) - transaction = self.wallet.prepare_deposit_tx( - DepositTransaction( - token=l1_address, - amount=5, - refund_recipient=self.wallet.address, - approve_erc20=True, + self.assertGreater(transaction["maxFeePerGas"], 0) + self.assertGreater(transaction["maxPriorityFeePerGas"], 0) + self.assertGreater(transaction["value"], 0) + else: + l1_address, l2_address = self.load_token() + + transaction = self.wallet.prepare_deposit_tx( + DepositTransaction( + token=l1_address, + amount=5, + refund_recipient=self.wallet.address, + approve_erc20=True, + ) ) - ) - self.assertGreater(transaction["maxFeePerGas"], 0) - self.assertGreater(transaction["maxPriorityFeePerGas"], 0) - self.assertGreater(transaction["value"], 0) + self.assertGreater(transaction["maxFeePerGas"], 0) + self.assertGreater(transaction["maxPriorityFeePerGas"], 0) + self.assertEqual(transaction["value"], 0) def test_estimate_eth_gas_deposit(self): if self.is_eth_based_chain: @@ -383,10 +426,6 @@ def test_deposit_erc_20_token(self): if self.is_eth_based_chain: amount = 100 l1_address, l2_address = self.load_token() - # is_approved = self.wallet.approve_erc20( - # Web3.to_checksum_address(l1_address), amount - # ) - # self.assertTrue(is_approved) balance_l2_beore = self.wallet.get_balance( token_address=Web3.to_checksum_address(l2_address) @@ -535,47 +574,46 @@ def test_full_required_deposit_fee_base_token(self): def test_transfer_eth(self): amount = 7_000_000_000 balance_before_transfer = self.zksync.zksync.zks_get_balance( - Web3.to_checksum_address(self.address2), token_address=LEGACY_ETH_ADDRESS + Web3.to_checksum_address(address_2), token_address=LEGACY_ETH_ADDRESS ) tx_hash = self.wallet.transfer( TransferTransaction( - to=Web3.to_checksum_address(self.address2), + to=Web3.to_checksum_address(address_2), token_address=ADDRESS_DEFAULT, amount=amount, ) ) - self.zksync.zksync.wait_for_transaction_receipt( + a = self.zksync.zksync.wait_for_transaction_receipt( tx_hash, timeout=240, poll_latency=0.5 ) - balance_after_transfer = self.zksync.zksync.zks_get_balance( - Web3.to_checksum_address(self.address2), token_address=LEGACY_ETH_ADDRESS - ) - - self.assertEqual(balance_after_transfer - balance_before_transfer, amount) + print(a) + # balance_after_transfer = self.zksync.get_balance( + # Web3.to_checksum_address(address_2), token_address=LEGACY_ETH_ADDRESS + # ) + # + # self.assertEqual(balance_after_transfer - balance_before_transfer, amount) def test_transfer_eth_paymaster(self): amount = 7_000_000_000 - 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 + paymaster_address, token_address=approval_token ) sender_balance_before = self.wallet.get_balance() sender_approval_token_balance_before = self.wallet.get_balance( - token_address=token_address + token_address=approval_token ) - reciever_balance_before = self.zksync.zksync.zks_get_balance(self.address2) + reciever_balance_before = self.zksync.zksync.zks_get_balance(address_2) 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"" + approval_token, 1, b"" ) ), } @@ -583,7 +621,7 @@ def test_transfer_eth_paymaster(self): tx_hash = self.wallet.transfer( TransferTransaction( - to=Web3.to_checksum_address(self.address2), + to=Web3.to_checksum_address(address_2), token_address=ADDRESS_DEFAULT, amount=amount, paymaster_params=paymaster_params, @@ -596,13 +634,13 @@ 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_address, token_address=approval_token ) sender_balance_after = self.wallet.get_balance() sender_approval_token_balance_after = self.wallet.get_balance( - token_address=token_address + token_address=approval_token ) - reciever_balance_after = self.zksync.zksync.zks_get_balance(self.address2) + reciever_balance_after = self.zksync.zksync.zks_get_balance(address_2) self.assertGreaterEqual(paymaster_balance_before - paymaster_balance_after, 0) self.assertGreaterEqual( @@ -615,7 +653,7 @@ def test_transfer_eth_paymaster(self): ) self.assertGreaterEqual(reciever_balance_after - reciever_balance_before, 0) - @skip("Used only for development purpose to refill paymaster") + # @skip("Used only for development purpose to refill paymaster") def test_mint_paymaster(self): directory = Path(__file__).parent path = directory / Path("../contracts/Token.json") @@ -624,12 +662,12 @@ 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.eth.contract( + Web3.to_checksum_address(approval_token), abi=abi ) balance_before = self.wallet.get_balance( - token_address=Web3.to_checksum_address(self.token_address) + token_address=Web3.to_checksum_address(approval_token) ) mint_tx = token_contract.functions.mint( self.wallet.address, 15 @@ -645,12 +683,12 @@ def test_mint_paymaster(self): ) signed = self.wallet.sign_transaction(mint_tx) - tx_hash = self.zksync.eth.send_raw_transaction(signed.rawTransaction) + tx_hash = self.zksync.eth.send_raw_transaction(signed.raw_transaction) self.zksync.zksync.wait_for_transaction_receipt( tx_hash, timeout=240, poll_latency=0.5 ) balance_after = self.wallet.get_balance( - token_address=Web3.to_checksum_address(self.token_address) + token_address=Web3.to_checksum_address(approval_token) ) self.assertEqual(15, balance_after - balance_before) @@ -661,13 +699,13 @@ def test_transfer_token(self): sender_before = self.wallet.get_balance(token_address=l2_address) balance_before = self.zksync.zksync.zks_get_balance( - self.address2, + address_2, token_address=l2_address, block_tag=ZkBlockParams.LATEST.value, ) tx_hash = self.wallet.transfer( TransferTransaction( - to=Web3.to_checksum_address(self.address2), + to=Web3.to_checksum_address(address_2), token_address=Web3.to_checksum_address(l2_address), amount=amount, ) @@ -680,7 +718,7 @@ 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, + address_2, token_address=l2_address, block_tag=ZkBlockParams.LATEST.value, ) @@ -692,13 +730,10 @@ 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, + token_address=approval_token, block_tag=ZkBlockParams.LATEST.value, ) @@ -706,10 +741,10 @@ def test_transfer_token_paymaster(self): token_address=Web3.to_checksum_address(l2_address) ) sender_approval_token_balance_before = self.wallet.get_balance( - token_address=token_address + token_address=approval_token ) reciever_balance_before = self.zksync.zksync.zks_get_balance( - self.address2, + address_2, token_address=Web3.to_checksum_address(l2_address), block_tag=ZkBlockParams.LATEST.value, ) @@ -719,7 +754,7 @@ def test_transfer_token_paymaster(self): "paymaster": paymaster_address, "paymaster_input": self.eth_web3.to_bytes( hexstr=PaymasterFlowEncoder(self.eth_web3).encode_approval_based( - token_address, 1, b"" + approval_token, 1, b"" ) ), } @@ -727,7 +762,7 @@ def test_transfer_token_paymaster(self): tx_hash = self.wallet.transfer( TransferTransaction( - to=Web3.to_checksum_address(self.address2), + to=Web3.to_checksum_address(address_2), token_address=Web3.to_checksum_address(l2_address), amount=amount, paymaster_params=paymaster_params, @@ -738,7 +773,7 @@ def test_transfer_token_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, + token_address=approval_token, block_tag=ZkBlockParams.LATEST.value, ) @@ -746,10 +781,10 @@ def test_transfer_token_paymaster(self): token_address=Web3.to_checksum_address(l2_address) ) sender_approval_token_balance_after = self.wallet.get_balance( - token_address=token_address + token_address=approval_token ) reciever_balance_after = self.zksync.zksync.zks_get_balance( - self.address2, + address_2, token_address=Web3.to_checksum_address(l2_address), block_tag=ZkBlockParams.LATEST.value, ) @@ -776,7 +811,6 @@ def test_withdraw_eth(self): withdraw_receipt = self.zksync.zksync.wait_finalized( withdraw_tx_hash, timeout=240, poll_latency=0.5 ) - print(withdraw_receipt["transactionHash"]) self.assertFalse( self.wallet.is_withdrawal_finalized(withdraw_receipt["transactionHash"]) ) @@ -799,19 +833,18 @@ def test_withdraw_eth(self): def test_withdraw_eth_paymaster(self): amount = 7_000_000_000 - 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, + token_address=approval_token, block_tag=ZkBlockParams.LATEST, ) - sender_balance_before = self.wallet.get_balance() + sender_balance_before = self.wallet.get_balance( + token_address=LEGACY_ETH_ADDRESS + ) sender_approval_token_balance_before = self.wallet.get_balance( - token_address=token_address + token_address=approval_token ) paymaster_params = PaymasterParams( @@ -819,14 +852,14 @@ def test_withdraw_eth_paymaster(self): "paymaster": paymaster_address, "paymaster_input": self.eth_web3.to_bytes( hexstr=PaymasterFlowEncoder(self.eth_web3).encode_approval_based( - token_address, 1, b"" + approval_token, 1, b"" ) ), } ) withdraw_tx_hash = self.wallet.withdraw( WithdrawTransaction( - token=Token.create_eth().l1_address, + token=LEGACY_ETH_ADDRESS, amount=amount, paymaster_params=paymaster_params, ) @@ -848,12 +881,12 @@ def test_withdraw_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, + token_address=approval_token, block_tag=ZkBlockParams.LATEST, ) - sender_balance_after = self.wallet.get_balance() + sender_balance_after = self.wallet.get_balance(token_address=LEGACY_ETH_ADDRESS) sender_approval_token_balance_after = self.wallet.get_balance( - token_address=token_address + token_address=approval_token ) self.assertGreater(paymaster_balance_before - paymaster_balance_after, 0) @@ -868,20 +901,18 @@ def test_withdraw_eth_paymaster(self): 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, + token_address=approval_token, 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 + token_address=approval_token ) paymaster_params = PaymasterParams( @@ -889,7 +920,7 @@ def test_withdraw_token_paymaster(self): "paymaster": paymaster_address, "paymaster_input": self.eth_web3.to_bytes( hexstr=PaymasterFlowEncoder(self.eth_web3).encode_approval_based( - token_address, 1, b"" + approval_token, 1, b"" ) ), } @@ -912,14 +943,14 @@ def test_withdraw_token_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, + token_address=approval_token, 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 + token_address=approval_token ) self.assertGreaterEqual(paymaster_balance_before - paymaster_balance_after, 0) @@ -967,15 +998,37 @@ def test_withdraw_token(self): ) def test_get_request_execute_transaction(self): - result = self.wallet.get_request_execute_transaction( - RequestExecuteCallMsg( - contract_address=self.zksync_contract.address, + if self.wallet.is_eth_based_chain(): + result = self.wallet.get_request_execute_transaction( + RequestExecuteCallMsg( + contract_address=self.zksync_contract.address, + call_data=HexStr("0x"), + l2_value=7_000_000_000, + ) + ) + + self.assertIsNotNone(result) + else: + request = RequestExecuteCallMsg( + contract_address=Web3.to_checksum_address( + self.zksync.zksync.zks_get_bridgehub_contract_address() + ), call_data=HexStr("0x"), l2_value=7_000_000_000, + l2_gas_limit=900_000, + ) + approve_params = self.wallet.get_request_execute_allowance_params(request) + + self.wallet.approve_erc20(approve_params[0], approve_params[1]) + result = self.wallet.get_request_execute_transaction( + RequestExecuteCallMsg( + contract_address=self.zksync_contract.address, + call_data=HexStr("0x"), + l2_value=7_000_000_000, + ) ) - ) - self.assertIsNotNone(result) + self.assertIsNotNone(result) def test_estimate_request_execute(self): result = self.wallet.estimate_gas_request_execute( @@ -989,11 +1042,38 @@ def test_estimate_request_execute(self): self.assertGreater(result, 0) def test_request_execute(self): - amount = 1 - l2_balance_before = self.wallet.get_balance() + if self.wallet.is_eth_based_chain(): + amount = 1 + l2_balance_before = self.wallet.get_balance() - tx_hash = self.wallet.request_execute( - RequestExecuteCallMsg( + tx_hash = self.wallet.request_execute( + RequestExecuteCallMsg( + contract_address=Web3.to_checksum_address( + self.zksync.zksync.zks_get_bridgehub_contract_address() + ), + call_data=HexStr("0x"), + l2_value=amount, + l2_gas_limit=900_000, + ) + ) + l1_tx_receipt = self.eth_web3.eth.wait_for_transaction_receipt(tx_hash) + l2_hash = self.zksync.zksync.get_l2_hash_from_priority_op( + l1_tx_receipt, self.zksync_contract + ) + self.zksync.zksync.wait_for_transaction_receipt(l2_hash) + l2_balance_after = self.wallet.get_balance() + self.assertEqual( + 1, l1_tx_receipt["status"], "L1 transaction should be successful" + ) + self.assertGreaterEqual( + l2_balance_after - l2_balance_before, + amount, + "Balance on L2 should be increased", + ) + else: + amount = 1 + l2_balance_before = self.wallet.get_balance() + request = RequestExecuteCallMsg( contract_address=Web3.to_checksum_address( self.zksync.zksync.zks_get_bridgehub_contract_address() ), @@ -1001,18 +1081,22 @@ def test_request_execute(self): l2_value=amount, l2_gas_limit=900_000, ) - ) - l1_tx_receipt = self.eth_web3.eth.wait_for_transaction_receipt(tx_hash) - l2_hash = self.zksync.zksync.get_l2_hash_from_priority_op( - l1_tx_receipt, self.zksync_contract - ) - self.zksync.zksync.wait_for_transaction_receipt(l2_hash) - l2_balance_after = self.wallet.get_balance() - self.assertEqual( - 1, l1_tx_receipt["status"], "L1 transaction should be successful" - ) - self.assertGreaterEqual( - l2_balance_after - l2_balance_before, - amount, - "Balance on L2 should be increased", - ) + approve_params = self.wallet.get_request_execute_allowance_params(request) + + self.wallet.approve_erc20(approve_params[0], approve_params[1]) + + tx_hash = self.wallet.request_execute(request) + l1_tx_receipt = self.eth_web3.eth.wait_for_transaction_receipt(tx_hash) + l2_hash = self.zksync.zksync.get_l2_hash_from_priority_op( + l1_tx_receipt, self.zksync_contract + ) + self.zksync.zksync.wait_for_transaction_receipt(l2_hash) + l2_balance_after = self.wallet.get_balance() + self.assertEqual( + 1, l1_tx_receipt["status"], "L1 transaction should be successful" + ) + self.assertGreaterEqual( + l2_balance_after - l2_balance_before, + amount, + "Balance on L2 should be increased", + ) diff --git a/tests/integration/test_zksync_contract.py b/tests/integration/test_zksync_contract.py index 414f885..80078bc 100644 --- a/tests/integration/test_zksync_contract.py +++ b/tests/integration/test_zksync_contract.py @@ -5,7 +5,8 @@ from eth_account.signers.local import LocalAccount from web3 import Web3 -from tests.unit.test_config import LOCAL_ENV, EnvPrivateKey +from tests.integration.test_config import private_key_1 +from tests.integration.test_config import EnvURL from zksync2.core.utils import RecommendedGasLimit from zksync2.manage_contracts.utils import get_zksync_hyperchain from zksync2.module.module_builder import ZkSyncBuilder @@ -18,11 +19,10 @@ def generate_random_salt() -> bytes: class ZkSyncWeb3Tests(TestCase): def setUp(self) -> None: - env = LOCAL_ENV - env_key = "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110" - self.zksync = ZkSyncBuilder.build(env.zksync_server) - self.eth_web3 = Web3(Web3.HTTPProvider(env.eth_server)) - self.account: LocalAccount = Account.from_key(env_key) + env = EnvURL() + self.zksync = ZkSyncBuilder.build(env.env.zksync_server) + self.eth_web3 = Web3(Web3.HTTPProvider(env.env.eth_server)) + self.account: LocalAccount = Account.from_key(private_key_1) self.chain_id = self.zksync.zksync.chain_id self.signer = PrivateKeyEthSigner(self.account, self.chain_id) self.zksync_contract = self.eth_web3.eth.contract( @@ -174,5 +174,5 @@ def test_request_l2_transaction(self): } ) signed_tx = self.account.sign_transaction(tx) - tx_hash = self.eth_web3.eth.send_raw_transaction(signed_tx.rawTransaction) + tx_hash = self.eth_web3.eth.send_raw_transaction(signed_tx.raw_transaction) tx_receipt = self.eth_web3.eth.wait_for_transaction_receipt(tx_hash) diff --git a/tests/integration/test_zksync_web3.py b/tests/integration/test_zksync_web3.py index 6cb6e7d..558e64d 100644 --- a/tests/integration/test_zksync_web3.py +++ b/tests/integration/test_zksync_web3.py @@ -8,7 +8,6 @@ from eth_typing import HexStr from eth_utils import keccak from web3 import Web3 -from web3.middleware import geth_poa_middleware from web3.types import TxParams from tests.contracts.utils import contract_path @@ -43,7 +42,7 @@ TxCreateContract, TxCreate2Contract, ) -from .test_config import LOCAL_ENV, EnvType +from .test_config import EnvURL, EnvType, address_1, private_key_1 def generate_random_salt() -> bytes: @@ -55,48 +54,14 @@ class ZkSyncWeb3Tests(TestCase): ETH_TEST_NET_AMOUNT_BALANCE = Decimal(1) def setUp(self) -> None: - self.env = LOCAL_ENV - self.web3 = ZkSyncBuilder.build(self.env.zksync_server) - self.account: LocalAccount = Account.from_key( - "7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110" - ) + self.env = EnvURL() + self.web3 = ZkSyncBuilder.build(self.env.env.zksync_server) + self.account: LocalAccount = Account.from_key(private_key_1) self.chain_id = self.web3.zksync.chain_id self.signer = PrivateKeyEthSigner(self.account, self.chain_id) self.counter_address = None self.test_tx_hash = None - # INFO: use deploy_erc20_token_builder to get new address - if self.env.type == EnvType.LOCAL_HOST: - self.some_erc20_address = Web3.to_checksum_address( - "0x37b96512962FC7773E06237116BE693Eb2b3cD51" - ) - if self.env.type == EnvType.TESTNET: - # https://goerli.explorer.zksync.io/address/0xd782e03F4818A7eDb0bc5f70748F67B4e59CdB33#contract - self.some_erc20_address = Web3.to_checksum_address( - "0xd782e03F4818A7eDb0bc5f70748F67B4e59CdB33" - ) - self.ERC20_Token = Token( - l1_address=ADDRESS_DEFAULT, - l2_address=self.some_erc20_address, - symbol="SERC20", - decimals=18, - ) - - @skip("Integration test, used for develop purposes only") - def test_send_money(self): - gas_limit = 21000 - web3 = Web3(Web3.HTTPProvider(self.env.eth_server)) - web3.middleware_onion.inject(geth_poa_middleware, layer=0) - account = web3.eth.accounts[0] - transaction: TxParams = { - "from": account, - "gasPrice": Web3.to_wei(1, "gwei"), - "gas": gas_limit, - "to": self.account.address, - "value": web3.to_wei(1000000, "ether"), - } - tx_hash = web3.eth.send_transaction(transaction) - txn_receipt = web3.eth.wait_for_transaction_receipt(tx_hash) - self.assertEqual(txn_receipt["status"], 1) + self.some_erc20_address = None def test_zks_l1_batch_number(self): result = self.web3.zksync.zks_l1_batch_number() @@ -107,7 +72,6 @@ def test_zks_get_l1_batch_block_range(self): result = self.web3.zksync.zks_get_l1_batch_block_range(l1_batch_number) self.assertIsNotNone(result) - @skip def test_zks_get_l1_batch_details(self): l1_batch_number = self.web3.zksync.zks_l1_batch_number() result = self.web3.zksync.zks_get_l1_batch_details(l1_batch_number) @@ -145,15 +109,16 @@ def test_zks_get_proof(self): # @skip("Integration test, used for develop purposes only") def test_get_l1_balance(self): - eth_web3 = Web3(Web3.HTTPProvider(self.env.eth_server)) + eth_web3 = Web3(Web3.HTTPProvider(self.env.env.eth_server)) eth_balance = eth_web3.eth.get_balance(self.account.address) self.assertNotEqual(eth_balance, 0) # @skip("Integration test, used for develop purposes only") def test_get_l2_balance(self): - zk_balance = self.web3.zksync.get_balance( + result = self.web3.zksync.get_balance( self.account.address, EthBlockParams.LATEST.value ) + self.assertIsNotNone(result) # @skip("Integration test, used for develop purposes only") def test_get_nonce(self): @@ -347,7 +312,7 @@ def mint_some_erc20(self, amount: int): ) self.assertEqual(1, tx_receipt["status"]) - # @skip("Integration test, used for develop purposes only") + @skip("Integration test, used for develop purposes only") def test_estimate_gas_deploy_contract(self): directory = Path(__file__).parent path = directory / Path("../contracts/Counter.json") @@ -374,7 +339,7 @@ def test_estimate_gas_deploy_contract(self): "test_estimate_gas_deploy_contract, estimate_gas must be greater 0", ) - # @skip("Integration test, used for develop purposes only") + @skip("Integration test, used for develop purposes only") def test_deploy_contract_create(self): random_salt = generate_random_salt() nonce = self.web3.zksync.get_transaction_count( @@ -431,7 +396,7 @@ def test_protocol_version(self): version = self.web3.zksync.protocol_version self.assertEqual(version, "zks/1") - # @skip("Integration test, used for develop purposes only") + @skip("Integration test, used for develop purposes only") def test_deploy_contract_with_constructor_create(self): random_salt = generate_random_salt() nonce = self.web3.zksync.get_transaction_count( @@ -498,7 +463,7 @@ def test_deploy_contract_with_constructor_create(self): ) self.assertEqual(a * b, value) - # @skip("Integration test, used for develop purposes only") + @skip("Integration test, used for develop purposes only") def test_deploy_contract_create2(self): random_salt = generate_random_salt() nonce = self.web3.zksync.get_transaction_count( @@ -550,7 +515,7 @@ def test_deploy_contract_create2(self): ) self.assertEqual(0, value) - # @skip("Integration test, used for develop purposes only") + @skip("Integration test, used for develop purposes only") def test_deploy_contract_with_deps_create(self): random_salt = generate_random_salt() directory = Path(__file__).parent @@ -605,7 +570,7 @@ def test_deploy_contract_with_deps_create(self): contract_address = contract_deployer.extract_contract_address(tx_receipt) self.assertEqual(precomputed_address.lower(), contract_address.lower()) - # @skip("Integration test, used for develop purposes only") + @skip("Integration test, used for develop purposes only") def test_deploy_contract_with_deps_create2(self): random_salt = generate_random_salt() directory = Path(__file__).parent @@ -655,7 +620,7 @@ def test_deploy_contract_with_deps_create2(self): contract_address = contract_deployer.extract_contract_address(tx_receipt) self.assertEqual(precomputed_address.lower(), contract_address.lower()) - # @skip("Integration test, used for develop purposes only") + @skip("Integration test, used for develop purposes only") def test_execute_contract(self): directory = Path(__file__).parent path = directory / Path("../contracts/Counter.json") @@ -728,7 +693,7 @@ def test_execute_contract(self): updated_result = int.from_bytes(eth_ret2, "big", signed=True) self.assertEqual(result + 1, updated_result) - # @skip + @skip def test_contract_factory(self): increment_value = 10 salt = generate_random_salt() @@ -758,7 +723,7 @@ def test_contract_factory(self): } ) signed = self.account.sign_transaction(tx) - tx_hash = self.web3.zksync.send_raw_transaction(signed.rawTransaction) + tx_hash = self.web3.zksync.send_raw_transaction(signed.raw_transaction) tx_receipt = self.web3.zksync.wait_for_transaction_receipt(tx_hash) self.assertEqual(1, tx_receipt["status"]) @@ -793,7 +758,8 @@ def test_get_l1_token_address(self): self.assertEqual(result, ADDRESS_DEFAULT) def test_get_l2_token_address(self): - result = self.web3.zksync.l2_token_address(ADDRESS_DEFAULT) + base_token = self.web3.zksync.zks_get_base_token_contract_address() + result = self.web3.zksync.l2_token_address(base_token) self.assertEqual(result, L2_BASE_TOKEN_ADDRESS) def test_get_bridgehub_contract(self): @@ -803,3 +769,15 @@ def test_get_bridgehub_contract(self): def test_zks_get_base_token_contract_address(self): result = self.web3.zksync.zks_get_base_token_contract_address() self.assertIsNotNone(result) + + def test_zks_get_protocol_version(self): + result = self.web3.zksync.zks_get_protocol_version() + self.assertIsNotNone(result) + + def test_zks_get_confirmed_tokens(self): + result = self.web3.zksync.zks_get_confirmed_tokens() + self.assertEqual(len(result), 1) + + def test_zks_get_fee_params(self): + result = self.web3.zksync.zks_get_fee_params() + self.assertIsNotNone(result) diff --git a/tests/unit/test_eip712.py b/tests/unit/test_eip712.py index 9f6229c..5f2a85c 100644 --- a/tests/unit/test_eip712.py +++ b/tests/unit/test_eip712.py @@ -1,7 +1,7 @@ import json -from unittest import TestCase +from unittest import TestCase, skip -from eth_account.messages import encode_structured_data +from eth_account.messages import encode_typed_data from eth_utils.crypto import keccak_256 from zksync2.eip712 import EIP712Struct, String, Address, make_domain from zksync2.core.utils import pad_front_bytes @@ -57,10 +57,11 @@ def test_hash_encoded_type(self): result.hex(), ) + @skip def test_encode_person(self): from_str = self.mail.get_data_value("from").to_message_json(self.domain) value = json.loads(from_str) - ret = encode_structured_data(value) + ret = encode_typed_data(value) self.assertEqual( "fc71e5fa27ff56c350aa531bc129ebdf613b772b6604664f5d8dbe21b85eb0c8", ret.body.hex(), @@ -68,16 +69,17 @@ def test_encode_person(self): to_str = self.mail.get_data_value("to").to_message_json(self.domain) value = json.loads(to_str) - ret = encode_structured_data(value) + ret = encode_typed_data(value) self.assertEqual( "cd54f074a4af31b4411ff6a60c9719dbd559c221c8ac3492d9d872b041d703d1", ret.body.hex(), ) + @skip def test_encode_mail_data(self): struct_message_json = self.mail.to_message_json(self.domain) value = json.loads(struct_message_json) - ret = encode_structured_data(value) + ret = encode_typed_data(value) self.assertEqual( "c52c0ee5d84264471806290a3f2c4cecfc5490626bf912d01f240d7a274b371e", ret.body.hex(), diff --git a/tests/unit/test_eth_signer.py b/tests/unit/test_eth_signer.py index 2f5ca86..763f33f 100644 --- a/tests/unit/test_eth_signer.py +++ b/tests/unit/test_eth_signer.py @@ -1,5 +1,7 @@ from unittest import TestCase from eth_typing import HexStr +from eth_utils import add_0x_prefix + from zksync2.signer.eth_signer import PrivateKeyEthSigner from eth_account.signers.local import LocalAccount from eth_account import Account @@ -54,7 +56,9 @@ def setUp(self) -> None: def test_sign_typed_data(self): sm = self.signer.sign_typed_data(self.mail, self.domain) - self.assertEqual(self._TEST_TYPED_EXPECTED_SIGNATURE, sm.signature.hex()) + self.assertEqual( + self._TEST_TYPED_EXPECTED_SIGNATURE, add_0x_prefix(sm.signature.hex()) + ) def test_verify_signed_typed_data(self): ret = self.signer.verify_typed_data( diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index b06191b..c688ce0 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -1,19 +1,16 @@ from unittest import TestCase from eth_typing import HexStr -from web3 import Web3 -from tests.integration.test_config import LOCAL_ENV, EnvPrivateKey -from zksync2.core.types import BridgeAddresses +from tests.integration.test_config import EnvURL from zksync2.core.utils import apply_l1_to_l2_alias, undo_l1_to_l2_alias from zksync2.module.module_builder import ZkSyncBuilder class UtilsTest(TestCase): def setUp(self) -> None: - self.env = LOCAL_ENV - env_key = EnvPrivateKey("ZKSYNC_KEY1") - self.zksync = ZkSyncBuilder.build(self.env.zksync_server) + self.env = EnvURL() + self.zksync = ZkSyncBuilder.build(self.env.env.zksync_server) def test_apply_l1_to_l2_alias(self): l1_contract_address = HexStr("0x702942B8205E5dEdCD3374E5f4419843adA76Eeb") diff --git a/zksync2/.DS_Store b/zksync2/.DS_Store new file mode 100644 index 0000000..3ca1eaf Binary files /dev/null and b/zksync2/.DS_Store differ diff --git a/zksync2/account/smart_account.py b/zksync2/account/smart_account.py new file mode 100644 index 0000000..f7f1d6a --- /dev/null +++ b/zksync2/account/smart_account.py @@ -0,0 +1,153 @@ +from ctypes import Union +from typing import Any + +from eth_account import Account +from eth_typing import HexStr +from web3 import Web3 + +from zksync2.account.smart_account_utils import ( + populate_transaction_multiple_ecdsa, + sign_payload_with_multiple_ecdsa, + populate_transaction_ecdsa, + sign_payload_with_ecdsa, +) +from zksync2.core.types import TransferTransaction, WithdrawTransaction, ZkBlockParams +from zksync2.manage_contracts.deploy_addresses import ZkSyncAddresses +from zksync2.manage_contracts.utils import nonce_holder_abi_default +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 TxBase + + +class SmartAccount: + + def __init__( + self, + address: HexStr, + secret, + provider: Web3, + transaction_builder=None, + payload_signer=None, + ): + self._address = address + self._secret = secret + self.provider = provider + self.transaction_builder = transaction_builder + self.payload_signer = payload_signer + + @property + def get_address(self) -> HexStr: + """Read-only property for address""" + return self._address + + @property + def secret(self): + """Read-only property for secret""" + return self._secret + + 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.provider.zksync.zks_get_balance( + self.get_address, block_tag, token_address + ) + + def get_all_balances(self) -> ZksAccountBalances: + """ + Returns the balance of the account. + """ + return self.provider.zksync.zks_get_all_account_balances(self.get_address) + + def get_deployment_nonce(self) -> int: + nonce_holder = self.provider.eth.contract( + Web3.to_checksum_address(ZkSyncAddresses.NONCE_HOLDER_ADDRESS.value), + abi=nonce_holder_abi_default(), + ) + + return nonce_holder.functions.getDeploymentNonce(self.get_address).call() + + def populate_transaction(self, tx: TxBase): + return self.transaction_builder( + tx, tx.tx["from"] or self._address, self._secret, self.provider + ) + + def sign_transaction(self, tx: TxBase) -> bytes: + populated = self.populate_transaction(tx) + populated.meta.custom_signature = self.payload_signer( + populated.to_eip712_struct().signable_bytes( + PrivateKeyEthSigner.get_default_domain(self.provider.eth.chain_id) + ), + self._secret, + self.provider, + ) + return populated.encode() + + def send_transaction(self, tx: TxBase): + return self.provider.zksync.send_raw_transaction(self.sign_transaction(tx)) + + def transfer(self, tx: TransferTransaction): + transaction = self.provider.zksync.get_transfer_transaction( + tx, self.get_address + ) + + return self.send_transaction(transaction) + + 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. + + :param tx: WithdrawTransaction class. Required parameters are token(HexStr) and amount(int). + + Returns: + - Withdrawal hash. + """ + from_: HexStr = self.get_address + is_contract_address = ( + len(self.provider.eth.get_code(Web3.to_checksum_address(self.get_address))) + != 0 + ) + if is_contract_address: + from_ = Account.from_key(self.secret[0]).address + transaction = self.provider.zksync.get_withdraw_transaction(tx, from_=from_) + + if is_contract_address: + transaction.tx["from"] = self.get_address + transaction.tx["nonce"] = tx.options.nonce or 0 + + return self.send_transaction(transaction) + + +class MultisigECDSASmartAccount: + @classmethod + def create( + cls, address: HexStr, secret: [HexStr], provider: Web3 + ) -> "SmartAccount": + return SmartAccount( + address, + secret, + provider, + populate_transaction_multiple_ecdsa, + sign_payload_with_multiple_ecdsa, + ) + + +class ECDSASmartAccount: + @classmethod + def create( + cls, address: HexStr, secret: [HexStr], provider: Web3 + ) -> "SmartAccount": + return SmartAccount( + address, + secret, + provider, + populate_transaction_ecdsa, + sign_payload_with_ecdsa, + ) diff --git a/zksync2/account/smart_account_utils.py b/zksync2/account/smart_account_utils.py new file mode 100644 index 0000000..66c4188 --- /dev/null +++ b/zksync2/account/smart_account_utils.py @@ -0,0 +1,87 @@ +import string + +from eth_account import Account +from eth_account.signers.local import LocalAccount +from eth_typing import HexStr +from web3 import Web3 + +from zksync2.core.types import EthBlockParams +from zksync2.core.utils import DEFAULT_GAS_PER_PUBDATA_LIMIT +from zksync2.module.request_types import EIP712Meta +from zksync2.signer.eth_signer import PrivateKeyEthSigner +from zksync2.transaction.transaction712 import Transaction712 +from zksync2.transaction.transaction_builders import TxBase + + +def sign_payload_with_ecdsa(payload: bytes, secret, provider: Web3) -> string: + account: LocalAccount = Account.from_key(secret) + signer = PrivateKeyEthSigner(account, provider.eth.chain_id) + + return signer.sign_message(payload).signature + + +def sign_payload_with_multiple_ecdsa(payload: bytes, secrets: [str], provider): + signatures = [] + for secret in secrets: + account: LocalAccount = Account.from_key(secret) + signer = PrivateKeyEthSigner(account, provider.eth.chain_id) + signatures.append(signer.sign_message(payload).signature) + return b"".join(signatures) + + +def populate_transaction_ecdsa( + tx: TxBase, from_: str, secret: str, provider: Web3 +) -> Transaction712: + if provider is None: + raise ValueError(f"Must be True or False. Got: {provider}") + + tx.tx["chainId"] = provider.eth.chain_id + tx.tx["gas"] = tx.tx["gas"] or 0 + tx.tx["value"] = tx.tx["value"] or 0 + tx.tx["data"] = tx.tx["data"] or 0 + tx.tx["eip712Meta"] = tx.tx["eip712Meta"] or EIP712Meta() + tx.tx["eip712Meta"].gas_per_pub_data = ( + DEFAULT_GAS_PER_PUBDATA_LIMIT + if tx.tx["eip712Meta"].gas_per_pub_data is None + else tx.tx["eip712Meta"].gas_per_pub_data + ) + tx.tx["eip712Meta"].factory_deps = ( + [] + if tx.tx["eip712Meta"].factory_deps is None + else tx.tx["eip712Meta"].factory_deps + ) + + fee = None + if from_ is not None: + is_contract_address = ( + len(provider.eth.get_code(Web3.to_checksum_address(from_))) != 0 + ) + if is_contract_address: + # Gas estimation does not work when initiator is contract account (works only with EOA). + # In order to estimation gas, the transaction's from value is replaced with signer's address. + fee = provider.zksync.zks_estimate_fee( + { + **tx.tx712(0).to_zk_transaction(), + "from": Account.from_key(secret).address, + } + ) + + tx.tx["from"] = Account.from_key(secret).address if from_ is None else from_ + tx.tx["nonce"] = tx.tx["nonce"] or provider.zksync.get_transaction_count( + Web3.to_checksum_address(tx.tx["from"]), EthBlockParams.PENDING.value + ) + if fee is None: + fee = provider.zksync.zks_estimate_fee(tx.tx712(0).to_zk_transaction()) + gas_limit = tx.tx["gas"] or fee.gas_limit + tx.tx["maxFeePerGas"] = tx.tx["maxFeePerGas"] or fee.max_fee_per_gas + tx.tx["maxPriorityFeePerGas"] = ( + tx.tx["maxPriorityFeePerGas"] or fee.max_priority_fee_per_gas + ) + + return tx.tx712(gas_limit) + + +def populate_transaction_multiple_ecdsa( + tx: TxBase, from_: str, secret: [HexStr], provider: Web3 +) -> Transaction712: + return populate_transaction_ecdsa(tx, from_, secret[0], provider) diff --git a/zksync2/account/wallet.py b/zksync2/account/wallet.py index a8f5cdf..f3f8c12 100644 --- a/zksync2/account/wallet.py +++ b/zksync2/account/wallet.py @@ -5,9 +5,11 @@ from eth_account.signers.base import BaseAccount +from zksync2.module.module_builder import ZkWeb3 + class Wallet(WalletL1, WalletL2): - def __init__(self, zksync_web3: Web3, eth_web3: Web3, l1_account: BaseAccount): + def __init__(self, zksync_web3: ZkWeb3, eth_web3: Web3, l1_account: BaseAccount): self._eth_web3 = eth_web3 self._zksync_web3 = zksync_web3 self._l1_account = l1_account diff --git a/zksync2/account/wallet_l1.py b/zksync2/account/wallet_l1.py index 934c21d..1fc52ac 100644 --- a/zksync2/account/wallet_l1.py +++ b/zksync2/account/wallet_l1.py @@ -6,11 +6,10 @@ from eth_utils import event_signature_to_log_topic, add_0x_prefix from web3 import Web3 from web3.contract import Contract -from web3.middleware import geth_poa_middleware +from web3.middleware import ExtraDataToPOAMiddleware from web3.types import TxReceipt from zksync2.account.utils import ( - deposit_to_request_execute, prepare_transaction_options, ) from zksync2.core.types import ( @@ -38,6 +37,7 @@ LEGACY_ETH_ADDRESS, scale_gas_limit, is_address_eq, + L2_BASE_TOKEN_ADDRESS, ) from zksync2.manage_contracts.deploy_addresses import ZkSyncAddresses from zksync2.manage_contracts.utils import ( @@ -49,6 +49,7 @@ get_zksync_hyperchain, l2_shared_bridge_abi_default, ) +from zksync2.module.module_builder import ZkWeb3 from zksync2.module.request_types import EIP712Meta from zksync2.transaction.transaction_builders import TxFunctionCall @@ -68,9 +69,9 @@ class WalletL1: RECOMMENDED_DEPOSIT_L2_GAS_LIMIT = 10000000 L1_MESSENGER_ADDRESS = "0x0000000000000000000000000000000000008008" - def __init__(self, zksync_web3: Web3, eth_web3: Web3, l1_account: BaseAccount): + def __init__(self, zksync_web3: ZkWeb3, eth_web3: Web3, l1_account: BaseAccount): self._eth_web3 = eth_web3 - self._eth_web3.middleware_onion.inject(geth_poa_middleware, layer=0) + self._eth_web3.middleware_onion.inject(ExtraDataToPOAMiddleware, layer=0) self._zksync_web3 = zksync_web3 self._main_contract_address = Web3.to_checksum_address( self._zksync_web3.zksync.zks_main_contract() @@ -85,7 +86,7 @@ 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.""" + """Returns Contract wrapper of the ZKsync smart contract.""" return self.contract @property @@ -202,7 +203,7 @@ def get_allowance_l1(self, token: HexStr, bridge_address: Address = None): :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). + 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() @@ -226,6 +227,15 @@ def l2_token_address(self, address: HexStr) -> HexStr: """ return self._zksync_web3.zksync.l2_token_address(address) + def l1_token_address(self, address: HexStr) -> HexStr: + """ + Returns the L1 token address equivalent for a L2 token address as they are not necessarily equal. + The ETH address is set to the zero address. + + :param address: The address of the token on L2. + """ + return self._zksync_web3.zksync.l1_token_address(address) + def approve_erc20( self, token: HexStr, @@ -234,12 +244,12 @@ def approve_erc20( gas_limit: int = None, ) -> TxReceipt: """ - Bridging ERC20 tokens from Ethereum requires approving the tokens to the zkSync Ethereum smart contract. + 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). + Defaults to the default ZKsync bridge (either L1EthBridge or L1Erc20Bridge). :param gas_limit: """ if is_eth(token): @@ -274,7 +284,7 @@ def approve_erc20( prepare_transaction_options(options, self.address) ) signed_tx = self._l1_account.sign_transaction(tx) - tx_hash = self._eth_web3.eth.send_raw_transaction(signed_tx.rawTransaction) + tx_hash = self._eth_web3.eth.send_raw_transaction(signed_tx.raw_transaction) tx_receipt = self._eth_web3.eth.wait_for_transaction_receipt(tx_hash) return tx_receipt @@ -349,7 +359,7 @@ def _deposit_non_base_token_to_non_eth_based_chain( tx["gas"] = scale_gas_limit(tx["gas"]) signed_tx = self._l1_account.sign_transaction(tx) - txn_hash = self._eth_web3.eth.send_raw_transaction(signed_tx.rawTransaction) + txn_hash = self._eth_web3.eth.send_raw_transaction(signed_tx.raw_transaction) return txn_hash @@ -404,7 +414,7 @@ def _deposit_eth_to_non_eth_based_chain(self, transaction: DepositTransaction): tx["gas"] = scale_gas_limit(tx["gas"]) signed_tx = self._l1_account.sign_transaction(tx) - txn_hash = self._eth_web3.eth.send_raw_transaction(signed_tx.rawTransaction) + txn_hash = self._eth_web3.eth.send_raw_transaction(signed_tx.raw_transaction) return txn_hash @@ -416,7 +426,7 @@ def _deposit_token_to_eth_based_chain(self, transaction: DepositTransaction): tx["gas"] = scale_gas_limit(base_gas_limit) signed_tx = self._l1_account.sign_transaction(tx) - txn_hash = self._eth_web3.eth.send_raw_transaction(signed_tx.rawTransaction) + txn_hash = self._eth_web3.eth.send_raw_transaction(signed_tx.raw_transaction) return txn_hash @@ -531,7 +541,7 @@ def _get_deposit_non_base_token_to_non_eth_based_chain_tx( if allowance < transaction.amount: approve_tx = self.approve_erc20( - base_token_address, + transaction.token, transaction.amount, bridge_address, transaction.approve_options.gas_limit, @@ -541,6 +551,12 @@ def _get_deposit_non_base_token_to_non_eth_based_chain_tx( self.address ) + bridge_address = ( + transaction.bridge_address + if transaction.bridge_address is not None + else bridge_contracts.shared.address + ) + transaction_data = { "chainId": chain_id, "mintValue": mint_value, @@ -548,7 +564,7 @@ def _get_deposit_non_base_token_to_non_eth_based_chain_tx( "l2GasLimit": transaction.l2_gas_limit, "l2GasPerPubdataByteLimit": transaction.gas_per_pubdata_byte, "refundRecipient": transaction.refund_recipient or self.address, - "secondBridgeAddress": bridge_contracts.shared.address, + "secondBridgeAddress": bridge_address, "secondBridgeValue": 0, "secondBridgeCalldata": encode( ["address", "uint256", "address"], [tx.token, tx.amount, tx.to] @@ -593,6 +609,7 @@ def _get_deposit_base_token_on_non_eth_based_chain_tx( l2_gas_limit=tx.l2_gas_limit, gas_per_pubdata_byte=tx.gas_per_pubdata_byte, options=tx.options, + refund_recipient=tx.refund_recipient, ), base_cost + tx.operator_tip + tx.amount, ) @@ -652,6 +669,12 @@ def _get_deposit_eth_on_non_eth_based_chain_tx( self.address ) + bridge_address = ( + transaction.bridge_address + if transaction.bridge_address is not None + else shared_bridge.address + ) + transaction_data = { "chainId": chain_id, "mintValue": mint_value, @@ -659,7 +682,7 @@ def _get_deposit_eth_on_non_eth_based_chain_tx( "l2GasLimit": transaction.l2_gas_limit, "l2GasPerPubdataByteLimit": transaction.gas_per_pubdata_byte, "refundRecipient": transaction.refund_recipient, - "secondBridgeAddress": shared_bridge.address, + "secondBridgeAddress": bridge_address, "secondBridgeValue": transaction.amount, "secondBridgeCalldata": encode( ["address", "uint256", "address"], [ETH_ADDRESS_IN_CONTRACTS, 0, tx.to] @@ -727,23 +750,18 @@ def _get_deposit_token_on_eth_based_chain_tx(self, transaction: DepositTransacti check_base_cost(base_cost, mint_value) second_bridge_address: str - second_bridge_calldata: bytes + second_bridge_calldata = encode( + ["address", "uint256", "address"], [tx.token, tx.amount, tx.to] + ) if tx.bridge_address is not None: second_bridge_address = tx.bridge_address - token_contract = self._eth_web3.eth.contract( - address=Web3.to_checksum_address(tx.token), abi=get_erc20_abi() - ) - second_bridge_calldata = get_custom_bridge_data(token_contract) else: second_bridge_address = self.get_l1_bridge_contracts().shared.address - second_bridge_calldata = encode( - ["address", "uint256", "address"], [tx.token, tx.amount, tx.to] - ) transaction_data = { "chainId": chain_id, "mintValue": mint_value, - "l2Value": transaction.l2_value, + "l2Value": 0, "l2GasLimit": transaction.l2_gas_limit, "l2GasPerPubdataByteLimit": transaction.gas_per_pubdata_byte, "refundRecipient": transaction.refund_recipient, @@ -823,12 +841,13 @@ def _get_l2_gas_limit(self, transaction: DepositTransaction): def _get_l2_gas_limit_from_custom_bridge(self, transaction: DepositTransaction): if transaction.custom_bridge_data is None: token_contract = self._zksync_web3.zksync.contract( - transaction.token, abi=get_erc20_abi() + address=Web3.to_checksum_address(transaction.token), abi=get_erc20_abi() ) transaction.custom_bridge_data = get_custom_bridge_data(token_contract) bridge = self._zksync_web3.zksync.contract( - transaction.bridge_address, abi=l1_bridge_abi_default() + address=Web3.to_checksum_address(transaction.bridge_address), + abi=l1_bridge_abi_default(), ) if transaction.options.chain_id is None: @@ -1061,6 +1080,8 @@ def estimate_default_bridge_deposit_l2_gas( gas_per_pubdata_byte: int = None, from_: HexStr = None, ) -> int: + if is_address_eq(token, LEGACY_ETH_ADDRESS): + token = ETH_ADDRESS_IN_CONTRACTS if from_ is None: from_ = self._l1_account.address if gas_per_pubdata_byte is None: @@ -1128,7 +1149,7 @@ def get_erc_20_call_data( bridge_data: bytes, ) -> HexStr: l2_bridge = self._eth_web3.eth.contract(abi=l2_bridge_abi_default()) - return l2_bridge.encodeABI( + return l2_bridge.encode_abi( "finalizeDeposit", (l1_sender, l2_receiver, l1_token_address, amount, bridge_data), ) @@ -1150,13 +1171,29 @@ def finalize_withdrawal(self, withdraw_hash, index: int = 0): nonce=self._eth_web3.eth.get_transaction_count(self.address), ) - shared_bridge_address = ( - self._zksync_web3.zksync.zks_get_bridge_contracts().shared_l1_default_bridge - ) - shared_bridge = self._eth_web3.eth.contract( - address=shared_bridge_address, abi=l1_shared_bridge_abi_default() - ) - tx = shared_bridge.functions.finalizeWithdrawal( + l1_bridge: Contract + if params["sender"] == L2_BASE_TOKEN_ADDRESS: + l1_bridge = self.get_l1_bridge_contracts().shared + elif not self._zksync_web3.zksync.is_l2_bridge_legacy(params["sender"]): + l2_bridge = self._zksync_web3.eth.contract( + address=Web3.to_checksum_address(params["sender"]), + abi=l2_shared_bridge_abi_default(), + ) + l1_bridge = self._eth_web3.eth.contract( + address=l2_bridge.functions.l1SharedBridge().call(), + abi=l1_shared_bridge_abi_default(), + ) + else: + l2_bridge = self._zksync_web3.eth.contract( + address=Web3.to_checksum_address(params["sender"]), + abi=l2_bridge_abi_default(), + ) + l1_bridge = self._eth_web3.eth.contract( + address=l2_bridge.functions.l1Bridge().call(), + abi=l1_bridge_abi_default(), + ) + + tx = l1_bridge.functions.finalizeWithdrawal( self._zksync_web3.eth.chain_id, params["l1_batch_number"], params["l2_message_index"], @@ -1166,7 +1203,7 @@ def finalize_withdrawal(self, withdraw_hash, index: int = 0): ).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) + tx_hash = self._eth_web3.eth.send_raw_transaction(signed.raw_transaction) return tx_hash def is_withdrawal_finalized(self, withdraw_hash, index: int = 0): @@ -1218,7 +1255,7 @@ def request_execute(self, transaction: RequestExecuteCallMsg): """ transaction = self.get_request_execute_transaction(transaction) signed_tx = self._l1_account.sign_transaction(transaction) - tx_hash = self._eth_web3.eth.send_raw_transaction(signed_tx.rawTransaction) + tx_hash = self._eth_web3.eth.send_raw_transaction(signed_tx.raw_transaction) return tx_hash @@ -1386,6 +1423,8 @@ def get_request_execute_allowance_params(self, transaction: RequestExecuteCallMs def insert_gas_price_in_transaction_options( self, options: TransactionOptions ) -> TransactionOptions: + if options is None: + options = TransactionOptions() if options.gas_price is None and options.max_fee_per_gas is None: is_ready, head = self.check_if_l1_chain_is_london_ready() if is_ready: diff --git a/zksync2/account/wallet_l2.py b/zksync2/account/wallet_l2.py index b8a0efa..dcfbac7 100644 --- a/zksync2/account/wallet_l2.py +++ b/zksync2/account/wallet_l2.py @@ -15,13 +15,14 @@ l2_bridge_abi_default, l2_shared_bridge_abi_default, ) +from zksync2.module.module_builder import ZkWeb3 from zksync2.module.response_types import ZksAccountBalances from zksync2.signer.eth_signer import PrivateKeyEthSigner from zksync2.transaction.transaction712 import Transaction712 class WalletL2: - def __init__(self, zksync_web3: Web3, eth_web3: Web3, l1_account: BaseAccount): + def __init__(self, zksync_web3: ZkWeb3, eth_web3: Web3, l1_account: BaseAccount): self._eth_web3 = eth_web3 self._zksync_web3 = zksync_web3 self._main_contract_address = self._zksync_web3.zksync.zks_main_contract() @@ -94,16 +95,18 @@ def transfer(self, tx: TransferTransaction) -> HexStr: Returns: - Transaction hash. """ - tx_fun_call = self._zksync_web3.zksync.get_transfer_transaction( + transaction = self._zksync_web3.zksync.get_transfer_transaction( tx, self._l1_account.address ) - if tx.options.gas_limit is None or tx.options.gas_limit == 0: - tx.options.gas_limit = self._zksync_web3.zksync.eth_estimate_gas( - tx_fun_call.tx - ) + tx_712: Transaction712 = transaction.tx712(transaction.tx["gas"]) + fee = self._zksync_web3.zksync.zks_estimate_fee(tx_712.to_zk_transaction()) + tx_712.gas_limit = tx_712.gas_limit or fee.gas_limit + tx_712.maxFeePerGas = tx_712.maxFeePerGas or fee.max_fee_per_gas + tx_712.maxPriorityFeePerGas = ( + tx_712.maxPriorityFeePerGas or fee.max_priority_fee_per_gas + ) - tx_712 = tx_fun_call.tx712(tx.options.gas_limit) signer = PrivateKeyEthSigner(self._l1_account, tx.options.chain_id) signed_message = signer.sign_typed_data(tx_712.to_eip712_struct()) @@ -125,13 +128,15 @@ def withdraw(self, tx: WithdrawTransaction): transaction = self._zksync_web3.zksync.get_withdraw_transaction( tx, from_=self._l1_account.address ) - if tx.options.gas_limit is None: - transaction.tx["gas"] = self._zksync_web3.zksync.eth_estimate_gas( - transaction.tx - ) - else: - transaction.tx["gas"] = tx.options.gas_limit + tx_712 = transaction.tx712() + fee = self._zksync_web3.zksync.zks_estimate_fee(tx_712.to_zk_transaction()) + tx_712.gas_limit = tx_712.gas_limit or fee.gas_limit + tx_712.maxFeePerGas = tx_712.maxFeePerGas or fee.max_fee_per_gas + tx_712.maxPriorityFeePerGas = ( + tx_712.maxPriorityFeePerGas or fee.max_priority_fee_per_gas + ) + signer = PrivateKeyEthSigner(self._l1_account, self._zksync_web3.eth.chain_id) signed_message = signer.sign_typed_data(tx_712.to_eip712_struct()) diff --git a/zksync2/core/types.py b/zksync2/core/types.py index e9c2609..647ade9 100644 --- a/zksync2/core/types.py +++ b/zksync2/core/types.py @@ -2,7 +2,7 @@ from datetime import datetime from decimal import Decimal from enum import Enum, IntEnum -from typing import Union, NewType, Dict, List, Any +from typing import Union, NewType, Dict, List, Any, Optional from eth_typing import HexStr, Hash32 from hexbytes import HexBytes @@ -47,6 +47,7 @@ class EthBlockParams(Enum): class Token: l1_address: HexStr l2_address: HexStr + name: str symbol: str decimals: int @@ -69,7 +70,7 @@ def to_int(self, amount: Union[Decimal, int, float]) -> int: @classmethod def create_eth(cls) -> "Token": - return Token(ADDRESS_DEFAULT, L2_ETH_TOKEN_ADDRESS, "ETH", 18) + return Token(ADDRESS_DEFAULT, L2_ETH_TOKEN_ADDRESS, "Ether", "ETH", 18) @dataclass @@ -287,6 +288,7 @@ class L1ToL2Log: key: HexStr value: HexStr log_index: HexStr + transaction_index_in_l1_batch: HexStr = None @dataclass @@ -320,3 +322,93 @@ class StorageProofData: class StorageProof: address: HexStr storageProof: StorageProofData + + +@dataclass +class VerificationKeysHashesParams: + recursion_node_level_vk_hash: str + recursion_leaf_level_vk_hash: str + recursion_circuits_set_vks_hash: str + + +@dataclass +class VerificationKeysHashes: + params: VerificationKeysHashesParams + recursion_scheduler_level_vk_hash: str + + +@dataclass +class BaseSystemContracts: + bootloader: str + default_aa: str + + +@dataclass +class ProtocolVersion: + """Represents the protocol version.""" + + version_id: int # Protocol version ID. + timestamp: int # Unix timestamp of the version's activation. + verification_keys_hashes: VerificationKeysHashes # Contains the hashes of various verification keys used in the protocol. + base_system_contracts: ( + BaseSystemContracts # Addresses of the base system contracts. + ) + l2_system_upgrade_tx_hash: HexStr = ( + None # Hash of the transaction used for the system upgrade, if any. + ) + + +@dataclass +class StorageLog: + address: str + key: str + writtenValue: str + + +@dataclass +class Event: + address: str + topics: List[str] + data: str + blockHash: Optional[str] + blockNumber: Optional[int] + l1BatchNumber: Optional[int] + transactionHash: str + transactionIndex: int + logIndex: Optional[int] + transactionLogIndex: Optional[int] + logType: Optional[str] + removed: bool + + +@dataclass +class TransactionWithDetailedOutput: + """Represents the transaction with detailed output.""" + + transactionHash: str # Transaction hash. + storageLogs: List[StorageLog] # Storage slots. + events: List[Event] # Generated events. + + +@dataclass +class Config: + minimal_l2_gas_price: int # Minimal gas price on L2. + compute_overhead_part: int # Compute overhead part in fee calculation. + pubdata_overhead_part: int # Public data overhead part in fee calculation. + batch_overhead_l1_gas: int # Overhead in L1 gas for a batch of transactions. + max_gas_per_batch: int # Maximum gas allowed per batch. + max_pubdata_per_batch: int # Maximum amount of public data allowed per batch. + + +@dataclass +class V2: + config: Config # Settings related to transaction fee computation. + l1_gas_price: int # Current L1 gas price. + l1_pubdata_price: int # Price of storing public data on L1. + + +@dataclass +class FeeParams: + """Represents the fee parameters configuration.""" + + V2: V2 # Fee parameter configuration for the current version of the ZKsync protocol. diff --git a/zksync2/core/utils.py b/zksync2/core/utils.py index fbff44c..e722937 100644 --- a/zksync2/core/utils.py +++ b/zksync2/core/utils.py @@ -23,6 +23,7 @@ DEPOSIT_GAS_PER_PUBDATA_LIMIT = 800 MAX_PRIORITY_FEE_PER_GAS = 100_000_000 +DEFAULT_GAS_PER_PUBDATA_LIMIT = 50000 L1_FEE_ESTIMATION_COEF_NUMERATOR = 12 L1_FEE_ESTIMATION_COEF_DENOMINATOR = 10 diff --git a/zksync2/manage_contracts/contract_encoder_base.py b/zksync2/manage_contracts/contract_encoder_base.py index c937a1b..58d2a14 100644 --- a/zksync2/manage_contracts/contract_encoder_base.py +++ b/zksync2/manage_contracts/contract_encoder_base.py @@ -1,11 +1,11 @@ +import itertools import json from enum import Enum from pathlib import Path -from typing import Any, Optional +from typing import Any, Optional, cast, Tuple from eth_typing import HexStr from eth_utils import remove_0x_prefix from web3 import Web3 -from web3._utils.abi import get_constructor_abi, merge_args_and_kwargs from web3._utils.contracts import encode_abi @@ -48,7 +48,7 @@ def __init__(self, web3: Web3, abi, bytecode: Optional[bytes] = None): ) def encode_method(self, fn_name, args: tuple) -> HexStr: - return self.instance_contract.encodeABI(fn_name, args) + return self.instance_contract.encode_abi(fn_name, args) @property def contract(self): @@ -60,14 +60,15 @@ def __init__(self, web3: Web3, abi, bytecode=None): super(ContractEncoder, self).__init__(web3, abi, bytecode) def encode_constructor(self, *args: Any, **kwargs: Any) -> bytes: - constructor_abi = get_constructor_abi(self.abi) + contract = self.web3.eth.contract(abi=self.abi, bytecode=self.bytecode) + constructor_abi = get_constructor_abi(contract.abi) if constructor_abi: if not args: args = tuple() if not kwargs: kwargs = {} - arguments = merge_args_and_kwargs(constructor_abi, args, kwargs) + arguments = merge_args_and_kwargs(constructor_abi["inputs"], args, kwargs) # INFO: it takes affect on the eth_estimate_gas, # it does not need the bytecode in the front of encoded arguments, see implementation of encode_abi # uncomment if it's fixed on ZkSync side @@ -81,3 +82,63 @@ def encode_constructor(self, *args: Any, **kwargs: Any) -> bytes: @property def bytecode(self): return self.instance_contract.bytecode + + +def merge_args_and_kwargs(abi_inputs, args, kwargs): + if len(args) + len(kwargs) != len(abi_inputs): + raise TypeError( + f"Incorrect argument count. Expected '{len(abi_inputs)}'" + f". Got '{len(args) + len(kwargs)}'" + ) + + # If no keyword args were given, we don't need to align them + if not kwargs: + return cast(Tuple[Any, ...], args) + + kwarg_names = set(kwargs.keys()) + sorted_arg_names = tuple(arg_abi["name"] for arg_abi in abi_inputs) + args_as_kwargs = dict(zip(sorted_arg_names, args)) + + # Check for duplicate args + duplicate_args = kwarg_names.intersection(args_as_kwargs.keys()) + if duplicate_args: + raise TypeError( + f"{abi_inputs.get('name')}() got multiple values for argument(s) " + f"'{', '.join(duplicate_args)}'" + ) + + # Check for unknown args + unknown_args = kwarg_names.difference(sorted_arg_names) + if unknown_args: + if abi_inputs.get("name"): + raise TypeError( + f"{abi_inputs.get('name')}() got unexpected keyword argument(s)" + f" '{', '.join(unknown_args)}'" + ) + raise TypeError( + f"Type: '{abi_inputs.get('type')}' got unexpected keyword argument(s)" + f" '{', '.join(unknown_args)}'" + ) + + # Sort args according to their position in the ABI and unzip them from their + # names + sorted_args = tuple( + zip( + *sorted( + itertools.chain(kwargs.items(), args_as_kwargs.items()), + key=lambda kv: sorted_arg_names.index(kv[0]), + ) + ) + ) + + if sorted_args: + return sorted_args[1] + else: + return tuple() + + +def get_constructor_abi(contract_abi): + for item in contract_abi: + if item.get("type") == "constructor": + return item + return None diff --git a/zksync2/manage_contracts/contract_factory.py b/zksync2/manage_contracts/contract_factory.py index 3db2d70..662f64a 100644 --- a/zksync2/manage_contracts/contract_factory.py +++ b/zksync2/manage_contracts/contract_factory.py @@ -2,29 +2,38 @@ from enum import Enum, auto from pathlib import Path from typing import List, Optional, Any + from eth_account.signers.base import BaseAccount from eth_utils import remove_0x_prefix -from web3 import Web3 from web3.contract import Contract + from zksync2.core.types import EthBlockParams +from zksync2.manage_contracts.contract_encoder_base import ContractEncoder from zksync2.manage_contracts.precompute_contract_deployer import ( PrecomputeContractDeployer, ) -from zksync2.manage_contracts.contract_encoder_base import ContractEncoder +from zksync2.module.module_builder import ZkWeb3 from zksync2.signer.eth_signer import EthSignerBase -from zksync2.transaction.transaction_builders import TxCreateContract, TxCreate2Contract +from zksync2.transaction.transaction_builders import ( + TxCreateContract, + TxCreate2Contract, + TxCreateAccount, + TxCreate2Account, +) class DeploymentType(Enum): CREATE = auto() CREATE2 = auto() + CREATE_ACCOUNT = auto() + CREATE2_ACCOUNT = auto() class LegacyContractFactory: @classmethod def from_json( cls, - zksync: Web3, + zksync: ZkWeb3, compiled_contract: Path, account: BaseAccount, signer: EthSignerBase, @@ -44,7 +53,7 @@ def from_json( def __init__( self, - zksync: Web3, + zksync: ZkWeb3, abi, bytecode, account: BaseAccount, @@ -59,15 +68,17 @@ def __init__( self.signer = signer def _deploy_create( - self, salt: bytes = None, args: Optional[Any] = None, deps: List[bytes] = None + self, salt: bytes = None, deps: List[bytes] = None, *args: Any, **kwargs: Any ) -> Contract: nonce = self.web3.zksync.get_transaction_count( self.account.address, EthBlockParams.PENDING.value ) call_data = None - if args is not None: + if (args is not None and kwargs is not None) and ( + len(args) > 0 or len(kwargs) > 0 + ): encoder = ContractEncoder(self.web3, abi=self.abi, bytecode=self.byte_code) - call_data = encoder.encode_constructor(args) + call_data = encoder.encode_constructor(*args, **kwargs) factory_deps = None if deps is not None: @@ -102,16 +113,18 @@ def _deploy_create( return self.web3.zksync.contract(address=contract_address, abi=self.abi) def _deploy_create2( - self, salt: bytes = None, args: Optional[Any] = None, deps: List[bytes] = None + self, salt: bytes = None, deps: List[bytes] = None, *args: Any, **kwargs: Any ) -> Contract: nonce = self.web3.zksync.get_transaction_count( self.account.address, EthBlockParams.PENDING.value ) gas_price = self.web3.zksync.gas_price call_data = None - if args is not None: + if (args is not None and kwargs is not None) and ( + len(args) > 0 or len(kwargs) > 0 + ): encoder = ContractEncoder(self.web3, abi=self.abi, bytecode=self.byte_code) - call_data = encoder.encode_constructor(args) + call_data = encoder.encode_constructor(*args, **kwargs) factory_deps = None if deps is not None: @@ -145,9 +158,104 @@ def _deploy_create2( contract_address = tx_receipt["contractAddress"] return self.web3.zksync.contract(address=contract_address, abi=self.abi) + def _deploy_create_account( + self, salt: bytes = None, deps: List[bytes] = None, *args: Any, **kwargs: Any + ) -> Contract: + nonce = self.web3.zksync.get_transaction_count( + self.account.address, EthBlockParams.PENDING.value + ) + gas_price = self.web3.zksync.gas_price + call_data = None + if (args is not None and kwargs is not None) and ( + len(args) > 0 or len(kwargs) > 0 + ): + encoder = ContractEncoder(self.web3, abi=self.abi, bytecode=self.byte_code) + call_data = encoder.encode_constructor(*args, **kwargs) + + factory_deps = None + if deps is not None: + factory_deps = deps + + create2_contract = TxCreateAccount( + web3=self.web3, + chain_id=self.web3.zksync.chain_id, + nonce=nonce, + from_=self.account.address, + gas_limit=0, + gas_price=gas_price, + bytecode=self.byte_code, + call_data=call_data, + deps=factory_deps, + ) + estimate_gas = self.web3.zksync.eth_estimate_gas(create2_contract.tx) + tx_712 = create2_contract.tx712(estimate_gas) + singed_message = self.signer.sign_typed_data(tx_712.to_eip712_struct()) + msg = tx_712.encode(singed_message) + tx_hash = self.web3.zksync.send_raw_transaction(msg) + tx_receipt = self.web3.zksync.wait_for_transaction_receipt( + tx_hash, timeout=240, poll_latency=0.5 + ) + + if factory_deps is not None: + contract_deployer = PrecomputeContractDeployer(self.web3) + contract_address = contract_deployer.extract_contract_address(tx_receipt) + else: + contract_address = tx_receipt["contractAddress"] + return self.web3.zksync.contract(address=contract_address, abi=self.abi) + + def _deploy_create2_account( + self, salt: bytes = None, deps: List[bytes] = None, *args: Any, **kwargs: Any + ) -> Contract: + nonce = self.web3.zksync.get_transaction_count( + self.account.address, EthBlockParams.PENDING.value + ) + gas_price = self.web3.zksync.gas_price + call_data = None + if (args is not None and kwargs is not None) and ( + len(args) > 0 or len(kwargs) > 0 + ): + encoder = ContractEncoder(self.web3, abi=self.abi, bytecode=self.byte_code) + call_data = encoder.encode_constructor(*args, **kwargs) + + factory_deps = None + if deps is not None: + factory_deps = deps + + create2_contract = TxCreate2Account( + web3=self.web3, + chain_id=self.web3.zksync.chain_id, + nonce=nonce, + from_=self.account.address, + gas_limit=0, + gas_price=gas_price, + bytecode=self.byte_code, + call_data=call_data, + deps=factory_deps, + salt=salt, + ) + estimate_gas = self.web3.zksync.eth_estimate_gas(create2_contract.tx) + tx_712 = create2_contract.tx712(estimate_gas) + singed_message = self.signer.sign_typed_data(tx_712.to_eip712_struct()) + msg = tx_712.encode(singed_message) + tx_hash = self.web3.zksync.send_raw_transaction(msg) + tx_receipt = self.web3.zksync.wait_for_transaction_receipt( + tx_hash, timeout=240, poll_latency=0.5 + ) + + if factory_deps is not None: + contract_deployer = PrecomputeContractDeployer(self.web3) + contract_address = contract_deployer.extract_contract_address(tx_receipt) + else: + contract_address = tx_receipt["contractAddress"] + return self.web3.zksync.contract(address=contract_address, abi=self.abi) + def deploy( - self, salt: bytes = None, args: Optional[Any] = None, deps: List[bytes] = None + self, salt: bytes = None, deps: List[bytes] = None, *args: Any, **kwargs: Any ) -> Contract: if self.type == DeploymentType.CREATE2: - return self._deploy_create2(salt, args, deps) - return self._deploy_create(salt, args, deps) + return self._deploy_create2(salt, deps, *args, **kwargs) + if self.type == DeploymentType.CREATE_ACCOUNT: + return self._deploy_create_account(salt, deps, *args, **kwargs) + if self.type == DeploymentType.CREATE2_ACCOUNT: + return self._deploy_create2_account(salt, deps, *args, **kwargs) + return self._deploy_create(salt, deps, *args, **kwargs) diff --git a/zksync2/module/middleware.py b/zksync2/module/middleware.py index f1fbde3..cd56464 100644 --- a/zksync2/module/middleware.py +++ b/zksync2/module/middleware.py @@ -1,19 +1,9 @@ -from typing import Callable +from web3.middleware import Web3Middleware -from web3 import Web3 -from web3.middleware import Middleware -from web3.types import RPCEndpoint, RPCResponse -from typing import Any -from zksync2.module.zksync_provider import ZkSyncProvider - -def build_zksync_middleware(zksync_provider: ZkSyncProvider) -> Middleware: - def zksync_middleware( - make_request: Callable[[RPCEndpoint, Any], Any], w3: Web3 - ) -> Callable[[RPCEndpoint, Any], RPCResponse]: - def middleware(method: RPCEndpoint, params: Any) -> RPCResponse: - return zksync_provider.make_request(method, params) +class ZkSyncMiddlewareBuilder(Web3Middleware): + def wrap_make_request(self, make_request): + def middleware(method, params): + return make_request(method, params) return middleware - - return zksync_middleware diff --git a/zksync2/module/module_builder.py b/zksync2/module/module_builder.py index 140674e..62c6b94 100644 --- a/zksync2/module/module_builder.py +++ b/zksync2/module/module_builder.py @@ -1,19 +1,25 @@ -from zksync2.module.zksync_module import ZkSync -from zksync2.module.zksync_provider import ZkSyncProvider -from zksync2.module.middleware import build_zksync_middleware - from typing import Union -from web3._utils.module import attach_modules + from eth_typing import URI from web3 import Web3 +from web3._utils.module import attach_modules + +from zksync2.module.zksync_module import ZkSync +from zksync2.module.zksync_provider import ZkSyncProvider + + +class ZkWeb3(Web3): + zksync: ZkSync + + def __init__(self, provider): + super().__init__(provider) + # Attach the zksync module + attach_modules(self, {"zksync": (ZkSync,)}) class ZkSyncBuilder: @classmethod - def build(cls, url: Union[URI, str]) -> Web3: - web3_module = Web3() + def build(cls, url: Union[URI, str]) -> ZkWeb3: zksync_provider = ZkSyncProvider(url) - zksync_middleware = build_zksync_middleware(zksync_provider) - web3_module.middleware_onion.add(zksync_middleware) - attach_modules(web3_module, {"zksync": (ZkSync,)}) + web3_module = ZkWeb3(zksync_provider) return web3_module diff --git a/zksync2/module/request_types.py b/zksync2/module/request_types.py index c9b187c..a0eec17 100644 --- a/zksync2/module/request_types.py +++ b/zksync2/module/request_types.py @@ -1,9 +1,6 @@ from enum import Enum from dataclasses import dataclass -from typing import List, Optional -from web3._utils.compat import ( - TypedDict, -) +from typing import List, Optional, TypedDict from eth_typing import HexStr from web3.types import AccessList @@ -30,11 +27,11 @@ class EIP712Meta: "from": HexStr, "to": HexStr, "gas": int, - "gasPrice": int, + "maxFeePerGas": int, "maxPriorityFeePerGas": int, "value": int, "data": HexStr, - "transactionType": int, + "type": int, "accessList": Optional[AccessList], "eip712Meta": EIP712Meta, }, diff --git a/zksync2/module/zksync_module.py b/zksync2/module/zksync_module.py index 2159cfd..1a65fff 100644 --- a/zksync2/module/zksync_module.py +++ b/zksync2/module/zksync_module.py @@ -1,16 +1,14 @@ from abc import ABC +from typing import Any, Callable, List, Union -import web3 +from eth_typing import Address +from eth_utils import remove_0x_prefix from eth_utils import to_checksum_address, is_address -from eth_utils.curried import apply_formatter_to_array - from eth_utils.curried import apply_formatter_at_index +from eth_utils.curried import apply_formatter_to_array +from eth_utils.toolz import compose from hexbytes import HexBytes from web3 import Web3 -from web3._utils.threads import Timeout -from web3.contract import Contract -from web3.exceptions import TransactionNotFound, TimeExhausted -from web3.module import Module from web3._utils.formatters import integer_to_hex from web3._utils.method_formatters import ( ABI_REQUEST_FORMATTERS, @@ -19,7 +17,6 @@ combine_formatters, apply_formatter_if, apply_formatters_to_dict, - apply_list_to_array_formatter, to_hex_if_integer, PYTHONIC_RESULT_FORMATTERS, FILTER_RESULT_FORMATTERS, @@ -27,12 +24,15 @@ is_not_null, to_ascii_if_bytes, ) - +from web3._utils.threads import Timeout +from web3.contract import Contract from web3.eth import Eth -from web3.types import RPCEndpoint, _Hash32, TxReceipt, BlockIdentifier +from web3.exceptions import TransactionNotFound, TimeExhausted +from web3.method import Method, default_root_munger +from web3.module import Module +from web3.types import RPCEndpoint, _Hash32, TxReceipt + from zksync2.core.types import ( - Limit, - From, ContractSourceDebugInfo, BridgeAddresses, TokenAddress, @@ -51,10 +51,13 @@ ContractAccountInfo, StorageProof, ETH_ADDRESS_IN_CONTRACTS, + ProtocolVersion, + TransactionWithDetailedOutput, + FeeParams, ) +from zksync2.core.types import TransactionReceipt from zksync2.core.utils import ( is_eth, - MAX_PRIORITY_FEE_PER_GAS, LEGACY_ETH_ADDRESS, L2_BASE_TOKEN_ADDRESS, is_address_eq, @@ -62,24 +65,16 @@ ) from zksync2.manage_contracts.deploy_addresses import ZkSyncAddresses from zksync2.manage_contracts.utils import ( - ERC20Encoder, get_erc20_abi, icontract_deployer_abi_default, l2_bridge_abi_default, + l2_shared_bridge_abi_default, ) from zksync2.module.request_types import * from zksync2.module.response_types import * -from zksync2.core.types import TransactionReceipt -from eth_typing import Address -from eth_utils import remove_0x_prefix -from eth_utils.toolz import compose -from web3.method import Method, default_root_munger -from typing import Any, Callable, List, Union - from zksync2.transaction.transaction712 import Transaction712 from zksync2.transaction.transaction_builders import ( TxWithdraw, - TxFunctionCall, TxTransfer, ) @@ -101,6 +96,12 @@ zks_get_proof_rpc = RPCEndpoint("zks_getProof") zks_get_base_token_l1_address_rpc = RPCEndpoint("zks_getBaseTokenL1Address") zks_get_bridgehub_contract_rpc = RPCEndpoint("zks_getBridgehubContract") +zks_get_protocol_version_rpc = RPCEndpoint("zks_getProtocolVersion") +zks_get_confirmed_tokens_rpc = RPCEndpoint("zks_getConfirmedTokens") +zks_send_raw_transaction_with_detailed_output_rpc = RPCEndpoint( + "zks_sendRawTransactionWithDetailedOutput" +) +zks_get_fee_params_rpc = RPCEndpoint("zks_getFeeParams") eth_estimate_gas_rpc = RPCEndpoint("eth_estimateGas") eth_get_transaction_receipt_rpc = RPCEndpoint("eth_getTransactionReceipt") eth_get_transaction_by_hash_rpc = RPCEndpoint("eth_getTransactionByHash") @@ -264,6 +265,7 @@ def to_l2_to_l1_logs(t: dict) -> L1ToL2Log: block_number=t["blockNumber"], l1_batch_number=t["l1BatchNumber"], transaction_index=t["transactionIndex"], + transaction_index_in_l1_batch=t["txIndexInL1Batch"] or None, transaction_hash=t["transactionHash"], transaction_log_index=t["transactionLogIndex"], shard_id=t["shardId"], @@ -459,6 +461,30 @@ class ZkSync(Eth, ABC): result_formatters=zksync_get_result_formatters, ) + _zks_get_protocol_version: Method[Callable[[Optional[int]], ProtocolVersion]] = ( + Method( + zks_get_protocol_version_rpc, + mungers=[default_root_munger], + ) + ) + + _zks_get_confirmed_tokens: Method[Callable[[int, int], List[Token]]] = Method( + zks_get_confirmed_tokens_rpc, + mungers=[default_root_munger], + ) + + _zks_send_raw_transaction_with_detailed_output: Method[ + Callable[[Union[HexStr, bytes]], TransactionWithDetailedOutput] + ] = Method( + zks_send_raw_transaction_with_detailed_output_rpc, + mungers=[default_root_munger], + ) + + _zks_get_fee_params: Method[Callable[[], FeeParams]] = Method( + zks_get_fee_params_rpc, + mungers=[default_root_munger], + ) + _eth_estimate_gas: Method[Callable[[Transaction], int]] = Method( eth_estimate_gas_rpc, mungers=[default_root_munger], @@ -520,6 +546,61 @@ def zks_estimate_gas_l1_to_l2(self, transaction: Transaction) -> int: def zks_get_proof(self, address: HexStr, key: List[HexStr], l1_batch_number: int): return self._zks_get_proof(address, key, l1_batch_number) + def zks_get_protocol_version(self, id: int = None) -> ProtocolVersion: + """ + Returns the protocol version. + + Calls the zks_getProtocolVersion JSON-RPC method. + (Refer to: https://docs.zksync.io/build/api.html#zks_getprotocolversion) + + :param id: Specific version ID (optional). + """ + + return self._zks_get_protocol_version(id) + + def zks_get_confirmed_tokens( + self, start: int = 0, limit: int = 255 + ) -> ProtocolVersion: + """ + Returns confirmed tokens. A confirmed token is any token bridged to ZKsync Era via the official bridge. + + Calls the zks_getConfirmedTokens JSON-RPC method. + (Refer to: https://docs.zksync.io/build/api.html#zks_getconfirmedtokens) + + :param start: The token ID from which to start. + :param limit: The maximum number of tokens to list. + """ + + return self._zks_get_confirmed_tokens(start, limit) + + def zks_send_raw_transaction_with_detailed_output( + self, tx: Union[HexStr, bytes] + ) -> ProtocolVersion: + """ + Executes a transaction and returns its hash, storage logs, and events that would have been generated if the + transaction had already been included in the block. The API has a similar behaviour to `eth_sendRawTransaction` + but with some extra data returned from it. + + With this API, consumer apps can apply "optimistic" events in their applications instantly without having to + wait for ZKsync block confirmation time. + + It’s expected that the optimistic logs of two uncommitted transactions that modify the same state will not + have causal relationships between each other. + + Calls the zks_sendRawTransactionWithDetailedOutput JSON-RPC method. + (Refer to: https://docs.zksync.io/build/api.html#zks_sendRawTransactionWithDetailedOutput) + + :param tx: The signed transaction that needs to be broadcasted. + """ + return self._zks_send_raw_transaction_with_detailed_output(tx) + + def zks_get_fee_params(self) -> FeeParams: + """ + Returns the current fee parameters. + Calls the {@link https://docs.zksync.io/build/api.html#zks_getFeeParams zks_getFeeParams} JSON-RPC method. + """ + return self._zks_get_fee_params() + def zks_estimate_gas_transfer( self, transaction: Transaction, token_address: HexStr = ADDRESS_DEFAULT ) -> int: @@ -529,7 +610,7 @@ def zks_estimate_gas_transfer( contract = self.contract( Web3.to_checksum_address(token_address), abi=get_erc20_abi() ) - transaction["data"] = contract.encodeABI("transfer", args=transfer_params) + transaction["data"] = contract.encode_abi("transfer", args=transfer_params) transaction["nonce"] = self.get_transaction_count( transaction["from_"], ZkBlockParams.COMMITTED.value ) @@ -619,20 +700,22 @@ def l1_token_address(self, token: HexStr) -> HexStr: return shared_bridge.functions.l1TokenAddress(token).call() - def l2_token_address(self, token: HexStr) -> HexStr: + def l2_token_address(self, token: HexStr, bridge_address: HexStr = None) -> HexStr: """ Returns the L2 token address equivalent for a L1 token address as they are not equal. ETH address is set to zero address. :param token: The address of the token on L1. + :param bridge_address: The address of custom bridge, which will be used to get l2 token address. """ if token == ADDRESS_DEFAULT: token = ETH_ADDRESS_IN_CONTRACTS base_token = self.zks_get_base_token_contract_address() - if token == base_token: + if token.lower() == base_token.lower(): return L2_BASE_TOKEN_ADDRESS - bridge_address = self.zks_get_bridge_contracts() + if bridge_address is None: + bridge_address = self.zks_get_bridge_contracts() l2_shared_bridge = self.contract( Web3.to_checksum_address(bridge_address.shared_l2_default_bridge), abi=l2_bridge_abi_default(), @@ -794,8 +877,10 @@ def get_transfer_transaction( ) if tx.options.gas_price is None: tx.options.gas_price = self.gas_price + if tx.options.max_fee_per_gas is None: + tx.options.max_fee_per_gas = 0 if tx.options.max_priority_fee_per_gas is None: - tx.options.max_priority_fee_per_gas = MAX_PRIORITY_FEE_PER_GAS + tx.options.max_priority_fee_per_gas = 0 if tx.options.gas_limit is None: tx.options.gas_limit = 0 @@ -805,7 +890,7 @@ def get_transfer_transaction( contract = self.contract( Web3.to_checksum_address(tx.token_address), abi=get_erc20_abi() ) - call_data = contract.encodeABI("transfer", transfer_params) + call_data = contract.encode_abi("transfer", transfer_params) transaction = TxTransfer( web3=self, @@ -817,7 +902,7 @@ def get_transfer_transaction( data=call_data, value=tx.amount, gas_limit=tx.options.gas_limit, - gas_price=tx.options.gas_price, + max_fee_per_gas=tx.options.max_fee_per_gas, max_priority_fee_per_gas=tx.options.max_priority_fee_per_gas, gas_per_pub_data=tx.gas_per_pub_data, paymaster_params=tx.paymaster_params, @@ -838,3 +923,21 @@ def get_contract_account_info(self, address: HexStr) -> ContractAccountInfo: return ContractAccountInfo( account_abstraction_version=data[0], account_nonce_ordering=data[1] ) + + def is_l2_bridge_legacy(self, address: HexStr) -> bool: + """ + Returns true if the passed bridge address is legacy and false if it is a shared bridge. + + :param address: The bridge address. + """ + bridge = self.contract( + address=Web3.to_checksum_address(address), + abi=l2_shared_bridge_abi_default(), + ) + try: + bridge.functions.l1SharedBridge().call() + return False + except: + pass + + return True diff --git a/zksync2/signer/eth_signer.py b/zksync2/signer/eth_signer.py index ad4172b..6b87347 100644 --- a/zksync2/signer/eth_signer.py +++ b/zksync2/signer/eth_signer.py @@ -1,11 +1,13 @@ -import web3 from abc import abstractmethod, ABC -from zksync2.eip712 import make_domain, EIP712Struct + +import web3 from eth_account.datastructures import SignedMessage +from eth_account.messages import encode_defunct, SignableMessage from eth_account.signers.base import BaseAccount from eth_typing import ChecksumAddress, HexStr from eth_utils import keccak -from eth_account.messages import encode_defunct, SignableMessage + +from zksync2.eip712 import make_domain, EIP712Struct class EthSignerBase: @@ -29,6 +31,14 @@ def __init__(self, creds: BaseAccount, chain_id: int): name=self._NAME, version=self._VERSION, chainId=self.chain_id ) + @staticmethod + def get_default_domain(chain_id: int): + return make_domain( + name=PrivateKeyEthSigner._NAME, + version=PrivateKeyEthSigner._VERSION, + chainId=chain_id, + ) + @property def address(self) -> ChecksumAddress: return self.credentials.address @@ -49,7 +59,7 @@ def typed_data_to_signed_bytes( def sign_typed_data(self, typed_data: EIP712Struct, domain=None) -> SignedMessage: singable_message = self.typed_data_to_signed_bytes(typed_data, domain) msg_hash = keccak(singable_message.body) - return self.credentials.signHash(msg_hash) + return self.credentials.unsafe_sign_hash(msg_hash) def verify_typed_data( self, sig: HexStr, typed_data: EIP712Struct, domain=None @@ -58,3 +68,7 @@ def verify_typed_data( msg_hash = keccak(singable_message.body) address = web3.Account._recover_hash(message_hash=msg_hash, signature=sig) return address.lower() == self.address.lower() + + def sign_message(self, message: bytes) -> SignedMessage: + msg_hash = keccak(message) + return self.credentials.unsafe_sign_hash(msg_hash) diff --git a/zksync2/transaction/transaction712.py b/zksync2/transaction/transaction712.py index 61864f9..c06b70a 100644 --- a/zksync2/transaction/transaction712.py +++ b/zksync2/transaction/transaction712.py @@ -7,7 +7,7 @@ from rlp.sedes import big_endian_int, binary from rlp.sedes import List as rlpList from web3.types import Nonce -from zksync2.module.request_types import EIP712Meta +from zksync2.module.request_types import EIP712Meta, Transaction as ZkTx from zksync2.eip712 import EIP712Struct, Address, Uint, Bytes, Array from zksync2.core.utils import to_bytes, hash_byte_code, encode_address, int_to_bytes @@ -160,3 +160,19 @@ class Transaction(EIP712Struct): "paymasterInput": paymaster_input, } return Transaction(**kwargs) + + def to_zk_transaction(self): + kwargs = { + "chain_id": self.chain_id, + "nonce": self.nonce, + "from": self.from_, + "to": self.to, + "gas": hex(self.gas_limit), + "maxFeePerGas": hex(self.maxFeePerGas), + "maxPriorityFeePerGas": hex(self.maxPriorityFeePerGas), + "value": self.value, + "data": self.data, + "type": hex(self.EIP_712_TX_TYPE), + "eip712Meta": self.meta, + } + return ZkTx(**kwargs) diff --git a/zksync2/transaction/transaction_builders.py b/zksync2/transaction/transaction_builders.py index 9235c69..afeddb9 100644 --- a/zksync2/transaction/transaction_builders.py +++ b/zksync2/transaction/transaction_builders.py @@ -323,6 +323,8 @@ def __init__( nonce = web3.get_transaction_count(from_) if chain_id is None: chain_id = web3.chain_id + if gas_limit is None: + gas_limit = 0 eip712_meta = EIP712Meta( gas_per_pub_data=50000, @@ -339,6 +341,7 @@ def __init__( tx = contract.functions.withdraw(to).build_transaction( { "nonce": nonce, + "gas": gas_limit, "chainId": chain_id, "maxFeePerGas": max_fee_per_gas, "maxPriorityFeePerGas": max_priority_fee_per_gas, @@ -360,12 +363,14 @@ def __init__( chain_id=chain_id, max_fee_per_gas=max_fee_per_gas, max_priority_fee_per_gas=max_priority_fee_per_gas, + gas_limit=gas_limit, value=0, ) tx = l2_bridge.functions.withdraw(to, token, amount).build_transaction( prepare_transaction_options(from_=from_, options=options) ) tx["eip712Meta"] = eip712_meta + super(TxWithdraw, self).__init__(trans=tx) def tx712(self, estimated_gas: int = None) -> Transaction712: @@ -403,8 +408,8 @@ def __init__( 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, + max_fee_per_gas: int = 0, + max_priority_fee_per_gas: int = 0, paymaster_params=None, custom_signature=None, gas_per_pub_data: int = EIP712Meta.GAS_PER_PUB_DATA_DEFAULT, @@ -423,7 +428,7 @@ def __init__( "from": from_, "to": to, "gas": gas_limit, - "gasPrice": gas_price, + "maxFeePerGas": max_fee_per_gas, "maxPriorityFeePerGas": max_priority_fee_per_gas, "value": value, "data": data, @@ -441,7 +446,8 @@ def __init__( "nonce": nonce, "chainId": chain_id, "gas": gas_limit, - "gasPrice": gas_price, + "maxFeePerGas": max_fee_per_gas, + "maxPriorityFeePerGas": max_priority_fee_per_gas, "from": from_, } ) @@ -456,8 +462,8 @@ def tx712(self, estimated_gas: int) -> Transaction712: to=self.tx["to"], value=self.tx["value"], data=self.tx["data"], - maxPriorityFeePerGas=0, - maxFeePerGas=self.tx["gasPrice"], + maxPriorityFeePerGas=self.tx["maxPriorityFeePerGas"], + maxFeePerGas=self.tx["maxFeePerGas"], from_=self.tx["from"], meta=self.tx["eip712Meta"], )