From 3386666cf39cfb661c77853c976cce34e060087b Mon Sep 17 00:00:00 2001 From: laruh Date: Tue, 5 Mar 2024 19:03:35 +0700 Subject: [PATCH 01/80] functionality to deploy and mint NFTs, add nft_swap_contract_abi json and test nft abi. Make NFT type uppercase in CoinProtocol --- mm2src/coins/eth.rs | 7 +- mm2src/coins/eth/nft_swap_contract_abi.json | 898 ++++++++++++++++++ mm2src/coins/lp_coins.rs | 45 +- .../src/erc20_token_activation.rs | 2 +- mm2src/coins_activation/src/prelude.rs | 2 +- mm2src/mm2_main/src/lp_ordermatch.rs | 2 +- .../tests/docker_tests/docker_tests_common.rs | 119 +++ .../tests/docker_tests/eth_docker_tests.rs | 114 ++- .../dummy_files/erc1155_test_abi.json | 455 +++++++++ .../dummy_files/erc721_test_abi.json | 469 +++++++++ mm2src/mm2_test_helpers/src/for_tests.rs | 17 + 11 files changed, 2116 insertions(+), 14 deletions(-) create mode 100644 mm2src/coins/eth/nft_swap_contract_abi.json create mode 100644 mm2src/mm2_test_helpers/dummy_files/erc1155_test_abi.json create mode 100644 mm2src/mm2_test_helpers/dummy_files/erc721_test_abi.json diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 83a7f9d77f..6208040bd5 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -5874,7 +5874,7 @@ pub async fn eth_coin_from_conf_and_request( } let (coin_type, decimals) = match protocol { - CoinProtocol::ETH => (EthCoinType::Eth, ETH_DECIMALS), + CoinProtocol::ETH | CoinProtocol::NFT { .. } => (EthCoinType::Eth, ETH_DECIMALS), CoinProtocol::ERC20 { platform, contract_address, @@ -5895,7 +5895,7 @@ pub async fn eth_coin_from_conf_and_request( }; (EthCoinType::Erc20 { platform, token_addr }, decimals) }, - _ => return ERR!("Expect ETH or ERC20 protocol"), + _ => return ERR!("Expect ETH, ERC20 or NFT protocol"), }; // param from request should override the config @@ -5926,8 +5926,7 @@ pub async fn eth_coin_from_conf_and_request( let key_lock = match &coin_type { EthCoinType::Eth => String::from(ticker), - EthCoinType::Erc20 { ref platform, .. } => String::from(platform), - EthCoinType::Nft { .. } => return ERR!("Does not support NFT protocol"), + EthCoinType::Erc20 { platform, .. } | EthCoinType::Nft { platform } => String::from(platform), }; let nonce_lock = { diff --git a/mm2src/coins/eth/nft_swap_contract_abi.json b/mm2src/coins/eth/nft_swap_contract_abi.json new file mode 100644 index 0000000000..f0c3049d98 --- /dev/null +++ b/mm2src/coins/eth/nft_swap_contract_abi.json @@ -0,0 +1,898 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "feeAddress", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "AddressEmptyCode", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "AddressInsufficientBalance", + "type": "error" + }, + { + "inputs": [], + "name": "FailedInnerCall", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "SafeERC20FailedOperation", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "id", + "type": "bytes32" + } + ], + "name": "MakerPaymentRefundedSecret", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "id", + "type": "bytes32" + } + ], + "name": "MakerPaymentRefundedTimelock", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "id", + "type": "bytes32" + } + ], + "name": "MakerPaymentSent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "id", + "type": "bytes32" + } + ], + "name": "MakerPaymentSpent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "id", + "type": "bytes32" + } + ], + "name": "TakerPaymentApproved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "id", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "secret", + "type": "bytes32" + } + ], + "name": "TakerPaymentRefundedSecret", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "id", + "type": "bytes32" + } + ], + "name": "TakerPaymentRefundedTimelock", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "id", + "type": "bytes32" + } + ], + "name": "TakerPaymentSent", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bytes32", + "name": "id", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "secret", + "type": "bytes32" + } + ], + "name": "TakerPaymentSpent", + "type": "event" + }, + { + "inputs": [], + "name": "dexFeeAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dexFee", + "type": "uint256" + }, + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "takerSecretHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "makerSecretHash", + "type": "bytes32" + }, + { + "internalType": "uint32", + "name": "preApproveLockTime", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "paymentLockTime", + "type": "uint32" + } + ], + "name": "erc20TakerPayment", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "dexFee", + "type": "uint256" + }, + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "takerSecretHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "makerSecretHash", + "type": "bytes32" + }, + { + "internalType": "uint32", + "name": "preApproveLockTime", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "paymentLockTime", + "type": "uint32" + } + ], + "name": "ethTakerPayment", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "makerPayments", + "outputs": [ + { + "internalType": "bytes20", + "name": "paymentHash", + "type": "bytes20" + }, + { + "internalType": "uint32", + "name": "paymentLockTime", + "type": "uint32" + }, + { + "internalType": "enum EtomicSwapNft.MakerPaymentState", + "name": "state", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onERC1155BatchReceived", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "onERC1155Received", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "onERC721Received", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "taker", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "takerSecret", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "makerSecretHash", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "refundErc1155MakerPaymentSecret", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "taker", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "takerSecretHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "makerSecretHash", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "refundErc1155MakerPaymentTimelock", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "taker", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "takerSecret", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "makerSecretHash", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "refundErc721MakerPaymentSecret", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "taker", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "takerSecretHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "makerSecretHash", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "refundErc721MakerPaymentTimelock", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dexFee", + "type": "uint256" + }, + { + "internalType": "address", + "name": "maker", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "takerSecret", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "makerSecretHash", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + } + ], + "name": "refundTakerPaymentSecret", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dexFee", + "type": "uint256" + }, + { + "internalType": "address", + "name": "maker", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "takerSecretHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "makerSecretHash", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + } + ], + "name": "refundTakerPaymentTimelock", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "maker", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "takerSecretHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "makerSecret", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "spendErc1155MakerPayment", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "maker", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "takerSecretHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "makerSecret", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "spendErc721MakerPayment", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dexFee", + "type": "uint256" + }, + { + "internalType": "address", + "name": "taker", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "takerSecretHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "makerSecret", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + } + ], + "name": "spendTakerPayment", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "id", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "dexFee", + "type": "uint256" + }, + { + "internalType": "address", + "name": "maker", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "takerSecretHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "makerSecretHash", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + } + ], + "name": "takerPaymentApprove", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "takerPayments", + "outputs": [ + { + "internalType": "bytes20", + "name": "paymentHash", + "type": "bytes20" + }, + { + "internalType": "uint32", + "name": "preApproveLockTime", + "type": "uint32" + }, + { + "internalType": "uint32", + "name": "paymentLockTime", + "type": "uint32" + }, + { + "internalType": "enum EtomicSwapNft.TakerPaymentState", + "name": "state", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 5179a5db80..455bb78c0f 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -1575,6 +1575,45 @@ pub trait MakerCoinSwapOpsV2: CoinAssocTypes + Send + Sync + 'static { async fn spend_maker_payment_v2(&self, args: SpendMakerPaymentArgs<'_, Self>) -> Result; } +#[async_trait] +pub trait MakerNftSwapOpsV2: CoinAssocTypes + Send + Sync + 'static { + /// Spend ERC721 maker payment transaction + async fn spend_erc721_maker_payment_v2( + &self, + args: SpendMakerPaymentArgs<'_, Self>, + ) -> Result; + + /// Spend ERC1155 maker payment transaction + async fn spend_erc1155_maker_payment_v2( + &self, + args: SpendMakerPaymentArgs<'_, Self>, + ) -> Result; + + /// Refund ERC721 maker payment transaction using timelock path + async fn refund_erc721_maker_payment_v2_timelock( + &self, + args: RefundPaymentArgs<'_>, + ) -> Result; + + /// Refund ERC1155 maker payment transaction using timelock path + async fn refund_erc1155_maker_payment_v2_timelock( + &self, + args: RefundPaymentArgs<'_>, + ) -> Result; + + /// Refund ERC721 maker payment transaction using immediate refund path + async fn refund_erc721_maker_payment_v2_secret( + &self, + args: RefundMakerPaymentArgs<'_, Self>, + ) -> Result; + + /// Refund ERC1155 maker payment transaction using immediate refund path + async fn refund_erc1155_maker_payment_v2_secret( + &self, + args: RefundMakerPaymentArgs<'_, Self>, + ) -> Result; +} + /// Enum representing errors that can occur while waiting for taker payment spend. #[derive(Display)] pub enum WaitForTakerPaymentSpendError { @@ -3769,7 +3808,7 @@ pub enum CoinProtocol { decimals: u8, }, ZHTLC(ZcoinProtocolInfo), - Nft { + NFT { platform: String, }, } @@ -4024,7 +4063,7 @@ pub async fn lp_coininit(ctx: &MmArc, ticker: &str, req: &Json) -> Result return ERR!("TENDERMINT protocol is not supported by lp_coininit"), CoinProtocol::TENDERMINTTOKEN(_) => return ERR!("TENDERMINTTOKEN protocol is not supported by lp_coininit"), CoinProtocol::ZHTLC { .. } => return ERR!("ZHTLC protocol is not supported by lp_coininit"), - CoinProtocol::Nft { .. } => return ERR!("NFT protocol is not supported by lp_coininit"), + CoinProtocol::NFT { .. } => return ERR!("NFT protocol is not supported by lp_coininit"), #[cfg(not(target_arch = "wasm32"))] CoinProtocol::LIGHTNING { .. } => return ERR!("Lightning protocol is not supported by lp_coininit"), #[cfg(all(feature = "enable-solana", not(target_arch = "wasm32")))] @@ -4568,7 +4607,7 @@ pub fn address_by_coin_conf_and_pubkey_str( ) -> Result { let protocol: CoinProtocol = try_s!(json::from_value(conf["protocol"].clone())); match protocol { - CoinProtocol::ERC20 { .. } | CoinProtocol::ETH | CoinProtocol::Nft { .. } => eth::addr_from_pubkey_str(pubkey), + CoinProtocol::ERC20 { .. } | CoinProtocol::ETH | CoinProtocol::NFT { .. } => eth::addr_from_pubkey_str(pubkey), CoinProtocol::UTXO | CoinProtocol::QTUM | CoinProtocol::QRC20 { .. } | CoinProtocol::BCH { .. } => { utxo::address_by_conf_and_pubkey_str(coin, conf, pubkey, addr_format) }, diff --git a/mm2src/coins_activation/src/erc20_token_activation.rs b/mm2src/coins_activation/src/erc20_token_activation.rs index 027f767539..173092c65d 100644 --- a/mm2src/coins_activation/src/erc20_token_activation.rs +++ b/mm2src/coins_activation/src/erc20_token_activation.rs @@ -88,7 +88,7 @@ impl TryFromCoinProtocol for EthTokenProtocol { let erc20_protocol = Erc20Protocol::try_from_coin_protocol(proto)?; Ok(EthTokenProtocol::Erc20(erc20_protocol)) }, - CoinProtocol::Nft { platform } => Ok(EthTokenProtocol::Nft(NftProtocol { platform })), + CoinProtocol::NFT { platform } => Ok(EthTokenProtocol::Nft(NftProtocol { platform })), proto => MmError::err(proto), } } diff --git a/mm2src/coins_activation/src/prelude.rs b/mm2src/coins_activation/src/prelude.rs index 21a04ed8ad..967a4cae68 100644 --- a/mm2src/coins_activation/src/prelude.rs +++ b/mm2src/coins_activation/src/prelude.rs @@ -82,7 +82,7 @@ pub fn coin_conf_with_protocol( Ok(chain) => { let platform = chain.to_ticker(); let platform_conf = coin_conf(ctx, platform); - let nft_protocol = CoinProtocol::Nft { + let nft_protocol = CoinProtocol::NFT { platform: platform.to_string(), }; (platform_conf, nft_protocol) diff --git a/mm2src/mm2_main/src/lp_ordermatch.rs b/mm2src/mm2_main/src/lp_ordermatch.rs index a1393bf71e..04699c0dee 100644 --- a/mm2src/mm2_main/src/lp_ordermatch.rs +++ b/mm2src/mm2_main/src/lp_ordermatch.rs @@ -5802,7 +5802,7 @@ fn orderbook_address( ) -> Result> { let protocol: CoinProtocol = json::from_value(conf["protocol"].clone())?; match protocol { - CoinProtocol::ERC20 { .. } | CoinProtocol::ETH | CoinProtocol::Nft { .. } => { + CoinProtocol::ERC20 { .. } | CoinProtocol::ETH | CoinProtocol::NFT { .. } => { coins::eth::addr_from_pubkey_str(pubkey) .map(OrderbookAddress::Transparent) .map_to_mm(OrderbookAddrErr::AddrFromPubkeyError) diff --git a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs index 613ec4373e..ffec8335a7 100644 --- a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs +++ b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs @@ -80,6 +80,12 @@ pub static mut GETH_ERC20_CONTRACT: H160Eth = H160Eth::zero(); pub static mut GETH_SWAP_CONTRACT: H160Eth = H160Eth::zero(); /// Swap contract (with watchers support) address on Geth dev node pub static mut GETH_WATCHERS_SWAP_CONTRACT: H160Eth = H160Eth::zero(); +/// ERC721 token address on Geth dev node +pub static mut GETH_ERC721_CONTRACT: H160Eth = H160Eth::zero(); +/// ERC1155 token address on Geth dev node +pub static mut GETH_ERC1155_CONTRACT: H160Eth = H160Eth::zero(); +/// Nft Swap contract address on Geth dev node +pub static mut GETH_NFT_SWAP_CONTRACT: H160Eth = H160Eth::zero(); pub static GETH_RPC_URL: &str = "http://127.0.0.1:8545"; pub const UTXO_ASSET_DOCKER_IMAGE: &str = "docker.io/artempikulin/testblockchain"; @@ -89,6 +95,9 @@ pub const GETH_DOCKER_IMAGE_WITH_TAG: &str = "docker.io/ethereum/client-go:stabl pub const QTUM_ADDRESS_LABEL: &str = "MM2_ADDRESS_LABEL"; +pub const ERC721_TEST_ABI: &str = include_str!("../../../mm2_test_helpers/dummy_files/erc721_test_abi.json"); +pub const ERC1155_TEST_ABI: &str = include_str!("../../../mm2_test_helpers/dummy_files/erc1155_test_abi.json"); + /// Ticker of MYCOIN dockerized blockchain. pub const MYCOIN: &str = "MYCOIN"; /// Ticker of MYCOIN1 dockerized blockchain. @@ -97,6 +106,11 @@ pub const MYCOIN1: &str = "MYCOIN1"; pub const ERC20_TOKEN_BYTES: &str = "6080604052600860ff16600a0a633b9aca000260005534801561002157600080fd5b50600054600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610c69806100776000396000f3006080604052600436106100a4576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100a9578063095ea7b31461013957806318160ddd1461019e57806323b872dd146101c9578063313ce5671461024e5780635a3b7e421461027f57806370a082311461030f57806395d89b4114610366578063a9059cbb146103f6578063dd62ed3e1461045b575b600080fd5b3480156100b557600080fd5b506100be6104d2565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100fe5780820151818401526020810190506100e3565b50505050905090810190601f16801561012b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561014557600080fd5b50610184600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061050b565b604051808215151515815260200191505060405180910390f35b3480156101aa57600080fd5b506101b36106bb565b6040518082815260200191505060405180910390f35b3480156101d557600080fd5b50610234600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506106c1565b604051808215151515815260200191505060405180910390f35b34801561025a57600080fd5b506102636109a1565b604051808260ff1660ff16815260200191505060405180910390f35b34801561028b57600080fd5b506102946109a6565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156102d45780820151818401526020810190506102b9565b50505050905090810190601f1680156103015780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561031b57600080fd5b50610350600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506109df565b6040518082815260200191505060405180910390f35b34801561037257600080fd5b5061037b6109f7565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103bb5780820151818401526020810190506103a0565b50505050905090810190601f1680156103e85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561040257600080fd5b50610441600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610a30565b604051808215151515815260200191505060405180910390f35b34801561046757600080fd5b506104bc600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610be1565b6040518082815260200191505060405180910390f35b6040805190810160405280600881526020017f515243205445535400000000000000000000000000000000000000000000000081525081565b60008260008173ffffffffffffffffffffffffffffffffffffffff161415151561053457600080fd5b60008314806105bf57506000600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054145b15156105ca57600080fd5b82600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925856040518082815260200191505060405180910390a3600191505092915050565b60005481565b60008360008173ffffffffffffffffffffffffffffffffffffffff16141515156106ea57600080fd5b8360008173ffffffffffffffffffffffffffffffffffffffff161415151561071157600080fd5b610797600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205485610c06565b600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610860600160008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205485610c06565b600160008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506108ec600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205485610c1f565b600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef866040518082815260200191505060405180910390a36001925050509392505050565b600881565b6040805190810160405280600981526020017f546f6b656e20302e31000000000000000000000000000000000000000000000081525081565b60016020528060005260406000206000915090505481565b6040805190810160405280600381526020017f515443000000000000000000000000000000000000000000000000000000000081525081565b60008260008173ffffffffffffffffffffffffffffffffffffffff1614151515610a5957600080fd5b610aa2600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205484610c06565b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610b2e600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205484610c1f565b600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a3600191505092915050565b6002602052816000526040600020602052806000526040600020600091509150505481565b6000818310151515610c1457fe5b818303905092915050565b6000808284019050838110151515610c3357fe5b80915050929150505600a165627a7a723058207f2e5248b61b80365ea08a0f6d11ac0b47374c4dfd538de76bc2f19591bbbba40029"; pub const SWAP_CONTRACT_BYTES: &str = "608060405234801561001057600080fd5b50611437806100206000396000f3fe60806040526004361061004a5760003560e01c806302ed292b1461004f5780630716326d146100de578063152cf3af1461017b57806346fc0294146101f65780639b415b2a14610294575b600080fd5b34801561005b57600080fd5b506100dc600480360360a081101561007257600080fd5b81019080803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610339565b005b3480156100ea57600080fd5b506101176004803603602081101561010157600080fd5b8101908080359060200190929190505050610867565b60405180846bffffffffffffffffffffffff19166bffffffffffffffffffffffff191681526020018367ffffffffffffffff1667ffffffffffffffff16815260200182600381111561016557fe5b60ff168152602001935050505060405180910390f35b6101f46004803603608081101561019157600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080356bffffffffffffffffffffffff19169060200190929190803567ffffffffffffffff1690602001909291905050506108bf565b005b34801561020257600080fd5b50610292600480360360a081101561021957600080fd5b81019080803590602001909291908035906020019092919080356bffffffffffffffffffffffff19169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610bd9565b005b610337600480360360c08110156102aa57600080fd5b810190808035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080356bffffffffffffffffffffffff19169060200190929190803567ffffffffffffffff169060200190929190505050610fe2565b005b6001600381111561034657fe5b600080878152602001908152602001600020600001601c9054906101000a900460ff16600381111561037457fe5b1461037e57600080fd5b6000600333836003600288604051602001808281526020019150506040516020818303038152906040526040518082805190602001908083835b602083106103db57805182526020820191506020810190506020830392506103b8565b6001836020036101000a038019825116818451168082178552505050505050905001915050602060405180830381855afa15801561041d573d6000803e3d6000fd5b5050506040513d602081101561043257600080fd5b8101908080519060200190929190505050604051602001808281526020019150506040516020818303038152906040526040518082805190602001908083835b602083106104955780518252602082019150602081019050602083039250610472565b6001836020036101000a038019825116818451168082178552505050505050905001915050602060405180830381855afa1580156104d7573d6000803e3d6000fd5b5050506040515160601b8689604051602001808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b8152601401846bffffffffffffffffffffffff19166bffffffffffffffffffffffff191681526014018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b8152601401828152602001955050505050506040516020818303038152906040526040518082805190602001908083835b602083106105fc57805182526020820191506020810190506020830392506105d9565b6001836020036101000a038019825116818451168082178552505050505050905001915050602060405180830381855afa15801561063e573d6000803e3d6000fd5b5050506040515160601b905060008087815260200190815260200160002060000160009054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461069657600080fd5b6002600080888152602001908152602001600020600001601c6101000a81548160ff021916908360038111156106c857fe5b0217905550600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141561074e573373ffffffffffffffffffffffffffffffffffffffff166108fc869081150290604051600060405180830381858888f19350505050158015610748573d6000803e3d6000fd5b50610820565b60008390508073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33886040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156107da57600080fd5b505af11580156107ee573d6000803e3d6000fd5b505050506040513d602081101561080457600080fd5b810190808051906020019092919050505061081e57600080fd5b505b7f36c177bcb01c6d568244f05261e2946c8c977fa50822f3fa098c470770ee1f3e8685604051808381526020018281526020019250505060405180910390a1505050505050565b60006020528060005260406000206000915090508060000160009054906101000a900460601b908060000160149054906101000a900467ffffffffffffffff169080600001601c9054906101000a900460ff16905083565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141580156108fc5750600034115b801561094057506000600381111561091057fe5b600080868152602001908152602001600020600001601c9054906101000a900460ff16600381111561093e57fe5b145b61094957600080fd5b60006003843385600034604051602001808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b8152601401846bffffffffffffffffffffffff19166bffffffffffffffffffffffff191681526014018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b8152601401828152602001955050505050506040516020818303038152906040526040518082805190602001908083835b60208310610a6c5780518252602082019150602081019050602083039250610a49565b6001836020036101000a038019825116818451168082178552505050505050905001915050602060405180830381855afa158015610aae573d6000803e3d6000fd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018367ffffffffffffffff16815260200160016003811115610af757fe5b81525060008087815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c021790555060208201518160000160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550604082015181600001601c6101000a81548160ff02191690836003811115610b9357fe5b02179055509050507fccc9c05183599bd3135da606eaaf535daffe256e9de33c048014cffcccd4ad57856040518082815260200191505060405180910390a15050505050565b60016003811115610be657fe5b600080878152602001908152602001600020600001601c9054906101000a900460ff166003811115610c1457fe5b14610c1e57600080fd5b600060038233868689604051602001808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b8152601401846bffffffffffffffffffffffff19166bffffffffffffffffffffffff191681526014018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b8152601401828152602001955050505050506040516020818303038152906040526040518082805190602001908083835b60208310610d405780518252602082019150602081019050602083039250610d1d565b6001836020036101000a038019825116818451168082178552505050505050905001915050602060405180830381855afa158015610d82573d6000803e3d6000fd5b5050506040515160601b905060008087815260200190815260200160002060000160009054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916148015610e10575060008087815260200190815260200160002060000160149054906101000a900467ffffffffffffffff1667ffffffffffffffff164210155b610e1957600080fd5b6003600080888152602001908152602001600020600001601c6101000a81548160ff02191690836003811115610e4b57fe5b0217905550600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610ed1573373ffffffffffffffffffffffffffffffffffffffff166108fc869081150290604051600060405180830381858888f19350505050158015610ecb573d6000803e3d6000fd5b50610fa3565b60008390508073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33886040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015610f5d57600080fd5b505af1158015610f71573d6000803e3d6000fd5b505050506040513d6020811015610f8757600080fd5b8101908080519060200190929190505050610fa157600080fd5b505b7f1797d500133f8e427eb9da9523aa4a25cb40f50ebc7dbda3c7c81778973f35ba866040518082815260200191505060405180910390a1505050505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415801561101f5750600085115b801561106357506000600381111561103357fe5b600080888152602001908152602001600020600001601c9054906101000a900460ff16600381111561106157fe5b145b61106c57600080fd5b60006003843385888a604051602001808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b8152601401846bffffffffffffffffffffffff19166bffffffffffffffffffffffff191681526014018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b8152601401828152602001955050505050506040516020818303038152906040526040518082805190602001908083835b6020831061118e578051825260208201915060208101905060208303925061116b565b6001836020036101000a038019825116818451168082178552505050505050905001915050602060405180830381855afa1580156111d0573d6000803e3d6000fd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018367ffffffffffffffff1681526020016001600381111561121957fe5b81525060008089815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c021790555060208201518160000160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550604082015181600001601c6101000a81548160ff021916908360038111156112b557fe5b021790555090505060008590508073ffffffffffffffffffffffffffffffffffffffff166323b872dd33308a6040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b15801561137d57600080fd5b505af1158015611391573d6000803e3d6000fd5b505050506040513d60208110156113a757600080fd5b81019080805190602001909291905050506113c157600080fd5b7fccc9c05183599bd3135da606eaaf535daffe256e9de33c048014cffcccd4ad57886040518082815260200191505060405180910390a1505050505050505056fea265627a7a723158208c83db436905afce0b7be1012be64818c49323c12d451fe2ab6bce76ff6421c964736f6c63430005110032"; pub const WATCHERS_SWAP_CONTRACT_BYTES: &str = "608060405234801561000f575f80fd5b50612aa48061001d5f395ff3fe608060405260043610610085575f3560e01c806346fc02941161005857806346fc0294146101275780636a3227861461014f5780639b415b2a1461016b578063b5985c4d14610193578063cd1dde34146101bb57610085565b806302ed292b146100895780630716326d146100b15780630971fd54146100ef578063152cf3af1461010b575b5f80fd5b348015610094575f80fd5b506100af60048036038101906100aa9190611e1d565b6101e3565b005b3480156100bc575f80fd5b506100d760048036038101906100d29190611e94565b610518565b6040516100e693929190611f8e565b60405180910390f35b6101096004803603810190610104919061206f565b610568565b005b6101256004803603810190610120919061210c565b610787565b005b348015610132575f80fd5b5061014d60048036038101906101489190612170565b61099d565b005b610169600480360381019061016491906121e7565b610c4d565b005b348015610176575f80fd5b50610191600480360381019061018c91906122ab565b610f61565b005b34801561019e575f80fd5b506101b960048036038101906101b49190612334565b611203565b005b3480156101c6575f80fd5b506101e160048036038101906101dc91906123f8565b611887565b005b600160038111156101f7576101f6611f1b565b5b5f808781526020019081526020015f205f01601c9054906101000a900460ff16600381111561022957610228611f1b565b5b14610232575f80fd5b5f60033383600360028860405160200161024c91906124dc565b6040516020818303038152906040526040516102689190612562565b602060405180830381855afa158015610283573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906102a6919061258c565b6040516020016102b691906124dc565b6040516020818303038152906040526040516102d29190612562565b602060405180830381855afa1580156102ed573d5f803e3d5ffd5b5050506040515160601b868960405160200161030d95949392919061263c565b6040516020818303038152906040526040516103299190612562565b602060405180830381855afa158015610344573d5f803e3d5ffd5b5050506040515160601b90505f808781526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610397575f80fd5b60025f808881526020019081526020015f205f01601c6101000a81548160ff021916908360038111156103cd576103cc611f1b565b5b02179055505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361044e573373ffffffffffffffffffffffffffffffffffffffff166108fc8690811502906040515f60405180830381858888f19350505050158015610448573d5f803e3d5ffd5b506104d7565b5f8390508073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33886040518363ffffffff1660e01b815260040161048d9291906126b8565b6020604051808303815f875af11580156104a9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104cd91906126f3565b6104d5575f80fd5b505b7f36c177bcb01c6d568244f05261e2946c8c977fa50822f3fa098c470770ee1f3e868560405161050892919061272d565b60405180910390a1505050505050565b5f602052805f5260405f205f91509050805f015f9054906101000a900460601b90805f0160149054906101000a900467ffffffffffffffff1690805f01601c9054906101000a900460ff16905083565b5f73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16141580156105a357505f34115b80156105f157505f60038111156105bd576105bc611f1b565b5b5f808981526020019081526020015f205f01601c9054906101000a900460ff1660038111156105ef576105ee611f1b565b5b145b6105f9575f80fd5b5f60038733885f3489898960405160200161061b9897969594939291906127e7565b6040516020818303038152906040526040516106379190612562565b602060405180830381855afa158015610652573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018667ffffffffffffffff168152602001600160038111156106a2576106a1611f1b565b5b8152505f808a81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506040820151815f01601c6101000a81548160ff0219169083600381111561073e5761073d611f1b565b5b02179055509050507fccc9c05183599bd3135da606eaaf535daffe256e9de33c048014cffcccd4ad57886040516107759190612878565b60405180910390a15050505050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141580156107c257505f34115b801561081057505f60038111156107dc576107db611f1b565b5b5f808681526020019081526020015f205f01601c9054906101000a900460ff16600381111561080e5761080d611f1b565b5b145b610818575f80fd5b5f60038433855f3460405160200161083495949392919061263c565b6040516020818303038152906040526040516108509190612562565b602060405180830381855afa15801561086b573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018367ffffffffffffffff168152602001600160038111156108bb576108ba611f1b565b5b8152505f808781526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506040820151815f01601c6101000a81548160ff0219169083600381111561095757610956611f1b565b5b02179055509050507fccc9c05183599bd3135da606eaaf535daffe256e9de33c048014cffcccd4ad578560405161098e9190612878565b60405180910390a15050505050565b600160038111156109b1576109b0611f1b565b5b5f808781526020019081526020015f205f01601c9054906101000a900460ff1660038111156109e3576109e2611f1b565b5b146109ec575f80fd5b5f60038233868689604051602001610a0895949392919061263c565b604051602081830303815290604052604051610a249190612562565b602060405180830381855afa158015610a3f573d5f803e3d5ffd5b5050506040515160601b90505f808781526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916148015610ac657505f808781526020019081526020015f205f0160149054906101000a900467ffffffffffffffff1667ffffffffffffffff164210155b610ace575f80fd5b60035f808881526020019081526020015f205f01601c6101000a81548160ff02191690836003811115610b0457610b03611f1b565b5b02179055505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610b85573373ffffffffffffffffffffffffffffffffffffffff166108fc8690811502906040515f60405180830381858888f19350505050158015610b7f573d5f803e3d5ffd5b50610c0e565b5f8390508073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33886040518363ffffffff1660e01b8152600401610bc49291906126b8565b6020604051808303815f875af1158015610be0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c0491906126f3565b610c0c575f80fd5b505b7f1797d500133f8e427eb9da9523aa4a25cb40f50ebc7dbda3c7c81778973f35ba86604051610c3d9190612878565b60405180910390a1505050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614158015610c8857505f88115b8015610cd657505f6003811115610ca257610ca1611f1b565b5b5f808b81526020019081526020015f205f01601c9054906101000a900460ff166003811115610cd457610cd3611f1b565b5b145b610cde575f80fd5b5f6003811115610cf157610cf0611f1b565b5b836003811115610d0457610d03611f1b565b5b14158015610d365750600380811115610d2057610d1f611f1b565b5b836003811115610d3357610d32611f1b565b5b14155b15610d4757803414610d46575f80fd5b5b5f60038733888b8d898989604051602001610d699897969594939291906127e7565b604051602081830303815290604052604051610d859190612562565b602060405180830381855afa158015610da0573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018667ffffffffffffffff16815260200160016003811115610df057610def611f1b565b5b8152505f808c81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506040820151815f01601c6101000a81548160ff02191690836003811115610e8c57610e8b611f1b565b5b02179055509050505f8890508073ffffffffffffffffffffffffffffffffffffffff166323b872dd33308d6040518463ffffffff1660e01b8152600401610ed593929190612891565b6020604051808303815f875af1158015610ef1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f1591906126f3565b610f1d575f80fd5b7fccc9c05183599bd3135da606eaaf535daffe256e9de33c048014cffcccd4ad578b604051610f4c9190612878565b60405180910390a15050505050505050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614158015610f9c57505f85115b8015610fea57505f6003811115610fb657610fb5611f1b565b5b5f808881526020019081526020015f205f01601c9054906101000a900460ff166003811115610fe857610fe7611f1b565b5b145b610ff2575f80fd5b5f6003843385888a60405160200161100e95949392919061263c565b60405160208183030381529060405260405161102a9190612562565b602060405180830381855afa158015611045573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018367ffffffffffffffff1681526020016001600381111561109557611094611f1b565b5b8152505f808981526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506040820151815f01601c6101000a81548160ff0219169083600381111561113157611130611f1b565b5b02179055509050505f8590508073ffffffffffffffffffffffffffffffffffffffff166323b872dd33308a6040518463ffffffff1660e01b815260040161117a93929190612891565b6020604051808303815f875af1158015611196573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111ba91906126f3565b6111c2575f80fd5b7fccc9c05183599bd3135da606eaaf535daffe256e9de33c048014cffcccd4ad57886040516111f19190612878565b60405180910390a15050505050505050565b6001600381111561121757611216611f1b565b5b5f808b81526020019081526020015f205f01601c9054906101000a900460ff16600381111561124957611248611f1b565b5b14611289576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161128090612920565b60405180910390fd5b5f60038587600360028c6040516020016112a391906124dc565b6040516020818303038152906040526040516112bf9190612562565b602060405180830381855afa1580156112da573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906112fd919061258c565b60405160200161130d91906124dc565b6040516020818303038152906040526040516113299190612562565b602060405180830381855afa158015611344573d5f803e3d5ffd5b5050506040515160601b8a8d89898960405160200161136a9897969594939291906127e7565b6040516020818303038152906040526040516113869190612562565b602060405180830381855afa1580156113a1573d5f803e3d5ffd5b5050506040515160601b90505f808b81526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461142b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161142290612988565b60405180910390fd5b60025f808c81526020019081526020015f205f01601c6101000a81548160ff0219169083600381111561146157611460611f1b565b5b02179055505f73ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff160361159e575f8060038111156114ad576114ac611f1b565b5b8560038111156114c0576114bf611f1b565b5b1480156114cb575083155b6114e057828a6114db91906129d3565b6114e2565b895b90508573ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f19350505050158015611527573d5f803e3d5ffd5b5060038081111561153b5761153a611f1b565b5b85600381111561154e5761154d611f1b565b5b03611598573373ffffffffffffffffffffffffffffffffffffffff166108fc8490811502906040515f60405180830381858888f19350505050158015611596573d5f803e3d5ffd5b505b50611786565b5f6003808111156115b2576115b1611f1b565b5b8560038111156115c5576115c4611f1b565b5b146115d057896115dd565b828a6115dc91906129d3565b5b90505f8890508073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb88846040518363ffffffff1660e01b815260040161161e9291906126b8565b6020604051808303815f875af115801561163a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061165e91906126f3565b61169d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161169490612a50565b60405180910390fd5b6003808111156116b0576116af611f1b565b5b8660038111156116c3576116c2611f1b565b5b03611783578073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33866040518363ffffffff1660e01b81526004016117039291906126b8565b6020604051808303815f875af115801561171f573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061174391906126f3565b611782576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161177990612a50565b60405180910390fd5b5b50505b6002600381111561179a57611799611f1b565b5b8460038111156117ad576117ac611f1b565b5b036117f7578573ffffffffffffffffffffffffffffffffffffffff166108fc8390811502906040515f60405180830381858888f193505050501580156117f5573d5f803e3d5ffd5b505b8215611842573373ffffffffffffffffffffffffffffffffffffffff166108fc8390811502906040515f60405180830381858888f19350505050158015611840573d5f803e3d5ffd5b505b7f36c177bcb01c6d568244f05261e2946c8c977fa50822f3fa098c470770ee1f3e8a8960405161187392919061272d565b60405180910390a150505050505050505050565b6001600381111561189b5761189a611f1b565b5b5f808b81526020019081526020015f205f01601c9054906101000a900460ff1660038111156118cd576118cc611f1b565b5b146118d6575f80fd5b5f600385878a8a8d8989896040516020016118f89897969594939291906127e7565b6040516020818303038152906040526040516119149190612562565b602060405180830381855afa15801561192f573d5f803e3d5ffd5b5050506040515160601b90505f808b81526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161480156119b657505f808b81526020019081526020015f205f0160149054906101000a900467ffffffffffffffff1667ffffffffffffffff164210155b6119be575f80fd5b60035f808c81526020019081526020015f205f01601c6101000a81548160ff021916908360038111156119f4576119f3611f1b565b5b02179055505f73ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1603611b27575f806003811115611a4057611a3f611f1b565b5b856003811115611a5357611a52611f1b565b5b14611a6957828a611a6491906129d3565b611a6b565b895b90508673ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f19350505050158015611ab0573d5f803e3d5ffd5b505f6003811115611ac457611ac3611f1b565b5b856003811115611ad757611ad6611f1b565b5b14611b21573373ffffffffffffffffffffffffffffffffffffffff166108fc8490811502906040515f60405180830381858888f19350505050158015611b1f573d5f803e3d5ffd5b505b50611d16565b5f600380811115611b3b57611b3a611f1b565b5b856003811115611b4e57611b4d611f1b565b5b14611b595789611b66565b828a611b6591906129d3565b5b90505f8890508073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb89846040518363ffffffff1660e01b8152600401611ba79291906126b8565b6020604051808303815f875af1158015611bc3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611be791906126f3565b611bef575f80fd5b600380811115611c0257611c01611f1b565b5b866003811115611c1557611c14611f1b565b5b03611ca2578073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33866040518363ffffffff1660e01b8152600401611c559291906126b8565b6020604051808303815f875af1158015611c71573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c9591906126f3565b611c9d575f80fd5b611d13565b5f6003811115611cb557611cb4611f1b565b5b866003811115611cc857611cc7611f1b565b5b14611d12573373ffffffffffffffffffffffffffffffffffffffff166108fc8590811502906040515f60405180830381858888f19350505050158015611d10573d5f803e3d5ffd5b505b5b50505b7f1797d500133f8e427eb9da9523aa4a25cb40f50ebc7dbda3c7c81778973f35ba8a604051611d459190612878565b60405180910390a150505050505050505050565b5f80fd5b5f819050919050565b611d6f81611d5d565b8114611d79575f80fd5b50565b5f81359050611d8a81611d66565b92915050565b5f819050919050565b611da281611d90565b8114611dac575f80fd5b50565b5f81359050611dbd81611d99565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f611dec82611dc3565b9050919050565b611dfc81611de2565b8114611e06575f80fd5b50565b5f81359050611e1781611df3565b92915050565b5f805f805f60a08688031215611e3657611e35611d59565b5b5f611e4388828901611d7c565b9550506020611e5488828901611daf565b9450506040611e6588828901611d7c565b9350506060611e7688828901611e09565b9250506080611e8788828901611e09565b9150509295509295909350565b5f60208284031215611ea957611ea8611d59565b5b5f611eb684828501611d7c565b91505092915050565b5f7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b611ef381611ebf565b82525050565b5f67ffffffffffffffff82169050919050565b611f1581611ef9565b82525050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60048110611f5957611f58611f1b565b5b50565b5f819050611f6982611f48565b919050565b5f611f7882611f5c565b9050919050565b611f8881611f6e565b82525050565b5f606082019050611fa15f830186611eea565b611fae6020830185611f0c565b611fbb6040830184611f7f565b949350505050565b611fcc81611ebf565b8114611fd6575f80fd5b50565b5f81359050611fe781611fc3565b92915050565b611ff681611ef9565b8114612000575f80fd5b50565b5f8135905061201181611fed565b92915050565b60048110612023575f80fd5b50565b5f8135905061203481612017565b92915050565b5f8115159050919050565b61204e8161203a565b8114612058575f80fd5b50565b5f8135905061206981612045565b92915050565b5f805f805f805f60e0888a03121561208a57612089611d59565b5b5f6120978a828b01611d7c565b97505060206120a88a828b01611e09565b96505060406120b98a828b01611fd9565b95505060606120ca8a828b01612003565b94505060806120db8a828b01612026565b93505060a06120ec8a828b0161205b565b92505060c06120fd8a828b01611daf565b91505092959891949750929550565b5f805f806080858703121561212457612123611d59565b5b5f61213187828801611d7c565b945050602061214287828801611e09565b935050604061215387828801611fd9565b925050606061216487828801612003565b91505092959194509250565b5f805f805f60a0868803121561218957612188611d59565b5b5f61219688828901611d7c565b95505060206121a788828901611daf565b94505060406121b888828901611fd9565b93505060606121c988828901611e09565b92505060806121da88828901611e09565b9150509295509295909350565b5f805f805f805f805f6101208a8c03121561220557612204611d59565b5b5f6122128c828d01611d7c565b99505060206122238c828d01611daf565b98505060406122348c828d01611e09565b97505060606122458c828d01611e09565b96505060806122568c828d01611fd9565b95505060a06122678c828d01612003565b94505060c06122788c828d01612026565b93505060e06122898c828d0161205b565b92505061010061229b8c828d01611daf565b9150509295985092959850929598565b5f805f805f8060c087890312156122c5576122c4611d59565b5b5f6122d289828a01611d7c565b96505060206122e389828a01611daf565b95505060406122f489828a01611e09565b945050606061230589828a01611e09565b935050608061231689828a01611fd9565b92505060a061232789828a01612003565b9150509295509295509295565b5f805f805f805f805f6101208a8c03121561235257612351611d59565b5b5f61235f8c828d01611d7c565b99505060206123708c828d01611daf565b98505060406123818c828d01611d7c565b97505060606123928c828d01611e09565b96505060806123a38c828d01611e09565b95505060a06123b48c828d01611e09565b94505060c06123c58c828d01612026565b93505060e06123d68c828d0161205b565b9250506101006123e88c828d01611daf565b9150509295985092959850929598565b5f805f805f805f805f6101208a8c03121561241657612415611d59565b5b5f6124238c828d01611d7c565b99505060206124348c828d01611daf565b98505060406124458c828d01611fd9565b97505060606124568c828d01611e09565b96505060806124678c828d01611e09565b95505060a06124788c828d01611e09565b94505060c06124898c828d01612026565b93505060e061249a8c828d0161205b565b9250506101006124ac8c828d01611daf565b9150509295985092959850929598565b5f819050919050565b6124d66124d182611d5d565b6124bc565b82525050565b5f6124e782846124c5565b60208201915081905092915050565b5f81519050919050565b5f81905092915050565b5f5b8381101561252757808201518184015260208101905061250c565b5f8484015250505050565b5f61253c826124f6565b6125468185612500565b935061255681856020860161250a565b80840191505092915050565b5f61256d8284612532565b915081905092915050565b5f8151905061258681611d66565b92915050565b5f602082840312156125a1576125a0611d59565b5b5f6125ae84828501612578565b91505092915050565b5f8160601b9050919050565b5f6125cd826125b7565b9050919050565b5f6125de826125c3565b9050919050565b6125f66125f182611de2565b6125d4565b82525050565b5f819050919050565b61261661261182611ebf565b6125fc565b82525050565b5f819050919050565b61263661263182611d90565b61261c565b82525050565b5f61264782886125e5565b60148201915061265782876125e5565b6014820191506126678286612605565b60148201915061267782856125e5565b6014820191506126878284612625565b6020820191508190509695505050505050565b6126a381611de2565b82525050565b6126b281611d90565b82525050565b5f6040820190506126cb5f83018561269a565b6126d860208301846126a9565b9392505050565b5f815190506126ed81612045565b92915050565b5f6020828403121561270857612707611d59565b5b5f612715848285016126df565b91505092915050565b61272781611d5d565b82525050565b5f6040820190506127405f83018561271e565b61274d602083018461271e565b9392505050565b6004811061276557612764611f1b565b5b50565b5f81905061277582612754565b919050565b5f61278482612768565b9050919050565b5f8160f81b9050919050565b5f6127a18261278b565b9050919050565b6127b96127b48261277a565b612797565b82525050565b5f6127c982612797565b9050919050565b6127e16127dc8261203a565b6127bf565b82525050565b5f6127f2828b6125e5565b601482019150612802828a6125e5565b6014820191506128128289612605565b60148201915061282282886125e5565b6014820191506128328287612625565b60208201915061284282866127a8565b60018201915061285282856127d0565b6001820191506128628284612625565b6020820191508190509998505050505050505050565b5f60208201905061288b5f83018461271e565b92915050565b5f6060820190506128a45f83018661269a565b6128b1602083018561269a565b6128be60408301846126a9565b949350505050565b5f82825260208201905092915050565b7f5061796d656e7420776173206e6f742073656e740000000000000000000000005f82015250565b5f61290a6014836128c6565b9150612915826128d6565b602082019050919050565b5f6020820190508181035f830152612937816128fe565b9050919050565b7f496e76616c6964207061796d656e7420686173680000000000000000000000005f82015250565b5f6129726014836128c6565b915061297d8261293e565b602082019050919050565b5f6020820190508181035f83015261299f81612966565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6129dd82611d90565b91506129e883611d90565b9250828203905081811115612a00576129ff6129a6565b5b92915050565b7f546f6b656e207472616e73666572206661696c656400000000000000000000005f82015250565b5f612a3a6015836128c6565b9150612a4582612a06565b602082019050919050565b5f6020820190508181035f830152612a6781612a2e565b905091905056fea26469706673582212203106867e1b147b377237cde0aba42d82faf0282b83d7b6d62cca039d0b7f840564736f6c63430008160033"; +/// ERC721_TEST_TOKEN has additional mint function +pub const ERC721_TEST_TOKEN_BYTES: &str = "608060405234801562000010575f80fd5b50604051620022ac380380620022ac8339818101604052810190620000369190620001ea565b8181815f9081620000489190620004a4565b5080600190816200005a9190620004a4565b505050505062000588565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b620000c6826200007e565b810181811067ffffffffffffffff82111715620000e857620000e76200008e565b5b80604052505050565b5f620000fc62000065565b90506200010a8282620000bb565b919050565b5f67ffffffffffffffff8211156200012c576200012b6200008e565b5b62000137826200007e565b9050602081019050919050565b5f5b838110156200016357808201518184015260208101905062000146565b5f8484015250505050565b5f620001846200017e846200010f565b620000f1565b905082815260208101848484011115620001a357620001a26200007a565b5b620001b084828562000144565b509392505050565b5f82601f830112620001cf57620001ce62000076565b5b8151620001e18482602086016200016e565b91505092915050565b5f80604083850312156200020357620002026200006e565b5b5f83015167ffffffffffffffff81111562000223576200022262000072565b5b6200023185828601620001b8565b925050602083015167ffffffffffffffff81111562000255576200025462000072565b5b6200026385828601620001b8565b9150509250929050565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680620002bc57607f821691505b602082108103620002d257620002d162000277565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620003367fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620002f9565b620003428683620002f9565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f6200038c6200038662000380846200035a565b62000363565b6200035a565b9050919050565b5f819050919050565b620003a7836200036c565b620003bf620003b68262000393565b84845462000305565b825550505050565b5f90565b620003d5620003c7565b620003e28184846200039c565b505050565b5b818110156200040957620003fd5f82620003cb565b600181019050620003e8565b5050565b601f82111562000458576200042281620002d8565b6200042d84620002ea565b810160208510156200043d578190505b620004556200044c85620002ea565b830182620003e7565b50505b505050565b5f82821c905092915050565b5f6200047a5f19846008026200045d565b1980831691505092915050565b5f62000494838362000469565b9150826002028217905092915050565b620004af826200026d565b67ffffffffffffffff811115620004cb57620004ca6200008e565b5b620004d78254620002a4565b620004e48282856200040d565b5f60209050601f8311600181146200051a575f841562000505578287015190505b62000511858262000487565b86555062000580565b601f1984166200052a86620002d8565b5f5b8281101562000553578489015182556001820191506020850194506020810190506200052c565b868310156200057357848901516200056f601f89168262000469565b8355505b6001600288020188555050505b505050505050565b611d1680620005965f395ff3fe608060405234801561000f575f80fd5b50600436106100e8575f3560e01c80636352211e1161008a578063a22cb46511610064578063a22cb46514610258578063b88d4fde14610274578063c87b56dd14610290578063e985e9c5146102c0576100e8565b80636352211e146101da57806370a082311461020a57806395d89b411461023a576100e8565b8063095ea7b3116100c6578063095ea7b31461016a57806323b872dd1461018657806340c10f19146101a257806342842e0e146101be576100e8565b806301ffc9a7146100ec57806306fdde031461011c578063081812fc1461013a575b5f80fd5b610106600480360381019061010191906115a7565b6102f0565b60405161011391906115ec565b60405180910390f35b6101246103d1565b604051610131919061168f565b60405180910390f35b610154600480360381019061014f91906116e2565b610460565b604051610161919061174c565b60405180910390f35b610184600480360381019061017f919061178f565b61047b565b005b6101a0600480360381019061019b91906117cd565b610491565b005b6101bc60048036038101906101b7919061178f565b610590565b005b6101d860048036038101906101d391906117cd565b61059e565b005b6101f460048036038101906101ef91906116e2565b6105bd565b604051610201919061174c565b60405180910390f35b610224600480360381019061021f919061181d565b6105ce565b6040516102319190611857565b60405180910390f35b610242610684565b60405161024f919061168f565b60405180910390f35b610272600480360381019061026d919061189a565b610714565b005b61028e60048036038101906102899190611a04565b61072a565b005b6102aa60048036038101906102a591906116e2565b610747565b6040516102b7919061168f565b60405180910390f35b6102da60048036038101906102d59190611a84565b6107ad565b6040516102e791906115ec565b60405180910390f35b5f7f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806103ba57507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806103ca57506103c98261083b565b5b9050919050565b60605f80546103df90611aef565b80601f016020809104026020016040519081016040528092919081815260200182805461040b90611aef565b80156104565780601f1061042d57610100808354040283529160200191610456565b820191905f5260205f20905b81548152906001019060200180831161043957829003601f168201915b5050505050905090565b5f61046a826108a4565b506104748261092a565b9050919050565b61048d8282610488610963565b61096a565b5050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610501575f6040517f64a0ae920000000000000000000000000000000000000000000000000000000081526004016104f8919061174c565b60405180910390fd5b5f610514838361050f610963565b61097c565b90508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461058a578382826040517f64283d7b00000000000000000000000000000000000000000000000000000000815260040161058193929190611b1f565b60405180910390fd5b50505050565b61059a8282610b87565b5050565b6105b883838360405180602001604052805f81525061072a565b505050565b5f6105c7826108a4565b9050919050565b5f8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361063f575f6040517f89c62b64000000000000000000000000000000000000000000000000000000008152600401610636919061174c565b60405180910390fd5b60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b60606001805461069390611aef565b80601f01602080910402602001604051908101604052809291908181526020018280546106bf90611aef565b801561070a5780601f106106e15761010080835404028352916020019161070a565b820191905f5260205f20905b8154815290600101906020018083116106ed57829003601f168201915b5050505050905090565b61072661071f610963565b8383610c7a565b5050565b610735848484610491565b61074184848484610de3565b50505050565b6060610752826108a4565b505f61075c610f95565b90505f81511161077a5760405180602001604052805f8152506107a5565b8061078484610fab565b604051602001610795929190611b8e565b6040516020818303038152906040525b915050919050565b5f60055f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16905092915050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f806108af83611075565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361092157826040517f7e2732890000000000000000000000000000000000000000000000000000000081526004016109189190611857565b60405180910390fd5b80915050919050565b5f60045f8381526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b5f33905090565b61097783838360016110ae565b505050565b5f8061098784611075565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146109c8576109c781848661126d565b5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610a5357610a075f855f806110ae565b600160035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825403925050819055505b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614610ad257600160035f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055505b8460025f8681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550838573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4809150509392505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610bf7575f6040517f64a0ae92000000000000000000000000000000000000000000000000000000008152600401610bee919061174c565b60405180910390fd5b5f610c0383835f61097c565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610c75575f6040517f73c6ac6e000000000000000000000000000000000000000000000000000000008152600401610c6c919061174c565b60405180910390fd5b505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610cea57816040517f5b08ba18000000000000000000000000000000000000000000000000000000008152600401610ce1919061174c565b60405180910390fd5b8060055f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051610dd691906115ec565b60405180910390a3505050565b5f8373ffffffffffffffffffffffffffffffffffffffff163b1115610f8f578273ffffffffffffffffffffffffffffffffffffffff1663150b7a02610e26610963565b8685856040518563ffffffff1660e01b8152600401610e489493929190611c03565b6020604051808303815f875af1925050508015610e8357506040513d601f19601f82011682018060405250810190610e809190611c61565b60015b610f04573d805f8114610eb1576040519150601f19603f3d011682016040523d82523d5f602084013e610eb6565b606091505b505f815103610efc57836040517f64a0ae92000000000000000000000000000000000000000000000000000000008152600401610ef3919061174c565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614610f8d57836040517f64a0ae92000000000000000000000000000000000000000000000000000000008152600401610f84919061174c565b60405180910390fd5b505b50505050565b606060405180602001604052805f815250905090565b60605f6001610fb984611330565b0190505f8167ffffffffffffffff811115610fd757610fd66118e0565b5b6040519080825280601f01601f1916602001820160405280156110095781602001600182028036833780820191505090505b5090505f82602001820190505b60011561106a578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a858161105f5761105e611c8c565b5b0494505f8503611016575b819350505050919050565b5f60025f8381526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b80806110e657505f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b15611218575f6110f5846108a4565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415801561115f57508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b8015611172575061117081846107ad565b155b156111b457826040517fa9fbf51f0000000000000000000000000000000000000000000000000000000081526004016111ab919061174c565b60405180910390fd5b811561121657838573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b8360045f8581526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505050565b611278838383611481565b61132b575f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036112ec57806040517f7e2732890000000000000000000000000000000000000000000000000000000081526004016112e39190611857565b60405180910390fd5b81816040517f177e802f000000000000000000000000000000000000000000000000000000008152600401611322929190611cb9565b60405180910390fd5b505050565b5f805f90507a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000831061138c577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000838161138257611381611c8c565b5b0492506040810190505b6d04ee2d6d415b85acef810000000083106113c9576d04ee2d6d415b85acef810000000083816113bf576113be611c8c565b5b0492506020810190505b662386f26fc1000083106113f857662386f26fc1000083816113ee576113ed611c8c565b5b0492506010810190505b6305f5e1008310611421576305f5e100838161141757611416611c8c565b5b0492506008810190505b612710831061144657612710838161143c5761143b611c8c565b5b0492506004810190505b60648310611469576064838161145f5761145e611c8c565b5b0492506002810190505b600a8310611478576001810190505b80915050919050565b5f8073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415801561153857508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614806114f957506114f884846107ad565b5b8061153757508273ffffffffffffffffffffffffffffffffffffffff1661151f8361092a565b73ffffffffffffffffffffffffffffffffffffffff16145b5b90509392505050565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61158681611552565b8114611590575f80fd5b50565b5f813590506115a18161157d565b92915050565b5f602082840312156115bc576115bb61154a565b5b5f6115c984828501611593565b91505092915050565b5f8115159050919050565b6115e6816115d2565b82525050565b5f6020820190506115ff5f8301846115dd565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561163c578082015181840152602081019050611621565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61166182611605565b61166b818561160f565b935061167b81856020860161161f565b61168481611647565b840191505092915050565b5f6020820190508181035f8301526116a78184611657565b905092915050565b5f819050919050565b6116c1816116af565b81146116cb575f80fd5b50565b5f813590506116dc816116b8565b92915050565b5f602082840312156116f7576116f661154a565b5b5f611704848285016116ce565b91505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6117368261170d565b9050919050565b6117468161172c565b82525050565b5f60208201905061175f5f83018461173d565b92915050565b61176e8161172c565b8114611778575f80fd5b50565b5f8135905061178981611765565b92915050565b5f80604083850312156117a5576117a461154a565b5b5f6117b28582860161177b565b92505060206117c3858286016116ce565b9150509250929050565b5f805f606084860312156117e4576117e361154a565b5b5f6117f18682870161177b565b93505060206118028682870161177b565b9250506040611813868287016116ce565b9150509250925092565b5f602082840312156118325761183161154a565b5b5f61183f8482850161177b565b91505092915050565b611851816116af565b82525050565b5f60208201905061186a5f830184611848565b92915050565b611879816115d2565b8114611883575f80fd5b50565b5f8135905061189481611870565b92915050565b5f80604083850312156118b0576118af61154a565b5b5f6118bd8582860161177b565b92505060206118ce85828601611886565b9150509250929050565b5f80fd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61191682611647565b810181811067ffffffffffffffff82111715611935576119346118e0565b5b80604052505050565b5f611947611541565b9050611953828261190d565b919050565b5f67ffffffffffffffff821115611972576119716118e0565b5b61197b82611647565b9050602081019050919050565b828183375f83830152505050565b5f6119a86119a384611958565b61193e565b9050828152602081018484840111156119c4576119c36118dc565b5b6119cf848285611988565b509392505050565b5f82601f8301126119eb576119ea6118d8565b5b81356119fb848260208601611996565b91505092915050565b5f805f8060808587031215611a1c57611a1b61154a565b5b5f611a298782880161177b565b9450506020611a3a8782880161177b565b9350506040611a4b878288016116ce565b925050606085013567ffffffffffffffff811115611a6c57611a6b61154e565b5b611a78878288016119d7565b91505092959194509250565b5f8060408385031215611a9a57611a9961154a565b5b5f611aa78582860161177b565b9250506020611ab88582860161177b565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680611b0657607f821691505b602082108103611b1957611b18611ac2565b5b50919050565b5f606082019050611b325f83018661173d565b611b3f6020830185611848565b611b4c604083018461173d565b949350505050565b5f81905092915050565b5f611b6882611605565b611b728185611b54565b9350611b8281856020860161161f565b80840191505092915050565b5f611b998285611b5e565b9150611ba58284611b5e565b91508190509392505050565b5f81519050919050565b5f82825260208201905092915050565b5f611bd582611bb1565b611bdf8185611bbb565b9350611bef81856020860161161f565b611bf881611647565b840191505092915050565b5f608082019050611c165f83018761173d565b611c23602083018661173d565b611c306040830185611848565b8181036060830152611c428184611bcb565b905095945050505050565b5f81519050611c5b8161157d565b92915050565b5f60208284031215611c7657611c7561154a565b5b5f611c8384828501611c4d565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f604082019050611ccc5f83018561173d565b611cd96020830184611848565b939250505056fea26469706673582212207439b47c2a9a1624955997732075917bbf1da26949d000c778f561eb5687576164736f6c63430008180033"; +/// ERC1155_TEST_TOKEN has additional mint function +pub const ERC1155_TEST_TOKEN_BYTES: &str = "608060405234801562000010575f80fd5b50604051620024eb380380620024eb8339818101604052810190620000369190620001ea565b8062000048816200005060201b60201c565b505062000554565b806002908162000061919062000470565b5050565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b620000c6826200007e565b810181811067ffffffffffffffff82111715620000e857620000e76200008e565b5b80604052505050565b5f620000fc62000065565b90506200010a8282620000bb565b919050565b5f67ffffffffffffffff8211156200012c576200012b6200008e565b5b62000137826200007e565b9050602081019050919050565b5f5b838110156200016357808201518184015260208101905062000146565b5f8484015250505050565b5f620001846200017e846200010f565b620000f1565b905082815260208101848484011115620001a357620001a26200007a565b5b620001b084828562000144565b509392505050565b5f82601f830112620001cf57620001ce62000076565b5b8151620001e18482602086016200016e565b91505092915050565b5f602082840312156200020257620002016200006e565b5b5f82015167ffffffffffffffff81111562000222576200022162000072565b5b6200023084828501620001b8565b91505092915050565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806200028857607f821691505b6020821081036200029e576200029d62000243565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620003027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620002c5565b6200030e8683620002c5565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f62000358620003526200034c8462000326565b6200032f565b62000326565b9050919050565b5f819050919050565b620003738362000338565b6200038b62000382826200035f565b848454620002d1565b825550505050565b5f90565b620003a162000393565b620003ae81848462000368565b505050565b5b81811015620003d557620003c95f8262000397565b600181019050620003b4565b5050565b601f8211156200042457620003ee81620002a4565b620003f984620002b6565b8101602085101562000409578190505b620004216200041885620002b6565b830182620003b3565b50505b505050565b5f82821c905092915050565b5f620004465f198460080262000429565b1980831691505092915050565b5f62000460838362000435565b9150826002028217905092915050565b6200047b8262000239565b67ffffffffffffffff8111156200049757620004966200008e565b5b620004a3825462000270565b620004b0828285620003d9565b5f60209050601f831160018114620004e6575f8415620004d1578287015190505b620004dd858262000453565b8655506200054c565b601f198416620004f686620002a4565b5f5b828110156200051f57848901518255600182019150602085019450602081019050620004f8565b868310156200053f57848901516200053b601f89168262000435565b8355505b6001600288020188555050505b505050505050565b611f8980620005625f395ff3fe608060405234801561000f575f80fd5b5060043610610090575f3560e01c80634e1273f4116100645780634e1273f414610140578063731133e914610170578063a22cb4651461018c578063e985e9c5146101a8578063f242432a146101d857610090565b8062fdd58e1461009457806301ffc9a7146100c45780630e89341c146100f45780632eb2c2d614610124575b5f80fd5b6100ae60048036038101906100a991906113bd565b6101f4565b6040516100bb919061140a565b60405180910390f35b6100de60048036038101906100d99190611478565b610249565b6040516100eb91906114bd565b60405180910390f35b61010e600480360381019061010991906114d6565b61032a565b60405161011b919061158b565b60405180910390f35b61013e6004803603810190610139919061179b565b6103bc565b005b61015a60048036038101906101559190611926565b610463565b6040516101679190611a53565b60405180910390f35b61018a60048036038101906101859190611a73565b61056a565b005b6101a660048036038101906101a19190611b1d565b61057c565b005b6101c260048036038101906101bd9190611b5b565b610592565b6040516101cf91906114bd565b60405180910390f35b6101f260048036038101906101ed9190611b99565b610620565b005b5f805f8381526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905092915050565b5f7fd9b67a26000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061031357507f0e89341c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806103235750610322826106c7565b5b9050919050565b60606002805461033990611c59565b80601f016020809104026020016040519081016040528092919081815260200182805461036590611c59565b80156103b05780601f10610387576101008083540402835291602001916103b0565b820191905f5260205f20905b81548152906001019060200180831161039357829003601f168201915b50505050509050919050565b5f6103c5610730565b90508073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161415801561040a57506104088682610592565b155b1561044e5780866040517fe237d922000000000000000000000000000000000000000000000000000000008152600401610445929190611c98565b60405180910390fd5b61045b8686868686610737565b505050505050565b606081518351146104af57815183516040517f5b0599910000000000000000000000000000000000000000000000000000000081526004016104a6929190611cbf565b60405180910390fd5b5f835167ffffffffffffffff8111156104cb576104ca6115af565b5b6040519080825280602002602001820160405280156104f95781602001602082028036833780820191505090505b5090505f5b845181101561055f5761053561051d828761082b90919063ffffffff16565b610530838761083e90919063ffffffff16565b6101f4565b82828151811061054857610547611ce6565b5b6020026020010181815250508060010190506104fe565b508091505092915050565b61057684848484610851565b50505050565b61058e610587610730565b83836108e6565b5050565b5f60015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16905092915050565b5f610629610730565b90508073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161415801561066e575061066c8682610592565b155b156106b25780866040517fe237d9220000000000000000000000000000000000000000000000000000000081526004016106a9929190611c98565b60405180910390fd5b6106bf8686868686610a4f565b505050505050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f33905090565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036107a7575f6040517f57f447ce00000000000000000000000000000000000000000000000000000000815260040161079e9190611d13565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603610817575f6040517f01a8351400000000000000000000000000000000000000000000000000000000815260040161080e9190611d13565b60405180910390fd5b6108248585858585610b55565b5050505050565b5f60208202602084010151905092915050565b5f60208202602084010151905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036108c1575f6040517f57f447ce0000000000000000000000000000000000000000000000000000000081526004016108b89190611d13565b60405180910390fd5b5f806108cd8585610c01565b915091506108de5f87848487610b55565b505050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610956575f6040517fced3e10000000000000000000000000000000000000000000000000000000000815260040161094d9190611d13565b60405180910390fd5b8060015f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051610a4291906114bd565b60405180910390a3505050565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610abf575f6040517f57f447ce000000000000000000000000000000000000000000000000000000008152600401610ab69190611d13565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603610b2f575f6040517f01a83514000000000000000000000000000000000000000000000000000000008152600401610b269190611d13565b60405180910390fd5b5f80610b3b8585610c01565b91509150610b4c8787848487610b55565b50505050505050565b610b6185858585610c31565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614610bfa575f610b9d610730565b90506001845103610be9575f610bbc5f8661083e90919063ffffffff16565b90505f610bd25f8661083e90919063ffffffff16565b9050610be2838989858589610fc1565b5050610bf8565b610bf7818787878787611170565b5b505b5050505050565b60608060405191506001825283602083015260408201905060018152826020820152604081016040529250929050565b8051825114610c7b57815181516040517f5b059991000000000000000000000000000000000000000000000000000000008152600401610c72929190611cbf565b60405180910390fd5b5f610c84610730565b90505f5b8351811015610e80575f610ca5828661083e90919063ffffffff16565b90505f610cbb838661083e90919063ffffffff16565b90505f73ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614610dde575f805f8481526020019081526020015f205f8a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905081811015610d8a57888183856040517f03dee4c5000000000000000000000000000000000000000000000000000000008152600401610d819493929190611d2c565b60405180910390fd5b8181035f808581526020019081526020015f205f8b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550505b5f73ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614610e7357805f808481526020019081526020015f205f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610e6b9190611d9c565b925050819055505b5050806001019050610c88565b506001835103610f3b575f610e9e5f8561083e90919063ffffffff16565b90505f610eb45f8561083e90919063ffffffff16565b90508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628585604051610f2c929190611cbf565b60405180910390a45050610fba565b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8686604051610fb1929190611dcf565b60405180910390a45b5050505050565b5f8473ffffffffffffffffffffffffffffffffffffffff163b1115611168578373ffffffffffffffffffffffffffffffffffffffff1663f23a6e6187878686866040518663ffffffff1660e01b8152600401611021959493929190611e56565b6020604051808303815f875af192505050801561105c57506040513d601f19601f820116820180604052508101906110599190611ec2565b60015b6110dd573d805f811461108a576040519150601f19603f3d011682016040523d82523d5f602084013e61108f565b606091505b505f8151036110d557846040517f57f447ce0000000000000000000000000000000000000000000000000000000081526004016110cc9190611d13565b60405180910390fd5b805181602001fd5b63f23a6e6160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461116657846040517f57f447ce00000000000000000000000000000000000000000000000000000000815260040161115d9190611d13565b60405180910390fd5b505b505050505050565b5f8473ffffffffffffffffffffffffffffffffffffffff163b1115611317578373ffffffffffffffffffffffffffffffffffffffff1663bc197c8187878686866040518663ffffffff1660e01b81526004016111d0959493929190611eed565b6020604051808303815f875af192505050801561120b57506040513d601f19601f820116820180604052508101906112089190611ec2565b60015b61128c573d805f8114611239576040519150601f19603f3d011682016040523d82523d5f602084013e61123e565b606091505b505f81510361128457846040517f57f447ce00000000000000000000000000000000000000000000000000000000815260040161127b9190611d13565b60405180910390fd5b805181602001fd5b63bc197c8160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461131557846040517f57f447ce00000000000000000000000000000000000000000000000000000000815260040161130c9190611d13565b60405180910390fd5b505b505050505050565b5f604051905090565b5f80fd5b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61135982611330565b9050919050565b6113698161134f565b8114611373575f80fd5b50565b5f8135905061138481611360565b92915050565b5f819050919050565b61139c8161138a565b81146113a6575f80fd5b50565b5f813590506113b781611393565b92915050565b5f80604083850312156113d3576113d2611328565b5b5f6113e085828601611376565b92505060206113f1858286016113a9565b9150509250929050565b6114048161138a565b82525050565b5f60208201905061141d5f8301846113fb565b92915050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61145781611423565b8114611461575f80fd5b50565b5f813590506114728161144e565b92915050565b5f6020828403121561148d5761148c611328565b5b5f61149a84828501611464565b91505092915050565b5f8115159050919050565b6114b7816114a3565b82525050565b5f6020820190506114d05f8301846114ae565b92915050565b5f602082840312156114eb576114ea611328565b5b5f6114f8848285016113a9565b91505092915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561153857808201518184015260208101905061151d565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61155d82611501565b611567818561150b565b935061157781856020860161151b565b61158081611543565b840191505092915050565b5f6020820190508181035f8301526115a38184611553565b905092915050565b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6115e582611543565b810181811067ffffffffffffffff82111715611604576116036115af565b5b80604052505050565b5f61161661131f565b905061162282826115dc565b919050565b5f67ffffffffffffffff821115611641576116406115af565b5b602082029050602081019050919050565b5f80fd5b5f61166861166384611627565b61160d565b9050808382526020820190506020840283018581111561168b5761168a611652565b5b835b818110156116b457806116a088826113a9565b84526020840193505060208101905061168d565b5050509392505050565b5f82601f8301126116d2576116d16115ab565b5b81356116e2848260208601611656565b91505092915050565b5f80fd5b5f67ffffffffffffffff821115611709576117086115af565b5b61171282611543565b9050602081019050919050565b828183375f83830152505050565b5f61173f61173a846116ef565b61160d565b90508281526020810184848401111561175b5761175a6116eb565b5b61176684828561171f565b509392505050565b5f82601f830112611782576117816115ab565b5b813561179284826020860161172d565b91505092915050565b5f805f805f60a086880312156117b4576117b3611328565b5b5f6117c188828901611376565b95505060206117d288828901611376565b945050604086013567ffffffffffffffff8111156117f3576117f261132c565b5b6117ff888289016116be565b935050606086013567ffffffffffffffff8111156118205761181f61132c565b5b61182c888289016116be565b925050608086013567ffffffffffffffff81111561184d5761184c61132c565b5b6118598882890161176e565b9150509295509295909350565b5f67ffffffffffffffff8211156118805761187f6115af565b5b602082029050602081019050919050565b5f6118a361189e84611866565b61160d565b905080838252602082019050602084028301858111156118c6576118c5611652565b5b835b818110156118ef57806118db8882611376565b8452602084019350506020810190506118c8565b5050509392505050565b5f82601f83011261190d5761190c6115ab565b5b813561191d848260208601611891565b91505092915050565b5f806040838503121561193c5761193b611328565b5b5f83013567ffffffffffffffff8111156119595761195861132c565b5b611965858286016118f9565b925050602083013567ffffffffffffffff8111156119865761198561132c565b5b611992858286016116be565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b6119ce8161138a565b82525050565b5f6119df83836119c5565b60208301905092915050565b5f602082019050919050565b5f611a018261199c565b611a0b81856119a6565b9350611a16836119b6565b805f5b83811015611a46578151611a2d88826119d4565b9750611a38836119eb565b925050600181019050611a19565b5085935050505092915050565b5f6020820190508181035f830152611a6b81846119f7565b905092915050565b5f805f8060808587031215611a8b57611a8a611328565b5b5f611a9887828801611376565b9450506020611aa9878288016113a9565b9350506040611aba878288016113a9565b925050606085013567ffffffffffffffff811115611adb57611ada61132c565b5b611ae78782880161176e565b91505092959194509250565b611afc816114a3565b8114611b06575f80fd5b50565b5f81359050611b1781611af3565b92915050565b5f8060408385031215611b3357611b32611328565b5b5f611b4085828601611376565b9250506020611b5185828601611b09565b9150509250929050565b5f8060408385031215611b7157611b70611328565b5b5f611b7e85828601611376565b9250506020611b8f85828601611376565b9150509250929050565b5f805f805f60a08688031215611bb257611bb1611328565b5b5f611bbf88828901611376565b9550506020611bd088828901611376565b9450506040611be1888289016113a9565b9350506060611bf2888289016113a9565b925050608086013567ffffffffffffffff811115611c1357611c1261132c565b5b611c1f8882890161176e565b9150509295509295909350565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680611c7057607f821691505b602082108103611c8357611c82611c2c565b5b50919050565b611c928161134f565b82525050565b5f604082019050611cab5f830185611c89565b611cb86020830184611c89565b9392505050565b5f604082019050611cd25f8301856113fb565b611cdf60208301846113fb565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f602082019050611d265f830184611c89565b92915050565b5f608082019050611d3f5f830187611c89565b611d4c60208301866113fb565b611d5960408301856113fb565b611d6660608301846113fb565b95945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f611da68261138a565b9150611db18361138a565b9250828201905080821115611dc957611dc8611d6f565b5b92915050565b5f6040820190508181035f830152611de781856119f7565b90508181036020830152611dfb81846119f7565b90509392505050565b5f81519050919050565b5f82825260208201905092915050565b5f611e2882611e04565b611e328185611e0e565b9350611e4281856020860161151b565b611e4b81611543565b840191505092915050565b5f60a082019050611e695f830188611c89565b611e766020830187611c89565b611e8360408301866113fb565b611e9060608301856113fb565b8181036080830152611ea28184611e1e565b90509695505050505050565b5f81519050611ebc8161144e565b92915050565b5f60208284031215611ed757611ed6611328565b5b5f611ee484828501611eae565b91505092915050565b5f60a082019050611f005f830188611c89565b611f0d6020830187611c89565b8181036040830152611f1f81866119f7565b90508181036060830152611f3381856119f7565b90508181036080830152611f478184611e1e565b9050969550505050505056fea2646970667358221220aa7808c7a42c44ef257fdbc9ac99eb0d5840587290be50439b94642674548a7e64736f6c63430008180033"; +pub const NFT_SWAP_CONTRACT_BYTES: &str = "60a060405234801562000010575f80fd5b506040516200553a3803806200553a833981810160405281019062000036919062000147565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603620000a7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200009e90620001fb565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff1681525050506200021b565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6200011182620000e6565b9050919050565b620001238162000105565b81146200012e575f80fd5b50565b5f81519050620001418162000118565b92915050565b5f602082840312156200015f576200015e620000e2565b5b5f6200016e8482850162000131565b91505092915050565b5f82825260208201905092915050565b7f66656541646472657373206d757374206e6f74206265207a65726f20616464725f8201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b5f620001e360238362000177565b9150620001f08262000187565b604082019050919050565b5f6020820190508181035f8301526200021481620001d5565b9050919050565b6080516152f8620002425f395f8181612759015281816127f40152612bb201526152f85ff3fe608060405260043610610113575f3560e01c80639b4603f21161009f578063d6a71eb411610063578063d6a71eb41461038e578063e06cf966146103b6578063efccb9eb146103e0578063f23a6e611461041e578063fc45ef821461045a57610113565b80639b4603f2146102be578063ba157104146102da578063bc197c8114610302578063c8d9009b1461033e578063cc90c1991461036657610113565b806332c7d4f8116100e657806332c7d4f8146101df5780633e6af5f21461020757806346b95ac71461022f57806365e266171461026e5780636e6bf6d21461029657610113565b806301ffc9a7146101175780630f235fce14610153578063146e5b241461017b578063150b7a02146101a3575b5f80fd5b348015610122575f80fd5b5061013d60048036038101906101389190613807565b610482565b60405161014a919061384c565b60405180910390f35b34801561015e575f80fd5b5061017960048036038101906101749190613925565b6104fb565b005b348015610186575f80fd5b506101a1600480360381019061019c91906139ae565b6107b5565b005b3480156101ae575f80fd5b506101c960048036038101906101c49190613aac565b61099b565b6040516101d69190613b3f565b60405180910390f35b3480156101ea575f80fd5b5061020560048036038101906102009190613b58565b610dea565b005b348015610212575f80fd5b5061022d600480360381019061022891906139ae565b6110a9565b005b34801561023a575f80fd5b5061025560048036038101906102509190613bf5565b6113ba565b6040516102659493929190613ceb565b60405180910390f35b348015610279575f80fd5b50610294600480360381019061028f91906139ae565b61141c565b005b3480156102a1575f80fd5b506102bc60048036038101906102b79190613925565b611880565b005b6102d860048036038101906102d39190613d58565b611b3b565b005b3480156102e5575f80fd5b5061030060048036038101906102fb9190613b58565b611e71565b005b34801561030d575f80fd5b5061032860048036038101906103239190613e4a565b612131565b6040516103359190613b3f565b60405180910390f35b348015610349575f80fd5b50610364600480360381019061035f9190613925565b61216d565b005b348015610371575f80fd5b5061038c600480360381019061038791906139ae565b612496565b005b348015610399575f80fd5b506103b460048036038101906103af9190613f21565b612846565b005b3480156103c1575f80fd5b506103ca612bb0565b6040516103d79190613ff4565b60405180910390f35b3480156103eb575f80fd5b5061040660048036038101906104019190613bf5565b612bd4565b60405161041593929190614053565b60405180910390f35b348015610429575f80fd5b50610444600480360381019061043f9190614088565b612c20565b6040516104519190613b3f565b60405180910390f35b348015610465575f80fd5b50610480600480360381019061047b9190613b58565b6130b4565b005b5f7f4e2312e0000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806104f457506104f3826133e2565b5b9050919050565b6001600381111561050f5761050e613c78565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff16600381111561054157610540613c78565b5b14610581576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105789061419e565b60405180910390fd5b5f600386338787878760405160200161059f96959493929190614241565b6040516020818303038152906040526040516105bb919061431c565b602060405180830381855afa1580156105d6573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610660576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106579061437c565b60405180910390fd5b5f808881526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff164210156106cb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c29061440a565b60405180910390fd5b60035f808981526020019081526020015f205f0160186101000a81548160ff0219169083600381111561070157610700613c78565b5b02179055507f5dedc4f52b757d9112d09ca0b2f022927104d54e3f54da091587e8ad19219072876040516107359190614437565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b815260040161077e9392919061445f565b5f604051808303815f87803b158015610795575f80fd5b505af11580156107a7573d5f803e3d5ffd5b505050505050505050505050565b600160048111156107c9576107c8613c78565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff1660048111156107fc576107fb613c78565b5b1461083c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108339061419e565b60405180910390fd5b5f60038787873388888860405160200161085c9796959493929190614494565b604051602081830303815290604052604051610878919061431c565b602060405180830381855afa158015610893573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461091e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109159061437c565b60405180910390fd5b600260015f8a81526020019081526020015f205f01601c6101000a81548160ff0219169083600481111561095557610954613c78565b5b02179055507f9c45e43e2ef051f70491ffd5221bf02ab37e1324128714ef9610df5f24fc9fb5886040516109899190614437565b60405180910390a15050505050505050565b5f8083838101906109ac919061463d565b90505f73ffffffffffffffffffffffffffffffffffffffff16816020015173ffffffffffffffffffffffffffffffffffffffff1603610a20576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a17906146b2565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816040015173ffffffffffffffffffffffffffffffffffffffff1603610a92576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a899061471a565b60405180910390fd5b806040015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610b04576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610afb906147a8565b60405180910390fd5b8573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614610b72576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b6990614810565b60405180910390fd5b5f6003811115610b8557610b84613c78565b5b5f80835f015181526020019081526020015f205f0160189054906101000a900460ff166003811115610bba57610bb9613c78565b5b14610bfa576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bf19061489e565b60405180910390fd5b610c07816020015161344b565b15610c47576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c3e90614906565b60405180910390fd5b5f60038260200151888460600151856080015186604001518b604051602001610c7596959493929190614241565b604051602081830303815290604052604051610c91919061431c565b602060405180830381855afa158015610cac573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018360a0015163ffffffff16815260200160016003811115610cfc57610cfb613c78565b5b8152505f80845f015181526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548160ff02191690836003811115610d9357610d92613c78565b5b02179055509050507ff1dc11bbb6d7542c4267ecf1d370ff4c7092518633ecae9939e8488f4e53d2ad825f0151604051610dcd9190614437565b60405180910390a163150b7a0260e01b9250505095945050505050565b60016003811115610dfe57610dfd613c78565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff166003811115610e3057610e2f613c78565b5b14610e70576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e679061419e565b60405180910390fd5b5f60038633878787878d604051602001610e909796959493929190614924565b604051602081830303815290604052604051610eac919061431c565b602060405180830381855afa158015610ec7573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610f51576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f489061437c565b60405180910390fd5b5f808981526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff16421015610fbc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fb39061440a565b60405180910390fd5b60035f808a81526020019081526020015f205f0160186101000a81548160ff02191690836003811115610ff257610ff1613c78565b5b02179055507f5dedc4f52b757d9112d09ca0b2f022927104d54e3f54da091587e8ad19219072886040516110269190614437565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff1663f242432a3033868c6040518563ffffffff1660e01b815260040161107194939291906149d7565b5f604051808303815f87803b158015611088575f80fd5b505af115801561109a573d5f803e3d5ffd5b50505050505050505050505050565b600160048111156110bd576110bc613c78565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff1660048111156110f0576110ef613c78565b5b14611130576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111279061419e565b60405180910390fd5b5f60038787873360028960405160200161114a9190614a2d565b604051602081830303815290604052604051611166919061431c565b602060405180830381855afa158015611181573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906111a49190614a5b565b88886040516020016111bc9796959493929190614494565b6040516020818303038152906040526040516111d8919061431c565b602060405180830381855afa1580156111f3573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461127e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112759061437c565b60405180910390fd5b600460015f8a81526020019081526020015f205f01601c6101000a81548160ff021916908360048111156112b5576112b4613c78565b5b02179055507f45169a52eef651b20a81474b50b8a5d83225225fcd097ef3cf7952d9ab304f2788856040516112eb929190614a86565b60405180910390a15f86886113009190614ada565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361137e573373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f19350505050158015611378573d5f803e3d5ffd5b506113af565b5f8390506113ad33838373ffffffffffffffffffffffffffffffffffffffff1661345c9092919063ffffffff16565b505b505050505050505050565b6001602052805f5260405f205f91509050805f015f9054906101000a900460601b90805f0160149054906101000a900463ffffffff1690805f0160189054906101000a900463ffffffff1690805f01601c9054906101000a900460ff16905084565b600160048111156114305761142f613c78565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff16600481111561146357611462613c78565b5b14806114b357506002600481111561147e5761147d613c78565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff1660048111156114b1576114b0613c78565b5b145b6114f2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114e990614b7d565b60405180910390fd5b5f6003878787338888886040516020016115129796959493929190614494565b60405160208183030381529060405260405161152e919061431c565b602060405180830381855afa158015611549573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146115d4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115cb9061437c565b60405180910390fd5b600260048111156115e8576115e7613c78565b5b60015f8a81526020019081526020015f205f01601c9054906101000a900460ff16600481111561161b5761161a613c78565b5b0361168d5760015f8981526020019081526020015f205f0160189054906101000a900463ffffffff1663ffffffff1642101561168c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116839061440a565b60405180910390fd5b5b600160048111156116a1576116a0613c78565b5b60015f8a81526020019081526020015f205f01601c9054906101000a900460ff1660048111156116d4576116d3613c78565b5b036117465760015f8981526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff16421015611745576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161173c90614c0b565b60405180910390fd5b5b600460015f8a81526020019081526020015f205f01601c6101000a81548160ff0219169083600481111561177d5761177c613c78565b5b02179055507fbdd7a4be6d82798a500b59077706b12d3f45acf5504828919f92501307b2b953886040516117b19190614437565b60405180910390a15f86886117c69190614ada565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611844573373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f1935050505015801561183e573d5f803e3d5ffd5b50611875565b5f83905061187333838373ffffffffffffffffffffffffffffffffffffffff1661345c9092919063ffffffff16565b505b505050505050505050565b6001600381111561189457611893613c78565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff1660038111156118c6576118c5613c78565b5b14611906576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118fd9061419e565b60405180910390fd5b5f6003863360028860405160200161191e9190614a2d565b60405160208183030381529060405260405161193a919061431c565b602060405180830381855afa158015611955573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906119789190614a5b565b87878760405160200161199096959493929190614241565b6040516020818303038152906040526040516119ac919061431c565b602060405180830381855afa1580156119c7573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614611a51576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a489061437c565b60405180910390fd5b60035f808981526020019081526020015f205f0160186101000a81548160ff02191690836003811115611a8757611a86613c78565b5b02179055507fac509cdcc7ddb189f81fff6f4824f5c95076e64c3bdce542c50feaa6779afd7387604051611abb9190614437565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b8152600401611b049392919061445f565b5f604051808303815f87803b158015611b1b575f80fd5b505af1158015611b2d573d5f803e3d5ffd5b505050505050505050505050565b5f6004811115611b4e57611b4d613c78565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff166004811115611b8157611b80613c78565b5b14611bc1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bb890614c99565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603611c2f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c2690614d27565b60405180910390fd5b5f3411611c71576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c6890614db5565b60405180910390fd5b853411611cb3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611caa90614e43565b60405180910390fd5b5f60038734611cc29190614e61565b88883389895f604051602001611cde9796959493929190614494565b604051602081830303815290604052604051611cfa919061431c565b602060405180830381855afa158015611d15573d5f803e3d5ffd5b5050506040515160601b90506040518060800160405280826bffffffffffffffffffffffff191681526020018463ffffffff1681526020018363ffffffff16815260200160016004811115611d6d57611d6c613c78565b5b81525060015f8a81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548163ffffffff021916908363ffffffff1602179055506060820151815f01601c6101000a81548160ff02191690836004811115611e2857611e27613c78565b5b02179055509050507ffc6cdccd1d98ded12074a9ebc7f6ab74fed1814ff57f4fb5202464d8938bd93588604051611e5f9190614437565b60405180910390a15050505050505050565b60016003811115611e8557611e84613c78565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff166003811115611eb757611eb6613c78565b5b14611ef7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611eee9061419e565b60405180910390fd5b5f60038633600288604051602001611f0f9190614a2d565b604051602081830303815290604052604051611f2b919061431c565b602060405180830381855afa158015611f46573d5f803e3d5ffd5b5050506040513d601f19601f82011682018060405250810190611f699190614a5b565b8787878d604051602001611f839796959493929190614924565b604051602081830303815290604052604051611f9f919061431c565b602060405180830381855afa158015611fba573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614612044576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161203b9061437c565b60405180910390fd5b60035f808a81526020019081526020015f205f0160186101000a81548160ff0219169083600381111561207a57612079613c78565b5b02179055507fac509cdcc7ddb189f81fff6f4824f5c95076e64c3bdce542c50feaa6779afd73886040516120ae9190614437565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff1663f242432a3033868c6040518563ffffffff1660e01b81526004016120f994939291906149d7565b5f604051808303815f87803b158015612110575f80fd5b505af1158015612122573d5f803e3d5ffd5b50505050505050505050505050565b5f6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161216490614ede565b60405180910390fd5b6001600381111561218157612180613c78565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff1660038111156121b3576121b2613c78565b5b146121f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016121ea9061419e565b60405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612261576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161225890614f46565b60405180910390fd5b5f600333878760028860405160200161227a9190614a2d565b604051602081830303815290604052604051612296919061431c565b602060405180830381855afa1580156122b1573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906122d49190614a5b565b87876040516020016122eb96959493929190614241565b604051602081830303815290604052604051612307919061431c565b602060405180830381855afa158015612322573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146123ac576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016123a39061437c565b60405180910390fd5b60025f808981526020019081526020015f205f0160186101000a81548160ff021916908360038111156123e2576123e1613c78565b5b02179055507fad62ed075fe8969df63026f45152d6e996a0697a736a8de92ee85ae9c9958cf0876040516124169190614437565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b815260040161245f9392919061445f565b5f604051808303815f87803b158015612476575f80fd5b505af1158015612488573d5f803e3d5ffd5b505050505050505050505050565b600260048111156124aa576124a9613c78565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff1660048111156124dd576124dc613c78565b5b1461251d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161251490614fd4565b60405180910390fd5b5f600387873388886002896040516020016125389190614a2d565b604051602081830303815290604052604051612554919061431c565b602060405180830381855afa15801561256f573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906125929190614a5b565b886040516020016125a99796959493929190614494565b6040516020818303038152906040526040516125c5919061431c565b602060405180830381855afa1580156125e0573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461266b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016126629061437c565b60405180910390fd5b600360015f8a81526020019081526020015f205f01601c6101000a81548160ff021916908360048111156126a2576126a1613c78565b5b02179055507f0d0da0df275f85bed3a5fe7ae79f3559341a3f9ccd8e010133438135bda00a8788846040516126d8929190614a86565b60405180910390a15f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036127c0573373ffffffffffffffffffffffffffffffffffffffff166108fc8890811502906040515f60405180830381858888f19350505050158015612756573d5f803e3d5ffd5b507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166108fc8790811502906040515f60405180830381858888f193505050501580156127ba573d5f803e3d5ffd5b5061283c565b5f8290506127ef33898373ffffffffffffffffffffffffffffffffffffffff1661345c9092919063ffffffff16565b61283a7f0000000000000000000000000000000000000000000000000000000000000000888373ffffffffffffffffffffffffffffffffffffffff1661345c9092919063ffffffff16565b505b5050505050505050565b5f600481111561285957612858613c78565b5b60015f8b81526020019081526020015f205f01601c9054906101000a900460ff16600481111561288c5761288b613c78565b5b146128cc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016128c390615062565b60405180910390fd5b5f881161290e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612905906150ca565b60405180910390fd5b5f8711612950576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161294790615132565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16036129be576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129b590614d27565b60405180910390fd5b5f60038989883389898d6040516020016129de9796959493929190614494565b6040516020818303038152906040526040516129fa919061431c565b602060405180830381855afa158015612a15573d5f803e3d5ffd5b5050506040515160601b90506040518060800160405280826bffffffffffffffffffffffff191681526020018463ffffffff1681526020018363ffffffff16815260200160016004811115612a6d57612a6c613c78565b5b81525060015f8c81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548163ffffffff021916908363ffffffff1602179055506060820151815f01601c6101000a81548160ff02191690836004811115612b2857612b27613c78565b5b02179055509050507ffc6cdccd1d98ded12074a9ebc7f6ab74fed1814ff57f4fb5202464d8938bd9358a604051612b5f9190614437565b60405180910390a15f879050612ba333308b8d612b7c9190614ada565b8473ffffffffffffffffffffffffffffffffffffffff166134db909392919063ffffffff16565b5050505050505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b5f602052805f5260405f205f91509050805f015f9054906101000a900460601b90805f0160149054906101000a900463ffffffff1690805f0160189054906101000a900460ff16905083565b5f808383810190612c31919061463d565b90505f73ffffffffffffffffffffffffffffffffffffffff16816020015173ffffffffffffffffffffffffffffffffffffffff1603612ca5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c9c906146b2565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816040015173ffffffffffffffffffffffffffffffffffffffff1603612d17576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612d0e9061471a565b60405180910390fd5b806040015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612d89576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612d80906147a8565b60405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614612df7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612dee90614810565b60405180910390fd5b5f8511612e39576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612e309061519a565b60405180910390fd5b5f6003811115612e4c57612e4b613c78565b5b5f80835f015181526020019081526020015f205f0160189054906101000a900460ff166003811115612e8157612e80613c78565b5b14612ec1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612eb890615228565b60405180910390fd5b612ece816020015161344b565b15612f0e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612f0590614906565b60405180910390fd5b5f60038260200151898460600151856080015186604001518c8c604051602001612f3e9796959493929190614924565b604051602081830303815290604052604051612f5a919061431c565b602060405180830381855afa158015612f75573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018360a0015163ffffffff16815260200160016003811115612fc557612fc4613c78565b5b8152505f80845f015181526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548160ff0219169083600381111561305c5761305b613c78565b5b02179055509050507ff1dc11bbb6d7542c4267ecf1d370ff4c7092518633ecae9939e8488f4e53d2ad825f01516040516130969190614437565b60405180910390a163f23a6e6160e01b925050509695505050505050565b600160038111156130c8576130c7613c78565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff1660038111156130fa576130f9613c78565b5b1461313a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016131319061419e565b60405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146131a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161319f90614f46565b60405180910390fd5b5f60033387876002886040516020016131c19190614a2d565b6040516020818303038152906040526040516131dd919061431c565b602060405180830381855afa1580156131f8573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061321b9190614a5b565b87878d6040516020016132349796959493929190614924565b604051602081830303815290604052604051613250919061431c565b602060405180830381855afa15801561326b573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146132f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016132ec9061437c565b60405180910390fd5b60025f808a81526020019081526020015f205f0160186101000a81548160ff0219169083600381111561332b5761332a613c78565b5b02179055507fad62ed075fe8969df63026f45152d6e996a0697a736a8de92ee85ae9c9958cf08860405161335f9190614437565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff1663f242432a3033868c6040518563ffffffff1660e01b81526004016133aa94939291906149d7565b5f604051808303815f87803b1580156133c1575f80fd5b505af11580156133d3573d5f803e3d5ffd5b50505050505050505050505050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f80823b90505f8111915050919050565b6134d6838473ffffffffffffffffffffffffffffffffffffffff1663a9059cbb858560405160240161348f929190615246565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061355d565b505050565b613557848573ffffffffffffffffffffffffffffffffffffffff166323b872dd8686866040516024016135109392919061445f565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061355d565b50505050565b5f613587828473ffffffffffffffffffffffffffffffffffffffff166135f290919063ffffffff16565b90505f8151141580156135ab5750808060200190518101906135a99190615297565b155b156135ed57826040517f5274afe70000000000000000000000000000000000000000000000000000000081526004016135e49190613ff4565b60405180910390fd5b505050565b60606135ff83835f613607565b905092915050565b60608147101561364e57306040517fcd7860590000000000000000000000000000000000000000000000000000000081526004016136459190613ff4565b60405180910390fd5b5f808573ffffffffffffffffffffffffffffffffffffffff168486604051613676919061431c565b5f6040518083038185875af1925050503d805f81146136b0576040519150601f19603f3d011682016040523d82523d5f602084013e6136b5565b606091505b50915091506136c58683836136d0565b925050509392505050565b6060826136e5576136e08261375d565b613755565b5f825114801561370b57505f8473ffffffffffffffffffffffffffffffffffffffff163b145b1561374d57836040517f9996b3150000000000000000000000000000000000000000000000000000000081526004016137449190613ff4565b60405180910390fd5b819050613756565b5b9392505050565b5f8151111561376f5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6137e6816137b2565b81146137f0575f80fd5b50565b5f81359050613801816137dd565b92915050565b5f6020828403121561381c5761381b6137aa565b5b5f613829848285016137f3565b91505092915050565b5f8115159050919050565b61384681613832565b82525050565b5f60208201905061385f5f83018461383d565b92915050565b5f819050919050565b61387781613865565b8114613881575f80fd5b50565b5f813590506138928161386e565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6138c182613898565b9050919050565b6138d1816138b7565b81146138db575f80fd5b50565b5f813590506138ec816138c8565b92915050565b5f819050919050565b613904816138f2565b811461390e575f80fd5b50565b5f8135905061391f816138fb565b92915050565b5f805f805f8060c0878903121561393f5761393e6137aa565b5b5f61394c89828a01613884565b965050602061395d89828a016138de565b955050604061396e89828a01613884565b945050606061397f89828a01613884565b935050608061399089828a016138de565b92505060a06139a189828a01613911565b9150509295509295509295565b5f805f805f805f60e0888a0312156139c9576139c86137aa565b5b5f6139d68a828b01613884565b97505060206139e78a828b01613911565b96505060406139f88a828b01613911565b9550506060613a098a828b016138de565b9450506080613a1a8a828b01613884565b93505060a0613a2b8a828b01613884565b92505060c0613a3c8a828b016138de565b91505092959891949750929550565b5f80fd5b5f80fd5b5f80fd5b5f8083601f840112613a6c57613a6b613a4b565b5b8235905067ffffffffffffffff811115613a8957613a88613a4f565b5b602083019150836001820283011115613aa557613aa4613a53565b5b9250929050565b5f805f805f60808688031215613ac557613ac46137aa565b5b5f613ad2888289016138de565b9550506020613ae3888289016138de565b9450506040613af488828901613911565b935050606086013567ffffffffffffffff811115613b1557613b146137ae565b5b613b2188828901613a57565b92509250509295509295909350565b613b39816137b2565b82525050565b5f602082019050613b525f830184613b30565b92915050565b5f805f805f805f60e0888a031215613b7357613b726137aa565b5b5f613b808a828b01613884565b9750506020613b918a828b01613911565b9650506040613ba28a828b016138de565b9550506060613bb38a828b01613884565b9450506080613bc48a828b01613884565b93505060a0613bd58a828b016138de565b92505060c0613be68a828b01613911565b91505092959891949750929550565b5f60208284031215613c0a57613c096137aa565b5b5f613c1784828501613884565b91505092915050565b5f7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b613c5481613c20565b82525050565b5f63ffffffff82169050919050565b613c7281613c5a565b82525050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60058110613cb657613cb5613c78565b5b50565b5f819050613cc682613ca5565b919050565b5f613cd582613cb9565b9050919050565b613ce581613ccb565b82525050565b5f608082019050613cfe5f830187613c4b565b613d0b6020830186613c69565b613d186040830185613c69565b613d256060830184613cdc565b95945050505050565b613d3781613c5a565b8114613d41575f80fd5b50565b5f81359050613d5281613d2e565b92915050565b5f805f805f805f60e0888a031215613d7357613d726137aa565b5b5f613d808a828b01613884565b9750506020613d918a828b01613911565b9650506040613da28a828b016138de565b9550506060613db38a828b01613884565b9450506080613dc48a828b01613884565b93505060a0613dd58a828b01613d44565b92505060c0613de68a828b01613d44565b91505092959891949750929550565b5f8083601f840112613e0a57613e09613a4b565b5b8235905067ffffffffffffffff811115613e2757613e26613a4f565b5b602083019150836020820283011115613e4357613e42613a53565b5b9250929050565b5f805f805f805f8060a0898b031215613e6657613e656137aa565b5b5f613e738b828c016138de565b9850506020613e848b828c016138de565b975050604089013567ffffffffffffffff811115613ea557613ea46137ae565b5b613eb18b828c01613df5565b9650965050606089013567ffffffffffffffff811115613ed457613ed36137ae565b5b613ee08b828c01613df5565b9450945050608089013567ffffffffffffffff811115613f0357613f026137ae565b5b613f0f8b828c01613a57565b92509250509295985092959890939650565b5f805f805f805f805f6101208a8c031215613f3f57613f3e6137aa565b5b5f613f4c8c828d01613884565b9950506020613f5d8c828d01613911565b9850506040613f6e8c828d01613911565b9750506060613f7f8c828d016138de565b9650506080613f908c828d016138de565b95505060a0613fa18c828d01613884565b94505060c0613fb28c828d01613884565b93505060e0613fc38c828d01613d44565b925050610100613fd58c828d01613d44565b9150509295985092959850929598565b613fee816138b7565b82525050565b5f6020820190506140075f830184613fe5565b92915050565b6004811061401e5761401d613c78565b5b50565b5f81905061402e8261400d565b919050565b5f61403d82614021565b9050919050565b61404d81614033565b82525050565b5f6060820190506140665f830186613c4b565b6140736020830185613c69565b6140806040830184614044565b949350505050565b5f805f805f8060a087890312156140a2576140a16137aa565b5b5f6140af89828a016138de565b96505060206140c089828a016138de565b95505060406140d189828a01613911565b94505060606140e289828a01613911565b935050608087013567ffffffffffffffff811115614103576141026137ae565b5b61410f89828a01613a57565b92509250509295509295509295565b5f82825260208201905092915050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520505f8201527f61796d656e7453656e7400000000000000000000000000000000000000000000602082015250565b5f614188602a8361411e565b91506141938261412e565b604082019050919050565b5f6020820190508181035f8301526141b58161417c565b9050919050565b5f8160601b9050919050565b5f6141d2826141bc565b9050919050565b5f6141e3826141c8565b9050919050565b6141fb6141f6826138b7565b6141d9565b82525050565b5f819050919050565b61421b61421682613865565b614201565b82525050565b5f819050919050565b61423b614236826138f2565b614221565b82525050565b5f61424c82896141ea565b60148201915061425c82886141ea565b60148201915061426c828761420a565b60208201915061427c828661420a565b60208201915061428c82856141ea565b60148201915061429c828461422a565b602082019150819050979650505050505050565b5f81519050919050565b5f81905092915050565b5f5b838110156142e15780820151818401526020810190506142c6565b5f8484015250505050565b5f6142f6826142b0565b61430081856142ba565b93506143108185602086016142c4565b80840191505092915050565b5f61432782846142ec565b915081905092915050565b7f496e76616c6964207061796d656e7448617368000000000000000000000000005f82015250565b5f61436660138361411e565b915061437182614332565b602082019050919050565b5f6020820190508181035f8301526143938161435a565b9050919050565b7f43757272656e742074696d657374616d70206469646e277420657863656564205f8201527f7061796d656e7420726566756e64206c6f636b2074696d650000000000000000602082015250565b5f6143f460388361411e565b91506143ff8261439a565b604082019050919050565b5f6020820190508181035f830152614421816143e8565b9050919050565b61443181613865565b82525050565b5f60208201905061444a5f830184614428565b92915050565b614459816138f2565b82525050565b5f6060820190506144725f830186613fe5565b61447f6020830185613fe5565b61448c6040830184614450565b949350505050565b5f61449f828a61422a565b6020820191506144af828961422a565b6020820191506144bf82886141ea565b6014820191506144cf82876141ea565b6014820191506144df828661420a565b6020820191506144ef828561420a565b6020820191506144ff82846141ea565b60148201915081905098975050505050505050565b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61455e82614518565b810181811067ffffffffffffffff8211171561457d5761457c614528565b5b80604052505050565b5f61458f6137a1565b905061459b8282614555565b919050565b5f60c082840312156145b5576145b4614514565b5b6145bf60c0614586565b90505f6145ce84828501613884565b5f8301525060206145e1848285016138de565b60208301525060406145f5848285016138de565b604083015250606061460984828501613884565b606083015250608061461d84828501613884565b60808301525060a061463184828501613d44565b60a08301525092915050565b5f60c08284031215614652576146516137aa565b5b5f61465f848285016145a0565b91505092915050565b7f54616b6572206d757374206e6f74206265207a65726f206164647265737300005f82015250565b5f61469c601e8361411e565b91506146a782614668565b602082019050919050565b5f6020820190508181035f8301526146c981614690565b9050919050565b7f546f6b656e206d757374206e6f74206265207a65726f206164647265737300005f82015250565b5f614704601e8361411e565b915061470f826146d0565b602082019050919050565b5f6020820190508181035f830152614731816146f8565b9050919050565b7f546f6b656e206164647265737320646f6573206e6f74206d617463682073656e5f8201527f6465720000000000000000000000000000000000000000000000000000000000602082015250565b5f61479260238361411e565b915061479d82614738565b604082019050919050565b5f6020820190508181035f8301526147bf81614786565b9050919050565b7f4f70657261746f72206d757374206265207468652073656e64657200000000005f82015250565b5f6147fa601b8361411e565b9150614805826147c6565b602082019050919050565b5f6020820190508181035f830152614827816147ee565b9050919050565b7f4d616b657220455243373231207061796d656e74206d75737420626520556e695f8201527f6e697469616c697a656400000000000000000000000000000000000000000000602082015250565b5f614888602a8361411e565b91506148938261482e565b604082019050919050565b5f6020820190508181035f8301526148b58161487c565b9050919050565b7f54616b65722063616e6e6f74206265206120636f6e74726163740000000000005f82015250565b5f6148f0601a8361411e565b91506148fb826148bc565b602082019050919050565b5f6020820190508181035f83015261491d816148e4565b9050919050565b5f61492f828a6141ea565b60148201915061493f82896141ea565b60148201915061494f828861420a565b60208201915061495f828761420a565b60208201915061496f82866141ea565b60148201915061497f828561422a565b60208201915061498f828461422a565b60208201915081905098975050505050505050565b5f82825260208201905092915050565b50565b5f6149c25f836149a4565b91506149cd826149b4565b5f82019050919050565b5f60a0820190506149ea5f830187613fe5565b6149f76020830186613fe5565b614a046040830185614450565b614a116060830184614450565b8181036080830152614a22816149b7565b905095945050505050565b5f614a38828461420a565b60208201915081905092915050565b5f81519050614a558161386e565b92915050565b5f60208284031215614a7057614a6f6137aa565b5b5f614a7d84828501614a47565b91505092915050565b5f604082019050614a995f830185614428565b614aa66020830184614428565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f614ae4826138f2565b9150614aef836138f2565b9250828201905080821115614b0757614b06614aad565b5b92915050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520505f8201527f61796d656e7453656e74206f722054616b6572417070726f7665640000000000602082015250565b5f614b67603b8361411e565b9150614b7282614b0d565b604082019050919050565b5f6020820190508181035f830152614b9481614b5b565b9050919050565b7f43757272656e742074696d657374616d70206469646e277420657863656564205f8201527f7061796d656e74207072652d617070726f7665206c6f636b2074696d65000000602082015250565b5f614bf5603d8361411e565b9150614c0082614b9b565b604082019050919050565b5f6020820190508181035f830152614c2281614be9565b9050919050565b7f54616b6572207061796d656e7420697320616c726561647920696e697469616c5f8201527f697a656400000000000000000000000000000000000000000000000000000000602082015250565b5f614c8360248361411e565b9150614c8e82614c29565b604082019050919050565b5f6020820190508181035f830152614cb081614c77565b9050919050565b7f5265636569766572206d757374206e6f74206265207a65726f206164647265735f8201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b5f614d1160218361411e565b9150614d1c82614cb7565b604082019050919050565b5f6020820190508181035f830152614d3e81614d05565b9050919050565b7f4554482076616c7565206d7573742062652067726561746572207468616e207a5f8201527f65726f0000000000000000000000000000000000000000000000000000000000602082015250565b5f614d9f60238361411e565b9150614daa82614d45565b604082019050919050565b5f6020820190508181035f830152614dcc81614d93565b9050919050565b7f4554482076616c7565206d7573742062652067726561746572207468616e20645f8201527f6578206665650000000000000000000000000000000000000000000000000000602082015250565b5f614e2d60268361411e565b9150614e3882614dd3565b604082019050919050565b5f6020820190508181035f830152614e5a81614e21565b9050919050565b5f614e6b826138f2565b9150614e76836138f2565b9250828203905081811115614e8e57614e8d614aad565b5b92915050565b7f4261746368207472616e7366657273206e6f7420737570706f727465640000005f82015250565b5f614ec8601d8361411e565b9150614ed382614e94565b602082019050919050565b5f6020820190508181035f830152614ef581614ebc565b9050919050565b7f43616c6c6572206d75737420626520616e20454f4100000000000000000000005f82015250565b5f614f3060158361411e565b9150614f3b82614efc565b602082019050919050565b5f6020820190508181035f830152614f5d81614f24565b9050919050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520545f8201527f616b6572417070726f7665640000000000000000000000000000000000000000602082015250565b5f614fbe602c8361411e565b9150614fc982614f64565b604082019050919050565b5f6020820190508181035f830152614feb81614fb2565b9050919050565b7f4552433230207632207061796d656e7420697320616c726561647920696e69745f8201527f69616c697a656400000000000000000000000000000000000000000000000000602082015250565b5f61504c60278361411e565b915061505782614ff2565b604082019050919050565b5f6020820190508181035f83015261507981615040565b9050919050565b7f416d6f756e74206d757374206e6f74206265207a65726f0000000000000000005f82015250565b5f6150b460178361411e565b91506150bf82615080565b602082019050919050565b5f6020820190508181035f8301526150e1816150a8565b9050919050565b7f44657820666565206d757374206e6f74206265207a65726f00000000000000005f82015250565b5f61511c60188361411e565b9150615127826150e8565b602082019050919050565b5f6020820190508181035f83015261514981615110565b9050919050565b7f56616c7565206d7573742062652067726561746572207468616e2030000000005f82015250565b5f615184601c8361411e565b915061518f82615150565b602082019050919050565b5f6020820190508181035f8301526151b181615178565b9050919050565b7f4d616b65722045524331313535207061796d656e74206d75737420626520556e5f8201527f696e697469616c697a6564000000000000000000000000000000000000000000602082015250565b5f615212602b8361411e565b915061521d826151b8565b604082019050919050565b5f6020820190508181035f83015261523f81615206565b9050919050565b5f6040820190506152595f830185613fe5565b6152666020830184614450565b9392505050565b61527681613832565b8114615280575f80fd5b50565b5f815190506152918161526d565b92915050565b5f602082840312156152ac576152ab6137aa565b5b5f6152b984828501615283565b9150509291505056fea264697066735822122077b4b2078ef3c6b5011576148b3629aef4d5bdf826c80bb1e059ab90e714e30264736f6c63430008180033"; pub trait CoinDockerOps { fn rpc_client(&self) -> &UtxoRpcClientEnum; @@ -1146,6 +1160,111 @@ pub fn init_geth_node() { thread::sleep(Duration::from_millis(100)); } + let tx_request_deploy_erc721 = TransactionRequest { + from: GETH_ACCOUNT, + to: None, + gas: None, + gas_price: None, + value: None, + data: Some(hex::decode(ERC721_TEST_TOKEN_BYTES).unwrap().into()), + nonce: None, + condition: None, + transaction_type: None, + access_list: None, + max_fee_per_gas: None, + max_priority_fee_per_gas: None, + }; + let deploy_erc721_tx_hash = block_on(GETH_WEB3.eth().send_transaction(tx_request_deploy_erc721)).unwrap(); + log!("Sent ERC721 deploy transaction {:?}", deploy_erc721_tx_hash); + + loop { + let deploy_erc721_tx_receipt = match block_on(GETH_WEB3.eth().transaction_receipt(deploy_erc721_tx_hash)) { + Ok(receipt) => receipt, + Err(_) => { + thread::sleep(Duration::from_millis(100)); + continue; + }, + }; + + if let Some(receipt) = deploy_erc721_tx_receipt { + GETH_ERC721_CONTRACT = receipt.contract_address.unwrap(); + log!("GETH_ERC721_CONTRACT {:?}", GETH_ERC721_CONTRACT); + break; + } + thread::sleep(Duration::from_millis(100)); + } + + let tx_request_deploy_erc1155 = TransactionRequest { + from: GETH_ACCOUNT, + to: None, + gas: None, + gas_price: None, + value: None, + data: Some(hex::decode(ERC1155_TEST_TOKEN_BYTES).unwrap().into()), + nonce: None, + condition: None, + transaction_type: None, + access_list: None, + max_fee_per_gas: None, + max_priority_fee_per_gas: None, + }; + let deploy_erc1155_tx_hash = block_on(GETH_WEB3.eth().send_transaction(tx_request_deploy_erc1155)).unwrap(); + log!("Sent ERC1155 deploy transaction {:?}", deploy_erc721_tx_hash); + + loop { + let deploy_erc1155_tx_receipt = match block_on(GETH_WEB3.eth().transaction_receipt(deploy_erc1155_tx_hash)) + { + Ok(receipt) => receipt, + Err(_) => { + thread::sleep(Duration::from_millis(100)); + continue; + }, + }; + + if let Some(receipt) = deploy_erc1155_tx_receipt { + GETH_ERC1155_CONTRACT = receipt.contract_address.unwrap(); + log!("GETH_ERC1155_CONTRACT {:?}", GETH_ERC1155_CONTRACT); + break; + } + thread::sleep(Duration::from_millis(100)); + } + + let tx_request_deploy_nft_swap_contract = TransactionRequest { + from: GETH_ACCOUNT, + to: None, + gas: None, + gas_price: None, + value: None, + data: Some(hex::decode(NFT_SWAP_CONTRACT_BYTES).unwrap().into()), + nonce: None, + condition: None, + transaction_type: None, + access_list: None, + max_fee_per_gas: None, + max_priority_fee_per_gas: None, + }; + let deploy_nft_swap_tx_hash = + block_on(GETH_WEB3.eth().send_transaction(tx_request_deploy_nft_swap_contract)).unwrap(); + log!("Sent deploy nft swap contract transaction {:?}", deploy_swap_tx_hash); + + loop { + let deploy_nft_swap_tx_receipt = + match block_on(GETH_WEB3.eth().transaction_receipt(deploy_nft_swap_tx_hash)) { + Ok(receipt) => receipt, + Err(_) => { + thread::sleep(Duration::from_millis(100)); + continue; + }, + }; + + if let Some(receipt) = deploy_nft_swap_tx_receipt { + GETH_NFT_SWAP_CONTRACT = receipt.contract_address.unwrap(); + log!("GETH_NFT_SWAP_CONTRACT {:?}", GETH_SWAP_CONTRACT); + break; + } + thread::sleep(Duration::from_millis(100)); + } + let alice_passphrase = get_passphrase!(".env.client", "ALICE_PASSPHRASE").unwrap(); let alice_keypair = key_pair_from_seed(&alice_passphrase).unwrap(); let alice_eth_addr = addr_from_raw_pubkey(alice_keypair.public()).unwrap(); diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index b908e51bbf..9bde2ee719 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -1,6 +1,7 @@ -use crate::docker_tests::docker_tests_common::{random_secp256k1_secret, GETH_ACCOUNT, GETH_ERC20_CONTRACT, - GETH_NONCE_LOCK, GETH_SWAP_CONTRACT, GETH_WATCHERS_SWAP_CONTRACT, - GETH_WEB3, MM_CTX}; +use crate::docker_tests::docker_tests_common::{random_secp256k1_secret, ERC1155_TEST_ABI, ERC721_TEST_ABI, + GETH_ACCOUNT, GETH_ERC1155_CONTRACT, GETH_ERC20_CONTRACT, + GETH_ERC721_CONTRACT, GETH_NFT_SWAP_CONTRACT, GETH_NONCE_LOCK, + GETH_SWAP_CONTRACT, GETH_WATCHERS_SWAP_CONTRACT, GETH_WEB3, MM_CTX}; use bitcrypto::dhash160; use coins::eth::{checksum_address, eth_coin_from_conf_and_request, EthCoin, ERC20_ABI}; use coins::{CoinProtocol, ConfirmPaymentInput, FoundSwapTxSpend, MarketCoinOps, PrivKeyBuildPolicy, RefundPaymentArgs, @@ -8,7 +9,7 @@ use coins::{CoinProtocol, ConfirmPaymentInput, FoundSwapTxSpend, MarketCoinOps, use common::{block_on, now_sec}; use ethereum_types::U256; use futures01::Future; -use mm2_test_helpers::for_tests::{erc20_dev_conf, eth_dev_conf}; +use mm2_test_helpers::for_tests::{erc20_dev_conf, eth_dev_conf, nft_dev_conf}; use std::thread; use std::time::Duration; use web3::contract::{Contract, Options}; @@ -25,6 +26,11 @@ fn geth_account() -> Address { unsafe { GETH_ACCOUNT } } /// GETH_SWAP_CONTRACT is set once during initialization before tests start pub fn swap_contract() -> Address { unsafe { GETH_SWAP_CONTRACT } } +/// # Safety +/// +/// GETH_NFT_SWAP_CONTRACT is set once during initialization before tests start +pub fn nft_swap_contract() -> Address { unsafe { GETH_NFT_SWAP_CONTRACT } } + /// # Safety /// /// GETH_WATCHERS_SWAP_CONTRACT is set once during initialization before tests start @@ -38,6 +44,16 @@ pub fn erc20_contract() -> Address { unsafe { GETH_ERC20_CONTRACT } } /// Return ERC20 dev token contract address in checksum format pub fn erc20_contract_checksum() -> String { checksum_address(&format!("{:02x}", erc20_contract())) } +/// # Safety +/// +/// GETH_ERC721_CONTRACT is set once during initialization before tests start +pub fn erc721_contract() -> Address { unsafe { GETH_ERC721_CONTRACT } } + +/// # Safety +/// +/// GETH_ERC1155_CONTRACT is set once during initialization before tests start +pub fn erc1155_contract() -> Address { unsafe { GETH_ERC1155_CONTRACT } } + fn wait_for_confirmation(tx_hash: H256) { loop { match block_on(GETH_WEB3.eth().transaction_receipt(tx_hash)) { @@ -144,6 +160,70 @@ pub fn erc20_coin_with_random_privkey(swap_contract: Address) -> EthCoin { erc20_coin } +fn fill_erc721(to_addr: Address, token_id: U256) { + let _guard = GETH_NONCE_LOCK.lock().unwrap(); + let erc721_contract = Contract::from_json(GETH_WEB3.eth(), erc721_contract(), ERC721_TEST_ABI.as_bytes()).unwrap(); + + let tx_hash = block_on(erc721_contract.call( + "mint", + (Token::Address(to_addr), Token::Uint(token_id)), + geth_account(), + Options::default(), + )) + .unwrap(); + wait_for_confirmation(tx_hash); +} + +fn fill_erc1155(to_addr: Address, token_id: U256, amount: U256) { + let _guard = GETH_NONCE_LOCK.lock().unwrap(); + let erc1155_contract = + Contract::from_json(GETH_WEB3.eth(), erc1155_contract(), ERC1155_TEST_ABI.as_bytes()).unwrap(); + + let tx_hash = block_on(erc1155_contract.call( + "mint", + ( + Token::Address(to_addr), + Token::Uint(token_id), + Token::Uint(amount), + Token::Bytes("".into()), + ), + geth_account(), + Options::default(), + )) + .unwrap(); + wait_for_confirmation(tx_hash); +} + +/// Creates global NFT supplied with one ERC721 and 3 ERC1155 tokens owned by user in nfts_infos field +pub fn global_nft_with_random_privkey(swap_contract: Address) -> EthCoin { + let nft_conf = nft_dev_conf(); + let req = json!({ + "method": "enable", + "coin": "NFT_ETH", + "urls": ["http://127.0.0.1:8545"], + "swap_contract_address": swap_contract, + }); + + let global_nft = block_on(eth_coin_from_conf_and_request( + &MM_CTX, + "NFT_ETH", + &nft_conf, + &req, + CoinProtocol::NFT { + platform: "ETH".to_string(), + }, + PrivKeyBuildPolicy::IguanaPrivKey(random_secp256k1_secret()), + )) + .unwrap(); + + fill_erc721(global_nft.my_address, U256::from(1)); + fill_erc1155(global_nft.my_address, U256::from(1), U256::from(3)); + + // todo add minted nfts into nfts_infos field in global_nft + + global_nft +} + #[test] fn send_and_refund_eth_maker_payment() { let eth_coin = eth_coin_with_random_privkey(swap_contract()); @@ -296,6 +376,32 @@ fn send_and_spend_eth_maker_payment() { assert_eq!(expected, search_tx); } +#[test] +fn send_and_refund_erc2721_maker_payment() { + let global_nft = global_nft_with_random_privkey(nft_swap_contract()); + + let time_lock = now_sec() - 100; + let other_pubkey = &[ + 0x02, 0xc6, 0x6e, 0x7d, 0x89, 0x66, 0xb5, 0xc5, 0x55, 0xaf, 0x58, 0x05, 0x98, 0x9d, 0xa9, 0xfb, 0xf8, 0xdb, + 0x95, 0xe1, 0x56, 0x31, 0xce, 0x35, 0x8c, 0x3a, 0x17, 0x10, 0xc9, 0x62, 0x67, 0x90, 0x63, + ]; + let secret_hash = &[1; 20]; + + // todo provide new SendMakerNftPaymentArgs type + let _send_payment_args = SendPaymentArgs { + time_lock_duration: 100, + time_lock, + other_pubkey, + secret_hash, + amount: 1.into(), + swap_contract_address: &Some(nft_swap_contract().as_bytes().into()), + swap_unique_data: &[], + payment_instructions: &None, + watcher_reward: None, + wait_for_confirmation_until: now_sec() + 60, + }; +} + #[test] fn send_and_refund_erc20_maker_payment() { let erc20_coin = erc20_coin_with_random_privkey(swap_contract()); diff --git a/mm2src/mm2_test_helpers/dummy_files/erc1155_test_abi.json b/mm2src/mm2_test_helpers/dummy_files/erc1155_test_abi.json new file mode 100644 index 0000000000..8b2e2c2f80 --- /dev/null +++ b/mm2src/mm2_test_helpers/dummy_files/erc1155_test_abi.json @@ -0,0 +1,455 @@ +[ + { + "inputs": [ + { + "internalType": "string", + "name": "uri", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "ERC1155InsufficientBalance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "approver", + "type": "address" + } + ], + "name": "ERC1155InvalidApprover", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "idsLength", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "valuesLength", + "type": "uint256" + } + ], + "name": "ERC1155InvalidArrayLength", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "ERC1155InvalidOperator", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "ERC1155InvalidReceiver", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "ERC1155InvalidSender", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "ERC1155MissingApprovalForAll", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "ids", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + } + ], + "name": "TransferBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "TransferSingle", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "value", + "type": "string" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "URI", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "accounts", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "ids", + "type": "uint256[]" + } + ], + "name": "balanceOfBatch", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "ids", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeBatchTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "uri", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/mm2src/mm2_test_helpers/dummy_files/erc721_test_abi.json b/mm2src/mm2_test_helpers/dummy_files/erc721_test_abi.json new file mode 100644 index 0000000000..697eccce5c --- /dev/null +++ b/mm2src/mm2_test_helpers/dummy_files/erc721_test_abi.json @@ -0,0 +1,469 @@ +[ + { + "inputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "ERC721IncorrectOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "ERC721InsufficientApproval", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "approver", + "type": "address" + } + ], + "name": "ERC721InvalidApprover", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "ERC721InvalidOperator", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "ERC721InvalidOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "ERC721InvalidReceiver", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "ERC721InvalidSender", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "ERC721NonexistentToken", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "approved", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getApproved", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "ownerOf", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "tokenURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] \ No newline at end of file diff --git a/mm2src/mm2_test_helpers/src/for_tests.rs b/mm2src/mm2_test_helpers/src/for_tests.rs index 1728d92464..df3e12f314 100644 --- a/mm2src/mm2_test_helpers/src/for_tests.rs +++ b/mm2src/mm2_test_helpers/src/for_tests.rs @@ -813,6 +813,23 @@ pub fn erc20_dev_conf(contract_address: &str) -> Json { }) } +/// global NFT configuration used for dockerized Geth dev node +pub fn nft_dev_conf() -> Json { + json!({ + "coin": "ERC20DEV", + "name": "erc20dev", + "chain_id": 1337, + "mm2": 1, + "derivation_path": "m/44'/60'", + "protocol": { + "type": "NFT", + "protocol_data": { + "platform": "ETH" + } + } + }) +} + pub fn eth_sepolia_conf() -> Json { json!({ "coin": "ETH", From 1f6b2f77906007154b60e632f5099239ce06c4a9 Mon Sep 17 00:00:00 2001 From: laruh Date: Tue, 5 Mar 2024 20:20:07 +0700 Subject: [PATCH 02/80] encode nft contracts contracture arguments --- Cargo.lock | 1 + mm2src/mm2_main/Cargo.toml | 1 + .../tests/docker_tests/docker_tests_common.rs | 17 ++++++++++++++--- .../tests/docker_tests/eth_docker_tests.rs | 2 +- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 475508ffe3..86e7ea8df9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4444,6 +4444,7 @@ dependencies = [ "either", "enum-primitive-derive", "enum_derives", + "ethabi", "ethereum-types", "futures 0.1.29", "futures 0.3.28", diff --git a/mm2src/mm2_main/Cargo.toml b/mm2src/mm2_main/Cargo.toml index 3b037954f3..800012fff0 100644 --- a/mm2src/mm2_main/Cargo.toml +++ b/mm2src/mm2_main/Cargo.toml @@ -125,6 +125,7 @@ mm2_test_helpers = { path = "../mm2_test_helpers" } mocktopus = "0.8.0" testcontainers = "0.15.0" web3 = { git = "https://github.com/KomodoPlatform/rust-web3", tag = "v0.19.0", default-features = false, features = ["http"] } +ethabi = { version = "17.0.0" } [build-dependencies] chrono = "0.4" diff --git a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs index ffec8335a7..a41a8e3cec 100644 --- a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs +++ b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs @@ -7,7 +7,7 @@ pub use mm2_test_helpers::for_tests::{check_my_swap_status, check_recent_swaps, ETH_DEV_SWAP_CONTRACT, ETH_DEV_TOKEN_CONTRACT, MAKER_ERROR_EVENTS, MAKER_SUCCESS_EVENTS, TAKER_ERROR_EVENTS, TAKER_SUCCESS_EVENTS}; -use crate::docker_tests::eth_docker_tests::fill_eth; +use crate::docker_tests::eth_docker_tests::{erc721_contract, fill_eth}; use bitcrypto::{dhash160, ChecksumType}; use chain::TransactionOutput; use coins::eth::{addr_from_raw_pubkey, eth_coin_from_conf_and_request, EthCoin}; @@ -24,6 +24,7 @@ use coins::utxo::{coin_daemon_data_dir, sat_from_big_decimal, zcash_params_path, use coins::{CoinProtocol, ConfirmPaymentInput, MarketCoinOps, PrivKeyBuildPolicy, Transaction}; use crypto::privkey::key_pair_from_seed; use crypto::Secp256k1Secret; +use ethabi::Token; use ethereum_types::{H160 as H160Eth, U256}; use futures01::Future; use http::StatusCode; @@ -47,6 +48,7 @@ use std::time::Duration; use testcontainers::clients::Cli; use testcontainers::core::WaitFor; use testcontainers::{Container, GenericImage, RunnableImage}; +use web3::contract::Contract; use web3::transports::Http; use web3::types::TransactionRequest; use web3::Web3; @@ -1160,13 +1162,18 @@ pub fn init_geth_node() { thread::sleep(Duration::from_millis(100)); } + let name = Token::String("MyNFT".into()); + let symbol = Token::String("MNFT".into()); + let params = ethabi::encode(&[name, symbol]); + let erc721_data = format!("{}{}", ERC721_TEST_TOKEN_BYTES, hex::encode(params)); + let tx_request_deploy_erc721 = TransactionRequest { from: GETH_ACCOUNT, to: None, gas: None, gas_price: None, value: None, - data: Some(hex::decode(ERC721_TEST_TOKEN_BYTES).unwrap().into()), + data: Some(hex::decode(erc721_data).unwrap().into()), nonce: None, condition: None, transaction_type: None, @@ -1194,13 +1201,17 @@ pub fn init_geth_node() { thread::sleep(Duration::from_millis(100)); } + let uri = Token::String("MyNFTUri".into()); + let params = ethabi::encode(&[uri]); + let erc1155_data = format!("{}{}", ERC1155_TEST_TOKEN_BYTES, hex::encode(params)); + let tx_request_deploy_erc1155 = TransactionRequest { from: GETH_ACCOUNT, to: None, gas: None, gas_price: None, value: None, - data: Some(hex::decode(ERC1155_TEST_TOKEN_BYTES).unwrap().into()), + data: Some(hex::decode(erc1155_data).unwrap().into()), nonce: None, condition: None, transaction_type: None, diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index 9bde2ee719..e57ce06b02 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -378,7 +378,7 @@ fn send_and_spend_eth_maker_payment() { #[test] fn send_and_refund_erc2721_maker_payment() { - let global_nft = global_nft_with_random_privkey(nft_swap_contract()); + let _global_nft = global_nft_with_random_privkey(nft_swap_contract()); let time_lock = now_sec() - 100; let other_pubkey = &[ From 388d2e9dfdf582d52b5060fd1b8ae2d0c65cc450 Mon Sep 17 00:00:00 2001 From: laruh Date: Tue, 5 Mar 2024 21:01:25 +0700 Subject: [PATCH 03/80] encode dex_fee_address for nft_swap_data --- .../tests/docker_tests/docker_tests_common.rs | 14 +++++++++++--- .../tests/docker_tests/eth_docker_tests.rs | 12 +++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs index a41a8e3cec..e627ca3809 100644 --- a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs +++ b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs @@ -7,7 +7,7 @@ pub use mm2_test_helpers::for_tests::{check_my_swap_status, check_recent_swaps, ETH_DEV_SWAP_CONTRACT, ETH_DEV_TOKEN_CONTRACT, MAKER_ERROR_EVENTS, MAKER_SUCCESS_EVENTS, TAKER_ERROR_EVENTS, TAKER_SUCCESS_EVENTS}; -use crate::docker_tests::eth_docker_tests::{erc721_contract, fill_eth}; +use crate::docker_tests::eth_docker_tests::{dex_fee_address, fill_eth}; use bitcrypto::{dhash160, ChecksumType}; use chain::TransactionOutput; use coins::eth::{addr_from_raw_pubkey, eth_coin_from_conf_and_request, EthCoin}; @@ -48,7 +48,6 @@ use std::time::Duration; use testcontainers::clients::Cli; use testcontainers::core::WaitFor; use testcontainers::{Container, GenericImage, RunnableImage}; -use web3::contract::Contract; use web3::transports::Http; use web3::types::TransactionRequest; use web3::Web3; @@ -88,6 +87,8 @@ pub static mut GETH_ERC721_CONTRACT: H160Eth = H160Eth::zero(); pub static mut GETH_ERC1155_CONTRACT: H160Eth = H160Eth::zero(); /// Nft Swap contract address on Geth dev node pub static mut GETH_NFT_SWAP_CONTRACT: H160Eth = H160Eth::zero(); +/// Dex fee address on Geth dev node +pub static mut GETH_DEX_FEE_ADDRESS: H160Eth = H160Eth::zero(); pub static GETH_RPC_URL: &str = "http://127.0.0.1:8545"; pub const UTXO_ASSET_DOCKER_IMAGE: &str = "docker.io/artempikulin/testblockchain"; @@ -1050,6 +1051,9 @@ pub fn init_geth_node() { GETH_ACCOUNT = accounts[0]; log!("GETH ACCOUNT {:?}", GETH_ACCOUNT); + GETH_DEX_FEE_ADDRESS = accounts[1]; + log!("GETH_DEX_FEE_ADDRESS {:?}", GETH_DEX_FEE_ADDRESS); + let tx_request_deploy_erc20 = TransactionRequest { from: GETH_ACCOUNT, to: None, @@ -1240,13 +1244,17 @@ pub fn init_geth_node() { thread::sleep(Duration::from_millis(100)); } + let dex_fee_address = Token::Address(dex_fee_address()); + let params = ethabi::encode(&[dex_fee_address]); + let nft_swap_data = format!("{}{}", NFT_SWAP_CONTRACT_BYTES, hex::encode(params)); + let tx_request_deploy_nft_swap_contract = TransactionRequest { from: GETH_ACCOUNT, to: None, gas: None, gas_price: None, value: None, - data: Some(hex::decode(NFT_SWAP_CONTRACT_BYTES).unwrap().into()), + data: Some(hex::decode(nft_swap_data).unwrap().into()), nonce: None, condition: None, transaction_type: None, diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index e57ce06b02..51a9571926 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -1,7 +1,8 @@ use crate::docker_tests::docker_tests_common::{random_secp256k1_secret, ERC1155_TEST_ABI, ERC721_TEST_ABI, - GETH_ACCOUNT, GETH_ERC1155_CONTRACT, GETH_ERC20_CONTRACT, - GETH_ERC721_CONTRACT, GETH_NFT_SWAP_CONTRACT, GETH_NONCE_LOCK, - GETH_SWAP_CONTRACT, GETH_WATCHERS_SWAP_CONTRACT, GETH_WEB3, MM_CTX}; + GETH_ACCOUNT, GETH_DEX_FEE_ADDRESS, GETH_ERC1155_CONTRACT, + GETH_ERC20_CONTRACT, GETH_ERC721_CONTRACT, GETH_NFT_SWAP_CONTRACT, + GETH_NONCE_LOCK, GETH_SWAP_CONTRACT, GETH_WATCHERS_SWAP_CONTRACT, + GETH_WEB3, MM_CTX}; use bitcrypto::dhash160; use coins::eth::{checksum_address, eth_coin_from_conf_and_request, EthCoin, ERC20_ABI}; use coins::{CoinProtocol, ConfirmPaymentInput, FoundSwapTxSpend, MarketCoinOps, PrivKeyBuildPolicy, RefundPaymentArgs, @@ -31,6 +32,11 @@ pub fn swap_contract() -> Address { unsafe { GETH_SWAP_CONTRACT } } /// GETH_NFT_SWAP_CONTRACT is set once during initialization before tests start pub fn nft_swap_contract() -> Address { unsafe { GETH_NFT_SWAP_CONTRACT } } +/// # Safety +/// +/// GETH_DEX_FEE_ADDRESS is set once during initialization before tests start +pub fn dex_fee_address() -> Address { unsafe { GETH_DEX_FEE_ADDRESS } } + /// # Safety /// /// GETH_WATCHERS_SWAP_CONTRACT is set once during initialization before tests start From ccd064542c120545517d22b8b7639325aff39dd6 Mon Sep 17 00:00:00 2001 From: laruh Date: Tue, 5 Mar 2024 21:16:50 +0700 Subject: [PATCH 04/80] use geth_account as dex_fee_address --- .../tests/docker_tests/docker_tests_common.rs | 9 ++------- .../tests/docker_tests/eth_docker_tests.rs | 14 ++++---------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs index e627ca3809..f72d5f39e8 100644 --- a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs +++ b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs @@ -7,7 +7,7 @@ pub use mm2_test_helpers::for_tests::{check_my_swap_status, check_recent_swaps, ETH_DEV_SWAP_CONTRACT, ETH_DEV_TOKEN_CONTRACT, MAKER_ERROR_EVENTS, MAKER_SUCCESS_EVENTS, TAKER_ERROR_EVENTS, TAKER_SUCCESS_EVENTS}; -use crate::docker_tests::eth_docker_tests::{dex_fee_address, fill_eth}; +use crate::docker_tests::eth_docker_tests::{fill_eth, geth_account}; use bitcrypto::{dhash160, ChecksumType}; use chain::TransactionOutput; use coins::eth::{addr_from_raw_pubkey, eth_coin_from_conf_and_request, EthCoin}; @@ -87,8 +87,6 @@ pub static mut GETH_ERC721_CONTRACT: H160Eth = H160Eth::zero(); pub static mut GETH_ERC1155_CONTRACT: H160Eth = H160Eth::zero(); /// Nft Swap contract address on Geth dev node pub static mut GETH_NFT_SWAP_CONTRACT: H160Eth = H160Eth::zero(); -/// Dex fee address on Geth dev node -pub static mut GETH_DEX_FEE_ADDRESS: H160Eth = H160Eth::zero(); pub static GETH_RPC_URL: &str = "http://127.0.0.1:8545"; pub const UTXO_ASSET_DOCKER_IMAGE: &str = "docker.io/artempikulin/testblockchain"; @@ -1051,9 +1049,6 @@ pub fn init_geth_node() { GETH_ACCOUNT = accounts[0]; log!("GETH ACCOUNT {:?}", GETH_ACCOUNT); - GETH_DEX_FEE_ADDRESS = accounts[1]; - log!("GETH_DEX_FEE_ADDRESS {:?}", GETH_DEX_FEE_ADDRESS); - let tx_request_deploy_erc20 = TransactionRequest { from: GETH_ACCOUNT, to: None, @@ -1244,7 +1239,7 @@ pub fn init_geth_node() { thread::sleep(Duration::from_millis(100)); } - let dex_fee_address = Token::Address(dex_fee_address()); + let dex_fee_address = Token::Address(geth_account()); let params = ethabi::encode(&[dex_fee_address]); let nft_swap_data = format!("{}{}", NFT_SWAP_CONTRACT_BYTES, hex::encode(params)); diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index 51a9571926..c388545a95 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -1,8 +1,7 @@ use crate::docker_tests::docker_tests_common::{random_secp256k1_secret, ERC1155_TEST_ABI, ERC721_TEST_ABI, - GETH_ACCOUNT, GETH_DEX_FEE_ADDRESS, GETH_ERC1155_CONTRACT, - GETH_ERC20_CONTRACT, GETH_ERC721_CONTRACT, GETH_NFT_SWAP_CONTRACT, - GETH_NONCE_LOCK, GETH_SWAP_CONTRACT, GETH_WATCHERS_SWAP_CONTRACT, - GETH_WEB3, MM_CTX}; + GETH_ACCOUNT, GETH_ERC1155_CONTRACT, GETH_ERC20_CONTRACT, + GETH_ERC721_CONTRACT, GETH_NFT_SWAP_CONTRACT, GETH_NONCE_LOCK, + GETH_SWAP_CONTRACT, GETH_WATCHERS_SWAP_CONTRACT, GETH_WEB3, MM_CTX}; use bitcrypto::dhash160; use coins::eth::{checksum_address, eth_coin_from_conf_and_request, EthCoin, ERC20_ABI}; use coins::{CoinProtocol, ConfirmPaymentInput, FoundSwapTxSpend, MarketCoinOps, PrivKeyBuildPolicy, RefundPaymentArgs, @@ -20,7 +19,7 @@ use web3::types::{Address, TransactionRequest, H256}; /// # Safety /// /// GETH_ACCOUNT is set once during initialization before tests start -fn geth_account() -> Address { unsafe { GETH_ACCOUNT } } +pub fn geth_account() -> Address { unsafe { GETH_ACCOUNT } } /// # Safety /// @@ -32,11 +31,6 @@ pub fn swap_contract() -> Address { unsafe { GETH_SWAP_CONTRACT } } /// GETH_NFT_SWAP_CONTRACT is set once during initialization before tests start pub fn nft_swap_contract() -> Address { unsafe { GETH_NFT_SWAP_CONTRACT } } -/// # Safety -/// -/// GETH_DEX_FEE_ADDRESS is set once during initialization before tests start -pub fn dex_fee_address() -> Address { unsafe { GETH_DEX_FEE_ADDRESS } } - /// # Safety /// /// GETH_WATCHERS_SWAP_CONTRACT is set once during initialization before tests start From 141c9f07b9999230c1726d35a49318f402c16a6b Mon Sep 17 00:00:00 2001 From: laruh Date: Wed, 6 Mar 2024 19:08:45 +0700 Subject: [PATCH 05/80] impl CoinAssocTypes for EthCoin --- mm2src/coins/eth.rs | 78 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 3 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 6208040bd5..181a75e68f 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -26,7 +26,7 @@ use crate::eth::web3_transport::websocket_transport::{WebsocketTransport, Websoc use crate::lp_price::get_base_price_in_rel; use crate::nft::nft_structs::{ContractType, ConvertChain, NftInfo, TransactionNftDetails, WithdrawErc1155, WithdrawErc721}; -use crate::{DexFee, RpcCommonOps, ValidateWatcherSpendInput, WatcherSpendType}; +use crate::{CoinAssocTypes, DexFee, RpcCommonOps, ToBytes, ValidateWatcherSpendInput, WatcherSpendType}; use async_trait::async_trait; use bitcrypto::{dhash160, keccak256, ripemd160, sha256}; use common::custom_futures::repeatable::{Ready, Retry, RetryOnError}; @@ -46,8 +46,7 @@ use ethabi::{Contract, Function, Token}; pub use ethcore_transaction::SignedTransaction as SignedEthTx; use ethcore_transaction::{Action, Transaction as UnSignedEthTx, UnverifiedTransaction}; use ethereum_types::{Address, H160, H256, U256}; -use ethkey::{public_to_address, KeyPair, Public, Signature}; -use ethkey::{sign, verify_address}; +use ethkey::{public_to_address, sign, verify_address, KeyPair, Public, Signature}; use futures::compat::Future01CompatExt; use futures::future::{join_all, select_ok, try_join_all, Either, FutureExt, TryFutureExt}; use futures01::Future; @@ -108,6 +107,7 @@ use super::{coin_conf, lp_coinfind_or_err, AsyncMutex, BalanceError, BalanceFut, EARLY_CONFIRMATION_ERR_LOG, INVALID_CONTRACT_ADDRESS_ERR_LOG, INVALID_PAYMENT_STATE_ERR_LOG, INVALID_RECEIVER_ERR_LOG, INVALID_SENDER_ERR_LOG, INVALID_SWAP_ID_ERR_LOG}; pub use rlp; +use rlp::{DecoderError, Encodable, RlpStream}; mod eth_balance_events; mod eth_rpc; @@ -6178,3 +6178,75 @@ async fn get_eth_gas_details( }, } } + +impl ToBytes for Signature { + fn to_bytes(&self) -> Vec { self.to_vec() } +} + +impl ToBytes for SignedEthTx { + fn to_bytes(&self) -> Vec { + let mut stream = RlpStream::new(); + self.rlp_append(&mut stream); + // there is minimal but risk that stream.out() may panic + debug_assert!(stream.is_finished(), "RlpStream must be finished before calling out"); + Vec::from(stream.out()) + } +} + +impl ToBytes for Public { + fn to_bytes(&self) -> Vec { self.0.to_vec() } +} + +#[derive(Debug, Display)] +pub enum CoinAssocTypesError { + InvalidHexString(String), + TxParseError(String), + SignatureParseError(String), + ParseSignatureError(String), +} + +impl From for CoinAssocTypesError { + fn from(e: DecoderError) -> Self { CoinAssocTypesError::TxParseError(e.to_string()) } +} + +impl CoinAssocTypes for EthCoin { + type Address = Address; + type AddressParseError = CoinAssocTypesError; + type Pubkey = Public; + type PubkeyParseError = CoinAssocTypesError; + type Tx = SignedEthTx; + type TxParseError = CoinAssocTypesError; + type Preimage = SignedEthTx; + type PreimageParseError = CoinAssocTypesError; + type Sig = Signature; + type SigParseError = CoinAssocTypesError; + + fn my_addr(&self) -> &Self::Address { &self.my_address } + + fn parse_address(&self, address: &str) -> Result { + Address::from_str(address).map_err(|e| CoinAssocTypesError::InvalidHexString(e.to_string())) + } + + fn parse_pubkey(&self, pubkey: &[u8]) -> Result { + Ok(Public::from_slice(pubkey)) + } + + fn parse_tx(&self, tx: &[u8]) -> Result { + let unverified: UnverifiedTransaction = rlp::decode(tx).map_err(CoinAssocTypesError::from)?; + SignedEthTx::new(unverified).map_err(|e| CoinAssocTypesError::TxParseError(e.to_string())) + } + + fn parse_preimage(&self, tx: &[u8]) -> Result { self.parse_tx(tx) } + + fn parse_signature(&self, sig: &[u8]) -> Result { + if sig.len() == 65 { + let mut arr = [0; 65]; + arr.copy_from_slice(sig); + Ok(Signature::from(arr)) // Assuming `Signature::from([u8; 65])` exists + } else { + Err(CoinAssocTypesError::ParseSignatureError( + "Signature slice is not 65 bytes long".to_string(), + )) + } + } +} From 56303c66afe49c7775a26fd11092ce182b1b0f72 Mon Sep 17 00:00:00 2001 From: laruh Date: Sun, 10 Mar 2024 14:48:02 +0700 Subject: [PATCH 06/80] impl NftAssocTypes. move nft tests to new nft_swap_proto_v2_tests.rs --- mm2src/coins/eth.rs | 124 ++++++++++++++++- mm2src/coins/lp_coins.rs | 83 ++++++++--- mm2src/coins/nft/nft_structs.rs | 33 +++-- .../tests/docker_tests/eth_docker_tests.rs | 130 +++++++++--------- mm2src/mm2_main/tests/docker_tests/mod.rs | 1 + .../docker_tests/nft_swap_proto_v2_tests.rs | 32 +++++ 6 files changed, 302 insertions(+), 101 deletions(-) create mode 100644 mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 181a75e68f..4bf83a4859 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -24,9 +24,11 @@ use super::eth::Action::{Call, Create}; use crate::eth::eth_rpc::ETH_RPC_REQUEST_TIMEOUT; use crate::eth::web3_transport::websocket_transport::{WebsocketTransport, WebsocketTransportNode}; use crate::lp_price::get_base_price_in_rel; -use crate::nft::nft_structs::{ContractType, ConvertChain, NftInfo, TransactionNftDetails, WithdrawErc1155, +use crate::nft::nft_structs::{Chain, ContractType, ConvertChain, NftInfo, TransactionNftDetails, WithdrawErc1155, WithdrawErc721}; -use crate::{CoinAssocTypes, DexFee, RpcCommonOps, ToBytes, ValidateWatcherSpendInput, WatcherSpendType}; +use crate::{CoinAssocTypes, DexFee, MakerNftSwapOpsV2, NftAssocTypes, RefundMakerPaymentArgs, RpcCommonOps, + SendNftMakerPaymentArgs, SpendMakerPaymentArgs, ToBytes, ValidateMakerPaymentArgs, + ValidateWatcherSpendInput, WatcherSpendType}; use async_trait::async_trait; use bitcrypto::{dhash160, keccak256, ripemd160, sha256}; use common::custom_futures::repeatable::{Ready, Retry, RetryOnError}; @@ -57,7 +59,7 @@ use mm2_err_handle::prelude::*; use mm2_event_stream::behaviour::{EventBehaviour, EventInitStatus}; use mm2_net::transport::{slurp_url, GuiAuthValidation, GuiAuthValidationGenerator, SlurpError}; use mm2_number::bigdecimal_custom::CheckedDivision; -use mm2_number::{BigDecimal, MmNumber}; +use mm2_number::{BigDecimal, BigUint, MmNumber}; use mm2_rpc::data::legacy::GasStationPricePolicy; #[cfg(test)] use mocktopus::macros::*; use rand::seq::SliceRandom; @@ -70,6 +72,7 @@ use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; use std::ops::Deref; #[cfg(not(target_arch = "wasm32"))] use std::path::PathBuf; +use std::str::from_utf8; use std::str::FromStr; use std::sync::atomic::{AtomicU64, Ordering as AtomicOrdering}; use std::sync::{Arc, Mutex}; @@ -121,7 +124,7 @@ use v2_activation::{build_address_and_priv_key_policy, EthActivationV2Error}; mod nonce; use crate::coin_errors::ValidatePaymentResult; -use crate::nft::nft_errors::GetNftInfoError; +use crate::nft::nft_errors::{GetNftInfoError, ParseChainTypeError, ParseContractTypeError}; use crate::{PrivKeyPolicy, TransactionResult, WithdrawFrom}; use nonce::ParityNonce; @@ -6002,7 +6005,7 @@ pub fn checksum_address(addr: &str) -> String { /// `eth_addr_to_hex` converts Address to hex format. /// Note: the result will be in lowercase. -pub(crate) fn eth_addr_to_hex(address: &Address) -> String { format!("{:#02x}", address) } +pub fn eth_addr_to_hex(address: &Address) -> String { format!("{:#02x}", address) } /// Checks that input is valid mixed-case checksum form address /// The input must be 0x prefixed hex string @@ -6201,7 +6204,6 @@ impl ToBytes for Public { pub enum CoinAssocTypesError { InvalidHexString(String), TxParseError(String), - SignatureParseError(String), ParseSignatureError(String), } @@ -6209,6 +6211,21 @@ impl From for CoinAssocTypesError { fn from(e: DecoderError) -> Self { CoinAssocTypesError::TxParseError(e.to_string()) } } +#[derive(Debug, Display)] +pub enum NftAssocTypesError { + Utf8Error(String), + ParseChainError(ParseChainTypeError), + ParseContractError(ParseContractTypeError), +} + +impl From for NftAssocTypesError { + fn from(e: ParseChainTypeError) -> Self { NftAssocTypesError::ParseChainError(e) } +} + +impl From for NftAssocTypesError { + fn from(e: ParseContractTypeError) -> Self { NftAssocTypesError::ParseContractError(e) } +} + impl CoinAssocTypes for EthCoin { type Address = Address; type AddressParseError = CoinAssocTypesError; @@ -6250,3 +6267,98 @@ impl CoinAssocTypes for EthCoin { } } } + +impl ToBytes for Address { + fn to_bytes(&self) -> Vec { self.0.to_vec() } +} + +impl ToBytes for BigUint { + fn to_bytes(&self) -> Vec { self.to_bytes_be() } +} + +impl ToBytes for Chain { + fn to_bytes(&self) -> Vec { self.to_ticker().as_bytes().to_vec() } +} + +impl ToBytes for ContractType { + fn to_bytes(&self) -> Vec { self.to_string().into_bytes() } +} + +impl NftAssocTypes for EthCoin { + type TokenAddress = Address; + type TokenContractAddressParseError = NftAssocTypesError; + type TokenId = BigUint; + type TokenIdParseError = NftAssocTypesError; + type Chain = Chain; + type ChainParseError = NftAssocTypesError; + type Contract = ContractType; + type ContractParseError = NftAssocTypesError; + + fn parse_token_contract_address( + &self, + token_address: &[u8], + ) -> Result { + Ok(Address::from_slice(token_address)) + } + + fn parse_token_id(&self, token_id: &[u8]) -> Result { + Ok(BigUint::from_bytes_be(token_id)) + } + + fn parse_chain(&self, chain: &[u8]) -> Result { + let chain_str = from_utf8(chain).map_err(|e| NftAssocTypesError::Utf8Error(e.to_string()))?; + Chain::from_ticker(chain_str).map_err(NftAssocTypesError::from) + } + + fn parse_contract(&self, contract: &[u8]) -> Result { + let contract_str = from_utf8(contract).map_err(|e| NftAssocTypesError::Utf8Error(e.to_string()))?; + ContractType::from_str(contract_str).map_err(NftAssocTypesError::from) + } +} + +#[async_trait] +impl MakerNftSwapOpsV2 for EthCoin { + async fn send_nft_maker_payment_v2( + &self, + args: SendNftMakerPaymentArgs<'_, Self>, + ) -> Result { + self.send_nft_maker_payment_v2_impl(args).await + } + + async fn validate_nft_maker_payment_v2( + &self, + _args: ValidateMakerPaymentArgs<'_, Self>, + ) -> ValidatePaymentResult<()> { + todo!() + } + + async fn spend_nft_maker_payment_v2( + &self, + _args: SpendMakerPaymentArgs<'_, Self>, + ) -> Result { + todo!() + } + + async fn refund_nft_maker_payment_v2_timelock( + &self, + _args: RefundPaymentArgs<'_>, + ) -> Result { + todo!() + } + + async fn refund_nft_maker_payment_v2_secret( + &self, + _args: RefundMakerPaymentArgs<'_, Self>, + ) -> Result { + todo!() + } +} + +impl EthCoin { + async fn send_nft_maker_payment_v2_impl( + &self, + _args: SendNftMakerPaymentArgs<'_, Self>, + ) -> Result { + todo!() + } +} diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 455bb78c0f..0d80a4c932 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -1487,6 +1487,29 @@ pub trait CoinAssocTypes { fn parse_signature(&self, sig: &[u8]) -> Result; } +/// Defines associated types specific to each coin (Pubkey, Address, etc.) +pub trait NftAssocTypes { + type TokenAddress: Send + Sync + fmt::Display; + type TokenContractAddressParseError: fmt::Debug + Send + fmt::Display; + type TokenId: ToBytes + Send + Sync; + type TokenIdParseError: fmt::Debug + Send + fmt::Display; + type Chain: ToBytes + Send + Sync; + type ChainParseError: fmt::Debug + Send + fmt::Display; + type Contract: ToBytes + Send + Sync; + type ContractParseError: fmt::Debug + Send + fmt::Display; + + fn parse_token_contract_address( + &self, + token_address: &[u8], + ) -> Result; + + fn parse_token_id(&self, token_id: &[u8]) -> Result; + + fn parse_chain(&self, chain: &[u8]) -> Result; + + fn parse_contract(&self, contract: &[u8]) -> Result; +} + pub struct SendMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { /// Maker will be able to refund the payment after this timestamp pub time_lock: u64, @@ -1502,6 +1525,31 @@ pub struct SendMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { pub swap_unique_data: &'a [u8], } +pub struct SendNftMakerPaymentArgs<'a, Coin: CoinAssocTypes + NftAssocTypes + ?Sized> { + /// Maker will be able to refund the payment after this timestamp + pub time_lock: u64, + /// The hash of the secret generated by taker, this is used for immediate refund + pub taker_secret_hash: &'a [u8], + /// The hash of the secret generated by maker, taker needs it to spend the payment + pub maker_secret_hash: &'a [u8], + /// Payment amount + pub amount: BigDecimal, + /// Taker's HTLC pubkey + pub taker_pub: &'a Coin::Pubkey, + /// Unique data of specific swap + pub swap_unique_data: &'a [u8], + /// The address of the NFT token + pub token_address: &'a [u8], + /// The ID of the NFT token. + pub token_id: &'a [u8], + /// The blockchain where the NFT exists + pub chain: &'a [u8], + /// The type of smart contract that governs this NFT + pub contract_type: &'a [u8], + // Etomic swap contract address + pub swap_contract_address: &'a [u8], +} + pub struct ValidateMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { /// Maker payment tx pub maker_payment_tx: &'a Coin::Tx, @@ -1576,39 +1624,32 @@ pub trait MakerCoinSwapOpsV2: CoinAssocTypes + Send + Sync + 'static { } #[async_trait] -pub trait MakerNftSwapOpsV2: CoinAssocTypes + Send + Sync + 'static { - /// Spend ERC721 maker payment transaction - async fn spend_erc721_maker_payment_v2( +pub trait MakerNftSwapOpsV2: CoinAssocTypes + NftAssocTypes + Send + Sync + 'static { + async fn send_nft_maker_payment_v2( &self, - args: SpendMakerPaymentArgs<'_, Self>, + args: SendNftMakerPaymentArgs<'_, Self>, ) -> Result; - /// Spend ERC1155 maker payment transaction - async fn spend_erc1155_maker_payment_v2( + /// Validate NFT maker payment transaction + async fn validate_nft_maker_payment_v2( &self, - args: SpendMakerPaymentArgs<'_, Self>, - ) -> Result; + args: ValidateMakerPaymentArgs<'_, Self>, + ) -> ValidatePaymentResult<()>; - /// Refund ERC721 maker payment transaction using timelock path - async fn refund_erc721_maker_payment_v2_timelock( + /// Spend NFT maker payment transaction + async fn spend_nft_maker_payment_v2( &self, - args: RefundPaymentArgs<'_>, + args: SpendMakerPaymentArgs<'_, Self>, ) -> Result; - /// Refund ERC1155 maker payment transaction using timelock path - async fn refund_erc1155_maker_payment_v2_timelock( + /// Refund NFT maker payment transaction using timelock path + async fn refund_nft_maker_payment_v2_timelock( &self, args: RefundPaymentArgs<'_>, ) -> Result; - /// Refund ERC721 maker payment transaction using immediate refund path - async fn refund_erc721_maker_payment_v2_secret( - &self, - args: RefundMakerPaymentArgs<'_, Self>, - ) -> Result; - - /// Refund ERC1155 maker payment transaction using immediate refund path - async fn refund_erc1155_maker_payment_v2_secret( + /// Refund NFT maker payment transaction using immediate refund path + async fn refund_nft_maker_payment_v2_secret( &self, args: RefundMakerPaymentArgs<'_, Self>, ) -> Result; diff --git a/mm2src/coins/nft/nft_structs.rs b/mm2src/coins/nft/nft_structs.rs index baf6c0c65d..9755bd7367 100644 --- a/mm2src/coins/nft/nft_structs.rs +++ b/mm2src/coins/nft/nft_structs.rs @@ -114,9 +114,9 @@ pub enum Chain { pub trait ConvertChain { fn to_ticker(&self) -> &'static str; - fn from_ticker(s: &str) -> MmResult; + fn from_ticker(s: &str) -> Result; fn to_nft_ticker(&self) -> &'static str; - fn from_nft_ticker(s: &str) -> MmResult; + fn from_nft_ticker(s: &str) -> Result; } impl ConvertChain for Chain { @@ -133,14 +133,14 @@ impl ConvertChain for Chain { /// Converts a coin ticker string to a `Chain` enum. #[inline(always)] - fn from_ticker(s: &str) -> MmResult { + fn from_ticker(s: &str) -> Result { match s { "AVAX" | "avax" => Ok(Chain::Avalanche), "BNB" | "bnb" => Ok(Chain::Bsc), "ETH" | "eth" => Ok(Chain::Eth), "FTM" | "ftm" => Ok(Chain::Fantom), "MATIC" | "matic" => Ok(Chain::Polygon), - _ => MmError::err(ParseChainTypeError::UnsupportedChainType), + _ => Err(ParseChainTypeError::UnsupportedChainType), } } @@ -157,14 +157,14 @@ impl ConvertChain for Chain { /// Converts a NFT ticker string to a `Chain` enum. #[inline(always)] - fn from_nft_ticker(s: &str) -> MmResult { + fn from_nft_ticker(s: &str) -> Result { match s.to_uppercase().as_str() { "NFT_AVAX" => Ok(Chain::Avalanche), "NFT_BNB" => Ok(Chain::Bsc), "NFT_ETH" => Ok(Chain::Eth), "NFT_FTM" => Ok(Chain::Fantom), "NFT_MATIC" => Ok(Chain::Polygon), - _ => MmError::err(ParseChainTypeError::UnsupportedChainType), + _ => Err(ParseChainTypeError::UnsupportedChainType), } } } @@ -817,15 +817,28 @@ pub struct ClearNftDbReq { #[derive(Clone, Debug, Serialize)] pub struct NftInfo { /// The address of the NFT token. - pub(crate) token_address: Address, + pub token_address: Address, /// The ID of the NFT token. #[serde(serialize_with = "serialize_token_id")] + pub token_id: BigUint, + /// The blockchain where the NFT exists. + pub chain: Chain, + /// The type of smart contract that governs this NFT. + pub contract_type: ContractType, + /// The quantity of this type of NFT owned. Particularly relevant for ERC-1155 tokens, + /// where a single token ID can represent multiple assets. + pub amount: BigDecimal, +} + +/// Represents the Swap information about a Non-Fungible Token (NFT). +#[derive(Clone, Debug, Serialize)] +pub struct NftSwapInfo { + /// The address of the NFT token. + pub(crate) token_address: Address, + /// The ID of the NFT token. pub(crate) token_id: BigUint, /// The blockchain where the NFT exists. pub(crate) chain: Chain, /// The type of smart contract that governs this NFT. pub(crate) contract_type: ContractType, - /// The quantity of this type of NFT owned. Particularly relevant for ERC-1155 tokens, - /// where a single token ID can represent multiple assets. - pub(crate) amount: BigDecimal, } diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index c388545a95..20d21511d6 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -3,12 +3,14 @@ use crate::docker_tests::docker_tests_common::{random_secp256k1_secret, ERC1155_ GETH_ERC721_CONTRACT, GETH_NFT_SWAP_CONTRACT, GETH_NONCE_LOCK, GETH_SWAP_CONTRACT, GETH_WATCHERS_SWAP_CONTRACT, GETH_WEB3, MM_CTX}; use bitcrypto::dhash160; -use coins::eth::{checksum_address, eth_coin_from_conf_and_request, EthCoin, ERC20_ABI}; +use coins::eth::{checksum_address, eth_addr_to_hex, eth_coin_from_conf_and_request, EthCoin, ERC20_ABI}; +use coins::nft::nft_structs::{Chain, ContractType, NftInfo}; use coins::{CoinProtocol, ConfirmPaymentInput, FoundSwapTxSpend, MarketCoinOps, PrivKeyBuildPolicy, RefundPaymentArgs, SearchForSwapTxSpendInput, SendPaymentArgs, SpendPaymentArgs, SwapOps, SwapTxTypeWithSecretHash}; use common::{block_on, now_sec}; use ethereum_types::U256; use futures01::Future; +use mm2_number::{BigDecimal, BigUint}; use mm2_test_helpers::for_tests::{erc20_dev_conf, eth_dev_conf, nft_dev_conf}; use std::thread; use std::time::Duration; @@ -102,6 +104,67 @@ fn fill_erc20(to_addr: Address, amount: U256) { wait_for_confirmation(tx_hash); } +fn fill_erc721(to_addr: Address, token_id: U256) { + let _guard = GETH_NONCE_LOCK.lock().unwrap(); + let erc721_contract = Contract::from_json(GETH_WEB3.eth(), erc721_contract(), ERC721_TEST_ABI.as_bytes()).unwrap(); + + let tx_hash = block_on(erc721_contract.call( + "mint", + (Token::Address(to_addr), Token::Uint(token_id)), + geth_account(), + Options::default(), + )) + .unwrap(); + wait_for_confirmation(tx_hash); +} + +fn fill_erc1155(to_addr: Address, token_id: U256, amount: U256) { + let _guard = GETH_NONCE_LOCK.lock().unwrap(); + let erc1155_contract = + Contract::from_json(GETH_WEB3.eth(), erc1155_contract(), ERC1155_TEST_ABI.as_bytes()).unwrap(); + + let tx_hash = block_on(erc1155_contract.call( + "mint", + ( + Token::Address(to_addr), + Token::Uint(token_id), + Token::Uint(amount), + Token::Bytes("".into()), + ), + geth_account(), + Options::default(), + )) + .unwrap(); + wait_for_confirmation(tx_hash); +} + +async fn fill_nfts_info(eth_coin: &EthCoin) { + let nft_infos_lock = eth_coin.nfts_infos.clone(); + let mut nft_infos = nft_infos_lock.lock().await; + + let erc721_nft_info = NftInfo { + token_address: erc721_contract(), + token_id: BigUint::from(1u32), // Assuming a tokenId of 1 for simplicity + chain: Chain::Eth, + contract_type: ContractType::Erc721, + amount: BigDecimal::from(1), + }; + let erc721_address_str = eth_addr_to_hex(&erc721_contract()); + let erc721_key = format!("{},{}", erc721_address_str, 1); + nft_infos.insert(erc721_key, erc721_nft_info); + + let erc1155_nft_info = NftInfo { + token_address: erc1155_contract(), + token_id: BigUint::from(1u32), + chain: Chain::Eth, + contract_type: ContractType::Erc1155, + amount: BigDecimal::from(3), + }; + let erc1155_address_str = eth_addr_to_hex(&erc1155_contract()); + let erc1155_key = format!("{},{}", erc1155_address_str, 1); + nft_infos.insert(erc1155_key, erc1155_nft_info); +} + /// Creates ETH protocol coin supplied with 100 ETH pub fn eth_coin_with_random_privkey(swap_contract: Address) -> EthCoin { let eth_conf = eth_dev_conf(); @@ -160,42 +223,8 @@ pub fn erc20_coin_with_random_privkey(swap_contract: Address) -> EthCoin { erc20_coin } -fn fill_erc721(to_addr: Address, token_id: U256) { - let _guard = GETH_NONCE_LOCK.lock().unwrap(); - let erc721_contract = Contract::from_json(GETH_WEB3.eth(), erc721_contract(), ERC721_TEST_ABI.as_bytes()).unwrap(); - - let tx_hash = block_on(erc721_contract.call( - "mint", - (Token::Address(to_addr), Token::Uint(token_id)), - geth_account(), - Options::default(), - )) - .unwrap(); - wait_for_confirmation(tx_hash); -} - -fn fill_erc1155(to_addr: Address, token_id: U256, amount: U256) { - let _guard = GETH_NONCE_LOCK.lock().unwrap(); - let erc1155_contract = - Contract::from_json(GETH_WEB3.eth(), erc1155_contract(), ERC1155_TEST_ABI.as_bytes()).unwrap(); - - let tx_hash = block_on(erc1155_contract.call( - "mint", - ( - Token::Address(to_addr), - Token::Uint(token_id), - Token::Uint(amount), - Token::Bytes("".into()), - ), - geth_account(), - Options::default(), - )) - .unwrap(); - wait_for_confirmation(tx_hash); -} - /// Creates global NFT supplied with one ERC721 and 3 ERC1155 tokens owned by user in nfts_infos field -pub fn global_nft_with_random_privkey(swap_contract: Address) -> EthCoin { +pub async fn global_nft_with_random_privkey(swap_contract: Address) -> EthCoin { let nft_conf = nft_dev_conf(); let req = json!({ "method": "enable", @@ -218,8 +247,7 @@ pub fn global_nft_with_random_privkey(swap_contract: Address) -> EthCoin { fill_erc721(global_nft.my_address, U256::from(1)); fill_erc1155(global_nft.my_address, U256::from(1), U256::from(3)); - - // todo add minted nfts into nfts_infos field in global_nft + fill_nfts_info(&global_nft).await; global_nft } @@ -376,32 +404,6 @@ fn send_and_spend_eth_maker_payment() { assert_eq!(expected, search_tx); } -#[test] -fn send_and_refund_erc2721_maker_payment() { - let _global_nft = global_nft_with_random_privkey(nft_swap_contract()); - - let time_lock = now_sec() - 100; - let other_pubkey = &[ - 0x02, 0xc6, 0x6e, 0x7d, 0x89, 0x66, 0xb5, 0xc5, 0x55, 0xaf, 0x58, 0x05, 0x98, 0x9d, 0xa9, 0xfb, 0xf8, 0xdb, - 0x95, 0xe1, 0x56, 0x31, 0xce, 0x35, 0x8c, 0x3a, 0x17, 0x10, 0xc9, 0x62, 0x67, 0x90, 0x63, - ]; - let secret_hash = &[1; 20]; - - // todo provide new SendMakerNftPaymentArgs type - let _send_payment_args = SendPaymentArgs { - time_lock_duration: 100, - time_lock, - other_pubkey, - secret_hash, - amount: 1.into(), - swap_contract_address: &Some(nft_swap_contract().as_bytes().into()), - swap_unique_data: &[], - payment_instructions: &None, - watcher_reward: None, - wait_for_confirmation_until: now_sec() + 60, - }; -} - #[test] fn send_and_refund_erc20_maker_payment() { let erc20_coin = erc20_coin_with_random_privkey(swap_contract()); diff --git a/mm2src/mm2_main/tests/docker_tests/mod.rs b/mm2src/mm2_main/tests/docker_tests/mod.rs index 848e43c1eb..a401678a81 100644 --- a/mm2src/mm2_main/tests/docker_tests/mod.rs +++ b/mm2src/mm2_main/tests/docker_tests/mod.rs @@ -3,6 +3,7 @@ pub mod docker_tests_common; mod docker_ordermatch_tests; mod docker_tests_inner; mod eth_docker_tests; +mod nft_swap_proto_v2_tests; pub mod qrc20_tests; mod slp_tests; #[cfg(feature = "enable-solana")] mod solana_tests; diff --git a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs new file mode 100644 index 0000000000..5e70512571 --- /dev/null +++ b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs @@ -0,0 +1,32 @@ +use super::eth_docker_tests::{eth_coin_with_random_privkey, global_nft_with_random_privkey, nft_swap_contract}; +use coins::nft::nft_structs::{Chain, ContractType}; +use coins::{SendNftMakerPaymentArgs, SwapOps, ToBytes}; +use common::{block_on, now_sec}; +use mm2_number::BigUint; + +#[test] +fn send_and_spend_erc721_maker_payment() { + // TODO generate pair of utxo & eth coins from same random secret for maker / taker + let _maker_global_nft = block_on(global_nft_with_random_privkey(nft_swap_contract())); + // in prod we will need to enable global NFT for taker or add new field (for nft swap address) in EthCoin, + // as EtomicSwapNft will have its own contract address, due to EIP-170 contract size limitations. + // TODO need to add NFT conf in coin conf and refactor enable nft a bit + let taker_global_nft = eth_coin_with_random_privkey(nft_swap_contract()); + + let time_lock = now_sec() - 100; + let taker_pubkey = taker_global_nft.derive_htlc_pubkey(&[]); + + let _send_payment_args = SendNftMakerPaymentArgs { + time_lock, + taker_secret_hash: &[], + maker_secret_hash: &[], + amount: 1.into(), + taker_pub: &taker_pubkey, + swap_unique_data: &[], + token_address: &[], + token_id: &BigUint::from(1u32).to_bytes(), + chain: &Chain::Eth.to_bytes(), + contract_type: &ContractType::Erc721.to_bytes(), + swap_contract_address: &Some(nft_swap_contract().as_bytes().into()), + }; +} From c9ee4de2c785e34ee99d1e937c29a3a2e6842b60 Mon Sep 17 00:00:00 2001 From: laruh Date: Sun, 10 Mar 2024 15:02:21 +0700 Subject: [PATCH 07/80] use parse_pubkey --- .../tests/docker_tests/nft_swap_proto_v2_tests.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs index 5e70512571..04ccec6e05 100644 --- a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs @@ -1,6 +1,7 @@ use super::eth_docker_tests::{eth_coin_with_random_privkey, global_nft_with_random_privkey, nft_swap_contract}; +use coins::eth::EthCoin; use coins::nft::nft_structs::{Chain, ContractType}; -use coins::{SendNftMakerPaymentArgs, SwapOps, ToBytes}; +use coins::{CoinAssocTypes, SendNftMakerPaymentArgs, SwapOps, ToBytes}; use common::{block_on, now_sec}; use mm2_number::BigUint; @@ -11,22 +12,22 @@ fn send_and_spend_erc721_maker_payment() { // in prod we will need to enable global NFT for taker or add new field (for nft swap address) in EthCoin, // as EtomicSwapNft will have its own contract address, due to EIP-170 contract size limitations. // TODO need to add NFT conf in coin conf and refactor enable nft a bit - let taker_global_nft = eth_coin_with_random_privkey(nft_swap_contract()); + let taker_eth_coin = eth_coin_with_random_privkey(nft_swap_contract()); let time_lock = now_sec() - 100; - let taker_pubkey = taker_global_nft.derive_htlc_pubkey(&[]); + let taker_pubkey = taker_eth_coin.derive_htlc_pubkey(&[]); - let _send_payment_args = SendNftMakerPaymentArgs { + let _send_payment_args: SendNftMakerPaymentArgs = SendNftMakerPaymentArgs { time_lock, taker_secret_hash: &[], maker_secret_hash: &[], amount: 1.into(), - taker_pub: &taker_pubkey, + taker_pub: &taker_eth_coin.parse_pubkey(&taker_pubkey).unwrap(), swap_unique_data: &[], token_address: &[], token_id: &BigUint::from(1u32).to_bytes(), chain: &Chain::Eth.to_bytes(), contract_type: &ContractType::Erc721.to_bytes(), - swap_contract_address: &Some(nft_swap_contract().as_bytes().into()), + swap_contract_address: nft_swap_contract().as_bytes(), }; } From 35b6dbc245155e5be3d47d133859816d9ea1f109 Mon Sep 17 00:00:00 2001 From: laruh Date: Sun, 10 Mar 2024 20:41:55 +0700 Subject: [PATCH 08/80] remove await and use block_on --- mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs | 4 ++-- mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index 20d21511d6..86f8818ad1 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -224,7 +224,7 @@ pub fn erc20_coin_with_random_privkey(swap_contract: Address) -> EthCoin { } /// Creates global NFT supplied with one ERC721 and 3 ERC1155 tokens owned by user in nfts_infos field -pub async fn global_nft_with_random_privkey(swap_contract: Address) -> EthCoin { +pub fn global_nft_with_random_privkey(swap_contract: Address) -> EthCoin { let nft_conf = nft_dev_conf(); let req = json!({ "method": "enable", @@ -247,7 +247,7 @@ pub async fn global_nft_with_random_privkey(swap_contract: Address) -> EthCoin { fill_erc721(global_nft.my_address, U256::from(1)); fill_erc1155(global_nft.my_address, U256::from(1), U256::from(3)); - fill_nfts_info(&global_nft).await; + block_on(fill_nfts_info(&global_nft)); global_nft } diff --git a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs index 04ccec6e05..091daaa4c3 100644 --- a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs @@ -2,13 +2,13 @@ use super::eth_docker_tests::{eth_coin_with_random_privkey, global_nft_with_rand use coins::eth::EthCoin; use coins::nft::nft_structs::{Chain, ContractType}; use coins::{CoinAssocTypes, SendNftMakerPaymentArgs, SwapOps, ToBytes}; -use common::{block_on, now_sec}; +use common::now_sec; use mm2_number::BigUint; #[test] fn send_and_spend_erc721_maker_payment() { // TODO generate pair of utxo & eth coins from same random secret for maker / taker - let _maker_global_nft = block_on(global_nft_with_random_privkey(nft_swap_contract())); + let _maker_global_nft = global_nft_with_random_privkey(nft_swap_contract()); // in prod we will need to enable global NFT for taker or add new field (for nft swap address) in EthCoin, // as EtomicSwapNft will have its own contract address, due to EIP-170 contract size limitations. // TODO need to add NFT conf in coin conf and refactor enable nft a bit From 816b295c79ae0ed54249ccde3af5cbfb218cc87a Mon Sep 17 00:00:00 2001 From: laruh Date: Sun, 10 Mar 2024 22:00:19 +0700 Subject: [PATCH 09/80] use Public from keys crate as we call derive_htlc_pubkey func --- mm2src/coins/eth.rs | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 4bf83a4859..9b991e08a9 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -54,6 +54,7 @@ use futures::future::{join_all, select_ok, try_join_all, Either, FutureExt, TryF use futures01::Future; use http::{StatusCode, Uri}; use instant::Instant; +use keys::Public as HtlcPubKey; use mm2_core::mm_ctx::{MmArc, MmWeak}; use mm2_err_handle::prelude::*; use mm2_event_stream::behaviour::{EventBehaviour, EventInitStatus}; @@ -6196,21 +6197,22 @@ impl ToBytes for SignedEthTx { } } -impl ToBytes for Public { - fn to_bytes(&self) -> Vec { self.0.to_vec() } -} - #[derive(Debug, Display)] pub enum CoinAssocTypesError { InvalidHexString(String), TxParseError(String), ParseSignatureError(String), + KeysError(keys::Error), } impl From for CoinAssocTypesError { fn from(e: DecoderError) -> Self { CoinAssocTypesError::TxParseError(e.to_string()) } } +impl From for CoinAssocTypesError { + fn from(e: keys::Error) -> Self { CoinAssocTypesError::KeysError(e) } +} + #[derive(Debug, Display)] pub enum NftAssocTypesError { Utf8Error(String), @@ -6228,29 +6230,29 @@ impl From for NftAssocTypesError { impl CoinAssocTypes for EthCoin { type Address = Address; - type AddressParseError = CoinAssocTypesError; - type Pubkey = Public; - type PubkeyParseError = CoinAssocTypesError; + type AddressParseError = MmError; + type Pubkey = HtlcPubKey; + type PubkeyParseError = MmError; type Tx = SignedEthTx; - type TxParseError = CoinAssocTypesError; + type TxParseError = MmError; type Preimage = SignedEthTx; - type PreimageParseError = CoinAssocTypesError; + type PreimageParseError = MmError; type Sig = Signature; - type SigParseError = CoinAssocTypesError; + type SigParseError = MmError; fn my_addr(&self) -> &Self::Address { &self.my_address } fn parse_address(&self, address: &str) -> Result { - Address::from_str(address).map_err(|e| CoinAssocTypesError::InvalidHexString(e.to_string())) + Address::from_str(address).map_to_mm(|e| CoinAssocTypesError::InvalidHexString(e.to_string())) } fn parse_pubkey(&self, pubkey: &[u8]) -> Result { - Ok(Public::from_slice(pubkey)) + HtlcPubKey::from_slice(pubkey).map_to_mm(CoinAssocTypesError::from) } fn parse_tx(&self, tx: &[u8]) -> Result { let unverified: UnverifiedTransaction = rlp::decode(tx).map_err(CoinAssocTypesError::from)?; - SignedEthTx::new(unverified).map_err(|e| CoinAssocTypesError::TxParseError(e.to_string())) + SignedEthTx::new(unverified).map_to_mm(|e| CoinAssocTypesError::TxParseError(e.to_string())) } fn parse_preimage(&self, tx: &[u8]) -> Result { self.parse_tx(tx) } @@ -6261,7 +6263,7 @@ impl CoinAssocTypes for EthCoin { arr.copy_from_slice(sig); Ok(Signature::from(arr)) // Assuming `Signature::from([u8; 65])` exists } else { - Err(CoinAssocTypesError::ParseSignatureError( + MmError::err(CoinAssocTypesError::ParseSignatureError( "Signature slice is not 65 bytes long".to_string(), )) } From 10943d3bdc5e71371e9d0935b15368c5bcadf9c2 Mon Sep 17 00:00:00 2001 From: laruh Date: Mon, 11 Mar 2024 14:44:01 +0700 Subject: [PATCH 10/80] call try_to_address in parse_token_contract_address, recompile ERC1155_TEST_TOKEN_BYTES from formatted code --- mm2src/coins/eth.rs | 21 ++++++++++++------- mm2src/coins/lp_coins.rs | 19 +++++++++++------ mm2src/coins/utxo/slp.rs | 5 +++-- .../tests/docker_tests/docker_tests_common.rs | 6 +++--- 4 files changed, 32 insertions(+), 19 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 9b991e08a9..0bf81da4d2 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -6217,7 +6217,8 @@ impl From for CoinAssocTypesError { pub enum NftAssocTypesError { Utf8Error(String), ParseChainError(ParseChainTypeError), - ParseContractError(ParseContractTypeError), + ParseContractTypeError(ParseContractTypeError), + ParseTokenContractError(String), } impl From for NftAssocTypesError { @@ -6225,7 +6226,7 @@ impl From for NftAssocTypesError { } impl From for NftAssocTypesError { - fn from(e: ParseContractTypeError) -> Self { NftAssocTypesError::ParseContractError(e) } + fn from(e: ParseContractTypeError) -> Self { NftAssocTypesError::ParseContractTypeError(e) } } impl CoinAssocTypes for EthCoin { @@ -6287,8 +6288,8 @@ impl ToBytes for ContractType { } impl NftAssocTypes for EthCoin { - type TokenAddress = Address; - type TokenContractAddressParseError = NftAssocTypesError; + type TokenContractAddr = Address; + type TokenContractAddrParseError = NftAssocTypesError; type TokenId = BigUint; type TokenIdParseError = NftAssocTypesError; type Chain = Chain; @@ -6298,9 +6299,11 @@ impl NftAssocTypes for EthCoin { fn parse_token_contract_address( &self, - token_address: &[u8], - ) -> Result { - Ok(Address::from_slice(token_address)) + token_contract_addr: &[u8], + ) -> Result { + token_contract_addr + .try_to_address() + .map_err(NftAssocTypesError::ParseTokenContractError) } fn parse_token_id(&self, token_id: &[u8]) -> Result { @@ -6359,8 +6362,10 @@ impl MakerNftSwapOpsV2 for EthCoin { impl EthCoin { async fn send_nft_maker_payment_v2_impl( &self, - _args: SendNftMakerPaymentArgs<'_, Self>, + args: SendNftMakerPaymentArgs<'_, Self>, ) -> Result { + let _taker_address = addr_from_raw_pubkey(args.taker_pub).map_err(TransactionErr::Plain)?; + let _swap_contract_address = self.parse_token_contract_address(args.swap_contract_address)?; todo!() } } diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 0d80a4c932..e82d119379 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -294,6 +294,7 @@ use script::Script; pub mod z_coin; use crate::coin_errors::ValidatePaymentResult; +use crate::eth::NftAssocTypesError; use crate::utxo::swap_proto_v2_scripts; use crate::utxo::utxo_common::{payment_script, WaitForOutputSpendErr}; use z_coin::{ZCoin, ZcoinProtocolInfo}; @@ -641,6 +642,7 @@ pub enum TransactionErr { /// Simply for plain error messages. Plain(String), NftProtocolNotSupported(String), + NftAssocTypesError(String), } impl TransactionErr { @@ -658,8 +660,9 @@ impl TransactionErr { pub fn get_plain_text_format(&self) -> String { match self { TransactionErr::TxRecoverable(_, err) => err.to_string(), - TransactionErr::Plain(err) => err.to_string(), - TransactionErr::NftProtocolNotSupported(err) => err.to_string(), + TransactionErr::Plain(err) + | TransactionErr::NftProtocolNotSupported(err) + | TransactionErr::NftAssocTypesError(err) => err.to_string(), } } } @@ -668,6 +671,10 @@ impl From for TransactionErr { fn from(e: keys::Error) -> Self { TransactionErr::Plain(e.to_string()) } } +impl From for TransactionErr { + fn from(e: NftAssocTypesError) -> Self { TransactionErr::NftAssocTypesError(e.to_string()) } +} + #[derive(Debug, PartialEq)] pub enum FoundSwapTxSpend { Spent(TransactionEnum), @@ -1489,8 +1496,8 @@ pub trait CoinAssocTypes { /// Defines associated types specific to each coin (Pubkey, Address, etc.) pub trait NftAssocTypes { - type TokenAddress: Send + Sync + fmt::Display; - type TokenContractAddressParseError: fmt::Debug + Send + fmt::Display; + type TokenContractAddr: Send + Sync + fmt::Display; + type TokenContractAddrParseError: fmt::Debug + Send + fmt::Display; type TokenId: ToBytes + Send + Sync; type TokenIdParseError: fmt::Debug + Send + fmt::Display; type Chain: ToBytes + Send + Sync; @@ -1500,8 +1507,8 @@ pub trait NftAssocTypes { fn parse_token_contract_address( &self, - token_address: &[u8], - ) -> Result; + token_contract_addr: &[u8], + ) -> Result; fn parse_token_id(&self, token_id: &[u8]) -> Result; diff --git a/mm2src/coins/utxo/slp.rs b/mm2src/coins/utxo/slp.rs index 2b5087e0e0..fc080ed74a 100644 --- a/mm2src/coins/utxo/slp.rs +++ b/mm2src/coins/utxo/slp.rs @@ -2171,8 +2171,9 @@ mod slp_tests { let err = match tx_err.clone() { TransactionErr::TxRecoverable(_tx, err) => err, - TransactionErr::Plain(err) => err, - TransactionErr::NftProtocolNotSupported(err) => err, + TransactionErr::Plain(err) + | TransactionErr::NftProtocolNotSupported(err) + | TransactionErr::NftAssocTypesError(err) => err, }; println!("{:?}", err); diff --git a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs index f72d5f39e8..b324ee157e 100644 --- a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs +++ b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs @@ -96,7 +96,9 @@ pub const GETH_DOCKER_IMAGE_WITH_TAG: &str = "docker.io/ethereum/client-go:stabl pub const QTUM_ADDRESS_LABEL: &str = "MM2_ADDRESS_LABEL"; +/// ERC721_TEST_TOKEN has additional mint function pub const ERC721_TEST_ABI: &str = include_str!("../../../mm2_test_helpers/dummy_files/erc721_test_abi.json"); +/// ERC1155_TEST_TOKEN has additional mint function pub const ERC1155_TEST_ABI: &str = include_str!("../../../mm2_test_helpers/dummy_files/erc1155_test_abi.json"); /// Ticker of MYCOIN dockerized blockchain. @@ -107,10 +109,8 @@ pub const MYCOIN1: &str = "MYCOIN1"; pub const ERC20_TOKEN_BYTES: &str = "6080604052600860ff16600a0a633b9aca000260005534801561002157600080fd5b50600054600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610c69806100776000396000f3006080604052600436106100a4576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100a9578063095ea7b31461013957806318160ddd1461019e57806323b872dd146101c9578063313ce5671461024e5780635a3b7e421461027f57806370a082311461030f57806395d89b4114610366578063a9059cbb146103f6578063dd62ed3e1461045b575b600080fd5b3480156100b557600080fd5b506100be6104d2565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100fe5780820151818401526020810190506100e3565b50505050905090810190601f16801561012b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561014557600080fd5b50610184600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061050b565b604051808215151515815260200191505060405180910390f35b3480156101aa57600080fd5b506101b36106bb565b6040518082815260200191505060405180910390f35b3480156101d557600080fd5b50610234600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506106c1565b604051808215151515815260200191505060405180910390f35b34801561025a57600080fd5b506102636109a1565b604051808260ff1660ff16815260200191505060405180910390f35b34801561028b57600080fd5b506102946109a6565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156102d45780820151818401526020810190506102b9565b50505050905090810190601f1680156103015780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561031b57600080fd5b50610350600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506109df565b6040518082815260200191505060405180910390f35b34801561037257600080fd5b5061037b6109f7565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103bb5780820151818401526020810190506103a0565b50505050905090810190601f1680156103e85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561040257600080fd5b50610441600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610a30565b604051808215151515815260200191505060405180910390f35b34801561046757600080fd5b506104bc600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610be1565b6040518082815260200191505060405180910390f35b6040805190810160405280600881526020017f515243205445535400000000000000000000000000000000000000000000000081525081565b60008260008173ffffffffffffffffffffffffffffffffffffffff161415151561053457600080fd5b60008314806105bf57506000600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054145b15156105ca57600080fd5b82600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925856040518082815260200191505060405180910390a3600191505092915050565b60005481565b60008360008173ffffffffffffffffffffffffffffffffffffffff16141515156106ea57600080fd5b8360008173ffffffffffffffffffffffffffffffffffffffff161415151561071157600080fd5b610797600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205485610c06565b600260008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610860600160008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205485610c06565b600160008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506108ec600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205485610c1f565b600160008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef866040518082815260200191505060405180910390a36001925050509392505050565b600881565b6040805190810160405280600981526020017f546f6b656e20302e31000000000000000000000000000000000000000000000081525081565b60016020528060005260406000206000915090505481565b6040805190810160405280600381526020017f515443000000000000000000000000000000000000000000000000000000000081525081565b60008260008173ffffffffffffffffffffffffffffffffffffffff1614151515610a5957600080fd5b610aa2600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205484610c06565b600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610b2e600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205484610c1f565b600160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a3600191505092915050565b6002602052816000526040600020602052806000526040600020600091509150505481565b6000818310151515610c1457fe5b818303905092915050565b6000808284019050838110151515610c3357fe5b80915050929150505600a165627a7a723058207f2e5248b61b80365ea08a0f6d11ac0b47374c4dfd538de76bc2f19591bbbba40029"; pub const SWAP_CONTRACT_BYTES: &str = "608060405234801561001057600080fd5b50611437806100206000396000f3fe60806040526004361061004a5760003560e01c806302ed292b1461004f5780630716326d146100de578063152cf3af1461017b57806346fc0294146101f65780639b415b2a14610294575b600080fd5b34801561005b57600080fd5b506100dc600480360360a081101561007257600080fd5b81019080803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610339565b005b3480156100ea57600080fd5b506101176004803603602081101561010157600080fd5b8101908080359060200190929190505050610867565b60405180846bffffffffffffffffffffffff19166bffffffffffffffffffffffff191681526020018367ffffffffffffffff1667ffffffffffffffff16815260200182600381111561016557fe5b60ff168152602001935050505060405180910390f35b6101f46004803603608081101561019157600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080356bffffffffffffffffffffffff19169060200190929190803567ffffffffffffffff1690602001909291905050506108bf565b005b34801561020257600080fd5b50610292600480360360a081101561021957600080fd5b81019080803590602001909291908035906020019092919080356bffffffffffffffffffffffff19169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610bd9565b005b610337600480360360c08110156102aa57600080fd5b810190808035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080356bffffffffffffffffffffffff19169060200190929190803567ffffffffffffffff169060200190929190505050610fe2565b005b6001600381111561034657fe5b600080878152602001908152602001600020600001601c9054906101000a900460ff16600381111561037457fe5b1461037e57600080fd5b6000600333836003600288604051602001808281526020019150506040516020818303038152906040526040518082805190602001908083835b602083106103db57805182526020820191506020810190506020830392506103b8565b6001836020036101000a038019825116818451168082178552505050505050905001915050602060405180830381855afa15801561041d573d6000803e3d6000fd5b5050506040513d602081101561043257600080fd5b8101908080519060200190929190505050604051602001808281526020019150506040516020818303038152906040526040518082805190602001908083835b602083106104955780518252602082019150602081019050602083039250610472565b6001836020036101000a038019825116818451168082178552505050505050905001915050602060405180830381855afa1580156104d7573d6000803e3d6000fd5b5050506040515160601b8689604051602001808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b8152601401846bffffffffffffffffffffffff19166bffffffffffffffffffffffff191681526014018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b8152601401828152602001955050505050506040516020818303038152906040526040518082805190602001908083835b602083106105fc57805182526020820191506020810190506020830392506105d9565b6001836020036101000a038019825116818451168082178552505050505050905001915050602060405180830381855afa15801561063e573d6000803e3d6000fd5b5050506040515160601b905060008087815260200190815260200160002060000160009054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461069657600080fd5b6002600080888152602001908152602001600020600001601c6101000a81548160ff021916908360038111156106c857fe5b0217905550600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141561074e573373ffffffffffffffffffffffffffffffffffffffff166108fc869081150290604051600060405180830381858888f19350505050158015610748573d6000803e3d6000fd5b50610820565b60008390508073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33886040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156107da57600080fd5b505af11580156107ee573d6000803e3d6000fd5b505050506040513d602081101561080457600080fd5b810190808051906020019092919050505061081e57600080fd5b505b7f36c177bcb01c6d568244f05261e2946c8c977fa50822f3fa098c470770ee1f3e8685604051808381526020018281526020019250505060405180910390a1505050505050565b60006020528060005260406000206000915090508060000160009054906101000a900460601b908060000160149054906101000a900467ffffffffffffffff169080600001601c9054906101000a900460ff16905083565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141580156108fc5750600034115b801561094057506000600381111561091057fe5b600080868152602001908152602001600020600001601c9054906101000a900460ff16600381111561093e57fe5b145b61094957600080fd5b60006003843385600034604051602001808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b8152601401846bffffffffffffffffffffffff19166bffffffffffffffffffffffff191681526014018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b8152601401828152602001955050505050506040516020818303038152906040526040518082805190602001908083835b60208310610a6c5780518252602082019150602081019050602083039250610a49565b6001836020036101000a038019825116818451168082178552505050505050905001915050602060405180830381855afa158015610aae573d6000803e3d6000fd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018367ffffffffffffffff16815260200160016003811115610af757fe5b81525060008087815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c021790555060208201518160000160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550604082015181600001601c6101000a81548160ff02191690836003811115610b9357fe5b02179055509050507fccc9c05183599bd3135da606eaaf535daffe256e9de33c048014cffcccd4ad57856040518082815260200191505060405180910390a15050505050565b60016003811115610be657fe5b600080878152602001908152602001600020600001601c9054906101000a900460ff166003811115610c1457fe5b14610c1e57600080fd5b600060038233868689604051602001808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b8152601401846bffffffffffffffffffffffff19166bffffffffffffffffffffffff191681526014018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b8152601401828152602001955050505050506040516020818303038152906040526040518082805190602001908083835b60208310610d405780518252602082019150602081019050602083039250610d1d565b6001836020036101000a038019825116818451168082178552505050505050905001915050602060405180830381855afa158015610d82573d6000803e3d6000fd5b5050506040515160601b905060008087815260200190815260200160002060000160009054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916148015610e10575060008087815260200190815260200160002060000160149054906101000a900467ffffffffffffffff1667ffffffffffffffff164210155b610e1957600080fd5b6003600080888152602001908152602001600020600001601c6101000a81548160ff02191690836003811115610e4b57fe5b0217905550600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610ed1573373ffffffffffffffffffffffffffffffffffffffff166108fc869081150290604051600060405180830381858888f19350505050158015610ecb573d6000803e3d6000fd5b50610fa3565b60008390508073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33886040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015610f5d57600080fd5b505af1158015610f71573d6000803e3d6000fd5b505050506040513d6020811015610f8757600080fd5b8101908080519060200190929190505050610fa157600080fd5b505b7f1797d500133f8e427eb9da9523aa4a25cb40f50ebc7dbda3c7c81778973f35ba866040518082815260200191505060405180910390a1505050505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415801561101f5750600085115b801561106357506000600381111561103357fe5b600080888152602001908152602001600020600001601c9054906101000a900460ff16600381111561106157fe5b145b61106c57600080fd5b60006003843385888a604051602001808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014018573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b8152601401846bffffffffffffffffffffffff19166bffffffffffffffffffffffff191681526014018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b8152601401828152602001955050505050506040516020818303038152906040526040518082805190602001908083835b6020831061118e578051825260208201915060208101905060208303925061116b565b6001836020036101000a038019825116818451168082178552505050505050905001915050602060405180830381855afa1580156111d0573d6000803e3d6000fd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018367ffffffffffffffff1681526020016001600381111561121957fe5b81525060008089815260200190815260200160002060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c021790555060208201518160000160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550604082015181600001601c6101000a81548160ff021916908360038111156112b557fe5b021790555090505060008590508073ffffffffffffffffffffffffffffffffffffffff166323b872dd33308a6040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b15801561137d57600080fd5b505af1158015611391573d6000803e3d6000fd5b505050506040513d60208110156113a757600080fd5b81019080805190602001909291905050506113c157600080fd5b7fccc9c05183599bd3135da606eaaf535daffe256e9de33c048014cffcccd4ad57886040518082815260200191505060405180910390a1505050505050505056fea265627a7a723158208c83db436905afce0b7be1012be64818c49323c12d451fe2ab6bce76ff6421c964736f6c63430005110032"; pub const WATCHERS_SWAP_CONTRACT_BYTES: &str = "608060405234801561000f575f80fd5b50612aa48061001d5f395ff3fe608060405260043610610085575f3560e01c806346fc02941161005857806346fc0294146101275780636a3227861461014f5780639b415b2a1461016b578063b5985c4d14610193578063cd1dde34146101bb57610085565b806302ed292b146100895780630716326d146100b15780630971fd54146100ef578063152cf3af1461010b575b5f80fd5b348015610094575f80fd5b506100af60048036038101906100aa9190611e1d565b6101e3565b005b3480156100bc575f80fd5b506100d760048036038101906100d29190611e94565b610518565b6040516100e693929190611f8e565b60405180910390f35b6101096004803603810190610104919061206f565b610568565b005b6101256004803603810190610120919061210c565b610787565b005b348015610132575f80fd5b5061014d60048036038101906101489190612170565b61099d565b005b610169600480360381019061016491906121e7565b610c4d565b005b348015610176575f80fd5b50610191600480360381019061018c91906122ab565b610f61565b005b34801561019e575f80fd5b506101b960048036038101906101b49190612334565b611203565b005b3480156101c6575f80fd5b506101e160048036038101906101dc91906123f8565b611887565b005b600160038111156101f7576101f6611f1b565b5b5f808781526020019081526020015f205f01601c9054906101000a900460ff16600381111561022957610228611f1b565b5b14610232575f80fd5b5f60033383600360028860405160200161024c91906124dc565b6040516020818303038152906040526040516102689190612562565b602060405180830381855afa158015610283573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906102a6919061258c565b6040516020016102b691906124dc565b6040516020818303038152906040526040516102d29190612562565b602060405180830381855afa1580156102ed573d5f803e3d5ffd5b5050506040515160601b868960405160200161030d95949392919061263c565b6040516020818303038152906040526040516103299190612562565b602060405180830381855afa158015610344573d5f803e3d5ffd5b5050506040515160601b90505f808781526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610397575f80fd5b60025f808881526020019081526020015f205f01601c6101000a81548160ff021916908360038111156103cd576103cc611f1b565b5b02179055505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361044e573373ffffffffffffffffffffffffffffffffffffffff166108fc8690811502906040515f60405180830381858888f19350505050158015610448573d5f803e3d5ffd5b506104d7565b5f8390508073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33886040518363ffffffff1660e01b815260040161048d9291906126b8565b6020604051808303815f875af11580156104a9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104cd91906126f3565b6104d5575f80fd5b505b7f36c177bcb01c6d568244f05261e2946c8c977fa50822f3fa098c470770ee1f3e868560405161050892919061272d565b60405180910390a1505050505050565b5f602052805f5260405f205f91509050805f015f9054906101000a900460601b90805f0160149054906101000a900467ffffffffffffffff1690805f01601c9054906101000a900460ff16905083565b5f73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16141580156105a357505f34115b80156105f157505f60038111156105bd576105bc611f1b565b5b5f808981526020019081526020015f205f01601c9054906101000a900460ff1660038111156105ef576105ee611f1b565b5b145b6105f9575f80fd5b5f60038733885f3489898960405160200161061b9897969594939291906127e7565b6040516020818303038152906040526040516106379190612562565b602060405180830381855afa158015610652573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018667ffffffffffffffff168152602001600160038111156106a2576106a1611f1b565b5b8152505f808a81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506040820151815f01601c6101000a81548160ff0219169083600381111561073e5761073d611f1b565b5b02179055509050507fccc9c05183599bd3135da606eaaf535daffe256e9de33c048014cffcccd4ad57886040516107759190612878565b60405180910390a15050505050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141580156107c257505f34115b801561081057505f60038111156107dc576107db611f1b565b5b5f808681526020019081526020015f205f01601c9054906101000a900460ff16600381111561080e5761080d611f1b565b5b145b610818575f80fd5b5f60038433855f3460405160200161083495949392919061263c565b6040516020818303038152906040526040516108509190612562565b602060405180830381855afa15801561086b573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018367ffffffffffffffff168152602001600160038111156108bb576108ba611f1b565b5b8152505f808781526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506040820151815f01601c6101000a81548160ff0219169083600381111561095757610956611f1b565b5b02179055509050507fccc9c05183599bd3135da606eaaf535daffe256e9de33c048014cffcccd4ad578560405161098e9190612878565b60405180910390a15050505050565b600160038111156109b1576109b0611f1b565b5b5f808781526020019081526020015f205f01601c9054906101000a900460ff1660038111156109e3576109e2611f1b565b5b146109ec575f80fd5b5f60038233868689604051602001610a0895949392919061263c565b604051602081830303815290604052604051610a249190612562565b602060405180830381855afa158015610a3f573d5f803e3d5ffd5b5050506040515160601b90505f808781526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916148015610ac657505f808781526020019081526020015f205f0160149054906101000a900467ffffffffffffffff1667ffffffffffffffff164210155b610ace575f80fd5b60035f808881526020019081526020015f205f01601c6101000a81548160ff02191690836003811115610b0457610b03611f1b565b5b02179055505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610b85573373ffffffffffffffffffffffffffffffffffffffff166108fc8690811502906040515f60405180830381858888f19350505050158015610b7f573d5f803e3d5ffd5b50610c0e565b5f8390508073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33886040518363ffffffff1660e01b8152600401610bc49291906126b8565b6020604051808303815f875af1158015610be0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c0491906126f3565b610c0c575f80fd5b505b7f1797d500133f8e427eb9da9523aa4a25cb40f50ebc7dbda3c7c81778973f35ba86604051610c3d9190612878565b60405180910390a1505050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614158015610c8857505f88115b8015610cd657505f6003811115610ca257610ca1611f1b565b5b5f808b81526020019081526020015f205f01601c9054906101000a900460ff166003811115610cd457610cd3611f1b565b5b145b610cde575f80fd5b5f6003811115610cf157610cf0611f1b565b5b836003811115610d0457610d03611f1b565b5b14158015610d365750600380811115610d2057610d1f611f1b565b5b836003811115610d3357610d32611f1b565b5b14155b15610d4757803414610d46575f80fd5b5b5f60038733888b8d898989604051602001610d699897969594939291906127e7565b604051602081830303815290604052604051610d859190612562565b602060405180830381855afa158015610da0573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018667ffffffffffffffff16815260200160016003811115610df057610def611f1b565b5b8152505f808c81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506040820151815f01601c6101000a81548160ff02191690836003811115610e8c57610e8b611f1b565b5b02179055509050505f8890508073ffffffffffffffffffffffffffffffffffffffff166323b872dd33308d6040518463ffffffff1660e01b8152600401610ed593929190612891565b6020604051808303815f875af1158015610ef1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f1591906126f3565b610f1d575f80fd5b7fccc9c05183599bd3135da606eaaf535daffe256e9de33c048014cffcccd4ad578b604051610f4c9190612878565b60405180910390a15050505050505050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614158015610f9c57505f85115b8015610fea57505f6003811115610fb657610fb5611f1b565b5b5f808881526020019081526020015f205f01601c9054906101000a900460ff166003811115610fe857610fe7611f1b565b5b145b610ff2575f80fd5b5f6003843385888a60405160200161100e95949392919061263c565b60405160208183030381529060405260405161102a9190612562565b602060405180830381855afa158015611045573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018367ffffffffffffffff1681526020016001600381111561109557611094611f1b565b5b8152505f808981526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506040820151815f01601c6101000a81548160ff0219169083600381111561113157611130611f1b565b5b02179055509050505f8590508073ffffffffffffffffffffffffffffffffffffffff166323b872dd33308a6040518463ffffffff1660e01b815260040161117a93929190612891565b6020604051808303815f875af1158015611196573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111ba91906126f3565b6111c2575f80fd5b7fccc9c05183599bd3135da606eaaf535daffe256e9de33c048014cffcccd4ad57886040516111f19190612878565b60405180910390a15050505050505050565b6001600381111561121757611216611f1b565b5b5f808b81526020019081526020015f205f01601c9054906101000a900460ff16600381111561124957611248611f1b565b5b14611289576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161128090612920565b60405180910390fd5b5f60038587600360028c6040516020016112a391906124dc565b6040516020818303038152906040526040516112bf9190612562565b602060405180830381855afa1580156112da573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906112fd919061258c565b60405160200161130d91906124dc565b6040516020818303038152906040526040516113299190612562565b602060405180830381855afa158015611344573d5f803e3d5ffd5b5050506040515160601b8a8d89898960405160200161136a9897969594939291906127e7565b6040516020818303038152906040526040516113869190612562565b602060405180830381855afa1580156113a1573d5f803e3d5ffd5b5050506040515160601b90505f808b81526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461142b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161142290612988565b60405180910390fd5b60025f808c81526020019081526020015f205f01601c6101000a81548160ff0219169083600381111561146157611460611f1b565b5b02179055505f73ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff160361159e575f8060038111156114ad576114ac611f1b565b5b8560038111156114c0576114bf611f1b565b5b1480156114cb575083155b6114e057828a6114db91906129d3565b6114e2565b895b90508573ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f19350505050158015611527573d5f803e3d5ffd5b5060038081111561153b5761153a611f1b565b5b85600381111561154e5761154d611f1b565b5b03611598573373ffffffffffffffffffffffffffffffffffffffff166108fc8490811502906040515f60405180830381858888f19350505050158015611596573d5f803e3d5ffd5b505b50611786565b5f6003808111156115b2576115b1611f1b565b5b8560038111156115c5576115c4611f1b565b5b146115d057896115dd565b828a6115dc91906129d3565b5b90505f8890508073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb88846040518363ffffffff1660e01b815260040161161e9291906126b8565b6020604051808303815f875af115801561163a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061165e91906126f3565b61169d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161169490612a50565b60405180910390fd5b6003808111156116b0576116af611f1b565b5b8660038111156116c3576116c2611f1b565b5b03611783578073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33866040518363ffffffff1660e01b81526004016117039291906126b8565b6020604051808303815f875af115801561171f573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061174391906126f3565b611782576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161177990612a50565b60405180910390fd5b5b50505b6002600381111561179a57611799611f1b565b5b8460038111156117ad576117ac611f1b565b5b036117f7578573ffffffffffffffffffffffffffffffffffffffff166108fc8390811502906040515f60405180830381858888f193505050501580156117f5573d5f803e3d5ffd5b505b8215611842573373ffffffffffffffffffffffffffffffffffffffff166108fc8390811502906040515f60405180830381858888f19350505050158015611840573d5f803e3d5ffd5b505b7f36c177bcb01c6d568244f05261e2946c8c977fa50822f3fa098c470770ee1f3e8a8960405161187392919061272d565b60405180910390a150505050505050505050565b6001600381111561189b5761189a611f1b565b5b5f808b81526020019081526020015f205f01601c9054906101000a900460ff1660038111156118cd576118cc611f1b565b5b146118d6575f80fd5b5f600385878a8a8d8989896040516020016118f89897969594939291906127e7565b6040516020818303038152906040526040516119149190612562565b602060405180830381855afa15801561192f573d5f803e3d5ffd5b5050506040515160601b90505f808b81526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161480156119b657505f808b81526020019081526020015f205f0160149054906101000a900467ffffffffffffffff1667ffffffffffffffff164210155b6119be575f80fd5b60035f808c81526020019081526020015f205f01601c6101000a81548160ff021916908360038111156119f4576119f3611f1b565b5b02179055505f73ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1603611b27575f806003811115611a4057611a3f611f1b565b5b856003811115611a5357611a52611f1b565b5b14611a6957828a611a6491906129d3565b611a6b565b895b90508673ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f19350505050158015611ab0573d5f803e3d5ffd5b505f6003811115611ac457611ac3611f1b565b5b856003811115611ad757611ad6611f1b565b5b14611b21573373ffffffffffffffffffffffffffffffffffffffff166108fc8490811502906040515f60405180830381858888f19350505050158015611b1f573d5f803e3d5ffd5b505b50611d16565b5f600380811115611b3b57611b3a611f1b565b5b856003811115611b4e57611b4d611f1b565b5b14611b595789611b66565b828a611b6591906129d3565b5b90505f8890508073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb89846040518363ffffffff1660e01b8152600401611ba79291906126b8565b6020604051808303815f875af1158015611bc3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611be791906126f3565b611bef575f80fd5b600380811115611c0257611c01611f1b565b5b866003811115611c1557611c14611f1b565b5b03611ca2578073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33866040518363ffffffff1660e01b8152600401611c559291906126b8565b6020604051808303815f875af1158015611c71573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c9591906126f3565b611c9d575f80fd5b611d13565b5f6003811115611cb557611cb4611f1b565b5b866003811115611cc857611cc7611f1b565b5b14611d12573373ffffffffffffffffffffffffffffffffffffffff166108fc8590811502906040515f60405180830381858888f19350505050158015611d10573d5f803e3d5ffd5b505b5b50505b7f1797d500133f8e427eb9da9523aa4a25cb40f50ebc7dbda3c7c81778973f35ba8a604051611d459190612878565b60405180910390a150505050505050505050565b5f80fd5b5f819050919050565b611d6f81611d5d565b8114611d79575f80fd5b50565b5f81359050611d8a81611d66565b92915050565b5f819050919050565b611da281611d90565b8114611dac575f80fd5b50565b5f81359050611dbd81611d99565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f611dec82611dc3565b9050919050565b611dfc81611de2565b8114611e06575f80fd5b50565b5f81359050611e1781611df3565b92915050565b5f805f805f60a08688031215611e3657611e35611d59565b5b5f611e4388828901611d7c565b9550506020611e5488828901611daf565b9450506040611e6588828901611d7c565b9350506060611e7688828901611e09565b9250506080611e8788828901611e09565b9150509295509295909350565b5f60208284031215611ea957611ea8611d59565b5b5f611eb684828501611d7c565b91505092915050565b5f7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b611ef381611ebf565b82525050565b5f67ffffffffffffffff82169050919050565b611f1581611ef9565b82525050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60048110611f5957611f58611f1b565b5b50565b5f819050611f6982611f48565b919050565b5f611f7882611f5c565b9050919050565b611f8881611f6e565b82525050565b5f606082019050611fa15f830186611eea565b611fae6020830185611f0c565b611fbb6040830184611f7f565b949350505050565b611fcc81611ebf565b8114611fd6575f80fd5b50565b5f81359050611fe781611fc3565b92915050565b611ff681611ef9565b8114612000575f80fd5b50565b5f8135905061201181611fed565b92915050565b60048110612023575f80fd5b50565b5f8135905061203481612017565b92915050565b5f8115159050919050565b61204e8161203a565b8114612058575f80fd5b50565b5f8135905061206981612045565b92915050565b5f805f805f805f60e0888a03121561208a57612089611d59565b5b5f6120978a828b01611d7c565b97505060206120a88a828b01611e09565b96505060406120b98a828b01611fd9565b95505060606120ca8a828b01612003565b94505060806120db8a828b01612026565b93505060a06120ec8a828b0161205b565b92505060c06120fd8a828b01611daf565b91505092959891949750929550565b5f805f806080858703121561212457612123611d59565b5b5f61213187828801611d7c565b945050602061214287828801611e09565b935050604061215387828801611fd9565b925050606061216487828801612003565b91505092959194509250565b5f805f805f60a0868803121561218957612188611d59565b5b5f61219688828901611d7c565b95505060206121a788828901611daf565b94505060406121b888828901611fd9565b93505060606121c988828901611e09565b92505060806121da88828901611e09565b9150509295509295909350565b5f805f805f805f805f6101208a8c03121561220557612204611d59565b5b5f6122128c828d01611d7c565b99505060206122238c828d01611daf565b98505060406122348c828d01611e09565b97505060606122458c828d01611e09565b96505060806122568c828d01611fd9565b95505060a06122678c828d01612003565b94505060c06122788c828d01612026565b93505060e06122898c828d0161205b565b92505061010061229b8c828d01611daf565b9150509295985092959850929598565b5f805f805f8060c087890312156122c5576122c4611d59565b5b5f6122d289828a01611d7c565b96505060206122e389828a01611daf565b95505060406122f489828a01611e09565b945050606061230589828a01611e09565b935050608061231689828a01611fd9565b92505060a061232789828a01612003565b9150509295509295509295565b5f805f805f805f805f6101208a8c03121561235257612351611d59565b5b5f61235f8c828d01611d7c565b99505060206123708c828d01611daf565b98505060406123818c828d01611d7c565b97505060606123928c828d01611e09565b96505060806123a38c828d01611e09565b95505060a06123b48c828d01611e09565b94505060c06123c58c828d01612026565b93505060e06123d68c828d0161205b565b9250506101006123e88c828d01611daf565b9150509295985092959850929598565b5f805f805f805f805f6101208a8c03121561241657612415611d59565b5b5f6124238c828d01611d7c565b99505060206124348c828d01611daf565b98505060406124458c828d01611fd9565b97505060606124568c828d01611e09565b96505060806124678c828d01611e09565b95505060a06124788c828d01611e09565b94505060c06124898c828d01612026565b93505060e061249a8c828d0161205b565b9250506101006124ac8c828d01611daf565b9150509295985092959850929598565b5f819050919050565b6124d66124d182611d5d565b6124bc565b82525050565b5f6124e782846124c5565b60208201915081905092915050565b5f81519050919050565b5f81905092915050565b5f5b8381101561252757808201518184015260208101905061250c565b5f8484015250505050565b5f61253c826124f6565b6125468185612500565b935061255681856020860161250a565b80840191505092915050565b5f61256d8284612532565b915081905092915050565b5f8151905061258681611d66565b92915050565b5f602082840312156125a1576125a0611d59565b5b5f6125ae84828501612578565b91505092915050565b5f8160601b9050919050565b5f6125cd826125b7565b9050919050565b5f6125de826125c3565b9050919050565b6125f66125f182611de2565b6125d4565b82525050565b5f819050919050565b61261661261182611ebf565b6125fc565b82525050565b5f819050919050565b61263661263182611d90565b61261c565b82525050565b5f61264782886125e5565b60148201915061265782876125e5565b6014820191506126678286612605565b60148201915061267782856125e5565b6014820191506126878284612625565b6020820191508190509695505050505050565b6126a381611de2565b82525050565b6126b281611d90565b82525050565b5f6040820190506126cb5f83018561269a565b6126d860208301846126a9565b9392505050565b5f815190506126ed81612045565b92915050565b5f6020828403121561270857612707611d59565b5b5f612715848285016126df565b91505092915050565b61272781611d5d565b82525050565b5f6040820190506127405f83018561271e565b61274d602083018461271e565b9392505050565b6004811061276557612764611f1b565b5b50565b5f81905061277582612754565b919050565b5f61278482612768565b9050919050565b5f8160f81b9050919050565b5f6127a18261278b565b9050919050565b6127b96127b48261277a565b612797565b82525050565b5f6127c982612797565b9050919050565b6127e16127dc8261203a565b6127bf565b82525050565b5f6127f2828b6125e5565b601482019150612802828a6125e5565b6014820191506128128289612605565b60148201915061282282886125e5565b6014820191506128328287612625565b60208201915061284282866127a8565b60018201915061285282856127d0565b6001820191506128628284612625565b6020820191508190509998505050505050505050565b5f60208201905061288b5f83018461271e565b92915050565b5f6060820190506128a45f83018661269a565b6128b1602083018561269a565b6128be60408301846126a9565b949350505050565b5f82825260208201905092915050565b7f5061796d656e7420776173206e6f742073656e740000000000000000000000005f82015250565b5f61290a6014836128c6565b9150612915826128d6565b602082019050919050565b5f6020820190508181035f830152612937816128fe565b9050919050565b7f496e76616c6964207061796d656e7420686173680000000000000000000000005f82015250565b5f6129726014836128c6565b915061297d8261293e565b602082019050919050565b5f6020820190508181035f83015261299f81612966565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6129dd82611d90565b91506129e883611d90565b9250828203905081811115612a00576129ff6129a6565b5b92915050565b7f546f6b656e207472616e73666572206661696c656400000000000000000000005f82015250565b5f612a3a6015836128c6565b9150612a4582612a06565b602082019050919050565b5f6020820190508181035f830152612a6781612a2e565b905091905056fea26469706673582212203106867e1b147b377237cde0aba42d82faf0282b83d7b6d62cca039d0b7f840564736f6c63430008160033"; -/// ERC721_TEST_TOKEN has additional mint function pub const ERC721_TEST_TOKEN_BYTES: &str = "608060405234801562000010575f80fd5b50604051620022ac380380620022ac8339818101604052810190620000369190620001ea565b8181815f9081620000489190620004a4565b5080600190816200005a9190620004a4565b505050505062000588565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b620000c6826200007e565b810181811067ffffffffffffffff82111715620000e857620000e76200008e565b5b80604052505050565b5f620000fc62000065565b90506200010a8282620000bb565b919050565b5f67ffffffffffffffff8211156200012c576200012b6200008e565b5b62000137826200007e565b9050602081019050919050565b5f5b838110156200016357808201518184015260208101905062000146565b5f8484015250505050565b5f620001846200017e846200010f565b620000f1565b905082815260208101848484011115620001a357620001a26200007a565b5b620001b084828562000144565b509392505050565b5f82601f830112620001cf57620001ce62000076565b5b8151620001e18482602086016200016e565b91505092915050565b5f80604083850312156200020357620002026200006e565b5b5f83015167ffffffffffffffff81111562000223576200022262000072565b5b6200023185828601620001b8565b925050602083015167ffffffffffffffff81111562000255576200025462000072565b5b6200026385828601620001b8565b9150509250929050565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680620002bc57607f821691505b602082108103620002d257620002d162000277565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620003367fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620002f9565b620003428683620002f9565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f6200038c6200038662000380846200035a565b62000363565b6200035a565b9050919050565b5f819050919050565b620003a7836200036c565b620003bf620003b68262000393565b84845462000305565b825550505050565b5f90565b620003d5620003c7565b620003e28184846200039c565b505050565b5b818110156200040957620003fd5f82620003cb565b600181019050620003e8565b5050565b601f82111562000458576200042281620002d8565b6200042d84620002ea565b810160208510156200043d578190505b620004556200044c85620002ea565b830182620003e7565b50505b505050565b5f82821c905092915050565b5f6200047a5f19846008026200045d565b1980831691505092915050565b5f62000494838362000469565b9150826002028217905092915050565b620004af826200026d565b67ffffffffffffffff811115620004cb57620004ca6200008e565b5b620004d78254620002a4565b620004e48282856200040d565b5f60209050601f8311600181146200051a575f841562000505578287015190505b62000511858262000487565b86555062000580565b601f1984166200052a86620002d8565b5f5b8281101562000553578489015182556001820191506020850194506020810190506200052c565b868310156200057357848901516200056f601f89168262000469565b8355505b6001600288020188555050505b505050505050565b611d1680620005965f395ff3fe608060405234801561000f575f80fd5b50600436106100e8575f3560e01c80636352211e1161008a578063a22cb46511610064578063a22cb46514610258578063b88d4fde14610274578063c87b56dd14610290578063e985e9c5146102c0576100e8565b80636352211e146101da57806370a082311461020a57806395d89b411461023a576100e8565b8063095ea7b3116100c6578063095ea7b31461016a57806323b872dd1461018657806340c10f19146101a257806342842e0e146101be576100e8565b806301ffc9a7146100ec57806306fdde031461011c578063081812fc1461013a575b5f80fd5b610106600480360381019061010191906115a7565b6102f0565b60405161011391906115ec565b60405180910390f35b6101246103d1565b604051610131919061168f565b60405180910390f35b610154600480360381019061014f91906116e2565b610460565b604051610161919061174c565b60405180910390f35b610184600480360381019061017f919061178f565b61047b565b005b6101a0600480360381019061019b91906117cd565b610491565b005b6101bc60048036038101906101b7919061178f565b610590565b005b6101d860048036038101906101d391906117cd565b61059e565b005b6101f460048036038101906101ef91906116e2565b6105bd565b604051610201919061174c565b60405180910390f35b610224600480360381019061021f919061181d565b6105ce565b6040516102319190611857565b60405180910390f35b610242610684565b60405161024f919061168f565b60405180910390f35b610272600480360381019061026d919061189a565b610714565b005b61028e60048036038101906102899190611a04565b61072a565b005b6102aa60048036038101906102a591906116e2565b610747565b6040516102b7919061168f565b60405180910390f35b6102da60048036038101906102d59190611a84565b6107ad565b6040516102e791906115ec565b60405180910390f35b5f7f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806103ba57507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806103ca57506103c98261083b565b5b9050919050565b60605f80546103df90611aef565b80601f016020809104026020016040519081016040528092919081815260200182805461040b90611aef565b80156104565780601f1061042d57610100808354040283529160200191610456565b820191905f5260205f20905b81548152906001019060200180831161043957829003601f168201915b5050505050905090565b5f61046a826108a4565b506104748261092a565b9050919050565b61048d8282610488610963565b61096a565b5050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610501575f6040517f64a0ae920000000000000000000000000000000000000000000000000000000081526004016104f8919061174c565b60405180910390fd5b5f610514838361050f610963565b61097c565b90508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461058a578382826040517f64283d7b00000000000000000000000000000000000000000000000000000000815260040161058193929190611b1f565b60405180910390fd5b50505050565b61059a8282610b87565b5050565b6105b883838360405180602001604052805f81525061072a565b505050565b5f6105c7826108a4565b9050919050565b5f8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361063f575f6040517f89c62b64000000000000000000000000000000000000000000000000000000008152600401610636919061174c565b60405180910390fd5b60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b60606001805461069390611aef565b80601f01602080910402602001604051908101604052809291908181526020018280546106bf90611aef565b801561070a5780601f106106e15761010080835404028352916020019161070a565b820191905f5260205f20905b8154815290600101906020018083116106ed57829003601f168201915b5050505050905090565b61072661071f610963565b8383610c7a565b5050565b610735848484610491565b61074184848484610de3565b50505050565b6060610752826108a4565b505f61075c610f95565b90505f81511161077a5760405180602001604052805f8152506107a5565b8061078484610fab565b604051602001610795929190611b8e565b6040516020818303038152906040525b915050919050565b5f60055f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16905092915050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f806108af83611075565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361092157826040517f7e2732890000000000000000000000000000000000000000000000000000000081526004016109189190611857565b60405180910390fd5b80915050919050565b5f60045f8381526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b5f33905090565b61097783838360016110ae565b505050565b5f8061098784611075565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146109c8576109c781848661126d565b5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610a5357610a075f855f806110ae565b600160035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825403925050819055505b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614610ad257600160035f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055505b8460025f8681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550838573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4809150509392505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610bf7575f6040517f64a0ae92000000000000000000000000000000000000000000000000000000008152600401610bee919061174c565b60405180910390fd5b5f610c0383835f61097c565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610c75575f6040517f73c6ac6e000000000000000000000000000000000000000000000000000000008152600401610c6c919061174c565b60405180910390fd5b505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610cea57816040517f5b08ba18000000000000000000000000000000000000000000000000000000008152600401610ce1919061174c565b60405180910390fd5b8060055f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051610dd691906115ec565b60405180910390a3505050565b5f8373ffffffffffffffffffffffffffffffffffffffff163b1115610f8f578273ffffffffffffffffffffffffffffffffffffffff1663150b7a02610e26610963565b8685856040518563ffffffff1660e01b8152600401610e489493929190611c03565b6020604051808303815f875af1925050508015610e8357506040513d601f19601f82011682018060405250810190610e809190611c61565b60015b610f04573d805f8114610eb1576040519150601f19603f3d011682016040523d82523d5f602084013e610eb6565b606091505b505f815103610efc57836040517f64a0ae92000000000000000000000000000000000000000000000000000000008152600401610ef3919061174c565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614610f8d57836040517f64a0ae92000000000000000000000000000000000000000000000000000000008152600401610f84919061174c565b60405180910390fd5b505b50505050565b606060405180602001604052805f815250905090565b60605f6001610fb984611330565b0190505f8167ffffffffffffffff811115610fd757610fd66118e0565b5b6040519080825280601f01601f1916602001820160405280156110095781602001600182028036833780820191505090505b5090505f82602001820190505b60011561106a578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a858161105f5761105e611c8c565b5b0494505f8503611016575b819350505050919050565b5f60025f8381526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b80806110e657505f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b15611218575f6110f5846108a4565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415801561115f57508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b8015611172575061117081846107ad565b155b156111b457826040517fa9fbf51f0000000000000000000000000000000000000000000000000000000081526004016111ab919061174c565b60405180910390fd5b811561121657838573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b8360045f8581526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505050565b611278838383611481565b61132b575f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036112ec57806040517f7e2732890000000000000000000000000000000000000000000000000000000081526004016112e39190611857565b60405180910390fd5b81816040517f177e802f000000000000000000000000000000000000000000000000000000008152600401611322929190611cb9565b60405180910390fd5b505050565b5f805f90507a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000831061138c577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000838161138257611381611c8c565b5b0492506040810190505b6d04ee2d6d415b85acef810000000083106113c9576d04ee2d6d415b85acef810000000083816113bf576113be611c8c565b5b0492506020810190505b662386f26fc1000083106113f857662386f26fc1000083816113ee576113ed611c8c565b5b0492506010810190505b6305f5e1008310611421576305f5e100838161141757611416611c8c565b5b0492506008810190505b612710831061144657612710838161143c5761143b611c8c565b5b0492506004810190505b60648310611469576064838161145f5761145e611c8c565b5b0492506002810190505b600a8310611478576001810190505b80915050919050565b5f8073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415801561153857508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614806114f957506114f884846107ad565b5b8061153757508273ffffffffffffffffffffffffffffffffffffffff1661151f8361092a565b73ffffffffffffffffffffffffffffffffffffffff16145b5b90509392505050565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61158681611552565b8114611590575f80fd5b50565b5f813590506115a18161157d565b92915050565b5f602082840312156115bc576115bb61154a565b5b5f6115c984828501611593565b91505092915050565b5f8115159050919050565b6115e6816115d2565b82525050565b5f6020820190506115ff5f8301846115dd565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561163c578082015181840152602081019050611621565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61166182611605565b61166b818561160f565b935061167b81856020860161161f565b61168481611647565b840191505092915050565b5f6020820190508181035f8301526116a78184611657565b905092915050565b5f819050919050565b6116c1816116af565b81146116cb575f80fd5b50565b5f813590506116dc816116b8565b92915050565b5f602082840312156116f7576116f661154a565b5b5f611704848285016116ce565b91505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6117368261170d565b9050919050565b6117468161172c565b82525050565b5f60208201905061175f5f83018461173d565b92915050565b61176e8161172c565b8114611778575f80fd5b50565b5f8135905061178981611765565b92915050565b5f80604083850312156117a5576117a461154a565b5b5f6117b28582860161177b565b92505060206117c3858286016116ce565b9150509250929050565b5f805f606084860312156117e4576117e361154a565b5b5f6117f18682870161177b565b93505060206118028682870161177b565b9250506040611813868287016116ce565b9150509250925092565b5f602082840312156118325761183161154a565b5b5f61183f8482850161177b565b91505092915050565b611851816116af565b82525050565b5f60208201905061186a5f830184611848565b92915050565b611879816115d2565b8114611883575f80fd5b50565b5f8135905061189481611870565b92915050565b5f80604083850312156118b0576118af61154a565b5b5f6118bd8582860161177b565b92505060206118ce85828601611886565b9150509250929050565b5f80fd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61191682611647565b810181811067ffffffffffffffff82111715611935576119346118e0565b5b80604052505050565b5f611947611541565b9050611953828261190d565b919050565b5f67ffffffffffffffff821115611972576119716118e0565b5b61197b82611647565b9050602081019050919050565b828183375f83830152505050565b5f6119a86119a384611958565b61193e565b9050828152602081018484840111156119c4576119c36118dc565b5b6119cf848285611988565b509392505050565b5f82601f8301126119eb576119ea6118d8565b5b81356119fb848260208601611996565b91505092915050565b5f805f8060808587031215611a1c57611a1b61154a565b5b5f611a298782880161177b565b9450506020611a3a8782880161177b565b9350506040611a4b878288016116ce565b925050606085013567ffffffffffffffff811115611a6c57611a6b61154e565b5b611a78878288016119d7565b91505092959194509250565b5f8060408385031215611a9a57611a9961154a565b5b5f611aa78582860161177b565b9250506020611ab88582860161177b565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680611b0657607f821691505b602082108103611b1957611b18611ac2565b5b50919050565b5f606082019050611b325f83018661173d565b611b3f6020830185611848565b611b4c604083018461173d565b949350505050565b5f81905092915050565b5f611b6882611605565b611b728185611b54565b9350611b8281856020860161161f565b80840191505092915050565b5f611b998285611b5e565b9150611ba58284611b5e565b91508190509392505050565b5f81519050919050565b5f82825260208201905092915050565b5f611bd582611bb1565b611bdf8185611bbb565b9350611bef81856020860161161f565b611bf881611647565b840191505092915050565b5f608082019050611c165f83018761173d565b611c23602083018661173d565b611c306040830185611848565b8181036060830152611c428184611bcb565b905095945050505050565b5f81519050611c5b8161157d565b92915050565b5f60208284031215611c7657611c7561154a565b5b5f611c8384828501611c4d565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f604082019050611ccc5f83018561173d565b611cd96020830184611848565b939250505056fea26469706673582212207439b47c2a9a1624955997732075917bbf1da26949d000c778f561eb5687576164736f6c63430008180033"; -/// ERC1155_TEST_TOKEN has additional mint function -pub const ERC1155_TEST_TOKEN_BYTES: &str = "608060405234801562000010575f80fd5b50604051620024eb380380620024eb8339818101604052810190620000369190620001ea565b8062000048816200005060201b60201c565b505062000554565b806002908162000061919062000470565b5050565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b620000c6826200007e565b810181811067ffffffffffffffff82111715620000e857620000e76200008e565b5b80604052505050565b5f620000fc62000065565b90506200010a8282620000bb565b919050565b5f67ffffffffffffffff8211156200012c576200012b6200008e565b5b62000137826200007e565b9050602081019050919050565b5f5b838110156200016357808201518184015260208101905062000146565b5f8484015250505050565b5f620001846200017e846200010f565b620000f1565b905082815260208101848484011115620001a357620001a26200007a565b5b620001b084828562000144565b509392505050565b5f82601f830112620001cf57620001ce62000076565b5b8151620001e18482602086016200016e565b91505092915050565b5f602082840312156200020257620002016200006e565b5b5f82015167ffffffffffffffff81111562000222576200022162000072565b5b6200023084828501620001b8565b91505092915050565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806200028857607f821691505b6020821081036200029e576200029d62000243565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620003027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620002c5565b6200030e8683620002c5565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f62000358620003526200034c8462000326565b6200032f565b62000326565b9050919050565b5f819050919050565b620003738362000338565b6200038b62000382826200035f565b848454620002d1565b825550505050565b5f90565b620003a162000393565b620003ae81848462000368565b505050565b5b81811015620003d557620003c95f8262000397565b600181019050620003b4565b5050565b601f8211156200042457620003ee81620002a4565b620003f984620002b6565b8101602085101562000409578190505b620004216200041885620002b6565b830182620003b3565b50505b505050565b5f82821c905092915050565b5f620004465f198460080262000429565b1980831691505092915050565b5f62000460838362000435565b9150826002028217905092915050565b6200047b8262000239565b67ffffffffffffffff8111156200049757620004966200008e565b5b620004a3825462000270565b620004b0828285620003d9565b5f60209050601f831160018114620004e6575f8415620004d1578287015190505b620004dd858262000453565b8655506200054c565b601f198416620004f686620002a4565b5f5b828110156200051f57848901518255600182019150602085019450602081019050620004f8565b868310156200053f57848901516200053b601f89168262000435565b8355505b6001600288020188555050505b505050505050565b611f8980620005625f395ff3fe608060405234801561000f575f80fd5b5060043610610090575f3560e01c80634e1273f4116100645780634e1273f414610140578063731133e914610170578063a22cb4651461018c578063e985e9c5146101a8578063f242432a146101d857610090565b8062fdd58e1461009457806301ffc9a7146100c45780630e89341c146100f45780632eb2c2d614610124575b5f80fd5b6100ae60048036038101906100a991906113bd565b6101f4565b6040516100bb919061140a565b60405180910390f35b6100de60048036038101906100d99190611478565b610249565b6040516100eb91906114bd565b60405180910390f35b61010e600480360381019061010991906114d6565b61032a565b60405161011b919061158b565b60405180910390f35b61013e6004803603810190610139919061179b565b6103bc565b005b61015a60048036038101906101559190611926565b610463565b6040516101679190611a53565b60405180910390f35b61018a60048036038101906101859190611a73565b61056a565b005b6101a660048036038101906101a19190611b1d565b61057c565b005b6101c260048036038101906101bd9190611b5b565b610592565b6040516101cf91906114bd565b60405180910390f35b6101f260048036038101906101ed9190611b99565b610620565b005b5f805f8381526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905092915050565b5f7fd9b67a26000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061031357507f0e89341c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806103235750610322826106c7565b5b9050919050565b60606002805461033990611c59565b80601f016020809104026020016040519081016040528092919081815260200182805461036590611c59565b80156103b05780601f10610387576101008083540402835291602001916103b0565b820191905f5260205f20905b81548152906001019060200180831161039357829003601f168201915b50505050509050919050565b5f6103c5610730565b90508073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161415801561040a57506104088682610592565b155b1561044e5780866040517fe237d922000000000000000000000000000000000000000000000000000000008152600401610445929190611c98565b60405180910390fd5b61045b8686868686610737565b505050505050565b606081518351146104af57815183516040517f5b0599910000000000000000000000000000000000000000000000000000000081526004016104a6929190611cbf565b60405180910390fd5b5f835167ffffffffffffffff8111156104cb576104ca6115af565b5b6040519080825280602002602001820160405280156104f95781602001602082028036833780820191505090505b5090505f5b845181101561055f5761053561051d828761082b90919063ffffffff16565b610530838761083e90919063ffffffff16565b6101f4565b82828151811061054857610547611ce6565b5b6020026020010181815250508060010190506104fe565b508091505092915050565b61057684848484610851565b50505050565b61058e610587610730565b83836108e6565b5050565b5f60015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16905092915050565b5f610629610730565b90508073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161415801561066e575061066c8682610592565b155b156106b25780866040517fe237d9220000000000000000000000000000000000000000000000000000000081526004016106a9929190611c98565b60405180910390fd5b6106bf8686868686610a4f565b505050505050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f33905090565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036107a7575f6040517f57f447ce00000000000000000000000000000000000000000000000000000000815260040161079e9190611d13565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603610817575f6040517f01a8351400000000000000000000000000000000000000000000000000000000815260040161080e9190611d13565b60405180910390fd5b6108248585858585610b55565b5050505050565b5f60208202602084010151905092915050565b5f60208202602084010151905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036108c1575f6040517f57f447ce0000000000000000000000000000000000000000000000000000000081526004016108b89190611d13565b60405180910390fd5b5f806108cd8585610c01565b915091506108de5f87848487610b55565b505050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610956575f6040517fced3e10000000000000000000000000000000000000000000000000000000000815260040161094d9190611d13565b60405180910390fd5b8060015f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051610a4291906114bd565b60405180910390a3505050565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610abf575f6040517f57f447ce000000000000000000000000000000000000000000000000000000008152600401610ab69190611d13565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603610b2f575f6040517f01a83514000000000000000000000000000000000000000000000000000000008152600401610b269190611d13565b60405180910390fd5b5f80610b3b8585610c01565b91509150610b4c8787848487610b55565b50505050505050565b610b6185858585610c31565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614610bfa575f610b9d610730565b90506001845103610be9575f610bbc5f8661083e90919063ffffffff16565b90505f610bd25f8661083e90919063ffffffff16565b9050610be2838989858589610fc1565b5050610bf8565b610bf7818787878787611170565b5b505b5050505050565b60608060405191506001825283602083015260408201905060018152826020820152604081016040529250929050565b8051825114610c7b57815181516040517f5b059991000000000000000000000000000000000000000000000000000000008152600401610c72929190611cbf565b60405180910390fd5b5f610c84610730565b90505f5b8351811015610e80575f610ca5828661083e90919063ffffffff16565b90505f610cbb838661083e90919063ffffffff16565b90505f73ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614610dde575f805f8481526020019081526020015f205f8a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905081811015610d8a57888183856040517f03dee4c5000000000000000000000000000000000000000000000000000000008152600401610d819493929190611d2c565b60405180910390fd5b8181035f808581526020019081526020015f205f8b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550505b5f73ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614610e7357805f808481526020019081526020015f205f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610e6b9190611d9c565b925050819055505b5050806001019050610c88565b506001835103610f3b575f610e9e5f8561083e90919063ffffffff16565b90505f610eb45f8561083e90919063ffffffff16565b90508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628585604051610f2c929190611cbf565b60405180910390a45050610fba565b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8686604051610fb1929190611dcf565b60405180910390a45b5050505050565b5f8473ffffffffffffffffffffffffffffffffffffffff163b1115611168578373ffffffffffffffffffffffffffffffffffffffff1663f23a6e6187878686866040518663ffffffff1660e01b8152600401611021959493929190611e56565b6020604051808303815f875af192505050801561105c57506040513d601f19601f820116820180604052508101906110599190611ec2565b60015b6110dd573d805f811461108a576040519150601f19603f3d011682016040523d82523d5f602084013e61108f565b606091505b505f8151036110d557846040517f57f447ce0000000000000000000000000000000000000000000000000000000081526004016110cc9190611d13565b60405180910390fd5b805181602001fd5b63f23a6e6160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461116657846040517f57f447ce00000000000000000000000000000000000000000000000000000000815260040161115d9190611d13565b60405180910390fd5b505b505050505050565b5f8473ffffffffffffffffffffffffffffffffffffffff163b1115611317578373ffffffffffffffffffffffffffffffffffffffff1663bc197c8187878686866040518663ffffffff1660e01b81526004016111d0959493929190611eed565b6020604051808303815f875af192505050801561120b57506040513d601f19601f820116820180604052508101906112089190611ec2565b60015b61128c573d805f8114611239576040519150601f19603f3d011682016040523d82523d5f602084013e61123e565b606091505b505f81510361128457846040517f57f447ce00000000000000000000000000000000000000000000000000000000815260040161127b9190611d13565b60405180910390fd5b805181602001fd5b63bc197c8160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461131557846040517f57f447ce00000000000000000000000000000000000000000000000000000000815260040161130c9190611d13565b60405180910390fd5b505b505050505050565b5f604051905090565b5f80fd5b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61135982611330565b9050919050565b6113698161134f565b8114611373575f80fd5b50565b5f8135905061138481611360565b92915050565b5f819050919050565b61139c8161138a565b81146113a6575f80fd5b50565b5f813590506113b781611393565b92915050565b5f80604083850312156113d3576113d2611328565b5b5f6113e085828601611376565b92505060206113f1858286016113a9565b9150509250929050565b6114048161138a565b82525050565b5f60208201905061141d5f8301846113fb565b92915050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61145781611423565b8114611461575f80fd5b50565b5f813590506114728161144e565b92915050565b5f6020828403121561148d5761148c611328565b5b5f61149a84828501611464565b91505092915050565b5f8115159050919050565b6114b7816114a3565b82525050565b5f6020820190506114d05f8301846114ae565b92915050565b5f602082840312156114eb576114ea611328565b5b5f6114f8848285016113a9565b91505092915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561153857808201518184015260208101905061151d565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61155d82611501565b611567818561150b565b935061157781856020860161151b565b61158081611543565b840191505092915050565b5f6020820190508181035f8301526115a38184611553565b905092915050565b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6115e582611543565b810181811067ffffffffffffffff82111715611604576116036115af565b5b80604052505050565b5f61161661131f565b905061162282826115dc565b919050565b5f67ffffffffffffffff821115611641576116406115af565b5b602082029050602081019050919050565b5f80fd5b5f61166861166384611627565b61160d565b9050808382526020820190506020840283018581111561168b5761168a611652565b5b835b818110156116b457806116a088826113a9565b84526020840193505060208101905061168d565b5050509392505050565b5f82601f8301126116d2576116d16115ab565b5b81356116e2848260208601611656565b91505092915050565b5f80fd5b5f67ffffffffffffffff821115611709576117086115af565b5b61171282611543565b9050602081019050919050565b828183375f83830152505050565b5f61173f61173a846116ef565b61160d565b90508281526020810184848401111561175b5761175a6116eb565b5b61176684828561171f565b509392505050565b5f82601f830112611782576117816115ab565b5b813561179284826020860161172d565b91505092915050565b5f805f805f60a086880312156117b4576117b3611328565b5b5f6117c188828901611376565b95505060206117d288828901611376565b945050604086013567ffffffffffffffff8111156117f3576117f261132c565b5b6117ff888289016116be565b935050606086013567ffffffffffffffff8111156118205761181f61132c565b5b61182c888289016116be565b925050608086013567ffffffffffffffff81111561184d5761184c61132c565b5b6118598882890161176e565b9150509295509295909350565b5f67ffffffffffffffff8211156118805761187f6115af565b5b602082029050602081019050919050565b5f6118a361189e84611866565b61160d565b905080838252602082019050602084028301858111156118c6576118c5611652565b5b835b818110156118ef57806118db8882611376565b8452602084019350506020810190506118c8565b5050509392505050565b5f82601f83011261190d5761190c6115ab565b5b813561191d848260208601611891565b91505092915050565b5f806040838503121561193c5761193b611328565b5b5f83013567ffffffffffffffff8111156119595761195861132c565b5b611965858286016118f9565b925050602083013567ffffffffffffffff8111156119865761198561132c565b5b611992858286016116be565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b6119ce8161138a565b82525050565b5f6119df83836119c5565b60208301905092915050565b5f602082019050919050565b5f611a018261199c565b611a0b81856119a6565b9350611a16836119b6565b805f5b83811015611a46578151611a2d88826119d4565b9750611a38836119eb565b925050600181019050611a19565b5085935050505092915050565b5f6020820190508181035f830152611a6b81846119f7565b905092915050565b5f805f8060808587031215611a8b57611a8a611328565b5b5f611a9887828801611376565b9450506020611aa9878288016113a9565b9350506040611aba878288016113a9565b925050606085013567ffffffffffffffff811115611adb57611ada61132c565b5b611ae78782880161176e565b91505092959194509250565b611afc816114a3565b8114611b06575f80fd5b50565b5f81359050611b1781611af3565b92915050565b5f8060408385031215611b3357611b32611328565b5b5f611b4085828601611376565b9250506020611b5185828601611b09565b9150509250929050565b5f8060408385031215611b7157611b70611328565b5b5f611b7e85828601611376565b9250506020611b8f85828601611376565b9150509250929050565b5f805f805f60a08688031215611bb257611bb1611328565b5b5f611bbf88828901611376565b9550506020611bd088828901611376565b9450506040611be1888289016113a9565b9350506060611bf2888289016113a9565b925050608086013567ffffffffffffffff811115611c1357611c1261132c565b5b611c1f8882890161176e565b9150509295509295909350565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680611c7057607f821691505b602082108103611c8357611c82611c2c565b5b50919050565b611c928161134f565b82525050565b5f604082019050611cab5f830185611c89565b611cb86020830184611c89565b9392505050565b5f604082019050611cd25f8301856113fb565b611cdf60208301846113fb565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f602082019050611d265f830184611c89565b92915050565b5f608082019050611d3f5f830187611c89565b611d4c60208301866113fb565b611d5960408301856113fb565b611d6660608301846113fb565b95945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f611da68261138a565b9150611db18361138a565b9250828201905080821115611dc957611dc8611d6f565b5b92915050565b5f6040820190508181035f830152611de781856119f7565b90508181036020830152611dfb81846119f7565b90509392505050565b5f81519050919050565b5f82825260208201905092915050565b5f611e2882611e04565b611e328185611e0e565b9350611e4281856020860161151b565b611e4b81611543565b840191505092915050565b5f60a082019050611e695f830188611c89565b611e766020830187611c89565b611e8360408301866113fb565b611e9060608301856113fb565b8181036080830152611ea28184611e1e565b90509695505050505050565b5f81519050611ebc8161144e565b92915050565b5f60208284031215611ed757611ed6611328565b5b5f611ee484828501611eae565b91505092915050565b5f60a082019050611f005f830188611c89565b611f0d6020830187611c89565b8181036040830152611f1f81866119f7565b90508181036060830152611f3381856119f7565b90508181036080830152611f478184611e1e565b9050969550505050505056fea2646970667358221220aa7808c7a42c44ef257fdbc9ac99eb0d5840587290be50439b94642674548a7e64736f6c63430008180033"; +pub const ERC1155_TEST_TOKEN_BYTES: &str = "608060405234801562000010575f80fd5b50604051620024eb380380620024eb8339818101604052810190620000369190620001ea565b8062000048816200005060201b60201c565b505062000554565b806002908162000061919062000470565b5050565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b620000c6826200007e565b810181811067ffffffffffffffff82111715620000e857620000e76200008e565b5b80604052505050565b5f620000fc62000065565b90506200010a8282620000bb565b919050565b5f67ffffffffffffffff8211156200012c576200012b6200008e565b5b62000137826200007e565b9050602081019050919050565b5f5b838110156200016357808201518184015260208101905062000146565b5f8484015250505050565b5f620001846200017e846200010f565b620000f1565b905082815260208101848484011115620001a357620001a26200007a565b5b620001b084828562000144565b509392505050565b5f82601f830112620001cf57620001ce62000076565b5b8151620001e18482602086016200016e565b91505092915050565b5f602082840312156200020257620002016200006e565b5b5f82015167ffffffffffffffff81111562000222576200022162000072565b5b6200023084828501620001b8565b91505092915050565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806200028857607f821691505b6020821081036200029e576200029d62000243565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620003027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620002c5565b6200030e8683620002c5565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f62000358620003526200034c8462000326565b6200032f565b62000326565b9050919050565b5f819050919050565b620003738362000338565b6200038b62000382826200035f565b848454620002d1565b825550505050565b5f90565b620003a162000393565b620003ae81848462000368565b505050565b5b81811015620003d557620003c95f8262000397565b600181019050620003b4565b5050565b601f8211156200042457620003ee81620002a4565b620003f984620002b6565b8101602085101562000409578190505b620004216200041885620002b6565b830182620003b3565b50505b505050565b5f82821c905092915050565b5f620004465f198460080262000429565b1980831691505092915050565b5f62000460838362000435565b9150826002028217905092915050565b6200047b8262000239565b67ffffffffffffffff8111156200049757620004966200008e565b5b620004a3825462000270565b620004b0828285620003d9565b5f60209050601f831160018114620004e6575f8415620004d1578287015190505b620004dd858262000453565b8655506200054c565b601f198416620004f686620002a4565b5f5b828110156200051f57848901518255600182019150602085019450602081019050620004f8565b868310156200053f57848901516200053b601f89168262000435565b8355505b6001600288020188555050505b505050505050565b611f8980620005625f395ff3fe608060405234801561000f575f80fd5b5060043610610090575f3560e01c80634e1273f4116100645780634e1273f414610140578063731133e914610170578063a22cb4651461018c578063e985e9c5146101a8578063f242432a146101d857610090565b8062fdd58e1461009457806301ffc9a7146100c45780630e89341c146100f45780632eb2c2d614610124575b5f80fd5b6100ae60048036038101906100a991906113bd565b6101f4565b6040516100bb919061140a565b60405180910390f35b6100de60048036038101906100d99190611478565b610249565b6040516100eb91906114bd565b60405180910390f35b61010e600480360381019061010991906114d6565b61032a565b60405161011b919061158b565b60405180910390f35b61013e6004803603810190610139919061179b565b6103bc565b005b61015a60048036038101906101559190611926565b610463565b6040516101679190611a53565b60405180910390f35b61018a60048036038101906101859190611a73565b61056a565b005b6101a660048036038101906101a19190611b1d565b61057c565b005b6101c260048036038101906101bd9190611b5b565b610592565b6040516101cf91906114bd565b60405180910390f35b6101f260048036038101906101ed9190611b99565b610620565b005b5f805f8381526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905092915050565b5f7fd9b67a26000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061031357507f0e89341c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806103235750610322826106c7565b5b9050919050565b60606002805461033990611c59565b80601f016020809104026020016040519081016040528092919081815260200182805461036590611c59565b80156103b05780601f10610387576101008083540402835291602001916103b0565b820191905f5260205f20905b81548152906001019060200180831161039357829003601f168201915b50505050509050919050565b5f6103c5610730565b90508073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161415801561040a57506104088682610592565b155b1561044e5780866040517fe237d922000000000000000000000000000000000000000000000000000000008152600401610445929190611c98565b60405180910390fd5b61045b8686868686610737565b505050505050565b606081518351146104af57815183516040517f5b0599910000000000000000000000000000000000000000000000000000000081526004016104a6929190611cbf565b60405180910390fd5b5f835167ffffffffffffffff8111156104cb576104ca6115af565b5b6040519080825280602002602001820160405280156104f95781602001602082028036833780820191505090505b5090505f5b845181101561055f5761053561051d828761082b90919063ffffffff16565b610530838761083e90919063ffffffff16565b6101f4565b82828151811061054857610547611ce6565b5b6020026020010181815250508060010190506104fe565b508091505092915050565b61057684848484610851565b50505050565b61058e610587610730565b83836108e6565b5050565b5f60015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16905092915050565b5f610629610730565b90508073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161415801561066e575061066c8682610592565b155b156106b25780866040517fe237d9220000000000000000000000000000000000000000000000000000000081526004016106a9929190611c98565b60405180910390fd5b6106bf8686868686610a4f565b505050505050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f33905090565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036107a7575f6040517f57f447ce00000000000000000000000000000000000000000000000000000000815260040161079e9190611d13565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603610817575f6040517f01a8351400000000000000000000000000000000000000000000000000000000815260040161080e9190611d13565b60405180910390fd5b6108248585858585610b55565b5050505050565b5f60208202602084010151905092915050565b5f60208202602084010151905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036108c1575f6040517f57f447ce0000000000000000000000000000000000000000000000000000000081526004016108b89190611d13565b60405180910390fd5b5f806108cd8585610c01565b915091506108de5f87848487610b55565b505050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610956575f6040517fced3e10000000000000000000000000000000000000000000000000000000000815260040161094d9190611d13565b60405180910390fd5b8060015f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051610a4291906114bd565b60405180910390a3505050565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610abf575f6040517f57f447ce000000000000000000000000000000000000000000000000000000008152600401610ab69190611d13565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603610b2f575f6040517f01a83514000000000000000000000000000000000000000000000000000000008152600401610b269190611d13565b60405180910390fd5b5f80610b3b8585610c01565b91509150610b4c8787848487610b55565b50505050505050565b610b6185858585610c31565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614610bfa575f610b9d610730565b90506001845103610be9575f610bbc5f8661083e90919063ffffffff16565b90505f610bd25f8661083e90919063ffffffff16565b9050610be2838989858589610fc1565b5050610bf8565b610bf7818787878787611170565b5b505b5050505050565b60608060405191506001825283602083015260408201905060018152826020820152604081016040529250929050565b8051825114610c7b57815181516040517f5b059991000000000000000000000000000000000000000000000000000000008152600401610c72929190611cbf565b60405180910390fd5b5f610c84610730565b90505f5b8351811015610e80575f610ca5828661083e90919063ffffffff16565b90505f610cbb838661083e90919063ffffffff16565b90505f73ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614610dde575f805f8481526020019081526020015f205f8a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905081811015610d8a57888183856040517f03dee4c5000000000000000000000000000000000000000000000000000000008152600401610d819493929190611d2c565b60405180910390fd5b8181035f808581526020019081526020015f205f8b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550505b5f73ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614610e7357805f808481526020019081526020015f205f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610e6b9190611d9c565b925050819055505b5050806001019050610c88565b506001835103610f3b575f610e9e5f8561083e90919063ffffffff16565b90505f610eb45f8561083e90919063ffffffff16565b90508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628585604051610f2c929190611cbf565b60405180910390a45050610fba565b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8686604051610fb1929190611dcf565b60405180910390a45b5050505050565b5f8473ffffffffffffffffffffffffffffffffffffffff163b1115611168578373ffffffffffffffffffffffffffffffffffffffff1663f23a6e6187878686866040518663ffffffff1660e01b8152600401611021959493929190611e56565b6020604051808303815f875af192505050801561105c57506040513d601f19601f820116820180604052508101906110599190611ec2565b60015b6110dd573d805f811461108a576040519150601f19603f3d011682016040523d82523d5f602084013e61108f565b606091505b505f8151036110d557846040517f57f447ce0000000000000000000000000000000000000000000000000000000081526004016110cc9190611d13565b60405180910390fd5b805181602001fd5b63f23a6e6160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461116657846040517f57f447ce00000000000000000000000000000000000000000000000000000000815260040161115d9190611d13565b60405180910390fd5b505b505050505050565b5f8473ffffffffffffffffffffffffffffffffffffffff163b1115611317578373ffffffffffffffffffffffffffffffffffffffff1663bc197c8187878686866040518663ffffffff1660e01b81526004016111d0959493929190611eed565b6020604051808303815f875af192505050801561120b57506040513d601f19601f820116820180604052508101906112089190611ec2565b60015b61128c573d805f8114611239576040519150601f19603f3d011682016040523d82523d5f602084013e61123e565b606091505b505f81510361128457846040517f57f447ce00000000000000000000000000000000000000000000000000000000815260040161127b9190611d13565b60405180910390fd5b805181602001fd5b63bc197c8160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461131557846040517f57f447ce00000000000000000000000000000000000000000000000000000000815260040161130c9190611d13565b60405180910390fd5b505b505050505050565b5f604051905090565b5f80fd5b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61135982611330565b9050919050565b6113698161134f565b8114611373575f80fd5b50565b5f8135905061138481611360565b92915050565b5f819050919050565b61139c8161138a565b81146113a6575f80fd5b50565b5f813590506113b781611393565b92915050565b5f80604083850312156113d3576113d2611328565b5b5f6113e085828601611376565b92505060206113f1858286016113a9565b9150509250929050565b6114048161138a565b82525050565b5f60208201905061141d5f8301846113fb565b92915050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61145781611423565b8114611461575f80fd5b50565b5f813590506114728161144e565b92915050565b5f6020828403121561148d5761148c611328565b5b5f61149a84828501611464565b91505092915050565b5f8115159050919050565b6114b7816114a3565b82525050565b5f6020820190506114d05f8301846114ae565b92915050565b5f602082840312156114eb576114ea611328565b5b5f6114f8848285016113a9565b91505092915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561153857808201518184015260208101905061151d565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61155d82611501565b611567818561150b565b935061157781856020860161151b565b61158081611543565b840191505092915050565b5f6020820190508181035f8301526115a38184611553565b905092915050565b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6115e582611543565b810181811067ffffffffffffffff82111715611604576116036115af565b5b80604052505050565b5f61161661131f565b905061162282826115dc565b919050565b5f67ffffffffffffffff821115611641576116406115af565b5b602082029050602081019050919050565b5f80fd5b5f61166861166384611627565b61160d565b9050808382526020820190506020840283018581111561168b5761168a611652565b5b835b818110156116b457806116a088826113a9565b84526020840193505060208101905061168d565b5050509392505050565b5f82601f8301126116d2576116d16115ab565b5b81356116e2848260208601611656565b91505092915050565b5f80fd5b5f67ffffffffffffffff821115611709576117086115af565b5b61171282611543565b9050602081019050919050565b828183375f83830152505050565b5f61173f61173a846116ef565b61160d565b90508281526020810184848401111561175b5761175a6116eb565b5b61176684828561171f565b509392505050565b5f82601f830112611782576117816115ab565b5b813561179284826020860161172d565b91505092915050565b5f805f805f60a086880312156117b4576117b3611328565b5b5f6117c188828901611376565b95505060206117d288828901611376565b945050604086013567ffffffffffffffff8111156117f3576117f261132c565b5b6117ff888289016116be565b935050606086013567ffffffffffffffff8111156118205761181f61132c565b5b61182c888289016116be565b925050608086013567ffffffffffffffff81111561184d5761184c61132c565b5b6118598882890161176e565b9150509295509295909350565b5f67ffffffffffffffff8211156118805761187f6115af565b5b602082029050602081019050919050565b5f6118a361189e84611866565b61160d565b905080838252602082019050602084028301858111156118c6576118c5611652565b5b835b818110156118ef57806118db8882611376565b8452602084019350506020810190506118c8565b5050509392505050565b5f82601f83011261190d5761190c6115ab565b5b813561191d848260208601611891565b91505092915050565b5f806040838503121561193c5761193b611328565b5b5f83013567ffffffffffffffff8111156119595761195861132c565b5b611965858286016118f9565b925050602083013567ffffffffffffffff8111156119865761198561132c565b5b611992858286016116be565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b6119ce8161138a565b82525050565b5f6119df83836119c5565b60208301905092915050565b5f602082019050919050565b5f611a018261199c565b611a0b81856119a6565b9350611a16836119b6565b805f5b83811015611a46578151611a2d88826119d4565b9750611a38836119eb565b925050600181019050611a19565b5085935050505092915050565b5f6020820190508181035f830152611a6b81846119f7565b905092915050565b5f805f8060808587031215611a8b57611a8a611328565b5b5f611a9887828801611376565b9450506020611aa9878288016113a9565b9350506040611aba878288016113a9565b925050606085013567ffffffffffffffff811115611adb57611ada61132c565b5b611ae78782880161176e565b91505092959194509250565b611afc816114a3565b8114611b06575f80fd5b50565b5f81359050611b1781611af3565b92915050565b5f8060408385031215611b3357611b32611328565b5b5f611b4085828601611376565b9250506020611b5185828601611b09565b9150509250929050565b5f8060408385031215611b7157611b70611328565b5b5f611b7e85828601611376565b9250506020611b8f85828601611376565b9150509250929050565b5f805f805f60a08688031215611bb257611bb1611328565b5b5f611bbf88828901611376565b9550506020611bd088828901611376565b9450506040611be1888289016113a9565b9350506060611bf2888289016113a9565b925050608086013567ffffffffffffffff811115611c1357611c1261132c565b5b611c1f8882890161176e565b9150509295509295909350565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680611c7057607f821691505b602082108103611c8357611c82611c2c565b5b50919050565b611c928161134f565b82525050565b5f604082019050611cab5f830185611c89565b611cb86020830184611c89565b9392505050565b5f604082019050611cd25f8301856113fb565b611cdf60208301846113fb565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f602082019050611d265f830184611c89565b92915050565b5f608082019050611d3f5f830187611c89565b611d4c60208301866113fb565b611d5960408301856113fb565b611d6660608301846113fb565b95945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f611da68261138a565b9150611db18361138a565b9250828201905080821115611dc957611dc8611d6f565b5b92915050565b5f6040820190508181035f830152611de781856119f7565b90508181036020830152611dfb81846119f7565b90509392505050565b5f81519050919050565b5f82825260208201905092915050565b5f611e2882611e04565b611e328185611e0e565b9350611e4281856020860161151b565b611e4b81611543565b840191505092915050565b5f60a082019050611e695f830188611c89565b611e766020830187611c89565b611e8360408301866113fb565b611e9060608301856113fb565b8181036080830152611ea28184611e1e565b90509695505050505050565b5f81519050611ebc8161144e565b92915050565b5f60208284031215611ed757611ed6611328565b5b5f611ee484828501611eae565b91505092915050565b5f60a082019050611f005f830188611c89565b611f0d6020830187611c89565b8181036040830152611f1f81866119f7565b90508181036060830152611f3381856119f7565b90508181036080830152611f478184611e1e565b9050969550505050505056fea26469706673582212203835581c6344b12728c44fa4d9e912cd60e64012c1b772bb703d1c36825c16fd64736f6c63430008180033"; pub const NFT_SWAP_CONTRACT_BYTES: &str = "60a060405234801562000010575f80fd5b506040516200553a3803806200553a833981810160405281019062000036919062000147565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603620000a7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200009e90620001fb565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff1681525050506200021b565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6200011182620000e6565b9050919050565b620001238162000105565b81146200012e575f80fd5b50565b5f81519050620001418162000118565b92915050565b5f602082840312156200015f576200015e620000e2565b5b5f6200016e8482850162000131565b91505092915050565b5f82825260208201905092915050565b7f66656541646472657373206d757374206e6f74206265207a65726f20616464725f8201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b5f620001e360238362000177565b9150620001f08262000187565b604082019050919050565b5f6020820190508181035f8301526200021481620001d5565b9050919050565b6080516152f8620002425f395f8181612759015281816127f40152612bb201526152f85ff3fe608060405260043610610113575f3560e01c80639b4603f21161009f578063d6a71eb411610063578063d6a71eb41461038e578063e06cf966146103b6578063efccb9eb146103e0578063f23a6e611461041e578063fc45ef821461045a57610113565b80639b4603f2146102be578063ba157104146102da578063bc197c8114610302578063c8d9009b1461033e578063cc90c1991461036657610113565b806332c7d4f8116100e657806332c7d4f8146101df5780633e6af5f21461020757806346b95ac71461022f57806365e266171461026e5780636e6bf6d21461029657610113565b806301ffc9a7146101175780630f235fce14610153578063146e5b241461017b578063150b7a02146101a3575b5f80fd5b348015610122575f80fd5b5061013d60048036038101906101389190613807565b610482565b60405161014a919061384c565b60405180910390f35b34801561015e575f80fd5b5061017960048036038101906101749190613925565b6104fb565b005b348015610186575f80fd5b506101a1600480360381019061019c91906139ae565b6107b5565b005b3480156101ae575f80fd5b506101c960048036038101906101c49190613aac565b61099b565b6040516101d69190613b3f565b60405180910390f35b3480156101ea575f80fd5b5061020560048036038101906102009190613b58565b610dea565b005b348015610212575f80fd5b5061022d600480360381019061022891906139ae565b6110a9565b005b34801561023a575f80fd5b5061025560048036038101906102509190613bf5565b6113ba565b6040516102659493929190613ceb565b60405180910390f35b348015610279575f80fd5b50610294600480360381019061028f91906139ae565b61141c565b005b3480156102a1575f80fd5b506102bc60048036038101906102b79190613925565b611880565b005b6102d860048036038101906102d39190613d58565b611b3b565b005b3480156102e5575f80fd5b5061030060048036038101906102fb9190613b58565b611e71565b005b34801561030d575f80fd5b5061032860048036038101906103239190613e4a565b612131565b6040516103359190613b3f565b60405180910390f35b348015610349575f80fd5b50610364600480360381019061035f9190613925565b61216d565b005b348015610371575f80fd5b5061038c600480360381019061038791906139ae565b612496565b005b348015610399575f80fd5b506103b460048036038101906103af9190613f21565b612846565b005b3480156103c1575f80fd5b506103ca612bb0565b6040516103d79190613ff4565b60405180910390f35b3480156103eb575f80fd5b5061040660048036038101906104019190613bf5565b612bd4565b60405161041593929190614053565b60405180910390f35b348015610429575f80fd5b50610444600480360381019061043f9190614088565b612c20565b6040516104519190613b3f565b60405180910390f35b348015610465575f80fd5b50610480600480360381019061047b9190613b58565b6130b4565b005b5f7f4e2312e0000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806104f457506104f3826133e2565b5b9050919050565b6001600381111561050f5761050e613c78565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff16600381111561054157610540613c78565b5b14610581576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105789061419e565b60405180910390fd5b5f600386338787878760405160200161059f96959493929190614241565b6040516020818303038152906040526040516105bb919061431c565b602060405180830381855afa1580156105d6573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610660576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106579061437c565b60405180910390fd5b5f808881526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff164210156106cb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c29061440a565b60405180910390fd5b60035f808981526020019081526020015f205f0160186101000a81548160ff0219169083600381111561070157610700613c78565b5b02179055507f5dedc4f52b757d9112d09ca0b2f022927104d54e3f54da091587e8ad19219072876040516107359190614437565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b815260040161077e9392919061445f565b5f604051808303815f87803b158015610795575f80fd5b505af11580156107a7573d5f803e3d5ffd5b505050505050505050505050565b600160048111156107c9576107c8613c78565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff1660048111156107fc576107fb613c78565b5b1461083c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108339061419e565b60405180910390fd5b5f60038787873388888860405160200161085c9796959493929190614494565b604051602081830303815290604052604051610878919061431c565b602060405180830381855afa158015610893573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461091e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109159061437c565b60405180910390fd5b600260015f8a81526020019081526020015f205f01601c6101000a81548160ff0219169083600481111561095557610954613c78565b5b02179055507f9c45e43e2ef051f70491ffd5221bf02ab37e1324128714ef9610df5f24fc9fb5886040516109899190614437565b60405180910390a15050505050505050565b5f8083838101906109ac919061463d565b90505f73ffffffffffffffffffffffffffffffffffffffff16816020015173ffffffffffffffffffffffffffffffffffffffff1603610a20576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a17906146b2565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816040015173ffffffffffffffffffffffffffffffffffffffff1603610a92576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a899061471a565b60405180910390fd5b806040015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610b04576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610afb906147a8565b60405180910390fd5b8573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614610b72576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b6990614810565b60405180910390fd5b5f6003811115610b8557610b84613c78565b5b5f80835f015181526020019081526020015f205f0160189054906101000a900460ff166003811115610bba57610bb9613c78565b5b14610bfa576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bf19061489e565b60405180910390fd5b610c07816020015161344b565b15610c47576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c3e90614906565b60405180910390fd5b5f60038260200151888460600151856080015186604001518b604051602001610c7596959493929190614241565b604051602081830303815290604052604051610c91919061431c565b602060405180830381855afa158015610cac573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018360a0015163ffffffff16815260200160016003811115610cfc57610cfb613c78565b5b8152505f80845f015181526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548160ff02191690836003811115610d9357610d92613c78565b5b02179055509050507ff1dc11bbb6d7542c4267ecf1d370ff4c7092518633ecae9939e8488f4e53d2ad825f0151604051610dcd9190614437565b60405180910390a163150b7a0260e01b9250505095945050505050565b60016003811115610dfe57610dfd613c78565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff166003811115610e3057610e2f613c78565b5b14610e70576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e679061419e565b60405180910390fd5b5f60038633878787878d604051602001610e909796959493929190614924565b604051602081830303815290604052604051610eac919061431c565b602060405180830381855afa158015610ec7573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610f51576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f489061437c565b60405180910390fd5b5f808981526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff16421015610fbc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fb39061440a565b60405180910390fd5b60035f808a81526020019081526020015f205f0160186101000a81548160ff02191690836003811115610ff257610ff1613c78565b5b02179055507f5dedc4f52b757d9112d09ca0b2f022927104d54e3f54da091587e8ad19219072886040516110269190614437565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff1663f242432a3033868c6040518563ffffffff1660e01b815260040161107194939291906149d7565b5f604051808303815f87803b158015611088575f80fd5b505af115801561109a573d5f803e3d5ffd5b50505050505050505050505050565b600160048111156110bd576110bc613c78565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff1660048111156110f0576110ef613c78565b5b14611130576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111279061419e565b60405180910390fd5b5f60038787873360028960405160200161114a9190614a2d565b604051602081830303815290604052604051611166919061431c565b602060405180830381855afa158015611181573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906111a49190614a5b565b88886040516020016111bc9796959493929190614494565b6040516020818303038152906040526040516111d8919061431c565b602060405180830381855afa1580156111f3573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461127e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112759061437c565b60405180910390fd5b600460015f8a81526020019081526020015f205f01601c6101000a81548160ff021916908360048111156112b5576112b4613c78565b5b02179055507f45169a52eef651b20a81474b50b8a5d83225225fcd097ef3cf7952d9ab304f2788856040516112eb929190614a86565b60405180910390a15f86886113009190614ada565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361137e573373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f19350505050158015611378573d5f803e3d5ffd5b506113af565b5f8390506113ad33838373ffffffffffffffffffffffffffffffffffffffff1661345c9092919063ffffffff16565b505b505050505050505050565b6001602052805f5260405f205f91509050805f015f9054906101000a900460601b90805f0160149054906101000a900463ffffffff1690805f0160189054906101000a900463ffffffff1690805f01601c9054906101000a900460ff16905084565b600160048111156114305761142f613c78565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff16600481111561146357611462613c78565b5b14806114b357506002600481111561147e5761147d613c78565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff1660048111156114b1576114b0613c78565b5b145b6114f2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114e990614b7d565b60405180910390fd5b5f6003878787338888886040516020016115129796959493929190614494565b60405160208183030381529060405260405161152e919061431c565b602060405180830381855afa158015611549573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146115d4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115cb9061437c565b60405180910390fd5b600260048111156115e8576115e7613c78565b5b60015f8a81526020019081526020015f205f01601c9054906101000a900460ff16600481111561161b5761161a613c78565b5b0361168d5760015f8981526020019081526020015f205f0160189054906101000a900463ffffffff1663ffffffff1642101561168c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116839061440a565b60405180910390fd5b5b600160048111156116a1576116a0613c78565b5b60015f8a81526020019081526020015f205f01601c9054906101000a900460ff1660048111156116d4576116d3613c78565b5b036117465760015f8981526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff16421015611745576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161173c90614c0b565b60405180910390fd5b5b600460015f8a81526020019081526020015f205f01601c6101000a81548160ff0219169083600481111561177d5761177c613c78565b5b02179055507fbdd7a4be6d82798a500b59077706b12d3f45acf5504828919f92501307b2b953886040516117b19190614437565b60405180910390a15f86886117c69190614ada565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611844573373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f1935050505015801561183e573d5f803e3d5ffd5b50611875565b5f83905061187333838373ffffffffffffffffffffffffffffffffffffffff1661345c9092919063ffffffff16565b505b505050505050505050565b6001600381111561189457611893613c78565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff1660038111156118c6576118c5613c78565b5b14611906576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118fd9061419e565b60405180910390fd5b5f6003863360028860405160200161191e9190614a2d565b60405160208183030381529060405260405161193a919061431c565b602060405180830381855afa158015611955573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906119789190614a5b565b87878760405160200161199096959493929190614241565b6040516020818303038152906040526040516119ac919061431c565b602060405180830381855afa1580156119c7573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614611a51576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a489061437c565b60405180910390fd5b60035f808981526020019081526020015f205f0160186101000a81548160ff02191690836003811115611a8757611a86613c78565b5b02179055507fac509cdcc7ddb189f81fff6f4824f5c95076e64c3bdce542c50feaa6779afd7387604051611abb9190614437565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b8152600401611b049392919061445f565b5f604051808303815f87803b158015611b1b575f80fd5b505af1158015611b2d573d5f803e3d5ffd5b505050505050505050505050565b5f6004811115611b4e57611b4d613c78565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff166004811115611b8157611b80613c78565b5b14611bc1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bb890614c99565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603611c2f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c2690614d27565b60405180910390fd5b5f3411611c71576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c6890614db5565b60405180910390fd5b853411611cb3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611caa90614e43565b60405180910390fd5b5f60038734611cc29190614e61565b88883389895f604051602001611cde9796959493929190614494565b604051602081830303815290604052604051611cfa919061431c565b602060405180830381855afa158015611d15573d5f803e3d5ffd5b5050506040515160601b90506040518060800160405280826bffffffffffffffffffffffff191681526020018463ffffffff1681526020018363ffffffff16815260200160016004811115611d6d57611d6c613c78565b5b81525060015f8a81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548163ffffffff021916908363ffffffff1602179055506060820151815f01601c6101000a81548160ff02191690836004811115611e2857611e27613c78565b5b02179055509050507ffc6cdccd1d98ded12074a9ebc7f6ab74fed1814ff57f4fb5202464d8938bd93588604051611e5f9190614437565b60405180910390a15050505050505050565b60016003811115611e8557611e84613c78565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff166003811115611eb757611eb6613c78565b5b14611ef7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611eee9061419e565b60405180910390fd5b5f60038633600288604051602001611f0f9190614a2d565b604051602081830303815290604052604051611f2b919061431c565b602060405180830381855afa158015611f46573d5f803e3d5ffd5b5050506040513d601f19601f82011682018060405250810190611f699190614a5b565b8787878d604051602001611f839796959493929190614924565b604051602081830303815290604052604051611f9f919061431c565b602060405180830381855afa158015611fba573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614612044576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161203b9061437c565b60405180910390fd5b60035f808a81526020019081526020015f205f0160186101000a81548160ff0219169083600381111561207a57612079613c78565b5b02179055507fac509cdcc7ddb189f81fff6f4824f5c95076e64c3bdce542c50feaa6779afd73886040516120ae9190614437565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff1663f242432a3033868c6040518563ffffffff1660e01b81526004016120f994939291906149d7565b5f604051808303815f87803b158015612110575f80fd5b505af1158015612122573d5f803e3d5ffd5b50505050505050505050505050565b5f6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161216490614ede565b60405180910390fd5b6001600381111561218157612180613c78565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff1660038111156121b3576121b2613c78565b5b146121f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016121ea9061419e565b60405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612261576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161225890614f46565b60405180910390fd5b5f600333878760028860405160200161227a9190614a2d565b604051602081830303815290604052604051612296919061431c565b602060405180830381855afa1580156122b1573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906122d49190614a5b565b87876040516020016122eb96959493929190614241565b604051602081830303815290604052604051612307919061431c565b602060405180830381855afa158015612322573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146123ac576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016123a39061437c565b60405180910390fd5b60025f808981526020019081526020015f205f0160186101000a81548160ff021916908360038111156123e2576123e1613c78565b5b02179055507fad62ed075fe8969df63026f45152d6e996a0697a736a8de92ee85ae9c9958cf0876040516124169190614437565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b815260040161245f9392919061445f565b5f604051808303815f87803b158015612476575f80fd5b505af1158015612488573d5f803e3d5ffd5b505050505050505050505050565b600260048111156124aa576124a9613c78565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff1660048111156124dd576124dc613c78565b5b1461251d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161251490614fd4565b60405180910390fd5b5f600387873388886002896040516020016125389190614a2d565b604051602081830303815290604052604051612554919061431c565b602060405180830381855afa15801561256f573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906125929190614a5b565b886040516020016125a99796959493929190614494565b6040516020818303038152906040526040516125c5919061431c565b602060405180830381855afa1580156125e0573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461266b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016126629061437c565b60405180910390fd5b600360015f8a81526020019081526020015f205f01601c6101000a81548160ff021916908360048111156126a2576126a1613c78565b5b02179055507f0d0da0df275f85bed3a5fe7ae79f3559341a3f9ccd8e010133438135bda00a8788846040516126d8929190614a86565b60405180910390a15f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036127c0573373ffffffffffffffffffffffffffffffffffffffff166108fc8890811502906040515f60405180830381858888f19350505050158015612756573d5f803e3d5ffd5b507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166108fc8790811502906040515f60405180830381858888f193505050501580156127ba573d5f803e3d5ffd5b5061283c565b5f8290506127ef33898373ffffffffffffffffffffffffffffffffffffffff1661345c9092919063ffffffff16565b61283a7f0000000000000000000000000000000000000000000000000000000000000000888373ffffffffffffffffffffffffffffffffffffffff1661345c9092919063ffffffff16565b505b5050505050505050565b5f600481111561285957612858613c78565b5b60015f8b81526020019081526020015f205f01601c9054906101000a900460ff16600481111561288c5761288b613c78565b5b146128cc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016128c390615062565b60405180910390fd5b5f881161290e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612905906150ca565b60405180910390fd5b5f8711612950576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161294790615132565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16036129be576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129b590614d27565b60405180910390fd5b5f60038989883389898d6040516020016129de9796959493929190614494565b6040516020818303038152906040526040516129fa919061431c565b602060405180830381855afa158015612a15573d5f803e3d5ffd5b5050506040515160601b90506040518060800160405280826bffffffffffffffffffffffff191681526020018463ffffffff1681526020018363ffffffff16815260200160016004811115612a6d57612a6c613c78565b5b81525060015f8c81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548163ffffffff021916908363ffffffff1602179055506060820151815f01601c6101000a81548160ff02191690836004811115612b2857612b27613c78565b5b02179055509050507ffc6cdccd1d98ded12074a9ebc7f6ab74fed1814ff57f4fb5202464d8938bd9358a604051612b5f9190614437565b60405180910390a15f879050612ba333308b8d612b7c9190614ada565b8473ffffffffffffffffffffffffffffffffffffffff166134db909392919063ffffffff16565b5050505050505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b5f602052805f5260405f205f91509050805f015f9054906101000a900460601b90805f0160149054906101000a900463ffffffff1690805f0160189054906101000a900460ff16905083565b5f808383810190612c31919061463d565b90505f73ffffffffffffffffffffffffffffffffffffffff16816020015173ffffffffffffffffffffffffffffffffffffffff1603612ca5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c9c906146b2565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816040015173ffffffffffffffffffffffffffffffffffffffff1603612d17576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612d0e9061471a565b60405180910390fd5b806040015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612d89576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612d80906147a8565b60405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614612df7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612dee90614810565b60405180910390fd5b5f8511612e39576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612e309061519a565b60405180910390fd5b5f6003811115612e4c57612e4b613c78565b5b5f80835f015181526020019081526020015f205f0160189054906101000a900460ff166003811115612e8157612e80613c78565b5b14612ec1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612eb890615228565b60405180910390fd5b612ece816020015161344b565b15612f0e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612f0590614906565b60405180910390fd5b5f60038260200151898460600151856080015186604001518c8c604051602001612f3e9796959493929190614924565b604051602081830303815290604052604051612f5a919061431c565b602060405180830381855afa158015612f75573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018360a0015163ffffffff16815260200160016003811115612fc557612fc4613c78565b5b8152505f80845f015181526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548160ff0219169083600381111561305c5761305b613c78565b5b02179055509050507ff1dc11bbb6d7542c4267ecf1d370ff4c7092518633ecae9939e8488f4e53d2ad825f01516040516130969190614437565b60405180910390a163f23a6e6160e01b925050509695505050505050565b600160038111156130c8576130c7613c78565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff1660038111156130fa576130f9613c78565b5b1461313a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016131319061419e565b60405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146131a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161319f90614f46565b60405180910390fd5b5f60033387876002886040516020016131c19190614a2d565b6040516020818303038152906040526040516131dd919061431c565b602060405180830381855afa1580156131f8573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061321b9190614a5b565b87878d6040516020016132349796959493929190614924565b604051602081830303815290604052604051613250919061431c565b602060405180830381855afa15801561326b573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146132f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016132ec9061437c565b60405180910390fd5b60025f808a81526020019081526020015f205f0160186101000a81548160ff0219169083600381111561332b5761332a613c78565b5b02179055507fad62ed075fe8969df63026f45152d6e996a0697a736a8de92ee85ae9c9958cf08860405161335f9190614437565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff1663f242432a3033868c6040518563ffffffff1660e01b81526004016133aa94939291906149d7565b5f604051808303815f87803b1580156133c1575f80fd5b505af11580156133d3573d5f803e3d5ffd5b50505050505050505050505050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f80823b90505f8111915050919050565b6134d6838473ffffffffffffffffffffffffffffffffffffffff1663a9059cbb858560405160240161348f929190615246565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061355d565b505050565b613557848573ffffffffffffffffffffffffffffffffffffffff166323b872dd8686866040516024016135109392919061445f565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061355d565b50505050565b5f613587828473ffffffffffffffffffffffffffffffffffffffff166135f290919063ffffffff16565b90505f8151141580156135ab5750808060200190518101906135a99190615297565b155b156135ed57826040517f5274afe70000000000000000000000000000000000000000000000000000000081526004016135e49190613ff4565b60405180910390fd5b505050565b60606135ff83835f613607565b905092915050565b60608147101561364e57306040517fcd7860590000000000000000000000000000000000000000000000000000000081526004016136459190613ff4565b60405180910390fd5b5f808573ffffffffffffffffffffffffffffffffffffffff168486604051613676919061431c565b5f6040518083038185875af1925050503d805f81146136b0576040519150601f19603f3d011682016040523d82523d5f602084013e6136b5565b606091505b50915091506136c58683836136d0565b925050509392505050565b6060826136e5576136e08261375d565b613755565b5f825114801561370b57505f8473ffffffffffffffffffffffffffffffffffffffff163b145b1561374d57836040517f9996b3150000000000000000000000000000000000000000000000000000000081526004016137449190613ff4565b60405180910390fd5b819050613756565b5b9392505050565b5f8151111561376f5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6137e6816137b2565b81146137f0575f80fd5b50565b5f81359050613801816137dd565b92915050565b5f6020828403121561381c5761381b6137aa565b5b5f613829848285016137f3565b91505092915050565b5f8115159050919050565b61384681613832565b82525050565b5f60208201905061385f5f83018461383d565b92915050565b5f819050919050565b61387781613865565b8114613881575f80fd5b50565b5f813590506138928161386e565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6138c182613898565b9050919050565b6138d1816138b7565b81146138db575f80fd5b50565b5f813590506138ec816138c8565b92915050565b5f819050919050565b613904816138f2565b811461390e575f80fd5b50565b5f8135905061391f816138fb565b92915050565b5f805f805f8060c0878903121561393f5761393e6137aa565b5b5f61394c89828a01613884565b965050602061395d89828a016138de565b955050604061396e89828a01613884565b945050606061397f89828a01613884565b935050608061399089828a016138de565b92505060a06139a189828a01613911565b9150509295509295509295565b5f805f805f805f60e0888a0312156139c9576139c86137aa565b5b5f6139d68a828b01613884565b97505060206139e78a828b01613911565b96505060406139f88a828b01613911565b9550506060613a098a828b016138de565b9450506080613a1a8a828b01613884565b93505060a0613a2b8a828b01613884565b92505060c0613a3c8a828b016138de565b91505092959891949750929550565b5f80fd5b5f80fd5b5f80fd5b5f8083601f840112613a6c57613a6b613a4b565b5b8235905067ffffffffffffffff811115613a8957613a88613a4f565b5b602083019150836001820283011115613aa557613aa4613a53565b5b9250929050565b5f805f805f60808688031215613ac557613ac46137aa565b5b5f613ad2888289016138de565b9550506020613ae3888289016138de565b9450506040613af488828901613911565b935050606086013567ffffffffffffffff811115613b1557613b146137ae565b5b613b2188828901613a57565b92509250509295509295909350565b613b39816137b2565b82525050565b5f602082019050613b525f830184613b30565b92915050565b5f805f805f805f60e0888a031215613b7357613b726137aa565b5b5f613b808a828b01613884565b9750506020613b918a828b01613911565b9650506040613ba28a828b016138de565b9550506060613bb38a828b01613884565b9450506080613bc48a828b01613884565b93505060a0613bd58a828b016138de565b92505060c0613be68a828b01613911565b91505092959891949750929550565b5f60208284031215613c0a57613c096137aa565b5b5f613c1784828501613884565b91505092915050565b5f7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b613c5481613c20565b82525050565b5f63ffffffff82169050919050565b613c7281613c5a565b82525050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60058110613cb657613cb5613c78565b5b50565b5f819050613cc682613ca5565b919050565b5f613cd582613cb9565b9050919050565b613ce581613ccb565b82525050565b5f608082019050613cfe5f830187613c4b565b613d0b6020830186613c69565b613d186040830185613c69565b613d256060830184613cdc565b95945050505050565b613d3781613c5a565b8114613d41575f80fd5b50565b5f81359050613d5281613d2e565b92915050565b5f805f805f805f60e0888a031215613d7357613d726137aa565b5b5f613d808a828b01613884565b9750506020613d918a828b01613911565b9650506040613da28a828b016138de565b9550506060613db38a828b01613884565b9450506080613dc48a828b01613884565b93505060a0613dd58a828b01613d44565b92505060c0613de68a828b01613d44565b91505092959891949750929550565b5f8083601f840112613e0a57613e09613a4b565b5b8235905067ffffffffffffffff811115613e2757613e26613a4f565b5b602083019150836020820283011115613e4357613e42613a53565b5b9250929050565b5f805f805f805f8060a0898b031215613e6657613e656137aa565b5b5f613e738b828c016138de565b9850506020613e848b828c016138de565b975050604089013567ffffffffffffffff811115613ea557613ea46137ae565b5b613eb18b828c01613df5565b9650965050606089013567ffffffffffffffff811115613ed457613ed36137ae565b5b613ee08b828c01613df5565b9450945050608089013567ffffffffffffffff811115613f0357613f026137ae565b5b613f0f8b828c01613a57565b92509250509295985092959890939650565b5f805f805f805f805f6101208a8c031215613f3f57613f3e6137aa565b5b5f613f4c8c828d01613884565b9950506020613f5d8c828d01613911565b9850506040613f6e8c828d01613911565b9750506060613f7f8c828d016138de565b9650506080613f908c828d016138de565b95505060a0613fa18c828d01613884565b94505060c0613fb28c828d01613884565b93505060e0613fc38c828d01613d44565b925050610100613fd58c828d01613d44565b9150509295985092959850929598565b613fee816138b7565b82525050565b5f6020820190506140075f830184613fe5565b92915050565b6004811061401e5761401d613c78565b5b50565b5f81905061402e8261400d565b919050565b5f61403d82614021565b9050919050565b61404d81614033565b82525050565b5f6060820190506140665f830186613c4b565b6140736020830185613c69565b6140806040830184614044565b949350505050565b5f805f805f8060a087890312156140a2576140a16137aa565b5b5f6140af89828a016138de565b96505060206140c089828a016138de565b95505060406140d189828a01613911565b94505060606140e289828a01613911565b935050608087013567ffffffffffffffff811115614103576141026137ae565b5b61410f89828a01613a57565b92509250509295509295509295565b5f82825260208201905092915050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520505f8201527f61796d656e7453656e7400000000000000000000000000000000000000000000602082015250565b5f614188602a8361411e565b91506141938261412e565b604082019050919050565b5f6020820190508181035f8301526141b58161417c565b9050919050565b5f8160601b9050919050565b5f6141d2826141bc565b9050919050565b5f6141e3826141c8565b9050919050565b6141fb6141f6826138b7565b6141d9565b82525050565b5f819050919050565b61421b61421682613865565b614201565b82525050565b5f819050919050565b61423b614236826138f2565b614221565b82525050565b5f61424c82896141ea565b60148201915061425c82886141ea565b60148201915061426c828761420a565b60208201915061427c828661420a565b60208201915061428c82856141ea565b60148201915061429c828461422a565b602082019150819050979650505050505050565b5f81519050919050565b5f81905092915050565b5f5b838110156142e15780820151818401526020810190506142c6565b5f8484015250505050565b5f6142f6826142b0565b61430081856142ba565b93506143108185602086016142c4565b80840191505092915050565b5f61432782846142ec565b915081905092915050565b7f496e76616c6964207061796d656e7448617368000000000000000000000000005f82015250565b5f61436660138361411e565b915061437182614332565b602082019050919050565b5f6020820190508181035f8301526143938161435a565b9050919050565b7f43757272656e742074696d657374616d70206469646e277420657863656564205f8201527f7061796d656e7420726566756e64206c6f636b2074696d650000000000000000602082015250565b5f6143f460388361411e565b91506143ff8261439a565b604082019050919050565b5f6020820190508181035f830152614421816143e8565b9050919050565b61443181613865565b82525050565b5f60208201905061444a5f830184614428565b92915050565b614459816138f2565b82525050565b5f6060820190506144725f830186613fe5565b61447f6020830185613fe5565b61448c6040830184614450565b949350505050565b5f61449f828a61422a565b6020820191506144af828961422a565b6020820191506144bf82886141ea565b6014820191506144cf82876141ea565b6014820191506144df828661420a565b6020820191506144ef828561420a565b6020820191506144ff82846141ea565b60148201915081905098975050505050505050565b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61455e82614518565b810181811067ffffffffffffffff8211171561457d5761457c614528565b5b80604052505050565b5f61458f6137a1565b905061459b8282614555565b919050565b5f60c082840312156145b5576145b4614514565b5b6145bf60c0614586565b90505f6145ce84828501613884565b5f8301525060206145e1848285016138de565b60208301525060406145f5848285016138de565b604083015250606061460984828501613884565b606083015250608061461d84828501613884565b60808301525060a061463184828501613d44565b60a08301525092915050565b5f60c08284031215614652576146516137aa565b5b5f61465f848285016145a0565b91505092915050565b7f54616b6572206d757374206e6f74206265207a65726f206164647265737300005f82015250565b5f61469c601e8361411e565b91506146a782614668565b602082019050919050565b5f6020820190508181035f8301526146c981614690565b9050919050565b7f546f6b656e206d757374206e6f74206265207a65726f206164647265737300005f82015250565b5f614704601e8361411e565b915061470f826146d0565b602082019050919050565b5f6020820190508181035f830152614731816146f8565b9050919050565b7f546f6b656e206164647265737320646f6573206e6f74206d617463682073656e5f8201527f6465720000000000000000000000000000000000000000000000000000000000602082015250565b5f61479260238361411e565b915061479d82614738565b604082019050919050565b5f6020820190508181035f8301526147bf81614786565b9050919050565b7f4f70657261746f72206d757374206265207468652073656e64657200000000005f82015250565b5f6147fa601b8361411e565b9150614805826147c6565b602082019050919050565b5f6020820190508181035f830152614827816147ee565b9050919050565b7f4d616b657220455243373231207061796d656e74206d75737420626520556e695f8201527f6e697469616c697a656400000000000000000000000000000000000000000000602082015250565b5f614888602a8361411e565b91506148938261482e565b604082019050919050565b5f6020820190508181035f8301526148b58161487c565b9050919050565b7f54616b65722063616e6e6f74206265206120636f6e74726163740000000000005f82015250565b5f6148f0601a8361411e565b91506148fb826148bc565b602082019050919050565b5f6020820190508181035f83015261491d816148e4565b9050919050565b5f61492f828a6141ea565b60148201915061493f82896141ea565b60148201915061494f828861420a565b60208201915061495f828761420a565b60208201915061496f82866141ea565b60148201915061497f828561422a565b60208201915061498f828461422a565b60208201915081905098975050505050505050565b5f82825260208201905092915050565b50565b5f6149c25f836149a4565b91506149cd826149b4565b5f82019050919050565b5f60a0820190506149ea5f830187613fe5565b6149f76020830186613fe5565b614a046040830185614450565b614a116060830184614450565b8181036080830152614a22816149b7565b905095945050505050565b5f614a38828461420a565b60208201915081905092915050565b5f81519050614a558161386e565b92915050565b5f60208284031215614a7057614a6f6137aa565b5b5f614a7d84828501614a47565b91505092915050565b5f604082019050614a995f830185614428565b614aa66020830184614428565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f614ae4826138f2565b9150614aef836138f2565b9250828201905080821115614b0757614b06614aad565b5b92915050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520505f8201527f61796d656e7453656e74206f722054616b6572417070726f7665640000000000602082015250565b5f614b67603b8361411e565b9150614b7282614b0d565b604082019050919050565b5f6020820190508181035f830152614b9481614b5b565b9050919050565b7f43757272656e742074696d657374616d70206469646e277420657863656564205f8201527f7061796d656e74207072652d617070726f7665206c6f636b2074696d65000000602082015250565b5f614bf5603d8361411e565b9150614c0082614b9b565b604082019050919050565b5f6020820190508181035f830152614c2281614be9565b9050919050565b7f54616b6572207061796d656e7420697320616c726561647920696e697469616c5f8201527f697a656400000000000000000000000000000000000000000000000000000000602082015250565b5f614c8360248361411e565b9150614c8e82614c29565b604082019050919050565b5f6020820190508181035f830152614cb081614c77565b9050919050565b7f5265636569766572206d757374206e6f74206265207a65726f206164647265735f8201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b5f614d1160218361411e565b9150614d1c82614cb7565b604082019050919050565b5f6020820190508181035f830152614d3e81614d05565b9050919050565b7f4554482076616c7565206d7573742062652067726561746572207468616e207a5f8201527f65726f0000000000000000000000000000000000000000000000000000000000602082015250565b5f614d9f60238361411e565b9150614daa82614d45565b604082019050919050565b5f6020820190508181035f830152614dcc81614d93565b9050919050565b7f4554482076616c7565206d7573742062652067726561746572207468616e20645f8201527f6578206665650000000000000000000000000000000000000000000000000000602082015250565b5f614e2d60268361411e565b9150614e3882614dd3565b604082019050919050565b5f6020820190508181035f830152614e5a81614e21565b9050919050565b5f614e6b826138f2565b9150614e76836138f2565b9250828203905081811115614e8e57614e8d614aad565b5b92915050565b7f4261746368207472616e7366657273206e6f7420737570706f727465640000005f82015250565b5f614ec8601d8361411e565b9150614ed382614e94565b602082019050919050565b5f6020820190508181035f830152614ef581614ebc565b9050919050565b7f43616c6c6572206d75737420626520616e20454f4100000000000000000000005f82015250565b5f614f3060158361411e565b9150614f3b82614efc565b602082019050919050565b5f6020820190508181035f830152614f5d81614f24565b9050919050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520545f8201527f616b6572417070726f7665640000000000000000000000000000000000000000602082015250565b5f614fbe602c8361411e565b9150614fc982614f64565b604082019050919050565b5f6020820190508181035f830152614feb81614fb2565b9050919050565b7f4552433230207632207061796d656e7420697320616c726561647920696e69745f8201527f69616c697a656400000000000000000000000000000000000000000000000000602082015250565b5f61504c60278361411e565b915061505782614ff2565b604082019050919050565b5f6020820190508181035f83015261507981615040565b9050919050565b7f416d6f756e74206d757374206e6f74206265207a65726f0000000000000000005f82015250565b5f6150b460178361411e565b91506150bf82615080565b602082019050919050565b5f6020820190508181035f8301526150e1816150a8565b9050919050565b7f44657820666565206d757374206e6f74206265207a65726f00000000000000005f82015250565b5f61511c60188361411e565b9150615127826150e8565b602082019050919050565b5f6020820190508181035f83015261514981615110565b9050919050565b7f56616c7565206d7573742062652067726561746572207468616e2030000000005f82015250565b5f615184601c8361411e565b915061518f82615150565b602082019050919050565b5f6020820190508181035f8301526151b181615178565b9050919050565b7f4d616b65722045524331313535207061796d656e74206d75737420626520556e5f8201527f696e697469616c697a6564000000000000000000000000000000000000000000602082015250565b5f615212602b8361411e565b915061521d826151b8565b604082019050919050565b5f6020820190508181035f83015261523f81615206565b9050919050565b5f6040820190506152595f830185613fe5565b6152666020830184614450565b9392505050565b61527681613832565b8114615280575f80fd5b50565b5f815190506152918161526d565b92915050565b5f602082840312156152ac576152ab6137aa565b5b5f6152b984828501615283565b9150509291505056fea264697066735822122077b4b2078ef3c6b5011576148b3629aef4d5bdf826c80bb1e059ab90e714e30264736f6c63430008180033"; pub trait CoinDockerOps { From f937bb709f1d9b97c2a5da5dd90b9e7363623cc8 Mon Sep 17 00:00:00 2001 From: laruh Date: Mon, 11 Mar 2024 19:35:41 +0700 Subject: [PATCH 11/80] add some values and checks in send_nft_maker_payment_v2_impl func --- mm2src/coins/eth.rs | 40 ++++++++++++++++++++++++++++++++++++---- mm2src/coins/lp_coins.rs | 6 +++--- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 0bf81da4d2..b8197ccfc6 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -71,6 +71,7 @@ use serialization::{CompactInteger, Serializable, Stream}; use sha3::{Digest, Keccak256}; use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; +use std::num::TryFromIntError; use std::ops::Deref; #[cfg(not(target_arch = "wasm32"))] use std::path::PathBuf; use std::str::from_utf8; @@ -6294,8 +6295,8 @@ impl NftAssocTypes for EthCoin { type TokenIdParseError = NftAssocTypesError; type Chain = Chain; type ChainParseError = NftAssocTypesError; - type Contract = ContractType; - type ContractParseError = NftAssocTypesError; + type ContractType = ContractType; + type ContractTypeParseError = NftAssocTypesError; fn parse_token_contract_address( &self, @@ -6315,8 +6316,8 @@ impl NftAssocTypes for EthCoin { Chain::from_ticker(chain_str).map_err(NftAssocTypesError::from) } - fn parse_contract(&self, contract: &[u8]) -> Result { - let contract_str = from_utf8(contract).map_err(|e| NftAssocTypesError::Utf8Error(e.to_string()))?; + fn parse_contract_type(&self, contract_type: &[u8]) -> Result { + let contract_str = from_utf8(contract_type).map_err(|e| NftAssocTypesError::Utf8Error(e.to_string()))?; ContractType::from_str(contract_str).map_err(NftAssocTypesError::from) } } @@ -6364,8 +6365,39 @@ impl EthCoin { &self, args: SendNftMakerPaymentArgs<'_, Self>, ) -> Result { + let contract_type = self.parse_contract_type(args.contract_type)?; + match contract_type { + ContractType::Erc721 => { + if args.amount != BigDecimal::from(1) { + return Err(TransactionErr::Plain("ERC-721 amount must be 1".to_string())); + } + }, + ContractType::Erc1155 => { + if !is_positive_integer(&args.amount) { + return Err(TransactionErr::Plain( + "ERC-1155 amount must be a positive integer".to_string(), + )); + } + }, + } let _taker_address = addr_from_raw_pubkey(args.taker_pub).map_err(TransactionErr::Plain)?; let _swap_contract_address = self.parse_token_contract_address(args.swap_contract_address)?; + let time_lock_u32 = args + .time_lock + .try_into() + .map_err(|e: TryFromIntError| TransactionErr::Plain(e.to_string()))?; + let _id = self.etomic_swap_id(time_lock_u32, args.maker_secret_hash); + + let _time_lock_u256 = U256::from(args.time_lock); + let _gas = U256::from(ETH_GAS); + let _token_id = self.parse_token_id(args.token_id)?; + + // todo re-check do we need changes in sign_and_send_transaction method for nft broadcast + todo!() } } + +/// Utility function example to check if BigDecimal is a positive integer +#[inline(always)] +fn is_positive_integer(amount: &BigDecimal) -> bool { amount == &amount.with_scale(0) && amount > &BigDecimal::from(0) } diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index e82d119379..825c5f04a3 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -1502,8 +1502,8 @@ pub trait NftAssocTypes { type TokenIdParseError: fmt::Debug + Send + fmt::Display; type Chain: ToBytes + Send + Sync; type ChainParseError: fmt::Debug + Send + fmt::Display; - type Contract: ToBytes + Send + Sync; - type ContractParseError: fmt::Debug + Send + fmt::Display; + type ContractType: ToBytes + Send + Sync; + type ContractTypeParseError: fmt::Debug + Send + fmt::Display; fn parse_token_contract_address( &self, @@ -1514,7 +1514,7 @@ pub trait NftAssocTypes { fn parse_chain(&self, chain: &[u8]) -> Result; - fn parse_contract(&self, contract: &[u8]) -> Result; + fn parse_contract_type(&self, contract_type: &[u8]) -> Result; } pub struct SendMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { From 8484e0e1c503ee088443cd5d56c28517fd910082 Mon Sep 17 00:00:00 2001 From: laruh Date: Mon, 11 Mar 2024 20:51:30 +0700 Subject: [PATCH 12/80] rename coin in nft_dev_conf --- mm2src/coins/eth.rs | 2 +- mm2src/mm2_test_helpers/src/for_tests.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index b8197ccfc6..a072b89bf7 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -6398,6 +6398,6 @@ impl EthCoin { } } -/// Utility function example to check if BigDecimal is a positive integer +/// function to check if BigDecimal is a positive integer #[inline(always)] fn is_positive_integer(amount: &BigDecimal) -> bool { amount == &amount.with_scale(0) && amount > &BigDecimal::from(0) } diff --git a/mm2src/mm2_test_helpers/src/for_tests.rs b/mm2src/mm2_test_helpers/src/for_tests.rs index df3e12f314..439a33813f 100644 --- a/mm2src/mm2_test_helpers/src/for_tests.rs +++ b/mm2src/mm2_test_helpers/src/for_tests.rs @@ -816,8 +816,8 @@ pub fn erc20_dev_conf(contract_address: &str) -> Json { /// global NFT configuration used for dockerized Geth dev node pub fn nft_dev_conf() -> Json { json!({ - "coin": "ERC20DEV", - "name": "erc20dev", + "coin": "NFT_ETH", + "name": "nftdev", "chain_id": 1337, "mm2": 1, "derivation_path": "m/44'/60'", From 53ad64c7ec7f496d776455da9988f489dc0c72b4 Mon Sep 17 00:00:00 2001 From: laruh Date: Tue, 12 Mar 2024 20:15:28 +0700 Subject: [PATCH 13/80] WIP send_nft_maker_payment_v2_impl: added some validations, prepared data for Erc1155 transfer --- mm2src/coins/eth.rs | 84 ++++++++++++++++++++++++++++++---------- mm2src/coins/lp_coins.rs | 20 ++++++++-- mm2src/coins/utxo/slp.rs | 6 ++- 3 files changed, 83 insertions(+), 27 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index a072b89bf7..446265aa10 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -2265,7 +2265,7 @@ impl MarketCoinOps for EthCoin { EthCoinType::Eth => get_function_name("ethPayment", args.watcher_reward), EthCoinType::Erc20 { .. } => get_function_name("erc20Payment", args.watcher_reward), EthCoinType::Nft { .. } => { - return Box::new(futures01::future::err(TransactionErr::NftProtocolNotSupported(ERRL!( + return Box::new(futures01::future::err(TransactionErr::ProtocolNotSupported(ERRL!( "Nft Protocol is not supported yet!" )))) }, @@ -3458,7 +3458,7 @@ impl EthCoin { self.sign_and_send_transaction(0.into(), Action::Call(*token_addr), data, U256::from(210_000)) }, EthCoinType::Nft { .. } => { - return Box::new(futures01::future::err(TransactionErr::NftProtocolNotSupported(ERRL!( + return Box::new(futures01::future::err(TransactionErr::ProtocolNotSupported(ERRL!( "Nft Protocol is not supported yet!" )))) }, @@ -3623,7 +3623,7 @@ impl EthCoin { })) }, EthCoinType::Nft { .. } => { - return Box::new(futures01::future::err(TransactionErr::NftProtocolNotSupported(ERRL!( + return Box::new(futures01::future::err(TransactionErr::ProtocolNotSupported(ERRL!( "Nft Protocol is not supported yet!" )))) }, @@ -3744,7 +3744,7 @@ impl EthCoin { ) }, EthCoinType::Nft { .. } => { - return Box::new(futures01::future::err(TransactionErr::NftProtocolNotSupported(ERRL!( + return Box::new(futures01::future::err(TransactionErr::ProtocolNotSupported(ERRL!( "Nft Protocol is not supported yet!" )))) }, @@ -3869,7 +3869,7 @@ impl EthCoin { ) }, EthCoinType::Nft { .. } => { - return Box::new(futures01::future::err(TransactionErr::NftProtocolNotSupported(ERRL!( + return Box::new(futures01::future::err(TransactionErr::ProtocolNotSupported(ERRL!( "Nft Protocol is not supported yet!" )))) }, @@ -3991,7 +3991,7 @@ impl EthCoin { ) }, EthCoinType::Nft { .. } => { - return Box::new(futures01::future::err(TransactionErr::NftProtocolNotSupported(ERRL!( + return Box::new(futures01::future::err(TransactionErr::ProtocolNotSupported(ERRL!( "Nft Protocol is not supported yet!" )))) }, @@ -4114,7 +4114,7 @@ impl EthCoin { ) }, EthCoinType::Nft { .. } => { - return Box::new(futures01::future::err(TransactionErr::NftProtocolNotSupported(ERRL!( + return Box::new(futures01::future::err(TransactionErr::ProtocolNotSupported(ERRL!( "Nft Protocol is not supported yet!" )))) }, @@ -4364,7 +4364,7 @@ impl EthCoin { EthCoinType::Eth => return TX_PLAIN_ERR!("'approve' is expected to be call for ERC20 coins only"), EthCoinType::Erc20 { token_addr, .. } => token_addr, EthCoinType::Nft { .. } => { - return Err(TransactionErr::NftProtocolNotSupported(ERRL!( + return Err(TransactionErr::ProtocolNotSupported(ERRL!( "Nft Protocol is not supported yet!" ))) }, @@ -6367,11 +6367,6 @@ impl EthCoin { ) -> Result { let contract_type = self.parse_contract_type(args.contract_type)?; match contract_type { - ContractType::Erc721 => { - if args.amount != BigDecimal::from(1) { - return Err(TransactionErr::Plain("ERC-721 amount must be 1".to_string())); - } - }, ContractType::Erc1155 => { if !is_positive_integer(&args.amount) { return Err(TransactionErr::Plain( @@ -6379,22 +6374,69 @@ impl EthCoin { )); } }, + ContractType::Erc721 => { + if args.amount != BigDecimal::from(1) { + return Err(TransactionErr::Plain("ERC-721 amount must be 1".to_string())); + } + }, + } + if args.taker_secret_hash.len() != 32 { + return Err(TransactionErr::Plain("taker_secret_hash must be 32 bytes".to_string())); } - let _taker_address = addr_from_raw_pubkey(args.taker_pub).map_err(TransactionErr::Plain)?; - let _swap_contract_address = self.parse_token_contract_address(args.swap_contract_address)?; + if args.maker_secret_hash.len() != 32 { + return Err(TransactionErr::Plain("maker_secret_hash must be 32 bytes".to_string())); + } + + let taker_address = addr_from_raw_pubkey(args.taker_pub).map_err(TransactionErr::Plain)?; + let swap_contract_address = self.parse_token_contract_address(args.swap_contract_address)?; let time_lock_u32 = args .time_lock .try_into() .map_err(|e: TryFromIntError| TransactionErr::Plain(e.to_string()))?; - let _id = self.etomic_swap_id(time_lock_u32, args.maker_secret_hash); - - let _time_lock_u256 = U256::from(args.time_lock); + let id = self.etomic_swap_id(time_lock_u32, args.maker_secret_hash); let _gas = U256::from(ETH_GAS); - let _token_id = self.parse_token_id(args.token_id)?; + let token_id = self.parse_token_id(args.token_id)?; + let token_id_u256 = + U256::from_dec_str(&token_id.to_string()).map_err(|e| NumConversError::new(e.to_string()))?; + let amount_u256 = + U256::from_dec_str(&args.amount.to_string()).map_err(|e| NumConversError::new(e.to_string()))?; - // todo re-check do we need changes in sign_and_send_transaction method for nft broadcast + // todo after getting data for sign and send in EthCoinType::Eth match: + // re-check do we need changes in sign_and_send_transaction function for nft broadcast to etomic swap address. + // UPD: Yes, changes are needed as sign_and_send_transaction returns Box type. - todo!() + match &self.coin_type { + EthCoinType::Eth => match contract_type { + ContractType::Erc1155 => { + let function = ERC1155_CONTRACT.function("safeTransferFrom")?; + let additional_data = ethabi::encode(&[ + Token::FixedBytes(id), + Token::Address(taker_address), + Token::Address(swap_contract_address), + Token::FixedBytes(args.taker_secret_hash.to_vec()), + Token::FixedBytes(args.maker_secret_hash.to_vec()), + Token::Uint(U256::from(time_lock_u32)), + ]); + let _data = function.encode_input(&[ + Token::Address(self.my_address), + Token::Address(swap_contract_address), + Token::Uint(token_id_u256), + Token::Uint(amount_u256), + Token::Bytes(additional_data), + ])?; + todo!() + }, + ContractType::Erc721 => { + todo!() + }, + }, + EthCoinType::Erc20 { .. } => Err(TransactionErr::ProtocolNotSupported( + "ERC20 Protocol is not supported for NFT Swaps".to_string(), + )), + EthCoinType::Nft { .. } => Err(TransactionErr::ProtocolNotSupported( + "Nft Protocol is not supported yet for NFT Swaps!".to_string(), + )), + } } } diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 825c5f04a3..e86c652e36 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -641,8 +641,10 @@ pub enum TransactionErr { TxRecoverable(TransactionEnum, String), /// Simply for plain error messages. Plain(String), - NftProtocolNotSupported(String), + ProtocolNotSupported(String), NftAssocTypesError(String), + NumConversError(NumConversError), + AbiError(String), } impl TransactionErr { @@ -661,8 +663,10 @@ impl TransactionErr { match self { TransactionErr::TxRecoverable(_, err) => err.to_string(), TransactionErr::Plain(err) - | TransactionErr::NftProtocolNotSupported(err) - | TransactionErr::NftAssocTypesError(err) => err.to_string(), + | TransactionErr::ProtocolNotSupported(err) + | TransactionErr::NftAssocTypesError(err) + | TransactionErr::AbiError(err) => err.to_string(), + TransactionErr::NumConversError(err) => err.to_string(), } } } @@ -675,6 +679,14 @@ impl From for TransactionErr { fn from(e: NftAssocTypesError) -> Self { TransactionErr::NftAssocTypesError(e.to_string()) } } +impl From for TransactionErr { + fn from(e: NumConversError) -> Self { TransactionErr::NumConversError(e) } +} + +impl From for TransactionErr { + fn from(e: ethabi::Error) -> Self { TransactionErr::AbiError(e.to_string()) } +} + #[derive(Debug, PartialEq)] pub enum FoundSwapTxSpend { Spent(TransactionEnum), @@ -2405,7 +2417,7 @@ impl TradePreimageError { } /// The reason of unsuccessful conversion of two internal numbers, e.g. `u64` from `BigNumber`. -#[derive(Debug, Display)] +#[derive(Clone, Debug, Display)] pub struct NumConversError(String); impl From for NumConversError { diff --git a/mm2src/coins/utxo/slp.rs b/mm2src/coins/utxo/slp.rs index fc080ed74a..f242fd53dd 100644 --- a/mm2src/coins/utxo/slp.rs +++ b/mm2src/coins/utxo/slp.rs @@ -2172,8 +2172,10 @@ mod slp_tests { let err = match tx_err.clone() { TransactionErr::TxRecoverable(_tx, err) => err, TransactionErr::Plain(err) - | TransactionErr::NftProtocolNotSupported(err) - | TransactionErr::NftAssocTypesError(err) => err, + | TransactionErr::ProtocolNotSupported(err) + | TransactionErr::NftAssocTypesError(err) + | TransactionErr::AbiError(err) => err, + TransactionErr::NumConversError(err) => err.to_string(), }; println!("{:?}", err); From 66fceade0eec5a26603d0a2e1c40ab6ab2296554 Mon Sep 17 00:00:00 2001 From: laruh Date: Wed, 13 Mar 2024 14:36:23 +0700 Subject: [PATCH 14/80] polish send_nft_maker_payment_v2_impl func --- mm2src/coins/eth.rs | 98 ++++++++++++++++++++++++++++----------------- 1 file changed, 61 insertions(+), 37 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 446265aa10..958fb84337 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -6366,67 +6366,46 @@ impl EthCoin { args: SendNftMakerPaymentArgs<'_, Self>, ) -> Result { let contract_type = self.parse_contract_type(args.contract_type)?; - match contract_type { - ContractType::Erc1155 => { - if !is_positive_integer(&args.amount) { - return Err(TransactionErr::Plain( - "ERC-1155 amount must be a positive integer".to_string(), - )); - } - }, - ContractType::Erc721 => { - if args.amount != BigDecimal::from(1) { - return Err(TransactionErr::Plain("ERC-721 amount must be 1".to_string())); - } - }, - } - if args.taker_secret_hash.len() != 32 { - return Err(TransactionErr::Plain("taker_secret_hash must be 32 bytes".to_string())); - } - if args.maker_secret_hash.len() != 32 { - return Err(TransactionErr::Plain("maker_secret_hash must be 32 bytes".to_string())); - } + self.validate_payment_args(&args, &contract_type) + .map_err(TransactionErr::Plain)?; let taker_address = addr_from_raw_pubkey(args.taker_pub).map_err(TransactionErr::Plain)?; + let token_address = self.parse_token_contract_address(args.token_address)?; let swap_contract_address = self.parse_token_contract_address(args.swap_contract_address)?; let time_lock_u32 = args .time_lock .try_into() .map_err(|e: TryFromIntError| TransactionErr::Plain(e.to_string()))?; - let id = self.etomic_swap_id(time_lock_u32, args.maker_secret_hash); - let _gas = U256::from(ETH_GAS); let token_id = self.parse_token_id(args.token_id)?; let token_id_u256 = U256::from_dec_str(&token_id.to_string()).map_err(|e| NumConversError::new(e.to_string()))?; - let amount_u256 = - U256::from_dec_str(&args.amount.to_string()).map_err(|e| NumConversError::new(e.to_string()))?; - - // todo after getting data for sign and send in EthCoinType::Eth match: - // re-check do we need changes in sign_and_send_transaction function for nft broadcast to etomic swap address. - // UPD: Yes, changes are needed as sign_and_send_transaction returns Box type. + let htlc_data = self.prepare_htlc_data(&args, taker_address, token_address, time_lock_u32); match &self.coin_type { EthCoinType::Eth => match contract_type { ContractType::Erc1155 => { let function = ERC1155_CONTRACT.function("safeTransferFrom")?; - let additional_data = ethabi::encode(&[ - Token::FixedBytes(id), - Token::Address(taker_address), - Token::Address(swap_contract_address), - Token::FixedBytes(args.taker_secret_hash.to_vec()), - Token::FixedBytes(args.maker_secret_hash.to_vec()), - Token::Uint(U256::from(time_lock_u32)), - ]); + let amount_u256 = U256::from_dec_str(&args.amount.to_string()) + .map_err(|e| NumConversError::new(e.to_string()))?; let _data = function.encode_input(&[ Token::Address(self.my_address), Token::Address(swap_contract_address), Token::Uint(token_id_u256), Token::Uint(amount_u256), - Token::Bytes(additional_data), + Token::Bytes(htlc_data), ])?; + let _gas = U256::from(ETH_GAS); todo!() }, ContractType::Erc721 => { + let function = ERC721_CONTRACT.function("safeTransferFrom")?; + let _data = function.encode_input(&[ + Token::Address(self.my_address), + Token::Address(swap_contract_address), + Token::Uint(token_id_u256), + Token::Bytes(htlc_data), + ])?; + let _gas = U256::from(ETH_GAS); todo!() }, }, @@ -6438,6 +6417,51 @@ impl EthCoin { )), } } + + fn validate_payment_args( + &self, + args: &SendNftMakerPaymentArgs, + contract_type: &ContractType, + ) -> Result<(), String> { + match contract_type { + ContractType::Erc1155 => { + if !is_positive_integer(&args.amount) { + return Err("ERC-1155 amount must be a positive integer".to_string()); + } + }, + ContractType::Erc721 => { + if args.amount != BigDecimal::from(1) { + return Err("ERC-721 amount must be 1".to_string()); + } + }, + } + if args.taker_secret_hash.len() != 32 { + return Err("taker_secret_hash must be 32 bytes".to_string()); + } + if args.maker_secret_hash.len() != 32 { + return Err("maker_secret_hash must be 32 bytes".to_string()); + } + + Ok(()) + } + + fn prepare_htlc_data( + &self, + args: &SendNftMakerPaymentArgs<'_, Self>, + taker_address: Address, + token_address: Address, + time_lock: u32, + ) -> Vec { + let id = self.etomic_swap_id(time_lock, args.maker_secret_hash); + ethabi::encode(&[ + Token::FixedBytes(id), + Token::Address(taker_address), + Token::Address(token_address), + Token::FixedBytes(args.taker_secret_hash.to_vec()), + Token::FixedBytes(args.maker_secret_hash.to_vec()), + Token::Uint(U256::from(time_lock)), + ]) + } } /// function to check if BigDecimal is a positive integer From c42799e44db8c94a5c1df1e807e2ffad2094f086 Mon Sep 17 00:00:00 2001 From: laruh Date: Wed, 13 Mar 2024 17:17:04 +0700 Subject: [PATCH 15/80] call send_nft_maker_payment_v2 in nft test --- mm2src/coins/eth.rs | 39 ++++++++++++++++--- .../docker_tests/nft_swap_proto_v2_tests.rs | 18 +++++---- 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 958fb84337..640dac082d 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -3445,6 +3445,31 @@ impl EthCoin { Box::new(fut.boxed().compat()) } + async fn sign_and_send_transaction_async( + &self, + value: U256, + action: Action, + data: Vec, + gas: U256, + ) -> Result { + let ctx = MmArc::from_weak(&self.ctx) + .ok_or("!ctx") + .map_err(|e| TransactionErr::Plain(e.to_string()))?; + let coin = self.clone(); + match coin.priv_key_policy { + EthPrivKeyPolicy::Iguana(ref key_pair) + | EthPrivKeyPolicy::HDWallet { + activated_key: ref key_pair, + .. + } => sign_and_send_transaction_with_keypair(ctx, &coin, key_pair, value, action, data, gas).await, + EthPrivKeyPolicy::Trezor => Err(TransactionErr::Plain(ERRL!("Trezor is not supported for EVM yet!"))), + #[cfg(target_arch = "wasm32")] + EthPrivKeyPolicy::Metamask(_) => { + sign_and_send_transaction_with_metamask(coin, value, action, data, gas).await + }, + } + } + pub fn send_to_address(&self, address: Address, value: U256) -> EthTxFut { match &self.coin_type { EthCoinType::Eth => self.sign_and_send_transaction(value, Action::Call(address), vec![], U256::from(21000)), @@ -6387,26 +6412,28 @@ impl EthCoin { let function = ERC1155_CONTRACT.function("safeTransferFrom")?; let amount_u256 = U256::from_dec_str(&args.amount.to_string()) .map_err(|e| NumConversError::new(e.to_string()))?; - let _data = function.encode_input(&[ + let data = function.encode_input(&[ Token::Address(self.my_address), Token::Address(swap_contract_address), Token::Uint(token_id_u256), Token::Uint(amount_u256), Token::Bytes(htlc_data), ])?; - let _gas = U256::from(ETH_GAS); - todo!() + let gas = U256::from(ETH_GAS); + self.sign_and_send_transaction_async(0.into(), Action::Call(token_address), data, gas) + .await }, ContractType::Erc721 => { let function = ERC721_CONTRACT.function("safeTransferFrom")?; - let _data = function.encode_input(&[ + let data = function.encode_input(&[ Token::Address(self.my_address), Token::Address(swap_contract_address), Token::Uint(token_id_u256), Token::Bytes(htlc_data), ])?; - let _gas = U256::from(ETH_GAS); - todo!() + let gas = U256::from(ETH_GAS); + self.sign_and_send_transaction_async(0.into(), Action::Call(token_address), data, gas) + .await }, }, EthCoinType::Erc20 { .. } => Err(TransactionErr::ProtocolNotSupported( diff --git a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs index 091daaa4c3..ee52516ea9 100644 --- a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs @@ -1,14 +1,15 @@ -use super::eth_docker_tests::{eth_coin_with_random_privkey, global_nft_with_random_privkey, nft_swap_contract}; +use super::eth_docker_tests::{erc721_contract, eth_coin_with_random_privkey, global_nft_with_random_privkey, + nft_swap_contract}; use coins::eth::EthCoin; use coins::nft::nft_structs::{Chain, ContractType}; -use coins::{CoinAssocTypes, SendNftMakerPaymentArgs, SwapOps, ToBytes}; -use common::now_sec; +use coins::{CoinAssocTypes, MakerNftSwapOpsV2, SendNftMakerPaymentArgs, SwapOps, ToBytes}; +use common::{block_on, now_sec}; use mm2_number::BigUint; #[test] fn send_and_spend_erc721_maker_payment() { // TODO generate pair of utxo & eth coins from same random secret for maker / taker - let _maker_global_nft = global_nft_with_random_privkey(nft_swap_contract()); + let maker_global_nft = global_nft_with_random_privkey(nft_swap_contract()); // in prod we will need to enable global NFT for taker or add new field (for nft swap address) in EthCoin, // as EtomicSwapNft will have its own contract address, due to EIP-170 contract size limitations. // TODO need to add NFT conf in coin conf and refactor enable nft a bit @@ -17,17 +18,18 @@ fn send_and_spend_erc721_maker_payment() { let time_lock = now_sec() - 100; let taker_pubkey = taker_eth_coin.derive_htlc_pubkey(&[]); - let _send_payment_args: SendNftMakerPaymentArgs = SendNftMakerPaymentArgs { + let send_payment_args: SendNftMakerPaymentArgs = SendNftMakerPaymentArgs { time_lock, - taker_secret_hash: &[], - maker_secret_hash: &[], + taker_secret_hash: &[0; 32], + maker_secret_hash: &[0; 32], amount: 1.into(), taker_pub: &taker_eth_coin.parse_pubkey(&taker_pubkey).unwrap(), swap_unique_data: &[], - token_address: &[], + token_address: &erc721_contract().to_bytes(), token_id: &BigUint::from(1u32).to_bytes(), chain: &Chain::Eth.to_bytes(), contract_type: &ContractType::Erc721.to_bytes(), swap_contract_address: nft_swap_contract().as_bytes(), }; + block_on(maker_global_nft.send_nft_maker_payment_v2(send_payment_args)).unwrap(); } From 53431927baac6938dd1ae0d2dddd3e1060f7bdd5 Mon Sep 17 00:00:00 2001 From: laruh Date: Wed, 13 Mar 2024 17:32:47 +0700 Subject: [PATCH 16/80] use &nft_swap_contract().to_bytes() --- mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs index ee52516ea9..b6eee4fead 100644 --- a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs @@ -29,7 +29,7 @@ fn send_and_spend_erc721_maker_payment() { token_id: &BigUint::from(1u32).to_bytes(), chain: &Chain::Eth.to_bytes(), contract_type: &ContractType::Erc721.to_bytes(), - swap_contract_address: nft_swap_contract().as_bytes(), + swap_contract_address: &nft_swap_contract().to_bytes(), }; block_on(maker_global_nft.send_nft_maker_payment_v2(send_payment_args)).unwrap(); } From 3bde7746b8c8ccf86c74d00b2ac082b1be5dcb0d Mon Sep 17 00:00:00 2001 From: laruh Date: Wed, 13 Mar 2024 18:22:13 +0700 Subject: [PATCH 17/80] send_and_spend_erc1155_maker_payment and logs --- mm2src/coins/eth.rs | 16 +++++++++---- .../docker_tests/nft_swap_proto_v2_tests.rs | 24 +++++++++++++++++++ 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 640dac082d..964e7b6983 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -6400,18 +6400,21 @@ impl EthCoin { let time_lock_u32 = args .time_lock .try_into() - .map_err(|e: TryFromIntError| TransactionErr::Plain(e.to_string()))?; + .map_err(|e: TryFromIntError| TransactionErr::Plain(ERRL!("{}", e)))?; let token_id = self.parse_token_id(args.token_id)?; let token_id_u256 = - U256::from_dec_str(&token_id.to_string()).map_err(|e| NumConversError::new(e.to_string()))?; + U256::from_dec_str(&token_id.to_string()).map_err(|e| NumConversError::new(ERRL!("{}", e)))?; let htlc_data = self.prepare_htlc_data(&args, taker_address, token_address, time_lock_u32); match &self.coin_type { EthCoinType::Eth => match contract_type { ContractType::Erc1155 => { - let function = ERC1155_CONTRACT.function("safeTransferFrom")?; + let function = ERC1155_CONTRACT + .function("safeTransferFrom") + .map_err(|e| TransactionErr::AbiError(ERRL!("{}", e)))?; + info!("Got ERC1155 safeTransferFrom ..."); let amount_u256 = U256::from_dec_str(&args.amount.to_string()) - .map_err(|e| NumConversError::new(e.to_string()))?; + .map_err(|e| NumConversError::new(ERRL!("{}", e)))?; let data = function.encode_input(&[ Token::Address(self.my_address), Token::Address(swap_contract_address), @@ -6424,7 +6427,10 @@ impl EthCoin { .await }, ContractType::Erc721 => { - let function = ERC721_CONTRACT.function("safeTransferFrom")?; + let function = ERC721_CONTRACT + .function("safeTransferFrom") + .map_err(|e| TransactionErr::AbiError(ERRL!("{}", e)))?; + info!("Got ERC721 safeTransferFrom ..."); let data = function.encode_input(&[ Token::Address(self.my_address), Token::Address(swap_contract_address), diff --git a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs index b6eee4fead..2f56406eb0 100644 --- a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs @@ -33,3 +33,27 @@ fn send_and_spend_erc721_maker_payment() { }; block_on(maker_global_nft.send_nft_maker_payment_v2(send_payment_args)).unwrap(); } + +#[test] +fn send_and_spend_erc1155_maker_payment() { + let maker_global_nft = global_nft_with_random_privkey(nft_swap_contract()); + let taker_eth_coin = eth_coin_with_random_privkey(nft_swap_contract()); + + let time_lock = now_sec() - 100; + let taker_pubkey = taker_eth_coin.derive_htlc_pubkey(&[]); + + let send_payment_args: SendNftMakerPaymentArgs = SendNftMakerPaymentArgs { + time_lock, + taker_secret_hash: &[0; 32], + maker_secret_hash: &[0; 32], + amount: 3.into(), + taker_pub: &taker_eth_coin.parse_pubkey(&taker_pubkey).unwrap(), + swap_unique_data: &[], + token_address: &erc721_contract().to_bytes(), + token_id: &BigUint::from(1u32).to_bytes(), + chain: &Chain::Eth.to_bytes(), + contract_type: &ContractType::Erc1155.to_bytes(), + swap_contract_address: &nft_swap_contract().to_bytes(), + }; + block_on(maker_global_nft.send_nft_maker_payment_v2(send_payment_args)).unwrap(); +} From 854482eeabb96ce82fc93f5626733e932cfed529 Mon Sep 17 00:00:00 2001 From: laruh Date: Wed, 13 Mar 2024 19:25:56 +0700 Subject: [PATCH 18/80] fill global nft wallet with ETH and search the right version of safeTransferFrom func --- mm2src/coins/eth.rs | 26 +++++++++++++++---- .../tests/docker_tests/eth_docker_tests.rs | 1 + 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 964e7b6983..225ce0c229 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -3454,7 +3454,7 @@ impl EthCoin { ) -> Result { let ctx = MmArc::from_weak(&self.ctx) .ok_or("!ctx") - .map_err(|e| TransactionErr::Plain(e.to_string()))?; + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; let coin = self.clone(); match coin.priv_key_policy { EthPrivKeyPolicy::Iguana(ref key_pair) @@ -6412,7 +6412,6 @@ impl EthCoin { let function = ERC1155_CONTRACT .function("safeTransferFrom") .map_err(|e| TransactionErr::AbiError(ERRL!("{}", e)))?; - info!("Got ERC1155 safeTransferFrom ..."); let amount_u256 = U256::from_dec_str(&args.amount.to_string()) .map_err(|e| NumConversError::new(ERRL!("{}", e)))?; let data = function.encode_input(&[ @@ -6427,10 +6426,27 @@ impl EthCoin { .await }, ContractType::Erc721 => { - let function = ERC721_CONTRACT - .function("safeTransferFrom") + // ERC721 contract has overloaded versions of the safeTransferFrom function + let functions = ERC721_CONTRACT + .functions_by_name("safeTransferFrom") .map_err(|e| TransactionErr::AbiError(ERRL!("{}", e)))?; - info!("Got ERC721 safeTransferFrom ..."); + + // Find the correct function variant by inspecting the input parameters. + let function = functions + .iter() + .find(|f| { + f.inputs.len() == 4 + && matches!( + f.inputs.last().map(|input| &input.kind), + Some(ðabi::ParamType::Bytes) + ) + }) + .ok_or_else(|| { + TransactionErr::AbiError( + "Failed to find the correct safeTransferFrom function variant".to_string(), + ) + })?; + let data = function.encode_input(&[ Token::Address(self.my_address), Token::Address(swap_contract_address), diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index 86f8818ad1..4af155a5f1 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -245,6 +245,7 @@ pub fn global_nft_with_random_privkey(swap_contract: Address) -> EthCoin { )) .unwrap(); + fill_eth(global_nft.my_address, U256::from(10).pow(U256::from(20))); fill_erc721(global_nft.my_address, U256::from(1)); fill_erc1155(global_nft.my_address, U256::from(1), U256::from(3)); block_on(fill_nfts_info(&global_nft)); From 6f1ba46675576843407040003029c43dc764e250 Mon Sep 17 00:00:00 2001 From: laruh Date: Wed, 13 Mar 2024 20:12:20 +0700 Subject: [PATCH 19/80] increase gas usage for erc721 mint, use different token ids --- mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs | 9 +++++++-- .../tests/docker_tests/nft_swap_proto_v2_tests.rs | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index 4af155a5f1..0a2c2314c9 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -108,11 +108,16 @@ fn fill_erc721(to_addr: Address, token_id: U256) { let _guard = GETH_NONCE_LOCK.lock().unwrap(); let erc721_contract = Contract::from_json(GETH_WEB3.eth(), erc721_contract(), ERC721_TEST_ABI.as_bytes()).unwrap(); + let options = Options { + gas: Some(U256::from(1_000_000)), + ..Options::default() + }; + let tx_hash = block_on(erc721_contract.call( "mint", (Token::Address(to_addr), Token::Uint(token_id)), geth_account(), - Options::default(), + options, )) .unwrap(); wait_for_confirmation(tx_hash); @@ -247,7 +252,7 @@ pub fn global_nft_with_random_privkey(swap_contract: Address) -> EthCoin { fill_eth(global_nft.my_address, U256::from(10).pow(U256::from(20))); fill_erc721(global_nft.my_address, U256::from(1)); - fill_erc1155(global_nft.my_address, U256::from(1), U256::from(3)); + fill_erc1155(global_nft.my_address, U256::from(2), U256::from(3)); block_on(fill_nfts_info(&global_nft)); global_nft diff --git a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs index 2f56406eb0..0441c0056b 100644 --- a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs @@ -50,7 +50,7 @@ fn send_and_spend_erc1155_maker_payment() { taker_pub: &taker_eth_coin.parse_pubkey(&taker_pubkey).unwrap(), swap_unique_data: &[], token_address: &erc721_contract().to_bytes(), - token_id: &BigUint::from(1u32).to_bytes(), + token_id: &BigUint::from(2u32).to_bytes(), chain: &Chain::Eth.to_bytes(), contract_type: &ContractType::Erc1155.to_bytes(), swap_contract_address: &nft_swap_contract().to_bytes(), From 2c6fb5a4d7210267fbe74bb522f6ab85dfd61f9c Mon Sep 17 00:00:00 2001 From: laruh Date: Wed, 13 Mar 2024 20:45:59 +0700 Subject: [PATCH 20/80] add note about function method --- mm2src/coins/eth.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 225ce0c229..64e66d9eff 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -6426,7 +6426,8 @@ impl EthCoin { .await }, ContractType::Erc721 => { - // ERC721 contract has overloaded versions of the safeTransferFrom function + // ERC721 contract has overloaded versions of the safeTransferFrom function, + // but Contract::function method returns only the first if there are overloaded versions of the same function. let functions = ERC721_CONTRACT .functions_by_name("safeTransferFrom") .map_err(|e| TransactionErr::AbiError(ERRL!("{}", e)))?; From b7fa154e4328d5265581cdd1669b1f880537fdb9 Mon Sep 17 00:00:00 2001 From: laruh Date: Thu, 14 Mar 2024 15:14:29 +0700 Subject: [PATCH 21/80] return an empty Vec in to_bytes, use non async sign_and_send_transaction with compat --- mm2src/coins/eth.rs | 42 ++++++++++++------------------------------ 1 file changed, 12 insertions(+), 30 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 64e66d9eff..9182cf0928 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -3445,31 +3445,6 @@ impl EthCoin { Box::new(fut.boxed().compat()) } - async fn sign_and_send_transaction_async( - &self, - value: U256, - action: Action, - data: Vec, - gas: U256, - ) -> Result { - let ctx = MmArc::from_weak(&self.ctx) - .ok_or("!ctx") - .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; - let coin = self.clone(); - match coin.priv_key_policy { - EthPrivKeyPolicy::Iguana(ref key_pair) - | EthPrivKeyPolicy::HDWallet { - activated_key: ref key_pair, - .. - } => sign_and_send_transaction_with_keypair(ctx, &coin, key_pair, value, action, data, gas).await, - EthPrivKeyPolicy::Trezor => Err(TransactionErr::Plain(ERRL!("Trezor is not supported for EVM yet!"))), - #[cfg(target_arch = "wasm32")] - EthPrivKeyPolicy::Metamask(_) => { - sign_and_send_transaction_with_metamask(coin, value, action, data, gas).await - }, - } - } - pub fn send_to_address(&self, address: Address, value: U256) -> EthTxFut { match &self.coin_type { EthCoinType::Eth => self.sign_and_send_transaction(value, Action::Call(address), vec![], U256::from(21000)), @@ -6217,9 +6192,14 @@ impl ToBytes for SignedEthTx { fn to_bytes(&self) -> Vec { let mut stream = RlpStream::new(); self.rlp_append(&mut stream); - // there is minimal but risk that stream.out() may panic - debug_assert!(stream.is_finished(), "RlpStream must be finished before calling out"); - Vec::from(stream.out()) + // Handle potential panicking. + if stream.is_finished() { + Vec::from(stream.out()) + } else { + // TODO: Consider returning Result, Error> in future refactoring for better error handling. + warn!("RlpStream was not finished; returning an empty Vec as a fail-safe."); + vec![] + } } } @@ -6422,7 +6402,8 @@ impl EthCoin { Token::Bytes(htlc_data), ])?; let gas = U256::from(ETH_GAS); - self.sign_and_send_transaction_async(0.into(), Action::Call(token_address), data, gas) + self.sign_and_send_transaction(0.into(), Action::Call(token_address), data, gas) + .compat() .await }, ContractType::Erc721 => { @@ -6455,7 +6436,8 @@ impl EthCoin { Token::Bytes(htlc_data), ])?; let gas = U256::from(ETH_GAS); - self.sign_and_send_transaction_async(0.into(), Action::Call(token_address), data, gas) + self.sign_and_send_transaction(0.into(), Action::Call(token_address), data, gas) + .compat() .await }, }, From 04b5a93265d68b00585389ef3d1e3c21ae3c071c Mon Sep 17 00:00:00 2001 From: laruh Date: Fri, 15 Mar 2024 13:15:01 +0700 Subject: [PATCH 22/80] impl utxo_nft_eth_pair_with_random_privkey func, mint erc721 and erc1155 with token_id=1 --- .../tests/docker_tests/docker_tests_common.rs | 14 +++- .../tests/docker_tests/eth_docker_tests.rs | 64 +++++++++++++++---- .../docker_tests/nft_swap_proto_v2_tests.rs | 26 ++++---- 3 files changed, 80 insertions(+), 24 deletions(-) diff --git a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs index b324ee157e..ac85c6146c 100644 --- a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs +++ b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs @@ -7,7 +7,7 @@ pub use mm2_test_helpers::for_tests::{check_my_swap_status, check_recent_swaps, ETH_DEV_SWAP_CONTRACT, ETH_DEV_TOKEN_CONTRACT, MAKER_ERROR_EVENTS, MAKER_SUCCESS_EVENTS, TAKER_ERROR_EVENTS, TAKER_SUCCESS_EVENTS}; -use crate::docker_tests::eth_docker_tests::{fill_eth, geth_account}; +use super::eth_docker_tests::{fill_eth, geth_account, global_nft_with_privkey}; use bitcrypto::{dhash160, ChecksumType}; use chain::TransactionOutput; use coins::eth::{addr_from_raw_pubkey, eth_coin_from_conf_and_request, EthCoin}; @@ -517,6 +517,18 @@ pub fn generate_utxo_coin_with_random_privkey( (ctx, coin, priv_key) } +/// Generates a pair of utxo coin and global NFT_ETH. Fills utxo and NFT_ETH addresses with balance enough for swaps. +/// If mint_nft true, mints one ERC721 and 3 ERC1155 tokens to NFT_ETH address. +pub fn utxo_nft_eth_pair_with_random_privkey( + utxo_ticker: &str, + swap_contract: web3::types::Address, + mint_nft: bool, +) -> (UtxoStandardCoin, EthCoin) { + let (ctx, utxo, priv_key) = generate_utxo_coin_with_random_privkey(utxo_ticker, 1000.into()); + let global_nft = global_nft_with_privkey(&ctx, swap_contract, priv_key, mint_nft); + (utxo, global_nft) +} + /// Get only one address assigned the specified label. pub fn get_address_by_label(coin: T, label: &str) -> String where diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index 0a2c2314c9..a8580849d9 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -8,8 +8,10 @@ use coins::nft::nft_structs::{Chain, ContractType, NftInfo}; use coins::{CoinProtocol, ConfirmPaymentInput, FoundSwapTxSpend, MarketCoinOps, PrivKeyBuildPolicy, RefundPaymentArgs, SearchForSwapTxSpendInput, SendPaymentArgs, SpendPaymentArgs, SwapOps, SwapTxTypeWithSecretHash}; use common::{block_on, now_sec}; +use crypto::Secp256k1Secret; use ethereum_types::U256; use futures01::Future; +use mm2_core::mm_ctx::MmArc; use mm2_number::{BigDecimal, BigUint}; use mm2_test_helpers::for_tests::{erc20_dev_conf, eth_dev_conf, nft_dev_conf}; use std::thread; @@ -104,7 +106,7 @@ fn fill_erc20(to_addr: Address, amount: U256) { wait_for_confirmation(tx_hash); } -fn fill_erc721(to_addr: Address, token_id: U256) { +pub(crate) fn fill_erc721(to_addr: Address, token_id: U256) { let _guard = GETH_NONCE_LOCK.lock().unwrap(); let erc721_contract = Contract::from_json(GETH_WEB3.eth(), erc721_contract(), ERC721_TEST_ABI.as_bytes()).unwrap(); @@ -123,7 +125,7 @@ fn fill_erc721(to_addr: Address, token_id: U256) { wait_for_confirmation(tx_hash); } -fn fill_erc1155(to_addr: Address, token_id: U256, amount: U256) { +pub(crate) fn fill_erc1155(to_addr: Address, token_id: U256, amount: U256) { let _guard = GETH_NONCE_LOCK.lock().unwrap(); let erc1155_contract = Contract::from_json(GETH_WEB3.eth(), erc1155_contract(), ERC1155_TEST_ABI.as_bytes()).unwrap(); @@ -143,30 +145,30 @@ fn fill_erc1155(to_addr: Address, token_id: U256, amount: U256) { wait_for_confirmation(tx_hash); } -async fn fill_nfts_info(eth_coin: &EthCoin) { +pub(crate) async fn fill_nfts_info(eth_coin: &EthCoin, tokens_ids: u32, erc1155_amount: BigDecimal) { let nft_infos_lock = eth_coin.nfts_infos.clone(); let mut nft_infos = nft_infos_lock.lock().await; let erc721_nft_info = NftInfo { token_address: erc721_contract(), - token_id: BigUint::from(1u32), // Assuming a tokenId of 1 for simplicity + token_id: BigUint::from(tokens_ids), chain: Chain::Eth, contract_type: ContractType::Erc721, amount: BigDecimal::from(1), }; let erc721_address_str = eth_addr_to_hex(&erc721_contract()); - let erc721_key = format!("{},{}", erc721_address_str, 1); + let erc721_key = format!("{},{}", erc721_address_str, tokens_ids); nft_infos.insert(erc721_key, erc721_nft_info); let erc1155_nft_info = NftInfo { token_address: erc1155_contract(), - token_id: BigUint::from(1u32), + token_id: BigUint::from(tokens_ids), chain: Chain::Eth, contract_type: ContractType::Erc1155, - amount: BigDecimal::from(3), + amount: erc1155_amount, }; let erc1155_address_str = eth_addr_to_hex(&erc1155_contract()); - let erc1155_key = format!("{},{}", erc1155_address_str, 1); + let erc1155_key = format!("{},{}", erc1155_address_str, tokens_ids); nft_infos.insert(erc1155_key, erc1155_nft_info); } @@ -228,7 +230,9 @@ pub fn erc20_coin_with_random_privkey(swap_contract: Address) -> EthCoin { erc20_coin } -/// Creates global NFT supplied with one ERC721 and 3 ERC1155 tokens owned by user in nfts_infos field +/// Creates global NFT from generated random privkey supplied with 100 ETH, +/// one ERC721 and 3 ERC1155 tokens owned by NFT address in nfts_infos field +#[allow(dead_code)] pub fn global_nft_with_random_privkey(swap_contract: Address) -> EthCoin { let nft_conf = nft_dev_conf(); let req = json!({ @@ -252,8 +256,46 @@ pub fn global_nft_with_random_privkey(swap_contract: Address) -> EthCoin { fill_eth(global_nft.my_address, U256::from(10).pow(U256::from(20))); fill_erc721(global_nft.my_address, U256::from(1)); - fill_erc1155(global_nft.my_address, U256::from(2), U256::from(3)); - block_on(fill_nfts_info(&global_nft)); + fill_erc1155(global_nft.my_address, U256::from(1), U256::from(3)); + block_on(fill_nfts_info(&global_nft, 1u32, BigDecimal::from(3))); + + global_nft +} + +/// Generates global NFT from privkey supplied with 100 ETH. +/// If mint_nft true, mints one ERC721 and 3 ERC1155 tokens to NFT_ETH address. +pub fn global_nft_with_privkey( + ctx: &MmArc, + swap_contract: Address, + priv_key: Secp256k1Secret, + mint_nft: bool, +) -> EthCoin { + let nft_conf = nft_dev_conf(); + let req = json!({ + "method": "enable", + "coin": "NFT_ETH", + "urls": ["http://127.0.0.1:8545"], + "swap_contract_address": swap_contract, + }); + + let global_nft = block_on(eth_coin_from_conf_and_request( + ctx, + "NFT_ETH", + &nft_conf, + &req, + CoinProtocol::NFT { + platform: "ETH".to_string(), + }, + PrivKeyBuildPolicy::IguanaPrivKey(priv_key), + )) + .unwrap(); + + fill_eth(global_nft.my_address, U256::from(10).pow(U256::from(20))); + if mint_nft { + fill_erc721(global_nft.my_address, U256::from(1)); + fill_erc1155(global_nft.my_address, U256::from(1), U256::from(3)); + block_on(fill_nfts_info(&global_nft, 1u32, BigDecimal::from(3))); + } global_nft } diff --git a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs index 0441c0056b..048aa53ced 100644 --- a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs @@ -1,5 +1,5 @@ -use super::eth_docker_tests::{erc721_contract, eth_coin_with_random_privkey, global_nft_with_random_privkey, - nft_swap_contract}; +use super::docker_tests_common::{utxo_nft_eth_pair_with_random_privkey, MYCOIN}; +use super::eth_docker_tests::{erc721_contract, nft_swap_contract}; use coins::eth::EthCoin; use coins::nft::nft_structs::{Chain, ContractType}; use coins::{CoinAssocTypes, MakerNftSwapOpsV2, SendNftMakerPaymentArgs, SwapOps, ToBytes}; @@ -8,22 +8,23 @@ use mm2_number::BigUint; #[test] fn send_and_spend_erc721_maker_payment() { - // TODO generate pair of utxo & eth coins from same random secret for maker / taker - let maker_global_nft = global_nft_with_random_privkey(nft_swap_contract()); // in prod we will need to enable global NFT for taker or add new field (for nft swap address) in EthCoin, // as EtomicSwapNft will have its own contract address, due to EIP-170 contract size limitations. // TODO need to add NFT conf in coin conf and refactor enable nft a bit - let taker_eth_coin = eth_coin_with_random_privkey(nft_swap_contract()); + + let (_maker_utxo, maker_global_nft) = utxo_nft_eth_pair_with_random_privkey(MYCOIN, nft_swap_contract(), true); + // We can treat taker global NFT as ETH coin, as they are generated with same priv key and configurations + let (_taker_utxo, taker_global_nft) = utxo_nft_eth_pair_with_random_privkey(MYCOIN, nft_swap_contract(), false); let time_lock = now_sec() - 100; - let taker_pubkey = taker_eth_coin.derive_htlc_pubkey(&[]); + let taker_pubkey = taker_global_nft.derive_htlc_pubkey(&[]); let send_payment_args: SendNftMakerPaymentArgs = SendNftMakerPaymentArgs { time_lock, taker_secret_hash: &[0; 32], maker_secret_hash: &[0; 32], amount: 1.into(), - taker_pub: &taker_eth_coin.parse_pubkey(&taker_pubkey).unwrap(), + taker_pub: &taker_global_nft.parse_pubkey(&taker_pubkey).unwrap(), swap_unique_data: &[], token_address: &erc721_contract().to_bytes(), token_id: &BigUint::from(1u32).to_bytes(), @@ -36,21 +37,22 @@ fn send_and_spend_erc721_maker_payment() { #[test] fn send_and_spend_erc1155_maker_payment() { - let maker_global_nft = global_nft_with_random_privkey(nft_swap_contract()); - let taker_eth_coin = eth_coin_with_random_privkey(nft_swap_contract()); + let (_maker_utxo, maker_global_nft) = utxo_nft_eth_pair_with_random_privkey(MYCOIN, nft_swap_contract(), true); + // We can treat taker global NFT as ETH coin + let (_taker_utxo, taker_global_nft) = utxo_nft_eth_pair_with_random_privkey(MYCOIN, nft_swap_contract(), false); let time_lock = now_sec() - 100; - let taker_pubkey = taker_eth_coin.derive_htlc_pubkey(&[]); + let taker_pubkey = taker_global_nft.derive_htlc_pubkey(&[]); let send_payment_args: SendNftMakerPaymentArgs = SendNftMakerPaymentArgs { time_lock, taker_secret_hash: &[0; 32], maker_secret_hash: &[0; 32], amount: 3.into(), - taker_pub: &taker_eth_coin.parse_pubkey(&taker_pubkey).unwrap(), + taker_pub: &taker_global_nft.parse_pubkey(&taker_pubkey).unwrap(), swap_unique_data: &[], token_address: &erc721_contract().to_bytes(), - token_id: &BigUint::from(2u32).to_bytes(), + token_id: &BigUint::from(1u32).to_bytes(), chain: &Chain::Eth.to_bytes(), contract_type: &ContractType::Erc1155.to_bytes(), swap_contract_address: &nft_swap_contract().to_bytes(), From 855d5a367bcb11950f8a77284d65319f9fc9e301 Mon Sep 17 00:00:00 2001 From: laruh Date: Fri, 15 Mar 2024 13:55:33 +0700 Subject: [PATCH 23/80] use `pub static ref MM_CTX` for global_nft generation --- .../mm2_main/tests/docker_tests/docker_tests_common.rs | 4 ++-- mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs | 10 ++-------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs index ac85c6146c..b1d2f4c2c2 100644 --- a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs +++ b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs @@ -524,8 +524,8 @@ pub fn utxo_nft_eth_pair_with_random_privkey( swap_contract: web3::types::Address, mint_nft: bool, ) -> (UtxoStandardCoin, EthCoin) { - let (ctx, utxo, priv_key) = generate_utxo_coin_with_random_privkey(utxo_ticker, 1000.into()); - let global_nft = global_nft_with_privkey(&ctx, swap_contract, priv_key, mint_nft); + let (_, utxo, priv_key) = generate_utxo_coin_with_random_privkey(utxo_ticker, 1000.into()); + let global_nft = global_nft_with_privkey(swap_contract, priv_key, mint_nft); (utxo, global_nft) } diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index a8580849d9..e22fd6a24b 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -11,7 +11,6 @@ use common::{block_on, now_sec}; use crypto::Secp256k1Secret; use ethereum_types::U256; use futures01::Future; -use mm2_core::mm_ctx::MmArc; use mm2_number::{BigDecimal, BigUint}; use mm2_test_helpers::for_tests::{erc20_dev_conf, eth_dev_conf, nft_dev_conf}; use std::thread; @@ -264,12 +263,7 @@ pub fn global_nft_with_random_privkey(swap_contract: Address) -> EthCoin { /// Generates global NFT from privkey supplied with 100 ETH. /// If mint_nft true, mints one ERC721 and 3 ERC1155 tokens to NFT_ETH address. -pub fn global_nft_with_privkey( - ctx: &MmArc, - swap_contract: Address, - priv_key: Secp256k1Secret, - mint_nft: bool, -) -> EthCoin { +pub fn global_nft_with_privkey(swap_contract: Address, priv_key: Secp256k1Secret, mint_nft: bool) -> EthCoin { let nft_conf = nft_dev_conf(); let req = json!({ "method": "enable", @@ -279,7 +273,7 @@ pub fn global_nft_with_privkey( }); let global_nft = block_on(eth_coin_from_conf_and_request( - ctx, + &MM_CTX, "NFT_ETH", &nft_conf, &req, From 20b4452f8fa1092cfc8e27498d786b4e731ebdcd Mon Sep 17 00:00:00 2001 From: laruh Date: Sun, 17 Mar 2024 23:27:51 +0700 Subject: [PATCH 24/80] validate_nft_maker_payment_v2_impl, payment_status_v2 WIP --- mm2src/coins/coin_errors.rs | 9 ++++ mm2src/coins/eth.rs | 104 ++++++++++++++++++++++++++++++++---- mm2src/coins/lp_coins.rs | 29 +++++++++- 3 files changed, 130 insertions(+), 12 deletions(-) diff --git a/mm2src/coins/coin_errors.rs b/mm2src/coins/coin_errors.rs index 6c0d88b452..6a73c45cb1 100644 --- a/mm2src/coins/coin_errors.rs +++ b/mm2src/coins/coin_errors.rs @@ -1,3 +1,4 @@ +use crate::eth::{CoinAssocTypesError, NftAssocTypesError}; use crate::{eth::Web3RpcError, my_tx_history_v2::MyTxHistoryErrorV2, utxo::rpc_clients::UtxoRpcError, DelegationError, NumConversError, TxHistoryError, UnexpectedDerivationMethod, WithdrawError}; use futures01::Future; @@ -90,6 +91,14 @@ impl From for ValidatePaymentError { fn from(err: keys::Error) -> Self { Self::InternalError(err.to_string()) } } +impl From for ValidatePaymentError { + fn from(err: NftAssocTypesError) -> Self { Self::InternalError(err.to_string()) } +} + +impl From for ValidatePaymentError { + fn from(err: CoinAssocTypesError) -> Self { Self::InternalError(err.to_string()) } +} + #[derive(Debug, Display)] pub enum MyAddressError { UnexpectedDerivationMethod(String), diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 9182cf0928..babba03727 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -27,7 +27,7 @@ use crate::lp_price::get_base_price_in_rel; use crate::nft::nft_structs::{Chain, ContractType, ConvertChain, NftInfo, TransactionNftDetails, WithdrawErc1155, WithdrawErc721}; use crate::{CoinAssocTypes, DexFee, MakerNftSwapOpsV2, NftAssocTypes, RefundMakerPaymentArgs, RpcCommonOps, - SendNftMakerPaymentArgs, SpendMakerPaymentArgs, ToBytes, ValidateMakerPaymentArgs, + SendNftMakerPaymentArgs, SpendMakerPaymentArgs, ToBytes, ValidateNftMakerPaymentArgs, ValidateWatcherSpendInput, WatcherSpendType}; use async_trait::async_trait; use bitcrypto::{dhash160, keccak256, ripemd160, sha256}; @@ -6338,9 +6338,9 @@ impl MakerNftSwapOpsV2 for EthCoin { async fn validate_nft_maker_payment_v2( &self, - _args: ValidateMakerPaymentArgs<'_, Self>, + args: ValidateNftMakerPaymentArgs<'_, Self>, ) -> ValidatePaymentResult<()> { - todo!() + self.validate_nft_maker_payment_v2_impl(args).await } async fn spend_nft_maker_payment_v2( @@ -6371,8 +6371,13 @@ impl EthCoin { args: SendNftMakerPaymentArgs<'_, Self>, ) -> Result { let contract_type = self.parse_contract_type(args.contract_type)?; - self.validate_payment_args(&args, &contract_type) - .map_err(TransactionErr::Plain)?; + self.validate_payment_args( + args.taker_secret_hash, + args.maker_secret_hash, + &args.amount, + &contract_type, + ) + .map_err(TransactionErr::Plain)?; let taker_address = addr_from_raw_pubkey(args.taker_pub).map_err(TransactionErr::Plain)?; let token_address = self.parse_token_contract_address(args.token_address)?; @@ -6450,27 +6455,29 @@ impl EthCoin { } } - fn validate_payment_args( + fn validate_payment_args<'a>( &self, - args: &SendNftMakerPaymentArgs, + taker_secret_hash: &'a [u8], + maker_secret_hash: &'a [u8], + amount: &BigDecimal, contract_type: &ContractType, ) -> Result<(), String> { match contract_type { ContractType::Erc1155 => { - if !is_positive_integer(&args.amount) { + if !is_positive_integer(amount) { return Err("ERC-1155 amount must be a positive integer".to_string()); } }, ContractType::Erc721 => { - if args.amount != BigDecimal::from(1) { + if amount != &BigDecimal::from(1) { return Err("ERC-721 amount must be 1".to_string()); } }, } - if args.taker_secret_hash.len() != 32 { + if taker_secret_hash.len() != 32 { return Err("taker_secret_hash must be 32 bytes".to_string()); } - if args.maker_secret_hash.len() != 32 { + if maker_secret_hash.len() != 32 { return Err("maker_secret_hash must be 32 bytes".to_string()); } @@ -6494,6 +6501,81 @@ impl EthCoin { Token::Uint(U256::from(time_lock)), ]) } + + async fn validate_nft_maker_payment_v2_impl( + &self, + args: ValidateNftMakerPaymentArgs<'_, Self>, + ) -> ValidatePaymentResult<()> { + let contract_type = self.parse_contract_type(args.contract_type)?; + self.validate_payment_args( + args.taker_secret_hash, + args.maker_secret_hash, + &args.amount, + &contract_type, + ) + .map_err(ValidatePaymentError::InternalError)?; + let _expected_swap_contract = self.parse_token_contract_address(args.swap_contract_address)?; + let _maker_address = addr_from_raw_pubkey(args.maker_pub).map_err(ValidatePaymentError::InternalError)?; + let time_lock_u32 = args + .time_lock + .try_into() + .map_err(ValidatePaymentError::TimelockOverflow)?; + let _swap_id = self.etomic_swap_id(time_lock_u32, args.maker_secret_hash); + + todo!() + } + + #[allow(dead_code)] + async fn payment_status_v2( + &self, + swap_contract_addr: Address, + swap_id: Token, + contract: Contract, + state_type: StateType, + ) -> Result { + let function_name = state_type.as_str(); + let function = contract.function(function_name)?; + let data = function.encode_input(&[swap_id])?; + let bytes = self.call_request(swap_contract_addr, None, Some(data.into())).await?; + let decoded_tokens = function.decode_output(&bytes.0)?; + let _state = decoded_tokens.get(2).ok_or_else(|| { + PaymentStatusErr::Internal("Payment status must contain 'state' as the 2nd token".to_string()) + })?; + todo!() + } +} + +#[derive(Debug, Display)] +enum PaymentStatusErr { + #[display(fmt = "Abi error: {}", _0)] + AbiError(String), + #[display(fmt = "Transport error: {}", _0)] + Transport(String), + #[display(fmt = "Internal error: {}", _0)] + Internal(String), +} + +impl From for PaymentStatusErr { + fn from(e: ethabi::Error) -> Self { Self::AbiError(e.to_string()) } +} + +impl From for PaymentStatusErr { + fn from(err: web3::Error) -> Self { Self::Transport(err.to_string()) } +} + +#[allow(dead_code)] +enum StateType { + MakerPayments, + TakerPayments, +} + +impl StateType { + fn as_str(&self) -> &'static str { + match self { + StateType::MakerPayments => "makerPayments", + StateType::TakerPayments => "takerPayments", + } + } } /// function to check if BigDecimal is a positive integer diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index e86c652e36..c62c2c3e8e 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -1586,6 +1586,33 @@ pub struct ValidateMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { pub swap_unique_data: &'a [u8], } +pub struct ValidateNftMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { + /// Maker payment tx + pub maker_payment_tx: &'a Coin::Tx, + /// Maker will be able to refund the payment after this timestamp + pub time_lock: u64, + /// The hash of the secret generated by taker, this is used for immediate refund + pub taker_secret_hash: &'a [u8], + /// The hash of the secret generated by maker, taker needs it to spend the payment + pub maker_secret_hash: &'a [u8], + /// Payment amount + pub amount: BigDecimal, + /// Maker's HTLC pubkey + pub maker_pub: &'a Coin::Pubkey, + /// Unique data of specific swap + pub swap_unique_data: &'a [u8], + /// The address of the NFT token + pub token_address: &'a [u8], + /// The ID of the NFT token. + pub token_id: &'a [u8], + /// The blockchain where the NFT exists + pub chain: &'a [u8], + /// The type of smart contract that governs this NFT + pub contract_type: &'a [u8], + // Etomic swap contract address + pub swap_contract_address: &'a [u8], +} + pub struct RefundMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { /// Maker payment tx pub maker_payment_tx: &'a Coin::Tx, @@ -1652,7 +1679,7 @@ pub trait MakerNftSwapOpsV2: CoinAssocTypes + NftAssocTypes + Send + Sync + 'sta /// Validate NFT maker payment transaction async fn validate_nft_maker_payment_v2( &self, - args: ValidateMakerPaymentArgs<'_, Self>, + args: ValidateNftMakerPaymentArgs<'_, Self>, ) -> ValidatePaymentResult<()>; /// Spend NFT maker payment transaction From f778492539d6a65d9cc6653caf30a8b00325932a Mon Sep 17 00:00:00 2001 From: laruh Date: Mon, 18 Mar 2024 14:37:49 +0700 Subject: [PATCH 25/80] use only global nfts in nft_swap_proto_v2_tests.rs, allow only EthCoinType::Nft in send_nft_maker_payment fnc --- mm2src/coins/coin_errors.rs | 11 +++- mm2src/coins/eth.rs | 61 +++++++++++++++---- .../tests/docker_tests/docker_tests_common.rs | 14 +---- .../tests/docker_tests/eth_docker_tests.rs | 43 ++----------- .../docker_tests/nft_swap_proto_v2_tests.rs | 13 ++-- 5 files changed, 69 insertions(+), 73 deletions(-) diff --git a/mm2src/coins/coin_errors.rs b/mm2src/coins/coin_errors.rs index 6a73c45cb1..8836c9938f 100644 --- a/mm2src/coins/coin_errors.rs +++ b/mm2src/coins/coin_errors.rs @@ -1,4 +1,4 @@ -use crate::eth::{CoinAssocTypesError, NftAssocTypesError}; +use crate::eth::{CoinAssocTypesError, NftAssocTypesError, PaymentStatusErr}; use crate::{eth::Web3RpcError, my_tx_history_v2::MyTxHistoryErrorV2, utxo::rpc_clients::UtxoRpcError, DelegationError, NumConversError, TxHistoryError, UnexpectedDerivationMethod, WithdrawError}; use futures01::Future; @@ -99,6 +99,15 @@ impl From for ValidatePaymentError { fn from(err: CoinAssocTypesError) -> Self { Self::InternalError(err.to_string()) } } +impl From for ValidatePaymentError { + fn from(err: PaymentStatusErr) -> Self { + match err { + PaymentStatusErr::Transport(e) => Self::Transport(e), + PaymentStatusErr::AbiError(e) | PaymentStatusErr::Internal(e) => Self::InternalError(e), + } + } +} + #[derive(Debug, Display)] pub enum MyAddressError { UnexpectedDerivationMethod(String), diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index babba03727..fe147b82e4 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -141,6 +141,7 @@ pub const ERC20_ABI: &str = include_str!("eth/erc20_abi.json"); const ERC721_ABI: &str = include_str!("eth/erc721_abi.json"); /// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md const ERC1155_ABI: &str = include_str!("eth/erc1155_abi.json"); +const NFT_SWAP_CONTRACT_ABI: &str = include_str!("eth/nft_swap_contract_abi.json"); /// Payment states from etomic swap smart contract: https://github.com/artemii235/etomic-swap/blob/master/contracts/EtomicSwap.sol#L5 pub enum PaymentState { Uninitialized, @@ -148,6 +149,21 @@ pub enum PaymentState { Spent, Refunded, } +#[allow(dead_code)] +enum MakerPaymentState { + Uninitialized, + PaymentSent, + TakerSpent, + MakerRefunded, +} +#[allow(dead_code)] +enum TakerPaymentState { + Uninitialized, + PaymentSent, + TakerApproved, + MakerSpent, + TakerRefunded, +} // Ethgasstation API returns response in 10^8 wei units. So 10 from their API mean 1 gwei const ETH_GAS_STATION_DECIMALS: u8 = 8; const GAS_PRICE_PERCENT: u64 = 10; @@ -183,6 +199,7 @@ lazy_static! { pub static ref ERC20_CONTRACT: Contract = Contract::load(ERC20_ABI.as_bytes()).unwrap(); pub static ref ERC721_CONTRACT: Contract = Contract::load(ERC721_ABI.as_bytes()).unwrap(); pub static ref ERC1155_CONTRACT: Contract = Contract::load(ERC1155_ABI.as_bytes()).unwrap(); + pub static ref NFT_SWAP_CONTRACT: Contract = Contract::load(NFT_SWAP_CONTRACT_ABI.as_bytes()).unwrap(); } pub type Web3RpcFut = Box> + Send>; @@ -5879,7 +5896,7 @@ pub async fn eth_coin_from_conf_and_request( } let (coin_type, decimals) = match protocol { - CoinProtocol::ETH | CoinProtocol::NFT { .. } => (EthCoinType::Eth, ETH_DECIMALS), + CoinProtocol::ETH => (EthCoinType::Eth, ETH_DECIMALS), CoinProtocol::ERC20 { platform, contract_address, @@ -5900,6 +5917,7 @@ pub async fn eth_coin_from_conf_and_request( }; (EthCoinType::Erc20 { platform, token_addr }, decimals) }, + CoinProtocol::NFT { platform } => (EthCoinType::Nft { platform }, ETH_DECIMALS), _ => return ERR!("Expect ETH, ERC20 or NFT protocol"), }; @@ -6392,7 +6410,7 @@ impl EthCoin { let htlc_data = self.prepare_htlc_data(&args, taker_address, token_address, time_lock_u32); match &self.coin_type { - EthCoinType::Eth => match contract_type { + EthCoinType::Nft { .. } => match contract_type { ContractType::Erc1155 => { let function = ERC1155_CONTRACT .function("safeTransferFrom") @@ -6449,8 +6467,8 @@ impl EthCoin { EthCoinType::Erc20 { .. } => Err(TransactionErr::ProtocolNotSupported( "ERC20 Protocol is not supported for NFT Swaps".to_string(), )), - EthCoinType::Nft { .. } => Err(TransactionErr::ProtocolNotSupported( - "Nft Protocol is not supported yet for NFT Swaps!".to_string(), + EthCoinType::Eth => Err(TransactionErr::ProtocolNotSupported( + "ETH Protocol is not supported for NFT Swaps!".to_string(), )), } } @@ -6514,23 +6532,36 @@ impl EthCoin { &contract_type, ) .map_err(ValidatePaymentError::InternalError)?; - let _expected_swap_contract = self.parse_token_contract_address(args.swap_contract_address)?; - let _maker_address = addr_from_raw_pubkey(args.maker_pub).map_err(ValidatePaymentError::InternalError)?; + let expected_swap_contract = self.parse_token_contract_address(args.swap_contract_address)?; + let _maker_address = addr_from_raw_pubkey(args.maker_pub).map_to_mm(ValidatePaymentError::InternalError)?; let time_lock_u32 = args .time_lock .try_into() .map_err(ValidatePaymentError::TimelockOverflow)?; - let _swap_id = self.etomic_swap_id(time_lock_u32, args.maker_secret_hash); + let swap_id = self.etomic_swap_id(time_lock_u32, args.maker_secret_hash); + let maker_status = self + .payment_status_v2( + expected_swap_contract, + Token::FixedBytes(swap_id), + &NFT_SWAP_CONTRACT, + StateType::MakerPayments, + ) + .await?; + if maker_status != U256::from(MakerPaymentState::PaymentSent as u8) { + return MmError::err(ValidatePaymentError::UnexpectedPaymentState(format!( + "Maker Payment state is not PAYMENT_STATE_SENT, got {}", + maker_status + ))); + } todo!() } - #[allow(dead_code)] async fn payment_status_v2( &self, swap_contract_addr: Address, swap_id: Token, - contract: Contract, + contract: &Contract, state_type: StateType, ) -> Result { let function_name = state_type.as_str(); @@ -6538,15 +6569,21 @@ impl EthCoin { let data = function.encode_input(&[swap_id])?; let bytes = self.call_request(swap_contract_addr, None, Some(data.into())).await?; let decoded_tokens = function.decode_output(&bytes.0)?; - let _state = decoded_tokens.get(2).ok_or_else(|| { + let state = decoded_tokens.get(2).ok_or_else(|| { PaymentStatusErr::Internal("Payment status must contain 'state' as the 2nd token".to_string()) })?; - todo!() + match state { + Token::Uint(state) => Ok(*state), + _ => Err(PaymentStatusErr::Internal(format!( + "Payment status must be uint, got {:?}", + state + ))), + } } } #[derive(Debug, Display)] -enum PaymentStatusErr { +pub enum PaymentStatusErr { #[display(fmt = "Abi error: {}", _0)] AbiError(String), #[display(fmt = "Transport error: {}", _0)] diff --git a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs index b1d2f4c2c2..e3e20ba1af 100644 --- a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs +++ b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs @@ -7,7 +7,7 @@ pub use mm2_test_helpers::for_tests::{check_my_swap_status, check_recent_swaps, ETH_DEV_SWAP_CONTRACT, ETH_DEV_TOKEN_CONTRACT, MAKER_ERROR_EVENTS, MAKER_SUCCESS_EVENTS, TAKER_ERROR_EVENTS, TAKER_SUCCESS_EVENTS}; -use super::eth_docker_tests::{fill_eth, geth_account, global_nft_with_privkey}; +use super::eth_docker_tests::{fill_eth, geth_account}; use bitcrypto::{dhash160, ChecksumType}; use chain::TransactionOutput; use coins::eth::{addr_from_raw_pubkey, eth_coin_from_conf_and_request, EthCoin}; @@ -517,18 +517,6 @@ pub fn generate_utxo_coin_with_random_privkey( (ctx, coin, priv_key) } -/// Generates a pair of utxo coin and global NFT_ETH. Fills utxo and NFT_ETH addresses with balance enough for swaps. -/// If mint_nft true, mints one ERC721 and 3 ERC1155 tokens to NFT_ETH address. -pub fn utxo_nft_eth_pair_with_random_privkey( - utxo_ticker: &str, - swap_contract: web3::types::Address, - mint_nft: bool, -) -> (UtxoStandardCoin, EthCoin) { - let (_, utxo, priv_key) = generate_utxo_coin_with_random_privkey(utxo_ticker, 1000.into()); - let global_nft = global_nft_with_privkey(swap_contract, priv_key, mint_nft); - (utxo, global_nft) -} - /// Get only one address assigned the specified label. pub fn get_address_by_label(coin: T, label: &str) -> String where diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index e22fd6a24b..be96345367 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -1,14 +1,13 @@ -use crate::docker_tests::docker_tests_common::{random_secp256k1_secret, ERC1155_TEST_ABI, ERC721_TEST_ABI, - GETH_ACCOUNT, GETH_ERC1155_CONTRACT, GETH_ERC20_CONTRACT, - GETH_ERC721_CONTRACT, GETH_NFT_SWAP_CONTRACT, GETH_NONCE_LOCK, - GETH_SWAP_CONTRACT, GETH_WATCHERS_SWAP_CONTRACT, GETH_WEB3, MM_CTX}; +use super::docker_tests_common::{random_secp256k1_secret, ERC1155_TEST_ABI, ERC721_TEST_ABI, GETH_ACCOUNT, + GETH_ERC1155_CONTRACT, GETH_ERC20_CONTRACT, GETH_ERC721_CONTRACT, + GETH_NFT_SWAP_CONTRACT, GETH_NONCE_LOCK, GETH_SWAP_CONTRACT, + GETH_WATCHERS_SWAP_CONTRACT, GETH_WEB3, MM_CTX}; use bitcrypto::dhash160; use coins::eth::{checksum_address, eth_addr_to_hex, eth_coin_from_conf_and_request, EthCoin, ERC20_ABI}; use coins::nft::nft_structs::{Chain, ContractType, NftInfo}; use coins::{CoinProtocol, ConfirmPaymentInput, FoundSwapTxSpend, MarketCoinOps, PrivKeyBuildPolicy, RefundPaymentArgs, SearchForSwapTxSpendInput, SendPaymentArgs, SpendPaymentArgs, SwapOps, SwapTxTypeWithSecretHash}; use common::{block_on, now_sec}; -use crypto::Secp256k1Secret; use ethereum_types::U256; use futures01::Future; use mm2_number::{BigDecimal, BigUint}; @@ -231,7 +230,6 @@ pub fn erc20_coin_with_random_privkey(swap_contract: Address) -> EthCoin { /// Creates global NFT from generated random privkey supplied with 100 ETH, /// one ERC721 and 3 ERC1155 tokens owned by NFT address in nfts_infos field -#[allow(dead_code)] pub fn global_nft_with_random_privkey(swap_contract: Address) -> EthCoin { let nft_conf = nft_dev_conf(); let req = json!({ @@ -261,39 +259,6 @@ pub fn global_nft_with_random_privkey(swap_contract: Address) -> EthCoin { global_nft } -/// Generates global NFT from privkey supplied with 100 ETH. -/// If mint_nft true, mints one ERC721 and 3 ERC1155 tokens to NFT_ETH address. -pub fn global_nft_with_privkey(swap_contract: Address, priv_key: Secp256k1Secret, mint_nft: bool) -> EthCoin { - let nft_conf = nft_dev_conf(); - let req = json!({ - "method": "enable", - "coin": "NFT_ETH", - "urls": ["http://127.0.0.1:8545"], - "swap_contract_address": swap_contract, - }); - - let global_nft = block_on(eth_coin_from_conf_and_request( - &MM_CTX, - "NFT_ETH", - &nft_conf, - &req, - CoinProtocol::NFT { - platform: "ETH".to_string(), - }, - PrivKeyBuildPolicy::IguanaPrivKey(priv_key), - )) - .unwrap(); - - fill_eth(global_nft.my_address, U256::from(10).pow(U256::from(20))); - if mint_nft { - fill_erc721(global_nft.my_address, U256::from(1)); - fill_erc1155(global_nft.my_address, U256::from(1), U256::from(3)); - block_on(fill_nfts_info(&global_nft, 1u32, BigDecimal::from(3))); - } - - global_nft -} - #[test] fn send_and_refund_eth_maker_payment() { let eth_coin = eth_coin_with_random_privkey(swap_contract()); diff --git a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs index 048aa53ced..7455c51615 100644 --- a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs @@ -1,5 +1,4 @@ -use super::docker_tests_common::{utxo_nft_eth_pair_with_random_privkey, MYCOIN}; -use super::eth_docker_tests::{erc721_contract, nft_swap_contract}; +use super::eth_docker_tests::{erc721_contract, global_nft_with_random_privkey, nft_swap_contract}; use coins::eth::EthCoin; use coins::nft::nft_structs::{Chain, ContractType}; use coins::{CoinAssocTypes, MakerNftSwapOpsV2, SendNftMakerPaymentArgs, SwapOps, ToBytes}; @@ -12,9 +11,8 @@ fn send_and_spend_erc721_maker_payment() { // as EtomicSwapNft will have its own contract address, due to EIP-170 contract size limitations. // TODO need to add NFT conf in coin conf and refactor enable nft a bit - let (_maker_utxo, maker_global_nft) = utxo_nft_eth_pair_with_random_privkey(MYCOIN, nft_swap_contract(), true); - // We can treat taker global NFT as ETH coin, as they are generated with same priv key and configurations - let (_taker_utxo, taker_global_nft) = utxo_nft_eth_pair_with_random_privkey(MYCOIN, nft_swap_contract(), false); + let maker_global_nft = global_nft_with_random_privkey(nft_swap_contract()); + let taker_global_nft = global_nft_with_random_privkey(nft_swap_contract()); let time_lock = now_sec() - 100; let taker_pubkey = taker_global_nft.derive_htlc_pubkey(&[]); @@ -37,9 +35,8 @@ fn send_and_spend_erc721_maker_payment() { #[test] fn send_and_spend_erc1155_maker_payment() { - let (_maker_utxo, maker_global_nft) = utxo_nft_eth_pair_with_random_privkey(MYCOIN, nft_swap_contract(), true); - // We can treat taker global NFT as ETH coin - let (_taker_utxo, taker_global_nft) = utxo_nft_eth_pair_with_random_privkey(MYCOIN, nft_swap_contract(), false); + let maker_global_nft = global_nft_with_random_privkey(nft_swap_contract()); + let taker_global_nft = global_nft_with_random_privkey(nft_swap_contract()); let time_lock = now_sec() - 100; let taker_pubkey = taker_global_nft.derive_htlc_pubkey(&[]); From 656209a592e2196d85940ead3ff1b9b29136900a Mon Sep 17 00:00:00 2001 From: laruh Date: Mon, 18 Mar 2024 19:49:48 +0700 Subject: [PATCH 26/80] add more checks in validate_nft_maker_payment_v2_impl, use validate_nft_maker_payment_v2 WIP fnc in send_and_spend_erc1155_maker_payment test --- mm2src/coins/eth.rs | 65 ++++++++++++++++++- .../docker_tests/nft_swap_proto_v2_tests.rs | 24 +++++-- 2 files changed, 82 insertions(+), 7 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index fe147b82e4..c949c817d1 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -6533,7 +6533,7 @@ impl EthCoin { ) .map_err(ValidatePaymentError::InternalError)?; let expected_swap_contract = self.parse_token_contract_address(args.swap_contract_address)?; - let _maker_address = addr_from_raw_pubkey(args.maker_pub).map_to_mm(ValidatePaymentError::InternalError)?; + let maker_address = addr_from_raw_pubkey(args.maker_pub).map_to_mm(ValidatePaymentError::InternalError)?; let time_lock_u32 = args .time_lock .try_into() @@ -6553,8 +6553,67 @@ impl EthCoin { maker_status ))); } - - todo!() + let tx_from_rpc = self + .transaction(TransactionId::Hash(args.maker_payment_tx.hash)) + .await?; + let tx_from_rpc = tx_from_rpc.as_ref().ok_or_else(|| { + ValidatePaymentError::TxDoesNotExist(format!( + "Didn't find provided tx {:?} on ETH node", + args.maker_payment_tx.hash + )) + })?; + if tx_from_rpc.from != Some(maker_address) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Payment tx {:?} was sent from wrong address, expected {:?}", + tx_from_rpc, maker_address + ))); + } + if tx_from_rpc.to != Some(expected_swap_contract) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Payment tx {:?} was sent to wrong address, expected {:?}", + tx_from_rpc, expected_swap_contract, + ))); + } + match self.coin_type { + EthCoinType::Nft { .. } => match contract_type { + ContractType::Erc1155 => { + let function = NFT_SWAP_CONTRACT + .function("onERC1155Received") + .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; + let decoded = decode_contract_call(function, &tx_from_rpc.input.0) + .map_to_mm(|err| ValidatePaymentError::TxDeserializationError(err.to_string()))?; + if decoded[0] != Token::Address(maker_address) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid `operator` {:?}, expected {:?}", + decoded[0], + Token::Address(maker_address) + ))); + } + if decoded[1] != Token::Address(maker_address) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid `sender` {:?}, expected {:?}", + decoded[1], + Token::Address(maker_address) + ))); + } + // TODO complete other checks + }, + ContractType::Erc721 => { + let function = NFT_SWAP_CONTRACT + .function("onERC721Received") + .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; + let _decoded = decode_contract_call(function, &tx_from_rpc.input.0) + .map_to_mm(|err| ValidatePaymentError::TxDeserializationError(err.to_string()))?; + // TODO complete other checks + }, + }, + EthCoinType::Eth | EthCoinType::Erc20 { .. } => { + return MmError::err(ValidatePaymentError::InternalError( + "EthCoinType must be Nft".to_string(), + )) + }, + } + Ok(()) } async fn payment_status_v2( diff --git a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs index 7455c51615..aa31fe9748 100644 --- a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs @@ -1,7 +1,7 @@ -use super::eth_docker_tests::{erc721_contract, global_nft_with_random_privkey, nft_swap_contract}; +use super::eth_docker_tests::{erc1155_contract, erc721_contract, global_nft_with_random_privkey, nft_swap_contract}; use coins::eth::EthCoin; use coins::nft::nft_structs::{Chain, ContractType}; -use coins::{CoinAssocTypes, MakerNftSwapOpsV2, SendNftMakerPaymentArgs, SwapOps, ToBytes}; +use coins::{CoinAssocTypes, MakerNftSwapOpsV2, SendNftMakerPaymentArgs, SwapOps, ToBytes, ValidateNftMakerPaymentArgs}; use common::{block_on, now_sec}; use mm2_number::BigUint; @@ -39,6 +39,7 @@ fn send_and_spend_erc1155_maker_payment() { let taker_global_nft = global_nft_with_random_privkey(nft_swap_contract()); let time_lock = now_sec() - 100; + let maker_pubkey = maker_global_nft.derive_htlc_pubkey(&[]); let taker_pubkey = taker_global_nft.derive_htlc_pubkey(&[]); let send_payment_args: SendNftMakerPaymentArgs = SendNftMakerPaymentArgs { @@ -48,11 +49,26 @@ fn send_and_spend_erc1155_maker_payment() { amount: 3.into(), taker_pub: &taker_global_nft.parse_pubkey(&taker_pubkey).unwrap(), swap_unique_data: &[], - token_address: &erc721_contract().to_bytes(), + token_address: &erc1155_contract().to_bytes(), token_id: &BigUint::from(1u32).to_bytes(), chain: &Chain::Eth.to_bytes(), contract_type: &ContractType::Erc1155.to_bytes(), swap_contract_address: &nft_swap_contract().to_bytes(), }; - block_on(maker_global_nft.send_nft_maker_payment_v2(send_payment_args)).unwrap(); + let maker_payment = block_on(maker_global_nft.send_nft_maker_payment_v2(send_payment_args)).unwrap(); + let validate_args = ValidateNftMakerPaymentArgs { + maker_payment_tx: &maker_payment, + time_lock, + taker_secret_hash: &[0; 32], + maker_secret_hash: &[0; 32], + amount: 3.into(), + maker_pub: &maker_global_nft.parse_pubkey(&maker_pubkey).unwrap(), + swap_unique_data: &[], + token_address: &erc1155_contract().to_bytes(), + token_id: &BigUint::from(1u32).to_bytes(), + chain: &Chain::Eth.to_bytes(), + contract_type: &ContractType::Erc1155.to_bytes(), + swap_contract_address: &nft_swap_contract().to_bytes(), + }; + block_on(maker_global_nft.validate_nft_maker_payment_v2(validate_args)).unwrap(); } From 014ae6915cc9af54b23ea6f6c0f8321abcb868da Mon Sep 17 00:00:00 2001 From: laruh Date: Mon, 18 Mar 2024 20:48:50 +0700 Subject: [PATCH 27/80] try to call my_address directly --- mm2src/coins/eth.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index c949c817d1..3dbdda3648 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -6400,6 +6400,10 @@ impl EthCoin { let taker_address = addr_from_raw_pubkey(args.taker_pub).map_err(TransactionErr::Plain)?; let token_address = self.parse_token_contract_address(args.token_address)?; let swap_contract_address = self.parse_token_contract_address(args.swap_contract_address)?; + log!( + "swap_contract_address in SEND MAKER FUNCTION{:?}", + swap_contract_address + ); let time_lock_u32 = args .time_lock .try_into() @@ -6425,7 +6429,7 @@ impl EthCoin { Token::Bytes(htlc_data), ])?; let gas = U256::from(ETH_GAS); - self.sign_and_send_transaction(0.into(), Action::Call(token_address), data, gas) + self.sign_and_send_transaction(0.into(), Action::Call(self.my_address), data, gas) .compat() .await }, From 9cf7f17880ba399f5cc9acca53ea5746007dd5a2 Mon Sep 17 00:00:00 2001 From: laruh Date: Mon, 18 Mar 2024 21:13:46 +0700 Subject: [PATCH 28/80] As we call "safeTransferFrom" directly from token_address, then 'to' should equal expected_token_address --- mm2src/coins/eth.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 3dbdda3648..c7181f84ec 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -6400,10 +6400,6 @@ impl EthCoin { let taker_address = addr_from_raw_pubkey(args.taker_pub).map_err(TransactionErr::Plain)?; let token_address = self.parse_token_contract_address(args.token_address)?; let swap_contract_address = self.parse_token_contract_address(args.swap_contract_address)?; - log!( - "swap_contract_address in SEND MAKER FUNCTION{:?}", - swap_contract_address - ); let time_lock_u32 = args .time_lock .try_into() @@ -6429,7 +6425,7 @@ impl EthCoin { Token::Bytes(htlc_data), ])?; let gas = U256::from(ETH_GAS); - self.sign_and_send_transaction(0.into(), Action::Call(self.my_address), data, gas) + self.sign_and_send_transaction(0.into(), Action::Call(token_address), data, gas) .compat() .await }, @@ -6537,6 +6533,7 @@ impl EthCoin { ) .map_err(ValidatePaymentError::InternalError)?; let expected_swap_contract = self.parse_token_contract_address(args.swap_contract_address)?; + let expected_token_address = self.parse_token_contract_address(args.token_address)?; let maker_address = addr_from_raw_pubkey(args.maker_pub).map_to_mm(ValidatePaymentError::InternalError)?; let time_lock_u32 = args .time_lock @@ -6572,10 +6569,11 @@ impl EthCoin { tx_from_rpc, maker_address ))); } - if tx_from_rpc.to != Some(expected_swap_contract) { + // As we call "safeTransferFrom" directly from token_address, then 'to' should be expected_token_address + if tx_from_rpc.to != Some(expected_token_address) { return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( "Payment tx {:?} was sent to wrong address, expected {:?}", - tx_from_rpc, expected_swap_contract, + tx_from_rpc, expected_token_address, ))); } match self.coin_type { From fb5e7b24675708cab8f69226731030a10871c3f9 Mon Sep 17 00:00:00 2001 From: laruh Date: Tue, 19 Mar 2024 13:42:50 +0700 Subject: [PATCH 29/80] try to decode onERC1155Received data from receipt logs --- mm2src/coins/eth.rs | 58 ++++++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index c7181f84ec..3b7b9136b4 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -6565,7 +6565,7 @@ impl EthCoin { })?; if tx_from_rpc.from != Some(maker_address) { return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Payment tx {:?} was sent from wrong address, expected {:?}", + "Maker Payment tx {:?} was sent from wrong address, expected {:?}", tx_from_rpc, maker_address ))); } @@ -6576,27 +6576,47 @@ impl EthCoin { tx_from_rpc, expected_token_address, ))); } + let receipt = self.transaction_receipt(args.maker_payment_tx.hash).await?; + let receipt = match receipt { + Some(r) => r, + None => { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Receipt wasn't found in Maker Payment tx {:?}", + tx_from_rpc + ))) + }, + }; match self.coin_type { EthCoinType::Nft { .. } => match contract_type { ContractType::Erc1155 => { - let function = NFT_SWAP_CONTRACT - .function("onERC1155Received") - .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; - let decoded = decode_contract_call(function, &tx_from_rpc.input.0) - .map_to_mm(|err| ValidatePaymentError::TxDeserializationError(err.to_string()))?; - if decoded[0] != Token::Address(maker_address) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid `operator` {:?}, expected {:?}", - decoded[0], - Token::Address(maker_address) - ))); - } - if decoded[1] != Token::Address(maker_address) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid `sender` {:?}, expected {:?}", - decoded[1], - Token::Address(maker_address) - ))); + let topic = H256::from_slice( + keccak256("onERC1155Received(address,address,uint256,uint256,bytes)".as_bytes()).as_ref(), + ); + let transfer_events = receipt + .logs + .iter() + .filter(|log| log.address == expected_token_address && log.topics.get(0).unwrap() == &topic); + log!("ERC1155 Transfer Events \n {:?}", transfer_events); + for log in transfer_events { + let function = NFT_SWAP_CONTRACT + .function("onERC1155Received") + .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; + let decoded = decode_contract_call(function, &log.data.0) + .map_to_mm(|err| ValidatePaymentError::TxDeserializationError(err.to_string()))?; + if decoded[0] != Token::Address(maker_address) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid `operator` {:?}, expected {:?}", + decoded[0], + Token::Address(maker_address) + ))); + } + if decoded[1] != Token::Address(maker_address) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid `sender` {:?}, expected {:?}", + decoded[1], + Token::Address(maker_address) + ))); + } } // TODO complete other checks }, From 3858db6f98cf2bd11cd28308374bfcca648c43d8 Mon Sep 17 00:00:00 2001 From: laruh Date: Tue, 19 Mar 2024 16:17:18 +0700 Subject: [PATCH 30/80] add taker_pub in ValidateNftMakerPaymentArgs, decode htlc_params --- mm2src/coins/eth.rs | 63 +++++++++++++++++-- mm2src/coins/lp_coins.rs | 2 + .../docker_tests/nft_swap_proto_v2_tests.rs | 1 + 3 files changed, 62 insertions(+), 4 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 3b7b9136b4..9fcd15f95f 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -6543,7 +6543,7 @@ impl EthCoin { let maker_status = self .payment_status_v2( expected_swap_contract, - Token::FixedBytes(swap_id), + Token::FixedBytes(swap_id.clone()), &NFT_SWAP_CONTRACT, StateType::MakerPayments, ) @@ -6596,7 +6596,6 @@ impl EthCoin { .logs .iter() .filter(|log| log.address == expected_token_address && log.topics.get(0).unwrap() == &topic); - log!("ERC1155 Transfer Events \n {:?}", transfer_events); for log in transfer_events { let function = NFT_SWAP_CONTRACT .function("onERC1155Received") @@ -6612,13 +6611,69 @@ impl EthCoin { } if decoded[1] != Token::Address(maker_address) { return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid `sender` {:?}, expected {:?}", + "Invalid `maker` {:?}, expected {:?}", decoded[1], Token::Address(maker_address) ))); } + let token_id = self.parse_token_id(args.token_id)?; + let token_id = U256::from_dec_str(&token_id.to_string()) + .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; + if decoded[2] != Token::Uint(token_id) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid `token_id` {:?}, expected {:?}", + decoded[2], + Token::Uint(token_id) + ))); + } + let value = U256::from_dec_str(&args.amount.to_string()) + .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; + if decoded[3] != Token::Uint(value) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid `amount` {:?}, expected {:?}", + decoded[3], + Token::Uint(value) + ))); + } + + if let Some(Token::Bytes(data_bytes)) = decoded.get(4) { + let htlc_params = &[ + ethabi::ParamType::FixedBytes(32), + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::FixedBytes(32), + ethabi::ParamType::FixedBytes(32), + ethabi::ParamType::Uint(256), + ]; + + if let Ok(decoded_params) = ethabi::decode(htlc_params, data_bytes) { + if decoded_params[0] != Token::FixedBytes(swap_id.clone()) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid 'swap_id' {:?}, expected {:?}", + decoded_params[0], + Token::FixedBytes(swap_id) + ))); + } + let taker_address = addr_from_raw_pubkey(args.taker_pub) + .map_to_mm(ValidatePaymentError::InternalError)?; + if decoded_params[1] != Token::Address(taker_address) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid `taker` {:?}, expected {:?}", + decoded_params[1], + Token::Address(taker_address) + ))); + } + } else { + return MmError::err(ValidatePaymentError::TxDeserializationError( + "Failed to decode HTLCParams from data_bytes".to_string(), + )); + } + } else { + return MmError::err(ValidatePaymentError::TxDeserializationError( + "Expected bytes for HTLCParams data".to_string(), + )); + } } - // TODO complete other checks }, ContractType::Erc721 => { let function = NFT_SWAP_CONTRACT diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index c62c2c3e8e..cd03f9c8e4 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -1597,6 +1597,8 @@ pub struct ValidateNftMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { pub maker_secret_hash: &'a [u8], /// Payment amount pub amount: BigDecimal, + /// Taker's HTLC pubkey + pub taker_pub: &'a Coin::Pubkey, /// Maker's HTLC pubkey pub maker_pub: &'a Coin::Pubkey, /// Unique data of specific swap diff --git a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs index aa31fe9748..09b97b9887 100644 --- a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs @@ -62,6 +62,7 @@ fn send_and_spend_erc1155_maker_payment() { taker_secret_hash: &[0; 32], maker_secret_hash: &[0; 32], amount: 3.into(), + taker_pub: &taker_global_nft.parse_pubkey(&taker_pubkey).unwrap(), maker_pub: &maker_global_nft.parse_pubkey(&maker_pubkey).unwrap(), swap_unique_data: &[], token_address: &erc1155_contract().to_bytes(), From 942a56b29ea25e122bbec3860264b178492d05ad Mon Sep 17 00:00:00 2001 From: laruh Date: Tue, 19 Mar 2024 18:02:18 +0700 Subject: [PATCH 31/80] complete HTLCParams check in Erc1155 --- mm2src/coins/eth.rs | 47 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 9fcd15f95f..f775ddee40 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -6550,7 +6550,7 @@ impl EthCoin { .await?; if maker_status != U256::from(MakerPaymentState::PaymentSent as u8) { return MmError::err(ValidatePaymentError::UnexpectedPaymentState(format!( - "Maker Payment state is not PAYMENT_STATE_SENT, got {}", + "NFT Maker Payment state is not PAYMENT_STATE_SENT, got {}", maker_status ))); } @@ -6565,14 +6565,14 @@ impl EthCoin { })?; if tx_from_rpc.from != Some(maker_address) { return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Maker Payment tx {:?} was sent from wrong address, expected {:?}", + "NFT Maker Payment tx {:?} was sent from wrong address, expected {:?}", tx_from_rpc, maker_address ))); } // As we call "safeTransferFrom" directly from token_address, then 'to' should be expected_token_address if tx_from_rpc.to != Some(expected_token_address) { return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Payment tx {:?} was sent to wrong address, expected {:?}", + "NFT Maker Payment tx {:?} was sent to wrong address, expected {:?}", tx_from_rpc, expected_token_address, ))); } @@ -6581,7 +6581,7 @@ impl EthCoin { Some(r) => r, None => { return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Receipt wasn't found in Maker Payment tx {:?}", + "Receipt wasn't found in NFT Maker Payment tx {:?}", tx_from_rpc ))) }, @@ -6604,14 +6604,14 @@ impl EthCoin { .map_to_mm(|err| ValidatePaymentError::TxDeserializationError(err.to_string()))?; if decoded[0] != Token::Address(maker_address) { return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid `operator` {:?}, expected {:?}", + "NFT Maker Payment `operator` {:?} is invalid, expected {:?}", decoded[0], Token::Address(maker_address) ))); } if decoded[1] != Token::Address(maker_address) { return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid `maker` {:?}, expected {:?}", + "NFT Maker Payment `sender` {:?} is invalid, expected maker address {:?}", decoded[1], Token::Address(maker_address) ))); @@ -6621,7 +6621,7 @@ impl EthCoin { .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; if decoded[2] != Token::Uint(token_id) { return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid `token_id` {:?}, expected {:?}", + "NFT Maker Payment `token_id` {:?} is invalid, expected {:?}", decoded[2], Token::Uint(token_id) ))); @@ -6630,7 +6630,7 @@ impl EthCoin { .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; if decoded[3] != Token::Uint(value) { return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid `amount` {:?}, expected {:?}", + "NFT Maker Payment `amount` {:?} is invalid, expected {:?}", decoded[3], Token::Uint(value) ))); @@ -6663,6 +6663,34 @@ impl EthCoin { Token::Address(taker_address) ))); } + if decoded_params[2] != Token::Address(expected_token_address) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid `token_address` {:?}, expected {:?}", + decoded_params[2], + Token::Address(expected_token_address) + ))); + } + if decoded_params[3] != Token::FixedBytes(args.taker_secret_hash.to_vec()) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid 'taker_secret_hash' {:?}, expected {:?}", + decoded_params[3], + Token::FixedBytes(args.taker_secret_hash.to_vec()) + ))); + } + if decoded_params[4] != Token::FixedBytes(args.maker_secret_hash.to_vec()) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid 'maker_secret_hash' {:?}, expected {:?}", + decoded_params[4], + Token::FixedBytes(args.maker_secret_hash.to_vec()) + ))); + } + if decoded_params[5] != Token::Uint(U256::from(args.time_lock)) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid 'time_lock' {:?}, expected {:?}", + decoded_params[5], + Token::Uint(U256::from(args.time_lock)) + ))); + } } else { return MmError::err(ValidatePaymentError::TxDeserializationError( "Failed to decode HTLCParams from data_bytes".to_string(), @@ -6676,6 +6704,9 @@ impl EthCoin { } }, ContractType::Erc721 => { + let _topic = H256::from_slice( + keccak256("onERC721Received(address,address,uint256,bytes)".as_bytes()).as_ref(), + ); let function = NFT_SWAP_CONTRACT .function("onERC721Received") .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; From 6db6c1c2ce3065b4f0f0154ef8c4add51b6381e2 Mon Sep 17 00:00:00 2001 From: laruh Date: Tue, 19 Mar 2024 18:34:52 +0700 Subject: [PATCH 32/80] HTLCParams check in Erc721, validate erc721 payment in tests --- mm2src/coins/eth.rs | 333 +++++++++++------- .../docker_tests/nft_swap_proto_v2_tests.rs | 19 +- 2 files changed, 232 insertions(+), 120 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index f775ddee40..3497a9e8d7 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -6587,133 +6587,228 @@ impl EthCoin { }, }; match self.coin_type { - EthCoinType::Nft { .. } => match contract_type { - ContractType::Erc1155 => { - let topic = H256::from_slice( - keccak256("onERC1155Received(address,address,uint256,uint256,bytes)".as_bytes()).as_ref(), - ); - let transfer_events = receipt - .logs - .iter() - .filter(|log| log.address == expected_token_address && log.topics.get(0).unwrap() == &topic); - for log in transfer_events { - let function = NFT_SWAP_CONTRACT - .function("onERC1155Received") - .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; - let decoded = decode_contract_call(function, &log.data.0) - .map_to_mm(|err| ValidatePaymentError::TxDeserializationError(err.to_string()))?; - if decoded[0] != Token::Address(maker_address) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment `operator` {:?} is invalid, expected {:?}", - decoded[0], - Token::Address(maker_address) - ))); - } - if decoded[1] != Token::Address(maker_address) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment `sender` {:?} is invalid, expected maker address {:?}", - decoded[1], - Token::Address(maker_address) - ))); - } - let token_id = self.parse_token_id(args.token_id)?; - let token_id = U256::from_dec_str(&token_id.to_string()) - .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; - if decoded[2] != Token::Uint(token_id) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment `token_id` {:?} is invalid, expected {:?}", - decoded[2], - Token::Uint(token_id) - ))); - } - let value = U256::from_dec_str(&args.amount.to_string()) - .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; - if decoded[3] != Token::Uint(value) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment `amount` {:?} is invalid, expected {:?}", - decoded[3], - Token::Uint(value) - ))); - } + EthCoinType::Nft { .. } => { + match contract_type { + ContractType::Erc1155 => { + let topic = H256::from_slice( + keccak256("onERC1155Received(address,address,uint256,uint256,bytes)".as_bytes()).as_ref(), + ); + let transfer_events = receipt.logs.iter().filter(|log| { + log.address == expected_token_address && log.topics.get(0).unwrap() == &topic + }); + for log in transfer_events { + let function = NFT_SWAP_CONTRACT + .function("onERC1155Received") + .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; + let decoded = decode_contract_call(function, &log.data.0) + .map_to_mm(|err| ValidatePaymentError::TxDeserializationError(err.to_string()))?; + if decoded[0] != Token::Address(maker_address) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment `operator` {:?} is invalid, expected {:?}", + decoded[0], + Token::Address(maker_address) + ))); + } + if decoded[1] != Token::Address(maker_address) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment `sender` {:?} is invalid, expected maker address {:?}", + decoded[1], + Token::Address(maker_address) + ))); + } + let token_id = self.parse_token_id(args.token_id)?; + let token_id = U256::from_dec_str(&token_id.to_string()) + .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; + if decoded[2] != Token::Uint(token_id) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment `token_id` {:?} is invalid, expected {:?}", + decoded[2], + Token::Uint(token_id) + ))); + } + let value = U256::from_dec_str(&args.amount.to_string()) + .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; + if decoded[3] != Token::Uint(value) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment `amount` {:?} is invalid, expected {:?}", + decoded[3], + Token::Uint(value) + ))); + } - if let Some(Token::Bytes(data_bytes)) = decoded.get(4) { - let htlc_params = &[ - ethabi::ParamType::FixedBytes(32), - ethabi::ParamType::Address, - ethabi::ParamType::Address, - ethabi::ParamType::FixedBytes(32), - ethabi::ParamType::FixedBytes(32), - ethabi::ParamType::Uint(256), - ]; - - if let Ok(decoded_params) = ethabi::decode(htlc_params, data_bytes) { - if decoded_params[0] != Token::FixedBytes(swap_id.clone()) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid 'swap_id' {:?}, expected {:?}", - decoded_params[0], - Token::FixedBytes(swap_id) - ))); - } - let taker_address = addr_from_raw_pubkey(args.taker_pub) - .map_to_mm(ValidatePaymentError::InternalError)?; - if decoded_params[1] != Token::Address(taker_address) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid `taker` {:?}, expected {:?}", - decoded_params[1], - Token::Address(taker_address) - ))); - } - if decoded_params[2] != Token::Address(expected_token_address) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid `token_address` {:?}, expected {:?}", - decoded_params[2], - Token::Address(expected_token_address) - ))); - } - if decoded_params[3] != Token::FixedBytes(args.taker_secret_hash.to_vec()) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid 'taker_secret_hash' {:?}, expected {:?}", - decoded_params[3], - Token::FixedBytes(args.taker_secret_hash.to_vec()) - ))); - } - if decoded_params[4] != Token::FixedBytes(args.maker_secret_hash.to_vec()) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid 'maker_secret_hash' {:?}, expected {:?}", - decoded_params[4], - Token::FixedBytes(args.maker_secret_hash.to_vec()) - ))); + if let Some(Token::Bytes(data_bytes)) = decoded.get(4) { + let htlc_params = &[ + ethabi::ParamType::FixedBytes(32), + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::FixedBytes(32), + ethabi::ParamType::FixedBytes(32), + ethabi::ParamType::Uint(256), + ]; + + if let Ok(decoded_params) = ethabi::decode(htlc_params, data_bytes) { + if decoded_params[0] != Token::FixedBytes(swap_id.clone()) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid 'swap_id' {:?}, expected {:?}", + decoded_params[0], + Token::FixedBytes(swap_id) + ))); + } + let taker_address = addr_from_raw_pubkey(args.taker_pub) + .map_to_mm(ValidatePaymentError::InternalError)?; + if decoded_params[1] != Token::Address(taker_address) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid `taker` {:?}, expected {:?}", + decoded_params[1], + Token::Address(taker_address) + ))); + } + if decoded_params[2] != Token::Address(expected_token_address) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid `token_address` {:?}, expected {:?}", + decoded_params[2], + Token::Address(expected_token_address) + ))); + } + if decoded_params[3] != Token::FixedBytes(args.taker_secret_hash.to_vec()) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid 'taker_secret_hash' {:?}, expected {:?}", + decoded_params[3], + Token::FixedBytes(args.taker_secret_hash.to_vec()) + ))); + } + if decoded_params[4] != Token::FixedBytes(args.maker_secret_hash.to_vec()) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid 'maker_secret_hash' {:?}, expected {:?}", + decoded_params[4], + Token::FixedBytes(args.maker_secret_hash.to_vec()) + ))); + } + if decoded_params[4] != Token::Uint(U256::from(args.time_lock)) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid 'time_lock' {:?}, expected {:?}", + decoded_params[4], + Token::Uint(U256::from(args.time_lock)) + ))); + } + } else { + return MmError::err(ValidatePaymentError::TxDeserializationError( + "Failed to decode HTLCParams from data_bytes".to_string(), + )); } - if decoded_params[5] != Token::Uint(U256::from(args.time_lock)) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid 'time_lock' {:?}, expected {:?}", - decoded_params[5], - Token::Uint(U256::from(args.time_lock)) - ))); + } else { + return MmError::err(ValidatePaymentError::TxDeserializationError( + "Expected bytes for HTLCParams data".to_string(), + )); + } + } + }, + ContractType::Erc721 => { + let topic = H256::from_slice( + keccak256("onERC721Received(address,address,uint256,bytes)".as_bytes()).as_ref(), + ); + let transfer_events = receipt.logs.iter().filter(|log| { + log.address == expected_token_address && log.topics.get(0).unwrap() == &topic + }); + for log in transfer_events { + let function = NFT_SWAP_CONTRACT + .function("onERC721Received") + .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; + let decoded = decode_contract_call(function, &log.data.0) + .map_to_mm(|err| ValidatePaymentError::TxDeserializationError(err.to_string()))?; + if decoded[0] != Token::Address(maker_address) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment `operator` {:?} is invalid, expected {:?}", + decoded[0], + Token::Address(maker_address) + ))); + } + if decoded[1] != Token::Address(maker_address) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment `sender` {:?} is invalid, expected maker address {:?}", + decoded[1], + Token::Address(maker_address) + ))); + } + let token_id = self.parse_token_id(args.token_id)?; + let token_id = U256::from_dec_str(&token_id.to_string()) + .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; + if decoded[2] != Token::Uint(token_id) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment `token_id` {:?} is invalid, expected {:?}", + decoded[2], + Token::Uint(token_id) + ))); + } + + if let Some(Token::Bytes(data_bytes)) = decoded.get(3) { + let htlc_params = &[ + ethabi::ParamType::FixedBytes(32), + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::FixedBytes(32), + ethabi::ParamType::FixedBytes(32), + ethabi::ParamType::Uint(256), + ]; + + if let Ok(decoded_params) = ethabi::decode(htlc_params, data_bytes) { + if decoded_params[0] != Token::FixedBytes(swap_id.clone()) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid 'swap_id' {:?}, expected {:?}", + decoded_params[0], + Token::FixedBytes(swap_id) + ))); + } + let taker_address = addr_from_raw_pubkey(args.taker_pub) + .map_to_mm(ValidatePaymentError::InternalError)?; + if decoded_params[1] != Token::Address(taker_address) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid `taker` {:?}, expected {:?}", + decoded_params[1], + Token::Address(taker_address) + ))); + } + if decoded_params[2] != Token::Address(expected_token_address) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid `token_address` {:?}, expected {:?}", + decoded_params[2], + Token::Address(expected_token_address) + ))); + } + if decoded_params[3] != Token::FixedBytes(args.taker_secret_hash.to_vec()) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid 'taker_secret_hash' {:?}, expected {:?}", + decoded_params[3], + Token::FixedBytes(args.taker_secret_hash.to_vec()) + ))); + } + if decoded_params[4] != Token::FixedBytes(args.maker_secret_hash.to_vec()) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid 'maker_secret_hash' {:?}, expected {:?}", + decoded_params[4], + Token::FixedBytes(args.maker_secret_hash.to_vec()) + ))); + } + if decoded_params[5] != Token::Uint(U256::from(args.time_lock)) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid 'time_lock' {:?}, expected {:?}", + decoded_params[5], + Token::Uint(U256::from(args.time_lock)) + ))); + } + } else { + return MmError::err(ValidatePaymentError::TxDeserializationError( + "Failed to decode HTLCParams from data_bytes".to_string(), + )); } } else { return MmError::err(ValidatePaymentError::TxDeserializationError( - "Failed to decode HTLCParams from data_bytes".to_string(), + "Expected bytes for HTLCParams data".to_string(), )); } - } else { - return MmError::err(ValidatePaymentError::TxDeserializationError( - "Expected bytes for HTLCParams data".to_string(), - )); } - } - }, - ContractType::Erc721 => { - let _topic = H256::from_slice( - keccak256("onERC721Received(address,address,uint256,bytes)".as_bytes()).as_ref(), - ); - let function = NFT_SWAP_CONTRACT - .function("onERC721Received") - .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; - let _decoded = decode_contract_call(function, &tx_from_rpc.input.0) - .map_to_mm(|err| ValidatePaymentError::TxDeserializationError(err.to_string()))?; - // TODO complete other checks - }, + }, + } }, EthCoinType::Eth | EthCoinType::Erc20 { .. } => { return MmError::err(ValidatePaymentError::InternalError( diff --git a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs index 09b97b9887..1f742ad31d 100644 --- a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs @@ -15,6 +15,7 @@ fn send_and_spend_erc721_maker_payment() { let taker_global_nft = global_nft_with_random_privkey(nft_swap_contract()); let time_lock = now_sec() - 100; + let maker_pubkey = maker_global_nft.derive_htlc_pubkey(&[]); let taker_pubkey = taker_global_nft.derive_htlc_pubkey(&[]); let send_payment_args: SendNftMakerPaymentArgs = SendNftMakerPaymentArgs { @@ -30,7 +31,23 @@ fn send_and_spend_erc721_maker_payment() { contract_type: &ContractType::Erc721.to_bytes(), swap_contract_address: &nft_swap_contract().to_bytes(), }; - block_on(maker_global_nft.send_nft_maker_payment_v2(send_payment_args)).unwrap(); + let maker_payment = block_on(maker_global_nft.send_nft_maker_payment_v2(send_payment_args)).unwrap(); + let validate_args = ValidateNftMakerPaymentArgs { + maker_payment_tx: &maker_payment, + time_lock, + taker_secret_hash: &[0; 32], + maker_secret_hash: &[0; 32], + amount: 1.into(), + taker_pub: &taker_global_nft.parse_pubkey(&taker_pubkey).unwrap(), + maker_pub: &maker_global_nft.parse_pubkey(&maker_pubkey).unwrap(), + swap_unique_data: &[], + token_address: &erc721_contract().to_bytes(), + token_id: &BigUint::from(1u32).to_bytes(), + chain: &Chain::Eth.to_bytes(), + contract_type: &ContractType::Erc721.to_bytes(), + swap_contract_address: &nft_swap_contract().to_bytes(), + }; + block_on(maker_global_nft.validate_nft_maker_payment_v2(validate_args)).unwrap(); } #[test] From 4f8391523ee14943ca1e75e97871681e4c2b56d6 Mon Sep 17 00:00:00 2001 From: laruh Date: Tue, 19 Mar 2024 19:21:12 +0700 Subject: [PATCH 33/80] wait for confirmations --- .../docker_tests/nft_swap_proto_v2_tests.rs | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs index 1f742ad31d..9729731557 100644 --- a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs @@ -1,8 +1,10 @@ use super::eth_docker_tests::{erc1155_contract, erc721_contract, global_nft_with_random_privkey, nft_swap_contract}; use coins::eth::EthCoin; use coins::nft::nft_structs::{Chain, ContractType}; -use coins::{CoinAssocTypes, MakerNftSwapOpsV2, SendNftMakerPaymentArgs, SwapOps, ToBytes, ValidateNftMakerPaymentArgs}; +use coins::{CoinAssocTypes, ConfirmPaymentInput, MakerNftSwapOpsV2, MarketCoinOps, SendNftMakerPaymentArgs, SwapOps, + ToBytes, Transaction, ValidateNftMakerPaymentArgs}; use common::{block_on, now_sec}; +use futures01::Future; use mm2_number::BigUint; #[test] @@ -32,6 +34,16 @@ fn send_and_spend_erc721_maker_payment() { swap_contract_address: &nft_swap_contract().to_bytes(), }; let maker_payment = block_on(maker_global_nft.send_nft_maker_payment_v2(send_payment_args)).unwrap(); + + let confirm_input = ConfirmPaymentInput { + payment_tx: maker_payment.tx_hex(), + confirmations: 1, + requires_nota: false, + wait_until: now_sec() + 60, + check_every: 1, + }; + maker_global_nft.wait_for_confirmations(confirm_input).wait().unwrap(); + let validate_args = ValidateNftMakerPaymentArgs { maker_payment_tx: &maker_payment, time_lock, @@ -73,6 +85,16 @@ fn send_and_spend_erc1155_maker_payment() { swap_contract_address: &nft_swap_contract().to_bytes(), }; let maker_payment = block_on(maker_global_nft.send_nft_maker_payment_v2(send_payment_args)).unwrap(); + + let confirm_input = ConfirmPaymentInput { + payment_tx: maker_payment.tx_hex(), + confirmations: 1, + requires_nota: false, + wait_until: now_sec() + 60, + check_every: 1, + }; + maker_global_nft.wait_for_confirmations(confirm_input).wait().unwrap(); + let validate_args = ValidateNftMakerPaymentArgs { maker_payment_tx: &maker_payment, time_lock, From 1fa28833d1e13e265ec5115c0467d21370d37137 Mon Sep 17 00:00:00 2001 From: laruh Date: Tue, 19 Mar 2024 20:29:36 +0700 Subject: [PATCH 34/80] add No events found in receipt error, dont mint nfts to taker --- mm2src/coins/eth.rs | 14 ++++++++++++++ .../tests/docker_tests/eth_docker_tests.rs | 11 +++++++---- .../tests/docker_tests/nft_swap_proto_v2_tests.rs | 8 ++++---- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 3497a9e8d7..988c1defc0 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -6596,6 +6596,13 @@ impl EthCoin { let transfer_events = receipt.logs.iter().filter(|log| { log.address == expected_token_address && log.topics.get(0).unwrap() == &topic }); + let count = transfer_events.clone().count(); + if count == 0 { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "No events found in receipt {:?}", + receipt + ))); + } for log in transfer_events { let function = NFT_SWAP_CONTRACT .function("onERC1155Received") @@ -6710,6 +6717,13 @@ impl EthCoin { let transfer_events = receipt.logs.iter().filter(|log| { log.address == expected_token_address && log.topics.get(0).unwrap() == &topic }); + let count = transfer_events.clone().count(); + if count == 0 { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "No events found in receipt {:?}", + receipt + ))); + } for log in transfer_events { let function = NFT_SWAP_CONTRACT .function("onERC721Received") diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index be96345367..7f2762617e 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -12,6 +12,7 @@ use ethereum_types::U256; use futures01::Future; use mm2_number::{BigDecimal, BigUint}; use mm2_test_helpers::for_tests::{erc20_dev_conf, eth_dev_conf, nft_dev_conf}; +use std::cmp::min; use std::thread; use std::time::Duration; use web3::contract::{Contract, Options}; @@ -230,7 +231,7 @@ pub fn erc20_coin_with_random_privkey(swap_contract: Address) -> EthCoin { /// Creates global NFT from generated random privkey supplied with 100 ETH, /// one ERC721 and 3 ERC1155 tokens owned by NFT address in nfts_infos field -pub fn global_nft_with_random_privkey(swap_contract: Address) -> EthCoin { +pub fn global_nft_with_random_privkey(swap_contract: Address, mint_nft: bool) -> EthCoin { let nft_conf = nft_dev_conf(); let req = json!({ "method": "enable", @@ -252,9 +253,11 @@ pub fn global_nft_with_random_privkey(swap_contract: Address) -> EthCoin { .unwrap(); fill_eth(global_nft.my_address, U256::from(10).pow(U256::from(20))); - fill_erc721(global_nft.my_address, U256::from(1)); - fill_erc1155(global_nft.my_address, U256::from(1), U256::from(3)); - block_on(fill_nfts_info(&global_nft, 1u32, BigDecimal::from(3))); + if mint_nft { + fill_erc721(global_nft.my_address, U256::from(1)); + fill_erc1155(global_nft.my_address, U256::from(1), U256::from(3)); + block_on(fill_nfts_info(&global_nft, 1u32, BigDecimal::from(3))); + } global_nft } diff --git a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs index 9729731557..7c3f97b0eb 100644 --- a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs @@ -13,8 +13,8 @@ fn send_and_spend_erc721_maker_payment() { // as EtomicSwapNft will have its own contract address, due to EIP-170 contract size limitations. // TODO need to add NFT conf in coin conf and refactor enable nft a bit - let maker_global_nft = global_nft_with_random_privkey(nft_swap_contract()); - let taker_global_nft = global_nft_with_random_privkey(nft_swap_contract()); + let maker_global_nft = global_nft_with_random_privkey(nft_swap_contract(), true); + let taker_global_nft = global_nft_with_random_privkey(nft_swap_contract(), false); let time_lock = now_sec() - 100; let maker_pubkey = maker_global_nft.derive_htlc_pubkey(&[]); @@ -64,8 +64,8 @@ fn send_and_spend_erc721_maker_payment() { #[test] fn send_and_spend_erc1155_maker_payment() { - let maker_global_nft = global_nft_with_random_privkey(nft_swap_contract()); - let taker_global_nft = global_nft_with_random_privkey(nft_swap_contract()); + let maker_global_nft = global_nft_with_random_privkey(nft_swap_contract(), true); + let taker_global_nft = global_nft_with_random_privkey(nft_swap_contract(), false); let time_lock = now_sec() - 100; let maker_pubkey = maker_global_nft.derive_htlc_pubkey(&[]); From cc477ba0ecb984aa93467509be3f8b75f457331e Mon Sep 17 00:00:00 2001 From: laruh Date: Tue, 19 Mar 2024 21:09:29 +0700 Subject: [PATCH 35/80] refactor global_nft_with_random_privkey test func with mint and fill nft funcs, assert erc721 owner and check erc1155 balance --- mm2src/coins/eth.rs | 4 +- mm2src/coins/nft/nft_errors.rs | 7 +- .../tests/docker_tests/eth_docker_tests.rs | 91 ++++++++++++++----- .../docker_tests/nft_swap_proto_v2_tests.rs | 15 ++- 4 files changed, 80 insertions(+), 37 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 988c1defc0..aff92a5cd0 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -6691,10 +6691,10 @@ impl EthCoin { Token::FixedBytes(args.maker_secret_hash.to_vec()) ))); } - if decoded_params[4] != Token::Uint(U256::from(args.time_lock)) { + if decoded_params[5] != Token::Uint(U256::from(args.time_lock)) { return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( "Invalid 'time_lock' {:?}, expected {:?}", - decoded_params[4], + decoded_params[5], Token::Uint(U256::from(args.time_lock)) ))); } diff --git a/mm2src/coins/nft/nft_errors.rs b/mm2src/coins/nft/nft_errors.rs index ba1c31c0d2..cf1342fe5b 100644 --- a/mm2src/coins/nft/nft_errors.rs +++ b/mm2src/coins/nft/nft_errors.rs @@ -213,10 +213,6 @@ pub enum UpdateNftError { CoinDoesntSupportNft { coin: String, }, - #[display(fmt = "Global NFT type mismatch for token '{}'", token)] - GlobalNftTypeMismatch { - token: String, - }, } impl From for UpdateNftError { @@ -273,8 +269,7 @@ impl HttpStatusCode for UpdateNftError { | UpdateNftError::SerdeError(_) | UpdateNftError::ProtectFromSpamError(_) | UpdateNftError::NoSuchCoin { .. } - | UpdateNftError::CoinDoesntSupportNft { .. } - | UpdateNftError::GlobalNftTypeMismatch { .. } => StatusCode::INTERNAL_SERVER_ERROR, + | UpdateNftError::CoinDoesntSupportNft { .. } => StatusCode::INTERNAL_SERVER_ERROR, } } } diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index 7f2762617e..c5d2af45ac 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -12,7 +12,6 @@ use ethereum_types::U256; use futures01::Future; use mm2_number::{BigDecimal, BigUint}; use mm2_test_helpers::for_tests::{erc20_dev_conf, eth_dev_conf, nft_dev_conf}; -use std::cmp::min; use std::thread; use std::time::Duration; use web3::contract::{Contract, Options}; @@ -105,7 +104,7 @@ fn fill_erc20(to_addr: Address, amount: U256) { wait_for_confirmation(tx_hash); } -pub(crate) fn fill_erc721(to_addr: Address, token_id: U256) { +pub(crate) fn mint_erc721(to_addr: Address, token_id: U256) { let _guard = GETH_NONCE_LOCK.lock().unwrap(); let erc721_contract = Contract::from_json(GETH_WEB3.eth(), erc721_contract(), ERC721_TEST_ABI.as_bytes()).unwrap(); @@ -122,9 +121,18 @@ pub(crate) fn fill_erc721(to_addr: Address, token_id: U256) { )) .unwrap(); wait_for_confirmation(tx_hash); + + let owner: Address = + block_on(erc721_contract.query("ownerOf", Token::Uint(token_id), None, Options::default(), None)).unwrap(); + + assert_eq!( + owner, to_addr, + "The ownership of the tokenID {:?} does not match the expected address {:?}.", + token_id, to_addr + ); } -pub(crate) fn fill_erc1155(to_addr: Address, token_id: U256, amount: U256) { +pub(crate) fn mint_erc1155(to_addr: Address, token_id: U256, amount: U256) { let _guard = GETH_NONCE_LOCK.lock().unwrap(); let erc1155_contract = Contract::from_json(GETH_WEB3.eth(), erc1155_contract(), ERC1155_TEST_ABI.as_bytes()).unwrap(); @@ -142,33 +150,54 @@ pub(crate) fn fill_erc1155(to_addr: Address, token_id: U256, amount: U256) { )) .unwrap(); wait_for_confirmation(tx_hash); + + // Check the balance of the token for the to_addr + let balance: U256 = block_on(erc1155_contract.query( + "balanceOf", + (Token::Address(to_addr), Token::Uint(token_id)), + None, + Options::default(), + None, + )) + .unwrap(); + + assert_eq!( + balance, amount, + "The balance of tokenId {:?} for address {:?} does not match the expected amount {:?}.", + token_id, to_addr, amount + ); +} + +pub(crate) async fn fill_erc1155_info(eth_coin: &EthCoin, tokens_id: u32, amount: u32) { + let nft_infos_lock = eth_coin.nfts_infos.clone(); + let mut nft_infos = nft_infos_lock.lock().await; + + let erc1155_nft_info = NftInfo { + token_address: erc1155_contract(), + token_id: BigUint::from(tokens_id), + chain: Chain::Eth, + contract_type: ContractType::Erc1155, + amount: BigDecimal::from(amount), + }; + let erc1155_address_str = eth_addr_to_hex(&erc1155_contract()); + let erc1155_key = format!("{},{}", erc1155_address_str, tokens_id); + nft_infos.insert(erc1155_key, erc1155_nft_info); } -pub(crate) async fn fill_nfts_info(eth_coin: &EthCoin, tokens_ids: u32, erc1155_amount: BigDecimal) { +pub(crate) async fn fill_erc721_info(eth_coin: &EthCoin, tokens_id: u32) { let nft_infos_lock = eth_coin.nfts_infos.clone(); let mut nft_infos = nft_infos_lock.lock().await; let erc721_nft_info = NftInfo { token_address: erc721_contract(), - token_id: BigUint::from(tokens_ids), + token_id: BigUint::from(tokens_id), chain: Chain::Eth, contract_type: ContractType::Erc721, amount: BigDecimal::from(1), }; let erc721_address_str = eth_addr_to_hex(&erc721_contract()); - let erc721_key = format!("{},{}", erc721_address_str, tokens_ids); + let erc721_key = format!("{},{}", erc721_address_str, tokens_id); nft_infos.insert(erc721_key, erc721_nft_info); - - let erc1155_nft_info = NftInfo { - token_address: erc1155_contract(), - token_id: BigUint::from(tokens_ids), - chain: Chain::Eth, - contract_type: ContractType::Erc1155, - amount: erc1155_amount, - }; - let erc1155_address_str = eth_addr_to_hex(&erc1155_contract()); - let erc1155_key = format!("{},{}", erc1155_address_str, tokens_ids); - nft_infos.insert(erc1155_key, erc1155_nft_info); } /// Creates ETH protocol coin supplied with 100 ETH @@ -229,9 +258,15 @@ pub fn erc20_coin_with_random_privkey(swap_contract: Address) -> EthCoin { erc20_coin } -/// Creates global NFT from generated random privkey supplied with 100 ETH, -/// one ERC721 and 3 ERC1155 tokens owned by NFT address in nfts_infos field -pub fn global_nft_with_random_privkey(swap_contract: Address, mint_nft: bool) -> EthCoin { +pub enum TestNftType { + Erc1155 { token_id: u32, amount: u32 }, + Erc721 { token_id: u32 }, +} + +/// Generates a global NFT coin instance with a random private key and an initial 100 ETH balance. +/// Optionally mints a specified NFT (either ERC721 or ERC1155) to the global NFT address, +/// with details recorded in the `nfts_infos` field based on the provided `nft_type`. +pub fn global_nft_with_random_privkey(swap_contract: Address, nft_type: Option) -> EthCoin { let nft_conf = nft_dev_conf(); let req = json!({ "method": "enable", @@ -253,10 +288,18 @@ pub fn global_nft_with_random_privkey(swap_contract: Address, mint_nft: bool) -> .unwrap(); fill_eth(global_nft.my_address, U256::from(10).pow(U256::from(20))); - if mint_nft { - fill_erc721(global_nft.my_address, U256::from(1)); - fill_erc1155(global_nft.my_address, U256::from(1), U256::from(3)); - block_on(fill_nfts_info(&global_nft, 1u32, BigDecimal::from(3))); + + if let Some(nft_type) = nft_type { + match nft_type { + TestNftType::Erc1155 { token_id, amount } => { + mint_erc1155(global_nft.my_address, U256::from(token_id), U256::from(amount)); + block_on(fill_erc1155_info(&global_nft, token_id, amount)); + }, + TestNftType::Erc721 { token_id } => { + mint_erc721(global_nft.my_address, U256::from(token_id)); + block_on(fill_erc721_info(&global_nft, token_id)); + }, + } } global_nft diff --git a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs index 7c3f97b0eb..ca11b65f4d 100644 --- a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs @@ -1,4 +1,5 @@ -use super::eth_docker_tests::{erc1155_contract, erc721_contract, global_nft_with_random_privkey, nft_swap_contract}; +use super::eth_docker_tests::{erc1155_contract, erc721_contract, global_nft_with_random_privkey, nft_swap_contract, + TestNftType}; use coins::eth::EthCoin; use coins::nft::nft_structs::{Chain, ContractType}; use coins::{CoinAssocTypes, ConfirmPaymentInput, MakerNftSwapOpsV2, MarketCoinOps, SendNftMakerPaymentArgs, SwapOps, @@ -13,8 +14,10 @@ fn send_and_spend_erc721_maker_payment() { // as EtomicSwapNft will have its own contract address, due to EIP-170 contract size limitations. // TODO need to add NFT conf in coin conf and refactor enable nft a bit - let maker_global_nft = global_nft_with_random_privkey(nft_swap_contract(), true); - let taker_global_nft = global_nft_with_random_privkey(nft_swap_contract(), false); + let erc721_nft = TestNftType::Erc721 { token_id: 1 }; + + let maker_global_nft = global_nft_with_random_privkey(nft_swap_contract(), Some(erc721_nft)); + let taker_global_nft = global_nft_with_random_privkey(nft_swap_contract(), None); let time_lock = now_sec() - 100; let maker_pubkey = maker_global_nft.derive_htlc_pubkey(&[]); @@ -64,8 +67,10 @@ fn send_and_spend_erc721_maker_payment() { #[test] fn send_and_spend_erc1155_maker_payment() { - let maker_global_nft = global_nft_with_random_privkey(nft_swap_contract(), true); - let taker_global_nft = global_nft_with_random_privkey(nft_swap_contract(), false); + let erc1155_nft = TestNftType::Erc1155 { token_id: 1, amount: 3 }; + + let maker_global_nft = global_nft_with_random_privkey(nft_swap_contract(), Some(erc1155_nft)); + let taker_global_nft = global_nft_with_random_privkey(nft_swap_contract(), None); let time_lock = now_sec() - 100; let maker_pubkey = maker_global_nft.derive_htlc_pubkey(&[]); From 1011caae9e297839204e5f84b744edfc2503421e Mon Sep 17 00:00:00 2001 From: laruh Date: Wed, 20 Mar 2024 14:08:53 +0700 Subject: [PATCH 36/80] check nft ownership --- mm2src/coins/eth.rs | 5 +++++ mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs | 2 ++ .../mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs | 4 ++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index aff92a5cd0..5b880b51f6 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -52,6 +52,7 @@ use ethkey::{public_to_address, sign, verify_address, KeyPair, Public, Signature use futures::compat::Future01CompatExt; use futures::future::{join_all, select_ok, try_join_all, Either, FutureExt, TryFutureExt}; use futures01::Future; +use hex::ToHex; use http::{StatusCode, Uri}; use instant::Instant; use keys::Public as HtlcPubKey; @@ -6409,6 +6410,10 @@ impl EthCoin { U256::from_dec_str(&token_id.to_string()).map_err(|e| NumConversError::new(ERRL!("{}", e)))?; let htlc_data = self.prepare_htlc_data(&args, taker_address, token_address, time_lock_u32); + println!("htlc_data vec \n {:?} \n", htlc_data); + let hex_htlc_data = htlc_data.encode_hex::(); + println!("hex_htlc_data \n {:?} \n", hex_htlc_data); + match &self.coin_type { EthCoinType::Nft { .. } => match contract_type { ContractType::Erc1155 => { diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index c5d2af45ac..7882834b64 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -130,6 +130,7 @@ pub(crate) fn mint_erc721(to_addr: Address, token_id: U256) { "The ownership of the tokenID {:?} does not match the expected address {:?}.", token_id, to_addr ); + println!("\n to_addr {:?}, current ERC721 owner {:?} \n", to_addr, owner) } pub(crate) fn mint_erc1155(to_addr: Address, token_id: U256, amount: U256) { @@ -166,6 +167,7 @@ pub(crate) fn mint_erc1155(to_addr: Address, token_id: U256, amount: U256) { "The balance of tokenId {:?} for address {:?} does not match the expected amount {:?}.", token_id, to_addr, amount ); + println!("\n to_addr {:?}, ERC1155 balance {:?} \n", to_addr, balance); } pub(crate) async fn fill_erc1155_info(eth_coin: &EthCoin, tokens_id: u32, amount: u32) { diff --git a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs index ca11b65f4d..a8643e8b45 100644 --- a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs @@ -14,7 +14,7 @@ fn send_and_spend_erc721_maker_payment() { // as EtomicSwapNft will have its own contract address, due to EIP-170 contract size limitations. // TODO need to add NFT conf in coin conf and refactor enable nft a bit - let erc721_nft = TestNftType::Erc721 { token_id: 1 }; + let erc721_nft = TestNftType::Erc721 { token_id: 2 }; let maker_global_nft = global_nft_with_random_privkey(nft_swap_contract(), Some(erc721_nft)); let taker_global_nft = global_nft_with_random_privkey(nft_swap_contract(), None); @@ -31,7 +31,7 @@ fn send_and_spend_erc721_maker_payment() { taker_pub: &taker_global_nft.parse_pubkey(&taker_pubkey).unwrap(), swap_unique_data: &[], token_address: &erc721_contract().to_bytes(), - token_id: &BigUint::from(1u32).to_bytes(), + token_id: &BigUint::from(2u32).to_bytes(), chain: &Chain::Eth.to_bytes(), contract_type: &ContractType::Erc721.to_bytes(), swap_contract_address: &nft_swap_contract().to_bytes(), From fc888c71cf0f14b2edc5b881d8ae02f8956f7643 Mon Sep 17 00:00:00 2001 From: laruh Date: Wed, 20 Mar 2024 16:58:11 +0700 Subject: [PATCH 37/80] add interfaceId == type(IERC721Receiver).interfaceId in function supportsInterface in EtomicSwapNft contract --- mm2src/coins/eth.rs | 5 ----- mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs | 2 +- mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs | 2 -- .../mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs | 2 ++ 4 files changed, 3 insertions(+), 8 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 5b880b51f6..aff92a5cd0 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -52,7 +52,6 @@ use ethkey::{public_to_address, sign, verify_address, KeyPair, Public, Signature use futures::compat::Future01CompatExt; use futures::future::{join_all, select_ok, try_join_all, Either, FutureExt, TryFutureExt}; use futures01::Future; -use hex::ToHex; use http::{StatusCode, Uri}; use instant::Instant; use keys::Public as HtlcPubKey; @@ -6410,10 +6409,6 @@ impl EthCoin { U256::from_dec_str(&token_id.to_string()).map_err(|e| NumConversError::new(ERRL!("{}", e)))?; let htlc_data = self.prepare_htlc_data(&args, taker_address, token_address, time_lock_u32); - println!("htlc_data vec \n {:?} \n", htlc_data); - let hex_htlc_data = htlc_data.encode_hex::(); - println!("hex_htlc_data \n {:?} \n", hex_htlc_data); - match &self.coin_type { EthCoinType::Nft { .. } => match contract_type { ContractType::Erc1155 => { diff --git a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs index e3e20ba1af..c854ef0c29 100644 --- a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs +++ b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs @@ -111,7 +111,7 @@ pub const SWAP_CONTRACT_BYTES: &str = "608060405234801561001057600080fd5b5061143 pub const WATCHERS_SWAP_CONTRACT_BYTES: &str = "608060405234801561000f575f80fd5b50612aa48061001d5f395ff3fe608060405260043610610085575f3560e01c806346fc02941161005857806346fc0294146101275780636a3227861461014f5780639b415b2a1461016b578063b5985c4d14610193578063cd1dde34146101bb57610085565b806302ed292b146100895780630716326d146100b15780630971fd54146100ef578063152cf3af1461010b575b5f80fd5b348015610094575f80fd5b506100af60048036038101906100aa9190611e1d565b6101e3565b005b3480156100bc575f80fd5b506100d760048036038101906100d29190611e94565b610518565b6040516100e693929190611f8e565b60405180910390f35b6101096004803603810190610104919061206f565b610568565b005b6101256004803603810190610120919061210c565b610787565b005b348015610132575f80fd5b5061014d60048036038101906101489190612170565b61099d565b005b610169600480360381019061016491906121e7565b610c4d565b005b348015610176575f80fd5b50610191600480360381019061018c91906122ab565b610f61565b005b34801561019e575f80fd5b506101b960048036038101906101b49190612334565b611203565b005b3480156101c6575f80fd5b506101e160048036038101906101dc91906123f8565b611887565b005b600160038111156101f7576101f6611f1b565b5b5f808781526020019081526020015f205f01601c9054906101000a900460ff16600381111561022957610228611f1b565b5b14610232575f80fd5b5f60033383600360028860405160200161024c91906124dc565b6040516020818303038152906040526040516102689190612562565b602060405180830381855afa158015610283573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906102a6919061258c565b6040516020016102b691906124dc565b6040516020818303038152906040526040516102d29190612562565b602060405180830381855afa1580156102ed573d5f803e3d5ffd5b5050506040515160601b868960405160200161030d95949392919061263c565b6040516020818303038152906040526040516103299190612562565b602060405180830381855afa158015610344573d5f803e3d5ffd5b5050506040515160601b90505f808781526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610397575f80fd5b60025f808881526020019081526020015f205f01601c6101000a81548160ff021916908360038111156103cd576103cc611f1b565b5b02179055505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361044e573373ffffffffffffffffffffffffffffffffffffffff166108fc8690811502906040515f60405180830381858888f19350505050158015610448573d5f803e3d5ffd5b506104d7565b5f8390508073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33886040518363ffffffff1660e01b815260040161048d9291906126b8565b6020604051808303815f875af11580156104a9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104cd91906126f3565b6104d5575f80fd5b505b7f36c177bcb01c6d568244f05261e2946c8c977fa50822f3fa098c470770ee1f3e868560405161050892919061272d565b60405180910390a1505050505050565b5f602052805f5260405f205f91509050805f015f9054906101000a900460601b90805f0160149054906101000a900467ffffffffffffffff1690805f01601c9054906101000a900460ff16905083565b5f73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16141580156105a357505f34115b80156105f157505f60038111156105bd576105bc611f1b565b5b5f808981526020019081526020015f205f01601c9054906101000a900460ff1660038111156105ef576105ee611f1b565b5b145b6105f9575f80fd5b5f60038733885f3489898960405160200161061b9897969594939291906127e7565b6040516020818303038152906040526040516106379190612562565b602060405180830381855afa158015610652573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018667ffffffffffffffff168152602001600160038111156106a2576106a1611f1b565b5b8152505f808a81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506040820151815f01601c6101000a81548160ff0219169083600381111561073e5761073d611f1b565b5b02179055509050507fccc9c05183599bd3135da606eaaf535daffe256e9de33c048014cffcccd4ad57886040516107759190612878565b60405180910390a15050505050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141580156107c257505f34115b801561081057505f60038111156107dc576107db611f1b565b5b5f808681526020019081526020015f205f01601c9054906101000a900460ff16600381111561080e5761080d611f1b565b5b145b610818575f80fd5b5f60038433855f3460405160200161083495949392919061263c565b6040516020818303038152906040526040516108509190612562565b602060405180830381855afa15801561086b573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018367ffffffffffffffff168152602001600160038111156108bb576108ba611f1b565b5b8152505f808781526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506040820151815f01601c6101000a81548160ff0219169083600381111561095757610956611f1b565b5b02179055509050507fccc9c05183599bd3135da606eaaf535daffe256e9de33c048014cffcccd4ad578560405161098e9190612878565b60405180910390a15050505050565b600160038111156109b1576109b0611f1b565b5b5f808781526020019081526020015f205f01601c9054906101000a900460ff1660038111156109e3576109e2611f1b565b5b146109ec575f80fd5b5f60038233868689604051602001610a0895949392919061263c565b604051602081830303815290604052604051610a249190612562565b602060405180830381855afa158015610a3f573d5f803e3d5ffd5b5050506040515160601b90505f808781526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916148015610ac657505f808781526020019081526020015f205f0160149054906101000a900467ffffffffffffffff1667ffffffffffffffff164210155b610ace575f80fd5b60035f808881526020019081526020015f205f01601c6101000a81548160ff02191690836003811115610b0457610b03611f1b565b5b02179055505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610b85573373ffffffffffffffffffffffffffffffffffffffff166108fc8690811502906040515f60405180830381858888f19350505050158015610b7f573d5f803e3d5ffd5b50610c0e565b5f8390508073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33886040518363ffffffff1660e01b8152600401610bc49291906126b8565b6020604051808303815f875af1158015610be0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c0491906126f3565b610c0c575f80fd5b505b7f1797d500133f8e427eb9da9523aa4a25cb40f50ebc7dbda3c7c81778973f35ba86604051610c3d9190612878565b60405180910390a1505050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614158015610c8857505f88115b8015610cd657505f6003811115610ca257610ca1611f1b565b5b5f808b81526020019081526020015f205f01601c9054906101000a900460ff166003811115610cd457610cd3611f1b565b5b145b610cde575f80fd5b5f6003811115610cf157610cf0611f1b565b5b836003811115610d0457610d03611f1b565b5b14158015610d365750600380811115610d2057610d1f611f1b565b5b836003811115610d3357610d32611f1b565b5b14155b15610d4757803414610d46575f80fd5b5b5f60038733888b8d898989604051602001610d699897969594939291906127e7565b604051602081830303815290604052604051610d859190612562565b602060405180830381855afa158015610da0573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018667ffffffffffffffff16815260200160016003811115610df057610def611f1b565b5b8152505f808c81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506040820151815f01601c6101000a81548160ff02191690836003811115610e8c57610e8b611f1b565b5b02179055509050505f8890508073ffffffffffffffffffffffffffffffffffffffff166323b872dd33308d6040518463ffffffff1660e01b8152600401610ed593929190612891565b6020604051808303815f875af1158015610ef1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f1591906126f3565b610f1d575f80fd5b7fccc9c05183599bd3135da606eaaf535daffe256e9de33c048014cffcccd4ad578b604051610f4c9190612878565b60405180910390a15050505050505050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614158015610f9c57505f85115b8015610fea57505f6003811115610fb657610fb5611f1b565b5b5f808881526020019081526020015f205f01601c9054906101000a900460ff166003811115610fe857610fe7611f1b565b5b145b610ff2575f80fd5b5f6003843385888a60405160200161100e95949392919061263c565b60405160208183030381529060405260405161102a9190612562565b602060405180830381855afa158015611045573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018367ffffffffffffffff1681526020016001600381111561109557611094611f1b565b5b8152505f808981526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506040820151815f01601c6101000a81548160ff0219169083600381111561113157611130611f1b565b5b02179055509050505f8590508073ffffffffffffffffffffffffffffffffffffffff166323b872dd33308a6040518463ffffffff1660e01b815260040161117a93929190612891565b6020604051808303815f875af1158015611196573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111ba91906126f3565b6111c2575f80fd5b7fccc9c05183599bd3135da606eaaf535daffe256e9de33c048014cffcccd4ad57886040516111f19190612878565b60405180910390a15050505050505050565b6001600381111561121757611216611f1b565b5b5f808b81526020019081526020015f205f01601c9054906101000a900460ff16600381111561124957611248611f1b565b5b14611289576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161128090612920565b60405180910390fd5b5f60038587600360028c6040516020016112a391906124dc565b6040516020818303038152906040526040516112bf9190612562565b602060405180830381855afa1580156112da573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906112fd919061258c565b60405160200161130d91906124dc565b6040516020818303038152906040526040516113299190612562565b602060405180830381855afa158015611344573d5f803e3d5ffd5b5050506040515160601b8a8d89898960405160200161136a9897969594939291906127e7565b6040516020818303038152906040526040516113869190612562565b602060405180830381855afa1580156113a1573d5f803e3d5ffd5b5050506040515160601b90505f808b81526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461142b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161142290612988565b60405180910390fd5b60025f808c81526020019081526020015f205f01601c6101000a81548160ff0219169083600381111561146157611460611f1b565b5b02179055505f73ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff160361159e575f8060038111156114ad576114ac611f1b565b5b8560038111156114c0576114bf611f1b565b5b1480156114cb575083155b6114e057828a6114db91906129d3565b6114e2565b895b90508573ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f19350505050158015611527573d5f803e3d5ffd5b5060038081111561153b5761153a611f1b565b5b85600381111561154e5761154d611f1b565b5b03611598573373ffffffffffffffffffffffffffffffffffffffff166108fc8490811502906040515f60405180830381858888f19350505050158015611596573d5f803e3d5ffd5b505b50611786565b5f6003808111156115b2576115b1611f1b565b5b8560038111156115c5576115c4611f1b565b5b146115d057896115dd565b828a6115dc91906129d3565b5b90505f8890508073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb88846040518363ffffffff1660e01b815260040161161e9291906126b8565b6020604051808303815f875af115801561163a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061165e91906126f3565b61169d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161169490612a50565b60405180910390fd5b6003808111156116b0576116af611f1b565b5b8660038111156116c3576116c2611f1b565b5b03611783578073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33866040518363ffffffff1660e01b81526004016117039291906126b8565b6020604051808303815f875af115801561171f573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061174391906126f3565b611782576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161177990612a50565b60405180910390fd5b5b50505b6002600381111561179a57611799611f1b565b5b8460038111156117ad576117ac611f1b565b5b036117f7578573ffffffffffffffffffffffffffffffffffffffff166108fc8390811502906040515f60405180830381858888f193505050501580156117f5573d5f803e3d5ffd5b505b8215611842573373ffffffffffffffffffffffffffffffffffffffff166108fc8390811502906040515f60405180830381858888f19350505050158015611840573d5f803e3d5ffd5b505b7f36c177bcb01c6d568244f05261e2946c8c977fa50822f3fa098c470770ee1f3e8a8960405161187392919061272d565b60405180910390a150505050505050505050565b6001600381111561189b5761189a611f1b565b5b5f808b81526020019081526020015f205f01601c9054906101000a900460ff1660038111156118cd576118cc611f1b565b5b146118d6575f80fd5b5f600385878a8a8d8989896040516020016118f89897969594939291906127e7565b6040516020818303038152906040526040516119149190612562565b602060405180830381855afa15801561192f573d5f803e3d5ffd5b5050506040515160601b90505f808b81526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161480156119b657505f808b81526020019081526020015f205f0160149054906101000a900467ffffffffffffffff1667ffffffffffffffff164210155b6119be575f80fd5b60035f808c81526020019081526020015f205f01601c6101000a81548160ff021916908360038111156119f4576119f3611f1b565b5b02179055505f73ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1603611b27575f806003811115611a4057611a3f611f1b565b5b856003811115611a5357611a52611f1b565b5b14611a6957828a611a6491906129d3565b611a6b565b895b90508673ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f19350505050158015611ab0573d5f803e3d5ffd5b505f6003811115611ac457611ac3611f1b565b5b856003811115611ad757611ad6611f1b565b5b14611b21573373ffffffffffffffffffffffffffffffffffffffff166108fc8490811502906040515f60405180830381858888f19350505050158015611b1f573d5f803e3d5ffd5b505b50611d16565b5f600380811115611b3b57611b3a611f1b565b5b856003811115611b4e57611b4d611f1b565b5b14611b595789611b66565b828a611b6591906129d3565b5b90505f8890508073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb89846040518363ffffffff1660e01b8152600401611ba79291906126b8565b6020604051808303815f875af1158015611bc3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611be791906126f3565b611bef575f80fd5b600380811115611c0257611c01611f1b565b5b866003811115611c1557611c14611f1b565b5b03611ca2578073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33866040518363ffffffff1660e01b8152600401611c559291906126b8565b6020604051808303815f875af1158015611c71573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c9591906126f3565b611c9d575f80fd5b611d13565b5f6003811115611cb557611cb4611f1b565b5b866003811115611cc857611cc7611f1b565b5b14611d12573373ffffffffffffffffffffffffffffffffffffffff166108fc8590811502906040515f60405180830381858888f19350505050158015611d10573d5f803e3d5ffd5b505b5b50505b7f1797d500133f8e427eb9da9523aa4a25cb40f50ebc7dbda3c7c81778973f35ba8a604051611d459190612878565b60405180910390a150505050505050505050565b5f80fd5b5f819050919050565b611d6f81611d5d565b8114611d79575f80fd5b50565b5f81359050611d8a81611d66565b92915050565b5f819050919050565b611da281611d90565b8114611dac575f80fd5b50565b5f81359050611dbd81611d99565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f611dec82611dc3565b9050919050565b611dfc81611de2565b8114611e06575f80fd5b50565b5f81359050611e1781611df3565b92915050565b5f805f805f60a08688031215611e3657611e35611d59565b5b5f611e4388828901611d7c565b9550506020611e5488828901611daf565b9450506040611e6588828901611d7c565b9350506060611e7688828901611e09565b9250506080611e8788828901611e09565b9150509295509295909350565b5f60208284031215611ea957611ea8611d59565b5b5f611eb684828501611d7c565b91505092915050565b5f7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b611ef381611ebf565b82525050565b5f67ffffffffffffffff82169050919050565b611f1581611ef9565b82525050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60048110611f5957611f58611f1b565b5b50565b5f819050611f6982611f48565b919050565b5f611f7882611f5c565b9050919050565b611f8881611f6e565b82525050565b5f606082019050611fa15f830186611eea565b611fae6020830185611f0c565b611fbb6040830184611f7f565b949350505050565b611fcc81611ebf565b8114611fd6575f80fd5b50565b5f81359050611fe781611fc3565b92915050565b611ff681611ef9565b8114612000575f80fd5b50565b5f8135905061201181611fed565b92915050565b60048110612023575f80fd5b50565b5f8135905061203481612017565b92915050565b5f8115159050919050565b61204e8161203a565b8114612058575f80fd5b50565b5f8135905061206981612045565b92915050565b5f805f805f805f60e0888a03121561208a57612089611d59565b5b5f6120978a828b01611d7c565b97505060206120a88a828b01611e09565b96505060406120b98a828b01611fd9565b95505060606120ca8a828b01612003565b94505060806120db8a828b01612026565b93505060a06120ec8a828b0161205b565b92505060c06120fd8a828b01611daf565b91505092959891949750929550565b5f805f806080858703121561212457612123611d59565b5b5f61213187828801611d7c565b945050602061214287828801611e09565b935050604061215387828801611fd9565b925050606061216487828801612003565b91505092959194509250565b5f805f805f60a0868803121561218957612188611d59565b5b5f61219688828901611d7c565b95505060206121a788828901611daf565b94505060406121b888828901611fd9565b93505060606121c988828901611e09565b92505060806121da88828901611e09565b9150509295509295909350565b5f805f805f805f805f6101208a8c03121561220557612204611d59565b5b5f6122128c828d01611d7c565b99505060206122238c828d01611daf565b98505060406122348c828d01611e09565b97505060606122458c828d01611e09565b96505060806122568c828d01611fd9565b95505060a06122678c828d01612003565b94505060c06122788c828d01612026565b93505060e06122898c828d0161205b565b92505061010061229b8c828d01611daf565b9150509295985092959850929598565b5f805f805f8060c087890312156122c5576122c4611d59565b5b5f6122d289828a01611d7c565b96505060206122e389828a01611daf565b95505060406122f489828a01611e09565b945050606061230589828a01611e09565b935050608061231689828a01611fd9565b92505060a061232789828a01612003565b9150509295509295509295565b5f805f805f805f805f6101208a8c03121561235257612351611d59565b5b5f61235f8c828d01611d7c565b99505060206123708c828d01611daf565b98505060406123818c828d01611d7c565b97505060606123928c828d01611e09565b96505060806123a38c828d01611e09565b95505060a06123b48c828d01611e09565b94505060c06123c58c828d01612026565b93505060e06123d68c828d0161205b565b9250506101006123e88c828d01611daf565b9150509295985092959850929598565b5f805f805f805f805f6101208a8c03121561241657612415611d59565b5b5f6124238c828d01611d7c565b99505060206124348c828d01611daf565b98505060406124458c828d01611fd9565b97505060606124568c828d01611e09565b96505060806124678c828d01611e09565b95505060a06124788c828d01611e09565b94505060c06124898c828d01612026565b93505060e061249a8c828d0161205b565b9250506101006124ac8c828d01611daf565b9150509295985092959850929598565b5f819050919050565b6124d66124d182611d5d565b6124bc565b82525050565b5f6124e782846124c5565b60208201915081905092915050565b5f81519050919050565b5f81905092915050565b5f5b8381101561252757808201518184015260208101905061250c565b5f8484015250505050565b5f61253c826124f6565b6125468185612500565b935061255681856020860161250a565b80840191505092915050565b5f61256d8284612532565b915081905092915050565b5f8151905061258681611d66565b92915050565b5f602082840312156125a1576125a0611d59565b5b5f6125ae84828501612578565b91505092915050565b5f8160601b9050919050565b5f6125cd826125b7565b9050919050565b5f6125de826125c3565b9050919050565b6125f66125f182611de2565b6125d4565b82525050565b5f819050919050565b61261661261182611ebf565b6125fc565b82525050565b5f819050919050565b61263661263182611d90565b61261c565b82525050565b5f61264782886125e5565b60148201915061265782876125e5565b6014820191506126678286612605565b60148201915061267782856125e5565b6014820191506126878284612625565b6020820191508190509695505050505050565b6126a381611de2565b82525050565b6126b281611d90565b82525050565b5f6040820190506126cb5f83018561269a565b6126d860208301846126a9565b9392505050565b5f815190506126ed81612045565b92915050565b5f6020828403121561270857612707611d59565b5b5f612715848285016126df565b91505092915050565b61272781611d5d565b82525050565b5f6040820190506127405f83018561271e565b61274d602083018461271e565b9392505050565b6004811061276557612764611f1b565b5b50565b5f81905061277582612754565b919050565b5f61278482612768565b9050919050565b5f8160f81b9050919050565b5f6127a18261278b565b9050919050565b6127b96127b48261277a565b612797565b82525050565b5f6127c982612797565b9050919050565b6127e16127dc8261203a565b6127bf565b82525050565b5f6127f2828b6125e5565b601482019150612802828a6125e5565b6014820191506128128289612605565b60148201915061282282886125e5565b6014820191506128328287612625565b60208201915061284282866127a8565b60018201915061285282856127d0565b6001820191506128628284612625565b6020820191508190509998505050505050505050565b5f60208201905061288b5f83018461271e565b92915050565b5f6060820190506128a45f83018661269a565b6128b1602083018561269a565b6128be60408301846126a9565b949350505050565b5f82825260208201905092915050565b7f5061796d656e7420776173206e6f742073656e740000000000000000000000005f82015250565b5f61290a6014836128c6565b9150612915826128d6565b602082019050919050565b5f6020820190508181035f830152612937816128fe565b9050919050565b7f496e76616c6964207061796d656e7420686173680000000000000000000000005f82015250565b5f6129726014836128c6565b915061297d8261293e565b602082019050919050565b5f6020820190508181035f83015261299f81612966565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6129dd82611d90565b91506129e883611d90565b9250828203905081811115612a00576129ff6129a6565b5b92915050565b7f546f6b656e207472616e73666572206661696c656400000000000000000000005f82015250565b5f612a3a6015836128c6565b9150612a4582612a06565b602082019050919050565b5f6020820190508181035f830152612a6781612a2e565b905091905056fea26469706673582212203106867e1b147b377237cde0aba42d82faf0282b83d7b6d62cca039d0b7f840564736f6c63430008160033"; pub const ERC721_TEST_TOKEN_BYTES: &str = "608060405234801562000010575f80fd5b50604051620022ac380380620022ac8339818101604052810190620000369190620001ea565b8181815f9081620000489190620004a4565b5080600190816200005a9190620004a4565b505050505062000588565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b620000c6826200007e565b810181811067ffffffffffffffff82111715620000e857620000e76200008e565b5b80604052505050565b5f620000fc62000065565b90506200010a8282620000bb565b919050565b5f67ffffffffffffffff8211156200012c576200012b6200008e565b5b62000137826200007e565b9050602081019050919050565b5f5b838110156200016357808201518184015260208101905062000146565b5f8484015250505050565b5f620001846200017e846200010f565b620000f1565b905082815260208101848484011115620001a357620001a26200007a565b5b620001b084828562000144565b509392505050565b5f82601f830112620001cf57620001ce62000076565b5b8151620001e18482602086016200016e565b91505092915050565b5f80604083850312156200020357620002026200006e565b5b5f83015167ffffffffffffffff81111562000223576200022262000072565b5b6200023185828601620001b8565b925050602083015167ffffffffffffffff81111562000255576200025462000072565b5b6200026385828601620001b8565b9150509250929050565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680620002bc57607f821691505b602082108103620002d257620002d162000277565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620003367fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620002f9565b620003428683620002f9565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f6200038c6200038662000380846200035a565b62000363565b6200035a565b9050919050565b5f819050919050565b620003a7836200036c565b620003bf620003b68262000393565b84845462000305565b825550505050565b5f90565b620003d5620003c7565b620003e28184846200039c565b505050565b5b818110156200040957620003fd5f82620003cb565b600181019050620003e8565b5050565b601f82111562000458576200042281620002d8565b6200042d84620002ea565b810160208510156200043d578190505b620004556200044c85620002ea565b830182620003e7565b50505b505050565b5f82821c905092915050565b5f6200047a5f19846008026200045d565b1980831691505092915050565b5f62000494838362000469565b9150826002028217905092915050565b620004af826200026d565b67ffffffffffffffff811115620004cb57620004ca6200008e565b5b620004d78254620002a4565b620004e48282856200040d565b5f60209050601f8311600181146200051a575f841562000505578287015190505b62000511858262000487565b86555062000580565b601f1984166200052a86620002d8565b5f5b8281101562000553578489015182556001820191506020850194506020810190506200052c565b868310156200057357848901516200056f601f89168262000469565b8355505b6001600288020188555050505b505050505050565b611d1680620005965f395ff3fe608060405234801561000f575f80fd5b50600436106100e8575f3560e01c80636352211e1161008a578063a22cb46511610064578063a22cb46514610258578063b88d4fde14610274578063c87b56dd14610290578063e985e9c5146102c0576100e8565b80636352211e146101da57806370a082311461020a57806395d89b411461023a576100e8565b8063095ea7b3116100c6578063095ea7b31461016a57806323b872dd1461018657806340c10f19146101a257806342842e0e146101be576100e8565b806301ffc9a7146100ec57806306fdde031461011c578063081812fc1461013a575b5f80fd5b610106600480360381019061010191906115a7565b6102f0565b60405161011391906115ec565b60405180910390f35b6101246103d1565b604051610131919061168f565b60405180910390f35b610154600480360381019061014f91906116e2565b610460565b604051610161919061174c565b60405180910390f35b610184600480360381019061017f919061178f565b61047b565b005b6101a0600480360381019061019b91906117cd565b610491565b005b6101bc60048036038101906101b7919061178f565b610590565b005b6101d860048036038101906101d391906117cd565b61059e565b005b6101f460048036038101906101ef91906116e2565b6105bd565b604051610201919061174c565b60405180910390f35b610224600480360381019061021f919061181d565b6105ce565b6040516102319190611857565b60405180910390f35b610242610684565b60405161024f919061168f565b60405180910390f35b610272600480360381019061026d919061189a565b610714565b005b61028e60048036038101906102899190611a04565b61072a565b005b6102aa60048036038101906102a591906116e2565b610747565b6040516102b7919061168f565b60405180910390f35b6102da60048036038101906102d59190611a84565b6107ad565b6040516102e791906115ec565b60405180910390f35b5f7f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806103ba57507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806103ca57506103c98261083b565b5b9050919050565b60605f80546103df90611aef565b80601f016020809104026020016040519081016040528092919081815260200182805461040b90611aef565b80156104565780601f1061042d57610100808354040283529160200191610456565b820191905f5260205f20905b81548152906001019060200180831161043957829003601f168201915b5050505050905090565b5f61046a826108a4565b506104748261092a565b9050919050565b61048d8282610488610963565b61096a565b5050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610501575f6040517f64a0ae920000000000000000000000000000000000000000000000000000000081526004016104f8919061174c565b60405180910390fd5b5f610514838361050f610963565b61097c565b90508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461058a578382826040517f64283d7b00000000000000000000000000000000000000000000000000000000815260040161058193929190611b1f565b60405180910390fd5b50505050565b61059a8282610b87565b5050565b6105b883838360405180602001604052805f81525061072a565b505050565b5f6105c7826108a4565b9050919050565b5f8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361063f575f6040517f89c62b64000000000000000000000000000000000000000000000000000000008152600401610636919061174c565b60405180910390fd5b60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b60606001805461069390611aef565b80601f01602080910402602001604051908101604052809291908181526020018280546106bf90611aef565b801561070a5780601f106106e15761010080835404028352916020019161070a565b820191905f5260205f20905b8154815290600101906020018083116106ed57829003601f168201915b5050505050905090565b61072661071f610963565b8383610c7a565b5050565b610735848484610491565b61074184848484610de3565b50505050565b6060610752826108a4565b505f61075c610f95565b90505f81511161077a5760405180602001604052805f8152506107a5565b8061078484610fab565b604051602001610795929190611b8e565b6040516020818303038152906040525b915050919050565b5f60055f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16905092915050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f806108af83611075565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361092157826040517f7e2732890000000000000000000000000000000000000000000000000000000081526004016109189190611857565b60405180910390fd5b80915050919050565b5f60045f8381526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b5f33905090565b61097783838360016110ae565b505050565b5f8061098784611075565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146109c8576109c781848661126d565b5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610a5357610a075f855f806110ae565b600160035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825403925050819055505b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614610ad257600160035f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055505b8460025f8681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550838573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4809150509392505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610bf7575f6040517f64a0ae92000000000000000000000000000000000000000000000000000000008152600401610bee919061174c565b60405180910390fd5b5f610c0383835f61097c565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610c75575f6040517f73c6ac6e000000000000000000000000000000000000000000000000000000008152600401610c6c919061174c565b60405180910390fd5b505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610cea57816040517f5b08ba18000000000000000000000000000000000000000000000000000000008152600401610ce1919061174c565b60405180910390fd5b8060055f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051610dd691906115ec565b60405180910390a3505050565b5f8373ffffffffffffffffffffffffffffffffffffffff163b1115610f8f578273ffffffffffffffffffffffffffffffffffffffff1663150b7a02610e26610963565b8685856040518563ffffffff1660e01b8152600401610e489493929190611c03565b6020604051808303815f875af1925050508015610e8357506040513d601f19601f82011682018060405250810190610e809190611c61565b60015b610f04573d805f8114610eb1576040519150601f19603f3d011682016040523d82523d5f602084013e610eb6565b606091505b505f815103610efc57836040517f64a0ae92000000000000000000000000000000000000000000000000000000008152600401610ef3919061174c565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614610f8d57836040517f64a0ae92000000000000000000000000000000000000000000000000000000008152600401610f84919061174c565b60405180910390fd5b505b50505050565b606060405180602001604052805f815250905090565b60605f6001610fb984611330565b0190505f8167ffffffffffffffff811115610fd757610fd66118e0565b5b6040519080825280601f01601f1916602001820160405280156110095781602001600182028036833780820191505090505b5090505f82602001820190505b60011561106a578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a858161105f5761105e611c8c565b5b0494505f8503611016575b819350505050919050565b5f60025f8381526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b80806110e657505f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b15611218575f6110f5846108a4565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415801561115f57508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b8015611172575061117081846107ad565b155b156111b457826040517fa9fbf51f0000000000000000000000000000000000000000000000000000000081526004016111ab919061174c565b60405180910390fd5b811561121657838573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b8360045f8581526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505050565b611278838383611481565b61132b575f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036112ec57806040517f7e2732890000000000000000000000000000000000000000000000000000000081526004016112e39190611857565b60405180910390fd5b81816040517f177e802f000000000000000000000000000000000000000000000000000000008152600401611322929190611cb9565b60405180910390fd5b505050565b5f805f90507a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000831061138c577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000838161138257611381611c8c565b5b0492506040810190505b6d04ee2d6d415b85acef810000000083106113c9576d04ee2d6d415b85acef810000000083816113bf576113be611c8c565b5b0492506020810190505b662386f26fc1000083106113f857662386f26fc1000083816113ee576113ed611c8c565b5b0492506010810190505b6305f5e1008310611421576305f5e100838161141757611416611c8c565b5b0492506008810190505b612710831061144657612710838161143c5761143b611c8c565b5b0492506004810190505b60648310611469576064838161145f5761145e611c8c565b5b0492506002810190505b600a8310611478576001810190505b80915050919050565b5f8073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415801561153857508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614806114f957506114f884846107ad565b5b8061153757508273ffffffffffffffffffffffffffffffffffffffff1661151f8361092a565b73ffffffffffffffffffffffffffffffffffffffff16145b5b90509392505050565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61158681611552565b8114611590575f80fd5b50565b5f813590506115a18161157d565b92915050565b5f602082840312156115bc576115bb61154a565b5b5f6115c984828501611593565b91505092915050565b5f8115159050919050565b6115e6816115d2565b82525050565b5f6020820190506115ff5f8301846115dd565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561163c578082015181840152602081019050611621565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61166182611605565b61166b818561160f565b935061167b81856020860161161f565b61168481611647565b840191505092915050565b5f6020820190508181035f8301526116a78184611657565b905092915050565b5f819050919050565b6116c1816116af565b81146116cb575f80fd5b50565b5f813590506116dc816116b8565b92915050565b5f602082840312156116f7576116f661154a565b5b5f611704848285016116ce565b91505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6117368261170d565b9050919050565b6117468161172c565b82525050565b5f60208201905061175f5f83018461173d565b92915050565b61176e8161172c565b8114611778575f80fd5b50565b5f8135905061178981611765565b92915050565b5f80604083850312156117a5576117a461154a565b5b5f6117b28582860161177b565b92505060206117c3858286016116ce565b9150509250929050565b5f805f606084860312156117e4576117e361154a565b5b5f6117f18682870161177b565b93505060206118028682870161177b565b9250506040611813868287016116ce565b9150509250925092565b5f602082840312156118325761183161154a565b5b5f61183f8482850161177b565b91505092915050565b611851816116af565b82525050565b5f60208201905061186a5f830184611848565b92915050565b611879816115d2565b8114611883575f80fd5b50565b5f8135905061189481611870565b92915050565b5f80604083850312156118b0576118af61154a565b5b5f6118bd8582860161177b565b92505060206118ce85828601611886565b9150509250929050565b5f80fd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61191682611647565b810181811067ffffffffffffffff82111715611935576119346118e0565b5b80604052505050565b5f611947611541565b9050611953828261190d565b919050565b5f67ffffffffffffffff821115611972576119716118e0565b5b61197b82611647565b9050602081019050919050565b828183375f83830152505050565b5f6119a86119a384611958565b61193e565b9050828152602081018484840111156119c4576119c36118dc565b5b6119cf848285611988565b509392505050565b5f82601f8301126119eb576119ea6118d8565b5b81356119fb848260208601611996565b91505092915050565b5f805f8060808587031215611a1c57611a1b61154a565b5b5f611a298782880161177b565b9450506020611a3a8782880161177b565b9350506040611a4b878288016116ce565b925050606085013567ffffffffffffffff811115611a6c57611a6b61154e565b5b611a78878288016119d7565b91505092959194509250565b5f8060408385031215611a9a57611a9961154a565b5b5f611aa78582860161177b565b9250506020611ab88582860161177b565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680611b0657607f821691505b602082108103611b1957611b18611ac2565b5b50919050565b5f606082019050611b325f83018661173d565b611b3f6020830185611848565b611b4c604083018461173d565b949350505050565b5f81905092915050565b5f611b6882611605565b611b728185611b54565b9350611b8281856020860161161f565b80840191505092915050565b5f611b998285611b5e565b9150611ba58284611b5e565b91508190509392505050565b5f81519050919050565b5f82825260208201905092915050565b5f611bd582611bb1565b611bdf8185611bbb565b9350611bef81856020860161161f565b611bf881611647565b840191505092915050565b5f608082019050611c165f83018761173d565b611c23602083018661173d565b611c306040830185611848565b8181036060830152611c428184611bcb565b905095945050505050565b5f81519050611c5b8161157d565b92915050565b5f60208284031215611c7657611c7561154a565b5b5f611c8384828501611c4d565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f604082019050611ccc5f83018561173d565b611cd96020830184611848565b939250505056fea26469706673582212207439b47c2a9a1624955997732075917bbf1da26949d000c778f561eb5687576164736f6c63430008180033"; pub const ERC1155_TEST_TOKEN_BYTES: &str = "608060405234801562000010575f80fd5b50604051620024eb380380620024eb8339818101604052810190620000369190620001ea565b8062000048816200005060201b60201c565b505062000554565b806002908162000061919062000470565b5050565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b620000c6826200007e565b810181811067ffffffffffffffff82111715620000e857620000e76200008e565b5b80604052505050565b5f620000fc62000065565b90506200010a8282620000bb565b919050565b5f67ffffffffffffffff8211156200012c576200012b6200008e565b5b62000137826200007e565b9050602081019050919050565b5f5b838110156200016357808201518184015260208101905062000146565b5f8484015250505050565b5f620001846200017e846200010f565b620000f1565b905082815260208101848484011115620001a357620001a26200007a565b5b620001b084828562000144565b509392505050565b5f82601f830112620001cf57620001ce62000076565b5b8151620001e18482602086016200016e565b91505092915050565b5f602082840312156200020257620002016200006e565b5b5f82015167ffffffffffffffff81111562000222576200022162000072565b5b6200023084828501620001b8565b91505092915050565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806200028857607f821691505b6020821081036200029e576200029d62000243565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620003027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620002c5565b6200030e8683620002c5565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f62000358620003526200034c8462000326565b6200032f565b62000326565b9050919050565b5f819050919050565b620003738362000338565b6200038b62000382826200035f565b848454620002d1565b825550505050565b5f90565b620003a162000393565b620003ae81848462000368565b505050565b5b81811015620003d557620003c95f8262000397565b600181019050620003b4565b5050565b601f8211156200042457620003ee81620002a4565b620003f984620002b6565b8101602085101562000409578190505b620004216200041885620002b6565b830182620003b3565b50505b505050565b5f82821c905092915050565b5f620004465f198460080262000429565b1980831691505092915050565b5f62000460838362000435565b9150826002028217905092915050565b6200047b8262000239565b67ffffffffffffffff8111156200049757620004966200008e565b5b620004a3825462000270565b620004b0828285620003d9565b5f60209050601f831160018114620004e6575f8415620004d1578287015190505b620004dd858262000453565b8655506200054c565b601f198416620004f686620002a4565b5f5b828110156200051f57848901518255600182019150602085019450602081019050620004f8565b868310156200053f57848901516200053b601f89168262000435565b8355505b6001600288020188555050505b505050505050565b611f8980620005625f395ff3fe608060405234801561000f575f80fd5b5060043610610090575f3560e01c80634e1273f4116100645780634e1273f414610140578063731133e914610170578063a22cb4651461018c578063e985e9c5146101a8578063f242432a146101d857610090565b8062fdd58e1461009457806301ffc9a7146100c45780630e89341c146100f45780632eb2c2d614610124575b5f80fd5b6100ae60048036038101906100a991906113bd565b6101f4565b6040516100bb919061140a565b60405180910390f35b6100de60048036038101906100d99190611478565b610249565b6040516100eb91906114bd565b60405180910390f35b61010e600480360381019061010991906114d6565b61032a565b60405161011b919061158b565b60405180910390f35b61013e6004803603810190610139919061179b565b6103bc565b005b61015a60048036038101906101559190611926565b610463565b6040516101679190611a53565b60405180910390f35b61018a60048036038101906101859190611a73565b61056a565b005b6101a660048036038101906101a19190611b1d565b61057c565b005b6101c260048036038101906101bd9190611b5b565b610592565b6040516101cf91906114bd565b60405180910390f35b6101f260048036038101906101ed9190611b99565b610620565b005b5f805f8381526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905092915050565b5f7fd9b67a26000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061031357507f0e89341c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806103235750610322826106c7565b5b9050919050565b60606002805461033990611c59565b80601f016020809104026020016040519081016040528092919081815260200182805461036590611c59565b80156103b05780601f10610387576101008083540402835291602001916103b0565b820191905f5260205f20905b81548152906001019060200180831161039357829003601f168201915b50505050509050919050565b5f6103c5610730565b90508073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161415801561040a57506104088682610592565b155b1561044e5780866040517fe237d922000000000000000000000000000000000000000000000000000000008152600401610445929190611c98565b60405180910390fd5b61045b8686868686610737565b505050505050565b606081518351146104af57815183516040517f5b0599910000000000000000000000000000000000000000000000000000000081526004016104a6929190611cbf565b60405180910390fd5b5f835167ffffffffffffffff8111156104cb576104ca6115af565b5b6040519080825280602002602001820160405280156104f95781602001602082028036833780820191505090505b5090505f5b845181101561055f5761053561051d828761082b90919063ffffffff16565b610530838761083e90919063ffffffff16565b6101f4565b82828151811061054857610547611ce6565b5b6020026020010181815250508060010190506104fe565b508091505092915050565b61057684848484610851565b50505050565b61058e610587610730565b83836108e6565b5050565b5f60015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16905092915050565b5f610629610730565b90508073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161415801561066e575061066c8682610592565b155b156106b25780866040517fe237d9220000000000000000000000000000000000000000000000000000000081526004016106a9929190611c98565b60405180910390fd5b6106bf8686868686610a4f565b505050505050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f33905090565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036107a7575f6040517f57f447ce00000000000000000000000000000000000000000000000000000000815260040161079e9190611d13565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603610817575f6040517f01a8351400000000000000000000000000000000000000000000000000000000815260040161080e9190611d13565b60405180910390fd5b6108248585858585610b55565b5050505050565b5f60208202602084010151905092915050565b5f60208202602084010151905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036108c1575f6040517f57f447ce0000000000000000000000000000000000000000000000000000000081526004016108b89190611d13565b60405180910390fd5b5f806108cd8585610c01565b915091506108de5f87848487610b55565b505050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610956575f6040517fced3e10000000000000000000000000000000000000000000000000000000000815260040161094d9190611d13565b60405180910390fd5b8060015f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051610a4291906114bd565b60405180910390a3505050565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610abf575f6040517f57f447ce000000000000000000000000000000000000000000000000000000008152600401610ab69190611d13565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603610b2f575f6040517f01a83514000000000000000000000000000000000000000000000000000000008152600401610b269190611d13565b60405180910390fd5b5f80610b3b8585610c01565b91509150610b4c8787848487610b55565b50505050505050565b610b6185858585610c31565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614610bfa575f610b9d610730565b90506001845103610be9575f610bbc5f8661083e90919063ffffffff16565b90505f610bd25f8661083e90919063ffffffff16565b9050610be2838989858589610fc1565b5050610bf8565b610bf7818787878787611170565b5b505b5050505050565b60608060405191506001825283602083015260408201905060018152826020820152604081016040529250929050565b8051825114610c7b57815181516040517f5b059991000000000000000000000000000000000000000000000000000000008152600401610c72929190611cbf565b60405180910390fd5b5f610c84610730565b90505f5b8351811015610e80575f610ca5828661083e90919063ffffffff16565b90505f610cbb838661083e90919063ffffffff16565b90505f73ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614610dde575f805f8481526020019081526020015f205f8a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905081811015610d8a57888183856040517f03dee4c5000000000000000000000000000000000000000000000000000000008152600401610d819493929190611d2c565b60405180910390fd5b8181035f808581526020019081526020015f205f8b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550505b5f73ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614610e7357805f808481526020019081526020015f205f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610e6b9190611d9c565b925050819055505b5050806001019050610c88565b506001835103610f3b575f610e9e5f8561083e90919063ffffffff16565b90505f610eb45f8561083e90919063ffffffff16565b90508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628585604051610f2c929190611cbf565b60405180910390a45050610fba565b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8686604051610fb1929190611dcf565b60405180910390a45b5050505050565b5f8473ffffffffffffffffffffffffffffffffffffffff163b1115611168578373ffffffffffffffffffffffffffffffffffffffff1663f23a6e6187878686866040518663ffffffff1660e01b8152600401611021959493929190611e56565b6020604051808303815f875af192505050801561105c57506040513d601f19601f820116820180604052508101906110599190611ec2565b60015b6110dd573d805f811461108a576040519150601f19603f3d011682016040523d82523d5f602084013e61108f565b606091505b505f8151036110d557846040517f57f447ce0000000000000000000000000000000000000000000000000000000081526004016110cc9190611d13565b60405180910390fd5b805181602001fd5b63f23a6e6160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461116657846040517f57f447ce00000000000000000000000000000000000000000000000000000000815260040161115d9190611d13565b60405180910390fd5b505b505050505050565b5f8473ffffffffffffffffffffffffffffffffffffffff163b1115611317578373ffffffffffffffffffffffffffffffffffffffff1663bc197c8187878686866040518663ffffffff1660e01b81526004016111d0959493929190611eed565b6020604051808303815f875af192505050801561120b57506040513d601f19601f820116820180604052508101906112089190611ec2565b60015b61128c573d805f8114611239576040519150601f19603f3d011682016040523d82523d5f602084013e61123e565b606091505b505f81510361128457846040517f57f447ce00000000000000000000000000000000000000000000000000000000815260040161127b9190611d13565b60405180910390fd5b805181602001fd5b63bc197c8160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461131557846040517f57f447ce00000000000000000000000000000000000000000000000000000000815260040161130c9190611d13565b60405180910390fd5b505b505050505050565b5f604051905090565b5f80fd5b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61135982611330565b9050919050565b6113698161134f565b8114611373575f80fd5b50565b5f8135905061138481611360565b92915050565b5f819050919050565b61139c8161138a565b81146113a6575f80fd5b50565b5f813590506113b781611393565b92915050565b5f80604083850312156113d3576113d2611328565b5b5f6113e085828601611376565b92505060206113f1858286016113a9565b9150509250929050565b6114048161138a565b82525050565b5f60208201905061141d5f8301846113fb565b92915050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61145781611423565b8114611461575f80fd5b50565b5f813590506114728161144e565b92915050565b5f6020828403121561148d5761148c611328565b5b5f61149a84828501611464565b91505092915050565b5f8115159050919050565b6114b7816114a3565b82525050565b5f6020820190506114d05f8301846114ae565b92915050565b5f602082840312156114eb576114ea611328565b5b5f6114f8848285016113a9565b91505092915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561153857808201518184015260208101905061151d565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61155d82611501565b611567818561150b565b935061157781856020860161151b565b61158081611543565b840191505092915050565b5f6020820190508181035f8301526115a38184611553565b905092915050565b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6115e582611543565b810181811067ffffffffffffffff82111715611604576116036115af565b5b80604052505050565b5f61161661131f565b905061162282826115dc565b919050565b5f67ffffffffffffffff821115611641576116406115af565b5b602082029050602081019050919050565b5f80fd5b5f61166861166384611627565b61160d565b9050808382526020820190506020840283018581111561168b5761168a611652565b5b835b818110156116b457806116a088826113a9565b84526020840193505060208101905061168d565b5050509392505050565b5f82601f8301126116d2576116d16115ab565b5b81356116e2848260208601611656565b91505092915050565b5f80fd5b5f67ffffffffffffffff821115611709576117086115af565b5b61171282611543565b9050602081019050919050565b828183375f83830152505050565b5f61173f61173a846116ef565b61160d565b90508281526020810184848401111561175b5761175a6116eb565b5b61176684828561171f565b509392505050565b5f82601f830112611782576117816115ab565b5b813561179284826020860161172d565b91505092915050565b5f805f805f60a086880312156117b4576117b3611328565b5b5f6117c188828901611376565b95505060206117d288828901611376565b945050604086013567ffffffffffffffff8111156117f3576117f261132c565b5b6117ff888289016116be565b935050606086013567ffffffffffffffff8111156118205761181f61132c565b5b61182c888289016116be565b925050608086013567ffffffffffffffff81111561184d5761184c61132c565b5b6118598882890161176e565b9150509295509295909350565b5f67ffffffffffffffff8211156118805761187f6115af565b5b602082029050602081019050919050565b5f6118a361189e84611866565b61160d565b905080838252602082019050602084028301858111156118c6576118c5611652565b5b835b818110156118ef57806118db8882611376565b8452602084019350506020810190506118c8565b5050509392505050565b5f82601f83011261190d5761190c6115ab565b5b813561191d848260208601611891565b91505092915050565b5f806040838503121561193c5761193b611328565b5b5f83013567ffffffffffffffff8111156119595761195861132c565b5b611965858286016118f9565b925050602083013567ffffffffffffffff8111156119865761198561132c565b5b611992858286016116be565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b6119ce8161138a565b82525050565b5f6119df83836119c5565b60208301905092915050565b5f602082019050919050565b5f611a018261199c565b611a0b81856119a6565b9350611a16836119b6565b805f5b83811015611a46578151611a2d88826119d4565b9750611a38836119eb565b925050600181019050611a19565b5085935050505092915050565b5f6020820190508181035f830152611a6b81846119f7565b905092915050565b5f805f8060808587031215611a8b57611a8a611328565b5b5f611a9887828801611376565b9450506020611aa9878288016113a9565b9350506040611aba878288016113a9565b925050606085013567ffffffffffffffff811115611adb57611ada61132c565b5b611ae78782880161176e565b91505092959194509250565b611afc816114a3565b8114611b06575f80fd5b50565b5f81359050611b1781611af3565b92915050565b5f8060408385031215611b3357611b32611328565b5b5f611b4085828601611376565b9250506020611b5185828601611b09565b9150509250929050565b5f8060408385031215611b7157611b70611328565b5b5f611b7e85828601611376565b9250506020611b8f85828601611376565b9150509250929050565b5f805f805f60a08688031215611bb257611bb1611328565b5b5f611bbf88828901611376565b9550506020611bd088828901611376565b9450506040611be1888289016113a9565b9350506060611bf2888289016113a9565b925050608086013567ffffffffffffffff811115611c1357611c1261132c565b5b611c1f8882890161176e565b9150509295509295909350565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680611c7057607f821691505b602082108103611c8357611c82611c2c565b5b50919050565b611c928161134f565b82525050565b5f604082019050611cab5f830185611c89565b611cb86020830184611c89565b9392505050565b5f604082019050611cd25f8301856113fb565b611cdf60208301846113fb565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f602082019050611d265f830184611c89565b92915050565b5f608082019050611d3f5f830187611c89565b611d4c60208301866113fb565b611d5960408301856113fb565b611d6660608301846113fb565b95945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f611da68261138a565b9150611db18361138a565b9250828201905080821115611dc957611dc8611d6f565b5b92915050565b5f6040820190508181035f830152611de781856119f7565b90508181036020830152611dfb81846119f7565b90509392505050565b5f81519050919050565b5f82825260208201905092915050565b5f611e2882611e04565b611e328185611e0e565b9350611e4281856020860161151b565b611e4b81611543565b840191505092915050565b5f60a082019050611e695f830188611c89565b611e766020830187611c89565b611e8360408301866113fb565b611e9060608301856113fb565b8181036080830152611ea28184611e1e565b90509695505050505050565b5f81519050611ebc8161144e565b92915050565b5f60208284031215611ed757611ed6611328565b5b5f611ee484828501611eae565b91505092915050565b5f60a082019050611f005f830188611c89565b611f0d6020830187611c89565b8181036040830152611f1f81866119f7565b90508181036060830152611f3381856119f7565b90508181036080830152611f478184611e1e565b9050969550505050505056fea26469706673582212203835581c6344b12728c44fa4d9e912cd60e64012c1b772bb703d1c36825c16fd64736f6c63430008180033"; -pub const NFT_SWAP_CONTRACT_BYTES: &str = "60a060405234801562000010575f80fd5b506040516200553a3803806200553a833981810160405281019062000036919062000147565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603620000a7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200009e90620001fb565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff1681525050506200021b565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6200011182620000e6565b9050919050565b620001238162000105565b81146200012e575f80fd5b50565b5f81519050620001418162000118565b92915050565b5f602082840312156200015f576200015e620000e2565b5b5f6200016e8482850162000131565b91505092915050565b5f82825260208201905092915050565b7f66656541646472657373206d757374206e6f74206265207a65726f20616464725f8201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b5f620001e360238362000177565b9150620001f08262000187565b604082019050919050565b5f6020820190508181035f8301526200021481620001d5565b9050919050565b6080516152f8620002425f395f8181612759015281816127f40152612bb201526152f85ff3fe608060405260043610610113575f3560e01c80639b4603f21161009f578063d6a71eb411610063578063d6a71eb41461038e578063e06cf966146103b6578063efccb9eb146103e0578063f23a6e611461041e578063fc45ef821461045a57610113565b80639b4603f2146102be578063ba157104146102da578063bc197c8114610302578063c8d9009b1461033e578063cc90c1991461036657610113565b806332c7d4f8116100e657806332c7d4f8146101df5780633e6af5f21461020757806346b95ac71461022f57806365e266171461026e5780636e6bf6d21461029657610113565b806301ffc9a7146101175780630f235fce14610153578063146e5b241461017b578063150b7a02146101a3575b5f80fd5b348015610122575f80fd5b5061013d60048036038101906101389190613807565b610482565b60405161014a919061384c565b60405180910390f35b34801561015e575f80fd5b5061017960048036038101906101749190613925565b6104fb565b005b348015610186575f80fd5b506101a1600480360381019061019c91906139ae565b6107b5565b005b3480156101ae575f80fd5b506101c960048036038101906101c49190613aac565b61099b565b6040516101d69190613b3f565b60405180910390f35b3480156101ea575f80fd5b5061020560048036038101906102009190613b58565b610dea565b005b348015610212575f80fd5b5061022d600480360381019061022891906139ae565b6110a9565b005b34801561023a575f80fd5b5061025560048036038101906102509190613bf5565b6113ba565b6040516102659493929190613ceb565b60405180910390f35b348015610279575f80fd5b50610294600480360381019061028f91906139ae565b61141c565b005b3480156102a1575f80fd5b506102bc60048036038101906102b79190613925565b611880565b005b6102d860048036038101906102d39190613d58565b611b3b565b005b3480156102e5575f80fd5b5061030060048036038101906102fb9190613b58565b611e71565b005b34801561030d575f80fd5b5061032860048036038101906103239190613e4a565b612131565b6040516103359190613b3f565b60405180910390f35b348015610349575f80fd5b50610364600480360381019061035f9190613925565b61216d565b005b348015610371575f80fd5b5061038c600480360381019061038791906139ae565b612496565b005b348015610399575f80fd5b506103b460048036038101906103af9190613f21565b612846565b005b3480156103c1575f80fd5b506103ca612bb0565b6040516103d79190613ff4565b60405180910390f35b3480156103eb575f80fd5b5061040660048036038101906104019190613bf5565b612bd4565b60405161041593929190614053565b60405180910390f35b348015610429575f80fd5b50610444600480360381019061043f9190614088565b612c20565b6040516104519190613b3f565b60405180910390f35b348015610465575f80fd5b50610480600480360381019061047b9190613b58565b6130b4565b005b5f7f4e2312e0000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806104f457506104f3826133e2565b5b9050919050565b6001600381111561050f5761050e613c78565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff16600381111561054157610540613c78565b5b14610581576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105789061419e565b60405180910390fd5b5f600386338787878760405160200161059f96959493929190614241565b6040516020818303038152906040526040516105bb919061431c565b602060405180830381855afa1580156105d6573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610660576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106579061437c565b60405180910390fd5b5f808881526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff164210156106cb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106c29061440a565b60405180910390fd5b60035f808981526020019081526020015f205f0160186101000a81548160ff0219169083600381111561070157610700613c78565b5b02179055507f5dedc4f52b757d9112d09ca0b2f022927104d54e3f54da091587e8ad19219072876040516107359190614437565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b815260040161077e9392919061445f565b5f604051808303815f87803b158015610795575f80fd5b505af11580156107a7573d5f803e3d5ffd5b505050505050505050505050565b600160048111156107c9576107c8613c78565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff1660048111156107fc576107fb613c78565b5b1461083c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108339061419e565b60405180910390fd5b5f60038787873388888860405160200161085c9796959493929190614494565b604051602081830303815290604052604051610878919061431c565b602060405180830381855afa158015610893573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461091e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109159061437c565b60405180910390fd5b600260015f8a81526020019081526020015f205f01601c6101000a81548160ff0219169083600481111561095557610954613c78565b5b02179055507f9c45e43e2ef051f70491ffd5221bf02ab37e1324128714ef9610df5f24fc9fb5886040516109899190614437565b60405180910390a15050505050505050565b5f8083838101906109ac919061463d565b90505f73ffffffffffffffffffffffffffffffffffffffff16816020015173ffffffffffffffffffffffffffffffffffffffff1603610a20576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a17906146b2565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816040015173ffffffffffffffffffffffffffffffffffffffff1603610a92576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a899061471a565b60405180910390fd5b806040015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610b04576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610afb906147a8565b60405180910390fd5b8573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614610b72576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b6990614810565b60405180910390fd5b5f6003811115610b8557610b84613c78565b5b5f80835f015181526020019081526020015f205f0160189054906101000a900460ff166003811115610bba57610bb9613c78565b5b14610bfa576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bf19061489e565b60405180910390fd5b610c07816020015161344b565b15610c47576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c3e90614906565b60405180910390fd5b5f60038260200151888460600151856080015186604001518b604051602001610c7596959493929190614241565b604051602081830303815290604052604051610c91919061431c565b602060405180830381855afa158015610cac573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018360a0015163ffffffff16815260200160016003811115610cfc57610cfb613c78565b5b8152505f80845f015181526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548160ff02191690836003811115610d9357610d92613c78565b5b02179055509050507ff1dc11bbb6d7542c4267ecf1d370ff4c7092518633ecae9939e8488f4e53d2ad825f0151604051610dcd9190614437565b60405180910390a163150b7a0260e01b9250505095945050505050565b60016003811115610dfe57610dfd613c78565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff166003811115610e3057610e2f613c78565b5b14610e70576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e679061419e565b60405180910390fd5b5f60038633878787878d604051602001610e909796959493929190614924565b604051602081830303815290604052604051610eac919061431c565b602060405180830381855afa158015610ec7573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610f51576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f489061437c565b60405180910390fd5b5f808981526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff16421015610fbc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fb39061440a565b60405180910390fd5b60035f808a81526020019081526020015f205f0160186101000a81548160ff02191690836003811115610ff257610ff1613c78565b5b02179055507f5dedc4f52b757d9112d09ca0b2f022927104d54e3f54da091587e8ad19219072886040516110269190614437565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff1663f242432a3033868c6040518563ffffffff1660e01b815260040161107194939291906149d7565b5f604051808303815f87803b158015611088575f80fd5b505af115801561109a573d5f803e3d5ffd5b50505050505050505050505050565b600160048111156110bd576110bc613c78565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff1660048111156110f0576110ef613c78565b5b14611130576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111279061419e565b60405180910390fd5b5f60038787873360028960405160200161114a9190614a2d565b604051602081830303815290604052604051611166919061431c565b602060405180830381855afa158015611181573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906111a49190614a5b565b88886040516020016111bc9796959493929190614494565b6040516020818303038152906040526040516111d8919061431c565b602060405180830381855afa1580156111f3573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461127e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112759061437c565b60405180910390fd5b600460015f8a81526020019081526020015f205f01601c6101000a81548160ff021916908360048111156112b5576112b4613c78565b5b02179055507f45169a52eef651b20a81474b50b8a5d83225225fcd097ef3cf7952d9ab304f2788856040516112eb929190614a86565b60405180910390a15f86886113009190614ada565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361137e573373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f19350505050158015611378573d5f803e3d5ffd5b506113af565b5f8390506113ad33838373ffffffffffffffffffffffffffffffffffffffff1661345c9092919063ffffffff16565b505b505050505050505050565b6001602052805f5260405f205f91509050805f015f9054906101000a900460601b90805f0160149054906101000a900463ffffffff1690805f0160189054906101000a900463ffffffff1690805f01601c9054906101000a900460ff16905084565b600160048111156114305761142f613c78565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff16600481111561146357611462613c78565b5b14806114b357506002600481111561147e5761147d613c78565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff1660048111156114b1576114b0613c78565b5b145b6114f2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114e990614b7d565b60405180910390fd5b5f6003878787338888886040516020016115129796959493929190614494565b60405160208183030381529060405260405161152e919061431c565b602060405180830381855afa158015611549573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146115d4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115cb9061437c565b60405180910390fd5b600260048111156115e8576115e7613c78565b5b60015f8a81526020019081526020015f205f01601c9054906101000a900460ff16600481111561161b5761161a613c78565b5b0361168d5760015f8981526020019081526020015f205f0160189054906101000a900463ffffffff1663ffffffff1642101561168c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116839061440a565b60405180910390fd5b5b600160048111156116a1576116a0613c78565b5b60015f8a81526020019081526020015f205f01601c9054906101000a900460ff1660048111156116d4576116d3613c78565b5b036117465760015f8981526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff16421015611745576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161173c90614c0b565b60405180910390fd5b5b600460015f8a81526020019081526020015f205f01601c6101000a81548160ff0219169083600481111561177d5761177c613c78565b5b02179055507fbdd7a4be6d82798a500b59077706b12d3f45acf5504828919f92501307b2b953886040516117b19190614437565b60405180910390a15f86886117c69190614ada565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611844573373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f1935050505015801561183e573d5f803e3d5ffd5b50611875565b5f83905061187333838373ffffffffffffffffffffffffffffffffffffffff1661345c9092919063ffffffff16565b505b505050505050505050565b6001600381111561189457611893613c78565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff1660038111156118c6576118c5613c78565b5b14611906576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118fd9061419e565b60405180910390fd5b5f6003863360028860405160200161191e9190614a2d565b60405160208183030381529060405260405161193a919061431c565b602060405180830381855afa158015611955573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906119789190614a5b565b87878760405160200161199096959493929190614241565b6040516020818303038152906040526040516119ac919061431c565b602060405180830381855afa1580156119c7573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614611a51576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a489061437c565b60405180910390fd5b60035f808981526020019081526020015f205f0160186101000a81548160ff02191690836003811115611a8757611a86613c78565b5b02179055507fac509cdcc7ddb189f81fff6f4824f5c95076e64c3bdce542c50feaa6779afd7387604051611abb9190614437565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b8152600401611b049392919061445f565b5f604051808303815f87803b158015611b1b575f80fd5b505af1158015611b2d573d5f803e3d5ffd5b505050505050505050505050565b5f6004811115611b4e57611b4d613c78565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff166004811115611b8157611b80613c78565b5b14611bc1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bb890614c99565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603611c2f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c2690614d27565b60405180910390fd5b5f3411611c71576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c6890614db5565b60405180910390fd5b853411611cb3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611caa90614e43565b60405180910390fd5b5f60038734611cc29190614e61565b88883389895f604051602001611cde9796959493929190614494565b604051602081830303815290604052604051611cfa919061431c565b602060405180830381855afa158015611d15573d5f803e3d5ffd5b5050506040515160601b90506040518060800160405280826bffffffffffffffffffffffff191681526020018463ffffffff1681526020018363ffffffff16815260200160016004811115611d6d57611d6c613c78565b5b81525060015f8a81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548163ffffffff021916908363ffffffff1602179055506060820151815f01601c6101000a81548160ff02191690836004811115611e2857611e27613c78565b5b02179055509050507ffc6cdccd1d98ded12074a9ebc7f6ab74fed1814ff57f4fb5202464d8938bd93588604051611e5f9190614437565b60405180910390a15050505050505050565b60016003811115611e8557611e84613c78565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff166003811115611eb757611eb6613c78565b5b14611ef7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611eee9061419e565b60405180910390fd5b5f60038633600288604051602001611f0f9190614a2d565b604051602081830303815290604052604051611f2b919061431c565b602060405180830381855afa158015611f46573d5f803e3d5ffd5b5050506040513d601f19601f82011682018060405250810190611f699190614a5b565b8787878d604051602001611f839796959493929190614924565b604051602081830303815290604052604051611f9f919061431c565b602060405180830381855afa158015611fba573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614612044576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161203b9061437c565b60405180910390fd5b60035f808a81526020019081526020015f205f0160186101000a81548160ff0219169083600381111561207a57612079613c78565b5b02179055507fac509cdcc7ddb189f81fff6f4824f5c95076e64c3bdce542c50feaa6779afd73886040516120ae9190614437565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff1663f242432a3033868c6040518563ffffffff1660e01b81526004016120f994939291906149d7565b5f604051808303815f87803b158015612110575f80fd5b505af1158015612122573d5f803e3d5ffd5b50505050505050505050505050565b5f6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161216490614ede565b60405180910390fd5b6001600381111561218157612180613c78565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff1660038111156121b3576121b2613c78565b5b146121f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016121ea9061419e565b60405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612261576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161225890614f46565b60405180910390fd5b5f600333878760028860405160200161227a9190614a2d565b604051602081830303815290604052604051612296919061431c565b602060405180830381855afa1580156122b1573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906122d49190614a5b565b87876040516020016122eb96959493929190614241565b604051602081830303815290604052604051612307919061431c565b602060405180830381855afa158015612322573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146123ac576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016123a39061437c565b60405180910390fd5b60025f808981526020019081526020015f205f0160186101000a81548160ff021916908360038111156123e2576123e1613c78565b5b02179055507fad62ed075fe8969df63026f45152d6e996a0697a736a8de92ee85ae9c9958cf0876040516124169190614437565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b815260040161245f9392919061445f565b5f604051808303815f87803b158015612476575f80fd5b505af1158015612488573d5f803e3d5ffd5b505050505050505050505050565b600260048111156124aa576124a9613c78565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff1660048111156124dd576124dc613c78565b5b1461251d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161251490614fd4565b60405180910390fd5b5f600387873388886002896040516020016125389190614a2d565b604051602081830303815290604052604051612554919061431c565b602060405180830381855afa15801561256f573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906125929190614a5b565b886040516020016125a99796959493929190614494565b6040516020818303038152906040526040516125c5919061431c565b602060405180830381855afa1580156125e0573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461266b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016126629061437c565b60405180910390fd5b600360015f8a81526020019081526020015f205f01601c6101000a81548160ff021916908360048111156126a2576126a1613c78565b5b02179055507f0d0da0df275f85bed3a5fe7ae79f3559341a3f9ccd8e010133438135bda00a8788846040516126d8929190614a86565b60405180910390a15f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036127c0573373ffffffffffffffffffffffffffffffffffffffff166108fc8890811502906040515f60405180830381858888f19350505050158015612756573d5f803e3d5ffd5b507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166108fc8790811502906040515f60405180830381858888f193505050501580156127ba573d5f803e3d5ffd5b5061283c565b5f8290506127ef33898373ffffffffffffffffffffffffffffffffffffffff1661345c9092919063ffffffff16565b61283a7f0000000000000000000000000000000000000000000000000000000000000000888373ffffffffffffffffffffffffffffffffffffffff1661345c9092919063ffffffff16565b505b5050505050505050565b5f600481111561285957612858613c78565b5b60015f8b81526020019081526020015f205f01601c9054906101000a900460ff16600481111561288c5761288b613c78565b5b146128cc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016128c390615062565b60405180910390fd5b5f881161290e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612905906150ca565b60405180910390fd5b5f8711612950576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161294790615132565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16036129be576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129b590614d27565b60405180910390fd5b5f60038989883389898d6040516020016129de9796959493929190614494565b6040516020818303038152906040526040516129fa919061431c565b602060405180830381855afa158015612a15573d5f803e3d5ffd5b5050506040515160601b90506040518060800160405280826bffffffffffffffffffffffff191681526020018463ffffffff1681526020018363ffffffff16815260200160016004811115612a6d57612a6c613c78565b5b81525060015f8c81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548163ffffffff021916908363ffffffff1602179055506060820151815f01601c6101000a81548160ff02191690836004811115612b2857612b27613c78565b5b02179055509050507ffc6cdccd1d98ded12074a9ebc7f6ab74fed1814ff57f4fb5202464d8938bd9358a604051612b5f9190614437565b60405180910390a15f879050612ba333308b8d612b7c9190614ada565b8473ffffffffffffffffffffffffffffffffffffffff166134db909392919063ffffffff16565b5050505050505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b5f602052805f5260405f205f91509050805f015f9054906101000a900460601b90805f0160149054906101000a900463ffffffff1690805f0160189054906101000a900460ff16905083565b5f808383810190612c31919061463d565b90505f73ffffffffffffffffffffffffffffffffffffffff16816020015173ffffffffffffffffffffffffffffffffffffffff1603612ca5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c9c906146b2565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816040015173ffffffffffffffffffffffffffffffffffffffff1603612d17576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612d0e9061471a565b60405180910390fd5b806040015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612d89576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612d80906147a8565b60405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614612df7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612dee90614810565b60405180910390fd5b5f8511612e39576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612e309061519a565b60405180910390fd5b5f6003811115612e4c57612e4b613c78565b5b5f80835f015181526020019081526020015f205f0160189054906101000a900460ff166003811115612e8157612e80613c78565b5b14612ec1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612eb890615228565b60405180910390fd5b612ece816020015161344b565b15612f0e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612f0590614906565b60405180910390fd5b5f60038260200151898460600151856080015186604001518c8c604051602001612f3e9796959493929190614924565b604051602081830303815290604052604051612f5a919061431c565b602060405180830381855afa158015612f75573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018360a0015163ffffffff16815260200160016003811115612fc557612fc4613c78565b5b8152505f80845f015181526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548160ff0219169083600381111561305c5761305b613c78565b5b02179055509050507ff1dc11bbb6d7542c4267ecf1d370ff4c7092518633ecae9939e8488f4e53d2ad825f01516040516130969190614437565b60405180910390a163f23a6e6160e01b925050509695505050505050565b600160038111156130c8576130c7613c78565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff1660038111156130fa576130f9613c78565b5b1461313a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016131319061419e565b60405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146131a8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161319f90614f46565b60405180910390fd5b5f60033387876002886040516020016131c19190614a2d565b6040516020818303038152906040526040516131dd919061431c565b602060405180830381855afa1580156131f8573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061321b9190614a5b565b87878d6040516020016132349796959493929190614924565b604051602081830303815290604052604051613250919061431c565b602060405180830381855afa15801561326b573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146132f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016132ec9061437c565b60405180910390fd5b60025f808a81526020019081526020015f205f0160186101000a81548160ff0219169083600381111561332b5761332a613c78565b5b02179055507fad62ed075fe8969df63026f45152d6e996a0697a736a8de92ee85ae9c9958cf08860405161335f9190614437565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff1663f242432a3033868c6040518563ffffffff1660e01b81526004016133aa94939291906149d7565b5f604051808303815f87803b1580156133c1575f80fd5b505af11580156133d3573d5f803e3d5ffd5b50505050505050505050505050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f80823b90505f8111915050919050565b6134d6838473ffffffffffffffffffffffffffffffffffffffff1663a9059cbb858560405160240161348f929190615246565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061355d565b505050565b613557848573ffffffffffffffffffffffffffffffffffffffff166323b872dd8686866040516024016135109392919061445f565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061355d565b50505050565b5f613587828473ffffffffffffffffffffffffffffffffffffffff166135f290919063ffffffff16565b90505f8151141580156135ab5750808060200190518101906135a99190615297565b155b156135ed57826040517f5274afe70000000000000000000000000000000000000000000000000000000081526004016135e49190613ff4565b60405180910390fd5b505050565b60606135ff83835f613607565b905092915050565b60608147101561364e57306040517fcd7860590000000000000000000000000000000000000000000000000000000081526004016136459190613ff4565b60405180910390fd5b5f808573ffffffffffffffffffffffffffffffffffffffff168486604051613676919061431c565b5f6040518083038185875af1925050503d805f81146136b0576040519150601f19603f3d011682016040523d82523d5f602084013e6136b5565b606091505b50915091506136c58683836136d0565b925050509392505050565b6060826136e5576136e08261375d565b613755565b5f825114801561370b57505f8473ffffffffffffffffffffffffffffffffffffffff163b145b1561374d57836040517f9996b3150000000000000000000000000000000000000000000000000000000081526004016137449190613ff4565b60405180910390fd5b819050613756565b5b9392505050565b5f8151111561376f5780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6137e6816137b2565b81146137f0575f80fd5b50565b5f81359050613801816137dd565b92915050565b5f6020828403121561381c5761381b6137aa565b5b5f613829848285016137f3565b91505092915050565b5f8115159050919050565b61384681613832565b82525050565b5f60208201905061385f5f83018461383d565b92915050565b5f819050919050565b61387781613865565b8114613881575f80fd5b50565b5f813590506138928161386e565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6138c182613898565b9050919050565b6138d1816138b7565b81146138db575f80fd5b50565b5f813590506138ec816138c8565b92915050565b5f819050919050565b613904816138f2565b811461390e575f80fd5b50565b5f8135905061391f816138fb565b92915050565b5f805f805f8060c0878903121561393f5761393e6137aa565b5b5f61394c89828a01613884565b965050602061395d89828a016138de565b955050604061396e89828a01613884565b945050606061397f89828a01613884565b935050608061399089828a016138de565b92505060a06139a189828a01613911565b9150509295509295509295565b5f805f805f805f60e0888a0312156139c9576139c86137aa565b5b5f6139d68a828b01613884565b97505060206139e78a828b01613911565b96505060406139f88a828b01613911565b9550506060613a098a828b016138de565b9450506080613a1a8a828b01613884565b93505060a0613a2b8a828b01613884565b92505060c0613a3c8a828b016138de565b91505092959891949750929550565b5f80fd5b5f80fd5b5f80fd5b5f8083601f840112613a6c57613a6b613a4b565b5b8235905067ffffffffffffffff811115613a8957613a88613a4f565b5b602083019150836001820283011115613aa557613aa4613a53565b5b9250929050565b5f805f805f60808688031215613ac557613ac46137aa565b5b5f613ad2888289016138de565b9550506020613ae3888289016138de565b9450506040613af488828901613911565b935050606086013567ffffffffffffffff811115613b1557613b146137ae565b5b613b2188828901613a57565b92509250509295509295909350565b613b39816137b2565b82525050565b5f602082019050613b525f830184613b30565b92915050565b5f805f805f805f60e0888a031215613b7357613b726137aa565b5b5f613b808a828b01613884565b9750506020613b918a828b01613911565b9650506040613ba28a828b016138de565b9550506060613bb38a828b01613884565b9450506080613bc48a828b01613884565b93505060a0613bd58a828b016138de565b92505060c0613be68a828b01613911565b91505092959891949750929550565b5f60208284031215613c0a57613c096137aa565b5b5f613c1784828501613884565b91505092915050565b5f7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b613c5481613c20565b82525050565b5f63ffffffff82169050919050565b613c7281613c5a565b82525050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60058110613cb657613cb5613c78565b5b50565b5f819050613cc682613ca5565b919050565b5f613cd582613cb9565b9050919050565b613ce581613ccb565b82525050565b5f608082019050613cfe5f830187613c4b565b613d0b6020830186613c69565b613d186040830185613c69565b613d256060830184613cdc565b95945050505050565b613d3781613c5a565b8114613d41575f80fd5b50565b5f81359050613d5281613d2e565b92915050565b5f805f805f805f60e0888a031215613d7357613d726137aa565b5b5f613d808a828b01613884565b9750506020613d918a828b01613911565b9650506040613da28a828b016138de565b9550506060613db38a828b01613884565b9450506080613dc48a828b01613884565b93505060a0613dd58a828b01613d44565b92505060c0613de68a828b01613d44565b91505092959891949750929550565b5f8083601f840112613e0a57613e09613a4b565b5b8235905067ffffffffffffffff811115613e2757613e26613a4f565b5b602083019150836020820283011115613e4357613e42613a53565b5b9250929050565b5f805f805f805f8060a0898b031215613e6657613e656137aa565b5b5f613e738b828c016138de565b9850506020613e848b828c016138de565b975050604089013567ffffffffffffffff811115613ea557613ea46137ae565b5b613eb18b828c01613df5565b9650965050606089013567ffffffffffffffff811115613ed457613ed36137ae565b5b613ee08b828c01613df5565b9450945050608089013567ffffffffffffffff811115613f0357613f026137ae565b5b613f0f8b828c01613a57565b92509250509295985092959890939650565b5f805f805f805f805f6101208a8c031215613f3f57613f3e6137aa565b5b5f613f4c8c828d01613884565b9950506020613f5d8c828d01613911565b9850506040613f6e8c828d01613911565b9750506060613f7f8c828d016138de565b9650506080613f908c828d016138de565b95505060a0613fa18c828d01613884565b94505060c0613fb28c828d01613884565b93505060e0613fc38c828d01613d44565b925050610100613fd58c828d01613d44565b9150509295985092959850929598565b613fee816138b7565b82525050565b5f6020820190506140075f830184613fe5565b92915050565b6004811061401e5761401d613c78565b5b50565b5f81905061402e8261400d565b919050565b5f61403d82614021565b9050919050565b61404d81614033565b82525050565b5f6060820190506140665f830186613c4b565b6140736020830185613c69565b6140806040830184614044565b949350505050565b5f805f805f8060a087890312156140a2576140a16137aa565b5b5f6140af89828a016138de565b96505060206140c089828a016138de565b95505060406140d189828a01613911565b94505060606140e289828a01613911565b935050608087013567ffffffffffffffff811115614103576141026137ae565b5b61410f89828a01613a57565b92509250509295509295509295565b5f82825260208201905092915050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520505f8201527f61796d656e7453656e7400000000000000000000000000000000000000000000602082015250565b5f614188602a8361411e565b91506141938261412e565b604082019050919050565b5f6020820190508181035f8301526141b58161417c565b9050919050565b5f8160601b9050919050565b5f6141d2826141bc565b9050919050565b5f6141e3826141c8565b9050919050565b6141fb6141f6826138b7565b6141d9565b82525050565b5f819050919050565b61421b61421682613865565b614201565b82525050565b5f819050919050565b61423b614236826138f2565b614221565b82525050565b5f61424c82896141ea565b60148201915061425c82886141ea565b60148201915061426c828761420a565b60208201915061427c828661420a565b60208201915061428c82856141ea565b60148201915061429c828461422a565b602082019150819050979650505050505050565b5f81519050919050565b5f81905092915050565b5f5b838110156142e15780820151818401526020810190506142c6565b5f8484015250505050565b5f6142f6826142b0565b61430081856142ba565b93506143108185602086016142c4565b80840191505092915050565b5f61432782846142ec565b915081905092915050565b7f496e76616c6964207061796d656e7448617368000000000000000000000000005f82015250565b5f61436660138361411e565b915061437182614332565b602082019050919050565b5f6020820190508181035f8301526143938161435a565b9050919050565b7f43757272656e742074696d657374616d70206469646e277420657863656564205f8201527f7061796d656e7420726566756e64206c6f636b2074696d650000000000000000602082015250565b5f6143f460388361411e565b91506143ff8261439a565b604082019050919050565b5f6020820190508181035f830152614421816143e8565b9050919050565b61443181613865565b82525050565b5f60208201905061444a5f830184614428565b92915050565b614459816138f2565b82525050565b5f6060820190506144725f830186613fe5565b61447f6020830185613fe5565b61448c6040830184614450565b949350505050565b5f61449f828a61422a565b6020820191506144af828961422a565b6020820191506144bf82886141ea565b6014820191506144cf82876141ea565b6014820191506144df828661420a565b6020820191506144ef828561420a565b6020820191506144ff82846141ea565b60148201915081905098975050505050505050565b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61455e82614518565b810181811067ffffffffffffffff8211171561457d5761457c614528565b5b80604052505050565b5f61458f6137a1565b905061459b8282614555565b919050565b5f60c082840312156145b5576145b4614514565b5b6145bf60c0614586565b90505f6145ce84828501613884565b5f8301525060206145e1848285016138de565b60208301525060406145f5848285016138de565b604083015250606061460984828501613884565b606083015250608061461d84828501613884565b60808301525060a061463184828501613d44565b60a08301525092915050565b5f60c08284031215614652576146516137aa565b5b5f61465f848285016145a0565b91505092915050565b7f54616b6572206d757374206e6f74206265207a65726f206164647265737300005f82015250565b5f61469c601e8361411e565b91506146a782614668565b602082019050919050565b5f6020820190508181035f8301526146c981614690565b9050919050565b7f546f6b656e206d757374206e6f74206265207a65726f206164647265737300005f82015250565b5f614704601e8361411e565b915061470f826146d0565b602082019050919050565b5f6020820190508181035f830152614731816146f8565b9050919050565b7f546f6b656e206164647265737320646f6573206e6f74206d617463682073656e5f8201527f6465720000000000000000000000000000000000000000000000000000000000602082015250565b5f61479260238361411e565b915061479d82614738565b604082019050919050565b5f6020820190508181035f8301526147bf81614786565b9050919050565b7f4f70657261746f72206d757374206265207468652073656e64657200000000005f82015250565b5f6147fa601b8361411e565b9150614805826147c6565b602082019050919050565b5f6020820190508181035f830152614827816147ee565b9050919050565b7f4d616b657220455243373231207061796d656e74206d75737420626520556e695f8201527f6e697469616c697a656400000000000000000000000000000000000000000000602082015250565b5f614888602a8361411e565b91506148938261482e565b604082019050919050565b5f6020820190508181035f8301526148b58161487c565b9050919050565b7f54616b65722063616e6e6f74206265206120636f6e74726163740000000000005f82015250565b5f6148f0601a8361411e565b91506148fb826148bc565b602082019050919050565b5f6020820190508181035f83015261491d816148e4565b9050919050565b5f61492f828a6141ea565b60148201915061493f82896141ea565b60148201915061494f828861420a565b60208201915061495f828761420a565b60208201915061496f82866141ea565b60148201915061497f828561422a565b60208201915061498f828461422a565b60208201915081905098975050505050505050565b5f82825260208201905092915050565b50565b5f6149c25f836149a4565b91506149cd826149b4565b5f82019050919050565b5f60a0820190506149ea5f830187613fe5565b6149f76020830186613fe5565b614a046040830185614450565b614a116060830184614450565b8181036080830152614a22816149b7565b905095945050505050565b5f614a38828461420a565b60208201915081905092915050565b5f81519050614a558161386e565b92915050565b5f60208284031215614a7057614a6f6137aa565b5b5f614a7d84828501614a47565b91505092915050565b5f604082019050614a995f830185614428565b614aa66020830184614428565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f614ae4826138f2565b9150614aef836138f2565b9250828201905080821115614b0757614b06614aad565b5b92915050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520505f8201527f61796d656e7453656e74206f722054616b6572417070726f7665640000000000602082015250565b5f614b67603b8361411e565b9150614b7282614b0d565b604082019050919050565b5f6020820190508181035f830152614b9481614b5b565b9050919050565b7f43757272656e742074696d657374616d70206469646e277420657863656564205f8201527f7061796d656e74207072652d617070726f7665206c6f636b2074696d65000000602082015250565b5f614bf5603d8361411e565b9150614c0082614b9b565b604082019050919050565b5f6020820190508181035f830152614c2281614be9565b9050919050565b7f54616b6572207061796d656e7420697320616c726561647920696e697469616c5f8201527f697a656400000000000000000000000000000000000000000000000000000000602082015250565b5f614c8360248361411e565b9150614c8e82614c29565b604082019050919050565b5f6020820190508181035f830152614cb081614c77565b9050919050565b7f5265636569766572206d757374206e6f74206265207a65726f206164647265735f8201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b5f614d1160218361411e565b9150614d1c82614cb7565b604082019050919050565b5f6020820190508181035f830152614d3e81614d05565b9050919050565b7f4554482076616c7565206d7573742062652067726561746572207468616e207a5f8201527f65726f0000000000000000000000000000000000000000000000000000000000602082015250565b5f614d9f60238361411e565b9150614daa82614d45565b604082019050919050565b5f6020820190508181035f830152614dcc81614d93565b9050919050565b7f4554482076616c7565206d7573742062652067726561746572207468616e20645f8201527f6578206665650000000000000000000000000000000000000000000000000000602082015250565b5f614e2d60268361411e565b9150614e3882614dd3565b604082019050919050565b5f6020820190508181035f830152614e5a81614e21565b9050919050565b5f614e6b826138f2565b9150614e76836138f2565b9250828203905081811115614e8e57614e8d614aad565b5b92915050565b7f4261746368207472616e7366657273206e6f7420737570706f727465640000005f82015250565b5f614ec8601d8361411e565b9150614ed382614e94565b602082019050919050565b5f6020820190508181035f830152614ef581614ebc565b9050919050565b7f43616c6c6572206d75737420626520616e20454f4100000000000000000000005f82015250565b5f614f3060158361411e565b9150614f3b82614efc565b602082019050919050565b5f6020820190508181035f830152614f5d81614f24565b9050919050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520545f8201527f616b6572417070726f7665640000000000000000000000000000000000000000602082015250565b5f614fbe602c8361411e565b9150614fc982614f64565b604082019050919050565b5f6020820190508181035f830152614feb81614fb2565b9050919050565b7f4552433230207632207061796d656e7420697320616c726561647920696e69745f8201527f69616c697a656400000000000000000000000000000000000000000000000000602082015250565b5f61504c60278361411e565b915061505782614ff2565b604082019050919050565b5f6020820190508181035f83015261507981615040565b9050919050565b7f416d6f756e74206d757374206e6f74206265207a65726f0000000000000000005f82015250565b5f6150b460178361411e565b91506150bf82615080565b602082019050919050565b5f6020820190508181035f8301526150e1816150a8565b9050919050565b7f44657820666565206d757374206e6f74206265207a65726f00000000000000005f82015250565b5f61511c60188361411e565b9150615127826150e8565b602082019050919050565b5f6020820190508181035f83015261514981615110565b9050919050565b7f56616c7565206d7573742062652067726561746572207468616e2030000000005f82015250565b5f615184601c8361411e565b915061518f82615150565b602082019050919050565b5f6020820190508181035f8301526151b181615178565b9050919050565b7f4d616b65722045524331313535207061796d656e74206d75737420626520556e5f8201527f696e697469616c697a6564000000000000000000000000000000000000000000602082015250565b5f615212602b8361411e565b915061521d826151b8565b604082019050919050565b5f6020820190508181035f83015261523f81615206565b9050919050565b5f6040820190506152595f830185613fe5565b6152666020830184614450565b9392505050565b61527681613832565b8114615280575f80fd5b50565b5f815190506152918161526d565b92915050565b5f602082840312156152ac576152ab6137aa565b5b5f6152b984828501615283565b9150509291505056fea264697066735822122077b4b2078ef3c6b5011576148b3629aef4d5bdf826c80bb1e059ab90e714e30264736f6c63430008180033"; +pub const NFT_SWAP_CONTRACT_BYTES: &str = "60a060405234801562000010575f80fd5b50604051620055a2380380620055a2833981810160405281019062000036919062000147565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603620000a7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200009e90620001fb565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff1681525050506200021b565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6200011182620000e6565b9050919050565b620001238162000105565b81146200012e575f80fd5b50565b5f81519050620001418162000118565b92915050565b5f602082840312156200015f576200015e620000e2565b5b5f6200016e8482850162000131565b91505092915050565b5f82825260208201905092915050565b7f66656541646472657373206d757374206e6f74206265207a65726f20616464725f8201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b5f620001e360238362000177565b9150620001f08262000187565b604082019050919050565b5f6020820190508181035f8301526200021481620001d5565b9050919050565b608051615360620002425f395f81816127c10152818161285c0152612c1a01526153605ff3fe608060405260043610610113575f3560e01c80639b4603f21161009f578063d6a71eb411610063578063d6a71eb41461038e578063e06cf966146103b6578063efccb9eb146103e0578063f23a6e611461041e578063fc45ef821461045a57610113565b80639b4603f2146102be578063ba157104146102da578063bc197c8114610302578063c8d9009b1461033e578063cc90c1991461036657610113565b806332c7d4f8116100e657806332c7d4f8146101df5780633e6af5f21461020757806346b95ac71461022f57806365e266171461026e5780636e6bf6d21461029657610113565b806301ffc9a7146101175780630f235fce14610153578063146e5b241461017b578063150b7a02146101a3575b5f80fd5b348015610122575f80fd5b5061013d6004803603810190610138919061386f565b610482565b60405161014a91906138b4565b60405180910390f35b34801561015e575f80fd5b506101796004803603810190610174919061398d565b610563565b005b348015610186575f80fd5b506101a1600480360381019061019c9190613a16565b61081d565b005b3480156101ae575f80fd5b506101c960048036038101906101c49190613b14565b610a03565b6040516101d69190613ba7565b60405180910390f35b3480156101ea575f80fd5b5061020560048036038101906102009190613bc0565b610e52565b005b348015610212575f80fd5b5061022d60048036038101906102289190613a16565b611111565b005b34801561023a575f80fd5b5061025560048036038101906102509190613c5d565b611422565b6040516102659493929190613d53565b60405180910390f35b348015610279575f80fd5b50610294600480360381019061028f9190613a16565b611484565b005b3480156102a1575f80fd5b506102bc60048036038101906102b7919061398d565b6118e8565b005b6102d860048036038101906102d39190613dc0565b611ba3565b005b3480156102e5575f80fd5b5061030060048036038101906102fb9190613bc0565b611ed9565b005b34801561030d575f80fd5b5061032860048036038101906103239190613eb2565b612199565b6040516103359190613ba7565b60405180910390f35b348015610349575f80fd5b50610364600480360381019061035f919061398d565b6121d5565b005b348015610371575f80fd5b5061038c60048036038101906103879190613a16565b6124fe565b005b348015610399575f80fd5b506103b460048036038101906103af9190613f89565b6128ae565b005b3480156103c1575f80fd5b506103ca612c18565b6040516103d7919061405c565b60405180910390f35b3480156103eb575f80fd5b5061040660048036038101906104019190613c5d565b612c3c565b604051610415939291906140bb565b60405180910390f35b348015610429575f80fd5b50610444600480360381019061043f91906140f0565b612c88565b6040516104519190613ba7565b60405180910390f35b348015610465575f80fd5b50610480600480360381019061047b9190613bc0565b61311c565b005b5f7f4e2312e0000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061054c57507f150b7a02000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061055c575061055b8261344a565b5b9050919050565b6001600381111561057757610576613ce0565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff1660038111156105a9576105a8613ce0565b5b146105e9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105e090614206565b60405180910390fd5b5f6003863387878787604051602001610607969594939291906142a9565b6040516020818303038152906040526040516106239190614384565b602060405180830381855afa15801561063e573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146106c8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106bf906143e4565b60405180910390fd5b5f808881526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff16421015610733576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161072a90614472565b60405180910390fd5b60035f808981526020019081526020015f205f0160186101000a81548160ff0219169083600381111561076957610768613ce0565b5b02179055507f5dedc4f52b757d9112d09ca0b2f022927104d54e3f54da091587e8ad192190728760405161079d919061449f565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b81526004016107e6939291906144c7565b5f604051808303815f87803b1580156107fd575f80fd5b505af115801561080f573d5f803e3d5ffd5b505050505050505050505050565b6001600481111561083157610830613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff16600481111561086457610863613ce0565b5b146108a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161089b90614206565b60405180910390fd5b5f6003878787338888886040516020016108c497969594939291906144fc565b6040516020818303038152906040526040516108e09190614384565b602060405180830381855afa1580156108fb573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610986576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161097d906143e4565b60405180910390fd5b600260015f8a81526020019081526020015f205f01601c6101000a81548160ff021916908360048111156109bd576109bc613ce0565b5b02179055507f9c45e43e2ef051f70491ffd5221bf02ab37e1324128714ef9610df5f24fc9fb5886040516109f1919061449f565b60405180910390a15050505050505050565b5f808383810190610a1491906146a5565b90505f73ffffffffffffffffffffffffffffffffffffffff16816020015173ffffffffffffffffffffffffffffffffffffffff1603610a88576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a7f9061471a565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816040015173ffffffffffffffffffffffffffffffffffffffff1603610afa576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610af190614782565b60405180910390fd5b806040015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610b6c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b6390614810565b60405180910390fd5b8573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614610bda576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bd190614878565b60405180910390fd5b5f6003811115610bed57610bec613ce0565b5b5f80835f015181526020019081526020015f205f0160189054906101000a900460ff166003811115610c2257610c21613ce0565b5b14610c62576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c5990614906565b60405180910390fd5b610c6f81602001516134b3565b15610caf576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ca69061496e565b60405180910390fd5b5f60038260200151888460600151856080015186604001518b604051602001610cdd969594939291906142a9565b604051602081830303815290604052604051610cf99190614384565b602060405180830381855afa158015610d14573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018360a0015163ffffffff16815260200160016003811115610d6457610d63613ce0565b5b8152505f80845f015181526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548160ff02191690836003811115610dfb57610dfa613ce0565b5b02179055509050507ff1dc11bbb6d7542c4267ecf1d370ff4c7092518633ecae9939e8488f4e53d2ad825f0151604051610e35919061449f565b60405180910390a163150b7a0260e01b9250505095945050505050565b60016003811115610e6657610e65613ce0565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff166003811115610e9857610e97613ce0565b5b14610ed8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ecf90614206565b60405180910390fd5b5f60038633878787878d604051602001610ef8979695949392919061498c565b604051602081830303815290604052604051610f149190614384565b602060405180830381855afa158015610f2f573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610fb9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fb0906143e4565b60405180910390fd5b5f808981526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff16421015611024576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161101b90614472565b60405180910390fd5b60035f808a81526020019081526020015f205f0160186101000a81548160ff0219169083600381111561105a57611059613ce0565b5b02179055507f5dedc4f52b757d9112d09ca0b2f022927104d54e3f54da091587e8ad192190728860405161108e919061449f565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff1663f242432a3033868c6040518563ffffffff1660e01b81526004016110d99493929190614a3f565b5f604051808303815f87803b1580156110f0575f80fd5b505af1158015611102573d5f803e3d5ffd5b50505050505050505050505050565b6001600481111561112557611124613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff16600481111561115857611157613ce0565b5b14611198576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161118f90614206565b60405180910390fd5b5f6003878787336002896040516020016111b29190614a95565b6040516020818303038152906040526040516111ce9190614384565b602060405180830381855afa1580156111e9573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061120c9190614ac3565b888860405160200161122497969594939291906144fc565b6040516020818303038152906040526040516112409190614384565b602060405180830381855afa15801561125b573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146112e6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112dd906143e4565b60405180910390fd5b600460015f8a81526020019081526020015f205f01601c6101000a81548160ff0219169083600481111561131d5761131c613ce0565b5b02179055507f45169a52eef651b20a81474b50b8a5d83225225fcd097ef3cf7952d9ab304f278885604051611353929190614aee565b60405180910390a15f86886113689190614b42565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036113e6573373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f193505050501580156113e0573d5f803e3d5ffd5b50611417565b5f83905061141533838373ffffffffffffffffffffffffffffffffffffffff166134c49092919063ffffffff16565b505b505050505050505050565b6001602052805f5260405f205f91509050805f015f9054906101000a900460601b90805f0160149054906101000a900463ffffffff1690805f0160189054906101000a900463ffffffff1690805f01601c9054906101000a900460ff16905084565b6001600481111561149857611497613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff1660048111156114cb576114ca613ce0565b5b148061151b5750600260048111156114e6576114e5613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff16600481111561151957611518613ce0565b5b145b61155a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161155190614be5565b60405180910390fd5b5f60038787873388888860405160200161157a97969594939291906144fc565b6040516020818303038152906040526040516115969190614384565b602060405180830381855afa1580156115b1573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461163c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611633906143e4565b60405180910390fd5b600260048111156116505761164f613ce0565b5b60015f8a81526020019081526020015f205f01601c9054906101000a900460ff16600481111561168357611682613ce0565b5b036116f55760015f8981526020019081526020015f205f0160189054906101000a900463ffffffff1663ffffffff164210156116f4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116eb90614472565b60405180910390fd5b5b6001600481111561170957611708613ce0565b5b60015f8a81526020019081526020015f205f01601c9054906101000a900460ff16600481111561173c5761173b613ce0565b5b036117ae5760015f8981526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff164210156117ad576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117a490614c73565b60405180910390fd5b5b600460015f8a81526020019081526020015f205f01601c6101000a81548160ff021916908360048111156117e5576117e4613ce0565b5b02179055507fbdd7a4be6d82798a500b59077706b12d3f45acf5504828919f92501307b2b95388604051611819919061449f565b60405180910390a15f868861182e9190614b42565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036118ac573373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f193505050501580156118a6573d5f803e3d5ffd5b506118dd565b5f8390506118db33838373ffffffffffffffffffffffffffffffffffffffff166134c49092919063ffffffff16565b505b505050505050505050565b600160038111156118fc576118fb613ce0565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff16600381111561192e5761192d613ce0565b5b1461196e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161196590614206565b60405180910390fd5b5f600386336002886040516020016119869190614a95565b6040516020818303038152906040526040516119a29190614384565b602060405180830381855afa1580156119bd573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906119e09190614ac3565b8787876040516020016119f8969594939291906142a9565b604051602081830303815290604052604051611a149190614384565b602060405180830381855afa158015611a2f573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614611ab9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ab0906143e4565b60405180910390fd5b60035f808981526020019081526020015f205f0160186101000a81548160ff02191690836003811115611aef57611aee613ce0565b5b02179055507fac509cdcc7ddb189f81fff6f4824f5c95076e64c3bdce542c50feaa6779afd7387604051611b23919061449f565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b8152600401611b6c939291906144c7565b5f604051808303815f87803b158015611b83575f80fd5b505af1158015611b95573d5f803e3d5ffd5b505050505050505050505050565b5f6004811115611bb657611bb5613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff166004811115611be957611be8613ce0565b5b14611c29576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c2090614d01565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603611c97576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c8e90614d8f565b60405180910390fd5b5f3411611cd9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611cd090614e1d565b60405180910390fd5b853411611d1b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d1290614eab565b60405180910390fd5b5f60038734611d2a9190614ec9565b88883389895f604051602001611d4697969594939291906144fc565b604051602081830303815290604052604051611d629190614384565b602060405180830381855afa158015611d7d573d5f803e3d5ffd5b5050506040515160601b90506040518060800160405280826bffffffffffffffffffffffff191681526020018463ffffffff1681526020018363ffffffff16815260200160016004811115611dd557611dd4613ce0565b5b81525060015f8a81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548163ffffffff021916908363ffffffff1602179055506060820151815f01601c6101000a81548160ff02191690836004811115611e9057611e8f613ce0565b5b02179055509050507ffc6cdccd1d98ded12074a9ebc7f6ab74fed1814ff57f4fb5202464d8938bd93588604051611ec7919061449f565b60405180910390a15050505050505050565b60016003811115611eed57611eec613ce0565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff166003811115611f1f57611f1e613ce0565b5b14611f5f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f5690614206565b60405180910390fd5b5f60038633600288604051602001611f779190614a95565b604051602081830303815290604052604051611f939190614384565b602060405180830381855afa158015611fae573d5f803e3d5ffd5b5050506040513d601f19601f82011682018060405250810190611fd19190614ac3565b8787878d604051602001611feb979695949392919061498c565b6040516020818303038152906040526040516120079190614384565b602060405180830381855afa158015612022573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146120ac576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120a3906143e4565b60405180910390fd5b60035f808a81526020019081526020015f205f0160186101000a81548160ff021916908360038111156120e2576120e1613ce0565b5b02179055507fac509cdcc7ddb189f81fff6f4824f5c95076e64c3bdce542c50feaa6779afd7388604051612116919061449f565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff1663f242432a3033868c6040518563ffffffff1660e01b81526004016121619493929190614a3f565b5f604051808303815f87803b158015612178575f80fd5b505af115801561218a573d5f803e3d5ffd5b50505050505050505050505050565b5f6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016121cc90614f46565b60405180910390fd5b600160038111156121e9576121e8613ce0565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff16600381111561221b5761221a613ce0565b5b1461225b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161225290614206565b60405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146122c9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122c090614fae565b60405180910390fd5b5f60033387876002886040516020016122e29190614a95565b6040516020818303038152906040526040516122fe9190614384565b602060405180830381855afa158015612319573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061233c9190614ac3565b8787604051602001612353969594939291906142a9565b60405160208183030381529060405260405161236f9190614384565b602060405180830381855afa15801561238a573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614612414576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161240b906143e4565b60405180910390fd5b60025f808981526020019081526020015f205f0160186101000a81548160ff0219169083600381111561244a57612449613ce0565b5b02179055507fad62ed075fe8969df63026f45152d6e996a0697a736a8de92ee85ae9c9958cf08760405161247e919061449f565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b81526004016124c7939291906144c7565b5f604051808303815f87803b1580156124de575f80fd5b505af11580156124f0573d5f803e3d5ffd5b505050505050505050505050565b6002600481111561251257612511613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff16600481111561254557612544613ce0565b5b14612585576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161257c9061503c565b60405180910390fd5b5f600387873388886002896040516020016125a09190614a95565b6040516020818303038152906040526040516125bc9190614384565b602060405180830381855afa1580156125d7573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906125fa9190614ac3565b8860405160200161261197969594939291906144fc565b60405160208183030381529060405260405161262d9190614384565b602060405180830381855afa158015612648573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146126d3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016126ca906143e4565b60405180910390fd5b600360015f8a81526020019081526020015f205f01601c6101000a81548160ff0219169083600481111561270a57612709613ce0565b5b02179055507f0d0da0df275f85bed3a5fe7ae79f3559341a3f9ccd8e010133438135bda00a878884604051612740929190614aee565b60405180910390a15f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612828573373ffffffffffffffffffffffffffffffffffffffff166108fc8890811502906040515f60405180830381858888f193505050501580156127be573d5f803e3d5ffd5b507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166108fc8790811502906040515f60405180830381858888f19350505050158015612822573d5f803e3d5ffd5b506128a4565b5f82905061285733898373ffffffffffffffffffffffffffffffffffffffff166134c49092919063ffffffff16565b6128a27f0000000000000000000000000000000000000000000000000000000000000000888373ffffffffffffffffffffffffffffffffffffffff166134c49092919063ffffffff16565b505b5050505050505050565b5f60048111156128c1576128c0613ce0565b5b60015f8b81526020019081526020015f205f01601c9054906101000a900460ff1660048111156128f4576128f3613ce0565b5b14612934576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161292b906150ca565b60405180910390fd5b5f8811612976576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161296d90615132565b60405180910390fd5b5f87116129b8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129af9061519a565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603612a26576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a1d90614d8f565b60405180910390fd5b5f60038989883389898d604051602001612a4697969594939291906144fc565b604051602081830303815290604052604051612a629190614384565b602060405180830381855afa158015612a7d573d5f803e3d5ffd5b5050506040515160601b90506040518060800160405280826bffffffffffffffffffffffff191681526020018463ffffffff1681526020018363ffffffff16815260200160016004811115612ad557612ad4613ce0565b5b81525060015f8c81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548163ffffffff021916908363ffffffff1602179055506060820151815f01601c6101000a81548160ff02191690836004811115612b9057612b8f613ce0565b5b02179055509050507ffc6cdccd1d98ded12074a9ebc7f6ab74fed1814ff57f4fb5202464d8938bd9358a604051612bc7919061449f565b60405180910390a15f879050612c0b33308b8d612be49190614b42565b8473ffffffffffffffffffffffffffffffffffffffff16613543909392919063ffffffff16565b5050505050505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b5f602052805f5260405f205f91509050805f015f9054906101000a900460601b90805f0160149054906101000a900463ffffffff1690805f0160189054906101000a900460ff16905083565b5f808383810190612c9991906146a5565b90505f73ffffffffffffffffffffffffffffffffffffffff16816020015173ffffffffffffffffffffffffffffffffffffffff1603612d0d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612d049061471a565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816040015173ffffffffffffffffffffffffffffffffffffffff1603612d7f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612d7690614782565b60405180910390fd5b806040015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612df1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612de890614810565b60405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614612e5f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612e5690614878565b60405180910390fd5b5f8511612ea1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612e9890615202565b60405180910390fd5b5f6003811115612eb457612eb3613ce0565b5b5f80835f015181526020019081526020015f205f0160189054906101000a900460ff166003811115612ee957612ee8613ce0565b5b14612f29576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612f2090615290565b60405180910390fd5b612f3681602001516134b3565b15612f76576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612f6d9061496e565b60405180910390fd5b5f60038260200151898460600151856080015186604001518c8c604051602001612fa6979695949392919061498c565b604051602081830303815290604052604051612fc29190614384565b602060405180830381855afa158015612fdd573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018360a0015163ffffffff1681526020016001600381111561302d5761302c613ce0565b5b8152505f80845f015181526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548160ff021916908360038111156130c4576130c3613ce0565b5b02179055509050507ff1dc11bbb6d7542c4267ecf1d370ff4c7092518633ecae9939e8488f4e53d2ad825f01516040516130fe919061449f565b60405180910390a163f23a6e6160e01b925050509695505050505050565b600160038111156131305761312f613ce0565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff16600381111561316257613161613ce0565b5b146131a2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161319990614206565b60405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614613210576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161320790614fae565b60405180910390fd5b5f60033387876002886040516020016132299190614a95565b6040516020818303038152906040526040516132459190614384565b602060405180830381855afa158015613260573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906132839190614ac3565b87878d60405160200161329c979695949392919061498c565b6040516020818303038152906040526040516132b89190614384565b602060405180830381855afa1580156132d3573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461335d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613354906143e4565b60405180910390fd5b60025f808a81526020019081526020015f205f0160186101000a81548160ff0219169083600381111561339357613392613ce0565b5b02179055507fad62ed075fe8969df63026f45152d6e996a0697a736a8de92ee85ae9c9958cf0886040516133c7919061449f565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff1663f242432a3033868c6040518563ffffffff1660e01b81526004016134129493929190614a3f565b5f604051808303815f87803b158015613429575f80fd5b505af115801561343b573d5f803e3d5ffd5b50505050505050505050505050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f80823b90505f8111915050919050565b61353e838473ffffffffffffffffffffffffffffffffffffffff1663a9059cbb85856040516024016134f79291906152ae565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506135c5565b505050565b6135bf848573ffffffffffffffffffffffffffffffffffffffff166323b872dd868686604051602401613578939291906144c7565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506135c5565b50505050565b5f6135ef828473ffffffffffffffffffffffffffffffffffffffff1661365a90919063ffffffff16565b90505f81511415801561361357508080602001905181019061361191906152ff565b155b1561365557826040517f5274afe700000000000000000000000000000000000000000000000000000000815260040161364c919061405c565b60405180910390fd5b505050565b606061366783835f61366f565b905092915050565b6060814710156136b657306040517fcd7860590000000000000000000000000000000000000000000000000000000081526004016136ad919061405c565b60405180910390fd5b5f808573ffffffffffffffffffffffffffffffffffffffff1684866040516136de9190614384565b5f6040518083038185875af1925050503d805f8114613718576040519150601f19603f3d011682016040523d82523d5f602084013e61371d565b606091505b509150915061372d868383613738565b925050509392505050565b60608261374d57613748826137c5565b6137bd565b5f825114801561377357505f8473ffffffffffffffffffffffffffffffffffffffff163b145b156137b557836040517f9996b3150000000000000000000000000000000000000000000000000000000081526004016137ac919061405c565b60405180910390fd5b8190506137be565b5b9392505050565b5f815111156137d75780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61384e8161381a565b8114613858575f80fd5b50565b5f8135905061386981613845565b92915050565b5f6020828403121561388457613883613812565b5b5f6138918482850161385b565b91505092915050565b5f8115159050919050565b6138ae8161389a565b82525050565b5f6020820190506138c75f8301846138a5565b92915050565b5f819050919050565b6138df816138cd565b81146138e9575f80fd5b50565b5f813590506138fa816138d6565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61392982613900565b9050919050565b6139398161391f565b8114613943575f80fd5b50565b5f8135905061395481613930565b92915050565b5f819050919050565b61396c8161395a565b8114613976575f80fd5b50565b5f8135905061398781613963565b92915050565b5f805f805f8060c087890312156139a7576139a6613812565b5b5f6139b489828a016138ec565b96505060206139c589828a01613946565b95505060406139d689828a016138ec565b94505060606139e789828a016138ec565b93505060806139f889828a01613946565b92505060a0613a0989828a01613979565b9150509295509295509295565b5f805f805f805f60e0888a031215613a3157613a30613812565b5b5f613a3e8a828b016138ec565b9750506020613a4f8a828b01613979565b9650506040613a608a828b01613979565b9550506060613a718a828b01613946565b9450506080613a828a828b016138ec565b93505060a0613a938a828b016138ec565b92505060c0613aa48a828b01613946565b91505092959891949750929550565b5f80fd5b5f80fd5b5f80fd5b5f8083601f840112613ad457613ad3613ab3565b5b8235905067ffffffffffffffff811115613af157613af0613ab7565b5b602083019150836001820283011115613b0d57613b0c613abb565b5b9250929050565b5f805f805f60808688031215613b2d57613b2c613812565b5b5f613b3a88828901613946565b9550506020613b4b88828901613946565b9450506040613b5c88828901613979565b935050606086013567ffffffffffffffff811115613b7d57613b7c613816565b5b613b8988828901613abf565b92509250509295509295909350565b613ba18161381a565b82525050565b5f602082019050613bba5f830184613b98565b92915050565b5f805f805f805f60e0888a031215613bdb57613bda613812565b5b5f613be88a828b016138ec565b9750506020613bf98a828b01613979565b9650506040613c0a8a828b01613946565b9550506060613c1b8a828b016138ec565b9450506080613c2c8a828b016138ec565b93505060a0613c3d8a828b01613946565b92505060c0613c4e8a828b01613979565b91505092959891949750929550565b5f60208284031215613c7257613c71613812565b5b5f613c7f848285016138ec565b91505092915050565b5f7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b613cbc81613c88565b82525050565b5f63ffffffff82169050919050565b613cda81613cc2565b82525050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60058110613d1e57613d1d613ce0565b5b50565b5f819050613d2e82613d0d565b919050565b5f613d3d82613d21565b9050919050565b613d4d81613d33565b82525050565b5f608082019050613d665f830187613cb3565b613d736020830186613cd1565b613d806040830185613cd1565b613d8d6060830184613d44565b95945050505050565b613d9f81613cc2565b8114613da9575f80fd5b50565b5f81359050613dba81613d96565b92915050565b5f805f805f805f60e0888a031215613ddb57613dda613812565b5b5f613de88a828b016138ec565b9750506020613df98a828b01613979565b9650506040613e0a8a828b01613946565b9550506060613e1b8a828b016138ec565b9450506080613e2c8a828b016138ec565b93505060a0613e3d8a828b01613dac565b92505060c0613e4e8a828b01613dac565b91505092959891949750929550565b5f8083601f840112613e7257613e71613ab3565b5b8235905067ffffffffffffffff811115613e8f57613e8e613ab7565b5b602083019150836020820283011115613eab57613eaa613abb565b5b9250929050565b5f805f805f805f8060a0898b031215613ece57613ecd613812565b5b5f613edb8b828c01613946565b9850506020613eec8b828c01613946565b975050604089013567ffffffffffffffff811115613f0d57613f0c613816565b5b613f198b828c01613e5d565b9650965050606089013567ffffffffffffffff811115613f3c57613f3b613816565b5b613f488b828c01613e5d565b9450945050608089013567ffffffffffffffff811115613f6b57613f6a613816565b5b613f778b828c01613abf565b92509250509295985092959890939650565b5f805f805f805f805f6101208a8c031215613fa757613fa6613812565b5b5f613fb48c828d016138ec565b9950506020613fc58c828d01613979565b9850506040613fd68c828d01613979565b9750506060613fe78c828d01613946565b9650506080613ff88c828d01613946565b95505060a06140098c828d016138ec565b94505060c061401a8c828d016138ec565b93505060e061402b8c828d01613dac565b92505061010061403d8c828d01613dac565b9150509295985092959850929598565b6140568161391f565b82525050565b5f60208201905061406f5f83018461404d565b92915050565b6004811061408657614085613ce0565b5b50565b5f81905061409682614075565b919050565b5f6140a582614089565b9050919050565b6140b58161409b565b82525050565b5f6060820190506140ce5f830186613cb3565b6140db6020830185613cd1565b6140e860408301846140ac565b949350505050565b5f805f805f8060a0878903121561410a57614109613812565b5b5f61411789828a01613946565b965050602061412889828a01613946565b955050604061413989828a01613979565b945050606061414a89828a01613979565b935050608087013567ffffffffffffffff81111561416b5761416a613816565b5b61417789828a01613abf565b92509250509295509295509295565b5f82825260208201905092915050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520505f8201527f61796d656e7453656e7400000000000000000000000000000000000000000000602082015250565b5f6141f0602a83614186565b91506141fb82614196565b604082019050919050565b5f6020820190508181035f83015261421d816141e4565b9050919050565b5f8160601b9050919050565b5f61423a82614224565b9050919050565b5f61424b82614230565b9050919050565b61426361425e8261391f565b614241565b82525050565b5f819050919050565b61428361427e826138cd565b614269565b82525050565b5f819050919050565b6142a361429e8261395a565b614289565b82525050565b5f6142b48289614252565b6014820191506142c48288614252565b6014820191506142d48287614272565b6020820191506142e48286614272565b6020820191506142f48285614252565b6014820191506143048284614292565b602082019150819050979650505050505050565b5f81519050919050565b5f81905092915050565b5f5b8381101561434957808201518184015260208101905061432e565b5f8484015250505050565b5f61435e82614318565b6143688185614322565b935061437881856020860161432c565b80840191505092915050565b5f61438f8284614354565b915081905092915050565b7f496e76616c6964207061796d656e7448617368000000000000000000000000005f82015250565b5f6143ce601383614186565b91506143d98261439a565b602082019050919050565b5f6020820190508181035f8301526143fb816143c2565b9050919050565b7f43757272656e742074696d657374616d70206469646e277420657863656564205f8201527f7061796d656e7420726566756e64206c6f636b2074696d650000000000000000602082015250565b5f61445c603883614186565b915061446782614402565b604082019050919050565b5f6020820190508181035f83015261448981614450565b9050919050565b614499816138cd565b82525050565b5f6020820190506144b25f830184614490565b92915050565b6144c18161395a565b82525050565b5f6060820190506144da5f83018661404d565b6144e7602083018561404d565b6144f460408301846144b8565b949350505050565b5f614507828a614292565b6020820191506145178289614292565b6020820191506145278288614252565b6014820191506145378287614252565b6014820191506145478286614272565b6020820191506145578285614272565b6020820191506145678284614252565b60148201915081905098975050505050505050565b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6145c682614580565b810181811067ffffffffffffffff821117156145e5576145e4614590565b5b80604052505050565b5f6145f7613809565b905061460382826145bd565b919050565b5f60c0828403121561461d5761461c61457c565b5b61462760c06145ee565b90505f614636848285016138ec565b5f83015250602061464984828501613946565b602083015250604061465d84828501613946565b6040830152506060614671848285016138ec565b6060830152506080614685848285016138ec565b60808301525060a061469984828501613dac565b60a08301525092915050565b5f60c082840312156146ba576146b9613812565b5b5f6146c784828501614608565b91505092915050565b7f54616b6572206d757374206e6f74206265207a65726f206164647265737300005f82015250565b5f614704601e83614186565b915061470f826146d0565b602082019050919050565b5f6020820190508181035f830152614731816146f8565b9050919050565b7f546f6b656e206d757374206e6f74206265207a65726f206164647265737300005f82015250565b5f61476c601e83614186565b915061477782614738565b602082019050919050565b5f6020820190508181035f83015261479981614760565b9050919050565b7f546f6b656e206164647265737320646f6573206e6f74206d617463682073656e5f8201527f6465720000000000000000000000000000000000000000000000000000000000602082015250565b5f6147fa602383614186565b9150614805826147a0565b604082019050919050565b5f6020820190508181035f830152614827816147ee565b9050919050565b7f4f70657261746f72206d757374206265207468652073656e64657200000000005f82015250565b5f614862601b83614186565b915061486d8261482e565b602082019050919050565b5f6020820190508181035f83015261488f81614856565b9050919050565b7f4d616b657220455243373231207061796d656e74206d75737420626520556e695f8201527f6e697469616c697a656400000000000000000000000000000000000000000000602082015250565b5f6148f0602a83614186565b91506148fb82614896565b604082019050919050565b5f6020820190508181035f83015261491d816148e4565b9050919050565b7f54616b65722063616e6e6f74206265206120636f6e74726163740000000000005f82015250565b5f614958601a83614186565b915061496382614924565b602082019050919050565b5f6020820190508181035f8301526149858161494c565b9050919050565b5f614997828a614252565b6014820191506149a78289614252565b6014820191506149b78288614272565b6020820191506149c78287614272565b6020820191506149d78286614252565b6014820191506149e78285614292565b6020820191506149f78284614292565b60208201915081905098975050505050505050565b5f82825260208201905092915050565b50565b5f614a2a5f83614a0c565b9150614a3582614a1c565b5f82019050919050565b5f60a082019050614a525f83018761404d565b614a5f602083018661404d565b614a6c60408301856144b8565b614a7960608301846144b8565b8181036080830152614a8a81614a1f565b905095945050505050565b5f614aa08284614272565b60208201915081905092915050565b5f81519050614abd816138d6565b92915050565b5f60208284031215614ad857614ad7613812565b5b5f614ae584828501614aaf565b91505092915050565b5f604082019050614b015f830185614490565b614b0e6020830184614490565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f614b4c8261395a565b9150614b578361395a565b9250828201905080821115614b6f57614b6e614b15565b5b92915050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520505f8201527f61796d656e7453656e74206f722054616b6572417070726f7665640000000000602082015250565b5f614bcf603b83614186565b9150614bda82614b75565b604082019050919050565b5f6020820190508181035f830152614bfc81614bc3565b9050919050565b7f43757272656e742074696d657374616d70206469646e277420657863656564205f8201527f7061796d656e74207072652d617070726f7665206c6f636b2074696d65000000602082015250565b5f614c5d603d83614186565b9150614c6882614c03565b604082019050919050565b5f6020820190508181035f830152614c8a81614c51565b9050919050565b7f54616b6572207061796d656e7420697320616c726561647920696e697469616c5f8201527f697a656400000000000000000000000000000000000000000000000000000000602082015250565b5f614ceb602483614186565b9150614cf682614c91565b604082019050919050565b5f6020820190508181035f830152614d1881614cdf565b9050919050565b7f5265636569766572206d757374206e6f74206265207a65726f206164647265735f8201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b5f614d79602183614186565b9150614d8482614d1f565b604082019050919050565b5f6020820190508181035f830152614da681614d6d565b9050919050565b7f4554482076616c7565206d7573742062652067726561746572207468616e207a5f8201527f65726f0000000000000000000000000000000000000000000000000000000000602082015250565b5f614e07602383614186565b9150614e1282614dad565b604082019050919050565b5f6020820190508181035f830152614e3481614dfb565b9050919050565b7f4554482076616c7565206d7573742062652067726561746572207468616e20645f8201527f6578206665650000000000000000000000000000000000000000000000000000602082015250565b5f614e95602683614186565b9150614ea082614e3b565b604082019050919050565b5f6020820190508181035f830152614ec281614e89565b9050919050565b5f614ed38261395a565b9150614ede8361395a565b9250828203905081811115614ef657614ef5614b15565b5b92915050565b7f4261746368207472616e7366657273206e6f7420737570706f727465640000005f82015250565b5f614f30601d83614186565b9150614f3b82614efc565b602082019050919050565b5f6020820190508181035f830152614f5d81614f24565b9050919050565b7f43616c6c6572206d75737420626520616e20454f4100000000000000000000005f82015250565b5f614f98601583614186565b9150614fa382614f64565b602082019050919050565b5f6020820190508181035f830152614fc581614f8c565b9050919050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520545f8201527f616b6572417070726f7665640000000000000000000000000000000000000000602082015250565b5f615026602c83614186565b915061503182614fcc565b604082019050919050565b5f6020820190508181035f8301526150538161501a565b9050919050565b7f4552433230207632207061796d656e7420697320616c726561647920696e69745f8201527f69616c697a656400000000000000000000000000000000000000000000000000602082015250565b5f6150b4602783614186565b91506150bf8261505a565b604082019050919050565b5f6020820190508181035f8301526150e1816150a8565b9050919050565b7f416d6f756e74206d757374206e6f74206265207a65726f0000000000000000005f82015250565b5f61511c601783614186565b9150615127826150e8565b602082019050919050565b5f6020820190508181035f83015261514981615110565b9050919050565b7f44657820666565206d757374206e6f74206265207a65726f00000000000000005f82015250565b5f615184601883614186565b915061518f82615150565b602082019050919050565b5f6020820190508181035f8301526151b181615178565b9050919050565b7f56616c7565206d7573742062652067726561746572207468616e2030000000005f82015250565b5f6151ec601c83614186565b91506151f7826151b8565b602082019050919050565b5f6020820190508181035f830152615219816151e0565b9050919050565b7f4d616b65722045524331313535207061796d656e74206d75737420626520556e5f8201527f696e697469616c697a6564000000000000000000000000000000000000000000602082015250565b5f61527a602b83614186565b915061528582615220565b604082019050919050565b5f6020820190508181035f8301526152a78161526e565b9050919050565b5f6040820190506152c15f83018561404d565b6152ce60208301846144b8565b9392505050565b6152de8161389a565b81146152e8575f80fd5b50565b5f815190506152f9816152d5565b92915050565b5f6020828403121561531457615313613812565b5b5f615321848285016152eb565b9150509291505056fea2646970667358221220de0fcae0c8d5c878eb19d054d488307775c257b169d9ffd7f39d5f524298f83564736f6c63430008180033"; pub trait CoinDockerOps { fn rpc_client(&self) -> &UtxoRpcClientEnum; diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index 7882834b64..c5d2af45ac 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -130,7 +130,6 @@ pub(crate) fn mint_erc721(to_addr: Address, token_id: U256) { "The ownership of the tokenID {:?} does not match the expected address {:?}.", token_id, to_addr ); - println!("\n to_addr {:?}, current ERC721 owner {:?} \n", to_addr, owner) } pub(crate) fn mint_erc1155(to_addr: Address, token_id: U256, amount: U256) { @@ -167,7 +166,6 @@ pub(crate) fn mint_erc1155(to_addr: Address, token_id: U256, amount: U256) { "The balance of tokenId {:?} for address {:?} does not match the expected amount {:?}.", token_id, to_addr, amount ); - println!("\n to_addr {:?}, ERC1155 balance {:?} \n", to_addr, balance); } pub(crate) async fn fill_erc1155_info(eth_coin: &EthCoin, tokens_id: u32, amount: u32) { diff --git a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs index a8643e8b45..acc2910287 100644 --- a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs @@ -37,6 +37,7 @@ fn send_and_spend_erc721_maker_payment() { swap_contract_address: &nft_swap_contract().to_bytes(), }; let maker_payment = block_on(maker_global_nft.send_nft_maker_payment_v2(send_payment_args)).unwrap(); + println!("Maker sent ERC721 NFT Payment tx hash {:02x}", maker_payment.tx_hash()); let confirm_input = ConfirmPaymentInput { payment_tx: maker_payment.tx_hex(), @@ -90,6 +91,7 @@ fn send_and_spend_erc1155_maker_payment() { swap_contract_address: &nft_swap_contract().to_bytes(), }; let maker_payment = block_on(maker_global_nft.send_nft_maker_payment_v2(send_payment_args)).unwrap(); + println!("Maker sent ERC1155 NFT Payment tx hash {:02x}", maker_payment.tx_hash()); let confirm_input = ConfirmPaymentInput { payment_tx: maker_payment.tx_hex(), From 008c999802c7dfe1d8b53288bc4632376fa12316 Mon Sep 17 00:00:00 2001 From: laruh Date: Wed, 20 Mar 2024 20:33:28 +0700 Subject: [PATCH 38/80] change topic and transfer_events for ERC1155 validation --- mm2src/coins/eth.rs | 233 +++--------------- .../tests/docker_tests/eth_docker_tests.rs | 2 +- 2 files changed, 30 insertions(+), 205 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index aff92a5cd0..ad06409712 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -6458,7 +6458,7 @@ impl EthCoin { Token::Uint(token_id_u256), Token::Bytes(htlc_data), ])?; - let gas = U256::from(ETH_GAS); + let gas = U256::from(200_000); self.sign_and_send_transaction(0.into(), Action::Call(token_address), data, gas) .compat() .await @@ -6590,8 +6590,9 @@ impl EthCoin { EthCoinType::Nft { .. } => { match contract_type { ContractType::Erc1155 => { + // as we use safeTransferFrom method, we can find erc1155 token payment info in logs emitted by events let topic = H256::from_slice( - keccak256("onERC1155Received(address,address,uint256,uint256,bytes)".as_bytes()).as_ref(), + keccak256("TransferSingle(address,address,address,uint256,uint256)".as_bytes()).as_ref(), ); let transfer_events = receipt.logs.iter().filter(|log| { log.address == expected_token_address && log.topics.get(0).unwrap() == &topic @@ -6604,116 +6605,33 @@ impl EthCoin { ))); } for log in transfer_events { - let function = NFT_SWAP_CONTRACT - .function("onERC1155Received") - .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; - let decoded = decode_contract_call(function, &log.data.0) - .map_to_mm(|err| ValidatePaymentError::TxDeserializationError(err.to_string()))?; - if decoded[0] != Token::Address(maker_address) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment `operator` {:?} is invalid, expected {:?}", - decoded[0], - Token::Address(maker_address) - ))); - } - if decoded[1] != Token::Address(maker_address) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment `sender` {:?} is invalid, expected maker address {:?}", - decoded[1], - Token::Address(maker_address) - ))); - } - let token_id = self.parse_token_id(args.token_id)?; - let token_id = U256::from_dec_str(&token_id.to_string()) - .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; - if decoded[2] != Token::Uint(token_id) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment `token_id` {:?} is invalid, expected {:?}", - decoded[2], - Token::Uint(token_id) - ))); - } - let value = U256::from_dec_str(&args.amount.to_string()) - .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; - if decoded[3] != Token::Uint(value) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment `amount` {:?} is invalid, expected {:?}", - decoded[3], - Token::Uint(value) - ))); - } - - if let Some(Token::Bytes(data_bytes)) = decoded.get(4) { - let htlc_params = &[ - ethabi::ParamType::FixedBytes(32), - ethabi::ParamType::Address, - ethabi::ParamType::Address, - ethabi::ParamType::FixedBytes(32), - ethabi::ParamType::FixedBytes(32), - ethabi::ParamType::Uint(256), - ]; - - if let Ok(decoded_params) = ethabi::decode(htlc_params, data_bytes) { - if decoded_params[0] != Token::FixedBytes(swap_id.clone()) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid 'swap_id' {:?}, expected {:?}", - decoded_params[0], - Token::FixedBytes(swap_id) - ))); - } - let taker_address = addr_from_raw_pubkey(args.taker_pub) - .map_to_mm(ValidatePaymentError::InternalError)?; - if decoded_params[1] != Token::Address(taker_address) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid `taker` {:?}, expected {:?}", - decoded_params[1], - Token::Address(taker_address) - ))); - } - if decoded_params[2] != Token::Address(expected_token_address) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid `token_address` {:?}, expected {:?}", - decoded_params[2], - Token::Address(expected_token_address) - ))); - } - if decoded_params[3] != Token::FixedBytes(args.taker_secret_hash.to_vec()) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid 'taker_secret_hash' {:?}, expected {:?}", - decoded_params[3], - Token::FixedBytes(args.taker_secret_hash.to_vec()) - ))); + let expected_maker = &H256::from(maker_address); + let valid_operator = log.topics.get(1).map_or(false, |op| op == expected_maker); + let valid_from = log.topics.get(2).map_or(false, |from| from == expected_maker); + let valid_to = log + .topics + .get(3) + .map_or(false, |to| to == &H256::from(expected_swap_contract)); + + if valid_operator && valid_from && valid_to { + let params = &[ethabi::ParamType::Uint(256), ethabi::ParamType::Uint(256)]; + + if let Ok(decoded_params) = ethabi::decode(params, &log.data.0) { + let valid_id = decoded_params[0] == Token::Uint(U256::from(args.token_id)); + let value = U256::from_dec_str(&args.amount.to_string()) + .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; + let valid_amount = decoded_params[1] == Token::Uint(value); + if valid_id && valid_amount { + return Ok(()); } - if decoded_params[4] != Token::FixedBytes(args.maker_secret_hash.to_vec()) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid 'maker_secret_hash' {:?}, expected {:?}", - decoded_params[4], - Token::FixedBytes(args.maker_secret_hash.to_vec()) - ))); - } - if decoded_params[5] != Token::Uint(U256::from(args.time_lock)) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid 'time_lock' {:?}, expected {:?}", - decoded_params[5], - Token::Uint(U256::from(args.time_lock)) - ))); - } - } else { - return MmError::err(ValidatePaymentError::TxDeserializationError( - "Failed to decode HTLCParams from data_bytes".to_string(), - )); } - } else { - return MmError::err(ValidatePaymentError::TxDeserializationError( - "Expected bytes for HTLCParams data".to_string(), - )); + // TODO add MakerPaymentSent event check } } }, ContractType::Erc721 => { - let topic = H256::from_slice( - keccak256("onERC721Received(address,address,uint256,bytes)".as_bytes()).as_ref(), - ); + let topic = + H256::from_slice(keccak256("Transfer(address,address,uint256)".as_bytes()).as_ref()); let transfer_events = receipt.logs.iter().filter(|log| { log.address == expected_token_address && log.topics.get(0).unwrap() == &topic }); @@ -6724,103 +6642,8 @@ impl EthCoin { receipt ))); } - for log in transfer_events { - let function = NFT_SWAP_CONTRACT - .function("onERC721Received") - .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; - let decoded = decode_contract_call(function, &log.data.0) - .map_to_mm(|err| ValidatePaymentError::TxDeserializationError(err.to_string()))?; - if decoded[0] != Token::Address(maker_address) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment `operator` {:?} is invalid, expected {:?}", - decoded[0], - Token::Address(maker_address) - ))); - } - if decoded[1] != Token::Address(maker_address) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment `sender` {:?} is invalid, expected maker address {:?}", - decoded[1], - Token::Address(maker_address) - ))); - } - let token_id = self.parse_token_id(args.token_id)?; - let token_id = U256::from_dec_str(&token_id.to_string()) - .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; - if decoded[2] != Token::Uint(token_id) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment `token_id` {:?} is invalid, expected {:?}", - decoded[2], - Token::Uint(token_id) - ))); - } - - if let Some(Token::Bytes(data_bytes)) = decoded.get(3) { - let htlc_params = &[ - ethabi::ParamType::FixedBytes(32), - ethabi::ParamType::Address, - ethabi::ParamType::Address, - ethabi::ParamType::FixedBytes(32), - ethabi::ParamType::FixedBytes(32), - ethabi::ParamType::Uint(256), - ]; - - if let Ok(decoded_params) = ethabi::decode(htlc_params, data_bytes) { - if decoded_params[0] != Token::FixedBytes(swap_id.clone()) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid 'swap_id' {:?}, expected {:?}", - decoded_params[0], - Token::FixedBytes(swap_id) - ))); - } - let taker_address = addr_from_raw_pubkey(args.taker_pub) - .map_to_mm(ValidatePaymentError::InternalError)?; - if decoded_params[1] != Token::Address(taker_address) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid `taker` {:?}, expected {:?}", - decoded_params[1], - Token::Address(taker_address) - ))); - } - if decoded_params[2] != Token::Address(expected_token_address) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid `token_address` {:?}, expected {:?}", - decoded_params[2], - Token::Address(expected_token_address) - ))); - } - if decoded_params[3] != Token::FixedBytes(args.taker_secret_hash.to_vec()) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid 'taker_secret_hash' {:?}, expected {:?}", - decoded_params[3], - Token::FixedBytes(args.taker_secret_hash.to_vec()) - ))); - } - if decoded_params[4] != Token::FixedBytes(args.maker_secret_hash.to_vec()) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid 'maker_secret_hash' {:?}, expected {:?}", - decoded_params[4], - Token::FixedBytes(args.maker_secret_hash.to_vec()) - ))); - } - if decoded_params[5] != Token::Uint(U256::from(args.time_lock)) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid 'time_lock' {:?}, expected {:?}", - decoded_params[5], - Token::Uint(U256::from(args.time_lock)) - ))); - } - } else { - return MmError::err(ValidatePaymentError::TxDeserializationError( - "Failed to decode HTLCParams from data_bytes".to_string(), - )); - } - } else { - return MmError::err(ValidatePaymentError::TxDeserializationError( - "Expected bytes for HTLCParams data".to_string(), - )); - } - } + // TODO add checks + return Ok(()); }, } }, @@ -6830,7 +6653,9 @@ impl EthCoin { )) }, } - Ok(()) + MmError::err(ValidatePaymentError::WrongPaymentTx( + "Didnt match expected Maker NFT Payment params".to_string(), + )) } async fn payment_status_v2( diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index c5d2af45ac..2c970394ad 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -109,7 +109,7 @@ pub(crate) fn mint_erc721(to_addr: Address, token_id: U256) { let erc721_contract = Contract::from_json(GETH_WEB3.eth(), erc721_contract(), ERC721_TEST_ABI.as_bytes()).unwrap(); let options = Options { - gas: Some(U256::from(1_000_000)), + gas: Some(U256::from(150_000)), ..Options::default() }; From ee42e2c0a5dfb830fa05a5ace80ec41b3379f41e Mon Sep 17 00:00:00 2001 From: laruh Date: Thu, 21 Mar 2024 20:48:40 +0700 Subject: [PATCH 39/80] decode and validate data from tx_from_rpc.input --- mm2src/coins/eth.rs | 278 ++++++++++++++++++++++++++++++++------------ 1 file changed, 202 insertions(+), 76 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index ad06409712..d88dd74b24 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -6458,7 +6458,7 @@ impl EthCoin { Token::Uint(token_id_u256), Token::Bytes(htlc_data), ])?; - let gas = U256::from(200_000); + let gas = U256::from(ETH_GAS); self.sign_and_send_transaction(0.into(), Action::Call(token_address), data, gas) .compat() .await @@ -6532,8 +6532,8 @@ impl EthCoin { &contract_type, ) .map_err(ValidatePaymentError::InternalError)?; - let expected_swap_contract = self.parse_token_contract_address(args.swap_contract_address)?; - let expected_token_address = self.parse_token_contract_address(args.token_address)?; + let etomic_swap_contract = self.parse_token_contract_address(args.swap_contract_address)?; + let token_address = self.parse_token_contract_address(args.token_address)?; let maker_address = addr_from_raw_pubkey(args.maker_pub).map_to_mm(ValidatePaymentError::InternalError)?; let time_lock_u32 = args .time_lock @@ -6542,7 +6542,7 @@ impl EthCoin { let swap_id = self.etomic_swap_id(time_lock_u32, args.maker_secret_hash); let maker_status = self .payment_status_v2( - expected_swap_contract, + etomic_swap_contract, Token::FixedBytes(swap_id.clone()), &NFT_SWAP_CONTRACT, StateType::MakerPayments, @@ -6569,83 +6569,211 @@ impl EthCoin { tx_from_rpc, maker_address ))); } - // As we call "safeTransferFrom" directly from token_address, then 'to' should be expected_token_address - if tx_from_rpc.to != Some(expected_token_address) { + // As we call "safeTransferFrom", then in Transaction 'to' field we expect token_address + if tx_from_rpc.to != Some(token_address) { return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( "NFT Maker Payment tx {:?} was sent to wrong address, expected {:?}", - tx_from_rpc, expected_token_address, + tx_from_rpc, token_address, ))); } - let receipt = self.transaction_receipt(args.maker_payment_tx.hash).await?; - let receipt = match receipt { - Some(r) => r, - None => { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Receipt wasn't found in NFT Maker Payment tx {:?}", - tx_from_rpc - ))) - }, - }; match self.coin_type { - EthCoinType::Nft { .. } => { - match contract_type { - ContractType::Erc1155 => { - // as we use safeTransferFrom method, we can find erc1155 token payment info in logs emitted by events - let topic = H256::from_slice( - keccak256("TransferSingle(address,address,address,uint256,uint256)".as_bytes()).as_ref(), - ); - let transfer_events = receipt.logs.iter().filter(|log| { - log.address == expected_token_address && log.topics.get(0).unwrap() == &topic - }); - let count = transfer_events.clone().count(); - if count == 0 { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "No events found in receipt {:?}", - receipt - ))); - } - for log in transfer_events { - let expected_maker = &H256::from(maker_address); - let valid_operator = log.topics.get(1).map_or(false, |op| op == expected_maker); - let valid_from = log.topics.get(2).map_or(false, |from| from == expected_maker); - let valid_to = log - .topics - .get(3) - .map_or(false, |to| to == &H256::from(expected_swap_contract)); - - if valid_operator && valid_from && valid_to { - let params = &[ethabi::ParamType::Uint(256), ethabi::ParamType::Uint(256)]; - - if let Ok(decoded_params) = ethabi::decode(params, &log.data.0) { - let valid_id = decoded_params[0] == Token::Uint(U256::from(args.token_id)); - let value = U256::from_dec_str(&args.amount.to_string()) - .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; - let valid_amount = decoded_params[1] == Token::Uint(value); - if valid_id && valid_amount { - return Ok(()); - } - } - // TODO add MakerPaymentSent event check + EthCoinType::Nft { .. } => match contract_type { + ContractType::Erc1155 => { + let function = ERC1155_CONTRACT + .function("safeTransferFrom") + .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; + let decoded = decode_contract_call(function, &tx_from_rpc.input.0) + .map_to_mm(|err| ValidatePaymentError::TxDeserializationError(err.to_string()))?; + if decoded[0] != Token::Address(maker_address) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment `maker_address` {:?} is invalid, expected {:?}", + decoded[0], + Token::Address(maker_address) + ))); + } + if decoded[1] != Token::Address(etomic_swap_contract) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment `etomic_swap_contract` {:?} is invalid, expected address {:?}", + decoded[1], + Token::Address(maker_address) + ))); + } + let token_id = U256::from(args.token_id); + if decoded[2] != Token::Uint(token_id) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment `token_id` {:?} is invalid, expected {:?}", + decoded[2], + Token::Uint(token_id) + ))); + } + let value = U256::from_dec_str(&args.amount.to_string()) + .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; + if decoded[3] != Token::Uint(value) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment `amount` {:?} is invalid, expected {:?}", + decoded[3], + Token::Uint(value) + ))); + } + if let Some(Token::Bytes(data_bytes)) = decoded.get(4) { + let htlc_params = &[ + ethabi::ParamType::FixedBytes(32), + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::FixedBytes(32), + ethabi::ParamType::FixedBytes(32), + ethabi::ParamType::Uint(256), + ]; + if let Ok(decoded_params) = ethabi::decode(htlc_params, data_bytes) { + if decoded_params[0] != Token::FixedBytes(swap_id.clone()) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid 'swap_id' {:?}, expected {:?}", + decoded_params[0], + Token::FixedBytes(swap_id) + ))); + } + let taker_address = + addr_from_raw_pubkey(args.taker_pub).map_to_mm(ValidatePaymentError::InternalError)?; + if decoded_params[1] != Token::Address(taker_address) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid `taker_address` {:?}, expected {:?}", + decoded_params[1], + Token::Address(taker_address) + ))); + } + if decoded_params[2] != Token::Address(token_address) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid `token_address` {:?}, expected {:?}", + decoded_params[2], + Token::Address(token_address) + ))); + } + if decoded_params[3] != Token::FixedBytes(args.taker_secret_hash.to_vec()) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid 'taker_secret_hash' {:?}, expected {:?}", + decoded_params[3], + Token::FixedBytes(args.taker_secret_hash.to_vec()) + ))); + } + if decoded_params[4] != Token::FixedBytes(args.maker_secret_hash.to_vec()) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid 'maker_secret_hash' {:?}, expected {:?}", + decoded_params[4], + Token::FixedBytes(args.maker_secret_hash.to_vec()) + ))); } + if decoded_params[5] != Token::Uint(U256::from(args.time_lock)) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid 'time_lock' {:?}, expected {:?}", + decoded_params[5], + Token::Uint(U256::from(args.time_lock)) + ))); + } + println!("ERC1155 Payment validated\n {:?}", tx_from_rpc); + } else { + return MmError::err(ValidatePaymentError::TxDeserializationError( + "Failed to decode HTLCParams from data_bytes".to_string(), + )); } - }, - ContractType::Erc721 => { - let topic = - H256::from_slice(keccak256("Transfer(address,address,uint256)".as_bytes()).as_ref()); - let transfer_events = receipt.logs.iter().filter(|log| { - log.address == expected_token_address && log.topics.get(0).unwrap() == &topic - }); - let count = transfer_events.clone().count(); - if count == 0 { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "No events found in receipt {:?}", - receipt - ))); + } else { + return MmError::err(ValidatePaymentError::TxDeserializationError( + "Expected bytes for HTLCParams data".to_string(), + )); + } + }, + ContractType::Erc721 => { + let function = ERC721_CONTRACT + .function("safeTransferFrom") + .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; + let decoded = decode_contract_call(function, &tx_from_rpc.input.0) + .map_to_mm(|err| ValidatePaymentError::TxDeserializationError(err.to_string()))?; + if decoded[0] != Token::Address(maker_address) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment `maker_address` {:?} is invalid, expected {:?}", + decoded[0], + Token::Address(maker_address) + ))); + } + if decoded[1] != Token::Address(etomic_swap_contract) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment `etomic_swap_contract` {:?} is invalid, expected address {:?}", + decoded[1], + Token::Address(maker_address) + ))); + } + let token_id = U256::from(args.token_id); + if decoded[2] != Token::Uint(token_id) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment `token_id` {:?} is invalid, expected {:?}", + decoded[2], + Token::Uint(token_id) + ))); + } + if let Some(Token::Bytes(data_bytes)) = decoded.get(3) { + let htlc_params = &[ + ethabi::ParamType::FixedBytes(32), + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::FixedBytes(32), + ethabi::ParamType::FixedBytes(32), + ethabi::ParamType::Uint(256), + ]; + if let Ok(decoded_params) = ethabi::decode(htlc_params, data_bytes) { + if decoded_params[0] != Token::FixedBytes(swap_id.clone()) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid 'swap_id' {:?}, expected {:?}", + decoded_params[0], + Token::FixedBytes(swap_id) + ))); + } + let taker_address = + addr_from_raw_pubkey(args.taker_pub).map_to_mm(ValidatePaymentError::InternalError)?; + if decoded_params[1] != Token::Address(taker_address) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid `taker_address` {:?}, expected {:?}", + decoded_params[1], + Token::Address(taker_address) + ))); + } + if decoded_params[2] != Token::Address(token_address) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid `token_address` {:?}, expected {:?}", + decoded_params[2], + Token::Address(token_address) + ))); + } + if decoded_params[3] != Token::FixedBytes(args.taker_secret_hash.to_vec()) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid 'taker_secret_hash' {:?}, expected {:?}", + decoded_params[3], + Token::FixedBytes(args.taker_secret_hash.to_vec()) + ))); + } + if decoded_params[4] != Token::FixedBytes(args.maker_secret_hash.to_vec()) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid 'maker_secret_hash' {:?}, expected {:?}", + decoded_params[4], + Token::FixedBytes(args.maker_secret_hash.to_vec()) + ))); + } + if decoded_params[5] != Token::Uint(U256::from(args.time_lock)) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "Invalid 'time_lock' {:?}, expected {:?}", + decoded_params[5], + Token::Uint(U256::from(args.time_lock)) + ))); + } + } else { + return MmError::err(ValidatePaymentError::TxDeserializationError( + "Failed to decode HTLCParams from data_bytes".to_string(), + )); } - // TODO add checks - return Ok(()); - }, - } + } else { + return MmError::err(ValidatePaymentError::TxDeserializationError( + "Expected bytes for HTLCParams data".to_string(), + )); + } + }, }, EthCoinType::Eth | EthCoinType::Erc20 { .. } => { return MmError::err(ValidatePaymentError::InternalError( @@ -6653,9 +6781,7 @@ impl EthCoin { )) }, } - MmError::err(ValidatePaymentError::WrongPaymentTx( - "Didnt match expected Maker NFT Payment params".to_string(), - )) + Ok(()) } async fn payment_status_v2( From 360be27dead3c11cc7a75adc9311903e4087bcb4 Mon Sep 17 00:00:00 2001 From: laruh Date: Thu, 21 Mar 2024 21:15:39 +0700 Subject: [PATCH 40/80] polish code --- mm2src/coins/eth.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index d88dd74b24..60e0c84fe1 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -6404,9 +6404,7 @@ impl EthCoin { .time_lock .try_into() .map_err(|e: TryFromIntError| TransactionErr::Plain(ERRL!("{}", e)))?; - let token_id = self.parse_token_id(args.token_id)?; - let token_id_u256 = - U256::from_dec_str(&token_id.to_string()).map_err(|e| NumConversError::new(ERRL!("{}", e)))?; + let token_id_u256 = U256::from(args.token_id); let htlc_data = self.prepare_htlc_data(&args, taker_address, token_address, time_lock_u32); match &self.coin_type { @@ -6464,11 +6462,8 @@ impl EthCoin { .await }, }, - EthCoinType::Erc20 { .. } => Err(TransactionErr::ProtocolNotSupported( - "ERC20 Protocol is not supported for NFT Swaps".to_string(), - )), - EthCoinType::Eth => Err(TransactionErr::ProtocolNotSupported( - "ETH Protocol is not supported for NFT Swaps!".to_string(), + EthCoinType::Eth | EthCoinType::Erc20 { .. } => Err(TransactionErr::ProtocolNotSupported( + "ETH and ERC20 Protocols are not supported for NFT Swaps".to_string(), )), } } From 1f5a3cf80afa6d0aee0fa8ca316b58ed1b646ee0 Mon Sep 17 00:00:00 2001 From: laruh Date: Fri, 22 Mar 2024 11:39:44 +0700 Subject: [PATCH 41/80] ignore erc1155 test, increase wait_until confirmation for erc721 --- mm2src/coins/eth.rs | 4 ++-- mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 60e0c84fe1..5ae9389d2f 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -6397,7 +6397,7 @@ impl EthCoin { ) .map_err(TransactionErr::Plain)?; - let taker_address = addr_from_raw_pubkey(args.taker_pub).map_err(TransactionErr::Plain)?; + let taker_address = addr_from_raw_pubkey(args.taker_pub).map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; let token_address = self.parse_token_contract_address(args.token_address)?; let swap_contract_address = self.parse_token_contract_address(args.swap_contract_address)?; let time_lock_u32 = args @@ -6797,7 +6797,7 @@ impl EthCoin { match state { Token::Uint(state) => Ok(*state), _ => Err(PaymentStatusErr::Internal(format!( - "Payment status must be uint, got {:?}", + "Payment status must be Uint, got {:?}", state ))), } diff --git a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs index acc2910287..e9907c3a25 100644 --- a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs @@ -43,7 +43,7 @@ fn send_and_spend_erc721_maker_payment() { payment_tx: maker_payment.tx_hex(), confirmations: 1, requires_nota: false, - wait_until: now_sec() + 60, + wait_until: now_sec() + 90, check_every: 1, }; maker_global_nft.wait_for_confirmations(confirm_input).wait().unwrap(); @@ -67,6 +67,7 @@ fn send_and_spend_erc721_maker_payment() { } #[test] +#[ignore] fn send_and_spend_erc1155_maker_payment() { let erc1155_nft = TestNftType::Erc1155 { token_id: 1, amount: 3 }; From fa27f7b2de3ef2d5c5e19ce9d4bcbce0bdc9a7e3 Mon Sep 17 00:00:00 2001 From: laruh Date: Fri, 22 Mar 2024 12:20:13 +0700 Subject: [PATCH 42/80] dont ignore erc1155 test, get correct version of overloaded "safeTransferFrom" func in erc721 validation --- mm2src/coins/eth.rs | 26 ++++++++++++++++--- .../docker_tests/nft_swap_proto_v2_tests.rs | 5 ++-- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 5ae9389d2f..0c2a84a3c8 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -6664,7 +6664,6 @@ impl EthCoin { Token::Uint(U256::from(args.time_lock)) ))); } - println!("ERC1155 Payment validated\n {:?}", tx_from_rpc); } else { return MmError::err(ValidatePaymentError::TxDeserializationError( "Failed to decode HTLCParams from data_bytes".to_string(), @@ -6677,9 +6676,28 @@ impl EthCoin { } }, ContractType::Erc721 => { - let function = ERC721_CONTRACT - .function("safeTransferFrom") - .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; + // ERC721 contract has overloaded versions of the safeTransferFrom function, + // but Contract::function method returns only the first if there are overloaded versions of the same function. + let functions = ERC721_CONTRACT + .functions_by_name("safeTransferFrom") + .map_err(|e| ValidatePaymentError::InternalError(ERRL!("{}", e)))?; + + // Find the correct function variant by inspecting the input parameters. + let function = functions + .iter() + .find(|f| { + f.inputs.len() == 4 + && matches!( + f.inputs.last().map(|input| &input.kind), + Some(ðabi::ParamType::Bytes) + ) + }) + .ok_or_else(|| { + ValidatePaymentError::InternalError( + "Failed to find the correct safeTransferFrom function variant".to_string(), + ) + })?; + let decoded = decode_contract_call(function, &tx_from_rpc.input.0) .map_to_mm(|err| ValidatePaymentError::TxDeserializationError(err.to_string()))?; if decoded[0] != Token::Address(maker_address) { diff --git a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs index e9907c3a25..712352b8b9 100644 --- a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs @@ -37,7 +37,7 @@ fn send_and_spend_erc721_maker_payment() { swap_contract_address: &nft_swap_contract().to_bytes(), }; let maker_payment = block_on(maker_global_nft.send_nft_maker_payment_v2(send_payment_args)).unwrap(); - println!("Maker sent ERC721 NFT Payment tx hash {:02x}", maker_payment.tx_hash()); + println!("Maker sent ERC721 NFT Payment tx {:?}", maker_payment); let confirm_input = ConfirmPaymentInput { payment_tx: maker_payment.tx_hex(), @@ -67,7 +67,6 @@ fn send_and_spend_erc721_maker_payment() { } #[test] -#[ignore] fn send_and_spend_erc1155_maker_payment() { let erc1155_nft = TestNftType::Erc1155 { token_id: 1, amount: 3 }; @@ -92,7 +91,7 @@ fn send_and_spend_erc1155_maker_payment() { swap_contract_address: &nft_swap_contract().to_bytes(), }; let maker_payment = block_on(maker_global_nft.send_nft_maker_payment_v2(send_payment_args)).unwrap(); - println!("Maker sent ERC1155 NFT Payment tx hash {:02x}", maker_payment.tx_hash()); + println!("Maker sent ERC1155 NFT Payment tx {:?}", maker_payment); let confirm_input = ConfirmPaymentInput { payment_tx: maker_payment.tx_hex(), From 718305d7604c09101349937f6f9f8e084335ce4e Mon Sep 17 00:00:00 2001 From: laruh Date: Fri, 22 Mar 2024 12:52:34 +0700 Subject: [PATCH 43/80] leave `wait_until: now_sec() + 60` for erc721, while erc1155 ignored --- .../tests/docker_tests/nft_swap_proto_v2_tests.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs index 712352b8b9..77eb7283e0 100644 --- a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs @@ -19,7 +19,7 @@ fn send_and_spend_erc721_maker_payment() { let maker_global_nft = global_nft_with_random_privkey(nft_swap_contract(), Some(erc721_nft)); let taker_global_nft = global_nft_with_random_privkey(nft_swap_contract(), None); - let time_lock = now_sec() - 100; + let time_lock = now_sec() + 1000; let maker_pubkey = maker_global_nft.derive_htlc_pubkey(&[]); let taker_pubkey = taker_global_nft.derive_htlc_pubkey(&[]); @@ -37,13 +37,13 @@ fn send_and_spend_erc721_maker_payment() { swap_contract_address: &nft_swap_contract().to_bytes(), }; let maker_payment = block_on(maker_global_nft.send_nft_maker_payment_v2(send_payment_args)).unwrap(); - println!("Maker sent ERC721 NFT Payment tx {:?}", maker_payment); + println!("Maker sent ERC721 Payment tx {:?}", maker_payment); let confirm_input = ConfirmPaymentInput { payment_tx: maker_payment.tx_hex(), confirmations: 1, requires_nota: false, - wait_until: now_sec() + 90, + wait_until: now_sec() + 60, // ERC721 tokens need more time for confirmation check_every: 1, }; maker_global_nft.wait_for_confirmations(confirm_input).wait().unwrap(); @@ -67,13 +67,14 @@ fn send_and_spend_erc721_maker_payment() { } #[test] +#[ignore] fn send_and_spend_erc1155_maker_payment() { let erc1155_nft = TestNftType::Erc1155 { token_id: 1, amount: 3 }; let maker_global_nft = global_nft_with_random_privkey(nft_swap_contract(), Some(erc1155_nft)); let taker_global_nft = global_nft_with_random_privkey(nft_swap_contract(), None); - let time_lock = now_sec() - 100; + let time_lock = now_sec() + 1000; let maker_pubkey = maker_global_nft.derive_htlc_pubkey(&[]); let taker_pubkey = taker_global_nft.derive_htlc_pubkey(&[]); @@ -91,7 +92,7 @@ fn send_and_spend_erc1155_maker_payment() { swap_contract_address: &nft_swap_contract().to_bytes(), }; let maker_payment = block_on(maker_global_nft.send_nft_maker_payment_v2(send_payment_args)).unwrap(); - println!("Maker sent ERC1155 NFT Payment tx {:?}", maker_payment); + println!("Maker sent ERC1155 Payment tx {:?}", maker_payment); let confirm_input = ConfirmPaymentInput { payment_tx: maker_payment.tx_hex(), From 9fdc5d81133954f612d767255e928d560b5b8cc4 Mon Sep 17 00:00:00 2001 From: laruh Date: Fri, 22 Mar 2024 13:24:09 +0700 Subject: [PATCH 44/80] correct tokenId in ValidateNftMakerPaymentArgs --- .../tests/docker_tests/nft_swap_proto_v2_tests.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs index 77eb7283e0..0b9cd0270c 100644 --- a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs @@ -37,13 +37,13 @@ fn send_and_spend_erc721_maker_payment() { swap_contract_address: &nft_swap_contract().to_bytes(), }; let maker_payment = block_on(maker_global_nft.send_nft_maker_payment_v2(send_payment_args)).unwrap(); - println!("Maker sent ERC721 Payment tx {:?}", maker_payment); + println!("Maker sent ERC721 NFT Payment tx hash {:02x}", maker_payment.tx_hash()); let confirm_input = ConfirmPaymentInput { payment_tx: maker_payment.tx_hex(), confirmations: 1, requires_nota: false, - wait_until: now_sec() + 60, // ERC721 tokens need more time for confirmation + wait_until: now_sec() + 60, check_every: 1, }; maker_global_nft.wait_for_confirmations(confirm_input).wait().unwrap(); @@ -58,7 +58,7 @@ fn send_and_spend_erc721_maker_payment() { maker_pub: &maker_global_nft.parse_pubkey(&maker_pubkey).unwrap(), swap_unique_data: &[], token_address: &erc721_contract().to_bytes(), - token_id: &BigUint::from(1u32).to_bytes(), + token_id: &BigUint::from(2u32).to_bytes(), chain: &Chain::Eth.to_bytes(), contract_type: &ContractType::Erc721.to_bytes(), swap_contract_address: &nft_swap_contract().to_bytes(), @@ -69,7 +69,7 @@ fn send_and_spend_erc721_maker_payment() { #[test] #[ignore] fn send_and_spend_erc1155_maker_payment() { - let erc1155_nft = TestNftType::Erc1155 { token_id: 1, amount: 3 }; + let erc1155_nft = TestNftType::Erc1155 { token_id: 4, amount: 3 }; let maker_global_nft = global_nft_with_random_privkey(nft_swap_contract(), Some(erc1155_nft)); let taker_global_nft = global_nft_with_random_privkey(nft_swap_contract(), None); @@ -86,13 +86,13 @@ fn send_and_spend_erc1155_maker_payment() { taker_pub: &taker_global_nft.parse_pubkey(&taker_pubkey).unwrap(), swap_unique_data: &[], token_address: &erc1155_contract().to_bytes(), - token_id: &BigUint::from(1u32).to_bytes(), + token_id: &BigUint::from(4u32).to_bytes(), chain: &Chain::Eth.to_bytes(), contract_type: &ContractType::Erc1155.to_bytes(), swap_contract_address: &nft_swap_contract().to_bytes(), }; let maker_payment = block_on(maker_global_nft.send_nft_maker_payment_v2(send_payment_args)).unwrap(); - println!("Maker sent ERC1155 Payment tx {:?}", maker_payment); + println!("Maker sent ERC1155 NFT Payment tx hash {:02x}", maker_payment.tx_hash()); let confirm_input = ConfirmPaymentInput { payment_tx: maker_payment.tx_hex(), @@ -113,7 +113,7 @@ fn send_and_spend_erc1155_maker_payment() { maker_pub: &maker_global_nft.parse_pubkey(&maker_pubkey).unwrap(), swap_unique_data: &[], token_address: &erc1155_contract().to_bytes(), - token_id: &BigUint::from(1u32).to_bytes(), + token_id: &BigUint::from(4u32).to_bytes(), chain: &Chain::Eth.to_bytes(), contract_type: &ContractType::Erc1155.to_bytes(), swap_contract_address: &nft_swap_contract().to_bytes(), From bb080f866359ddf746a17e49f83026c5e3bc41e1 Mon Sep 17 00:00:00 2001 From: laruh Date: Fri, 22 Mar 2024 14:27:17 +0700 Subject: [PATCH 45/80] log Current gas limit, in ERC721 test wait_until: now_sec() + 200 --- .../tests/docker_tests/docker_tests_common.rs | 13 ++++++++++++- .../tests/docker_tests/nft_swap_proto_v2_tests.rs | 3 +-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs index c854ef0c29..ae1ecec367 100644 --- a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs +++ b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs @@ -49,7 +49,7 @@ use testcontainers::clients::Cli; use testcontainers::core::WaitFor; use testcontainers::{Container, GenericImage, RunnableImage}; use web3::transports::Http; -use web3::types::TransactionRequest; +use web3::types::{BlockId, BlockNumber, TransactionRequest}; use web3::Web3; lazy_static! { @@ -1043,8 +1043,19 @@ pub fn withdraw_max_and_send_v1(mm: &MarketMakerIt, coin: &str, to: &str) -> Tra tx_details } +async fn get_current_gas_limit(web3: &Web3) { + match web3.eth().block(BlockId::Number(BlockNumber::Latest)).await { + Ok(Some(block)) => { + log!("Current gas limit: {}", block.gas_limit); + }, + Ok(None) => log!("Latest block information is not available."), + Err(e) => log!("Failed to fetch the latest block: {}", e), + } +} + pub fn init_geth_node() { unsafe { + block_on(get_current_gas_limit(&GETH_WEB3)); let accounts = block_on(GETH_WEB3.eth().accounts()).unwrap(); GETH_ACCOUNT = accounts[0]; log!("GETH ACCOUNT {:?}", GETH_ACCOUNT); diff --git a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs index 0b9cd0270c..f4720c2d78 100644 --- a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs @@ -43,7 +43,7 @@ fn send_and_spend_erc721_maker_payment() { payment_tx: maker_payment.tx_hex(), confirmations: 1, requires_nota: false, - wait_until: now_sec() + 60, + wait_until: now_sec() + 200, check_every: 1, }; maker_global_nft.wait_for_confirmations(confirm_input).wait().unwrap(); @@ -67,7 +67,6 @@ fn send_and_spend_erc721_maker_payment() { } #[test] -#[ignore] fn send_and_spend_erc1155_maker_payment() { let erc1155_nft = TestNftType::Erc1155 { token_id: 4, amount: 3 }; From 7141244fbd0bc69f72f202396d13c99acbb64aab Mon Sep 17 00:00:00 2001 From: laruh Date: Fri, 22 Mar 2024 15:29:48 +0700 Subject: [PATCH 46/80] impl decode_and_validate_htlc_params, erc721_transfer_with_data fncs --- mm2src/coins/coin_errors.rs | 15 +- mm2src/coins/eth.rs | 318 ++++++++---------- mm2src/coins/lp_coins.rs | 11 +- .../docker_tests/nft_swap_proto_v2_tests.rs | 3 +- 4 files changed, 171 insertions(+), 176 deletions(-) diff --git a/mm2src/coins/coin_errors.rs b/mm2src/coins/coin_errors.rs index 8836c9938f..5aef20ab83 100644 --- a/mm2src/coins/coin_errors.rs +++ b/mm2src/coins/coin_errors.rs @@ -1,4 +1,4 @@ -use crate::eth::{CoinAssocTypesError, NftAssocTypesError, PaymentStatusErr}; +use crate::eth::{CoinAssocTypesError, Erc721FunctionError, HtlcParamsError, NftAssocTypesError, PaymentStatusErr}; use crate::{eth::Web3RpcError, my_tx_history_v2::MyTxHistoryErrorV2, utxo::rpc_clients::UtxoRpcError, DelegationError, NumConversError, TxHistoryError, UnexpectedDerivationMethod, WithdrawError}; use futures01::Future; @@ -108,6 +108,19 @@ impl From for ValidatePaymentError { } } +impl From for ValidatePaymentError { + fn from(err: Erc721FunctionError) -> Self { Self::InternalError(err.to_string()) } +} + +impl From for ValidatePaymentError { + fn from(err: HtlcParamsError) -> Self { + match err { + HtlcParamsError::WrongPaymentTx(e) => ValidatePaymentError::WrongPaymentTx(e), + HtlcParamsError::TxDeserializationError(e) => ValidatePaymentError::TxDeserializationError(e), + } + } +} + #[derive(Debug, Display)] pub enum MyAddressError { UnexpectedDerivationMethod(String), diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 0c2a84a3c8..6f37aa2682 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -6428,28 +6428,7 @@ impl EthCoin { .await }, ContractType::Erc721 => { - // ERC721 contract has overloaded versions of the safeTransferFrom function, - // but Contract::function method returns only the first if there are overloaded versions of the same function. - let functions = ERC721_CONTRACT - .functions_by_name("safeTransferFrom") - .map_err(|e| TransactionErr::AbiError(ERRL!("{}", e)))?; - - // Find the correct function variant by inspecting the input parameters. - let function = functions - .iter() - .find(|f| { - f.inputs.len() == 4 - && matches!( - f.inputs.last().map(|input| &input.kind), - Some(ðabi::ParamType::Bytes) - ) - }) - .ok_or_else(|| { - TransactionErr::AbiError( - "Failed to find the correct safeTransferFrom function variant".to_string(), - ) - })?; - + let function = self.erc721_transfer_with_data()?; let data = function.encode_input(&[ Token::Address(self.my_address), Token::Address(swap_contract_address), @@ -6515,6 +6494,33 @@ impl EthCoin { ]) } + /// ERC721 contract has overloaded versions of the `safeTransferFrom` function, + /// but `Contract::function` method returns only the first if there are overloaded versions of the same function. + /// Provided function retrieves the `safeTransferFrom` variant that includes a `bytes` parameter. + /// This variant is specifically used for transferring ERC721 tokens with additional data. + fn erc721_transfer_with_data(&self) -> Result<ðabi::Function, Erc721FunctionError> { + let functions = ERC721_CONTRACT + .functions_by_name("safeTransferFrom") + .map_err(|e| Erc721FunctionError::AbiError(ERRL!("{}", e)))?; + + // Find the correct function variant by inspecting the input parameters. + let function = functions + .iter() + .find(|f| { + f.inputs.len() == 4 + && matches!( + f.inputs.last().map(|input| &input.kind), + Some(ðabi::ParamType::Bytes) + ) + }) + .ok_or_else(|| { + Erc721FunctionError::FunctionNotFound( + "Failed to find the correct safeTransferFrom function variant".to_string(), + ) + })?; + Ok(function) + } + async fn validate_nft_maker_payment_v2_impl( &self, args: ValidateNftMakerPaymentArgs<'_, Self>, @@ -6564,7 +6570,7 @@ impl EthCoin { tx_from_rpc, maker_address ))); } - // As we call "safeTransferFrom", then in Transaction 'to' field we expect token_address + // As NFT owner calls "safeTransferFrom" directly, then in Transaction 'to' field we expect token_address if tx_from_rpc.to != Some(token_address) { return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( "NFT Maker Payment tx {:?} was sent to wrong address, expected {:?}", @@ -6610,94 +6616,21 @@ impl EthCoin { Token::Uint(value) ))); } - if let Some(Token::Bytes(data_bytes)) = decoded.get(4) { - let htlc_params = &[ - ethabi::ParamType::FixedBytes(32), - ethabi::ParamType::Address, - ethabi::ParamType::Address, - ethabi::ParamType::FixedBytes(32), - ethabi::ParamType::FixedBytes(32), - ethabi::ParamType::Uint(256), - ]; - if let Ok(decoded_params) = ethabi::decode(htlc_params, data_bytes) { - if decoded_params[0] != Token::FixedBytes(swap_id.clone()) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid 'swap_id' {:?}, expected {:?}", - decoded_params[0], - Token::FixedBytes(swap_id) - ))); - } - let taker_address = - addr_from_raw_pubkey(args.taker_pub).map_to_mm(ValidatePaymentError::InternalError)?; - if decoded_params[1] != Token::Address(taker_address) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid `taker_address` {:?}, expected {:?}", - decoded_params[1], - Token::Address(taker_address) - ))); - } - if decoded_params[2] != Token::Address(token_address) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid `token_address` {:?}, expected {:?}", - decoded_params[2], - Token::Address(token_address) - ))); - } - if decoded_params[3] != Token::FixedBytes(args.taker_secret_hash.to_vec()) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid 'taker_secret_hash' {:?}, expected {:?}", - decoded_params[3], - Token::FixedBytes(args.taker_secret_hash.to_vec()) - ))); - } - if decoded_params[4] != Token::FixedBytes(args.maker_secret_hash.to_vec()) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid 'maker_secret_hash' {:?}, expected {:?}", - decoded_params[4], - Token::FixedBytes(args.maker_secret_hash.to_vec()) - ))); - } - if decoded_params[5] != Token::Uint(U256::from(args.time_lock)) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid 'time_lock' {:?}, expected {:?}", - decoded_params[5], - Token::Uint(U256::from(args.time_lock)) - ))); - } - } else { - return MmError::err(ValidatePaymentError::TxDeserializationError( - "Failed to decode HTLCParams from data_bytes".to_string(), - )); - } - } else { - return MmError::err(ValidatePaymentError::TxDeserializationError( - "Expected bytes for HTLCParams data".to_string(), - )); - } + + let taker_address = + addr_from_raw_pubkey(args.taker_pub).map_to_mm(ValidatePaymentError::InternalError)?; + let htlc_params = ExpectedHtlcParams { + swap_id, + taker_address, + token_address, + taker_secret_hash: args.taker_secret_hash.to_vec(), + maker_secret_hash: args.maker_secret_hash.to_vec(), + time_lock: U256::from(args.time_lock), + }; + decode_and_validate_htlc_params(decoded, 4, htlc_params)?; }, ContractType::Erc721 => { - // ERC721 contract has overloaded versions of the safeTransferFrom function, - // but Contract::function method returns only the first if there are overloaded versions of the same function. - let functions = ERC721_CONTRACT - .functions_by_name("safeTransferFrom") - .map_err(|e| ValidatePaymentError::InternalError(ERRL!("{}", e)))?; - - // Find the correct function variant by inspecting the input parameters. - let function = functions - .iter() - .find(|f| { - f.inputs.len() == 4 - && matches!( - f.inputs.last().map(|input| &input.kind), - Some(ðabi::ParamType::Bytes) - ) - }) - .ok_or_else(|| { - ValidatePaymentError::InternalError( - "Failed to find the correct safeTransferFrom function variant".to_string(), - ) - })?; - + let function = self.erc721_transfer_with_data()?; let decoded = decode_contract_call(function, &tx_from_rpc.input.0) .map_to_mm(|err| ValidatePaymentError::TxDeserializationError(err.to_string()))?; if decoded[0] != Token::Address(maker_address) { @@ -6722,70 +6655,18 @@ impl EthCoin { Token::Uint(token_id) ))); } - if let Some(Token::Bytes(data_bytes)) = decoded.get(3) { - let htlc_params = &[ - ethabi::ParamType::FixedBytes(32), - ethabi::ParamType::Address, - ethabi::ParamType::Address, - ethabi::ParamType::FixedBytes(32), - ethabi::ParamType::FixedBytes(32), - ethabi::ParamType::Uint(256), - ]; - if let Ok(decoded_params) = ethabi::decode(htlc_params, data_bytes) { - if decoded_params[0] != Token::FixedBytes(swap_id.clone()) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid 'swap_id' {:?}, expected {:?}", - decoded_params[0], - Token::FixedBytes(swap_id) - ))); - } - let taker_address = - addr_from_raw_pubkey(args.taker_pub).map_to_mm(ValidatePaymentError::InternalError)?; - if decoded_params[1] != Token::Address(taker_address) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid `taker_address` {:?}, expected {:?}", - decoded_params[1], - Token::Address(taker_address) - ))); - } - if decoded_params[2] != Token::Address(token_address) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid `token_address` {:?}, expected {:?}", - decoded_params[2], - Token::Address(token_address) - ))); - } - if decoded_params[3] != Token::FixedBytes(args.taker_secret_hash.to_vec()) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid 'taker_secret_hash' {:?}, expected {:?}", - decoded_params[3], - Token::FixedBytes(args.taker_secret_hash.to_vec()) - ))); - } - if decoded_params[4] != Token::FixedBytes(args.maker_secret_hash.to_vec()) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid 'maker_secret_hash' {:?}, expected {:?}", - decoded_params[4], - Token::FixedBytes(args.maker_secret_hash.to_vec()) - ))); - } - if decoded_params[5] != Token::Uint(U256::from(args.time_lock)) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "Invalid 'time_lock' {:?}, expected {:?}", - decoded_params[5], - Token::Uint(U256::from(args.time_lock)) - ))); - } - } else { - return MmError::err(ValidatePaymentError::TxDeserializationError( - "Failed to decode HTLCParams from data_bytes".to_string(), - )); - } - } else { - return MmError::err(ValidatePaymentError::TxDeserializationError( - "Expected bytes for HTLCParams data".to_string(), - )); - } + + let taker_address = + addr_from_raw_pubkey(args.taker_pub).map_to_mm(ValidatePaymentError::InternalError)?; + let htlc_params = ExpectedHtlcParams { + swap_id, + taker_address, + token_address, + taker_secret_hash: args.taker_secret_hash.to_vec(), + maker_secret_hash: args.maker_secret_hash.to_vec(), + time_lock: U256::from(args.time_lock), + }; + decode_and_validate_htlc_params(decoded, 3, htlc_params)?; }, }, EthCoinType::Eth | EthCoinType::Erc20 { .. } => { @@ -6822,6 +6703,12 @@ impl EthCoin { } } +#[derive(Debug, Display)] +pub enum Erc721FunctionError { + AbiError(String), + FunctionNotFound(String), +} + #[derive(Debug, Display)] pub enum PaymentStatusErr { #[display(fmt = "Abi error: {}", _0)] @@ -6858,3 +6745,88 @@ impl StateType { /// function to check if BigDecimal is a positive integer #[inline(always)] fn is_positive_integer(amount: &BigDecimal) -> bool { amount == &amount.with_scale(0) && amount > &BigDecimal::from(0) } + +#[derive(Debug, Display)] +pub enum HtlcParamsError { + WrongPaymentTx(String), + TxDeserializationError(String), +} + +struct ExpectedHtlcParams { + swap_id: Vec, + taker_address: Address, + token_address: Address, + taker_secret_hash: Vec, + maker_secret_hash: Vec, + time_lock: U256, +} + +fn decode_and_validate_htlc_params( + decoded: Vec, + index: usize, + expected_params: ExpectedHtlcParams, +) -> MmResult<(), HtlcParamsError> { + if let Some(Token::Bytes(data_bytes)) = decoded.get(index) { + let htlc_params = &[ + ethabi::ParamType::FixedBytes(32), + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::FixedBytes(32), + ethabi::ParamType::FixedBytes(32), + ethabi::ParamType::Uint(256), + ]; + if let Ok(decoded_params) = ethabi::decode(htlc_params, data_bytes) { + if decoded_params[0] != Token::FixedBytes(expected_params.swap_id.clone()) { + return MmError::err(HtlcParamsError::WrongPaymentTx(format!( + "Invalid 'swap_id' {:?}, expected {:?}", + decoded_params[0], + Token::FixedBytes(expected_params.swap_id) + ))); + } + if decoded_params[1] != Token::Address(expected_params.taker_address) { + return MmError::err(HtlcParamsError::WrongPaymentTx(format!( + "Invalid `taker_address` {:?}, expected {:?}", + decoded_params[1], + Token::Address(expected_params.taker_address) + ))); + } + if decoded_params[2] != Token::Address(expected_params.token_address) { + return MmError::err(HtlcParamsError::WrongPaymentTx(format!( + "Invalid `token_address` {:?}, expected {:?}", + decoded_params[2], + Token::Address(expected_params.token_address) + ))); + } + if decoded_params[3] != Token::FixedBytes(expected_params.taker_secret_hash.clone()) { + return MmError::err(HtlcParamsError::WrongPaymentTx(format!( + "Invalid 'taker_secret_hash' {:?}, expected {:?}", + decoded_params[3], + Token::FixedBytes(expected_params.taker_secret_hash) + ))); + } + if decoded_params[4] != Token::FixedBytes(expected_params.maker_secret_hash.clone()) { + return MmError::err(HtlcParamsError::WrongPaymentTx(format!( + "Invalid 'maker_secret_hash' {:?}, expected {:?}", + decoded_params[4], + Token::FixedBytes(expected_params.maker_secret_hash) + ))); + } + if decoded_params[5] != Token::Uint(expected_params.time_lock) { + return MmError::err(HtlcParamsError::WrongPaymentTx(format!( + "Invalid 'time_lock' {:?}, expected {:?}", + decoded_params[5], + Token::Uint(expected_params.time_lock) + ))); + } + } else { + return MmError::err(HtlcParamsError::TxDeserializationError( + "Failed to decode HTLCParams from data_bytes".to_string(), + )); + } + } else { + return MmError::err(HtlcParamsError::TxDeserializationError( + "Expected bytes for HTLCParams data".to_string(), + )); + } + Ok(()) +} diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index cd03f9c8e4..b7a07c18b3 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -294,7 +294,7 @@ use script::Script; pub mod z_coin; use crate::coin_errors::ValidatePaymentResult; -use crate::eth::NftAssocTypesError; +use crate::eth::{Erc721FunctionError, NftAssocTypesError}; use crate::utxo::swap_proto_v2_scripts; use crate::utxo::utxo_common::{payment_script, WaitForOutputSpendErr}; use z_coin::{ZCoin, ZcoinProtocolInfo}; @@ -687,6 +687,15 @@ impl From for TransactionErr { fn from(e: ethabi::Error) -> Self { TransactionErr::AbiError(e.to_string()) } } +impl From for TransactionErr { + fn from(e: Erc721FunctionError) -> Self { + match e { + Erc721FunctionError::AbiError(e) => Self::AbiError(e), + Erc721FunctionError::FunctionNotFound(e) => Self::Plain(e), + } + } +} + #[derive(Debug, PartialEq)] pub enum FoundSwapTxSpend { Spent(TransactionEnum), diff --git a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs index f4720c2d78..0b9cd0270c 100644 --- a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs @@ -43,7 +43,7 @@ fn send_and_spend_erc721_maker_payment() { payment_tx: maker_payment.tx_hex(), confirmations: 1, requires_nota: false, - wait_until: now_sec() + 200, + wait_until: now_sec() + 60, check_every: 1, }; maker_global_nft.wait_for_confirmations(confirm_input).wait().unwrap(); @@ -67,6 +67,7 @@ fn send_and_spend_erc721_maker_payment() { } #[test] +#[ignore] fn send_and_spend_erc1155_maker_payment() { let erc1155_nft = TestNftType::Erc1155 { token_id: 4, amount: 3 }; From e849c434b7b573f4abfbb1f66c10093ea66eb5e9 Mon Sep 17 00:00:00 2001 From: laruh Date: Fri, 22 Mar 2024 16:43:39 +0700 Subject: [PATCH 47/80] move tests to eth_docker_tests.rs --- .../tests/docker_tests/eth_docker_tests.rs | 118 ++++++++++++++++- mm2src/mm2_main/tests/docker_tests/mod.rs | 1 - .../docker_tests/nft_swap_proto_v2_tests.rs | 122 ------------------ 3 files changed, 116 insertions(+), 125 deletions(-) delete mode 100644 mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index 2c970394ad..2814c4b8e4 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -5,8 +5,10 @@ use super::docker_tests_common::{random_secp256k1_secret, ERC1155_TEST_ABI, ERC7 use bitcrypto::dhash160; use coins::eth::{checksum_address, eth_addr_to_hex, eth_coin_from_conf_and_request, EthCoin, ERC20_ABI}; use coins::nft::nft_structs::{Chain, ContractType, NftInfo}; -use coins::{CoinProtocol, ConfirmPaymentInput, FoundSwapTxSpend, MarketCoinOps, PrivKeyBuildPolicy, RefundPaymentArgs, - SearchForSwapTxSpendInput, SendPaymentArgs, SpendPaymentArgs, SwapOps, SwapTxTypeWithSecretHash}; +use coins::{CoinAssocTypes, CoinProtocol, ConfirmPaymentInput, FoundSwapTxSpend, MakerNftSwapOpsV2, MarketCoinOps, + PrivKeyBuildPolicy, RefundPaymentArgs, SearchForSwapTxSpendInput, SendNftMakerPaymentArgs, + SendPaymentArgs, SpendPaymentArgs, SwapOps, SwapTxTypeWithSecretHash, ToBytes, Transaction, + ValidateNftMakerPaymentArgs}; use common::{block_on, now_sec}; use ethereum_types::U256; use futures01::Future; @@ -609,3 +611,115 @@ fn send_and_spend_erc20_maker_payment() { let expected = FoundSwapTxSpend::Spent(payment_spend); assert_eq!(expected, search_tx); } + +#[test] +fn send_and_spend_erc721_maker_payment() { + // in prod we will need to enable global NFT for taker or add new field (for nft swap address) in EthCoin, + // as EtomicSwapNft will have its own contract address, due to EIP-170 contract size limitations. + // TODO need to add NFT conf in coin conf and refactor enable nft a bit + + let erc721_nft = TestNftType::Erc721 { token_id: 2 }; + + let maker_global_nft = global_nft_with_random_privkey(nft_swap_contract(), Some(erc721_nft)); + let taker_global_nft = global_nft_with_random_privkey(nft_swap_contract(), None); + + let time_lock = now_sec() + 1000; + let maker_pubkey = maker_global_nft.derive_htlc_pubkey(&[]); + let taker_pubkey = taker_global_nft.derive_htlc_pubkey(&[]); + + let send_payment_args: SendNftMakerPaymentArgs = SendNftMakerPaymentArgs { + time_lock, + taker_secret_hash: &[0; 32], + maker_secret_hash: &[0; 32], + amount: 1.into(), + taker_pub: &taker_global_nft.parse_pubkey(&taker_pubkey).unwrap(), + swap_unique_data: &[], + token_address: &erc721_contract().to_bytes(), + token_id: &BigUint::from(2u32).to_bytes(), + chain: &Chain::Eth.to_bytes(), + contract_type: &ContractType::Erc721.to_bytes(), + swap_contract_address: &nft_swap_contract().to_bytes(), + }; + let maker_payment = block_on(maker_global_nft.send_nft_maker_payment_v2(send_payment_args)).unwrap(); + println!("Maker sent ERC721 NFT Payment tx hash {:02x}", maker_payment.tx_hash()); + + let confirm_input = ConfirmPaymentInput { + payment_tx: maker_payment.tx_hex(), + confirmations: 1, + requires_nota: false, + wait_until: now_sec() + 70, + check_every: 1, + }; + maker_global_nft.wait_for_confirmations(confirm_input).wait().unwrap(); + + let validate_args = ValidateNftMakerPaymentArgs { + maker_payment_tx: &maker_payment, + time_lock, + taker_secret_hash: &[0; 32], + maker_secret_hash: &[0; 32], + amount: 1.into(), + taker_pub: &taker_global_nft.parse_pubkey(&taker_pubkey).unwrap(), + maker_pub: &maker_global_nft.parse_pubkey(&maker_pubkey).unwrap(), + swap_unique_data: &[], + token_address: &erc721_contract().to_bytes(), + token_id: &BigUint::from(2u32).to_bytes(), + chain: &Chain::Eth.to_bytes(), + contract_type: &ContractType::Erc721.to_bytes(), + swap_contract_address: &nft_swap_contract().to_bytes(), + }; + block_on(maker_global_nft.validate_nft_maker_payment_v2(validate_args)).unwrap(); +} + +#[test] +fn send_and_spend_erc1155_maker_payment() { + let erc1155_nft = TestNftType::Erc1155 { token_id: 4, amount: 3 }; + + let maker_global_nft = global_nft_with_random_privkey(nft_swap_contract(), Some(erc1155_nft)); + let taker_global_nft = global_nft_with_random_privkey(nft_swap_contract(), None); + + let time_lock = now_sec() + 1000; + let maker_pubkey = maker_global_nft.derive_htlc_pubkey(&[]); + let taker_pubkey = taker_global_nft.derive_htlc_pubkey(&[]); + + let send_payment_args: SendNftMakerPaymentArgs = SendNftMakerPaymentArgs { + time_lock, + taker_secret_hash: &[0; 32], + maker_secret_hash: &[0; 32], + amount: 3.into(), + taker_pub: &taker_global_nft.parse_pubkey(&taker_pubkey).unwrap(), + swap_unique_data: &[], + token_address: &erc1155_contract().to_bytes(), + token_id: &BigUint::from(4u32).to_bytes(), + chain: &Chain::Eth.to_bytes(), + contract_type: &ContractType::Erc1155.to_bytes(), + swap_contract_address: &nft_swap_contract().to_bytes(), + }; + let maker_payment = block_on(maker_global_nft.send_nft_maker_payment_v2(send_payment_args)).unwrap(); + println!("Maker sent ERC1155 NFT Payment tx hash {:02x}", maker_payment.tx_hash()); + + let confirm_input = ConfirmPaymentInput { + payment_tx: maker_payment.tx_hex(), + confirmations: 1, + requires_nota: false, + wait_until: now_sec() + 60, + check_every: 1, + }; + maker_global_nft.wait_for_confirmations(confirm_input).wait().unwrap(); + + let validate_args = ValidateNftMakerPaymentArgs { + maker_payment_tx: &maker_payment, + time_lock, + taker_secret_hash: &[0; 32], + maker_secret_hash: &[0; 32], + amount: 3.into(), + taker_pub: &taker_global_nft.parse_pubkey(&taker_pubkey).unwrap(), + maker_pub: &maker_global_nft.parse_pubkey(&maker_pubkey).unwrap(), + swap_unique_data: &[], + token_address: &erc1155_contract().to_bytes(), + token_id: &BigUint::from(4u32).to_bytes(), + chain: &Chain::Eth.to_bytes(), + contract_type: &ContractType::Erc1155.to_bytes(), + swap_contract_address: &nft_swap_contract().to_bytes(), + }; + block_on(maker_global_nft.validate_nft_maker_payment_v2(validate_args)).unwrap(); +} diff --git a/mm2src/mm2_main/tests/docker_tests/mod.rs b/mm2src/mm2_main/tests/docker_tests/mod.rs index a401678a81..848e43c1eb 100644 --- a/mm2src/mm2_main/tests/docker_tests/mod.rs +++ b/mm2src/mm2_main/tests/docker_tests/mod.rs @@ -3,7 +3,6 @@ pub mod docker_tests_common; mod docker_ordermatch_tests; mod docker_tests_inner; mod eth_docker_tests; -mod nft_swap_proto_v2_tests; pub mod qrc20_tests; mod slp_tests; #[cfg(feature = "enable-solana")] mod solana_tests; diff --git a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs deleted file mode 100644 index 0b9cd0270c..0000000000 --- a/mm2src/mm2_main/tests/docker_tests/nft_swap_proto_v2_tests.rs +++ /dev/null @@ -1,122 +0,0 @@ -use super::eth_docker_tests::{erc1155_contract, erc721_contract, global_nft_with_random_privkey, nft_swap_contract, - TestNftType}; -use coins::eth::EthCoin; -use coins::nft::nft_structs::{Chain, ContractType}; -use coins::{CoinAssocTypes, ConfirmPaymentInput, MakerNftSwapOpsV2, MarketCoinOps, SendNftMakerPaymentArgs, SwapOps, - ToBytes, Transaction, ValidateNftMakerPaymentArgs}; -use common::{block_on, now_sec}; -use futures01::Future; -use mm2_number::BigUint; - -#[test] -fn send_and_spend_erc721_maker_payment() { - // in prod we will need to enable global NFT for taker or add new field (for nft swap address) in EthCoin, - // as EtomicSwapNft will have its own contract address, due to EIP-170 contract size limitations. - // TODO need to add NFT conf in coin conf and refactor enable nft a bit - - let erc721_nft = TestNftType::Erc721 { token_id: 2 }; - - let maker_global_nft = global_nft_with_random_privkey(nft_swap_contract(), Some(erc721_nft)); - let taker_global_nft = global_nft_with_random_privkey(nft_swap_contract(), None); - - let time_lock = now_sec() + 1000; - let maker_pubkey = maker_global_nft.derive_htlc_pubkey(&[]); - let taker_pubkey = taker_global_nft.derive_htlc_pubkey(&[]); - - let send_payment_args: SendNftMakerPaymentArgs = SendNftMakerPaymentArgs { - time_lock, - taker_secret_hash: &[0; 32], - maker_secret_hash: &[0; 32], - amount: 1.into(), - taker_pub: &taker_global_nft.parse_pubkey(&taker_pubkey).unwrap(), - swap_unique_data: &[], - token_address: &erc721_contract().to_bytes(), - token_id: &BigUint::from(2u32).to_bytes(), - chain: &Chain::Eth.to_bytes(), - contract_type: &ContractType::Erc721.to_bytes(), - swap_contract_address: &nft_swap_contract().to_bytes(), - }; - let maker_payment = block_on(maker_global_nft.send_nft_maker_payment_v2(send_payment_args)).unwrap(); - println!("Maker sent ERC721 NFT Payment tx hash {:02x}", maker_payment.tx_hash()); - - let confirm_input = ConfirmPaymentInput { - payment_tx: maker_payment.tx_hex(), - confirmations: 1, - requires_nota: false, - wait_until: now_sec() + 60, - check_every: 1, - }; - maker_global_nft.wait_for_confirmations(confirm_input).wait().unwrap(); - - let validate_args = ValidateNftMakerPaymentArgs { - maker_payment_tx: &maker_payment, - time_lock, - taker_secret_hash: &[0; 32], - maker_secret_hash: &[0; 32], - amount: 1.into(), - taker_pub: &taker_global_nft.parse_pubkey(&taker_pubkey).unwrap(), - maker_pub: &maker_global_nft.parse_pubkey(&maker_pubkey).unwrap(), - swap_unique_data: &[], - token_address: &erc721_contract().to_bytes(), - token_id: &BigUint::from(2u32).to_bytes(), - chain: &Chain::Eth.to_bytes(), - contract_type: &ContractType::Erc721.to_bytes(), - swap_contract_address: &nft_swap_contract().to_bytes(), - }; - block_on(maker_global_nft.validate_nft_maker_payment_v2(validate_args)).unwrap(); -} - -#[test] -#[ignore] -fn send_and_spend_erc1155_maker_payment() { - let erc1155_nft = TestNftType::Erc1155 { token_id: 4, amount: 3 }; - - let maker_global_nft = global_nft_with_random_privkey(nft_swap_contract(), Some(erc1155_nft)); - let taker_global_nft = global_nft_with_random_privkey(nft_swap_contract(), None); - - let time_lock = now_sec() + 1000; - let maker_pubkey = maker_global_nft.derive_htlc_pubkey(&[]); - let taker_pubkey = taker_global_nft.derive_htlc_pubkey(&[]); - - let send_payment_args: SendNftMakerPaymentArgs = SendNftMakerPaymentArgs { - time_lock, - taker_secret_hash: &[0; 32], - maker_secret_hash: &[0; 32], - amount: 3.into(), - taker_pub: &taker_global_nft.parse_pubkey(&taker_pubkey).unwrap(), - swap_unique_data: &[], - token_address: &erc1155_contract().to_bytes(), - token_id: &BigUint::from(4u32).to_bytes(), - chain: &Chain::Eth.to_bytes(), - contract_type: &ContractType::Erc1155.to_bytes(), - swap_contract_address: &nft_swap_contract().to_bytes(), - }; - let maker_payment = block_on(maker_global_nft.send_nft_maker_payment_v2(send_payment_args)).unwrap(); - println!("Maker sent ERC1155 NFT Payment tx hash {:02x}", maker_payment.tx_hash()); - - let confirm_input = ConfirmPaymentInput { - payment_tx: maker_payment.tx_hex(), - confirmations: 1, - requires_nota: false, - wait_until: now_sec() + 60, - check_every: 1, - }; - maker_global_nft.wait_for_confirmations(confirm_input).wait().unwrap(); - - let validate_args = ValidateNftMakerPaymentArgs { - maker_payment_tx: &maker_payment, - time_lock, - taker_secret_hash: &[0; 32], - maker_secret_hash: &[0; 32], - amount: 3.into(), - taker_pub: &taker_global_nft.parse_pubkey(&taker_pubkey).unwrap(), - maker_pub: &maker_global_nft.parse_pubkey(&maker_pubkey).unwrap(), - swap_unique_data: &[], - token_address: &erc1155_contract().to_bytes(), - token_id: &BigUint::from(4u32).to_bytes(), - chain: &Chain::Eth.to_bytes(), - contract_type: &ContractType::Erc1155.to_bytes(), - swap_contract_address: &nft_swap_contract().to_bytes(), - }; - block_on(maker_global_nft.validate_nft_maker_payment_v2(validate_args)).unwrap(); -} From 510df902b0243c85a0115a3e82e2828e482164cf Mon Sep 17 00:00:00 2001 From: laruh Date: Sun, 24 Mar 2024 10:31:20 +0700 Subject: [PATCH 48/80] remove unused chain field from nft payment structures --- mm2src/coins/eth.rs | 34 +++++++------------ mm2src/coins/lp_coins.rs | 33 ++++++++++++------ .../tests/docker_tests/eth_docker_tests.rs | 4 --- 3 files changed, 36 insertions(+), 35 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 6f37aa2682..53d677e47b 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -24,10 +24,10 @@ use super::eth::Action::{Call, Create}; use crate::eth::eth_rpc::ETH_RPC_REQUEST_TIMEOUT; use crate::eth::web3_transport::websocket_transport::{WebsocketTransport, WebsocketTransportNode}; use crate::lp_price::get_base_price_in_rel; -use crate::nft::nft_structs::{Chain, ContractType, ConvertChain, NftInfo, TransactionNftDetails, WithdrawErc1155, +use crate::nft::nft_structs::{ContractType, ConvertChain, NftInfo, TransactionNftDetails, WithdrawErc1155, WithdrawErc721}; use crate::{CoinAssocTypes, DexFee, MakerNftSwapOpsV2, NftAssocTypes, RefundMakerPaymentArgs, RpcCommonOps, - SendNftMakerPaymentArgs, SpendMakerPaymentArgs, ToBytes, ValidateNftMakerPaymentArgs, + SendNftMakerPaymentArgs, SpendNftMakerPaymentArgs, ToBytes, ValidateNftMakerPaymentArgs, ValidateWatcherSpendInput, WatcherSpendType}; use async_trait::async_trait; use bitcrypto::{dhash160, keccak256, ripemd160, sha256}; @@ -126,7 +126,7 @@ use v2_activation::{build_address_and_priv_key_policy, EthActivationV2Error}; mod nonce; use crate::coin_errors::ValidatePaymentResult; -use crate::nft::nft_errors::{GetNftInfoError, ParseChainTypeError, ParseContractTypeError}; +use crate::nft::nft_errors::{GetNftInfoError, ParseContractTypeError}; use crate::{PrivKeyPolicy, TransactionResult, WithdrawFrom}; use nonce::ParityNonce; @@ -6240,15 +6240,10 @@ impl From for CoinAssocTypesError { #[derive(Debug, Display)] pub enum NftAssocTypesError { Utf8Error(String), - ParseChainError(ParseChainTypeError), ParseContractTypeError(ParseContractTypeError), ParseTokenContractError(String), } -impl From for NftAssocTypesError { - fn from(e: ParseChainTypeError) -> Self { NftAssocTypesError::ParseChainError(e) } -} - impl From for NftAssocTypesError { fn from(e: ParseContractTypeError) -> Self { NftAssocTypesError::ParseContractTypeError(e) } } @@ -6303,10 +6298,6 @@ impl ToBytes for BigUint { fn to_bytes(&self) -> Vec { self.to_bytes_be() } } -impl ToBytes for Chain { - fn to_bytes(&self) -> Vec { self.to_ticker().as_bytes().to_vec() } -} - impl ToBytes for ContractType { fn to_bytes(&self) -> Vec { self.to_string().into_bytes() } } @@ -6316,8 +6307,6 @@ impl NftAssocTypes for EthCoin { type TokenContractAddrParseError = NftAssocTypesError; type TokenId = BigUint; type TokenIdParseError = NftAssocTypesError; - type Chain = Chain; - type ChainParseError = NftAssocTypesError; type ContractType = ContractType; type ContractTypeParseError = NftAssocTypesError; @@ -6334,11 +6323,6 @@ impl NftAssocTypes for EthCoin { Ok(BigUint::from_bytes_be(token_id)) } - fn parse_chain(&self, chain: &[u8]) -> Result { - let chain_str = from_utf8(chain).map_err(|e| NftAssocTypesError::Utf8Error(e.to_string()))?; - Chain::from_ticker(chain_str).map_err(NftAssocTypesError::from) - } - fn parse_contract_type(&self, contract_type: &[u8]) -> Result { let contract_str = from_utf8(contract_type).map_err(|e| NftAssocTypesError::Utf8Error(e.to_string()))?; ContractType::from_str(contract_str).map_err(NftAssocTypesError::from) @@ -6363,9 +6347,9 @@ impl MakerNftSwapOpsV2 for EthCoin { async fn spend_nft_maker_payment_v2( &self, - _args: SpendMakerPaymentArgs<'_, Self>, + args: SpendNftMakerPaymentArgs<'_, Self>, ) -> Result { - todo!() + self.spend_nft_maker_payment_v2_impl(args).await } async fn refund_nft_maker_payment_v2_timelock( @@ -6701,6 +6685,14 @@ impl EthCoin { ))), } } + + async fn spend_nft_maker_payment_v2_impl( + &self, + args: SpendNftMakerPaymentArgs<'_, Self>, + ) -> Result { + let _contract_type = self.parse_contract_type(args.contract_type)?; + todo!() + } } #[derive(Debug, Display)] diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index b7a07c18b3..a747f02ed4 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -1515,14 +1515,12 @@ pub trait CoinAssocTypes { fn parse_signature(&self, sig: &[u8]) -> Result; } -/// Defines associated types specific to each coin (Pubkey, Address, etc.) +/// Defines associated types specific to Non-Fungible Tokens (Token Address, Token Id, etc.) pub trait NftAssocTypes { type TokenContractAddr: Send + Sync + fmt::Display; type TokenContractAddrParseError: fmt::Debug + Send + fmt::Display; type TokenId: ToBytes + Send + Sync; type TokenIdParseError: fmt::Debug + Send + fmt::Display; - type Chain: ToBytes + Send + Sync; - type ChainParseError: fmt::Debug + Send + fmt::Display; type ContractType: ToBytes + Send + Sync; type ContractTypeParseError: fmt::Debug + Send + fmt::Display; @@ -1533,8 +1531,6 @@ pub trait NftAssocTypes { fn parse_token_id(&self, token_id: &[u8]) -> Result; - fn parse_chain(&self, chain: &[u8]) -> Result; - fn parse_contract_type(&self, contract_type: &[u8]) -> Result; } @@ -1570,8 +1566,6 @@ pub struct SendNftMakerPaymentArgs<'a, Coin: CoinAssocTypes + NftAssocTypes + ?S pub token_address: &'a [u8], /// The ID of the NFT token. pub token_id: &'a [u8], - /// The blockchain where the NFT exists - pub chain: &'a [u8], /// The type of smart contract that governs this NFT pub contract_type: &'a [u8], // Etomic swap contract address @@ -1616,8 +1610,6 @@ pub struct ValidateNftMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { pub token_address: &'a [u8], /// The ID of the NFT token. pub token_id: &'a [u8], - /// The blockchain where the NFT exists - pub chain: &'a [u8], /// The type of smart contract that governs this NFT pub contract_type: &'a [u8], // Etomic swap contract address @@ -1658,6 +1650,27 @@ pub struct SpendMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { pub swap_unique_data: &'a [u8], } +pub struct SpendNftMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { + /// Maker payment tx + pub maker_payment_tx: &'a Coin::Tx, + /// Maker will be able to refund the payment after this timestamp + pub time_lock: u64, + /// The hash of the secret generated by taker, this is used for immediate refund + pub taker_secret_hash: &'a [u8], + /// The hash of the secret generated by maker, taker needs it to spend the payment + pub maker_secret_hash: &'a [u8], + /// The secret generated by maker, revealed when maker spends taker's payment + pub maker_secret: &'a [u8], + /// Maker's HTLC pubkey + pub maker_pub: &'a Coin::Pubkey, + /// Unique data of specific swap + pub swap_unique_data: &'a [u8], + /// The type of smart contract that governs this NFT + pub contract_type: &'a [u8], + // Etomic swap contract address + pub swap_contract_address: &'a [u8], +} + /// Operations specific to maker coin in [Trading Protocol Upgrade implementation](https://github.com/KomodoPlatform/komodo-defi-framework/issues/1895) #[async_trait] pub trait MakerCoinSwapOpsV2: CoinAssocTypes + Send + Sync + 'static { @@ -1696,7 +1709,7 @@ pub trait MakerNftSwapOpsV2: CoinAssocTypes + NftAssocTypes + Send + Sync + 'sta /// Spend NFT maker payment transaction async fn spend_nft_maker_payment_v2( &self, - args: SpendMakerPaymentArgs<'_, Self>, + args: SpendNftMakerPaymentArgs<'_, Self>, ) -> Result; /// Refund NFT maker payment transaction using timelock path diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index 2814c4b8e4..6013e5a2c0 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -636,7 +636,6 @@ fn send_and_spend_erc721_maker_payment() { swap_unique_data: &[], token_address: &erc721_contract().to_bytes(), token_id: &BigUint::from(2u32).to_bytes(), - chain: &Chain::Eth.to_bytes(), contract_type: &ContractType::Erc721.to_bytes(), swap_contract_address: &nft_swap_contract().to_bytes(), }; @@ -663,7 +662,6 @@ fn send_and_spend_erc721_maker_payment() { swap_unique_data: &[], token_address: &erc721_contract().to_bytes(), token_id: &BigUint::from(2u32).to_bytes(), - chain: &Chain::Eth.to_bytes(), contract_type: &ContractType::Erc721.to_bytes(), swap_contract_address: &nft_swap_contract().to_bytes(), }; @@ -690,7 +688,6 @@ fn send_and_spend_erc1155_maker_payment() { swap_unique_data: &[], token_address: &erc1155_contract().to_bytes(), token_id: &BigUint::from(4u32).to_bytes(), - chain: &Chain::Eth.to_bytes(), contract_type: &ContractType::Erc1155.to_bytes(), swap_contract_address: &nft_swap_contract().to_bytes(), }; @@ -717,7 +714,6 @@ fn send_and_spend_erc1155_maker_payment() { swap_unique_data: &[], token_address: &erc1155_contract().to_bytes(), token_id: &BigUint::from(4u32).to_bytes(), - chain: &Chain::Eth.to_bytes(), contract_type: &ContractType::Erc1155.to_bytes(), swap_contract_address: &nft_swap_contract().to_bytes(), }; From 02a004d12a6cb8e57d1e322651147b482237b021 Mon Sep 17 00:00:00 2001 From: laruh Date: Sun, 24 Mar 2024 13:47:38 +0700 Subject: [PATCH 49/80] spend_nft_maker_payment_v2_impl WIP --- mm2src/coins/coin_errors.rs | 4 +- mm2src/coins/eth.rs | 153 +++++++++++++++++++++++++++++------- mm2src/coins/lp_coins.rs | 11 +-- mm2src/coins/utxo/slp.rs | 3 +- 4 files changed, 131 insertions(+), 40 deletions(-) diff --git a/mm2src/coins/coin_errors.rs b/mm2src/coins/coin_errors.rs index 5aef20ab83..262c2acdb2 100644 --- a/mm2src/coins/coin_errors.rs +++ b/mm2src/coins/coin_errors.rs @@ -103,7 +103,9 @@ impl From for ValidatePaymentError { fn from(err: PaymentStatusErr) -> Self { match err { PaymentStatusErr::Transport(e) => Self::Transport(e), - PaymentStatusErr::AbiError(e) | PaymentStatusErr::Internal(e) => Self::InternalError(e), + PaymentStatusErr::AbiError(e) + | PaymentStatusErr::Internal(e) + | PaymentStatusErr::TxDeserializationError(e) => Self::InternalError(e), } } } diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 53d677e47b..c8a3b814a2 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -4009,7 +4009,7 @@ impl EthCoin { }, EthCoinType::Nft { .. } => { return Box::new(futures01::future::err(TransactionErr::ProtocolNotSupported(ERRL!( - "Nft Protocol is not supported yet!" + "Nft Protocol is not supported!" )))) }, } @@ -6379,7 +6379,7 @@ impl EthCoin { &args.amount, &contract_type, ) - .map_err(TransactionErr::Plain)?; + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; let taker_address = addr_from_raw_pubkey(args.taker_pub).map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; let token_address = self.parse_token_contract_address(args.token_address)?; @@ -6396,16 +6396,18 @@ impl EthCoin { ContractType::Erc1155 => { let function = ERC1155_CONTRACT .function("safeTransferFrom") - .map_err(|e| TransactionErr::AbiError(ERRL!("{}", e)))?; + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; let amount_u256 = U256::from_dec_str(&args.amount.to_string()) .map_err(|e| NumConversError::new(ERRL!("{}", e)))?; - let data = function.encode_input(&[ - Token::Address(self.my_address), - Token::Address(swap_contract_address), - Token::Uint(token_id_u256), - Token::Uint(amount_u256), - Token::Bytes(htlc_data), - ])?; + let data = function + .encode_input(&[ + Token::Address(self.my_address), + Token::Address(swap_contract_address), + Token::Uint(token_id_u256), + Token::Uint(amount_u256), + Token::Bytes(htlc_data), + ]) + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; let gas = U256::from(ETH_GAS); self.sign_and_send_transaction(0.into(), Action::Call(token_address), data, gas) .compat() @@ -6413,12 +6415,14 @@ impl EthCoin { }, ContractType::Erc721 => { let function = self.erc721_transfer_with_data()?; - let data = function.encode_input(&[ - Token::Address(self.my_address), - Token::Address(swap_contract_address), - Token::Uint(token_id_u256), - Token::Bytes(htlc_data), - ])?; + let data = function + .encode_input(&[ + Token::Address(self.my_address), + Token::Address(swap_contract_address), + Token::Uint(token_id_u256), + Token::Bytes(htlc_data), + ]) + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; let gas = U256::from(ETH_GAS); self.sign_and_send_transaction(0.into(), Action::Call(token_address), data, gas) .compat() @@ -6690,11 +6694,110 @@ impl EthCoin { &self, args: SpendNftMakerPaymentArgs<'_, Self>, ) -> Result { - let _contract_type = self.parse_contract_type(args.contract_type)?; - todo!() + let contract_type = self.parse_contract_type(args.contract_type)?; + let etomic_swap_contract = self.parse_token_contract_address(args.swap_contract_address)?; + if args.maker_secret.len() != 32 { + return Err(TransactionErr::Plain(ERRL!("maker_secret must be 32 bytes"))); + } + match self.coin_type { + EthCoinType::Nft { .. } => match contract_type { + ContractType::Erc1155 => { + let _spend_func = NFT_SWAP_CONTRACT + .function("spendErc1155MakerPayment") + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + let send_func = ERC1155_CONTRACT + .function("safeTransferFrom") + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + let decoded = decode_contract_call(send_func, &args.maker_payment_tx.data) + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + let state = self + .status_from_htlc_params( + etomic_swap_contract, + &ERC1155_CONTRACT, + decoded, + 4, + StateType::MakerPayments, + ) + .await + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + if state != U256::from(MakerPaymentState::PaymentSent as u8) { + return Err(TransactionErr::Plain(ERRL!( + "Payment {:?} state is not PAYMENT_STATE_SENT, got {}", + args.maker_payment_tx, + state + ))); + } + todo!() + }, + ContractType::Erc721 => { + let _spend_func = NFT_SWAP_CONTRACT + .function("spendErc721MakerPayment") + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + let send_func = self.erc721_transfer_with_data()?; + let decoded = decode_contract_call(send_func, &args.maker_payment_tx.data) + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + let state = self + .status_from_htlc_params( + etomic_swap_contract, + &ERC721_CONTRACT, + decoded, + 3, + StateType::MakerPayments, + ) + .await + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + if state != U256::from(MakerPaymentState::PaymentSent as u8) { + return Err(TransactionErr::Plain(ERRL!( + "Payment {:?} state is not PAYMENT_STATE_SENT, got {}", + args.maker_payment_tx, + state + ))); + } + todo!() + }, + }, + EthCoinType::Eth | EthCoinType::Erc20 { .. } => Err(TransactionErr::ProtocolNotSupported( + "ETH and ERC20 Protocols are not supported for NFT Swaps".to_string(), + )), + } + } + + async fn status_from_htlc_params( + &self, + swap_contract_addr: Address, + contract: &Contract, + decoded: Vec, + index: usize, + state_type: StateType, + ) -> Result { + if let Some(Token::Bytes(data_bytes)) = decoded.get(index) { + if let Ok(decoded_params) = ethabi::decode(htlc_params(), data_bytes) { + self.payment_status_v2(swap_contract_addr, decoded_params[0].clone(), contract, state_type) + .await + } else { + Err(PaymentStatusErr::TxDeserializationError(ERRL!( + "Failed to decode HTLCParams from data_bytes" + ))) + } + } else { + Err(PaymentStatusErr::TxDeserializationError(ERRL!( + "Failed to decode HTLCParams from data_bytes" + ))) + } } } +fn htlc_params() -> &'static [ethabi::ParamType] { + &[ + ethabi::ParamType::FixedBytes(32), + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::FixedBytes(32), + ethabi::ParamType::FixedBytes(32), + ethabi::ParamType::Uint(256), + ] +} + #[derive(Debug, Display)] pub enum Erc721FunctionError { AbiError(String), @@ -6709,6 +6812,8 @@ pub enum PaymentStatusErr { Transport(String), #[display(fmt = "Internal error: {}", _0)] Internal(String), + #[display(fmt = "Tx deserialization error: {}", _0)] + TxDeserializationError(String), } impl From for PaymentStatusErr { @@ -6759,15 +6864,7 @@ fn decode_and_validate_htlc_params( expected_params: ExpectedHtlcParams, ) -> MmResult<(), HtlcParamsError> { if let Some(Token::Bytes(data_bytes)) = decoded.get(index) { - let htlc_params = &[ - ethabi::ParamType::FixedBytes(32), - ethabi::ParamType::Address, - ethabi::ParamType::Address, - ethabi::ParamType::FixedBytes(32), - ethabi::ParamType::FixedBytes(32), - ethabi::ParamType::Uint(256), - ]; - if let Ok(decoded_params) = ethabi::decode(htlc_params, data_bytes) { + if let Ok(decoded_params) = ethabi::decode(htlc_params(), data_bytes) { if decoded_params[0] != Token::FixedBytes(expected_params.swap_id.clone()) { return MmError::err(HtlcParamsError::WrongPaymentTx(format!( "Invalid 'swap_id' {:?}, expected {:?}", @@ -6817,7 +6914,7 @@ fn decode_and_validate_htlc_params( } } else { return MmError::err(HtlcParamsError::TxDeserializationError( - "Expected bytes for HTLCParams data".to_string(), + "Expected Bytes for HTLCParams data".to_string(), )); } Ok(()) diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index a747f02ed4..9d298884c5 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -644,7 +644,6 @@ pub enum TransactionErr { ProtocolNotSupported(String), NftAssocTypesError(String), NumConversError(NumConversError), - AbiError(String), } impl TransactionErr { @@ -664,8 +663,7 @@ impl TransactionErr { TransactionErr::TxRecoverable(_, err) => err.to_string(), TransactionErr::Plain(err) | TransactionErr::ProtocolNotSupported(err) - | TransactionErr::NftAssocTypesError(err) - | TransactionErr::AbiError(err) => err.to_string(), + | TransactionErr::NftAssocTypesError(err) => err.to_string(), TransactionErr::NumConversError(err) => err.to_string(), } } @@ -683,15 +681,10 @@ impl From for TransactionErr { fn from(e: NumConversError) -> Self { TransactionErr::NumConversError(e) } } -impl From for TransactionErr { - fn from(e: ethabi::Error) -> Self { TransactionErr::AbiError(e.to_string()) } -} - impl From for TransactionErr { fn from(e: Erc721FunctionError) -> Self { match e { - Erc721FunctionError::AbiError(e) => Self::AbiError(e), - Erc721FunctionError::FunctionNotFound(e) => Self::Plain(e), + Erc721FunctionError::AbiError(e) | Erc721FunctionError::FunctionNotFound(e) => Self::Plain(e), } } } diff --git a/mm2src/coins/utxo/slp.rs b/mm2src/coins/utxo/slp.rs index f242fd53dd..f1fc1e3bc5 100644 --- a/mm2src/coins/utxo/slp.rs +++ b/mm2src/coins/utxo/slp.rs @@ -2173,8 +2173,7 @@ mod slp_tests { TransactionErr::TxRecoverable(_tx, err) => err, TransactionErr::Plain(err) | TransactionErr::ProtocolNotSupported(err) - | TransactionErr::NftAssocTypesError(err) - | TransactionErr::AbiError(err) => err, + | TransactionErr::NftAssocTypesError(err) => err, TransactionErr::NumConversError(err) => err.to_string(), }; From 6f9da2c0d1b8302f542ba874dc3e4a4064bfd256 Mon Sep 17 00:00:00 2001 From: laruh Date: Sun, 24 Mar 2024 15:26:05 +0700 Subject: [PATCH 50/80] spend_nft_maker_payment_v2_impl finish --- mm2src/coins/eth.rs | 75 +++++++++++++++++++++++++++++++++------------ 1 file changed, 55 insertions(+), 20 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index c8a3b814a2..5f61c85f3e 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -6408,8 +6408,7 @@ impl EthCoin { Token::Bytes(htlc_data), ]) .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; - let gas = U256::from(ETH_GAS); - self.sign_and_send_transaction(0.into(), Action::Call(token_address), data, gas) + self.sign_and_send_transaction(0.into(), Action::Call(token_address), data, U256::from(ETH_GAS)) .compat() .await }, @@ -6423,8 +6422,7 @@ impl EthCoin { Token::Bytes(htlc_data), ]) .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; - let gas = U256::from(ETH_GAS); - self.sign_and_send_transaction(0.into(), Action::Call(token_address), data, gas) + self.sign_and_send_transaction(0.into(), Action::Call(token_address), data, U256::from(ETH_GAS)) .compat() .await }, @@ -6702,7 +6700,7 @@ impl EthCoin { match self.coin_type { EthCoinType::Nft { .. } => match contract_type { ContractType::Erc1155 => { - let _spend_func = NFT_SWAP_CONTRACT + let spend_func = NFT_SWAP_CONTRACT .function("spendErc1155MakerPayment") .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; let send_func = ERC1155_CONTRACT @@ -6710,11 +6708,11 @@ impl EthCoin { .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; let decoded = decode_contract_call(send_func, &args.maker_payment_tx.data) .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; - let state = self - .status_from_htlc_params( + let (state, htlc_params) = self + .status_and_htlc_params_from_tx_data( etomic_swap_contract, &ERC1155_CONTRACT, - decoded, + &decoded, 4, StateType::MakerPayments, ) @@ -6727,20 +6725,38 @@ impl EthCoin { state ))); } - todo!() + let data = spend_func + .encode_input(&[ + htlc_params[0].clone(), // swap_id + decoded[3].clone(), // amount + Token::Address(args.maker_payment_tx.sender()), + Token::FixedBytes(args.taker_secret_hash.to_vec()), + Token::FixedBytes(args.maker_secret.to_vec()), + htlc_params[2].clone(), // tokenAddress + decoded[2].clone(), // tokenId + ]) + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + self.sign_and_send_transaction( + 0.into(), + Action::Call(etomic_swap_contract), + data, + U256::from(ETH_GAS), + ) + .compat() + .await }, ContractType::Erc721 => { - let _spend_func = NFT_SWAP_CONTRACT + let spend_func = NFT_SWAP_CONTRACT .function("spendErc721MakerPayment") .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; let send_func = self.erc721_transfer_with_data()?; let decoded = decode_contract_call(send_func, &args.maker_payment_tx.data) .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; - let state = self - .status_from_htlc_params( + let (state, htlc_params) = self + .status_and_htlc_params_from_tx_data( etomic_swap_contract, &ERC721_CONTRACT, - decoded, + &decoded, 3, StateType::MakerPayments, ) @@ -6753,7 +6769,24 @@ impl EthCoin { state ))); } - todo!() + let data = spend_func + .encode_input(&[ + htlc_params[0].clone(), // swap_id + Token::Address(args.maker_payment_tx.sender()), + Token::FixedBytes(args.taker_secret_hash.to_vec()), + Token::FixedBytes(args.maker_secret.to_vec()), + htlc_params[2].clone(), // tokenAddress + decoded[2].clone(), // tokenId + ]) + .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + self.sign_and_send_transaction( + 0.into(), + Action::Call(etomic_swap_contract), + data, + U256::from(ETH_GAS), + ) + .compat() + .await }, }, EthCoinType::Eth | EthCoinType::Erc20 { .. } => Err(TransactionErr::ProtocolNotSupported( @@ -6762,18 +6795,20 @@ impl EthCoin { } } - async fn status_from_htlc_params( + async fn status_and_htlc_params_from_tx_data( &self, swap_contract_addr: Address, contract: &Contract, - decoded: Vec, + decoded: &[Token], index: usize, state_type: StateType, - ) -> Result { + ) -> Result<(U256, Vec), PaymentStatusErr> { if let Some(Token::Bytes(data_bytes)) = decoded.get(index) { - if let Ok(decoded_params) = ethabi::decode(htlc_params(), data_bytes) { - self.payment_status_v2(swap_contract_addr, decoded_params[0].clone(), contract, state_type) - .await + if let Ok(htlc_params) = ethabi::decode(htlc_params(), data_bytes) { + let state = self + .payment_status_v2(swap_contract_addr, htlc_params[0].clone(), contract, state_type) + .await?; + Ok((state, htlc_params)) } else { Err(PaymentStatusErr::TxDeserializationError(ERRL!( "Failed to decode HTLCParams from data_bytes" From 14813758d075eb401f3e2270ea54763c52ae87df Mon Sep 17 00:00:00 2001 From: laruh Date: Sun, 24 Mar 2024 21:10:22 +0700 Subject: [PATCH 51/80] test spend_nft_maker_payment_v2 --- .../tests/docker_tests/eth_docker_tests.rs | 90 +++++++++++++++++-- 1 file changed, 83 insertions(+), 7 deletions(-) diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index 6013e5a2c0..605e6cc873 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -2,13 +2,13 @@ use super::docker_tests_common::{random_secp256k1_secret, ERC1155_TEST_ABI, ERC7 GETH_ERC1155_CONTRACT, GETH_ERC20_CONTRACT, GETH_ERC721_CONTRACT, GETH_NFT_SWAP_CONTRACT, GETH_NONCE_LOCK, GETH_SWAP_CONTRACT, GETH_WATCHERS_SWAP_CONTRACT, GETH_WEB3, MM_CTX}; -use bitcrypto::dhash160; +use bitcrypto::{dhash160, sha256}; use coins::eth::{checksum_address, eth_addr_to_hex, eth_coin_from_conf_and_request, EthCoin, ERC20_ABI}; use coins::nft::nft_structs::{Chain, ContractType, NftInfo}; use coins::{CoinAssocTypes, CoinProtocol, ConfirmPaymentInput, FoundSwapTxSpend, MakerNftSwapOpsV2, MarketCoinOps, PrivKeyBuildPolicy, RefundPaymentArgs, SearchForSwapTxSpendInput, SendNftMakerPaymentArgs, - SendPaymentArgs, SpendPaymentArgs, SwapOps, SwapTxTypeWithSecretHash, ToBytes, Transaction, - ValidateNftMakerPaymentArgs}; + SendPaymentArgs, SpendNftMakerPaymentArgs, SpendPaymentArgs, SwapOps, SwapTxTypeWithSecretHash, ToBytes, + Transaction, ValidateNftMakerPaymentArgs}; use common::{block_on, now_sec}; use ethereum_types::U256; use futures01::Future; @@ -134,6 +134,12 @@ pub(crate) fn mint_erc721(to_addr: Address, token_id: U256) { ); } +fn erc712_owner(token_id: U256) -> Address { + let _guard = GETH_NONCE_LOCK.lock().unwrap(); + let erc721_contract = Contract::from_json(GETH_WEB3.eth(), erc721_contract(), ERC721_TEST_ABI.as_bytes()).unwrap(); + block_on(erc721_contract.query("ownerOf", Token::Uint(token_id), None, Options::default(), None)).unwrap() +} + pub(crate) fn mint_erc1155(to_addr: Address, token_id: U256, amount: U256) { let _guard = GETH_NONCE_LOCK.lock().unwrap(); let erc1155_contract = @@ -170,6 +176,20 @@ pub(crate) fn mint_erc1155(to_addr: Address, token_id: U256, amount: U256) { ); } +fn erc1155_balance(wallet_addr: Address, token_id: U256) -> U256 { + let _guard = GETH_NONCE_LOCK.lock().unwrap(); + let erc1155_contract = + Contract::from_json(GETH_WEB3.eth(), erc1155_contract(), ERC1155_TEST_ABI.as_bytes()).unwrap(); + block_on(erc1155_contract.query( + "balanceOf", + (Token::Address(wallet_addr), Token::Uint(token_id)), + None, + Options::default(), + None, + )) + .unwrap() +} + pub(crate) async fn fill_erc1155_info(eth_coin: &EthCoin, tokens_id: u32, amount: u32) { let nft_infos_lock = eth_coin.nfts_infos.clone(); let mut nft_infos = nft_infos_lock.lock().await; @@ -627,10 +647,13 @@ fn send_and_spend_erc721_maker_payment() { let maker_pubkey = maker_global_nft.derive_htlc_pubkey(&[]); let taker_pubkey = taker_global_nft.derive_htlc_pubkey(&[]); + let maker_secret = &[1; 32]; + let maker_secret_hash = sha256(maker_secret).to_vec(); + let send_payment_args: SendNftMakerPaymentArgs = SendNftMakerPaymentArgs { time_lock, taker_secret_hash: &[0; 32], - maker_secret_hash: &[0; 32], + maker_secret_hash: &maker_secret_hash, amount: 1.into(), taker_pub: &taker_global_nft.parse_pubkey(&taker_pubkey).unwrap(), swap_unique_data: &[], @@ -655,7 +678,7 @@ fn send_and_spend_erc721_maker_payment() { maker_payment_tx: &maker_payment, time_lock, taker_secret_hash: &[0; 32], - maker_secret_hash: &[0; 32], + maker_secret_hash: &maker_secret_hash, amount: 1.into(), taker_pub: &taker_global_nft.parse_pubkey(&taker_pubkey).unwrap(), maker_pub: &maker_global_nft.parse_pubkey(&maker_pubkey).unwrap(), @@ -666,6 +689,31 @@ fn send_and_spend_erc721_maker_payment() { swap_contract_address: &nft_swap_contract().to_bytes(), }; block_on(maker_global_nft.validate_nft_maker_payment_v2(validate_args)).unwrap(); + + let spend_payment_args = SpendNftMakerPaymentArgs { + maker_payment_tx: &maker_payment, + time_lock, + taker_secret_hash: &[0; 32], + maker_secret_hash: &maker_secret_hash, + maker_secret, + maker_pub: &maker_global_nft.parse_pubkey(&maker_pubkey).unwrap(), + swap_unique_data: &[], + contract_type: &ContractType::Erc721.to_bytes(), + swap_contract_address: &nft_swap_contract().to_bytes(), + }; + let spend_tx = block_on(taker_global_nft.spend_nft_maker_payment_v2(spend_payment_args)).unwrap(); + + let confirm_input = ConfirmPaymentInput { + payment_tx: spend_tx.tx_hex(), + confirmations: 1, + requires_nota: false, + wait_until: now_sec() + 70, + check_every: 1, + }; + taker_global_nft.wait_for_confirmations(confirm_input).wait().unwrap(); + + let new_owner = erc712_owner(U256::from(2)); + assert_eq!(new_owner, taker_global_nft.my_address); } #[test] @@ -679,10 +727,13 @@ fn send_and_spend_erc1155_maker_payment() { let maker_pubkey = maker_global_nft.derive_htlc_pubkey(&[]); let taker_pubkey = taker_global_nft.derive_htlc_pubkey(&[]); + let maker_secret = &[1; 32]; + let maker_secret_hash = sha256(maker_secret).to_vec(); + let send_payment_args: SendNftMakerPaymentArgs = SendNftMakerPaymentArgs { time_lock, taker_secret_hash: &[0; 32], - maker_secret_hash: &[0; 32], + maker_secret_hash: &maker_secret_hash, amount: 3.into(), taker_pub: &taker_global_nft.parse_pubkey(&taker_pubkey).unwrap(), swap_unique_data: &[], @@ -707,7 +758,7 @@ fn send_and_spend_erc1155_maker_payment() { maker_payment_tx: &maker_payment, time_lock, taker_secret_hash: &[0; 32], - maker_secret_hash: &[0; 32], + maker_secret_hash: &maker_secret_hash, amount: 3.into(), taker_pub: &taker_global_nft.parse_pubkey(&taker_pubkey).unwrap(), maker_pub: &maker_global_nft.parse_pubkey(&maker_pubkey).unwrap(), @@ -718,4 +769,29 @@ fn send_and_spend_erc1155_maker_payment() { swap_contract_address: &nft_swap_contract().to_bytes(), }; block_on(maker_global_nft.validate_nft_maker_payment_v2(validate_args)).unwrap(); + + let spend_payment_args = SpendNftMakerPaymentArgs { + maker_payment_tx: &maker_payment, + time_lock, + taker_secret_hash: &[0; 32], + maker_secret_hash: &maker_secret_hash, + maker_secret, + maker_pub: &maker_global_nft.parse_pubkey(&maker_pubkey).unwrap(), + swap_unique_data: &[], + contract_type: &ContractType::Erc1155.to_bytes(), + swap_contract_address: &nft_swap_contract().to_bytes(), + }; + let spend_tx = block_on(taker_global_nft.spend_nft_maker_payment_v2(spend_payment_args)).unwrap(); + + let confirm_input = ConfirmPaymentInput { + payment_tx: spend_tx.tx_hex(), + confirmations: 1, + requires_nota: false, + wait_until: now_sec() + 60, + check_every: 1, + }; + taker_global_nft.wait_for_confirmations(confirm_input).wait().unwrap(); + + let balance = erc1155_balance(taker_global_nft.my_address, U256::from(4)); + assert_eq!(balance, U256::from(3)); } From adfe045ccb6613ed039a381a120d89f9338b7742 Mon Sep 17 00:00:00 2001 From: laruh Date: Sun, 24 Mar 2024 22:01:02 +0700 Subject: [PATCH 52/80] provide NFT_SWAP_CONTRACT to status_and_htlc_params_from_tx_data --- mm2src/coins/eth.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 5f61c85f3e..5ac9f18a51 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -6711,7 +6711,7 @@ impl EthCoin { let (state, htlc_params) = self .status_and_htlc_params_from_tx_data( etomic_swap_contract, - &ERC1155_CONTRACT, + &NFT_SWAP_CONTRACT, &decoded, 4, StateType::MakerPayments, @@ -6755,7 +6755,7 @@ impl EthCoin { let (state, htlc_params) = self .status_and_htlc_params_from_tx_data( etomic_swap_contract, - &ERC721_CONTRACT, + &NFT_SWAP_CONTRACT, &decoded, 3, StateType::MakerPayments, From ba3c0321962101f14fec4cd5cef5ef5c9737c055 Mon Sep 17 00:00:00 2001 From: laruh Date: Mon, 25 Mar 2024 17:06:10 +0700 Subject: [PATCH 53/80] update erc1155 Bytes abd ABI, move amount field below tokenId in spendErc1155MakerPayment --- mm2src/coins/eth.rs | 12 +++++++- mm2src/coins/eth/nft_swap_contract_abi.json | 30 +++++++++---------- .../tests/docker_tests/docker_tests_common.rs | 2 +- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 5ac9f18a51..801e1cbffa 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -6728,12 +6728,12 @@ impl EthCoin { let data = spend_func .encode_input(&[ htlc_params[0].clone(), // swap_id - decoded[3].clone(), // amount Token::Address(args.maker_payment_tx.sender()), Token::FixedBytes(args.taker_secret_hash.to_vec()), Token::FixedBytes(args.maker_secret.to_vec()), htlc_params[2].clone(), // tokenAddress decoded[2].clone(), // tokenId + decoded[3].clone(), // amount ]) .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; self.sign_and_send_transaction( @@ -6822,6 +6822,16 @@ impl EthCoin { } } +// Representation of the Solidity HTLCParams struct. +// +// struct HTLCParams { +// bytes32 id; +// address taker; +// address tokenAddress; +// bytes32 takerSecretHash; +// bytes32 makerSecretHash; +// uint32 paymentLockTime; +// } fn htlc_params() -> &'static [ethabi::ParamType] { &[ ethabi::ParamType::FixedBytes(32), diff --git a/mm2src/coins/eth/nft_swap_contract_abi.json b/mm2src/coins/eth/nft_swap_contract_abi.json index f0c3049d98..fd17b4cd8c 100644 --- a/mm2src/coins/eth/nft_swap_contract_abi.json +++ b/mm2src/coins/eth/nft_swap_contract_abi.json @@ -434,11 +434,6 @@ "name": "id", "type": "bytes32" }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, { "internalType": "address", "name": "taker", @@ -463,6 +458,11 @@ "internalType": "uint256", "name": "tokenId", "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" } ], "name": "refundErc1155MakerPaymentSecret", @@ -477,11 +477,6 @@ "name": "id", "type": "bytes32" }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, { "internalType": "address", "name": "taker", @@ -506,6 +501,11 @@ "internalType": "uint256", "name": "tokenId", "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" } ], "name": "refundErc1155MakerPaymentTimelock", @@ -682,11 +682,6 @@ "name": "id", "type": "bytes32" }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, { "internalType": "address", "name": "maker", @@ -711,6 +706,11 @@ "internalType": "uint256", "name": "tokenId", "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" } ], "name": "spendErc1155MakerPayment", diff --git a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs index ae1ecec367..f2b7c8d96b 100644 --- a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs +++ b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs @@ -111,7 +111,7 @@ pub const SWAP_CONTRACT_BYTES: &str = "608060405234801561001057600080fd5b5061143 pub const WATCHERS_SWAP_CONTRACT_BYTES: &str = "608060405234801561000f575f80fd5b50612aa48061001d5f395ff3fe608060405260043610610085575f3560e01c806346fc02941161005857806346fc0294146101275780636a3227861461014f5780639b415b2a1461016b578063b5985c4d14610193578063cd1dde34146101bb57610085565b806302ed292b146100895780630716326d146100b15780630971fd54146100ef578063152cf3af1461010b575b5f80fd5b348015610094575f80fd5b506100af60048036038101906100aa9190611e1d565b6101e3565b005b3480156100bc575f80fd5b506100d760048036038101906100d29190611e94565b610518565b6040516100e693929190611f8e565b60405180910390f35b6101096004803603810190610104919061206f565b610568565b005b6101256004803603810190610120919061210c565b610787565b005b348015610132575f80fd5b5061014d60048036038101906101489190612170565b61099d565b005b610169600480360381019061016491906121e7565b610c4d565b005b348015610176575f80fd5b50610191600480360381019061018c91906122ab565b610f61565b005b34801561019e575f80fd5b506101b960048036038101906101b49190612334565b611203565b005b3480156101c6575f80fd5b506101e160048036038101906101dc91906123f8565b611887565b005b600160038111156101f7576101f6611f1b565b5b5f808781526020019081526020015f205f01601c9054906101000a900460ff16600381111561022957610228611f1b565b5b14610232575f80fd5b5f60033383600360028860405160200161024c91906124dc565b6040516020818303038152906040526040516102689190612562565b602060405180830381855afa158015610283573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906102a6919061258c565b6040516020016102b691906124dc565b6040516020818303038152906040526040516102d29190612562565b602060405180830381855afa1580156102ed573d5f803e3d5ffd5b5050506040515160601b868960405160200161030d95949392919061263c565b6040516020818303038152906040526040516103299190612562565b602060405180830381855afa158015610344573d5f803e3d5ffd5b5050506040515160601b90505f808781526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610397575f80fd5b60025f808881526020019081526020015f205f01601c6101000a81548160ff021916908360038111156103cd576103cc611f1b565b5b02179055505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361044e573373ffffffffffffffffffffffffffffffffffffffff166108fc8690811502906040515f60405180830381858888f19350505050158015610448573d5f803e3d5ffd5b506104d7565b5f8390508073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33886040518363ffffffff1660e01b815260040161048d9291906126b8565b6020604051808303815f875af11580156104a9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104cd91906126f3565b6104d5575f80fd5b505b7f36c177bcb01c6d568244f05261e2946c8c977fa50822f3fa098c470770ee1f3e868560405161050892919061272d565b60405180910390a1505050505050565b5f602052805f5260405f205f91509050805f015f9054906101000a900460601b90805f0160149054906101000a900467ffffffffffffffff1690805f01601c9054906101000a900460ff16905083565b5f73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff16141580156105a357505f34115b80156105f157505f60038111156105bd576105bc611f1b565b5b5f808981526020019081526020015f205f01601c9054906101000a900460ff1660038111156105ef576105ee611f1b565b5b145b6105f9575f80fd5b5f60038733885f3489898960405160200161061b9897969594939291906127e7565b6040516020818303038152906040526040516106379190612562565b602060405180830381855afa158015610652573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018667ffffffffffffffff168152602001600160038111156106a2576106a1611f1b565b5b8152505f808a81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506040820151815f01601c6101000a81548160ff0219169083600381111561073e5761073d611f1b565b5b02179055509050507fccc9c05183599bd3135da606eaaf535daffe256e9de33c048014cffcccd4ad57886040516107759190612878565b60405180910390a15050505050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141580156107c257505f34115b801561081057505f60038111156107dc576107db611f1b565b5b5f808681526020019081526020015f205f01601c9054906101000a900460ff16600381111561080e5761080d611f1b565b5b145b610818575f80fd5b5f60038433855f3460405160200161083495949392919061263c565b6040516020818303038152906040526040516108509190612562565b602060405180830381855afa15801561086b573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018367ffffffffffffffff168152602001600160038111156108bb576108ba611f1b565b5b8152505f808781526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506040820151815f01601c6101000a81548160ff0219169083600381111561095757610956611f1b565b5b02179055509050507fccc9c05183599bd3135da606eaaf535daffe256e9de33c048014cffcccd4ad578560405161098e9190612878565b60405180910390a15050505050565b600160038111156109b1576109b0611f1b565b5b5f808781526020019081526020015f205f01601c9054906101000a900460ff1660038111156109e3576109e2611f1b565b5b146109ec575f80fd5b5f60038233868689604051602001610a0895949392919061263c565b604051602081830303815290604052604051610a249190612562565b602060405180830381855afa158015610a3f573d5f803e3d5ffd5b5050506040515160601b90505f808781526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916148015610ac657505f808781526020019081526020015f205f0160149054906101000a900467ffffffffffffffff1667ffffffffffffffff164210155b610ace575f80fd5b60035f808881526020019081526020015f205f01601c6101000a81548160ff02191690836003811115610b0457610b03611f1b565b5b02179055505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610b85573373ffffffffffffffffffffffffffffffffffffffff166108fc8690811502906040515f60405180830381858888f19350505050158015610b7f573d5f803e3d5ffd5b50610c0e565b5f8390508073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33886040518363ffffffff1660e01b8152600401610bc49291906126b8565b6020604051808303815f875af1158015610be0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c0491906126f3565b610c0c575f80fd5b505b7f1797d500133f8e427eb9da9523aa4a25cb40f50ebc7dbda3c7c81778973f35ba86604051610c3d9190612878565b60405180910390a1505050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614158015610c8857505f88115b8015610cd657505f6003811115610ca257610ca1611f1b565b5b5f808b81526020019081526020015f205f01601c9054906101000a900460ff166003811115610cd457610cd3611f1b565b5b145b610cde575f80fd5b5f6003811115610cf157610cf0611f1b565b5b836003811115610d0457610d03611f1b565b5b14158015610d365750600380811115610d2057610d1f611f1b565b5b836003811115610d3357610d32611f1b565b5b14155b15610d4757803414610d46575f80fd5b5b5f60038733888b8d898989604051602001610d699897969594939291906127e7565b604051602081830303815290604052604051610d859190612562565b602060405180830381855afa158015610da0573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018667ffffffffffffffff16815260200160016003811115610df057610def611f1b565b5b8152505f808c81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506040820151815f01601c6101000a81548160ff02191690836003811115610e8c57610e8b611f1b565b5b02179055509050505f8890508073ffffffffffffffffffffffffffffffffffffffff166323b872dd33308d6040518463ffffffff1660e01b8152600401610ed593929190612891565b6020604051808303815f875af1158015610ef1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f1591906126f3565b610f1d575f80fd5b7fccc9c05183599bd3135da606eaaf535daffe256e9de33c048014cffcccd4ad578b604051610f4c9190612878565b60405180910390a15050505050505050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614158015610f9c57505f85115b8015610fea57505f6003811115610fb657610fb5611f1b565b5b5f808881526020019081526020015f205f01601c9054906101000a900460ff166003811115610fe857610fe7611f1b565b5b145b610ff2575f80fd5b5f6003843385888a60405160200161100e95949392919061263c565b60405160208183030381529060405260405161102a9190612562565b602060405180830381855afa158015611045573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018367ffffffffffffffff1681526020016001600381111561109557611094611f1b565b5b8152505f808981526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506040820151815f01601c6101000a81548160ff0219169083600381111561113157611130611f1b565b5b02179055509050505f8590508073ffffffffffffffffffffffffffffffffffffffff166323b872dd33308a6040518463ffffffff1660e01b815260040161117a93929190612891565b6020604051808303815f875af1158015611196573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111ba91906126f3565b6111c2575f80fd5b7fccc9c05183599bd3135da606eaaf535daffe256e9de33c048014cffcccd4ad57886040516111f19190612878565b60405180910390a15050505050505050565b6001600381111561121757611216611f1b565b5b5f808b81526020019081526020015f205f01601c9054906101000a900460ff16600381111561124957611248611f1b565b5b14611289576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161128090612920565b60405180910390fd5b5f60038587600360028c6040516020016112a391906124dc565b6040516020818303038152906040526040516112bf9190612562565b602060405180830381855afa1580156112da573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906112fd919061258c565b60405160200161130d91906124dc565b6040516020818303038152906040526040516113299190612562565b602060405180830381855afa158015611344573d5f803e3d5ffd5b5050506040515160601b8a8d89898960405160200161136a9897969594939291906127e7565b6040516020818303038152906040526040516113869190612562565b602060405180830381855afa1580156113a1573d5f803e3d5ffd5b5050506040515160601b90505f808b81526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461142b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161142290612988565b60405180910390fd5b60025f808c81526020019081526020015f205f01601c6101000a81548160ff0219169083600381111561146157611460611f1b565b5b02179055505f73ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff160361159e575f8060038111156114ad576114ac611f1b565b5b8560038111156114c0576114bf611f1b565b5b1480156114cb575083155b6114e057828a6114db91906129d3565b6114e2565b895b90508573ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f19350505050158015611527573d5f803e3d5ffd5b5060038081111561153b5761153a611f1b565b5b85600381111561154e5761154d611f1b565b5b03611598573373ffffffffffffffffffffffffffffffffffffffff166108fc8490811502906040515f60405180830381858888f19350505050158015611596573d5f803e3d5ffd5b505b50611786565b5f6003808111156115b2576115b1611f1b565b5b8560038111156115c5576115c4611f1b565b5b146115d057896115dd565b828a6115dc91906129d3565b5b90505f8890508073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb88846040518363ffffffff1660e01b815260040161161e9291906126b8565b6020604051808303815f875af115801561163a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061165e91906126f3565b61169d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161169490612a50565b60405180910390fd5b6003808111156116b0576116af611f1b565b5b8660038111156116c3576116c2611f1b565b5b03611783578073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33866040518363ffffffff1660e01b81526004016117039291906126b8565b6020604051808303815f875af115801561171f573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061174391906126f3565b611782576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161177990612a50565b60405180910390fd5b5b50505b6002600381111561179a57611799611f1b565b5b8460038111156117ad576117ac611f1b565b5b036117f7578573ffffffffffffffffffffffffffffffffffffffff166108fc8390811502906040515f60405180830381858888f193505050501580156117f5573d5f803e3d5ffd5b505b8215611842573373ffffffffffffffffffffffffffffffffffffffff166108fc8390811502906040515f60405180830381858888f19350505050158015611840573d5f803e3d5ffd5b505b7f36c177bcb01c6d568244f05261e2946c8c977fa50822f3fa098c470770ee1f3e8a8960405161187392919061272d565b60405180910390a150505050505050505050565b6001600381111561189b5761189a611f1b565b5b5f808b81526020019081526020015f205f01601c9054906101000a900460ff1660038111156118cd576118cc611f1b565b5b146118d6575f80fd5b5f600385878a8a8d8989896040516020016118f89897969594939291906127e7565b6040516020818303038152906040526040516119149190612562565b602060405180830381855afa15801561192f573d5f803e3d5ffd5b5050506040515160601b90505f808b81526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161480156119b657505f808b81526020019081526020015f205f0160149054906101000a900467ffffffffffffffff1667ffffffffffffffff164210155b6119be575f80fd5b60035f808c81526020019081526020015f205f01601c6101000a81548160ff021916908360038111156119f4576119f3611f1b565b5b02179055505f73ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1603611b27575f806003811115611a4057611a3f611f1b565b5b856003811115611a5357611a52611f1b565b5b14611a6957828a611a6491906129d3565b611a6b565b895b90508673ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f19350505050158015611ab0573d5f803e3d5ffd5b505f6003811115611ac457611ac3611f1b565b5b856003811115611ad757611ad6611f1b565b5b14611b21573373ffffffffffffffffffffffffffffffffffffffff166108fc8490811502906040515f60405180830381858888f19350505050158015611b1f573d5f803e3d5ffd5b505b50611d16565b5f600380811115611b3b57611b3a611f1b565b5b856003811115611b4e57611b4d611f1b565b5b14611b595789611b66565b828a611b6591906129d3565b5b90505f8890508073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb89846040518363ffffffff1660e01b8152600401611ba79291906126b8565b6020604051808303815f875af1158015611bc3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611be791906126f3565b611bef575f80fd5b600380811115611c0257611c01611f1b565b5b866003811115611c1557611c14611f1b565b5b03611ca2578073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb33866040518363ffffffff1660e01b8152600401611c559291906126b8565b6020604051808303815f875af1158015611c71573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c9591906126f3565b611c9d575f80fd5b611d13565b5f6003811115611cb557611cb4611f1b565b5b866003811115611cc857611cc7611f1b565b5b14611d12573373ffffffffffffffffffffffffffffffffffffffff166108fc8590811502906040515f60405180830381858888f19350505050158015611d10573d5f803e3d5ffd5b505b5b50505b7f1797d500133f8e427eb9da9523aa4a25cb40f50ebc7dbda3c7c81778973f35ba8a604051611d459190612878565b60405180910390a150505050505050505050565b5f80fd5b5f819050919050565b611d6f81611d5d565b8114611d79575f80fd5b50565b5f81359050611d8a81611d66565b92915050565b5f819050919050565b611da281611d90565b8114611dac575f80fd5b50565b5f81359050611dbd81611d99565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f611dec82611dc3565b9050919050565b611dfc81611de2565b8114611e06575f80fd5b50565b5f81359050611e1781611df3565b92915050565b5f805f805f60a08688031215611e3657611e35611d59565b5b5f611e4388828901611d7c565b9550506020611e5488828901611daf565b9450506040611e6588828901611d7c565b9350506060611e7688828901611e09565b9250506080611e8788828901611e09565b9150509295509295909350565b5f60208284031215611ea957611ea8611d59565b5b5f611eb684828501611d7c565b91505092915050565b5f7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b611ef381611ebf565b82525050565b5f67ffffffffffffffff82169050919050565b611f1581611ef9565b82525050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60048110611f5957611f58611f1b565b5b50565b5f819050611f6982611f48565b919050565b5f611f7882611f5c565b9050919050565b611f8881611f6e565b82525050565b5f606082019050611fa15f830186611eea565b611fae6020830185611f0c565b611fbb6040830184611f7f565b949350505050565b611fcc81611ebf565b8114611fd6575f80fd5b50565b5f81359050611fe781611fc3565b92915050565b611ff681611ef9565b8114612000575f80fd5b50565b5f8135905061201181611fed565b92915050565b60048110612023575f80fd5b50565b5f8135905061203481612017565b92915050565b5f8115159050919050565b61204e8161203a565b8114612058575f80fd5b50565b5f8135905061206981612045565b92915050565b5f805f805f805f60e0888a03121561208a57612089611d59565b5b5f6120978a828b01611d7c565b97505060206120a88a828b01611e09565b96505060406120b98a828b01611fd9565b95505060606120ca8a828b01612003565b94505060806120db8a828b01612026565b93505060a06120ec8a828b0161205b565b92505060c06120fd8a828b01611daf565b91505092959891949750929550565b5f805f806080858703121561212457612123611d59565b5b5f61213187828801611d7c565b945050602061214287828801611e09565b935050604061215387828801611fd9565b925050606061216487828801612003565b91505092959194509250565b5f805f805f60a0868803121561218957612188611d59565b5b5f61219688828901611d7c565b95505060206121a788828901611daf565b94505060406121b888828901611fd9565b93505060606121c988828901611e09565b92505060806121da88828901611e09565b9150509295509295909350565b5f805f805f805f805f6101208a8c03121561220557612204611d59565b5b5f6122128c828d01611d7c565b99505060206122238c828d01611daf565b98505060406122348c828d01611e09565b97505060606122458c828d01611e09565b96505060806122568c828d01611fd9565b95505060a06122678c828d01612003565b94505060c06122788c828d01612026565b93505060e06122898c828d0161205b565b92505061010061229b8c828d01611daf565b9150509295985092959850929598565b5f805f805f8060c087890312156122c5576122c4611d59565b5b5f6122d289828a01611d7c565b96505060206122e389828a01611daf565b95505060406122f489828a01611e09565b945050606061230589828a01611e09565b935050608061231689828a01611fd9565b92505060a061232789828a01612003565b9150509295509295509295565b5f805f805f805f805f6101208a8c03121561235257612351611d59565b5b5f61235f8c828d01611d7c565b99505060206123708c828d01611daf565b98505060406123818c828d01611d7c565b97505060606123928c828d01611e09565b96505060806123a38c828d01611e09565b95505060a06123b48c828d01611e09565b94505060c06123c58c828d01612026565b93505060e06123d68c828d0161205b565b9250506101006123e88c828d01611daf565b9150509295985092959850929598565b5f805f805f805f805f6101208a8c03121561241657612415611d59565b5b5f6124238c828d01611d7c565b99505060206124348c828d01611daf565b98505060406124458c828d01611fd9565b97505060606124568c828d01611e09565b96505060806124678c828d01611e09565b95505060a06124788c828d01611e09565b94505060c06124898c828d01612026565b93505060e061249a8c828d0161205b565b9250506101006124ac8c828d01611daf565b9150509295985092959850929598565b5f819050919050565b6124d66124d182611d5d565b6124bc565b82525050565b5f6124e782846124c5565b60208201915081905092915050565b5f81519050919050565b5f81905092915050565b5f5b8381101561252757808201518184015260208101905061250c565b5f8484015250505050565b5f61253c826124f6565b6125468185612500565b935061255681856020860161250a565b80840191505092915050565b5f61256d8284612532565b915081905092915050565b5f8151905061258681611d66565b92915050565b5f602082840312156125a1576125a0611d59565b5b5f6125ae84828501612578565b91505092915050565b5f8160601b9050919050565b5f6125cd826125b7565b9050919050565b5f6125de826125c3565b9050919050565b6125f66125f182611de2565b6125d4565b82525050565b5f819050919050565b61261661261182611ebf565b6125fc565b82525050565b5f819050919050565b61263661263182611d90565b61261c565b82525050565b5f61264782886125e5565b60148201915061265782876125e5565b6014820191506126678286612605565b60148201915061267782856125e5565b6014820191506126878284612625565b6020820191508190509695505050505050565b6126a381611de2565b82525050565b6126b281611d90565b82525050565b5f6040820190506126cb5f83018561269a565b6126d860208301846126a9565b9392505050565b5f815190506126ed81612045565b92915050565b5f6020828403121561270857612707611d59565b5b5f612715848285016126df565b91505092915050565b61272781611d5d565b82525050565b5f6040820190506127405f83018561271e565b61274d602083018461271e565b9392505050565b6004811061276557612764611f1b565b5b50565b5f81905061277582612754565b919050565b5f61278482612768565b9050919050565b5f8160f81b9050919050565b5f6127a18261278b565b9050919050565b6127b96127b48261277a565b612797565b82525050565b5f6127c982612797565b9050919050565b6127e16127dc8261203a565b6127bf565b82525050565b5f6127f2828b6125e5565b601482019150612802828a6125e5565b6014820191506128128289612605565b60148201915061282282886125e5565b6014820191506128328287612625565b60208201915061284282866127a8565b60018201915061285282856127d0565b6001820191506128628284612625565b6020820191508190509998505050505050505050565b5f60208201905061288b5f83018461271e565b92915050565b5f6060820190506128a45f83018661269a565b6128b1602083018561269a565b6128be60408301846126a9565b949350505050565b5f82825260208201905092915050565b7f5061796d656e7420776173206e6f742073656e740000000000000000000000005f82015250565b5f61290a6014836128c6565b9150612915826128d6565b602082019050919050565b5f6020820190508181035f830152612937816128fe565b9050919050565b7f496e76616c6964207061796d656e7420686173680000000000000000000000005f82015250565b5f6129726014836128c6565b915061297d8261293e565b602082019050919050565b5f6020820190508181035f83015261299f81612966565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6129dd82611d90565b91506129e883611d90565b9250828203905081811115612a00576129ff6129a6565b5b92915050565b7f546f6b656e207472616e73666572206661696c656400000000000000000000005f82015250565b5f612a3a6015836128c6565b9150612a4582612a06565b602082019050919050565b5f6020820190508181035f830152612a6781612a2e565b905091905056fea26469706673582212203106867e1b147b377237cde0aba42d82faf0282b83d7b6d62cca039d0b7f840564736f6c63430008160033"; pub const ERC721_TEST_TOKEN_BYTES: &str = "608060405234801562000010575f80fd5b50604051620022ac380380620022ac8339818101604052810190620000369190620001ea565b8181815f9081620000489190620004a4565b5080600190816200005a9190620004a4565b505050505062000588565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b620000c6826200007e565b810181811067ffffffffffffffff82111715620000e857620000e76200008e565b5b80604052505050565b5f620000fc62000065565b90506200010a8282620000bb565b919050565b5f67ffffffffffffffff8211156200012c576200012b6200008e565b5b62000137826200007e565b9050602081019050919050565b5f5b838110156200016357808201518184015260208101905062000146565b5f8484015250505050565b5f620001846200017e846200010f565b620000f1565b905082815260208101848484011115620001a357620001a26200007a565b5b620001b084828562000144565b509392505050565b5f82601f830112620001cf57620001ce62000076565b5b8151620001e18482602086016200016e565b91505092915050565b5f80604083850312156200020357620002026200006e565b5b5f83015167ffffffffffffffff81111562000223576200022262000072565b5b6200023185828601620001b8565b925050602083015167ffffffffffffffff81111562000255576200025462000072565b5b6200026385828601620001b8565b9150509250929050565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680620002bc57607f821691505b602082108103620002d257620002d162000277565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620003367fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620002f9565b620003428683620002f9565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f6200038c6200038662000380846200035a565b62000363565b6200035a565b9050919050565b5f819050919050565b620003a7836200036c565b620003bf620003b68262000393565b84845462000305565b825550505050565b5f90565b620003d5620003c7565b620003e28184846200039c565b505050565b5b818110156200040957620003fd5f82620003cb565b600181019050620003e8565b5050565b601f82111562000458576200042281620002d8565b6200042d84620002ea565b810160208510156200043d578190505b620004556200044c85620002ea565b830182620003e7565b50505b505050565b5f82821c905092915050565b5f6200047a5f19846008026200045d565b1980831691505092915050565b5f62000494838362000469565b9150826002028217905092915050565b620004af826200026d565b67ffffffffffffffff811115620004cb57620004ca6200008e565b5b620004d78254620002a4565b620004e48282856200040d565b5f60209050601f8311600181146200051a575f841562000505578287015190505b62000511858262000487565b86555062000580565b601f1984166200052a86620002d8565b5f5b8281101562000553578489015182556001820191506020850194506020810190506200052c565b868310156200057357848901516200056f601f89168262000469565b8355505b6001600288020188555050505b505050505050565b611d1680620005965f395ff3fe608060405234801561000f575f80fd5b50600436106100e8575f3560e01c80636352211e1161008a578063a22cb46511610064578063a22cb46514610258578063b88d4fde14610274578063c87b56dd14610290578063e985e9c5146102c0576100e8565b80636352211e146101da57806370a082311461020a57806395d89b411461023a576100e8565b8063095ea7b3116100c6578063095ea7b31461016a57806323b872dd1461018657806340c10f19146101a257806342842e0e146101be576100e8565b806301ffc9a7146100ec57806306fdde031461011c578063081812fc1461013a575b5f80fd5b610106600480360381019061010191906115a7565b6102f0565b60405161011391906115ec565b60405180910390f35b6101246103d1565b604051610131919061168f565b60405180910390f35b610154600480360381019061014f91906116e2565b610460565b604051610161919061174c565b60405180910390f35b610184600480360381019061017f919061178f565b61047b565b005b6101a0600480360381019061019b91906117cd565b610491565b005b6101bc60048036038101906101b7919061178f565b610590565b005b6101d860048036038101906101d391906117cd565b61059e565b005b6101f460048036038101906101ef91906116e2565b6105bd565b604051610201919061174c565b60405180910390f35b610224600480360381019061021f919061181d565b6105ce565b6040516102319190611857565b60405180910390f35b610242610684565b60405161024f919061168f565b60405180910390f35b610272600480360381019061026d919061189a565b610714565b005b61028e60048036038101906102899190611a04565b61072a565b005b6102aa60048036038101906102a591906116e2565b610747565b6040516102b7919061168f565b60405180910390f35b6102da60048036038101906102d59190611a84565b6107ad565b6040516102e791906115ec565b60405180910390f35b5f7f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806103ba57507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806103ca57506103c98261083b565b5b9050919050565b60605f80546103df90611aef565b80601f016020809104026020016040519081016040528092919081815260200182805461040b90611aef565b80156104565780601f1061042d57610100808354040283529160200191610456565b820191905f5260205f20905b81548152906001019060200180831161043957829003601f168201915b5050505050905090565b5f61046a826108a4565b506104748261092a565b9050919050565b61048d8282610488610963565b61096a565b5050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610501575f6040517f64a0ae920000000000000000000000000000000000000000000000000000000081526004016104f8919061174c565b60405180910390fd5b5f610514838361050f610963565b61097c565b90508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461058a578382826040517f64283d7b00000000000000000000000000000000000000000000000000000000815260040161058193929190611b1f565b60405180910390fd5b50505050565b61059a8282610b87565b5050565b6105b883838360405180602001604052805f81525061072a565b505050565b5f6105c7826108a4565b9050919050565b5f8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361063f575f6040517f89c62b64000000000000000000000000000000000000000000000000000000008152600401610636919061174c565b60405180910390fd5b60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b60606001805461069390611aef565b80601f01602080910402602001604051908101604052809291908181526020018280546106bf90611aef565b801561070a5780601f106106e15761010080835404028352916020019161070a565b820191905f5260205f20905b8154815290600101906020018083116106ed57829003601f168201915b5050505050905090565b61072661071f610963565b8383610c7a565b5050565b610735848484610491565b61074184848484610de3565b50505050565b6060610752826108a4565b505f61075c610f95565b90505f81511161077a5760405180602001604052805f8152506107a5565b8061078484610fab565b604051602001610795929190611b8e565b6040516020818303038152906040525b915050919050565b5f60055f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16905092915050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f806108af83611075565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361092157826040517f7e2732890000000000000000000000000000000000000000000000000000000081526004016109189190611857565b60405180910390fd5b80915050919050565b5f60045f8381526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b5f33905090565b61097783838360016110ae565b505050565b5f8061098784611075565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146109c8576109c781848661126d565b5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610a5357610a075f855f806110ae565b600160035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825403925050819055505b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614610ad257600160035f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055505b8460025f8681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550838573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4809150509392505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610bf7575f6040517f64a0ae92000000000000000000000000000000000000000000000000000000008152600401610bee919061174c565b60405180910390fd5b5f610c0383835f61097c565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610c75575f6040517f73c6ac6e000000000000000000000000000000000000000000000000000000008152600401610c6c919061174c565b60405180910390fd5b505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610cea57816040517f5b08ba18000000000000000000000000000000000000000000000000000000008152600401610ce1919061174c565b60405180910390fd5b8060055f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051610dd691906115ec565b60405180910390a3505050565b5f8373ffffffffffffffffffffffffffffffffffffffff163b1115610f8f578273ffffffffffffffffffffffffffffffffffffffff1663150b7a02610e26610963565b8685856040518563ffffffff1660e01b8152600401610e489493929190611c03565b6020604051808303815f875af1925050508015610e8357506040513d601f19601f82011682018060405250810190610e809190611c61565b60015b610f04573d805f8114610eb1576040519150601f19603f3d011682016040523d82523d5f602084013e610eb6565b606091505b505f815103610efc57836040517f64a0ae92000000000000000000000000000000000000000000000000000000008152600401610ef3919061174c565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614610f8d57836040517f64a0ae92000000000000000000000000000000000000000000000000000000008152600401610f84919061174c565b60405180910390fd5b505b50505050565b606060405180602001604052805f815250905090565b60605f6001610fb984611330565b0190505f8167ffffffffffffffff811115610fd757610fd66118e0565b5b6040519080825280601f01601f1916602001820160405280156110095781602001600182028036833780820191505090505b5090505f82602001820190505b60011561106a578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a858161105f5761105e611c8c565b5b0494505f8503611016575b819350505050919050565b5f60025f8381526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b80806110e657505f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b15611218575f6110f5846108a4565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415801561115f57508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b8015611172575061117081846107ad565b155b156111b457826040517fa9fbf51f0000000000000000000000000000000000000000000000000000000081526004016111ab919061174c565b60405180910390fd5b811561121657838573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b8360045f8581526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505050565b611278838383611481565b61132b575f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036112ec57806040517f7e2732890000000000000000000000000000000000000000000000000000000081526004016112e39190611857565b60405180910390fd5b81816040517f177e802f000000000000000000000000000000000000000000000000000000008152600401611322929190611cb9565b60405180910390fd5b505050565b5f805f90507a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000831061138c577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000838161138257611381611c8c565b5b0492506040810190505b6d04ee2d6d415b85acef810000000083106113c9576d04ee2d6d415b85acef810000000083816113bf576113be611c8c565b5b0492506020810190505b662386f26fc1000083106113f857662386f26fc1000083816113ee576113ed611c8c565b5b0492506010810190505b6305f5e1008310611421576305f5e100838161141757611416611c8c565b5b0492506008810190505b612710831061144657612710838161143c5761143b611c8c565b5b0492506004810190505b60648310611469576064838161145f5761145e611c8c565b5b0492506002810190505b600a8310611478576001810190505b80915050919050565b5f8073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415801561153857508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614806114f957506114f884846107ad565b5b8061153757508273ffffffffffffffffffffffffffffffffffffffff1661151f8361092a565b73ffffffffffffffffffffffffffffffffffffffff16145b5b90509392505050565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61158681611552565b8114611590575f80fd5b50565b5f813590506115a18161157d565b92915050565b5f602082840312156115bc576115bb61154a565b5b5f6115c984828501611593565b91505092915050565b5f8115159050919050565b6115e6816115d2565b82525050565b5f6020820190506115ff5f8301846115dd565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561163c578082015181840152602081019050611621565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61166182611605565b61166b818561160f565b935061167b81856020860161161f565b61168481611647565b840191505092915050565b5f6020820190508181035f8301526116a78184611657565b905092915050565b5f819050919050565b6116c1816116af565b81146116cb575f80fd5b50565b5f813590506116dc816116b8565b92915050565b5f602082840312156116f7576116f661154a565b5b5f611704848285016116ce565b91505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6117368261170d565b9050919050565b6117468161172c565b82525050565b5f60208201905061175f5f83018461173d565b92915050565b61176e8161172c565b8114611778575f80fd5b50565b5f8135905061178981611765565b92915050565b5f80604083850312156117a5576117a461154a565b5b5f6117b28582860161177b565b92505060206117c3858286016116ce565b9150509250929050565b5f805f606084860312156117e4576117e361154a565b5b5f6117f18682870161177b565b93505060206118028682870161177b565b9250506040611813868287016116ce565b9150509250925092565b5f602082840312156118325761183161154a565b5b5f61183f8482850161177b565b91505092915050565b611851816116af565b82525050565b5f60208201905061186a5f830184611848565b92915050565b611879816115d2565b8114611883575f80fd5b50565b5f8135905061189481611870565b92915050565b5f80604083850312156118b0576118af61154a565b5b5f6118bd8582860161177b565b92505060206118ce85828601611886565b9150509250929050565b5f80fd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61191682611647565b810181811067ffffffffffffffff82111715611935576119346118e0565b5b80604052505050565b5f611947611541565b9050611953828261190d565b919050565b5f67ffffffffffffffff821115611972576119716118e0565b5b61197b82611647565b9050602081019050919050565b828183375f83830152505050565b5f6119a86119a384611958565b61193e565b9050828152602081018484840111156119c4576119c36118dc565b5b6119cf848285611988565b509392505050565b5f82601f8301126119eb576119ea6118d8565b5b81356119fb848260208601611996565b91505092915050565b5f805f8060808587031215611a1c57611a1b61154a565b5b5f611a298782880161177b565b9450506020611a3a8782880161177b565b9350506040611a4b878288016116ce565b925050606085013567ffffffffffffffff811115611a6c57611a6b61154e565b5b611a78878288016119d7565b91505092959194509250565b5f8060408385031215611a9a57611a9961154a565b5b5f611aa78582860161177b565b9250506020611ab88582860161177b565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680611b0657607f821691505b602082108103611b1957611b18611ac2565b5b50919050565b5f606082019050611b325f83018661173d565b611b3f6020830185611848565b611b4c604083018461173d565b949350505050565b5f81905092915050565b5f611b6882611605565b611b728185611b54565b9350611b8281856020860161161f565b80840191505092915050565b5f611b998285611b5e565b9150611ba58284611b5e565b91508190509392505050565b5f81519050919050565b5f82825260208201905092915050565b5f611bd582611bb1565b611bdf8185611bbb565b9350611bef81856020860161161f565b611bf881611647565b840191505092915050565b5f608082019050611c165f83018761173d565b611c23602083018661173d565b611c306040830185611848565b8181036060830152611c428184611bcb565b905095945050505050565b5f81519050611c5b8161157d565b92915050565b5f60208284031215611c7657611c7561154a565b5b5f611c8384828501611c4d565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f604082019050611ccc5f83018561173d565b611cd96020830184611848565b939250505056fea26469706673582212207439b47c2a9a1624955997732075917bbf1da26949d000c778f561eb5687576164736f6c63430008180033"; pub const ERC1155_TEST_TOKEN_BYTES: &str = "608060405234801562000010575f80fd5b50604051620024eb380380620024eb8339818101604052810190620000369190620001ea565b8062000048816200005060201b60201c565b505062000554565b806002908162000061919062000470565b5050565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b620000c6826200007e565b810181811067ffffffffffffffff82111715620000e857620000e76200008e565b5b80604052505050565b5f620000fc62000065565b90506200010a8282620000bb565b919050565b5f67ffffffffffffffff8211156200012c576200012b6200008e565b5b62000137826200007e565b9050602081019050919050565b5f5b838110156200016357808201518184015260208101905062000146565b5f8484015250505050565b5f620001846200017e846200010f565b620000f1565b905082815260208101848484011115620001a357620001a26200007a565b5b620001b084828562000144565b509392505050565b5f82601f830112620001cf57620001ce62000076565b5b8151620001e18482602086016200016e565b91505092915050565b5f602082840312156200020257620002016200006e565b5b5f82015167ffffffffffffffff81111562000222576200022162000072565b5b6200023084828501620001b8565b91505092915050565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806200028857607f821691505b6020821081036200029e576200029d62000243565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620003027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620002c5565b6200030e8683620002c5565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f62000358620003526200034c8462000326565b6200032f565b62000326565b9050919050565b5f819050919050565b620003738362000338565b6200038b62000382826200035f565b848454620002d1565b825550505050565b5f90565b620003a162000393565b620003ae81848462000368565b505050565b5b81811015620003d557620003c95f8262000397565b600181019050620003b4565b5050565b601f8211156200042457620003ee81620002a4565b620003f984620002b6565b8101602085101562000409578190505b620004216200041885620002b6565b830182620003b3565b50505b505050565b5f82821c905092915050565b5f620004465f198460080262000429565b1980831691505092915050565b5f62000460838362000435565b9150826002028217905092915050565b6200047b8262000239565b67ffffffffffffffff8111156200049757620004966200008e565b5b620004a3825462000270565b620004b0828285620003d9565b5f60209050601f831160018114620004e6575f8415620004d1578287015190505b620004dd858262000453565b8655506200054c565b601f198416620004f686620002a4565b5f5b828110156200051f57848901518255600182019150602085019450602081019050620004f8565b868310156200053f57848901516200053b601f89168262000435565b8355505b6001600288020188555050505b505050505050565b611f8980620005625f395ff3fe608060405234801561000f575f80fd5b5060043610610090575f3560e01c80634e1273f4116100645780634e1273f414610140578063731133e914610170578063a22cb4651461018c578063e985e9c5146101a8578063f242432a146101d857610090565b8062fdd58e1461009457806301ffc9a7146100c45780630e89341c146100f45780632eb2c2d614610124575b5f80fd5b6100ae60048036038101906100a991906113bd565b6101f4565b6040516100bb919061140a565b60405180910390f35b6100de60048036038101906100d99190611478565b610249565b6040516100eb91906114bd565b60405180910390f35b61010e600480360381019061010991906114d6565b61032a565b60405161011b919061158b565b60405180910390f35b61013e6004803603810190610139919061179b565b6103bc565b005b61015a60048036038101906101559190611926565b610463565b6040516101679190611a53565b60405180910390f35b61018a60048036038101906101859190611a73565b61056a565b005b6101a660048036038101906101a19190611b1d565b61057c565b005b6101c260048036038101906101bd9190611b5b565b610592565b6040516101cf91906114bd565b60405180910390f35b6101f260048036038101906101ed9190611b99565b610620565b005b5f805f8381526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905092915050565b5f7fd9b67a26000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061031357507f0e89341c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806103235750610322826106c7565b5b9050919050565b60606002805461033990611c59565b80601f016020809104026020016040519081016040528092919081815260200182805461036590611c59565b80156103b05780601f10610387576101008083540402835291602001916103b0565b820191905f5260205f20905b81548152906001019060200180831161039357829003601f168201915b50505050509050919050565b5f6103c5610730565b90508073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161415801561040a57506104088682610592565b155b1561044e5780866040517fe237d922000000000000000000000000000000000000000000000000000000008152600401610445929190611c98565b60405180910390fd5b61045b8686868686610737565b505050505050565b606081518351146104af57815183516040517f5b0599910000000000000000000000000000000000000000000000000000000081526004016104a6929190611cbf565b60405180910390fd5b5f835167ffffffffffffffff8111156104cb576104ca6115af565b5b6040519080825280602002602001820160405280156104f95781602001602082028036833780820191505090505b5090505f5b845181101561055f5761053561051d828761082b90919063ffffffff16565b610530838761083e90919063ffffffff16565b6101f4565b82828151811061054857610547611ce6565b5b6020026020010181815250508060010190506104fe565b508091505092915050565b61057684848484610851565b50505050565b61058e610587610730565b83836108e6565b5050565b5f60015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16905092915050565b5f610629610730565b90508073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161415801561066e575061066c8682610592565b155b156106b25780866040517fe237d9220000000000000000000000000000000000000000000000000000000081526004016106a9929190611c98565b60405180910390fd5b6106bf8686868686610a4f565b505050505050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f33905090565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036107a7575f6040517f57f447ce00000000000000000000000000000000000000000000000000000000815260040161079e9190611d13565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603610817575f6040517f01a8351400000000000000000000000000000000000000000000000000000000815260040161080e9190611d13565b60405180910390fd5b6108248585858585610b55565b5050505050565b5f60208202602084010151905092915050565b5f60208202602084010151905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036108c1575f6040517f57f447ce0000000000000000000000000000000000000000000000000000000081526004016108b89190611d13565b60405180910390fd5b5f806108cd8585610c01565b915091506108de5f87848487610b55565b505050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610956575f6040517fced3e10000000000000000000000000000000000000000000000000000000000815260040161094d9190611d13565b60405180910390fd5b8060015f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051610a4291906114bd565b60405180910390a3505050565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610abf575f6040517f57f447ce000000000000000000000000000000000000000000000000000000008152600401610ab69190611d13565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603610b2f575f6040517f01a83514000000000000000000000000000000000000000000000000000000008152600401610b269190611d13565b60405180910390fd5b5f80610b3b8585610c01565b91509150610b4c8787848487610b55565b50505050505050565b610b6185858585610c31565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614610bfa575f610b9d610730565b90506001845103610be9575f610bbc5f8661083e90919063ffffffff16565b90505f610bd25f8661083e90919063ffffffff16565b9050610be2838989858589610fc1565b5050610bf8565b610bf7818787878787611170565b5b505b5050505050565b60608060405191506001825283602083015260408201905060018152826020820152604081016040529250929050565b8051825114610c7b57815181516040517f5b059991000000000000000000000000000000000000000000000000000000008152600401610c72929190611cbf565b60405180910390fd5b5f610c84610730565b90505f5b8351811015610e80575f610ca5828661083e90919063ffffffff16565b90505f610cbb838661083e90919063ffffffff16565b90505f73ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614610dde575f805f8481526020019081526020015f205f8a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905081811015610d8a57888183856040517f03dee4c5000000000000000000000000000000000000000000000000000000008152600401610d819493929190611d2c565b60405180910390fd5b8181035f808581526020019081526020015f205f8b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550505b5f73ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614610e7357805f808481526020019081526020015f205f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610e6b9190611d9c565b925050819055505b5050806001019050610c88565b506001835103610f3b575f610e9e5f8561083e90919063ffffffff16565b90505f610eb45f8561083e90919063ffffffff16565b90508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628585604051610f2c929190611cbf565b60405180910390a45050610fba565b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8686604051610fb1929190611dcf565b60405180910390a45b5050505050565b5f8473ffffffffffffffffffffffffffffffffffffffff163b1115611168578373ffffffffffffffffffffffffffffffffffffffff1663f23a6e6187878686866040518663ffffffff1660e01b8152600401611021959493929190611e56565b6020604051808303815f875af192505050801561105c57506040513d601f19601f820116820180604052508101906110599190611ec2565b60015b6110dd573d805f811461108a576040519150601f19603f3d011682016040523d82523d5f602084013e61108f565b606091505b505f8151036110d557846040517f57f447ce0000000000000000000000000000000000000000000000000000000081526004016110cc9190611d13565b60405180910390fd5b805181602001fd5b63f23a6e6160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461116657846040517f57f447ce00000000000000000000000000000000000000000000000000000000815260040161115d9190611d13565b60405180910390fd5b505b505050505050565b5f8473ffffffffffffffffffffffffffffffffffffffff163b1115611317578373ffffffffffffffffffffffffffffffffffffffff1663bc197c8187878686866040518663ffffffff1660e01b81526004016111d0959493929190611eed565b6020604051808303815f875af192505050801561120b57506040513d601f19601f820116820180604052508101906112089190611ec2565b60015b61128c573d805f8114611239576040519150601f19603f3d011682016040523d82523d5f602084013e61123e565b606091505b505f81510361128457846040517f57f447ce00000000000000000000000000000000000000000000000000000000815260040161127b9190611d13565b60405180910390fd5b805181602001fd5b63bc197c8160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461131557846040517f57f447ce00000000000000000000000000000000000000000000000000000000815260040161130c9190611d13565b60405180910390fd5b505b505050505050565b5f604051905090565b5f80fd5b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61135982611330565b9050919050565b6113698161134f565b8114611373575f80fd5b50565b5f8135905061138481611360565b92915050565b5f819050919050565b61139c8161138a565b81146113a6575f80fd5b50565b5f813590506113b781611393565b92915050565b5f80604083850312156113d3576113d2611328565b5b5f6113e085828601611376565b92505060206113f1858286016113a9565b9150509250929050565b6114048161138a565b82525050565b5f60208201905061141d5f8301846113fb565b92915050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61145781611423565b8114611461575f80fd5b50565b5f813590506114728161144e565b92915050565b5f6020828403121561148d5761148c611328565b5b5f61149a84828501611464565b91505092915050565b5f8115159050919050565b6114b7816114a3565b82525050565b5f6020820190506114d05f8301846114ae565b92915050565b5f602082840312156114eb576114ea611328565b5b5f6114f8848285016113a9565b91505092915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561153857808201518184015260208101905061151d565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61155d82611501565b611567818561150b565b935061157781856020860161151b565b61158081611543565b840191505092915050565b5f6020820190508181035f8301526115a38184611553565b905092915050565b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6115e582611543565b810181811067ffffffffffffffff82111715611604576116036115af565b5b80604052505050565b5f61161661131f565b905061162282826115dc565b919050565b5f67ffffffffffffffff821115611641576116406115af565b5b602082029050602081019050919050565b5f80fd5b5f61166861166384611627565b61160d565b9050808382526020820190506020840283018581111561168b5761168a611652565b5b835b818110156116b457806116a088826113a9565b84526020840193505060208101905061168d565b5050509392505050565b5f82601f8301126116d2576116d16115ab565b5b81356116e2848260208601611656565b91505092915050565b5f80fd5b5f67ffffffffffffffff821115611709576117086115af565b5b61171282611543565b9050602081019050919050565b828183375f83830152505050565b5f61173f61173a846116ef565b61160d565b90508281526020810184848401111561175b5761175a6116eb565b5b61176684828561171f565b509392505050565b5f82601f830112611782576117816115ab565b5b813561179284826020860161172d565b91505092915050565b5f805f805f60a086880312156117b4576117b3611328565b5b5f6117c188828901611376565b95505060206117d288828901611376565b945050604086013567ffffffffffffffff8111156117f3576117f261132c565b5b6117ff888289016116be565b935050606086013567ffffffffffffffff8111156118205761181f61132c565b5b61182c888289016116be565b925050608086013567ffffffffffffffff81111561184d5761184c61132c565b5b6118598882890161176e565b9150509295509295909350565b5f67ffffffffffffffff8211156118805761187f6115af565b5b602082029050602081019050919050565b5f6118a361189e84611866565b61160d565b905080838252602082019050602084028301858111156118c6576118c5611652565b5b835b818110156118ef57806118db8882611376565b8452602084019350506020810190506118c8565b5050509392505050565b5f82601f83011261190d5761190c6115ab565b5b813561191d848260208601611891565b91505092915050565b5f806040838503121561193c5761193b611328565b5b5f83013567ffffffffffffffff8111156119595761195861132c565b5b611965858286016118f9565b925050602083013567ffffffffffffffff8111156119865761198561132c565b5b611992858286016116be565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b6119ce8161138a565b82525050565b5f6119df83836119c5565b60208301905092915050565b5f602082019050919050565b5f611a018261199c565b611a0b81856119a6565b9350611a16836119b6565b805f5b83811015611a46578151611a2d88826119d4565b9750611a38836119eb565b925050600181019050611a19565b5085935050505092915050565b5f6020820190508181035f830152611a6b81846119f7565b905092915050565b5f805f8060808587031215611a8b57611a8a611328565b5b5f611a9887828801611376565b9450506020611aa9878288016113a9565b9350506040611aba878288016113a9565b925050606085013567ffffffffffffffff811115611adb57611ada61132c565b5b611ae78782880161176e565b91505092959194509250565b611afc816114a3565b8114611b06575f80fd5b50565b5f81359050611b1781611af3565b92915050565b5f8060408385031215611b3357611b32611328565b5b5f611b4085828601611376565b9250506020611b5185828601611b09565b9150509250929050565b5f8060408385031215611b7157611b70611328565b5b5f611b7e85828601611376565b9250506020611b8f85828601611376565b9150509250929050565b5f805f805f60a08688031215611bb257611bb1611328565b5b5f611bbf88828901611376565b9550506020611bd088828901611376565b9450506040611be1888289016113a9565b9350506060611bf2888289016113a9565b925050608086013567ffffffffffffffff811115611c1357611c1261132c565b5b611c1f8882890161176e565b9150509295509295909350565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680611c7057607f821691505b602082108103611c8357611c82611c2c565b5b50919050565b611c928161134f565b82525050565b5f604082019050611cab5f830185611c89565b611cb86020830184611c89565b9392505050565b5f604082019050611cd25f8301856113fb565b611cdf60208301846113fb565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f602082019050611d265f830184611c89565b92915050565b5f608082019050611d3f5f830187611c89565b611d4c60208301866113fb565b611d5960408301856113fb565b611d6660608301846113fb565b95945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f611da68261138a565b9150611db18361138a565b9250828201905080821115611dc957611dc8611d6f565b5b92915050565b5f6040820190508181035f830152611de781856119f7565b90508181036020830152611dfb81846119f7565b90509392505050565b5f81519050919050565b5f82825260208201905092915050565b5f611e2882611e04565b611e328185611e0e565b9350611e4281856020860161151b565b611e4b81611543565b840191505092915050565b5f60a082019050611e695f830188611c89565b611e766020830187611c89565b611e8360408301866113fb565b611e9060608301856113fb565b8181036080830152611ea28184611e1e565b90509695505050505050565b5f81519050611ebc8161144e565b92915050565b5f60208284031215611ed757611ed6611328565b5b5f611ee484828501611eae565b91505092915050565b5f60a082019050611f005f830188611c89565b611f0d6020830187611c89565b8181036040830152611f1f81866119f7565b90508181036060830152611f3381856119f7565b90508181036080830152611f478184611e1e565b9050969550505050505056fea26469706673582212203835581c6344b12728c44fa4d9e912cd60e64012c1b772bb703d1c36825c16fd64736f6c63430008180033"; -pub const NFT_SWAP_CONTRACT_BYTES: &str = "60a060405234801562000010575f80fd5b50604051620055a2380380620055a2833981810160405281019062000036919062000147565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603620000a7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200009e90620001fb565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff1681525050506200021b565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6200011182620000e6565b9050919050565b620001238162000105565b81146200012e575f80fd5b50565b5f81519050620001418162000118565b92915050565b5f602082840312156200015f576200015e620000e2565b5b5f6200016e8482850162000131565b91505092915050565b5f82825260208201905092915050565b7f66656541646472657373206d757374206e6f74206265207a65726f20616464725f8201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b5f620001e360238362000177565b9150620001f08262000187565b604082019050919050565b5f6020820190508181035f8301526200021481620001d5565b9050919050565b608051615360620002425f395f81816127c10152818161285c0152612c1a01526153605ff3fe608060405260043610610113575f3560e01c80639b4603f21161009f578063d6a71eb411610063578063d6a71eb41461038e578063e06cf966146103b6578063efccb9eb146103e0578063f23a6e611461041e578063fc45ef821461045a57610113565b80639b4603f2146102be578063ba157104146102da578063bc197c8114610302578063c8d9009b1461033e578063cc90c1991461036657610113565b806332c7d4f8116100e657806332c7d4f8146101df5780633e6af5f21461020757806346b95ac71461022f57806365e266171461026e5780636e6bf6d21461029657610113565b806301ffc9a7146101175780630f235fce14610153578063146e5b241461017b578063150b7a02146101a3575b5f80fd5b348015610122575f80fd5b5061013d6004803603810190610138919061386f565b610482565b60405161014a91906138b4565b60405180910390f35b34801561015e575f80fd5b506101796004803603810190610174919061398d565b610563565b005b348015610186575f80fd5b506101a1600480360381019061019c9190613a16565b61081d565b005b3480156101ae575f80fd5b506101c960048036038101906101c49190613b14565b610a03565b6040516101d69190613ba7565b60405180910390f35b3480156101ea575f80fd5b5061020560048036038101906102009190613bc0565b610e52565b005b348015610212575f80fd5b5061022d60048036038101906102289190613a16565b611111565b005b34801561023a575f80fd5b5061025560048036038101906102509190613c5d565b611422565b6040516102659493929190613d53565b60405180910390f35b348015610279575f80fd5b50610294600480360381019061028f9190613a16565b611484565b005b3480156102a1575f80fd5b506102bc60048036038101906102b7919061398d565b6118e8565b005b6102d860048036038101906102d39190613dc0565b611ba3565b005b3480156102e5575f80fd5b5061030060048036038101906102fb9190613bc0565b611ed9565b005b34801561030d575f80fd5b5061032860048036038101906103239190613eb2565b612199565b6040516103359190613ba7565b60405180910390f35b348015610349575f80fd5b50610364600480360381019061035f919061398d565b6121d5565b005b348015610371575f80fd5b5061038c60048036038101906103879190613a16565b6124fe565b005b348015610399575f80fd5b506103b460048036038101906103af9190613f89565b6128ae565b005b3480156103c1575f80fd5b506103ca612c18565b6040516103d7919061405c565b60405180910390f35b3480156103eb575f80fd5b5061040660048036038101906104019190613c5d565b612c3c565b604051610415939291906140bb565b60405180910390f35b348015610429575f80fd5b50610444600480360381019061043f91906140f0565b612c88565b6040516104519190613ba7565b60405180910390f35b348015610465575f80fd5b50610480600480360381019061047b9190613bc0565b61311c565b005b5f7f4e2312e0000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061054c57507f150b7a02000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061055c575061055b8261344a565b5b9050919050565b6001600381111561057757610576613ce0565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff1660038111156105a9576105a8613ce0565b5b146105e9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105e090614206565b60405180910390fd5b5f6003863387878787604051602001610607969594939291906142a9565b6040516020818303038152906040526040516106239190614384565b602060405180830381855afa15801561063e573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146106c8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106bf906143e4565b60405180910390fd5b5f808881526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff16421015610733576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161072a90614472565b60405180910390fd5b60035f808981526020019081526020015f205f0160186101000a81548160ff0219169083600381111561076957610768613ce0565b5b02179055507f5dedc4f52b757d9112d09ca0b2f022927104d54e3f54da091587e8ad192190728760405161079d919061449f565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b81526004016107e6939291906144c7565b5f604051808303815f87803b1580156107fd575f80fd5b505af115801561080f573d5f803e3d5ffd5b505050505050505050505050565b6001600481111561083157610830613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff16600481111561086457610863613ce0565b5b146108a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161089b90614206565b60405180910390fd5b5f6003878787338888886040516020016108c497969594939291906144fc565b6040516020818303038152906040526040516108e09190614384565b602060405180830381855afa1580156108fb573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610986576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161097d906143e4565b60405180910390fd5b600260015f8a81526020019081526020015f205f01601c6101000a81548160ff021916908360048111156109bd576109bc613ce0565b5b02179055507f9c45e43e2ef051f70491ffd5221bf02ab37e1324128714ef9610df5f24fc9fb5886040516109f1919061449f565b60405180910390a15050505050505050565b5f808383810190610a1491906146a5565b90505f73ffffffffffffffffffffffffffffffffffffffff16816020015173ffffffffffffffffffffffffffffffffffffffff1603610a88576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a7f9061471a565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816040015173ffffffffffffffffffffffffffffffffffffffff1603610afa576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610af190614782565b60405180910390fd5b806040015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610b6c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b6390614810565b60405180910390fd5b8573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614610bda576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bd190614878565b60405180910390fd5b5f6003811115610bed57610bec613ce0565b5b5f80835f015181526020019081526020015f205f0160189054906101000a900460ff166003811115610c2257610c21613ce0565b5b14610c62576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c5990614906565b60405180910390fd5b610c6f81602001516134b3565b15610caf576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ca69061496e565b60405180910390fd5b5f60038260200151888460600151856080015186604001518b604051602001610cdd969594939291906142a9565b604051602081830303815290604052604051610cf99190614384565b602060405180830381855afa158015610d14573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018360a0015163ffffffff16815260200160016003811115610d6457610d63613ce0565b5b8152505f80845f015181526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548160ff02191690836003811115610dfb57610dfa613ce0565b5b02179055509050507ff1dc11bbb6d7542c4267ecf1d370ff4c7092518633ecae9939e8488f4e53d2ad825f0151604051610e35919061449f565b60405180910390a163150b7a0260e01b9250505095945050505050565b60016003811115610e6657610e65613ce0565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff166003811115610e9857610e97613ce0565b5b14610ed8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ecf90614206565b60405180910390fd5b5f60038633878787878d604051602001610ef8979695949392919061498c565b604051602081830303815290604052604051610f149190614384565b602060405180830381855afa158015610f2f573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610fb9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fb0906143e4565b60405180910390fd5b5f808981526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff16421015611024576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161101b90614472565b60405180910390fd5b60035f808a81526020019081526020015f205f0160186101000a81548160ff0219169083600381111561105a57611059613ce0565b5b02179055507f5dedc4f52b757d9112d09ca0b2f022927104d54e3f54da091587e8ad192190728860405161108e919061449f565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff1663f242432a3033868c6040518563ffffffff1660e01b81526004016110d99493929190614a3f565b5f604051808303815f87803b1580156110f0575f80fd5b505af1158015611102573d5f803e3d5ffd5b50505050505050505050505050565b6001600481111561112557611124613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff16600481111561115857611157613ce0565b5b14611198576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161118f90614206565b60405180910390fd5b5f6003878787336002896040516020016111b29190614a95565b6040516020818303038152906040526040516111ce9190614384565b602060405180830381855afa1580156111e9573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061120c9190614ac3565b888860405160200161122497969594939291906144fc565b6040516020818303038152906040526040516112409190614384565b602060405180830381855afa15801561125b573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146112e6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112dd906143e4565b60405180910390fd5b600460015f8a81526020019081526020015f205f01601c6101000a81548160ff0219169083600481111561131d5761131c613ce0565b5b02179055507f45169a52eef651b20a81474b50b8a5d83225225fcd097ef3cf7952d9ab304f278885604051611353929190614aee565b60405180910390a15f86886113689190614b42565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036113e6573373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f193505050501580156113e0573d5f803e3d5ffd5b50611417565b5f83905061141533838373ffffffffffffffffffffffffffffffffffffffff166134c49092919063ffffffff16565b505b505050505050505050565b6001602052805f5260405f205f91509050805f015f9054906101000a900460601b90805f0160149054906101000a900463ffffffff1690805f0160189054906101000a900463ffffffff1690805f01601c9054906101000a900460ff16905084565b6001600481111561149857611497613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff1660048111156114cb576114ca613ce0565b5b148061151b5750600260048111156114e6576114e5613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff16600481111561151957611518613ce0565b5b145b61155a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161155190614be5565b60405180910390fd5b5f60038787873388888860405160200161157a97969594939291906144fc565b6040516020818303038152906040526040516115969190614384565b602060405180830381855afa1580156115b1573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461163c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611633906143e4565b60405180910390fd5b600260048111156116505761164f613ce0565b5b60015f8a81526020019081526020015f205f01601c9054906101000a900460ff16600481111561168357611682613ce0565b5b036116f55760015f8981526020019081526020015f205f0160189054906101000a900463ffffffff1663ffffffff164210156116f4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116eb90614472565b60405180910390fd5b5b6001600481111561170957611708613ce0565b5b60015f8a81526020019081526020015f205f01601c9054906101000a900460ff16600481111561173c5761173b613ce0565b5b036117ae5760015f8981526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff164210156117ad576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117a490614c73565b60405180910390fd5b5b600460015f8a81526020019081526020015f205f01601c6101000a81548160ff021916908360048111156117e5576117e4613ce0565b5b02179055507fbdd7a4be6d82798a500b59077706b12d3f45acf5504828919f92501307b2b95388604051611819919061449f565b60405180910390a15f868861182e9190614b42565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036118ac573373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f193505050501580156118a6573d5f803e3d5ffd5b506118dd565b5f8390506118db33838373ffffffffffffffffffffffffffffffffffffffff166134c49092919063ffffffff16565b505b505050505050505050565b600160038111156118fc576118fb613ce0565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff16600381111561192e5761192d613ce0565b5b1461196e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161196590614206565b60405180910390fd5b5f600386336002886040516020016119869190614a95565b6040516020818303038152906040526040516119a29190614384565b602060405180830381855afa1580156119bd573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906119e09190614ac3565b8787876040516020016119f8969594939291906142a9565b604051602081830303815290604052604051611a149190614384565b602060405180830381855afa158015611a2f573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614611ab9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ab0906143e4565b60405180910390fd5b60035f808981526020019081526020015f205f0160186101000a81548160ff02191690836003811115611aef57611aee613ce0565b5b02179055507fac509cdcc7ddb189f81fff6f4824f5c95076e64c3bdce542c50feaa6779afd7387604051611b23919061449f565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b8152600401611b6c939291906144c7565b5f604051808303815f87803b158015611b83575f80fd5b505af1158015611b95573d5f803e3d5ffd5b505050505050505050505050565b5f6004811115611bb657611bb5613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff166004811115611be957611be8613ce0565b5b14611c29576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c2090614d01565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603611c97576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c8e90614d8f565b60405180910390fd5b5f3411611cd9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611cd090614e1d565b60405180910390fd5b853411611d1b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d1290614eab565b60405180910390fd5b5f60038734611d2a9190614ec9565b88883389895f604051602001611d4697969594939291906144fc565b604051602081830303815290604052604051611d629190614384565b602060405180830381855afa158015611d7d573d5f803e3d5ffd5b5050506040515160601b90506040518060800160405280826bffffffffffffffffffffffff191681526020018463ffffffff1681526020018363ffffffff16815260200160016004811115611dd557611dd4613ce0565b5b81525060015f8a81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548163ffffffff021916908363ffffffff1602179055506060820151815f01601c6101000a81548160ff02191690836004811115611e9057611e8f613ce0565b5b02179055509050507ffc6cdccd1d98ded12074a9ebc7f6ab74fed1814ff57f4fb5202464d8938bd93588604051611ec7919061449f565b60405180910390a15050505050505050565b60016003811115611eed57611eec613ce0565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff166003811115611f1f57611f1e613ce0565b5b14611f5f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f5690614206565b60405180910390fd5b5f60038633600288604051602001611f779190614a95565b604051602081830303815290604052604051611f939190614384565b602060405180830381855afa158015611fae573d5f803e3d5ffd5b5050506040513d601f19601f82011682018060405250810190611fd19190614ac3565b8787878d604051602001611feb979695949392919061498c565b6040516020818303038152906040526040516120079190614384565b602060405180830381855afa158015612022573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146120ac576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120a3906143e4565b60405180910390fd5b60035f808a81526020019081526020015f205f0160186101000a81548160ff021916908360038111156120e2576120e1613ce0565b5b02179055507fac509cdcc7ddb189f81fff6f4824f5c95076e64c3bdce542c50feaa6779afd7388604051612116919061449f565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff1663f242432a3033868c6040518563ffffffff1660e01b81526004016121619493929190614a3f565b5f604051808303815f87803b158015612178575f80fd5b505af115801561218a573d5f803e3d5ffd5b50505050505050505050505050565b5f6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016121cc90614f46565b60405180910390fd5b600160038111156121e9576121e8613ce0565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff16600381111561221b5761221a613ce0565b5b1461225b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161225290614206565b60405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146122c9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122c090614fae565b60405180910390fd5b5f60033387876002886040516020016122e29190614a95565b6040516020818303038152906040526040516122fe9190614384565b602060405180830381855afa158015612319573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061233c9190614ac3565b8787604051602001612353969594939291906142a9565b60405160208183030381529060405260405161236f9190614384565b602060405180830381855afa15801561238a573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614612414576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161240b906143e4565b60405180910390fd5b60025f808981526020019081526020015f205f0160186101000a81548160ff0219169083600381111561244a57612449613ce0565b5b02179055507fad62ed075fe8969df63026f45152d6e996a0697a736a8de92ee85ae9c9958cf08760405161247e919061449f565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b81526004016124c7939291906144c7565b5f604051808303815f87803b1580156124de575f80fd5b505af11580156124f0573d5f803e3d5ffd5b505050505050505050505050565b6002600481111561251257612511613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff16600481111561254557612544613ce0565b5b14612585576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161257c9061503c565b60405180910390fd5b5f600387873388886002896040516020016125a09190614a95565b6040516020818303038152906040526040516125bc9190614384565b602060405180830381855afa1580156125d7573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906125fa9190614ac3565b8860405160200161261197969594939291906144fc565b60405160208183030381529060405260405161262d9190614384565b602060405180830381855afa158015612648573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146126d3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016126ca906143e4565b60405180910390fd5b600360015f8a81526020019081526020015f205f01601c6101000a81548160ff0219169083600481111561270a57612709613ce0565b5b02179055507f0d0da0df275f85bed3a5fe7ae79f3559341a3f9ccd8e010133438135bda00a878884604051612740929190614aee565b60405180910390a15f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612828573373ffffffffffffffffffffffffffffffffffffffff166108fc8890811502906040515f60405180830381858888f193505050501580156127be573d5f803e3d5ffd5b507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166108fc8790811502906040515f60405180830381858888f19350505050158015612822573d5f803e3d5ffd5b506128a4565b5f82905061285733898373ffffffffffffffffffffffffffffffffffffffff166134c49092919063ffffffff16565b6128a27f0000000000000000000000000000000000000000000000000000000000000000888373ffffffffffffffffffffffffffffffffffffffff166134c49092919063ffffffff16565b505b5050505050505050565b5f60048111156128c1576128c0613ce0565b5b60015f8b81526020019081526020015f205f01601c9054906101000a900460ff1660048111156128f4576128f3613ce0565b5b14612934576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161292b906150ca565b60405180910390fd5b5f8811612976576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161296d90615132565b60405180910390fd5b5f87116129b8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129af9061519a565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603612a26576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612a1d90614d8f565b60405180910390fd5b5f60038989883389898d604051602001612a4697969594939291906144fc565b604051602081830303815290604052604051612a629190614384565b602060405180830381855afa158015612a7d573d5f803e3d5ffd5b5050506040515160601b90506040518060800160405280826bffffffffffffffffffffffff191681526020018463ffffffff1681526020018363ffffffff16815260200160016004811115612ad557612ad4613ce0565b5b81525060015f8c81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548163ffffffff021916908363ffffffff1602179055506060820151815f01601c6101000a81548160ff02191690836004811115612b9057612b8f613ce0565b5b02179055509050507ffc6cdccd1d98ded12074a9ebc7f6ab74fed1814ff57f4fb5202464d8938bd9358a604051612bc7919061449f565b60405180910390a15f879050612c0b33308b8d612be49190614b42565b8473ffffffffffffffffffffffffffffffffffffffff16613543909392919063ffffffff16565b5050505050505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b5f602052805f5260405f205f91509050805f015f9054906101000a900460601b90805f0160149054906101000a900463ffffffff1690805f0160189054906101000a900460ff16905083565b5f808383810190612c9991906146a5565b90505f73ffffffffffffffffffffffffffffffffffffffff16816020015173ffffffffffffffffffffffffffffffffffffffff1603612d0d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612d049061471a565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816040015173ffffffffffffffffffffffffffffffffffffffff1603612d7f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612d7690614782565b60405180910390fd5b806040015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612df1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612de890614810565b60405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614612e5f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612e5690614878565b60405180910390fd5b5f8511612ea1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612e9890615202565b60405180910390fd5b5f6003811115612eb457612eb3613ce0565b5b5f80835f015181526020019081526020015f205f0160189054906101000a900460ff166003811115612ee957612ee8613ce0565b5b14612f29576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612f2090615290565b60405180910390fd5b612f3681602001516134b3565b15612f76576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612f6d9061496e565b60405180910390fd5b5f60038260200151898460600151856080015186604001518c8c604051602001612fa6979695949392919061498c565b604051602081830303815290604052604051612fc29190614384565b602060405180830381855afa158015612fdd573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018360a0015163ffffffff1681526020016001600381111561302d5761302c613ce0565b5b8152505f80845f015181526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548160ff021916908360038111156130c4576130c3613ce0565b5b02179055509050507ff1dc11bbb6d7542c4267ecf1d370ff4c7092518633ecae9939e8488f4e53d2ad825f01516040516130fe919061449f565b60405180910390a163f23a6e6160e01b925050509695505050505050565b600160038111156131305761312f613ce0565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff16600381111561316257613161613ce0565b5b146131a2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161319990614206565b60405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614613210576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161320790614fae565b60405180910390fd5b5f60033387876002886040516020016132299190614a95565b6040516020818303038152906040526040516132459190614384565b602060405180830381855afa158015613260573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906132839190614ac3565b87878d60405160200161329c979695949392919061498c565b6040516020818303038152906040526040516132b89190614384565b602060405180830381855afa1580156132d3573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461335d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613354906143e4565b60405180910390fd5b60025f808a81526020019081526020015f205f0160186101000a81548160ff0219169083600381111561339357613392613ce0565b5b02179055507fad62ed075fe8969df63026f45152d6e996a0697a736a8de92ee85ae9c9958cf0886040516133c7919061449f565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff1663f242432a3033868c6040518563ffffffff1660e01b81526004016134129493929190614a3f565b5f604051808303815f87803b158015613429575f80fd5b505af115801561343b573d5f803e3d5ffd5b50505050505050505050505050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f80823b90505f8111915050919050565b61353e838473ffffffffffffffffffffffffffffffffffffffff1663a9059cbb85856040516024016134f79291906152ae565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506135c5565b505050565b6135bf848573ffffffffffffffffffffffffffffffffffffffff166323b872dd868686604051602401613578939291906144c7565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506135c5565b50505050565b5f6135ef828473ffffffffffffffffffffffffffffffffffffffff1661365a90919063ffffffff16565b90505f81511415801561361357508080602001905181019061361191906152ff565b155b1561365557826040517f5274afe700000000000000000000000000000000000000000000000000000000815260040161364c919061405c565b60405180910390fd5b505050565b606061366783835f61366f565b905092915050565b6060814710156136b657306040517fcd7860590000000000000000000000000000000000000000000000000000000081526004016136ad919061405c565b60405180910390fd5b5f808573ffffffffffffffffffffffffffffffffffffffff1684866040516136de9190614384565b5f6040518083038185875af1925050503d805f8114613718576040519150601f19603f3d011682016040523d82523d5f602084013e61371d565b606091505b509150915061372d868383613738565b925050509392505050565b60608261374d57613748826137c5565b6137bd565b5f825114801561377357505f8473ffffffffffffffffffffffffffffffffffffffff163b145b156137b557836040517f9996b3150000000000000000000000000000000000000000000000000000000081526004016137ac919061405c565b60405180910390fd5b8190506137be565b5b9392505050565b5f815111156137d75780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61384e8161381a565b8114613858575f80fd5b50565b5f8135905061386981613845565b92915050565b5f6020828403121561388457613883613812565b5b5f6138918482850161385b565b91505092915050565b5f8115159050919050565b6138ae8161389a565b82525050565b5f6020820190506138c75f8301846138a5565b92915050565b5f819050919050565b6138df816138cd565b81146138e9575f80fd5b50565b5f813590506138fa816138d6565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61392982613900565b9050919050565b6139398161391f565b8114613943575f80fd5b50565b5f8135905061395481613930565b92915050565b5f819050919050565b61396c8161395a565b8114613976575f80fd5b50565b5f8135905061398781613963565b92915050565b5f805f805f8060c087890312156139a7576139a6613812565b5b5f6139b489828a016138ec565b96505060206139c589828a01613946565b95505060406139d689828a016138ec565b94505060606139e789828a016138ec565b93505060806139f889828a01613946565b92505060a0613a0989828a01613979565b9150509295509295509295565b5f805f805f805f60e0888a031215613a3157613a30613812565b5b5f613a3e8a828b016138ec565b9750506020613a4f8a828b01613979565b9650506040613a608a828b01613979565b9550506060613a718a828b01613946565b9450506080613a828a828b016138ec565b93505060a0613a938a828b016138ec565b92505060c0613aa48a828b01613946565b91505092959891949750929550565b5f80fd5b5f80fd5b5f80fd5b5f8083601f840112613ad457613ad3613ab3565b5b8235905067ffffffffffffffff811115613af157613af0613ab7565b5b602083019150836001820283011115613b0d57613b0c613abb565b5b9250929050565b5f805f805f60808688031215613b2d57613b2c613812565b5b5f613b3a88828901613946565b9550506020613b4b88828901613946565b9450506040613b5c88828901613979565b935050606086013567ffffffffffffffff811115613b7d57613b7c613816565b5b613b8988828901613abf565b92509250509295509295909350565b613ba18161381a565b82525050565b5f602082019050613bba5f830184613b98565b92915050565b5f805f805f805f60e0888a031215613bdb57613bda613812565b5b5f613be88a828b016138ec565b9750506020613bf98a828b01613979565b9650506040613c0a8a828b01613946565b9550506060613c1b8a828b016138ec565b9450506080613c2c8a828b016138ec565b93505060a0613c3d8a828b01613946565b92505060c0613c4e8a828b01613979565b91505092959891949750929550565b5f60208284031215613c7257613c71613812565b5b5f613c7f848285016138ec565b91505092915050565b5f7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b613cbc81613c88565b82525050565b5f63ffffffff82169050919050565b613cda81613cc2565b82525050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60058110613d1e57613d1d613ce0565b5b50565b5f819050613d2e82613d0d565b919050565b5f613d3d82613d21565b9050919050565b613d4d81613d33565b82525050565b5f608082019050613d665f830187613cb3565b613d736020830186613cd1565b613d806040830185613cd1565b613d8d6060830184613d44565b95945050505050565b613d9f81613cc2565b8114613da9575f80fd5b50565b5f81359050613dba81613d96565b92915050565b5f805f805f805f60e0888a031215613ddb57613dda613812565b5b5f613de88a828b016138ec565b9750506020613df98a828b01613979565b9650506040613e0a8a828b01613946565b9550506060613e1b8a828b016138ec565b9450506080613e2c8a828b016138ec565b93505060a0613e3d8a828b01613dac565b92505060c0613e4e8a828b01613dac565b91505092959891949750929550565b5f8083601f840112613e7257613e71613ab3565b5b8235905067ffffffffffffffff811115613e8f57613e8e613ab7565b5b602083019150836020820283011115613eab57613eaa613abb565b5b9250929050565b5f805f805f805f8060a0898b031215613ece57613ecd613812565b5b5f613edb8b828c01613946565b9850506020613eec8b828c01613946565b975050604089013567ffffffffffffffff811115613f0d57613f0c613816565b5b613f198b828c01613e5d565b9650965050606089013567ffffffffffffffff811115613f3c57613f3b613816565b5b613f488b828c01613e5d565b9450945050608089013567ffffffffffffffff811115613f6b57613f6a613816565b5b613f778b828c01613abf565b92509250509295985092959890939650565b5f805f805f805f805f6101208a8c031215613fa757613fa6613812565b5b5f613fb48c828d016138ec565b9950506020613fc58c828d01613979565b9850506040613fd68c828d01613979565b9750506060613fe78c828d01613946565b9650506080613ff88c828d01613946565b95505060a06140098c828d016138ec565b94505060c061401a8c828d016138ec565b93505060e061402b8c828d01613dac565b92505061010061403d8c828d01613dac565b9150509295985092959850929598565b6140568161391f565b82525050565b5f60208201905061406f5f83018461404d565b92915050565b6004811061408657614085613ce0565b5b50565b5f81905061409682614075565b919050565b5f6140a582614089565b9050919050565b6140b58161409b565b82525050565b5f6060820190506140ce5f830186613cb3565b6140db6020830185613cd1565b6140e860408301846140ac565b949350505050565b5f805f805f8060a0878903121561410a57614109613812565b5b5f61411789828a01613946565b965050602061412889828a01613946565b955050604061413989828a01613979565b945050606061414a89828a01613979565b935050608087013567ffffffffffffffff81111561416b5761416a613816565b5b61417789828a01613abf565b92509250509295509295509295565b5f82825260208201905092915050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520505f8201527f61796d656e7453656e7400000000000000000000000000000000000000000000602082015250565b5f6141f0602a83614186565b91506141fb82614196565b604082019050919050565b5f6020820190508181035f83015261421d816141e4565b9050919050565b5f8160601b9050919050565b5f61423a82614224565b9050919050565b5f61424b82614230565b9050919050565b61426361425e8261391f565b614241565b82525050565b5f819050919050565b61428361427e826138cd565b614269565b82525050565b5f819050919050565b6142a361429e8261395a565b614289565b82525050565b5f6142b48289614252565b6014820191506142c48288614252565b6014820191506142d48287614272565b6020820191506142e48286614272565b6020820191506142f48285614252565b6014820191506143048284614292565b602082019150819050979650505050505050565b5f81519050919050565b5f81905092915050565b5f5b8381101561434957808201518184015260208101905061432e565b5f8484015250505050565b5f61435e82614318565b6143688185614322565b935061437881856020860161432c565b80840191505092915050565b5f61438f8284614354565b915081905092915050565b7f496e76616c6964207061796d656e7448617368000000000000000000000000005f82015250565b5f6143ce601383614186565b91506143d98261439a565b602082019050919050565b5f6020820190508181035f8301526143fb816143c2565b9050919050565b7f43757272656e742074696d657374616d70206469646e277420657863656564205f8201527f7061796d656e7420726566756e64206c6f636b2074696d650000000000000000602082015250565b5f61445c603883614186565b915061446782614402565b604082019050919050565b5f6020820190508181035f83015261448981614450565b9050919050565b614499816138cd565b82525050565b5f6020820190506144b25f830184614490565b92915050565b6144c18161395a565b82525050565b5f6060820190506144da5f83018661404d565b6144e7602083018561404d565b6144f460408301846144b8565b949350505050565b5f614507828a614292565b6020820191506145178289614292565b6020820191506145278288614252565b6014820191506145378287614252565b6014820191506145478286614272565b6020820191506145578285614272565b6020820191506145678284614252565b60148201915081905098975050505050505050565b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6145c682614580565b810181811067ffffffffffffffff821117156145e5576145e4614590565b5b80604052505050565b5f6145f7613809565b905061460382826145bd565b919050565b5f60c0828403121561461d5761461c61457c565b5b61462760c06145ee565b90505f614636848285016138ec565b5f83015250602061464984828501613946565b602083015250604061465d84828501613946565b6040830152506060614671848285016138ec565b6060830152506080614685848285016138ec565b60808301525060a061469984828501613dac565b60a08301525092915050565b5f60c082840312156146ba576146b9613812565b5b5f6146c784828501614608565b91505092915050565b7f54616b6572206d757374206e6f74206265207a65726f206164647265737300005f82015250565b5f614704601e83614186565b915061470f826146d0565b602082019050919050565b5f6020820190508181035f830152614731816146f8565b9050919050565b7f546f6b656e206d757374206e6f74206265207a65726f206164647265737300005f82015250565b5f61476c601e83614186565b915061477782614738565b602082019050919050565b5f6020820190508181035f83015261479981614760565b9050919050565b7f546f6b656e206164647265737320646f6573206e6f74206d617463682073656e5f8201527f6465720000000000000000000000000000000000000000000000000000000000602082015250565b5f6147fa602383614186565b9150614805826147a0565b604082019050919050565b5f6020820190508181035f830152614827816147ee565b9050919050565b7f4f70657261746f72206d757374206265207468652073656e64657200000000005f82015250565b5f614862601b83614186565b915061486d8261482e565b602082019050919050565b5f6020820190508181035f83015261488f81614856565b9050919050565b7f4d616b657220455243373231207061796d656e74206d75737420626520556e695f8201527f6e697469616c697a656400000000000000000000000000000000000000000000602082015250565b5f6148f0602a83614186565b91506148fb82614896565b604082019050919050565b5f6020820190508181035f83015261491d816148e4565b9050919050565b7f54616b65722063616e6e6f74206265206120636f6e74726163740000000000005f82015250565b5f614958601a83614186565b915061496382614924565b602082019050919050565b5f6020820190508181035f8301526149858161494c565b9050919050565b5f614997828a614252565b6014820191506149a78289614252565b6014820191506149b78288614272565b6020820191506149c78287614272565b6020820191506149d78286614252565b6014820191506149e78285614292565b6020820191506149f78284614292565b60208201915081905098975050505050505050565b5f82825260208201905092915050565b50565b5f614a2a5f83614a0c565b9150614a3582614a1c565b5f82019050919050565b5f60a082019050614a525f83018761404d565b614a5f602083018661404d565b614a6c60408301856144b8565b614a7960608301846144b8565b8181036080830152614a8a81614a1f565b905095945050505050565b5f614aa08284614272565b60208201915081905092915050565b5f81519050614abd816138d6565b92915050565b5f60208284031215614ad857614ad7613812565b5b5f614ae584828501614aaf565b91505092915050565b5f604082019050614b015f830185614490565b614b0e6020830184614490565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f614b4c8261395a565b9150614b578361395a565b9250828201905080821115614b6f57614b6e614b15565b5b92915050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520505f8201527f61796d656e7453656e74206f722054616b6572417070726f7665640000000000602082015250565b5f614bcf603b83614186565b9150614bda82614b75565b604082019050919050565b5f6020820190508181035f830152614bfc81614bc3565b9050919050565b7f43757272656e742074696d657374616d70206469646e277420657863656564205f8201527f7061796d656e74207072652d617070726f7665206c6f636b2074696d65000000602082015250565b5f614c5d603d83614186565b9150614c6882614c03565b604082019050919050565b5f6020820190508181035f830152614c8a81614c51565b9050919050565b7f54616b6572207061796d656e7420697320616c726561647920696e697469616c5f8201527f697a656400000000000000000000000000000000000000000000000000000000602082015250565b5f614ceb602483614186565b9150614cf682614c91565b604082019050919050565b5f6020820190508181035f830152614d1881614cdf565b9050919050565b7f5265636569766572206d757374206e6f74206265207a65726f206164647265735f8201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b5f614d79602183614186565b9150614d8482614d1f565b604082019050919050565b5f6020820190508181035f830152614da681614d6d565b9050919050565b7f4554482076616c7565206d7573742062652067726561746572207468616e207a5f8201527f65726f0000000000000000000000000000000000000000000000000000000000602082015250565b5f614e07602383614186565b9150614e1282614dad565b604082019050919050565b5f6020820190508181035f830152614e3481614dfb565b9050919050565b7f4554482076616c7565206d7573742062652067726561746572207468616e20645f8201527f6578206665650000000000000000000000000000000000000000000000000000602082015250565b5f614e95602683614186565b9150614ea082614e3b565b604082019050919050565b5f6020820190508181035f830152614ec281614e89565b9050919050565b5f614ed38261395a565b9150614ede8361395a565b9250828203905081811115614ef657614ef5614b15565b5b92915050565b7f4261746368207472616e7366657273206e6f7420737570706f727465640000005f82015250565b5f614f30601d83614186565b9150614f3b82614efc565b602082019050919050565b5f6020820190508181035f830152614f5d81614f24565b9050919050565b7f43616c6c6572206d75737420626520616e20454f4100000000000000000000005f82015250565b5f614f98601583614186565b9150614fa382614f64565b602082019050919050565b5f6020820190508181035f830152614fc581614f8c565b9050919050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520545f8201527f616b6572417070726f7665640000000000000000000000000000000000000000602082015250565b5f615026602c83614186565b915061503182614fcc565b604082019050919050565b5f6020820190508181035f8301526150538161501a565b9050919050565b7f4552433230207632207061796d656e7420697320616c726561647920696e69745f8201527f69616c697a656400000000000000000000000000000000000000000000000000602082015250565b5f6150b4602783614186565b91506150bf8261505a565b604082019050919050565b5f6020820190508181035f8301526150e1816150a8565b9050919050565b7f416d6f756e74206d757374206e6f74206265207a65726f0000000000000000005f82015250565b5f61511c601783614186565b9150615127826150e8565b602082019050919050565b5f6020820190508181035f83015261514981615110565b9050919050565b7f44657820666565206d757374206e6f74206265207a65726f00000000000000005f82015250565b5f615184601883614186565b915061518f82615150565b602082019050919050565b5f6020820190508181035f8301526151b181615178565b9050919050565b7f56616c7565206d7573742062652067726561746572207468616e2030000000005f82015250565b5f6151ec601c83614186565b91506151f7826151b8565b602082019050919050565b5f6020820190508181035f830152615219816151e0565b9050919050565b7f4d616b65722045524331313535207061796d656e74206d75737420626520556e5f8201527f696e697469616c697a6564000000000000000000000000000000000000000000602082015250565b5f61527a602b83614186565b915061528582615220565b604082019050919050565b5f6020820190508181035f8301526152a78161526e565b9050919050565b5f6040820190506152c15f83018561404d565b6152ce60208301846144b8565b9392505050565b6152de8161389a565b81146152e8575f80fd5b50565b5f815190506152f9816152d5565b92915050565b5f6020828403121561531457615313613812565b5b5f615321848285016152eb565b9150509291505056fea2646970667358221220de0fcae0c8d5c878eb19d054d488307775c257b169d9ffd7f39d5f524298f83564736f6c63430008180033"; +pub const NFT_SWAP_CONTRACT_BYTES: &str = "60a060405234801562000010575f80fd5b50604051620055a2380380620055a2833981810160405281019062000036919062000147565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603620000a7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200009e90620001fb565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff1681525050506200021b565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6200011182620000e6565b9050919050565b620001238162000105565b81146200012e575f80fd5b50565b5f81519050620001418162000118565b92915050565b5f602082840312156200015f576200015e620000e2565b5b5f6200016e8482850162000131565b91505092915050565b5f82825260208201905092915050565b7f66656541646472657373206d757374206e6f74206265207a65726f20616464725f8201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b5f620001e360238362000177565b9150620001f08262000187565b604082019050919050565b5f6020820190508181035f8301526200021481620001d5565b9050919050565b608051615360620002425f395f8181612aef01528181612b8a0152612f4801526153605ff3fe608060405260043610610113575f3560e01c80639b4603f21161009f578063cc90c19911610063578063cc90c1991461038e578063d6a71eb4146103b6578063e06cf966146103de578063efccb9eb14610408578063f23a6e611461044657610113565b80639b4603f2146102be578063b27e46fb146102da578063bc197c8114610302578063c8d9009b1461033e578063c92cd12d1461036657610113565b8063150b7a02116100e6578063150b7a02146101cb5780633e6af5f21461020757806346b95ac71461022f57806365e266171461026e5780636e6bf6d21461029657610113565b806301ffc9a71461011757806305ec158d146101535780630f235fce1461017b578063146e5b24146101a3575b5f80fd5b348015610122575f80fd5b5061013d6004803603810190610138919061386f565b610482565b60405161014a91906138b4565b60405180910390f35b34801561015e575f80fd5b506101796004803603810190610174919061398d565b610563565b005b348015610186575f80fd5b506101a1600480360381019061019c9190613a2a565b610823565b005b3480156101ae575f80fd5b506101c960048036038101906101c49190613ab3565b610add565b005b3480156101d6575f80fd5b506101f160048036038101906101ec9190613bb1565b610cc3565b6040516101fe9190613c44565b60405180910390f35b348015610212575f80fd5b5061022d60048036038101906102289190613ab3565b611112565b005b34801561023a575f80fd5b5061025560048036038101906102509190613c5d565b611423565b6040516102659493929190613d53565b60405180910390f35b348015610279575f80fd5b50610294600480360381019061028f9190613ab3565b611485565b005b3480156102a1575f80fd5b506102bc60048036038101906102b79190613a2a565b6118e9565b005b6102d860048036038101906102d39190613dc0565b611ba4565b005b3480156102e5575f80fd5b5061030060048036038101906102fb919061398d565b611eda565b005b34801561030d575f80fd5b5061032860048036038101906103239190613eb2565b612199565b6040516103359190613c44565b60405180910390f35b348015610349575f80fd5b50610364600480360381019061035f9190613a2a565b6121d5565b005b348015610371575f80fd5b5061038c6004803603810190610387919061398d565b6124fe565b005b348015610399575f80fd5b506103b460048036038101906103af9190613ab3565b61282c565b005b3480156103c1575f80fd5b506103dc60048036038101906103d79190613f89565b612bdc565b005b3480156103e9575f80fd5b506103f2612f46565b6040516103ff919061405c565b60405180910390f35b348015610413575f80fd5b5061042e60048036038101906104299190613c5d565b612f6a565b60405161043d939291906140bb565b60405180910390f35b348015610451575f80fd5b5061046c600480360381019061046791906140f0565b612fb6565b6040516104799190613c44565b60405180910390f35b5f7f4e2312e0000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061054c57507f150b7a02000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061055c575061055b8261344a565b5b9050919050565b6001600381111561057757610576613ce0565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff1660038111156105a9576105a8613ce0565b5b146105e9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105e090614206565b60405180910390fd5b5f600387336002896040516020016106019190614244565b60405160208183030381529060405260405161061d91906142ca565b602060405180830381855afa158015610638573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061065b91906142f4565b888888886040516020016106759796959493929190614384565b60405160208183030381529060405260405161069191906142ca565b602060405180830381855afa1580156106ac573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610736576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161072d9061444e565b60405180910390fd5b60035f808a81526020019081526020015f205f0160186101000a81548160ff0219169083600381111561076c5761076b613ce0565b5b02179055507fac509cdcc7ddb189f81fff6f4824f5c95076e64c3bdce542c50feaa6779afd73886040516107a0919061447b565b60405180910390a15f8490508073ffffffffffffffffffffffffffffffffffffffff1663f242432a303387876040518563ffffffff1660e01b81526004016107eb94939291906144d6565b5f604051808303815f87803b158015610802575f80fd5b505af1158015610814573d5f803e3d5ffd5b50505050505050505050505050565b6001600381111561083757610836613ce0565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff16600381111561086957610868613ce0565b5b146108a9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108a090614206565b60405180910390fd5b5f60038633878787876040516020016108c79695949392919061452c565b6040516020818303038152906040526040516108e391906142ca565b602060405180830381855afa1580156108fe573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610988576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161097f9061444e565b60405180910390fd5b5f808881526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff164210156109f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109ea9061460b565b60405180910390fd5b60035f808981526020019081526020015f205f0160186101000a81548160ff02191690836003811115610a2957610a28613ce0565b5b02179055507f5dedc4f52b757d9112d09ca0b2f022927104d54e3f54da091587e8ad1921907287604051610a5d919061447b565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b8152600401610aa693929190614629565b5f604051808303815f87803b158015610abd575f80fd5b505af1158015610acf573d5f803e3d5ffd5b505050505050505050505050565b60016004811115610af157610af0613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff166004811115610b2457610b23613ce0565b5b14610b64576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b5b90614206565b60405180910390fd5b5f600387878733888888604051602001610b84979695949392919061465e565b604051602081830303815290604052604051610ba091906142ca565b602060405180830381855afa158015610bbb573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610c46576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c3d9061444e565b60405180910390fd5b600260015f8a81526020019081526020015f205f01601c6101000a81548160ff02191690836004811115610c7d57610c7c613ce0565b5b02179055507f9c45e43e2ef051f70491ffd5221bf02ab37e1324128714ef9610df5f24fc9fb588604051610cb1919061447b565b60405180910390a15050505050505050565b5f808383810190610cd49190614807565b90505f6003811115610ce957610ce8613ce0565b5b5f80835f015181526020019081526020015f205f0160189054906101000a900460ff166003811115610d1e57610d1d613ce0565b5b14610d5e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d55906148a2565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816020015173ffffffffffffffffffffffffffffffffffffffff1603610dd0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610dc79061490a565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816040015173ffffffffffffffffffffffffffffffffffffffff1603610e42576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e3990614972565b60405180910390fd5b806040015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610eb4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610eab90614a00565b60405180910390fd5b8573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614610f22576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f1990614a68565b60405180910390fd5b610f2f81602001516134b3565b15610f6f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f6690614ad0565b60405180910390fd5b5f60038260200151888460600151856080015186604001518b604051602001610f9d9695949392919061452c565b604051602081830303815290604052604051610fb991906142ca565b602060405180830381855afa158015610fd4573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018360a0015163ffffffff1681526020016001600381111561102457611023613ce0565b5b8152505f80845f015181526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548160ff021916908360038111156110bb576110ba613ce0565b5b02179055509050507ff1dc11bbb6d7542c4267ecf1d370ff4c7092518633ecae9939e8488f4e53d2ad825f01516040516110f5919061447b565b60405180910390a163150b7a0260e01b9250505095945050505050565b6001600481111561112657611125613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff16600481111561115957611158613ce0565b5b14611199576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161119090614206565b60405180910390fd5b5f6003878787336002896040516020016111b39190614244565b6040516020818303038152906040526040516111cf91906142ca565b602060405180830381855afa1580156111ea573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061120d91906142f4565b8888604051602001611225979695949392919061465e565b60405160208183030381529060405260405161124191906142ca565b602060405180830381855afa15801561125c573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146112e7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112de9061444e565b60405180910390fd5b600460015f8a81526020019081526020015f205f01601c6101000a81548160ff0219169083600481111561131e5761131d613ce0565b5b02179055507f45169a52eef651b20a81474b50b8a5d83225225fcd097ef3cf7952d9ab304f278885604051611354929190614aee565b60405180910390a15f86886113699190614b42565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036113e7573373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f193505050501580156113e1573d5f803e3d5ffd5b50611418565b5f83905061141633838373ffffffffffffffffffffffffffffffffffffffff166134c49092919063ffffffff16565b505b505050505050505050565b6001602052805f5260405f205f91509050805f015f9054906101000a900460601b90805f0160149054906101000a900463ffffffff1690805f0160189054906101000a900463ffffffff1690805f01601c9054906101000a900460ff16905084565b6001600481111561149957611498613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff1660048111156114cc576114cb613ce0565b5b148061151c5750600260048111156114e7576114e6613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff16600481111561151a57611519613ce0565b5b145b61155b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161155290614be5565b60405180910390fd5b5f60038787873388888860405160200161157b979695949392919061465e565b60405160208183030381529060405260405161159791906142ca565b602060405180830381855afa1580156115b2573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461163d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116349061444e565b60405180910390fd5b6002600481111561165157611650613ce0565b5b60015f8a81526020019081526020015f205f01601c9054906101000a900460ff16600481111561168457611683613ce0565b5b036116f65760015f8981526020019081526020015f205f0160189054906101000a900463ffffffff1663ffffffff164210156116f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116ec9061460b565b60405180910390fd5b5b6001600481111561170a57611709613ce0565b5b60015f8a81526020019081526020015f205f01601c9054906101000a900460ff16600481111561173d5761173c613ce0565b5b036117af5760015f8981526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff164210156117ae576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117a590614c73565b60405180910390fd5b5b600460015f8a81526020019081526020015f205f01601c6101000a81548160ff021916908360048111156117e6576117e5613ce0565b5b02179055507fbdd7a4be6d82798a500b59077706b12d3f45acf5504828919f92501307b2b9538860405161181a919061447b565b60405180910390a15f868861182f9190614b42565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036118ad573373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f193505050501580156118a7573d5f803e3d5ffd5b506118de565b5f8390506118dc33838373ffffffffffffffffffffffffffffffffffffffff166134c49092919063ffffffff16565b505b505050505050505050565b600160038111156118fd576118fc613ce0565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff16600381111561192f5761192e613ce0565b5b1461196f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161196690614206565b60405180910390fd5b5f600386336002886040516020016119879190614244565b6040516020818303038152906040526040516119a391906142ca565b602060405180830381855afa1580156119be573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906119e191906142f4565b8787876040516020016119f99695949392919061452c565b604051602081830303815290604052604051611a1591906142ca565b602060405180830381855afa158015611a30573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614611aba576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ab19061444e565b60405180910390fd5b60035f808981526020019081526020015f205f0160186101000a81548160ff02191690836003811115611af057611aef613ce0565b5b02179055507fac509cdcc7ddb189f81fff6f4824f5c95076e64c3bdce542c50feaa6779afd7387604051611b24919061447b565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b8152600401611b6d93929190614629565b5f604051808303815f87803b158015611b84575f80fd5b505af1158015611b96573d5f803e3d5ffd5b505050505050505050505050565b5f6004811115611bb757611bb6613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff166004811115611bea57611be9613ce0565b5b14611c2a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c2190614d01565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603611c98576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c8f90614d8f565b60405180910390fd5b5f3411611cda576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611cd190614e1d565b60405180910390fd5b853411611d1c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d1390614eab565b60405180910390fd5b5f60038734611d2b9190614ec9565b88883389895f604051602001611d47979695949392919061465e565b604051602081830303815290604052604051611d6391906142ca565b602060405180830381855afa158015611d7e573d5f803e3d5ffd5b5050506040515160601b90506040518060800160405280826bffffffffffffffffffffffff191681526020018463ffffffff1681526020018363ffffffff16815260200160016004811115611dd657611dd5613ce0565b5b81525060015f8a81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548163ffffffff021916908363ffffffff1602179055506060820151815f01601c6101000a81548160ff02191690836004811115611e9157611e90613ce0565b5b02179055509050507ffc6cdccd1d98ded12074a9ebc7f6ab74fed1814ff57f4fb5202464d8938bd93588604051611ec8919061447b565b60405180910390a15050505050505050565b60016003811115611eee57611eed613ce0565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff166003811115611f2057611f1f613ce0565b5b14611f60576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f5790614206565b60405180910390fd5b5f600387338888888888604051602001611f809796959493929190614384565b604051602081830303815290604052604051611f9c91906142ca565b602060405180830381855afa158015611fb7573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614612041576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120389061444e565b60405180910390fd5b5f808981526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff164210156120ac576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120a39061460b565b60405180910390fd5b60035f808a81526020019081526020015f205f0160186101000a81548160ff021916908360038111156120e2576120e1613ce0565b5b02179055507f5dedc4f52b757d9112d09ca0b2f022927104d54e3f54da091587e8ad1921907288604051612116919061447b565b60405180910390a15f8490508073ffffffffffffffffffffffffffffffffffffffff1663f242432a303387876040518563ffffffff1660e01b815260040161216194939291906144d6565b5f604051808303815f87803b158015612178575f80fd5b505af115801561218a573d5f803e3d5ffd5b50505050505050505050505050565b5f6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016121cc90614f46565b60405180910390fd5b600160038111156121e9576121e8613ce0565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff16600381111561221b5761221a613ce0565b5b1461225b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161225290614206565b60405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146122c9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122c090614fae565b60405180910390fd5b5f60033387876002886040516020016122e29190614244565b6040516020818303038152906040526040516122fe91906142ca565b602060405180830381855afa158015612319573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061233c91906142f4565b87876040516020016123539695949392919061452c565b60405160208183030381529060405260405161236f91906142ca565b602060405180830381855afa15801561238a573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614612414576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161240b9061444e565b60405180910390fd5b60025f808981526020019081526020015f205f0160186101000a81548160ff0219169083600381111561244a57612449613ce0565b5b02179055507fad62ed075fe8969df63026f45152d6e996a0697a736a8de92ee85ae9c9958cf08760405161247e919061447b565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b81526004016124c793929190614629565b5f604051808303815f87803b1580156124de575f80fd5b505af11580156124f0573d5f803e3d5ffd5b505050505050505050505050565b6001600381111561251257612511613ce0565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff16600381111561254457612543613ce0565b5b14612584576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161257b90614206565b60405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146125f2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016125e990614fae565b60405180910390fd5b5f600333888860028960405160200161260b9190614244565b60405160208183030381529060405260405161262791906142ca565b602060405180830381855afa158015612642573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061266591906142f4565b88888860405160200161267e9796959493929190614384565b60405160208183030381529060405260405161269a91906142ca565b602060405180830381855afa1580156126b5573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461273f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016127369061444e565b60405180910390fd5b60025f808a81526020019081526020015f205f0160186101000a81548160ff0219169083600381111561277557612774613ce0565b5b02179055507fad62ed075fe8969df63026f45152d6e996a0697a736a8de92ee85ae9c9958cf0886040516127a9919061447b565b60405180910390a15f8490508073ffffffffffffffffffffffffffffffffffffffff1663f242432a303387876040518563ffffffff1660e01b81526004016127f494939291906144d6565b5f604051808303815f87803b15801561280b575f80fd5b505af115801561281d573d5f803e3d5ffd5b50505050505050505050505050565b600260048111156128405761283f613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff16600481111561287357612872613ce0565b5b146128b3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016128aa9061503c565b60405180910390fd5b5f600387873388886002896040516020016128ce9190614244565b6040516020818303038152906040526040516128ea91906142ca565b602060405180830381855afa158015612905573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061292891906142f4565b8860405160200161293f979695949392919061465e565b60405160208183030381529060405260405161295b91906142ca565b602060405180830381855afa158015612976573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614612a01576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129f89061444e565b60405180910390fd5b600360015f8a81526020019081526020015f205f01601c6101000a81548160ff02191690836004811115612a3857612a37613ce0565b5b02179055507f0d0da0df275f85bed3a5fe7ae79f3559341a3f9ccd8e010133438135bda00a878884604051612a6e929190614aee565b60405180910390a15f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612b56573373ffffffffffffffffffffffffffffffffffffffff166108fc8890811502906040515f60405180830381858888f19350505050158015612aec573d5f803e3d5ffd5b507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166108fc8790811502906040515f60405180830381858888f19350505050158015612b50573d5f803e3d5ffd5b50612bd2565b5f829050612b8533898373ffffffffffffffffffffffffffffffffffffffff166134c49092919063ffffffff16565b612bd07f0000000000000000000000000000000000000000000000000000000000000000888373ffffffffffffffffffffffffffffffffffffffff166134c49092919063ffffffff16565b505b5050505050505050565b5f6004811115612bef57612bee613ce0565b5b60015f8b81526020019081526020015f205f01601c9054906101000a900460ff166004811115612c2257612c21613ce0565b5b14612c62576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c59906150ca565b60405180910390fd5b5f8811612ca4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c9b90615132565b60405180910390fd5b5f8711612ce6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612cdd9061519a565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603612d54576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612d4b90614d8f565b60405180910390fd5b5f60038989883389898d604051602001612d74979695949392919061465e565b604051602081830303815290604052604051612d9091906142ca565b602060405180830381855afa158015612dab573d5f803e3d5ffd5b5050506040515160601b90506040518060800160405280826bffffffffffffffffffffffff191681526020018463ffffffff1681526020018363ffffffff16815260200160016004811115612e0357612e02613ce0565b5b81525060015f8c81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548163ffffffff021916908363ffffffff1602179055506060820151815f01601c6101000a81548160ff02191690836004811115612ebe57612ebd613ce0565b5b02179055509050507ffc6cdccd1d98ded12074a9ebc7f6ab74fed1814ff57f4fb5202464d8938bd9358a604051612ef5919061447b565b60405180910390a15f879050612f3933308b8d612f129190614b42565b8473ffffffffffffffffffffffffffffffffffffffff16613543909392919063ffffffff16565b5050505050505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b5f602052805f5260405f205f91509050805f015f9054906101000a900460601b90805f0160149054906101000a900463ffffffff1690805f0160189054906101000a900460ff16905083565b5f808383810190612fc79190614807565b90505f6003811115612fdc57612fdb613ce0565b5b5f80835f015181526020019081526020015f205f0160189054906101000a900460ff16600381111561301157613010613ce0565b5b14613051576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161304890615228565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816020015173ffffffffffffffffffffffffffffffffffffffff16036130c3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016130ba9061490a565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816040015173ffffffffffffffffffffffffffffffffffffffff1603613135576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161312c90614972565b60405180910390fd5b806040015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146131a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161319e90614a00565b60405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614613215576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161320c90614a68565b60405180910390fd5b5f8511613257576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161324e90615290565b60405180910390fd5b61326481602001516134b3565b156132a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161329b90614ad0565b60405180910390fd5b5f60038260200151898460600151856080015186604001518c8c6040516020016132d49796959493929190614384565b6040516020818303038152906040526040516132f091906142ca565b602060405180830381855afa15801561330b573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018360a0015163ffffffff1681526020016001600381111561335b5761335a613ce0565b5b8152505f80845f015181526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548160ff021916908360038111156133f2576133f1613ce0565b5b02179055509050507ff1dc11bbb6d7542c4267ecf1d370ff4c7092518633ecae9939e8488f4e53d2ad825f015160405161342c919061447b565b60405180910390a163f23a6e6160e01b925050509695505050505050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f80823b90505f8111915050919050565b61353e838473ffffffffffffffffffffffffffffffffffffffff1663a9059cbb85856040516024016134f79291906152ae565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506135c5565b505050565b6135bf848573ffffffffffffffffffffffffffffffffffffffff166323b872dd86868660405160240161357893929190614629565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506135c5565b50505050565b5f6135ef828473ffffffffffffffffffffffffffffffffffffffff1661365a90919063ffffffff16565b90505f81511415801561361357508080602001905181019061361191906152ff565b155b1561365557826040517f5274afe700000000000000000000000000000000000000000000000000000000815260040161364c919061405c565b60405180910390fd5b505050565b606061366783835f61366f565b905092915050565b6060814710156136b657306040517fcd7860590000000000000000000000000000000000000000000000000000000081526004016136ad919061405c565b60405180910390fd5b5f808573ffffffffffffffffffffffffffffffffffffffff1684866040516136de91906142ca565b5f6040518083038185875af1925050503d805f8114613718576040519150601f19603f3d011682016040523d82523d5f602084013e61371d565b606091505b509150915061372d868383613738565b925050509392505050565b60608261374d57613748826137c5565b6137bd565b5f825114801561377357505f8473ffffffffffffffffffffffffffffffffffffffff163b145b156137b557836040517f9996b3150000000000000000000000000000000000000000000000000000000081526004016137ac919061405c565b60405180910390fd5b8190506137be565b5b9392505050565b5f815111156137d75780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61384e8161381a565b8114613858575f80fd5b50565b5f8135905061386981613845565b92915050565b5f6020828403121561388457613883613812565b5b5f6138918482850161385b565b91505092915050565b5f8115159050919050565b6138ae8161389a565b82525050565b5f6020820190506138c75f8301846138a5565b92915050565b5f819050919050565b6138df816138cd565b81146138e9575f80fd5b50565b5f813590506138fa816138d6565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61392982613900565b9050919050565b6139398161391f565b8114613943575f80fd5b50565b5f8135905061395481613930565b92915050565b5f819050919050565b61396c8161395a565b8114613976575f80fd5b50565b5f8135905061398781613963565b92915050565b5f805f805f805f60e0888a0312156139a8576139a7613812565b5b5f6139b58a828b016138ec565b97505060206139c68a828b01613946565b96505060406139d78a828b016138ec565b95505060606139e88a828b016138ec565b94505060806139f98a828b01613946565b93505060a0613a0a8a828b01613979565b92505060c0613a1b8a828b01613979565b91505092959891949750929550565b5f805f805f8060c08789031215613a4457613a43613812565b5b5f613a5189828a016138ec565b9650506020613a6289828a01613946565b9550506040613a7389828a016138ec565b9450506060613a8489828a016138ec565b9350506080613a9589828a01613946565b92505060a0613aa689828a01613979565b9150509295509295509295565b5f805f805f805f60e0888a031215613ace57613acd613812565b5b5f613adb8a828b016138ec565b9750506020613aec8a828b01613979565b9650506040613afd8a828b01613979565b9550506060613b0e8a828b01613946565b9450506080613b1f8a828b016138ec565b93505060a0613b308a828b016138ec565b92505060c0613b418a828b01613946565b91505092959891949750929550565b5f80fd5b5f80fd5b5f80fd5b5f8083601f840112613b7157613b70613b50565b5b8235905067ffffffffffffffff811115613b8e57613b8d613b54565b5b602083019150836001820283011115613baa57613ba9613b58565b5b9250929050565b5f805f805f60808688031215613bca57613bc9613812565b5b5f613bd788828901613946565b9550506020613be888828901613946565b9450506040613bf988828901613979565b935050606086013567ffffffffffffffff811115613c1a57613c19613816565b5b613c2688828901613b5c565b92509250509295509295909350565b613c3e8161381a565b82525050565b5f602082019050613c575f830184613c35565b92915050565b5f60208284031215613c7257613c71613812565b5b5f613c7f848285016138ec565b91505092915050565b5f7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b613cbc81613c88565b82525050565b5f63ffffffff82169050919050565b613cda81613cc2565b82525050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60058110613d1e57613d1d613ce0565b5b50565b5f819050613d2e82613d0d565b919050565b5f613d3d82613d21565b9050919050565b613d4d81613d33565b82525050565b5f608082019050613d665f830187613cb3565b613d736020830186613cd1565b613d806040830185613cd1565b613d8d6060830184613d44565b95945050505050565b613d9f81613cc2565b8114613da9575f80fd5b50565b5f81359050613dba81613d96565b92915050565b5f805f805f805f60e0888a031215613ddb57613dda613812565b5b5f613de88a828b016138ec565b9750506020613df98a828b01613979565b9650506040613e0a8a828b01613946565b9550506060613e1b8a828b016138ec565b9450506080613e2c8a828b016138ec565b93505060a0613e3d8a828b01613dac565b92505060c0613e4e8a828b01613dac565b91505092959891949750929550565b5f8083601f840112613e7257613e71613b50565b5b8235905067ffffffffffffffff811115613e8f57613e8e613b54565b5b602083019150836020820283011115613eab57613eaa613b58565b5b9250929050565b5f805f805f805f8060a0898b031215613ece57613ecd613812565b5b5f613edb8b828c01613946565b9850506020613eec8b828c01613946565b975050604089013567ffffffffffffffff811115613f0d57613f0c613816565b5b613f198b828c01613e5d565b9650965050606089013567ffffffffffffffff811115613f3c57613f3b613816565b5b613f488b828c01613e5d565b9450945050608089013567ffffffffffffffff811115613f6b57613f6a613816565b5b613f778b828c01613b5c565b92509250509295985092959890939650565b5f805f805f805f805f6101208a8c031215613fa757613fa6613812565b5b5f613fb48c828d016138ec565b9950506020613fc58c828d01613979565b9850506040613fd68c828d01613979565b9750506060613fe78c828d01613946565b9650506080613ff88c828d01613946565b95505060a06140098c828d016138ec565b94505060c061401a8c828d016138ec565b93505060e061402b8c828d01613dac565b92505061010061403d8c828d01613dac565b9150509295985092959850929598565b6140568161391f565b82525050565b5f60208201905061406f5f83018461404d565b92915050565b6004811061408657614085613ce0565b5b50565b5f81905061409682614075565b919050565b5f6140a582614089565b9050919050565b6140b58161409b565b82525050565b5f6060820190506140ce5f830186613cb3565b6140db6020830185613cd1565b6140e860408301846140ac565b949350505050565b5f805f805f8060a0878903121561410a57614109613812565b5b5f61411789828a01613946565b965050602061412889828a01613946565b955050604061413989828a01613979565b945050606061414a89828a01613979565b935050608087013567ffffffffffffffff81111561416b5761416a613816565b5b61417789828a01613b5c565b92509250509295509295509295565b5f82825260208201905092915050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520505f8201527f61796d656e7453656e7400000000000000000000000000000000000000000000602082015250565b5f6141f0602a83614186565b91506141fb82614196565b604082019050919050565b5f6020820190508181035f83015261421d816141e4565b9050919050565b5f819050919050565b61423e614239826138cd565b614224565b82525050565b5f61424f828461422d565b60208201915081905092915050565b5f81519050919050565b5f81905092915050565b5f5b8381101561428f578082015181840152602081019050614274565b5f8484015250505050565b5f6142a48261425e565b6142ae8185614268565b93506142be818560208601614272565b80840191505092915050565b5f6142d5828461429a565b915081905092915050565b5f815190506142ee816138d6565b92915050565b5f6020828403121561430957614308613812565b5b5f614316848285016142e0565b91505092915050565b5f8160601b9050919050565b5f6143358261431f565b9050919050565b5f6143468261432b565b9050919050565b61435e6143598261391f565b61433c565b82525050565b5f819050919050565b61437e6143798261395a565b614364565b82525050565b5f61438f828a61434d565b60148201915061439f828961434d565b6014820191506143af828861422d565b6020820191506143bf828761422d565b6020820191506143cf828661434d565b6014820191506143df828561436d565b6020820191506143ef828461436d565b60208201915081905098975050505050505050565b7f496e76616c6964207061796d656e7448617368000000000000000000000000005f82015250565b5f614438601383614186565b915061444382614404565b602082019050919050565b5f6020820190508181035f8301526144658161442c565b9050919050565b614475816138cd565b82525050565b5f60208201905061448e5f83018461446c565b92915050565b61449d8161395a565b82525050565b5f82825260208201905092915050565b50565b5f6144c15f836144a3565b91506144cc826144b3565b5f82019050919050565b5f60a0820190506144e95f83018761404d565b6144f6602083018661404d565b6145036040830185614494565b6145106060830184614494565b8181036080830152614521816144b6565b905095945050505050565b5f614537828961434d565b601482019150614547828861434d565b601482019150614557828761422d565b602082019150614567828661422d565b602082019150614577828561434d565b601482019150614587828461436d565b602082019150819050979650505050505050565b7f43757272656e742074696d657374616d70206469646e277420657863656564205f8201527f7061796d656e7420726566756e64206c6f636b2074696d650000000000000000602082015250565b5f6145f5603883614186565b91506146008261459b565b604082019050919050565b5f6020820190508181035f830152614622816145e9565b9050919050565b5f60608201905061463c5f83018661404d565b614649602083018561404d565b6146566040830184614494565b949350505050565b5f614669828a61436d565b602082019150614679828961436d565b602082019150614689828861434d565b601482019150614699828761434d565b6014820191506146a9828661422d565b6020820191506146b9828561422d565b6020820191506146c9828461434d565b60148201915081905098975050505050505050565b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b614728826146e2565b810181811067ffffffffffffffff82111715614747576147466146f2565b5b80604052505050565b5f614759613809565b9050614765828261471f565b919050565b5f60c0828403121561477f5761477e6146de565b5b61478960c0614750565b90505f614798848285016138ec565b5f8301525060206147ab84828501613946565b60208301525060406147bf84828501613946565b60408301525060606147d3848285016138ec565b60608301525060806147e7848285016138ec565b60808301525060a06147fb84828501613dac565b60a08301525092915050565b5f60c0828403121561481c5761481b613812565b5b5f6148298482850161476a565b91505092915050565b7f4d616b657220455243373231207061796d656e74206d75737420626520556e695f8201527f6e697469616c697a656400000000000000000000000000000000000000000000602082015250565b5f61488c602a83614186565b915061489782614832565b604082019050919050565b5f6020820190508181035f8301526148b981614880565b9050919050565b7f54616b6572206d757374206e6f74206265207a65726f206164647265737300005f82015250565b5f6148f4601e83614186565b91506148ff826148c0565b602082019050919050565b5f6020820190508181035f830152614921816148e8565b9050919050565b7f546f6b656e206d757374206e6f74206265207a65726f206164647265737300005f82015250565b5f61495c601e83614186565b915061496782614928565b602082019050919050565b5f6020820190508181035f83015261498981614950565b9050919050565b7f546f6b656e206164647265737320646f6573206e6f74206d617463682073656e5f8201527f6465720000000000000000000000000000000000000000000000000000000000602082015250565b5f6149ea602383614186565b91506149f582614990565b604082019050919050565b5f6020820190508181035f830152614a17816149de565b9050919050565b7f4f70657261746f72206d757374206265207468652073656e64657200000000005f82015250565b5f614a52601b83614186565b9150614a5d82614a1e565b602082019050919050565b5f6020820190508181035f830152614a7f81614a46565b9050919050565b7f54616b65722063616e6e6f74206265206120636f6e74726163740000000000005f82015250565b5f614aba601a83614186565b9150614ac582614a86565b602082019050919050565b5f6020820190508181035f830152614ae781614aae565b9050919050565b5f604082019050614b015f83018561446c565b614b0e602083018461446c565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f614b4c8261395a565b9150614b578361395a565b9250828201905080821115614b6f57614b6e614b15565b5b92915050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520505f8201527f61796d656e7453656e74206f722054616b6572417070726f7665640000000000602082015250565b5f614bcf603b83614186565b9150614bda82614b75565b604082019050919050565b5f6020820190508181035f830152614bfc81614bc3565b9050919050565b7f43757272656e742074696d657374616d70206469646e277420657863656564205f8201527f7061796d656e74207072652d617070726f7665206c6f636b2074696d65000000602082015250565b5f614c5d603d83614186565b9150614c6882614c03565b604082019050919050565b5f6020820190508181035f830152614c8a81614c51565b9050919050565b7f54616b6572207061796d656e7420697320616c726561647920696e697469616c5f8201527f697a656400000000000000000000000000000000000000000000000000000000602082015250565b5f614ceb602483614186565b9150614cf682614c91565b604082019050919050565b5f6020820190508181035f830152614d1881614cdf565b9050919050565b7f5265636569766572206d757374206e6f74206265207a65726f206164647265735f8201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b5f614d79602183614186565b9150614d8482614d1f565b604082019050919050565b5f6020820190508181035f830152614da681614d6d565b9050919050565b7f4554482076616c7565206d7573742062652067726561746572207468616e207a5f8201527f65726f0000000000000000000000000000000000000000000000000000000000602082015250565b5f614e07602383614186565b9150614e1282614dad565b604082019050919050565b5f6020820190508181035f830152614e3481614dfb565b9050919050565b7f4554482076616c7565206d7573742062652067726561746572207468616e20645f8201527f6578206665650000000000000000000000000000000000000000000000000000602082015250565b5f614e95602683614186565b9150614ea082614e3b565b604082019050919050565b5f6020820190508181035f830152614ec281614e89565b9050919050565b5f614ed38261395a565b9150614ede8361395a565b9250828203905081811115614ef657614ef5614b15565b5b92915050565b7f4261746368207472616e7366657273206e6f7420737570706f727465640000005f82015250565b5f614f30601d83614186565b9150614f3b82614efc565b602082019050919050565b5f6020820190508181035f830152614f5d81614f24565b9050919050565b7f43616c6c6572206d75737420626520616e20454f4100000000000000000000005f82015250565b5f614f98601583614186565b9150614fa382614f64565b602082019050919050565b5f6020820190508181035f830152614fc581614f8c565b9050919050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520545f8201527f616b6572417070726f7665640000000000000000000000000000000000000000602082015250565b5f615026602c83614186565b915061503182614fcc565b604082019050919050565b5f6020820190508181035f8301526150538161501a565b9050919050565b7f4552433230207632207061796d656e7420697320616c726561647920696e69745f8201527f69616c697a656400000000000000000000000000000000000000000000000000602082015250565b5f6150b4602783614186565b91506150bf8261505a565b604082019050919050565b5f6020820190508181035f8301526150e1816150a8565b9050919050565b7f416d6f756e74206d757374206e6f74206265207a65726f0000000000000000005f82015250565b5f61511c601783614186565b9150615127826150e8565b602082019050919050565b5f6020820190508181035f83015261514981615110565b9050919050565b7f44657820666565206d757374206e6f74206265207a65726f00000000000000005f82015250565b5f615184601883614186565b915061518f82615150565b602082019050919050565b5f6020820190508181035f8301526151b181615178565b9050919050565b7f4d616b65722045524331313535207061796d656e74206d75737420626520556e5f8201527f696e697469616c697a6564000000000000000000000000000000000000000000602082015250565b5f615212602b83614186565b915061521d826151b8565b604082019050919050565b5f6020820190508181035f83015261523f81615206565b9050919050565b7f56616c7565206d7573742062652067726561746572207468616e2030000000005f82015250565b5f61527a601c83614186565b915061528582615246565b602082019050919050565b5f6020820190508181035f8301526152a78161526e565b9050919050565b5f6040820190506152c15f83018561404d565b6152ce6020830184614494565b9392505050565b6152de8161389a565b81146152e8575f80fd5b50565b5f815190506152f9816152d5565b92915050565b5f6020828403121561531457615313613812565b5b5f615321848285016152eb565b9150509291505056fea26469706673582212200d86b0f6898fb823c55626c3b02a7098bc8622606b092e0f458df6c86ce2967864736f6c63430008180033"; pub trait CoinDockerOps { fn rpc_client(&self) -> &UtxoRpcClientEnum; From f9387cfce5616cbecb311dbf7abb85f28d54dad2 Mon Sep 17 00:00:00 2001 From: laruh Date: Tue, 26 Mar 2024 19:12:04 +0700 Subject: [PATCH 54/80] add validate_decoded_data func --- mm2src/coins/eth.rs | 114 ++++++++++++++++++++++++-------------------- 1 file changed, 61 insertions(+), 53 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 801e1cbffa..b748fae5ac 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -6571,37 +6571,14 @@ impl EthCoin { .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; let decoded = decode_contract_call(function, &tx_from_rpc.input.0) .map_to_mm(|err| ValidatePaymentError::TxDeserializationError(err.to_string()))?; - if decoded[0] != Token::Address(maker_address) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment `maker_address` {:?} is invalid, expected {:?}", - decoded[0], - Token::Address(maker_address) - ))); - } - if decoded[1] != Token::Address(etomic_swap_contract) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment `etomic_swap_contract` {:?} is invalid, expected address {:?}", - decoded[1], - Token::Address(maker_address) - ))); - } - let token_id = U256::from(args.token_id); - if decoded[2] != Token::Uint(token_id) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment `token_id` {:?} is invalid, expected {:?}", - decoded[2], - Token::Uint(token_id) - ))); - } - let value = U256::from_dec_str(&args.amount.to_string()) - .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; - if decoded[3] != Token::Uint(value) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment `amount` {:?} is invalid, expected {:?}", - decoded[3], - Token::Uint(value) - ))); - } + + let validation_params = ValidationParams { + maker_address, + etomic_swap_contract, + token_id: args.token_id, + amount: Some(args.amount.to_string()), + }; + validate_decoded_data(&decoded, &validation_params)?; let taker_address = addr_from_raw_pubkey(args.taker_pub).map_to_mm(ValidatePaymentError::InternalError)?; @@ -6619,28 +6596,14 @@ impl EthCoin { let function = self.erc721_transfer_with_data()?; let decoded = decode_contract_call(function, &tx_from_rpc.input.0) .map_to_mm(|err| ValidatePaymentError::TxDeserializationError(err.to_string()))?; - if decoded[0] != Token::Address(maker_address) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment `maker_address` {:?} is invalid, expected {:?}", - decoded[0], - Token::Address(maker_address) - ))); - } - if decoded[1] != Token::Address(etomic_swap_contract) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment `etomic_swap_contract` {:?} is invalid, expected address {:?}", - decoded[1], - Token::Address(maker_address) - ))); - } - let token_id = U256::from(args.token_id); - if decoded[2] != Token::Uint(token_id) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment `token_id` {:?} is invalid, expected {:?}", - decoded[2], - Token::Uint(token_id) - ))); - } + + let validation_params = ValidationParams { + maker_address, + etomic_swap_contract, + token_id: args.token_id, + amount: None, + }; + validate_decoded_data(&decoded, &validation_params)?; let taker_address = addr_from_raw_pubkey(args.taker_pub).map_to_mm(ValidatePaymentError::InternalError)?; @@ -6888,6 +6851,51 @@ impl StateType { #[inline(always)] fn is_positive_integer(amount: &BigDecimal) -> bool { amount == &amount.with_scale(0) && amount > &BigDecimal::from(0) } +struct ValidationParams<'a> { + maker_address: Address, + etomic_swap_contract: Address, + token_id: &'a [u8], + // Optional, as it's not needed for ERC721 + amount: Option, +} + +/// Validates decoded data from tx input, related to `safeTransferFrom` contract call +fn validate_decoded_data(decoded: &[Token], params: &ValidationParams) -> Result<(), MmError> { + if decoded[0] != Token::Address(params.maker_address) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment `maker_address` {:?} is invalid, expected {:?}", + decoded[0], + Token::Address(params.maker_address) + ))); + } + if decoded[1] != Token::Address(params.etomic_swap_contract) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment `etomic_swap_contract` {:?} is invalid, expected address {:?}", + decoded[1], + Token::Address(params.etomic_swap_contract) + ))); + } + let token_id = U256::from(params.token_id); + if decoded[2] != Token::Uint(token_id) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment `token_id` {:?} is invalid, expected {:?}", + decoded[2], + Token::Uint(token_id) + ))); + } + if let Some(amount) = ¶ms.amount { + let value = U256::from_dec_str(amount).map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; + if decoded[3] != Token::Uint(value) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment `amount` {:?} is invalid, expected {:?}", + decoded[3], + Token::Uint(value) + ))); + } + } + Ok(()) +} + #[derive(Debug, Display)] pub enum HtlcParamsError { WrongPaymentTx(String), From c600db656e67228018d386ab54f72881679bd0b0 Mon Sep 17 00:00:00 2001 From: laruh Date: Thu, 28 Mar 2024 18:51:30 +0700 Subject: [PATCH 55/80] use EnumFromStringify macro --- mm2src/coins/coin_errors.rs | 79 ++++--------------- mm2src/coins/eth.rs | 18 +---- mm2src/coins/lp_coins.rs | 127 +++++++++---------------------- mm2src/coins/my_tx_history_v2.rs | 20 ++--- mm2src/coins/nft/nft_errors.rs | 22 ++---- mm2src/coins/utxo/rpc_clients.rs | 7 +- 6 files changed, 71 insertions(+), 202 deletions(-) diff --git a/mm2src/coins/coin_errors.rs b/mm2src/coins/coin_errors.rs index 262c2acdb2..3df7a2d854 100644 --- a/mm2src/coins/coin_errors.rs +++ b/mm2src/coins/coin_errors.rs @@ -1,6 +1,6 @@ use crate::eth::{CoinAssocTypesError, Erc721FunctionError, HtlcParamsError, NftAssocTypesError, PaymentStatusErr}; -use crate::{eth::Web3RpcError, my_tx_history_v2::MyTxHistoryErrorV2, utxo::rpc_clients::UtxoRpcError, DelegationError, - NumConversError, TxHistoryError, UnexpectedDerivationMethod, WithdrawError}; +use crate::{eth::Web3RpcError, utxo::rpc_clients::UtxoRpcError, NumConversError, UnexpectedDerivationMethod}; +use enum_derives::EnumFromStringify; use futures01::Future; use mm2_err_handle::prelude::MmError; use spv_validation::helpers_validation::SPVError; @@ -12,11 +12,20 @@ pub type ValidatePaymentFut = Box = Result>; /// Enum covering possible error cases of swap payment validation -#[derive(Debug, Display)] +#[derive(Debug, Display, EnumFromStringify)] pub enum ValidatePaymentError { /// Should be used to indicate internal MM2 state problems (e.g., DB errors, etc.). + #[from_stringify( + "CoinAssocTypesError", + "Erc721FunctionError", + "NftAssocTypesError", + "NumConversError", + "UnexpectedDerivationMethod", + "keys::Error" + )] InternalError(String), /// Problem with deserializing the transaction, or one of the transaction parts is invalid. + #[from_stringify("rlp::DecoderError", "serialization::Error")] TxDeserializationError(String), /// One of the input parameters is invalid. InvalidParameter(String), @@ -29,6 +38,7 @@ pub enum ValidatePaymentError { /// Payment transaction is in unexpected state. E.g., `Uninitialized` instead of `Sent` for ETH payment. UnexpectedPaymentState(String), /// Transport (RPC) error. + #[from_stringify("web3::Error")] Transport(String), /// Transaction has wrong properties, for example, it has been sent to a wrong address. WrongPaymentTx(String), @@ -40,30 +50,10 @@ pub enum ValidatePaymentError { NftProtocolNotSupported, } -impl From for ValidatePaymentError { - fn from(err: rlp::DecoderError) -> Self { Self::TxDeserializationError(err.to_string()) } -} - -impl From for ValidatePaymentError { - fn from(err: web3::Error) -> Self { Self::Transport(err.to_string()) } -} - -impl From for ValidatePaymentError { - fn from(err: NumConversError) -> Self { Self::InternalError(err.to_string()) } -} - impl From for ValidatePaymentError { fn from(err: SPVError) -> Self { Self::SPVError(err) } } -impl From for ValidatePaymentError { - fn from(err: serialization::Error) -> Self { Self::TxDeserializationError(err.to_string()) } -} - -impl From for ValidatePaymentError { - fn from(err: UnexpectedDerivationMethod) -> Self { Self::InternalError(err.to_string()) } -} - impl From for ValidatePaymentError { fn from(err: UtxoRpcError) -> Self { match err { @@ -87,18 +77,6 @@ impl From for ValidatePaymentError { } } -impl From for ValidatePaymentError { - fn from(err: keys::Error) -> Self { Self::InternalError(err.to_string()) } -} - -impl From for ValidatePaymentError { - fn from(err: NftAssocTypesError) -> Self { Self::InternalError(err.to_string()) } -} - -impl From for ValidatePaymentError { - fn from(err: CoinAssocTypesError) -> Self { Self::InternalError(err.to_string()) } -} - impl From for ValidatePaymentError { fn from(err: PaymentStatusErr) -> Self { match err { @@ -110,10 +88,6 @@ impl From for ValidatePaymentError { } } -impl From for ValidatePaymentError { - fn from(err: Erc721FunctionError) -> Self { Self::InternalError(err.to_string()) } -} - impl From for ValidatePaymentError { fn from(err: HtlcParamsError) -> Self { match err { @@ -123,32 +97,9 @@ impl From for ValidatePaymentError { } } -#[derive(Debug, Display)] +#[derive(Debug, Display, EnumFromStringify)] pub enum MyAddressError { + #[from_stringify("UnexpectedDerivationMethod")] UnexpectedDerivationMethod(String), InternalError(String), } - -impl From for MyAddressError { - fn from(err: UnexpectedDerivationMethod) -> Self { Self::UnexpectedDerivationMethod(err.to_string()) } -} - -impl From for WithdrawError { - fn from(err: MyAddressError) -> Self { Self::InternalError(err.to_string()) } -} - -impl From for UtxoRpcError { - fn from(err: MyAddressError) -> Self { Self::Internal(err.to_string()) } -} - -impl From for DelegationError { - fn from(err: MyAddressError) -> Self { Self::InternalError(err.to_string()) } -} - -impl From for TxHistoryError { - fn from(err: MyAddressError) -> Self { Self::InternalError(err.to_string()) } -} - -impl From for MyTxHistoryErrorV2 { - fn from(err: MyAddressError) -> Self { Self::Internal(err.to_string()) } -} diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index b748fae5ac..ce543f7842 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -208,22 +208,19 @@ pub type GasStationResult = Result>; type EthPrivKeyPolicy = PrivKeyPolicy; type GasDetails = (U256, U256); -#[derive(Debug, Display)] +#[derive(Debug, Display, EnumFromStringify)] pub enum GasStationReqErr { #[display(fmt = "Transport '{}' error: {}", uri, error)] Transport { uri: String, error: String, }, + #[from_stringify("serde_json::Error")] #[display(fmt = "Invalid response: {}", _0)] InvalidResponse(String), Internal(String), } -impl From for GasStationReqErr { - fn from(e: serde_json::Error) -> Self { GasStationReqErr::InvalidResponse(e.to_string()) } -} - impl From for GasStationReqErr { fn from(e: SlurpError) -> Self { let error = e.to_string(); @@ -237,10 +234,11 @@ impl From for GasStationReqErr { } } -#[derive(Debug, Display)] +#[derive(Debug, Display, EnumFromStringify)] pub enum Web3RpcError { #[display(fmt = "Transport: {}", _0)] Transport(String), + #[from_stringify("serde_json::Error")] #[display(fmt = "Invalid response: {}", _0)] InvalidResponse(String), #[display(fmt = "Timeout: {}", _0)] @@ -261,10 +259,6 @@ impl From for Web3RpcError { } } -impl From for Web3RpcError { - fn from(e: serde_json::Error) -> Self { Web3RpcError::InvalidResponse(e.to_string()) } -} - impl From for Web3RpcError { fn from(e: web3::Error) -> Self { let error_str = e.to_string(); @@ -280,10 +274,6 @@ impl From for Web3RpcError { } } -impl From for RawTransactionError { - fn from(e: web3::Error) -> Self { RawTransactionError::Transport(e.to_string()) } -} - impl From for RawTransactionError { fn from(e: Web3RpcError) -> Self { match e { diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 9d298884c5..d74d380834 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -342,13 +342,14 @@ pub const INVALID_SWAP_ID_ERR_LOG: &str = "Invalid swap id"; pub const INVALID_SCRIPT_ERR_LOG: &str = "Invalid script"; pub const INVALID_REFUND_TX_ERR_LOG: &str = "Invalid refund transaction"; -#[derive(Debug, Deserialize, Display, Serialize, SerializeErrorType)] +#[derive(Debug, Deserialize, Display, EnumFromStringify, Serialize, SerializeErrorType)] #[serde(tag = "error_type", content = "error_data")] pub enum RawTransactionError { #[display(fmt = "No such coin {}", coin)] NoSuchCoin { coin: String }, #[display(fmt = "Invalid hash: {}", _0)] InvalidHashError(String), + #[from_stringify("web3::Error")] #[display(fmt = "Transport error: {}", _0)] Transport(String), #[display(fmt = "Hash does not exist: {}", _0)] @@ -357,6 +358,7 @@ pub enum RawTransactionError { InternalError(String), #[display(fmt = "Transaction decode error: {}", _0)] DecodeError(String), + #[from_stringify("NumConversError", "FromHexError")] #[display(fmt = "Invalid param: {}", _0)] InvalidParam(String), #[display(fmt = "Non-existent previous output: {}", _0)] @@ -396,14 +398,6 @@ impl From for RawTransactionError { } } -impl From for RawTransactionError { - fn from(e: NumConversError) -> Self { RawTransactionError::InvalidParam(e.to_string()) } -} - -impl From for RawTransactionError { - fn from(e: FromHexError) -> Self { RawTransactionError::InvalidParam(e.to_string()) } -} - #[derive(Clone, Debug, Deserialize, Display, EnumFromStringify, PartialEq, Serialize, SerializeErrorType)] #[serde(tag = "error_type", content = "error_data")] pub enum GetMyAddressError { @@ -520,7 +514,7 @@ pub struct MyWalletAddress { pub type SignatureResult = Result>; pub type VerificationResult = Result>; -#[derive(Debug, Display)] +#[derive(Debug, Display, EnumFromStringify)] pub enum TxHistoryError { ErrorSerializing(String), ErrorDeserializing(String), @@ -532,6 +526,7 @@ pub enum TxHistoryError { internal_id: BytesJson, }, NotSupported(String), + #[from_stringify("MyAddressError")] InternalError(String), } @@ -634,14 +629,16 @@ pub enum TxMarshalingErr { Internal(String), } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, EnumFromStringify)] #[allow(clippy::large_enum_variant)] pub enum TransactionErr { /// Keeps transactions while throwing errors. TxRecoverable(TransactionEnum, String), /// Simply for plain error messages. + #[from_stringify("keys::Error")] Plain(String), ProtocolNotSupported(String), + #[from_stringify("NftAssocTypesError")] NftAssocTypesError(String), NumConversError(NumConversError), } @@ -669,14 +666,6 @@ impl TransactionErr { } } -impl From for TransactionErr { - fn from(e: keys::Error) -> Self { TransactionErr::Plain(e.to_string()) } -} - -impl From for TransactionErr { - fn from(e: NftAssocTypesError) -> Self { TransactionErr::NftAssocTypesError(e.to_string()) } -} - impl From for TransactionErr { fn from(e: NumConversError) -> Self { TransactionErr::NumConversError(e) } } @@ -1031,17 +1020,14 @@ pub struct PaymentInstructionArgs<'a> { pub wait_until: u64, } -#[derive(Display)] +#[derive(Display, EnumFromStringify)] pub enum PaymentInstructionsErr { LightningInvoiceErr(String), WatcherRewardErr(String), + #[from_stringify("NumConversError")] InternalError(String), } -impl From for PaymentInstructionsErr { - fn from(e: NumConversError) -> Self { PaymentInstructionsErr::InternalError(e.to_string()) } -} - #[derive(Display)] pub enum ValidateInstructionsErr { ValidateLightningInvoiceErr(String), @@ -1418,7 +1404,7 @@ impl From for ValidateSwapV2TxError { } /// Enum covering error cases that can happen during taker funding spend preimage validation. -#[derive(Debug, Display)] +#[derive(Debug, Display, EnumFromStringify)] pub enum ValidateTakerFundingSpendPreimageError { /// Funding tx has no outputs FundingTxNoOutputs, @@ -1429,37 +1415,30 @@ pub enum ValidateTakerFundingSpendPreimageError { /// Error during preimage comparison to an expected one. InvalidPreimage(String), /// Error during taker's signature check. + #[from_stringify("UtxoSignWithKeyPairError")] SignatureVerificationFailure(String), /// Error during generation of an expected preimage. TxGenError(String), /// Input payment timelock overflows the type used by specific coin. LocktimeOverflow(String), /// Coin's RPC error + #[from_stringify("UtxoRpcError")] Rpc(String), } -impl From for ValidateTakerFundingSpendPreimageError { - fn from(err: UtxoSignWithKeyPairError) -> Self { - ValidateTakerFundingSpendPreimageError::SignatureVerificationFailure(err.to_string()) - } -} - impl From for ValidateTakerFundingSpendPreimageError { fn from(err: TxGenError) -> Self { ValidateTakerFundingSpendPreimageError::TxGenError(format!("{:?}", err)) } } -impl From for ValidateTakerFundingSpendPreimageError { - fn from(err: UtxoRpcError) -> Self { ValidateTakerFundingSpendPreimageError::Rpc(err.to_string()) } -} - /// Enum covering error cases that can happen during taker payment spend preimage validation. -#[derive(Debug, Display)] +#[derive(Debug, Display, EnumFromStringify)] pub enum ValidateTakerPaymentSpendPreimageError { /// Error during signature deserialization. InvalidTakerSignature, /// Error during preimage comparison to an expected one. InvalidPreimage(String), /// Error during taker's signature check. + #[from_stringify("UtxoSignWithKeyPairError")] SignatureVerificationFailure(String), /// Error during generation of an expected preimage. TxGenError(String), @@ -1467,12 +1446,6 @@ pub enum ValidateTakerPaymentSpendPreimageError { LocktimeOverflow(String), } -impl From for ValidateTakerPaymentSpendPreimageError { - fn from(err: UtxoSignWithKeyPairError) -> Self { - ValidateTakerPaymentSpendPreimageError::SignatureVerificationFailure(err.to_string()) - } -} - impl From for ValidateTakerPaymentSpendPreimageError { fn from(err: TxGenError) -> Self { ValidateTakerPaymentSpendPreimageError::TxGenError(format!("{:?}", err)) } } @@ -2362,7 +2335,7 @@ pub enum TradePreimageValue { UpperBound(BigDecimal), } -#[derive(Debug, Display, PartialEq)] +#[derive(Debug, Display, EnumFromStringify, PartialEq)] pub enum TradePreimageError { #[display( fmt = "Not enough {} to preimage the trade: available {}, required at least {}", @@ -2379,20 +2352,13 @@ pub enum TradePreimageError { AmountIsTooSmall { amount: BigDecimal, threshold: BigDecimal }, #[display(fmt = "Transport error: {}", _0)] Transport(String), + #[from_stringify("NumConversError", "UnexpectedDerivationMethod")] #[display(fmt = "Internal error: {}", _0)] InternalError(String), #[display(fmt = "Nft Protocol is not supported yet!")] NftProtocolNotSupported, } -impl From for TradePreimageError { - fn from(e: NumConversError) -> Self { TradePreimageError::InternalError(e.to_string()) } -} - -impl From for TradePreimageError { - fn from(e: UnexpectedDerivationMethod) -> Self { TradePreimageError::InternalError(e.to_string()) } -} - impl TradePreimageError { /// Construct [`TradePreimageError`] from [`GenerateTxError`] using additional `coin` and `decimals`. pub fn from_generate_tx_error( @@ -2474,7 +2440,7 @@ impl NumConversError { pub fn description(&self) -> &str { &self.0 } } -#[derive(Clone, Debug, Display, PartialEq, Serialize, SerializeErrorType)] +#[derive(Clone, Debug, Display, EnumFromStringify, PartialEq, Serialize, SerializeErrorType)] #[serde(tag = "error_type", content = "error_data")] pub enum BalanceError { #[display(fmt = "Transport: {}", _0)] @@ -2484,6 +2450,7 @@ pub enum BalanceError { UnexpectedDerivationMethod(UnexpectedDerivationMethod), #[display(fmt = "Wallet storage error: {}", _0)] WalletStorageError(String), + #[from_stringify("Bip32Error", "NumConversError")] #[display(fmt = "Internal: {}", _0)] Internal(String), } @@ -2500,25 +2467,18 @@ impl From for GetNonZeroBalance { fn from(e: BalanceError) -> Self { GetNonZeroBalance::MyBalanceError(e) } } -impl From for BalanceError { - fn from(e: NumConversError) -> Self { BalanceError::Internal(e.to_string()) } -} - impl From for BalanceError { fn from(e: UnexpectedDerivationMethod) -> Self { BalanceError::UnexpectedDerivationMethod(e) } } -impl From for BalanceError { - fn from(e: Bip32Error) -> Self { BalanceError::Internal(e.to_string()) } -} - -#[derive(Debug, Deserialize, Display, Serialize, SerializeErrorType)] +#[derive(Debug, Deserialize, Display, EnumFromStringify, Serialize, SerializeErrorType)] #[serde(tag = "error_type", content = "error_data")] pub enum StakingInfosError { #[display(fmt = "Staking infos not available for: {}", coin)] CoinDoesntSupportStakingInfos { coin: String }, #[display(fmt = "No such coin {}", coin)] NoSuchCoin { coin: String }, + #[from_stringify("UnexpectedDerivationMethod")] #[display(fmt = "Derivation method is not supported: {}", _0)] UnexpectedDerivationMethod(String), #[display(fmt = "Transport error: {}", _0)] @@ -2539,10 +2499,6 @@ impl From for StakingInfosError { } } -impl From for StakingInfosError { - fn from(e: UnexpectedDerivationMethod) -> Self { StakingInfosError::UnexpectedDerivationMethod(e.to_string()) } -} - impl From for StakingInfosError { fn from(e: Qrc20AddressError) -> Self { match e { @@ -2574,7 +2530,7 @@ impl From for StakingInfosError { } } -#[derive(Debug, Deserialize, Display, Serialize, SerializeErrorType)] +#[derive(Debug, Deserialize, Display, EnumFromStringify, Serialize, SerializeErrorType)] #[serde(tag = "error_type", content = "error_data")] pub enum DelegationError { #[display( @@ -2596,6 +2552,7 @@ pub enum DelegationError { NoSuchCoin { coin: String }, #[display(fmt = "{}", _0)] CannotInteractWithSmartContract(String), + #[from_stringify("ScriptHashTypeNotSupported")] #[display(fmt = "{}", _0)] AddressError(String), #[display(fmt = "Already delegating to: {}", _0)] @@ -2604,6 +2561,7 @@ pub enum DelegationError { DelegationOpsNotSupported { reason: String }, #[display(fmt = "Transport error: {}", _0)] Transport(String), + #[from_stringify("MyAddressError")] #[display(fmt = "Internal error: {}", _0)] InternalError(String), } @@ -2674,10 +2632,6 @@ impl From for DelegationError { } } -impl From for DelegationError { - fn from(e: ScriptHashTypeNotSupported) -> Self { DelegationError::AddressError(e.to_string()) } -} - impl HttpStatusCode for DelegationError { fn status_code(&self) -> StatusCode { match self { @@ -2802,7 +2756,12 @@ pub enum WithdrawError { #[display(fmt = "Transport error: {}", _0)] Transport(String), #[from_trait(WithInternal::internal)] - #[from_stringify("NumConversError", "UnexpectedDerivationMethod", "PrivKeyPolicyNotAllowed")] + #[from_stringify( + "MyAddressError", + "NumConversError", + "UnexpectedDerivationMethod", + "PrivKeyPolicyNotAllowed" + )] #[display(fmt = "Internal error: {}", _0)] InternalError(String), #[display(fmt = "Unsupported error: {}", _0)] @@ -3003,17 +2962,21 @@ impl HttpStatusCode for SignatureError { } } -#[derive(Debug, Display, Serialize, SerializeErrorType)] +#[derive(Debug, Display, EnumFromStringify, Serialize, SerializeErrorType)] #[serde(tag = "error_type", content = "error_data")] pub enum VerificationError { #[display(fmt = "Invalid request: {}", _0)] InvalidRequest(String), + #[from_stringify("ethkey::Error", "keys::Error")] #[display(fmt = "Internal error: {}", _0)] InternalError(String), + #[from_stringify("base64::DecodeError")] #[display(fmt = "Signature decoding error: {}", _0)] SignatureDecodingError(String), + #[from_stringify("hex::FromHexError")] #[display(fmt = "Address decoding error: {}", _0)] AddressDecodingError(String), + #[from_stringify("CoinFindError")] #[display(fmt = "Coin is not found: {}", _0)] CoinIsNotFound(String), #[display(fmt = "sign_message_prefix is not set in coin config")] @@ -3033,14 +2996,6 @@ impl HttpStatusCode for VerificationError { } } -impl From for VerificationError { - fn from(e: base64::DecodeError) -> Self { VerificationError::SignatureDecodingError(e.to_string()) } -} - -impl From for VerificationError { - fn from(e: hex::FromHexError) -> Self { VerificationError::AddressDecodingError(e.to_string()) } -} - impl From for VerificationError { fn from(e: FromBase58Error) -> Self { match e { @@ -3054,18 +3009,6 @@ impl From for VerificationError { } } -impl From for VerificationError { - fn from(e: keys::Error) -> Self { VerificationError::InternalError(e.to_string()) } -} - -impl From for VerificationError { - fn from(e: ethkey::Error) -> Self { VerificationError::InternalError(e.to_string()) } -} - -impl From for VerificationError { - fn from(e: CoinFindError) -> Self { VerificationError::CoinIsNotFound(e.to_string()) } -} - /// NB: Implementations are expected to follow the pImpl idiom, providing cheap reference-counted cloning and garbage collection. #[async_trait] pub trait MmCoin: diff --git a/mm2src/coins/my_tx_history_v2.rs b/mm2src/coins/my_tx_history_v2.rs index 97c5a5ca8f..3ef74bb58f 100644 --- a/mm2src/coins/my_tx_history_v2.rs +++ b/mm2src/coins/my_tx_history_v2.rs @@ -3,6 +3,7 @@ use crate::tendermint::{TENDERMINT_ASSET_PROTOCOL_TYPE, TENDERMINT_COIN_PROTOCOL use crate::tx_history_storage::{CreateTxHistoryStorageError, FilteringAddresses, GetTxHistoryFilters, TxHistoryStorageBuilder, WalletId}; use crate::utxo::utxo_common::big_decimal_from_sat_unsigned; +use crate::MyAddressError; use crate::{coin_conf, lp_coinfind_or_err, BlockHeightAndTime, CoinFindError, HDAccountAddressId, HistorySyncState, MmCoin, MmCoinEnum, Transaction, TransactionDetails, TransactionType, TxFeeDetails, UtxoRpcError}; use async_trait::async_trait; @@ -10,6 +11,7 @@ use bitcrypto::sha256; use common::{calc_total_pages, ten, HttpStatusCode, PagingOptionsEnum, StatusCode}; use crypto::StandardHDPath; use derive_more::Display; +use enum_derives::EnumFromStringify; use futures::compat::Future01CompatExt; use keys::{Address, CashAddress}; use mm2_core::mm_ctx::MmArc; @@ -304,15 +306,19 @@ pub struct MyTxHistoryResponseV2 { pub(crate) paging_options: PagingOptionsEnum, } -#[derive(Debug, Display, Serialize, SerializeErrorType)] +#[derive(Debug, Display, EnumFromStringify, Serialize, SerializeErrorType)] #[serde(tag = "error_type", content = "error_data")] pub enum MyTxHistoryErrorV2 { CoinIsNotActive(String), + #[from_stringify("InvalidBip44ChainError")] InvalidTarget(String), StorageIsNotInitialized(String), + #[from_stringify("CreateTxHistoryStorageError")] StorageError(String), + #[from_stringify("UtxoRpcError")] RpcError(String), NotSupportedFor(String), + #[from_stringify("MyAddressError")] Internal(String), } @@ -350,14 +356,6 @@ impl From for MyTxHistoryErrorV2 { } } -impl From for MyTxHistoryErrorV2 { - fn from(e: CreateTxHistoryStorageError) -> Self { MyTxHistoryErrorV2::StorageError(e.to_string()) } -} - -impl From for MyTxHistoryErrorV2 { - fn from(err: UtxoRpcError) -> Self { MyTxHistoryErrorV2::RpcError(err.to_string()) } -} - impl From for MyTxHistoryErrorV2 { fn from(e: AddressDerivingError) -> Self { match e { @@ -368,10 +366,6 @@ impl From for MyTxHistoryErrorV2 { } } -impl From for MyTxHistoryErrorV2 { - fn from(e: InvalidBip44ChainError) -> Self { MyTxHistoryErrorV2::InvalidTarget(e.to_string()) } -} - #[async_trait] pub trait CoinWithTxHistoryV2 { fn history_wallet_id(&self) -> WalletId; diff --git a/mm2src/coins/nft/nft_errors.rs b/mm2src/coins/nft/nft_errors.rs index cf1342fe5b..8a6fb90f19 100644 --- a/mm2src/coins/nft/nft_errors.rs +++ b/mm2src/coins/nft/nft_errors.rs @@ -36,6 +36,7 @@ pub enum GetNftInfoError { token_address: String, token_id: String, }, + #[from_stringify("LockDBError")] #[display(fmt = "DB error {}", _0)] DbError(String), ParseRfc3339Err(ParseRfc3339Err), @@ -43,6 +44,7 @@ pub enum GetNftInfoError { ContractTypeIsNull, ProtectFromSpamError(ProtectFromSpamError), TransferConfirmationsError(TransferConfirmationsError), + #[from_stringify("NumConversError")] NumConversError(String), } @@ -102,10 +104,6 @@ impl From for GetNftInfoError { fn from(e: ProtectFromSpamError) -> Self { GetNftInfoError::ProtectFromSpamError(e) } } -impl From for GetNftInfoError { - fn from(e: LockDBError) -> Self { GetNftInfoError::DbError(e.to_string()) } -} - impl From for GetNftInfoError { fn from(e: TransferConfirmationsError) -> Self { GetNftInfoError::TransferConfirmationsError(e) } } @@ -118,10 +116,6 @@ impl From for GetNftInfoError { } } -impl From for GetNftInfoError { - fn from(e: NumConversError) -> Self { GetNftInfoError::NumConversError(e.to_string()) } -} - impl HttpStatusCode for GetNftInfoError { fn status_code(&self) -> StatusCode { match self { @@ -154,6 +148,7 @@ impl HttpStatusCode for GetNftInfoError { #[derive(Clone, Debug, Deserialize, Display, EnumFromStringify, PartialEq, Serialize, SerializeErrorType)] #[serde(tag = "error_type", content = "error_data")] pub enum UpdateNftError { + #[from_stringify("LockDBError")] #[display(fmt = "DB error {}", _0)] DbError(String), #[display(fmt = "Internal: {}", _0)] @@ -239,10 +234,6 @@ impl From for UpdateNftError { fn from(e: ProtectFromSpamError) -> Self { UpdateNftError::ProtectFromSpamError(e) } } -impl From for UpdateNftError { - fn from(e: LockDBError) -> Self { UpdateNftError::DbError(e.to_string()) } -} - impl From for UpdateNftError { fn from(e: CoinFindError) -> Self { match e { @@ -389,10 +380,11 @@ impl From for TransferConfirmationsError { } /// Enumerates errors that can occur while clearing NFT data from the database. -#[derive(Clone, Debug, Deserialize, Display, PartialEq, Serialize, SerializeErrorType)] +#[derive(Clone, Debug, Deserialize, Display, EnumFromStringify, PartialEq, Serialize, SerializeErrorType)] #[serde(tag = "error_type", content = "error_data")] pub enum ClearNftDbError { /// Represents errors related to database operations. + #[from_stringify("LockDBError")] #[display(fmt = "DB error {}", _0)] DbError(String), /// Indicates internal errors not directly associated with database operations. @@ -407,10 +399,6 @@ impl From for ClearNftDbError { fn from(err: T) -> Self { ClearNftDbError::DbError(format!("{:?}", err)) } } -impl From for ClearNftDbError { - fn from(e: LockDBError) -> Self { ClearNftDbError::DbError(e.to_string()) } -} - impl HttpStatusCode for ClearNftDbError { fn status_code(&self) -> StatusCode { match self { diff --git a/mm2src/coins/utxo/rpc_clients.rs b/mm2src/coins/utxo/rpc_clients.rs index 56a1c9289c..a2ed5a8aa5 100644 --- a/mm2src/coins/utxo/rpc_clients.rs +++ b/mm2src/coins/utxo/rpc_clients.rs @@ -4,7 +4,8 @@ use crate::utxo::utxo_block_header_storage::BlockHeaderStorage; use crate::utxo::{output_script, sat_from_big_decimal, GetBlockHeaderError, GetConfirmedTxError, GetTxError, GetTxHeightError, ScripthashNotification}; -use crate::{big_decimal_from_sat_unsigned, NumConversError, RpcTransportEventHandler, RpcTransportEventHandlerShared}; +use crate::{big_decimal_from_sat_unsigned, MyAddressError, NumConversError, RpcTransportEventHandler, + RpcTransportEventHandlerShared}; use async_trait::async_trait; use chain::{BlockHeader, BlockHeaderBits, BlockHeaderNonce, OutPoint, Transaction as UtxoTx, TransactionInput, TxHashAlgo}; @@ -18,6 +19,7 @@ use common::log::{debug, LogOnError}; use common::log::{error, info, warn}; use common::{median, now_float, now_ms, now_sec, OrdRange}; use derive_more::Display; +use enum_derives::EnumFromStringify; use futures::channel::oneshot as async_oneshot; use futures::compat::{Future01CompatExt, Stream01CompatExt}; use futures::future::{join_all, FutureExt, TryFutureExt}; @@ -292,11 +294,12 @@ pub struct SpentOutputInfo { pub type UtxoRpcResult = Result>; pub type UtxoRpcFut = Box> + Send + 'static>; -#[derive(Debug, Display)] +#[derive(Debug, Display, EnumFromStringify)] pub enum UtxoRpcError { Transport(JsonRpcError), ResponseParseError(JsonRpcError), InvalidResponse(String), + #[from_stringify("MyAddressError")] Internal(String), } From cd25455fd0e8b1bad6f52d8ed096b61e3ae985aa Mon Sep 17 00:00:00 2001 From: laruh Date: Fri, 29 Mar 2024 16:35:45 +0700 Subject: [PATCH 56/80] try_tx_s! macro instead of map_err TransactionErr::Plain(ERRL!("{}", e)) --- mm2src/coins/eth.rs | 162 +++++++++++++++++---------------------- mm2src/coins/lp_coins.rs | 21 +---- mm2src/coins/utxo/slp.rs | 5 +- 3 files changed, 73 insertions(+), 115 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index ce543f7842..3b269eca4f 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -71,7 +71,6 @@ use serialization::{CompactInteger, Serializable, Stream}; use sha3::{Digest, Keccak256}; use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; -use std::num::TryFromIntError; use std::ops::Deref; #[cfg(not(target_arch = "wasm32"))] use std::path::PathBuf; use std::str::from_utf8; @@ -6344,9 +6343,9 @@ impl MakerNftSwapOpsV2 for EthCoin { async fn refund_nft_maker_payment_v2_timelock( &self, - _args: RefundPaymentArgs<'_>, + args: RefundPaymentArgs<'_>, ) -> Result { - todo!() + self.refund_nft_maker_payment_v2_timelock_impl(args).await } async fn refund_nft_maker_payment_v2_secret( @@ -6362,56 +6361,45 @@ impl EthCoin { &self, args: SendNftMakerPaymentArgs<'_, Self>, ) -> Result { - let contract_type = self.parse_contract_type(args.contract_type)?; - self.validate_payment_args( + let contract_type = try_tx_s!(self.parse_contract_type(args.contract_type)); + try_tx_s!(self.validate_payment_args( args.taker_secret_hash, args.maker_secret_hash, &args.amount, &contract_type, - ) - .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + )); - let taker_address = addr_from_raw_pubkey(args.taker_pub).map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; - let token_address = self.parse_token_contract_address(args.token_address)?; - let swap_contract_address = self.parse_token_contract_address(args.swap_contract_address)?; - let time_lock_u32 = args - .time_lock - .try_into() - .map_err(|e: TryFromIntError| TransactionErr::Plain(ERRL!("{}", e)))?; + let taker_address = try_tx_s!(addr_from_raw_pubkey(args.taker_pub)); + let token_address = try_tx_s!(self.parse_token_contract_address(args.token_address)); + let swap_contract_address = try_tx_s!(self.parse_token_contract_address(args.swap_contract_address)); + let time_lock_u32 = try_tx_s!(args.time_lock.try_into()); let token_id_u256 = U256::from(args.token_id); let htlc_data = self.prepare_htlc_data(&args, taker_address, token_address, time_lock_u32); match &self.coin_type { EthCoinType::Nft { .. } => match contract_type { ContractType::Erc1155 => { - let function = ERC1155_CONTRACT - .function("safeTransferFrom") - .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; - let amount_u256 = U256::from_dec_str(&args.amount.to_string()) - .map_err(|e| NumConversError::new(ERRL!("{}", e)))?; - let data = function - .encode_input(&[ - Token::Address(self.my_address), - Token::Address(swap_contract_address), - Token::Uint(token_id_u256), - Token::Uint(amount_u256), - Token::Bytes(htlc_data), - ]) - .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + let function = try_tx_s!(ERC1155_CONTRACT.function("safeTransferFrom")); + let amount_u256 = try_tx_s!(U256::from_dec_str(&args.amount.to_string())); + let data = try_tx_s!(function.encode_input(&[ + Token::Address(self.my_address), + Token::Address(swap_contract_address), + Token::Uint(token_id_u256), + Token::Uint(amount_u256), + Token::Bytes(htlc_data), + ])); self.sign_and_send_transaction(0.into(), Action::Call(token_address), data, U256::from(ETH_GAS)) .compat() .await }, ContractType::Erc721 => { - let function = self.erc721_transfer_with_data()?; - let data = function - .encode_input(&[ - Token::Address(self.my_address), - Token::Address(swap_contract_address), - Token::Uint(token_id_u256), - Token::Bytes(htlc_data), - ]) - .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + let function = try_tx_s!(self.erc721_transfer_with_data()); + let data = try_tx_s!(function.encode_input(&[ + Token::Address(self.my_address), + Token::Address(swap_contract_address), + Token::Uint(token_id_u256), + Token::Bytes(htlc_data), + ])); self.sign_and_send_transaction(0.into(), Action::Call(token_address), data, U256::from(ETH_GAS)) .compat() .await @@ -6645,24 +6633,19 @@ impl EthCoin { &self, args: SpendNftMakerPaymentArgs<'_, Self>, ) -> Result { - let contract_type = self.parse_contract_type(args.contract_type)?; - let etomic_swap_contract = self.parse_token_contract_address(args.swap_contract_address)?; + let contract_type = try_tx_s!(self.parse_contract_type(args.contract_type)); + let etomic_swap_contract = try_tx_s!(self.parse_token_contract_address(args.swap_contract_address)); if args.maker_secret.len() != 32 { return Err(TransactionErr::Plain(ERRL!("maker_secret must be 32 bytes"))); } match self.coin_type { EthCoinType::Nft { .. } => match contract_type { ContractType::Erc1155 => { - let spend_func = NFT_SWAP_CONTRACT - .function("spendErc1155MakerPayment") - .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; - let send_func = ERC1155_CONTRACT - .function("safeTransferFrom") - .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; - let decoded = decode_contract_call(send_func, &args.maker_payment_tx.data) - .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; - let (state, htlc_params) = self - .status_and_htlc_params_from_tx_data( + let spend_func = try_tx_s!(NFT_SWAP_CONTRACT.function("spendErc1155MakerPayment")); + let send_func = try_tx_s!(ERC1155_CONTRACT.function("safeTransferFrom")); + let decoded = try_tx_s!(decode_contract_call(send_func, &args.maker_payment_tx.data)); + let (state, htlc_params) = try_tx_s!( + self.status_and_htlc_params_from_tx_data( etomic_swap_contract, &NFT_SWAP_CONTRACT, &decoded, @@ -6670,7 +6653,7 @@ impl EthCoin { StateType::MakerPayments, ) .await - .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + ); if state != U256::from(MakerPaymentState::PaymentSent as u8) { return Err(TransactionErr::Plain(ERRL!( "Payment {:?} state is not PAYMENT_STATE_SENT, got {}", @@ -6678,17 +6661,15 @@ impl EthCoin { state ))); } - let data = spend_func - .encode_input(&[ - htlc_params[0].clone(), // swap_id - Token::Address(args.maker_payment_tx.sender()), - Token::FixedBytes(args.taker_secret_hash.to_vec()), - Token::FixedBytes(args.maker_secret.to_vec()), - htlc_params[2].clone(), // tokenAddress - decoded[2].clone(), // tokenId - decoded[3].clone(), // amount - ]) - .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + let data = try_tx_s!(spend_func.encode_input(&[ + htlc_params[0].clone(), // swap_id + Token::Address(args.maker_payment_tx.sender()), + Token::FixedBytes(args.taker_secret_hash.to_vec()), + Token::FixedBytes(args.maker_secret.to_vec()), + htlc_params[2].clone(), // tokenAddress + decoded[2].clone(), // tokenId + decoded[3].clone(), // amount + ])); self.sign_and_send_transaction( 0.into(), Action::Call(etomic_swap_contract), @@ -6699,14 +6680,11 @@ impl EthCoin { .await }, ContractType::Erc721 => { - let spend_func = NFT_SWAP_CONTRACT - .function("spendErc721MakerPayment") - .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; - let send_func = self.erc721_transfer_with_data()?; - let decoded = decode_contract_call(send_func, &args.maker_payment_tx.data) - .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; - let (state, htlc_params) = self - .status_and_htlc_params_from_tx_data( + let spend_func = try_tx_s!(NFT_SWAP_CONTRACT.function("spendErc721MakerPayment")); + let send_func = try_tx_s!(self.erc721_transfer_with_data()); + let decoded = try_tx_s!(decode_contract_call(send_func, &args.maker_payment_tx.data)); + let (state, htlc_params) = try_tx_s!( + self.status_and_htlc_params_from_tx_data( etomic_swap_contract, &NFT_SWAP_CONTRACT, &decoded, @@ -6714,7 +6692,7 @@ impl EthCoin { StateType::MakerPayments, ) .await - .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + ); if state != U256::from(MakerPaymentState::PaymentSent as u8) { return Err(TransactionErr::Plain(ERRL!( "Payment {:?} state is not PAYMENT_STATE_SENT, got {}", @@ -6722,16 +6700,14 @@ impl EthCoin { state ))); } - let data = spend_func - .encode_input(&[ - htlc_params[0].clone(), // swap_id - Token::Address(args.maker_payment_tx.sender()), - Token::FixedBytes(args.taker_secret_hash.to_vec()), - Token::FixedBytes(args.maker_secret.to_vec()), - htlc_params[2].clone(), // tokenAddress - decoded[2].clone(), // tokenId - ]) - .map_err(|e| TransactionErr::Plain(ERRL!("{}", e)))?; + let data = try_tx_s!(spend_func.encode_input(&[ + htlc_params[0].clone(), // swap_id + Token::Address(args.maker_payment_tx.sender()), + Token::FixedBytes(args.taker_secret_hash.to_vec()), + Token::FixedBytes(args.maker_secret.to_vec()), + htlc_params[2].clone(), // tokenAddress + decoded[2].clone(), // tokenId + ])); self.sign_and_send_transaction( 0.into(), Action::Call(etomic_swap_contract), @@ -6752,11 +6728,11 @@ impl EthCoin { &self, swap_contract_addr: Address, contract: &Contract, - decoded: &[Token], + decoded_data: &[Token], index: usize, state_type: StateType, ) -> Result<(U256, Vec), PaymentStatusErr> { - if let Some(Token::Bytes(data_bytes)) = decoded.get(index) { + if let Some(Token::Bytes(data_bytes)) = decoded_data.get(index) { if let Ok(htlc_params) = ethabi::decode(htlc_params(), data_bytes) { let state = self .payment_status_v2(swap_contract_addr, htlc_params[0].clone(), contract, state_type) @@ -6773,6 +6749,16 @@ impl EthCoin { ))) } } + + async fn refund_nft_maker_payment_v2_timelock_impl( + &self, + args: RefundPaymentArgs<'_>, + ) -> Result { + let _etomic_swap_contract = try_tx_s!(args.swap_contract_address.try_to_address()); + let tx: UnverifiedTransaction = try_tx_s!(rlp::decode(args.payment_tx)); + let _payment = try_tx_s!(SignedEthTx::new(tx)); + todo!() + } } // Representation of the Solidity HTLCParams struct. @@ -6802,10 +6788,12 @@ pub enum Erc721FunctionError { FunctionNotFound(String), } -#[derive(Debug, Display)] +#[derive(Debug, Display, EnumFromStringify)] pub enum PaymentStatusErr { + #[from_stringify("ethabi::Error")] #[display(fmt = "Abi error: {}", _0)] AbiError(String), + #[from_stringify("web3::Error")] #[display(fmt = "Transport error: {}", _0)] Transport(String), #[display(fmt = "Internal error: {}", _0)] @@ -6814,14 +6802,6 @@ pub enum PaymentStatusErr { TxDeserializationError(String), } -impl From for PaymentStatusErr { - fn from(e: ethabi::Error) -> Self { Self::AbiError(e.to_string()) } -} - -impl From for PaymentStatusErr { - fn from(err: web3::Error) -> Self { Self::Transport(err.to_string()) } -} - #[allow(dead_code)] enum StateType { MakerPayments, diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index d74d380834..6a2470d66d 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -294,7 +294,6 @@ use script::Script; pub mod z_coin; use crate::coin_errors::ValidatePaymentResult; -use crate::eth::{Erc721FunctionError, NftAssocTypesError}; use crate::utxo::swap_proto_v2_scripts; use crate::utxo::utxo_common::{payment_script, WaitForOutputSpendErr}; use z_coin::{ZCoin, ZcoinProtocolInfo}; @@ -638,9 +637,6 @@ pub enum TransactionErr { #[from_stringify("keys::Error")] Plain(String), ProtocolNotSupported(String), - #[from_stringify("NftAssocTypesError")] - NftAssocTypesError(String), - NumConversError(NumConversError), } impl TransactionErr { @@ -658,22 +654,7 @@ impl TransactionErr { pub fn get_plain_text_format(&self) -> String { match self { TransactionErr::TxRecoverable(_, err) => err.to_string(), - TransactionErr::Plain(err) - | TransactionErr::ProtocolNotSupported(err) - | TransactionErr::NftAssocTypesError(err) => err.to_string(), - TransactionErr::NumConversError(err) => err.to_string(), - } - } -} - -impl From for TransactionErr { - fn from(e: NumConversError) -> Self { TransactionErr::NumConversError(e) } -} - -impl From for TransactionErr { - fn from(e: Erc721FunctionError) -> Self { - match e { - Erc721FunctionError::AbiError(e) | Erc721FunctionError::FunctionNotFound(e) => Self::Plain(e), + TransactionErr::Plain(err) | TransactionErr::ProtocolNotSupported(err) => err.to_string(), } } } diff --git a/mm2src/coins/utxo/slp.rs b/mm2src/coins/utxo/slp.rs index f1fc1e3bc5..ce531e4b56 100644 --- a/mm2src/coins/utxo/slp.rs +++ b/mm2src/coins/utxo/slp.rs @@ -2171,10 +2171,7 @@ mod slp_tests { let err = match tx_err.clone() { TransactionErr::TxRecoverable(_tx, err) => err, - TransactionErr::Plain(err) - | TransactionErr::ProtocolNotSupported(err) - | TransactionErr::NftAssocTypesError(err) => err, - TransactionErr::NumConversError(err) => err.to_string(), + TransactionErr::Plain(err) | TransactionErr::ProtocolNotSupported(err) => err, }; println!("{:?}", err); From 7c9ea1770b00b8ed7117aeb5df8badab6254d84d Mon Sep 17 00:00:00 2001 From: laruh Date: Mon, 1 Apr 2024 19:34:02 +0700 Subject: [PATCH 57/80] rename states to MakerPaymentStateV2 and TakerPaymentStateV2, add missing / --- mm2src/coins/eth.rs | 10 +++++----- mm2src/coins/lp_coins.rs | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 3b269eca4f..0df6f82eec 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -149,14 +149,14 @@ pub enum PaymentState { Refunded, } #[allow(dead_code)] -enum MakerPaymentState { +enum MakerPaymentStateV2 { Uninitialized, PaymentSent, TakerSpent, MakerRefunded, } #[allow(dead_code)] -enum TakerPaymentState { +enum TakerPaymentStateV2 { Uninitialized, PaymentSent, TakerApproved, @@ -6513,7 +6513,7 @@ impl EthCoin { StateType::MakerPayments, ) .await?; - if maker_status != U256::from(MakerPaymentState::PaymentSent as u8) { + if maker_status != U256::from(MakerPaymentStateV2::PaymentSent as u8) { return MmError::err(ValidatePaymentError::UnexpectedPaymentState(format!( "NFT Maker Payment state is not PAYMENT_STATE_SENT, got {}", maker_status @@ -6654,7 +6654,7 @@ impl EthCoin { ) .await ); - if state != U256::from(MakerPaymentState::PaymentSent as u8) { + if state != U256::from(MakerPaymentStateV2::PaymentSent as u8) { return Err(TransactionErr::Plain(ERRL!( "Payment {:?} state is not PAYMENT_STATE_SENT, got {}", args.maker_payment_tx, @@ -6693,7 +6693,7 @@ impl EthCoin { ) .await ); - if state != U256::from(MakerPaymentState::PaymentSent as u8) { + if state != U256::from(MakerPaymentStateV2::PaymentSent as u8) { return Err(TransactionErr::Plain(ERRL!( "Payment {:?} state is not PAYMENT_STATE_SENT, got {}", args.maker_payment_tx, diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 6a2470d66d..dbe53d3d94 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -1515,7 +1515,7 @@ pub struct SendNftMakerPaymentArgs<'a, Coin: CoinAssocTypes + NftAssocTypes + ?S pub token_id: &'a [u8], /// The type of smart contract that governs this NFT pub contract_type: &'a [u8], - // Etomic swap contract address + /// Etomic swap contract address pub swap_contract_address: &'a [u8], } @@ -1559,7 +1559,7 @@ pub struct ValidateNftMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { pub token_id: &'a [u8], /// The type of smart contract that governs this NFT pub contract_type: &'a [u8], - // Etomic swap contract address + /// Etomic swap contract address pub swap_contract_address: &'a [u8], } @@ -1614,7 +1614,7 @@ pub struct SpendNftMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { pub swap_unique_data: &'a [u8], /// The type of smart contract that governs this NFT pub contract_type: &'a [u8], - // Etomic swap contract address + /// Etomic swap contract address pub swap_contract_address: &'a [u8], } From ba61d495b5db96f79948c6a7714713592f825ca8 Mon Sep 17 00:00:00 2001 From: laruh Date: Mon, 1 Apr 2024 19:53:10 +0700 Subject: [PATCH 58/80] rename param to swap_contract, rename function to parse_contract_address --- mm2src/coins/eth.rs | 20 ++++++++++---------- mm2src/coins/lp_coins.rs | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 0df6f82eec..e3698ad5f5 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -6299,7 +6299,7 @@ impl NftAssocTypes for EthCoin { type ContractType = ContractType; type ContractTypeParseError = NftAssocTypesError; - fn parse_token_contract_address( + fn parse_contract_address( &self, token_contract_addr: &[u8], ) -> Result { @@ -6370,8 +6370,8 @@ impl EthCoin { )); let taker_address = try_tx_s!(addr_from_raw_pubkey(args.taker_pub)); - let token_address = try_tx_s!(self.parse_token_contract_address(args.token_address)); - let swap_contract_address = try_tx_s!(self.parse_token_contract_address(args.swap_contract_address)); + let token_address = try_tx_s!(self.parse_contract_address(args.token_address)); + let swap_contract_address = try_tx_s!(self.parse_contract_address(args.swap_contract_address)); let time_lock_u32 = try_tx_s!(args.time_lock.try_into()); let token_id_u256 = U256::from(args.token_id); let htlc_data = self.prepare_htlc_data(&args, taker_address, token_address, time_lock_u32); @@ -6497,8 +6497,8 @@ impl EthCoin { &contract_type, ) .map_err(ValidatePaymentError::InternalError)?; - let etomic_swap_contract = self.parse_token_contract_address(args.swap_contract_address)?; - let token_address = self.parse_token_contract_address(args.token_address)?; + let etomic_swap_contract = self.parse_contract_address(args.swap_contract_address)?; + let token_address = self.parse_contract_address(args.token_address)?; let maker_address = addr_from_raw_pubkey(args.maker_pub).map_to_mm(ValidatePaymentError::InternalError)?; let time_lock_u32 = args .time_lock @@ -6607,7 +6607,7 @@ impl EthCoin { async fn payment_status_v2( &self, - swap_contract_addr: Address, + swap_contract: Address, swap_id: Token, contract: &Contract, state_type: StateType, @@ -6615,7 +6615,7 @@ impl EthCoin { let function_name = state_type.as_str(); let function = contract.function(function_name)?; let data = function.encode_input(&[swap_id])?; - let bytes = self.call_request(swap_contract_addr, None, Some(data.into())).await?; + let bytes = self.call_request(swap_contract, None, Some(data.into())).await?; let decoded_tokens = function.decode_output(&bytes.0)?; let state = decoded_tokens.get(2).ok_or_else(|| { PaymentStatusErr::Internal("Payment status must contain 'state' as the 2nd token".to_string()) @@ -6634,7 +6634,7 @@ impl EthCoin { args: SpendNftMakerPaymentArgs<'_, Self>, ) -> Result { let contract_type = try_tx_s!(self.parse_contract_type(args.contract_type)); - let etomic_swap_contract = try_tx_s!(self.parse_token_contract_address(args.swap_contract_address)); + let etomic_swap_contract = try_tx_s!(self.parse_contract_address(args.swap_contract_address)); if args.maker_secret.len() != 32 { return Err(TransactionErr::Plain(ERRL!("maker_secret must be 32 bytes"))); } @@ -6726,7 +6726,7 @@ impl EthCoin { async fn status_and_htlc_params_from_tx_data( &self, - swap_contract_addr: Address, + swap_contract: Address, contract: &Contract, decoded_data: &[Token], index: usize, @@ -6735,7 +6735,7 @@ impl EthCoin { if let Some(Token::Bytes(data_bytes)) = decoded_data.get(index) { if let Ok(htlc_params) = ethabi::decode(htlc_params(), data_bytes) { let state = self - .payment_status_v2(swap_contract_addr, htlc_params[0].clone(), contract, state_type) + .payment_status_v2(swap_contract, htlc_params[0].clone(), contract, state_type) .await?; Ok((state, htlc_params)) } else { diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index dbe53d3d94..03bbd0f4be 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -1471,7 +1471,7 @@ pub trait NftAssocTypes { type ContractType: ToBytes + Send + Sync; type ContractTypeParseError: fmt::Debug + Send + fmt::Display; - fn parse_token_contract_address( + fn parse_contract_address( &self, token_contract_addr: &[u8], ) -> Result; From 3cdd257d7d40c9efc2c32dd413e20324d88642f2 Mon Sep 17 00:00:00 2001 From: laruh Date: Tue, 2 Apr 2024 14:00:43 +0700 Subject: [PATCH 59/80] create mod trading_proto_v2 for nft --- mm2src/coins/coin_errors.rs | 5 +- mm2src/coins/eth.rs | 608 +------------------ mm2src/coins/nft.rs | 1 + mm2src/coins/nft/trading_proto_v2/errors.rs | 27 + mm2src/coins/nft/trading_proto_v2/mod.rs | 549 +++++++++++++++++ mm2src/coins/nft/trading_proto_v2/structs.rs | 33 + 6 files changed, 626 insertions(+), 597 deletions(-) create mode 100644 mm2src/coins/nft/trading_proto_v2/errors.rs create mode 100644 mm2src/coins/nft/trading_proto_v2/mod.rs create mode 100644 mm2src/coins/nft/trading_proto_v2/structs.rs diff --git a/mm2src/coins/coin_errors.rs b/mm2src/coins/coin_errors.rs index 3df7a2d854..7eff697c62 100644 --- a/mm2src/coins/coin_errors.rs +++ b/mm2src/coins/coin_errors.rs @@ -1,5 +1,6 @@ -use crate::eth::{CoinAssocTypesError, Erc721FunctionError, HtlcParamsError, NftAssocTypesError, PaymentStatusErr}; -use crate::{eth::Web3RpcError, utxo::rpc_clients::UtxoRpcError, NumConversError, UnexpectedDerivationMethod}; +use crate::eth::{CoinAssocTypesError, NftAssocTypesError, Web3RpcError}; +use crate::nft::trading_proto_v2::errors::{Erc721FunctionError, HtlcParamsError, PaymentStatusErr}; +use crate::{utxo::rpc_clients::UtxoRpcError, NumConversError, UnexpectedDerivationMethod}; use enum_derives::EnumFromStringify; use futures01::Future; use mm2_err_handle::prelude::MmError; diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index e3698ad5f5..ff798f8d34 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -33,8 +33,8 @@ use async_trait::async_trait; use bitcrypto::{dhash160, keccak256, ripemd160, sha256}; use common::custom_futures::repeatable::{Ready, Retry, RetryOnError}; use common::custom_futures::timeout::FutureTimerExt; -use common::executor::{abortable_queue::AbortableQueue, AbortableSystem, AbortedError, Timer}; -use common::executor::{AbortSettings, SpawnAbortable}; +use common::executor::{abortable_queue::AbortableQueue, AbortSettings, AbortableSystem, AbortedError, SpawnAbortable, + Timer}; use common::log::{debug, error, info, warn}; use common::number_type_casting::SafeTypeCastingNumbers; use common::{get_utc_timestamp, now_sec, small_rng, DEX_FEE_ADDR_RAW_PUBKEY}; @@ -149,14 +149,14 @@ pub enum PaymentState { Refunded, } #[allow(dead_code)] -enum MakerPaymentStateV2 { +pub(crate) enum MakerPaymentStateV2 { Uninitialized, PaymentSent, TakerSpent, MakerRefunded, } #[allow(dead_code)] -enum TakerPaymentStateV2 { +pub(crate) enum TakerPaymentStateV2 { Uninitialized, PaymentSent, TakerApproved, @@ -188,7 +188,7 @@ const GAS_PRICE_APPROXIMATION_PERCENT_ON_ORDER_ISSUE: u64 = 5; /// - it may increase by 3% during the swap. const GAS_PRICE_APPROXIMATION_PERCENT_ON_TRADE_PREIMAGE: u64 = 7; -const ETH_GAS: u64 = 150_000; +pub(crate) const ETH_GAS: u64 = 150_000; /// Lifetime of generated signed message for gui-auth requests const GUI_AUTH_SIGNED_MESSAGE_LIFETIME_SEC: i64 = 90; @@ -612,7 +612,7 @@ impl EthCoinImpl { } /// The id used to differentiate payments on Etomic swap smart contract - fn etomic_swap_id(&self, time_lock: u32, secret_hash: &[u8]) -> Vec { + pub(crate) fn etomic_swap_id(&self, time_lock: u32, secret_hash: &[u8]) -> Vec { let mut input = vec![]; input.extend_from_slice(&time_lock.to_le_bytes()); input.extend_from_slice(secret_hash); @@ -3431,7 +3431,7 @@ impl EthCoin { #[cfg_attr(test, mockable)] impl EthCoin { - fn sign_and_send_transaction(&self, value: U256, action: Action, data: Vec, gas: U256) -> EthTxFut { + pub(crate) fn sign_and_send_transaction(&self, value: U256, action: Action, data: Vec, gas: U256) -> EthTxFut { let ctx = try_tx_fus!(MmArc::from_weak(&self.ctx).ok_or("!ctx")); let coin = self.clone(); let fut = async move { @@ -4287,7 +4287,12 @@ impl EthCoin { Box::new(fut.boxed().compat().map_to_mm_fut(BalanceError::from)) } - async fn call_request(&self, to: Address, value: Option, data: Option) -> Result { + pub(crate) async fn call_request( + &self, + to: Address, + value: Option, + data: Option, + ) -> Result { let request = CallRequest { from: Some(self.my_address), to: Some(to), @@ -6355,590 +6360,3 @@ impl MakerNftSwapOpsV2 for EthCoin { todo!() } } - -impl EthCoin { - async fn send_nft_maker_payment_v2_impl( - &self, - args: SendNftMakerPaymentArgs<'_, Self>, - ) -> Result { - let contract_type = try_tx_s!(self.parse_contract_type(args.contract_type)); - try_tx_s!(self.validate_payment_args( - args.taker_secret_hash, - args.maker_secret_hash, - &args.amount, - &contract_type, - )); - - let taker_address = try_tx_s!(addr_from_raw_pubkey(args.taker_pub)); - let token_address = try_tx_s!(self.parse_contract_address(args.token_address)); - let swap_contract_address = try_tx_s!(self.parse_contract_address(args.swap_contract_address)); - let time_lock_u32 = try_tx_s!(args.time_lock.try_into()); - let token_id_u256 = U256::from(args.token_id); - let htlc_data = self.prepare_htlc_data(&args, taker_address, token_address, time_lock_u32); - - match &self.coin_type { - EthCoinType::Nft { .. } => match contract_type { - ContractType::Erc1155 => { - let function = try_tx_s!(ERC1155_CONTRACT.function("safeTransferFrom")); - let amount_u256 = try_tx_s!(U256::from_dec_str(&args.amount.to_string())); - let data = try_tx_s!(function.encode_input(&[ - Token::Address(self.my_address), - Token::Address(swap_contract_address), - Token::Uint(token_id_u256), - Token::Uint(amount_u256), - Token::Bytes(htlc_data), - ])); - self.sign_and_send_transaction(0.into(), Action::Call(token_address), data, U256::from(ETH_GAS)) - .compat() - .await - }, - ContractType::Erc721 => { - let function = try_tx_s!(self.erc721_transfer_with_data()); - let data = try_tx_s!(function.encode_input(&[ - Token::Address(self.my_address), - Token::Address(swap_contract_address), - Token::Uint(token_id_u256), - Token::Bytes(htlc_data), - ])); - self.sign_and_send_transaction(0.into(), Action::Call(token_address), data, U256::from(ETH_GAS)) - .compat() - .await - }, - }, - EthCoinType::Eth | EthCoinType::Erc20 { .. } => Err(TransactionErr::ProtocolNotSupported( - "ETH and ERC20 Protocols are not supported for NFT Swaps".to_string(), - )), - } - } - - fn validate_payment_args<'a>( - &self, - taker_secret_hash: &'a [u8], - maker_secret_hash: &'a [u8], - amount: &BigDecimal, - contract_type: &ContractType, - ) -> Result<(), String> { - match contract_type { - ContractType::Erc1155 => { - if !is_positive_integer(amount) { - return Err("ERC-1155 amount must be a positive integer".to_string()); - } - }, - ContractType::Erc721 => { - if amount != &BigDecimal::from(1) { - return Err("ERC-721 amount must be 1".to_string()); - } - }, - } - if taker_secret_hash.len() != 32 { - return Err("taker_secret_hash must be 32 bytes".to_string()); - } - if maker_secret_hash.len() != 32 { - return Err("maker_secret_hash must be 32 bytes".to_string()); - } - - Ok(()) - } - - fn prepare_htlc_data( - &self, - args: &SendNftMakerPaymentArgs<'_, Self>, - taker_address: Address, - token_address: Address, - time_lock: u32, - ) -> Vec { - let id = self.etomic_swap_id(time_lock, args.maker_secret_hash); - ethabi::encode(&[ - Token::FixedBytes(id), - Token::Address(taker_address), - Token::Address(token_address), - Token::FixedBytes(args.taker_secret_hash.to_vec()), - Token::FixedBytes(args.maker_secret_hash.to_vec()), - Token::Uint(U256::from(time_lock)), - ]) - } - - /// ERC721 contract has overloaded versions of the `safeTransferFrom` function, - /// but `Contract::function` method returns only the first if there are overloaded versions of the same function. - /// Provided function retrieves the `safeTransferFrom` variant that includes a `bytes` parameter. - /// This variant is specifically used for transferring ERC721 tokens with additional data. - fn erc721_transfer_with_data(&self) -> Result<ðabi::Function, Erc721FunctionError> { - let functions = ERC721_CONTRACT - .functions_by_name("safeTransferFrom") - .map_err(|e| Erc721FunctionError::AbiError(ERRL!("{}", e)))?; - - // Find the correct function variant by inspecting the input parameters. - let function = functions - .iter() - .find(|f| { - f.inputs.len() == 4 - && matches!( - f.inputs.last().map(|input| &input.kind), - Some(ðabi::ParamType::Bytes) - ) - }) - .ok_or_else(|| { - Erc721FunctionError::FunctionNotFound( - "Failed to find the correct safeTransferFrom function variant".to_string(), - ) - })?; - Ok(function) - } - - async fn validate_nft_maker_payment_v2_impl( - &self, - args: ValidateNftMakerPaymentArgs<'_, Self>, - ) -> ValidatePaymentResult<()> { - let contract_type = self.parse_contract_type(args.contract_type)?; - self.validate_payment_args( - args.taker_secret_hash, - args.maker_secret_hash, - &args.amount, - &contract_type, - ) - .map_err(ValidatePaymentError::InternalError)?; - let etomic_swap_contract = self.parse_contract_address(args.swap_contract_address)?; - let token_address = self.parse_contract_address(args.token_address)?; - let maker_address = addr_from_raw_pubkey(args.maker_pub).map_to_mm(ValidatePaymentError::InternalError)?; - let time_lock_u32 = args - .time_lock - .try_into() - .map_err(ValidatePaymentError::TimelockOverflow)?; - let swap_id = self.etomic_swap_id(time_lock_u32, args.maker_secret_hash); - let maker_status = self - .payment_status_v2( - etomic_swap_contract, - Token::FixedBytes(swap_id.clone()), - &NFT_SWAP_CONTRACT, - StateType::MakerPayments, - ) - .await?; - if maker_status != U256::from(MakerPaymentStateV2::PaymentSent as u8) { - return MmError::err(ValidatePaymentError::UnexpectedPaymentState(format!( - "NFT Maker Payment state is not PAYMENT_STATE_SENT, got {}", - maker_status - ))); - } - let tx_from_rpc = self - .transaction(TransactionId::Hash(args.maker_payment_tx.hash)) - .await?; - let tx_from_rpc = tx_from_rpc.as_ref().ok_or_else(|| { - ValidatePaymentError::TxDoesNotExist(format!( - "Didn't find provided tx {:?} on ETH node", - args.maker_payment_tx.hash - )) - })?; - if tx_from_rpc.from != Some(maker_address) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment tx {:?} was sent from wrong address, expected {:?}", - tx_from_rpc, maker_address - ))); - } - // As NFT owner calls "safeTransferFrom" directly, then in Transaction 'to' field we expect token_address - if tx_from_rpc.to != Some(token_address) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment tx {:?} was sent to wrong address, expected {:?}", - tx_from_rpc, token_address, - ))); - } - match self.coin_type { - EthCoinType::Nft { .. } => match contract_type { - ContractType::Erc1155 => { - let function = ERC1155_CONTRACT - .function("safeTransferFrom") - .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; - let decoded = decode_contract_call(function, &tx_from_rpc.input.0) - .map_to_mm(|err| ValidatePaymentError::TxDeserializationError(err.to_string()))?; - - let validation_params = ValidationParams { - maker_address, - etomic_swap_contract, - token_id: args.token_id, - amount: Some(args.amount.to_string()), - }; - validate_decoded_data(&decoded, &validation_params)?; - - let taker_address = - addr_from_raw_pubkey(args.taker_pub).map_to_mm(ValidatePaymentError::InternalError)?; - let htlc_params = ExpectedHtlcParams { - swap_id, - taker_address, - token_address, - taker_secret_hash: args.taker_secret_hash.to_vec(), - maker_secret_hash: args.maker_secret_hash.to_vec(), - time_lock: U256::from(args.time_lock), - }; - decode_and_validate_htlc_params(decoded, 4, htlc_params)?; - }, - ContractType::Erc721 => { - let function = self.erc721_transfer_with_data()?; - let decoded = decode_contract_call(function, &tx_from_rpc.input.0) - .map_to_mm(|err| ValidatePaymentError::TxDeserializationError(err.to_string()))?; - - let validation_params = ValidationParams { - maker_address, - etomic_swap_contract, - token_id: args.token_id, - amount: None, - }; - validate_decoded_data(&decoded, &validation_params)?; - - let taker_address = - addr_from_raw_pubkey(args.taker_pub).map_to_mm(ValidatePaymentError::InternalError)?; - let htlc_params = ExpectedHtlcParams { - swap_id, - taker_address, - token_address, - taker_secret_hash: args.taker_secret_hash.to_vec(), - maker_secret_hash: args.maker_secret_hash.to_vec(), - time_lock: U256::from(args.time_lock), - }; - decode_and_validate_htlc_params(decoded, 3, htlc_params)?; - }, - }, - EthCoinType::Eth | EthCoinType::Erc20 { .. } => { - return MmError::err(ValidatePaymentError::InternalError( - "EthCoinType must be Nft".to_string(), - )) - }, - } - Ok(()) - } - - async fn payment_status_v2( - &self, - swap_contract: Address, - swap_id: Token, - contract: &Contract, - state_type: StateType, - ) -> Result { - let function_name = state_type.as_str(); - let function = contract.function(function_name)?; - let data = function.encode_input(&[swap_id])?; - let bytes = self.call_request(swap_contract, None, Some(data.into())).await?; - let decoded_tokens = function.decode_output(&bytes.0)?; - let state = decoded_tokens.get(2).ok_or_else(|| { - PaymentStatusErr::Internal("Payment status must contain 'state' as the 2nd token".to_string()) - })?; - match state { - Token::Uint(state) => Ok(*state), - _ => Err(PaymentStatusErr::Internal(format!( - "Payment status must be Uint, got {:?}", - state - ))), - } - } - - async fn spend_nft_maker_payment_v2_impl( - &self, - args: SpendNftMakerPaymentArgs<'_, Self>, - ) -> Result { - let contract_type = try_tx_s!(self.parse_contract_type(args.contract_type)); - let etomic_swap_contract = try_tx_s!(self.parse_contract_address(args.swap_contract_address)); - if args.maker_secret.len() != 32 { - return Err(TransactionErr::Plain(ERRL!("maker_secret must be 32 bytes"))); - } - match self.coin_type { - EthCoinType::Nft { .. } => match contract_type { - ContractType::Erc1155 => { - let spend_func = try_tx_s!(NFT_SWAP_CONTRACT.function("spendErc1155MakerPayment")); - let send_func = try_tx_s!(ERC1155_CONTRACT.function("safeTransferFrom")); - let decoded = try_tx_s!(decode_contract_call(send_func, &args.maker_payment_tx.data)); - let (state, htlc_params) = try_tx_s!( - self.status_and_htlc_params_from_tx_data( - etomic_swap_contract, - &NFT_SWAP_CONTRACT, - &decoded, - 4, - StateType::MakerPayments, - ) - .await - ); - if state != U256::from(MakerPaymentStateV2::PaymentSent as u8) { - return Err(TransactionErr::Plain(ERRL!( - "Payment {:?} state is not PAYMENT_STATE_SENT, got {}", - args.maker_payment_tx, - state - ))); - } - let data = try_tx_s!(spend_func.encode_input(&[ - htlc_params[0].clone(), // swap_id - Token::Address(args.maker_payment_tx.sender()), - Token::FixedBytes(args.taker_secret_hash.to_vec()), - Token::FixedBytes(args.maker_secret.to_vec()), - htlc_params[2].clone(), // tokenAddress - decoded[2].clone(), // tokenId - decoded[3].clone(), // amount - ])); - self.sign_and_send_transaction( - 0.into(), - Action::Call(etomic_swap_contract), - data, - U256::from(ETH_GAS), - ) - .compat() - .await - }, - ContractType::Erc721 => { - let spend_func = try_tx_s!(NFT_SWAP_CONTRACT.function("spendErc721MakerPayment")); - let send_func = try_tx_s!(self.erc721_transfer_with_data()); - let decoded = try_tx_s!(decode_contract_call(send_func, &args.maker_payment_tx.data)); - let (state, htlc_params) = try_tx_s!( - self.status_and_htlc_params_from_tx_data( - etomic_swap_contract, - &NFT_SWAP_CONTRACT, - &decoded, - 3, - StateType::MakerPayments, - ) - .await - ); - if state != U256::from(MakerPaymentStateV2::PaymentSent as u8) { - return Err(TransactionErr::Plain(ERRL!( - "Payment {:?} state is not PAYMENT_STATE_SENT, got {}", - args.maker_payment_tx, - state - ))); - } - let data = try_tx_s!(spend_func.encode_input(&[ - htlc_params[0].clone(), // swap_id - Token::Address(args.maker_payment_tx.sender()), - Token::FixedBytes(args.taker_secret_hash.to_vec()), - Token::FixedBytes(args.maker_secret.to_vec()), - htlc_params[2].clone(), // tokenAddress - decoded[2].clone(), // tokenId - ])); - self.sign_and_send_transaction( - 0.into(), - Action::Call(etomic_swap_contract), - data, - U256::from(ETH_GAS), - ) - .compat() - .await - }, - }, - EthCoinType::Eth | EthCoinType::Erc20 { .. } => Err(TransactionErr::ProtocolNotSupported( - "ETH and ERC20 Protocols are not supported for NFT Swaps".to_string(), - )), - } - } - - async fn status_and_htlc_params_from_tx_data( - &self, - swap_contract: Address, - contract: &Contract, - decoded_data: &[Token], - index: usize, - state_type: StateType, - ) -> Result<(U256, Vec), PaymentStatusErr> { - if let Some(Token::Bytes(data_bytes)) = decoded_data.get(index) { - if let Ok(htlc_params) = ethabi::decode(htlc_params(), data_bytes) { - let state = self - .payment_status_v2(swap_contract, htlc_params[0].clone(), contract, state_type) - .await?; - Ok((state, htlc_params)) - } else { - Err(PaymentStatusErr::TxDeserializationError(ERRL!( - "Failed to decode HTLCParams from data_bytes" - ))) - } - } else { - Err(PaymentStatusErr::TxDeserializationError(ERRL!( - "Failed to decode HTLCParams from data_bytes" - ))) - } - } - - async fn refund_nft_maker_payment_v2_timelock_impl( - &self, - args: RefundPaymentArgs<'_>, - ) -> Result { - let _etomic_swap_contract = try_tx_s!(args.swap_contract_address.try_to_address()); - let tx: UnverifiedTransaction = try_tx_s!(rlp::decode(args.payment_tx)); - let _payment = try_tx_s!(SignedEthTx::new(tx)); - todo!() - } -} - -// Representation of the Solidity HTLCParams struct. -// -// struct HTLCParams { -// bytes32 id; -// address taker; -// address tokenAddress; -// bytes32 takerSecretHash; -// bytes32 makerSecretHash; -// uint32 paymentLockTime; -// } -fn htlc_params() -> &'static [ethabi::ParamType] { - &[ - ethabi::ParamType::FixedBytes(32), - ethabi::ParamType::Address, - ethabi::ParamType::Address, - ethabi::ParamType::FixedBytes(32), - ethabi::ParamType::FixedBytes(32), - ethabi::ParamType::Uint(256), - ] -} - -#[derive(Debug, Display)] -pub enum Erc721FunctionError { - AbiError(String), - FunctionNotFound(String), -} - -#[derive(Debug, Display, EnumFromStringify)] -pub enum PaymentStatusErr { - #[from_stringify("ethabi::Error")] - #[display(fmt = "Abi error: {}", _0)] - AbiError(String), - #[from_stringify("web3::Error")] - #[display(fmt = "Transport error: {}", _0)] - Transport(String), - #[display(fmt = "Internal error: {}", _0)] - Internal(String), - #[display(fmt = "Tx deserialization error: {}", _0)] - TxDeserializationError(String), -} - -#[allow(dead_code)] -enum StateType { - MakerPayments, - TakerPayments, -} - -impl StateType { - fn as_str(&self) -> &'static str { - match self { - StateType::MakerPayments => "makerPayments", - StateType::TakerPayments => "takerPayments", - } - } -} - -/// function to check if BigDecimal is a positive integer -#[inline(always)] -fn is_positive_integer(amount: &BigDecimal) -> bool { amount == &amount.with_scale(0) && amount > &BigDecimal::from(0) } - -struct ValidationParams<'a> { - maker_address: Address, - etomic_swap_contract: Address, - token_id: &'a [u8], - // Optional, as it's not needed for ERC721 - amount: Option, -} - -/// Validates decoded data from tx input, related to `safeTransferFrom` contract call -fn validate_decoded_data(decoded: &[Token], params: &ValidationParams) -> Result<(), MmError> { - if decoded[0] != Token::Address(params.maker_address) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment `maker_address` {:?} is invalid, expected {:?}", - decoded[0], - Token::Address(params.maker_address) - ))); - } - if decoded[1] != Token::Address(params.etomic_swap_contract) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment `etomic_swap_contract` {:?} is invalid, expected address {:?}", - decoded[1], - Token::Address(params.etomic_swap_contract) - ))); - } - let token_id = U256::from(params.token_id); - if decoded[2] != Token::Uint(token_id) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment `token_id` {:?} is invalid, expected {:?}", - decoded[2], - Token::Uint(token_id) - ))); - } - if let Some(amount) = ¶ms.amount { - let value = U256::from_dec_str(amount).map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; - if decoded[3] != Token::Uint(value) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment `amount` {:?} is invalid, expected {:?}", - decoded[3], - Token::Uint(value) - ))); - } - } - Ok(()) -} - -#[derive(Debug, Display)] -pub enum HtlcParamsError { - WrongPaymentTx(String), - TxDeserializationError(String), -} - -struct ExpectedHtlcParams { - swap_id: Vec, - taker_address: Address, - token_address: Address, - taker_secret_hash: Vec, - maker_secret_hash: Vec, - time_lock: U256, -} - -fn decode_and_validate_htlc_params( - decoded: Vec, - index: usize, - expected_params: ExpectedHtlcParams, -) -> MmResult<(), HtlcParamsError> { - if let Some(Token::Bytes(data_bytes)) = decoded.get(index) { - if let Ok(decoded_params) = ethabi::decode(htlc_params(), data_bytes) { - if decoded_params[0] != Token::FixedBytes(expected_params.swap_id.clone()) { - return MmError::err(HtlcParamsError::WrongPaymentTx(format!( - "Invalid 'swap_id' {:?}, expected {:?}", - decoded_params[0], - Token::FixedBytes(expected_params.swap_id) - ))); - } - if decoded_params[1] != Token::Address(expected_params.taker_address) { - return MmError::err(HtlcParamsError::WrongPaymentTx(format!( - "Invalid `taker_address` {:?}, expected {:?}", - decoded_params[1], - Token::Address(expected_params.taker_address) - ))); - } - if decoded_params[2] != Token::Address(expected_params.token_address) { - return MmError::err(HtlcParamsError::WrongPaymentTx(format!( - "Invalid `token_address` {:?}, expected {:?}", - decoded_params[2], - Token::Address(expected_params.token_address) - ))); - } - if decoded_params[3] != Token::FixedBytes(expected_params.taker_secret_hash.clone()) { - return MmError::err(HtlcParamsError::WrongPaymentTx(format!( - "Invalid 'taker_secret_hash' {:?}, expected {:?}", - decoded_params[3], - Token::FixedBytes(expected_params.taker_secret_hash) - ))); - } - if decoded_params[4] != Token::FixedBytes(expected_params.maker_secret_hash.clone()) { - return MmError::err(HtlcParamsError::WrongPaymentTx(format!( - "Invalid 'maker_secret_hash' {:?}, expected {:?}", - decoded_params[4], - Token::FixedBytes(expected_params.maker_secret_hash) - ))); - } - if decoded_params[5] != Token::Uint(expected_params.time_lock) { - return MmError::err(HtlcParamsError::WrongPaymentTx(format!( - "Invalid 'time_lock' {:?}, expected {:?}", - decoded_params[5], - Token::Uint(expected_params.time_lock) - ))); - } - } else { - return MmError::err(HtlcParamsError::TxDeserializationError( - "Failed to decode HTLCParams from data_bytes".to_string(), - )); - } - } else { - return MmError::err(HtlcParamsError::TxDeserializationError( - "Expected Bytes for HTLCParams data".to_string(), - )); - } - Ok(()) -} diff --git a/mm2src/coins/nft.rs b/mm2src/coins/nft.rs index 8e73e2b272..e6ee1b8659 100644 --- a/mm2src/coins/nft.rs +++ b/mm2src/coins/nft.rs @@ -7,6 +7,7 @@ pub mod nft_structs; pub(crate) mod storage; #[cfg(any(test, target_arch = "wasm32"))] mod nft_tests; +pub(crate) mod trading_proto_v2; use crate::{coin_conf, get_my_address, lp_coinfind_or_err, CoinsContext, MarketCoinOps, MmCoinEnum, MmCoinStruct, MyAddressReq, WithdrawError}; diff --git a/mm2src/coins/nft/trading_proto_v2/errors.rs b/mm2src/coins/nft/trading_proto_v2/errors.rs new file mode 100644 index 0000000000..242254b6f5 --- /dev/null +++ b/mm2src/coins/nft/trading_proto_v2/errors.rs @@ -0,0 +1,27 @@ +use enum_derives::EnumFromStringify; + +#[derive(Debug, Display)] +pub(crate) enum Erc721FunctionError { + AbiError(String), + FunctionNotFound(String), +} + +#[derive(Debug, Display)] +pub(crate) enum HtlcParamsError { + WrongPaymentTx(String), + TxDeserializationError(String), +} + +#[derive(Debug, Display, EnumFromStringify)] +pub(crate) enum PaymentStatusErr { + #[from_stringify("ethabi::Error")] + #[display(fmt = "Abi error: {}", _0)] + AbiError(String), + #[from_stringify("web3::Error")] + #[display(fmt = "Transport error: {}", _0)] + Transport(String), + #[display(fmt = "Internal error: {}", _0)] + Internal(String), + #[display(fmt = "Tx deserialization error: {}", _0)] + TxDeserializationError(String), +} diff --git a/mm2src/coins/nft/trading_proto_v2/mod.rs b/mm2src/coins/nft/trading_proto_v2/mod.rs new file mode 100644 index 0000000000..e8b299854f --- /dev/null +++ b/mm2src/coins/nft/trading_proto_v2/mod.rs @@ -0,0 +1,549 @@ +use crate::coin_errors::{ValidatePaymentError, ValidatePaymentResult}; +use ethabi::{Contract, Token}; +use ethcore_transaction::{Action, UnverifiedTransaction}; +use ethereum_types::{Address, U256}; +use futures::compat::Future01CompatExt; +use mm2_err_handle::prelude::{MapToMmResult, MmError, MmResult}; +use mm2_number::BigDecimal; +use std::convert::TryInto; +use web3::types::TransactionId; + +pub(crate) mod errors; +use errors::{Erc721FunctionError, HtlcParamsError, PaymentStatusErr}; +pub(crate) mod structs; +use structs::{ExpectedHtlcParams, StateType, ValidationParams}; + +use super::ContractType; +use crate::eth::{addr_from_raw_pubkey, decode_contract_call, EthCoin, EthCoinType, MakerPaymentStateV2, SignedEthTx, + TryToAddress, ERC1155_CONTRACT, ERC721_CONTRACT, ETH_GAS, NFT_SWAP_CONTRACT}; +use crate::{NftAssocTypes, RefundPaymentArgs, SendNftMakerPaymentArgs, SpendNftMakerPaymentArgs, TransactionErr, + ValidateNftMakerPaymentArgs}; + +impl EthCoin { + pub(crate) async fn send_nft_maker_payment_v2_impl( + &self, + args: SendNftMakerPaymentArgs<'_, Self>, + ) -> Result { + let contract_type = try_tx_s!(self.parse_contract_type(args.contract_type)); + try_tx_s!(self.validate_payment_args( + args.taker_secret_hash, + args.maker_secret_hash, + &args.amount, + &contract_type, + )); + + let taker_address = try_tx_s!(addr_from_raw_pubkey(args.taker_pub)); + let token_address = try_tx_s!(self.parse_contract_address(args.token_address)); + let swap_contract_address = try_tx_s!(self.parse_contract_address(args.swap_contract_address)); + let time_lock_u32 = try_tx_s!(args.time_lock.try_into()); + let token_id_u256 = U256::from(args.token_id); + let htlc_data = self.prepare_htlc_data(&args, taker_address, token_address, time_lock_u32); + + match &self.coin_type { + EthCoinType::Nft { .. } => match contract_type { + ContractType::Erc1155 => { + let function = try_tx_s!(ERC1155_CONTRACT.function("safeTransferFrom")); + let amount_u256 = try_tx_s!(U256::from_dec_str(&args.amount.to_string())); + let data = try_tx_s!(function.encode_input(&[ + Token::Address(self.my_address), + Token::Address(swap_contract_address), + Token::Uint(token_id_u256), + Token::Uint(amount_u256), + Token::Bytes(htlc_data), + ])); + self.sign_and_send_transaction(0.into(), Action::Call(token_address), data, U256::from(ETH_GAS)) + .compat() + .await + }, + ContractType::Erc721 => { + let function = try_tx_s!(self.erc721_transfer_with_data()); + let data = try_tx_s!(function.encode_input(&[ + Token::Address(self.my_address), + Token::Address(swap_contract_address), + Token::Uint(token_id_u256), + Token::Bytes(htlc_data), + ])); + self.sign_and_send_transaction(0.into(), Action::Call(token_address), data, U256::from(ETH_GAS)) + .compat() + .await + }, + }, + EthCoinType::Eth | EthCoinType::Erc20 { .. } => Err(TransactionErr::ProtocolNotSupported( + "ETH and ERC20 Protocols are not supported for NFT Swaps".to_string(), + )), + } + } + + fn validate_payment_args<'a>( + &self, + taker_secret_hash: &'a [u8], + maker_secret_hash: &'a [u8], + amount: &BigDecimal, + contract_type: &ContractType, + ) -> Result<(), String> { + match contract_type { + ContractType::Erc1155 => { + if !is_positive_integer(amount) { + return Err("ERC-1155 amount must be a positive integer".to_string()); + } + }, + ContractType::Erc721 => { + if amount != &BigDecimal::from(1) { + return Err("ERC-721 amount must be 1".to_string()); + } + }, + } + if taker_secret_hash.len() != 32 { + return Err("taker_secret_hash must be 32 bytes".to_string()); + } + if maker_secret_hash.len() != 32 { + return Err("maker_secret_hash must be 32 bytes".to_string()); + } + + Ok(()) + } + + fn prepare_htlc_data( + &self, + args: &SendNftMakerPaymentArgs<'_, Self>, + taker_address: Address, + token_address: Address, + time_lock: u32, + ) -> Vec { + let id = self.etomic_swap_id(time_lock, args.maker_secret_hash); + ethabi::encode(&[ + Token::FixedBytes(id), + Token::Address(taker_address), + Token::Address(token_address), + Token::FixedBytes(args.taker_secret_hash.to_vec()), + Token::FixedBytes(args.maker_secret_hash.to_vec()), + Token::Uint(U256::from(time_lock)), + ]) + } + + /// ERC721 contract has overloaded versions of the `safeTransferFrom` function, + /// but `Contract::function` method returns only the first if there are overloaded versions of the same function. + /// Provided function retrieves the `safeTransferFrom` variant that includes a `bytes` parameter. + /// This variant is specifically used for transferring ERC721 tokens with additional data. + fn erc721_transfer_with_data(&self) -> Result<ðabi::Function, Erc721FunctionError> { + let functions = ERC721_CONTRACT + .functions_by_name("safeTransferFrom") + .map_err(|e| Erc721FunctionError::AbiError(ERRL!("{}", e)))?; + + // Find the correct function variant by inspecting the input parameters. + let function = functions + .iter() + .find(|f| { + f.inputs.len() == 4 + && matches!( + f.inputs.last().map(|input| &input.kind), + Some(ðabi::ParamType::Bytes) + ) + }) + .ok_or_else(|| { + Erc721FunctionError::FunctionNotFound( + "Failed to find the correct safeTransferFrom function variant".to_string(), + ) + })?; + Ok(function) + } + + pub(crate) async fn validate_nft_maker_payment_v2_impl( + &self, + args: ValidateNftMakerPaymentArgs<'_, Self>, + ) -> ValidatePaymentResult<()> { + let contract_type = self.parse_contract_type(args.contract_type)?; + self.validate_payment_args( + args.taker_secret_hash, + args.maker_secret_hash, + &args.amount, + &contract_type, + ) + .map_err(ValidatePaymentError::InternalError)?; + let etomic_swap_contract = self.parse_contract_address(args.swap_contract_address)?; + let token_address = self.parse_contract_address(args.token_address)?; + let maker_address = addr_from_raw_pubkey(args.maker_pub).map_to_mm(ValidatePaymentError::InternalError)?; + let time_lock_u32 = args + .time_lock + .try_into() + .map_err(ValidatePaymentError::TimelockOverflow)?; + let swap_id = self.etomic_swap_id(time_lock_u32, args.maker_secret_hash); + let maker_status = self + .payment_status_v2( + etomic_swap_contract, + Token::FixedBytes(swap_id.clone()), + &NFT_SWAP_CONTRACT, + StateType::MakerPayments, + ) + .await?; + if maker_status != U256::from(MakerPaymentStateV2::PaymentSent as u8) { + return MmError::err(ValidatePaymentError::UnexpectedPaymentState(format!( + "NFT Maker Payment state is not PAYMENT_STATE_SENT, got {}", + maker_status + ))); + } + let tx_from_rpc = self + .transaction(TransactionId::Hash(args.maker_payment_tx.hash)) + .await?; + let tx_from_rpc = tx_from_rpc.as_ref().ok_or_else(|| { + ValidatePaymentError::TxDoesNotExist(format!( + "Didn't find provided tx {:?} on ETH node", + args.maker_payment_tx.hash + )) + })?; + if tx_from_rpc.from != Some(maker_address) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment tx {:?} was sent from wrong address, expected {:?}", + tx_from_rpc, maker_address + ))); + } + // As NFT owner calls "safeTransferFrom" directly, then in Transaction 'to' field we expect token_address + if tx_from_rpc.to != Some(token_address) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment tx {:?} was sent to wrong address, expected {:?}", + tx_from_rpc, token_address, + ))); + } + match self.coin_type { + EthCoinType::Nft { .. } => match contract_type { + ContractType::Erc1155 => { + let function = ERC1155_CONTRACT + .function("safeTransferFrom") + .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; + let decoded = decode_contract_call(function, &tx_from_rpc.input.0) + .map_to_mm(|err| ValidatePaymentError::TxDeserializationError(err.to_string()))?; + + let validation_params = ValidationParams { + maker_address, + etomic_swap_contract, + token_id: args.token_id, + amount: Some(args.amount.to_string()), + }; + validate_decoded_data(&decoded, &validation_params)?; + + let taker_address = + addr_from_raw_pubkey(args.taker_pub).map_to_mm(ValidatePaymentError::InternalError)?; + let htlc_params = ExpectedHtlcParams { + swap_id, + taker_address, + token_address, + taker_secret_hash: args.taker_secret_hash.to_vec(), + maker_secret_hash: args.maker_secret_hash.to_vec(), + time_lock: U256::from(args.time_lock), + }; + decode_and_validate_htlc_params(decoded, 4, htlc_params)?; + }, + ContractType::Erc721 => { + let function = self.erc721_transfer_with_data()?; + let decoded = decode_contract_call(function, &tx_from_rpc.input.0) + .map_to_mm(|err| ValidatePaymentError::TxDeserializationError(err.to_string()))?; + + let validation_params = ValidationParams { + maker_address, + etomic_swap_contract, + token_id: args.token_id, + amount: None, + }; + validate_decoded_data(&decoded, &validation_params)?; + + let taker_address = + addr_from_raw_pubkey(args.taker_pub).map_to_mm(ValidatePaymentError::InternalError)?; + let htlc_params = ExpectedHtlcParams { + swap_id, + taker_address, + token_address, + taker_secret_hash: args.taker_secret_hash.to_vec(), + maker_secret_hash: args.maker_secret_hash.to_vec(), + time_lock: U256::from(args.time_lock), + }; + decode_and_validate_htlc_params(decoded, 3, htlc_params)?; + }, + }, + EthCoinType::Eth | EthCoinType::Erc20 { .. } => { + return MmError::err(ValidatePaymentError::InternalError( + "EthCoinType must be Nft".to_string(), + )) + }, + } + Ok(()) + } + + async fn payment_status_v2( + &self, + swap_contract: Address, + swap_id: Token, + contract: &Contract, + state_type: StateType, + ) -> Result { + let function_name = state_type.as_str(); + let function = contract.function(function_name)?; + let data = function.encode_input(&[swap_id])?; + let bytes = self.call_request(swap_contract, None, Some(data.into())).await?; + let decoded_tokens = function.decode_output(&bytes.0)?; + let state = decoded_tokens.get(2).ok_or_else(|| { + PaymentStatusErr::Internal("Payment status must contain 'state' as the 2nd token".to_string()) + })?; + match state { + Token::Uint(state) => Ok(*state), + _ => Err(PaymentStatusErr::Internal(format!( + "Payment status must be Uint, got {:?}", + state + ))), + } + } + + pub(crate) async fn spend_nft_maker_payment_v2_impl( + &self, + args: SpendNftMakerPaymentArgs<'_, Self>, + ) -> Result { + let contract_type = try_tx_s!(self.parse_contract_type(args.contract_type)); + let etomic_swap_contract = try_tx_s!(self.parse_contract_address(args.swap_contract_address)); + if args.maker_secret.len() != 32 { + return Err(TransactionErr::Plain(ERRL!("maker_secret must be 32 bytes"))); + } + match self.coin_type { + EthCoinType::Nft { .. } => match contract_type { + ContractType::Erc1155 => { + let spend_func = try_tx_s!(NFT_SWAP_CONTRACT.function("spendErc1155MakerPayment")); + let send_func = try_tx_s!(ERC1155_CONTRACT.function("safeTransferFrom")); + let decoded = try_tx_s!(decode_contract_call(send_func, &args.maker_payment_tx.data)); + let (state, htlc_params) = try_tx_s!( + self.status_and_htlc_params_from_tx_data( + etomic_swap_contract, + &NFT_SWAP_CONTRACT, + &decoded, + 4, + StateType::MakerPayments, + ) + .await + ); + if state != U256::from(MakerPaymentStateV2::PaymentSent as u8) { + return Err(TransactionErr::Plain(ERRL!( + "Payment {:?} state is not PAYMENT_STATE_SENT, got {}", + args.maker_payment_tx, + state + ))); + } + let data = try_tx_s!(spend_func.encode_input(&[ + htlc_params[0].clone(), // swap_id + Token::Address(args.maker_payment_tx.sender()), + Token::FixedBytes(args.taker_secret_hash.to_vec()), + Token::FixedBytes(args.maker_secret.to_vec()), + htlc_params[2].clone(), // tokenAddress + decoded[2].clone(), // tokenId + decoded[3].clone(), // amount + ])); + self.sign_and_send_transaction( + 0.into(), + Action::Call(etomic_swap_contract), + data, + U256::from(ETH_GAS), + ) + .compat() + .await + }, + ContractType::Erc721 => { + let spend_func = try_tx_s!(NFT_SWAP_CONTRACT.function("spendErc721MakerPayment")); + let send_func = try_tx_s!(self.erc721_transfer_with_data()); + let decoded = try_tx_s!(decode_contract_call(send_func, &args.maker_payment_tx.data)); + let (state, htlc_params) = try_tx_s!( + self.status_and_htlc_params_from_tx_data( + etomic_swap_contract, + &NFT_SWAP_CONTRACT, + &decoded, + 3, + StateType::MakerPayments, + ) + .await + ); + if state != U256::from(MakerPaymentStateV2::PaymentSent as u8) { + return Err(TransactionErr::Plain(ERRL!( + "Payment {:?} state is not PAYMENT_STATE_SENT, got {}", + args.maker_payment_tx, + state + ))); + } + let data = try_tx_s!(spend_func.encode_input(&[ + htlc_params[0].clone(), // swap_id + Token::Address(args.maker_payment_tx.sender()), + Token::FixedBytes(args.taker_secret_hash.to_vec()), + Token::FixedBytes(args.maker_secret.to_vec()), + htlc_params[2].clone(), // tokenAddress + decoded[2].clone(), // tokenId + ])); + self.sign_and_send_transaction( + 0.into(), + Action::Call(etomic_swap_contract), + data, + U256::from(ETH_GAS), + ) + .compat() + .await + }, + }, + EthCoinType::Eth | EthCoinType::Erc20 { .. } => Err(TransactionErr::ProtocolNotSupported( + "ETH and ERC20 Protocols are not supported for NFT Swaps".to_string(), + )), + } + } + + async fn status_and_htlc_params_from_tx_data( + &self, + swap_contract: Address, + contract: &Contract, + decoded_data: &[Token], + index: usize, + state_type: StateType, + ) -> Result<(U256, Vec), PaymentStatusErr> { + if let Some(Token::Bytes(data_bytes)) = decoded_data.get(index) { + if let Ok(htlc_params) = ethabi::decode(htlc_params(), data_bytes) { + let state = self + .payment_status_v2(swap_contract, htlc_params[0].clone(), contract, state_type) + .await?; + Ok((state, htlc_params)) + } else { + Err(PaymentStatusErr::TxDeserializationError(ERRL!( + "Failed to decode HTLCParams from data_bytes" + ))) + } + } else { + Err(PaymentStatusErr::TxDeserializationError(ERRL!( + "Failed to decode HTLCParams from data_bytes" + ))) + } + } + + pub(crate) async fn refund_nft_maker_payment_v2_timelock_impl( + &self, + args: RefundPaymentArgs<'_>, + ) -> Result { + let _etomic_swap_contract = try_tx_s!(args.swap_contract_address.try_to_address()); + let tx: UnverifiedTransaction = try_tx_s!(rlp::decode(args.payment_tx)); + let _payment = try_tx_s!(SignedEthTx::new(tx)); + todo!() + } +} + +/// Validates decoded data from tx input, related to `safeTransferFrom` contract call +fn validate_decoded_data(decoded: &[Token], params: &ValidationParams) -> Result<(), MmError> { + if decoded[0] != Token::Address(params.maker_address) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment `maker_address` {:?} is invalid, expected {:?}", + decoded[0], + Token::Address(params.maker_address) + ))); + } + if decoded[1] != Token::Address(params.etomic_swap_contract) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment `etomic_swap_contract` {:?} is invalid, expected address {:?}", + decoded[1], + Token::Address(params.etomic_swap_contract) + ))); + } + let token_id = U256::from(params.token_id); + if decoded[2] != Token::Uint(token_id) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment `token_id` {:?} is invalid, expected {:?}", + decoded[2], + Token::Uint(token_id) + ))); + } + if let Some(amount) = ¶ms.amount { + let value = U256::from_dec_str(amount).map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; + if decoded[3] != Token::Uint(value) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment `amount` {:?} is invalid, expected {:?}", + decoded[3], + Token::Uint(value) + ))); + } + } + Ok(()) +} + +fn decode_and_validate_htlc_params( + decoded: Vec, + index: usize, + expected_params: ExpectedHtlcParams, +) -> MmResult<(), HtlcParamsError> { + if let Some(Token::Bytes(data_bytes)) = decoded.get(index) { + if let Ok(decoded_params) = ethabi::decode(htlc_params(), data_bytes) { + if decoded_params[0] != Token::FixedBytes(expected_params.swap_id.clone()) { + return MmError::err(HtlcParamsError::WrongPaymentTx(format!( + "Invalid 'swap_id' {:?}, expected {:?}", + decoded_params[0], + Token::FixedBytes(expected_params.swap_id) + ))); + } + if decoded_params[1] != Token::Address(expected_params.taker_address) { + return MmError::err(HtlcParamsError::WrongPaymentTx(format!( + "Invalid `taker_address` {:?}, expected {:?}", + decoded_params[1], + Token::Address(expected_params.taker_address) + ))); + } + if decoded_params[2] != Token::Address(expected_params.token_address) { + return MmError::err(HtlcParamsError::WrongPaymentTx(format!( + "Invalid `token_address` {:?}, expected {:?}", + decoded_params[2], + Token::Address(expected_params.token_address) + ))); + } + if decoded_params[3] != Token::FixedBytes(expected_params.taker_secret_hash.clone()) { + return MmError::err(HtlcParamsError::WrongPaymentTx(format!( + "Invalid 'taker_secret_hash' {:?}, expected {:?}", + decoded_params[3], + Token::FixedBytes(expected_params.taker_secret_hash) + ))); + } + if decoded_params[4] != Token::FixedBytes(expected_params.maker_secret_hash.clone()) { + return MmError::err(HtlcParamsError::WrongPaymentTx(format!( + "Invalid 'maker_secret_hash' {:?}, expected {:?}", + decoded_params[4], + Token::FixedBytes(expected_params.maker_secret_hash) + ))); + } + if decoded_params[5] != Token::Uint(expected_params.time_lock) { + return MmError::err(HtlcParamsError::WrongPaymentTx(format!( + "Invalid 'time_lock' {:?}, expected {:?}", + decoded_params[5], + Token::Uint(expected_params.time_lock) + ))); + } + } else { + return MmError::err(HtlcParamsError::TxDeserializationError( + "Failed to decode HTLCParams from data_bytes".to_string(), + )); + } + } else { + return MmError::err(HtlcParamsError::TxDeserializationError( + "Expected Bytes for HTLCParams data".to_string(), + )); + } + Ok(()) +} + +// Representation of the Solidity HTLCParams struct. +// +// struct HTLCParams { +// bytes32 id; +// address taker; +// address tokenAddress; +// bytes32 takerSecretHash; +// bytes32 makerSecretHash; +// uint32 paymentLockTime; +// } +fn htlc_params() -> &'static [ethabi::ParamType] { + &[ + ethabi::ParamType::FixedBytes(32), + ethabi::ParamType::Address, + ethabi::ParamType::Address, + ethabi::ParamType::FixedBytes(32), + ethabi::ParamType::FixedBytes(32), + ethabi::ParamType::Uint(256), + ] +} + +/// function to check if BigDecimal is a positive integer +#[inline(always)] +fn is_positive_integer(amount: &BigDecimal) -> bool { amount == &amount.with_scale(0) && amount > &BigDecimal::from(0) } diff --git a/mm2src/coins/nft/trading_proto_v2/structs.rs b/mm2src/coins/nft/trading_proto_v2/structs.rs new file mode 100644 index 0000000000..673124d8c8 --- /dev/null +++ b/mm2src/coins/nft/trading_proto_v2/structs.rs @@ -0,0 +1,33 @@ +use ethereum_types::{Address, U256}; + +pub(crate) struct ExpectedHtlcParams { + pub(crate) swap_id: Vec, + pub(crate) taker_address: Address, + pub(crate) token_address: Address, + pub(crate) taker_secret_hash: Vec, + pub(crate) maker_secret_hash: Vec, + pub(crate) time_lock: U256, +} + +pub(crate) struct ValidationParams<'a> { + pub(crate) maker_address: Address, + pub(crate) etomic_swap_contract: Address, + pub(crate) token_id: &'a [u8], + // Optional, as it's not needed for ERC721 + pub(crate) amount: Option, +} + +#[allow(dead_code)] +pub(crate) enum StateType { + MakerPayments, + TakerPayments, +} + +impl StateType { + pub(crate) fn as_str(&self) -> &'static str { + match self { + StateType::MakerPayments => "makerPayments", + StateType::TakerPayments => "takerPayments", + } + } +} From 6edcdb9196b0839f7926fa5518926bf852d6bcf4 Mon Sep 17 00:00:00 2001 From: laruh Date: Tue, 2 Apr 2024 20:07:35 +0700 Subject: [PATCH 60/80] impl prepare_spend_nft_maker_v2_data and prepare_spend_nft_maker_v2_data funcs to reduce code duplication --- mm2src/coins/nft/trading_proto_v2/errors.rs | 14 ++ mm2src/coins/nft/trading_proto_v2/mod.rs | 225 ++++++++++---------- 2 files changed, 132 insertions(+), 107 deletions(-) diff --git a/mm2src/coins/nft/trading_proto_v2/errors.rs b/mm2src/coins/nft/trading_proto_v2/errors.rs index 242254b6f5..e66cd437d0 100644 --- a/mm2src/coins/nft/trading_proto_v2/errors.rs +++ b/mm2src/coins/nft/trading_proto_v2/errors.rs @@ -25,3 +25,17 @@ pub(crate) enum PaymentStatusErr { #[display(fmt = "Tx deserialization error: {}", _0)] TxDeserializationError(String), } + +#[derive(Debug, Display, EnumFromStringify)] +pub(crate) enum PrepareTxDataError { + #[from_stringify("ethabi::Error")] + #[display(fmt = "Abi error: {}", _0)] + AbiError(String), + #[display(fmt = "Internal error: {}", _0)] + Internal(String), + Erc721FunctionError(Erc721FunctionError), +} + +impl From for PrepareTxDataError { + fn from(e: Erc721FunctionError) -> Self { Self::Erc721FunctionError(e) } +} diff --git a/mm2src/coins/nft/trading_proto_v2/mod.rs b/mm2src/coins/nft/trading_proto_v2/mod.rs index e8b299854f..3ab33bf8ce 100644 --- a/mm2src/coins/nft/trading_proto_v2/mod.rs +++ b/mm2src/coins/nft/trading_proto_v2/mod.rs @@ -16,6 +16,7 @@ use structs::{ExpectedHtlcParams, StateType, ValidationParams}; use super::ContractType; use crate::eth::{addr_from_raw_pubkey, decode_contract_call, EthCoin, EthCoinType, MakerPaymentStateV2, SignedEthTx, TryToAddress, ERC1155_CONTRACT, ERC721_CONTRACT, ETH_GAS, NFT_SWAP_CONTRACT}; +use crate::nft::trading_proto_v2::errors::PrepareTxDataError; use crate::{NftAssocTypes, RefundPaymentArgs, SendNftMakerPaymentArgs, SpendNftMakerPaymentArgs, TransactionErr, ValidateNftMakerPaymentArgs}; @@ -40,33 +41,17 @@ impl EthCoin { let htlc_data = self.prepare_htlc_data(&args, taker_address, token_address, time_lock_u32); match &self.coin_type { - EthCoinType::Nft { .. } => match contract_type { - ContractType::Erc1155 => { - let function = try_tx_s!(ERC1155_CONTRACT.function("safeTransferFrom")); - let amount_u256 = try_tx_s!(U256::from_dec_str(&args.amount.to_string())); - let data = try_tx_s!(function.encode_input(&[ - Token::Address(self.my_address), - Token::Address(swap_contract_address), - Token::Uint(token_id_u256), - Token::Uint(amount_u256), - Token::Bytes(htlc_data), - ])); - self.sign_and_send_transaction(0.into(), Action::Call(token_address), data, U256::from(ETH_GAS)) - .compat() - .await - }, - ContractType::Erc721 => { - let function = try_tx_s!(self.erc721_transfer_with_data()); - let data = try_tx_s!(function.encode_input(&[ - Token::Address(self.my_address), - Token::Address(swap_contract_address), - Token::Uint(token_id_u256), - Token::Bytes(htlc_data), - ])); - self.sign_and_send_transaction(0.into(), Action::Call(token_address), data, U256::from(ETH_GAS)) - .compat() - .await - }, + EthCoinType::Nft { .. } => { + let data = try_tx_s!(self.prepare_nft_maker_payment_v2_data( + contract_type, + swap_contract_address, + token_id_u256, + &args, + htlc_data + )); + self.sign_and_send_transaction(0.into(), Action::Call(token_address), data, U256::from(ETH_GAS)) + .compat() + .await }, EthCoinType::Eth | EthCoinType::Erc20 { .. } => Err(TransactionErr::ProtocolNotSupported( "ETH and ERC20 Protocols are not supported for NFT Swaps".to_string(), @@ -74,6 +59,41 @@ impl EthCoin { } } + fn prepare_nft_maker_payment_v2_data( + &self, + contract_type: ContractType, + swap_contract_address: Address, + token_id: U256, + args: &SendNftMakerPaymentArgs<'_, Self>, + htlc_data: Vec, + ) -> Result, PrepareTxDataError> { + match contract_type { + ContractType::Erc1155 => { + let function = ERC1155_CONTRACT.function("safeTransferFrom")?; + let amount_u256 = U256::from_dec_str(&args.amount.to_string()) + .map_err(|e| PrepareTxDataError::Internal(e.to_string()))?; + let data = function.encode_input(&[ + Token::Address(self.my_address), + Token::Address(swap_contract_address), + Token::Uint(token_id), + Token::Uint(amount_u256), + Token::Bytes(htlc_data), + ])?; + Ok(data) + }, + ContractType::Erc721 => { + let function = self.erc721_transfer_with_data()?; + let data = function.encode_input(&[ + Token::Address(self.my_address), + Token::Address(swap_contract_address), + Token::Uint(token_id), + Token::Bytes(htlc_data), + ])?; + Ok(data) + }, + } + } + fn validate_payment_args<'a>( &self, taker_secret_hash: &'a [u8], @@ -280,12 +300,12 @@ impl EthCoin { let data = function.encode_input(&[swap_id])?; let bytes = self.call_request(swap_contract, None, Some(data.into())).await?; let decoded_tokens = function.decode_output(&bytes.0)?; - let state = decoded_tokens.get(2).ok_or_else(|| { - PaymentStatusErr::Internal("Payment status must contain 'state' as the 2nd token".to_string()) - })?; + let state = decoded_tokens + .get(2) + .ok_or_else(|| PaymentStatusErr::Internal(ERRL!("Payment status must contain 'state' as the 2nd token")))?; match state { Token::Uint(state) => Ok(*state), - _ => Err(PaymentStatusErr::Internal(format!( + _ => Err(PaymentStatusErr::Internal(ERRL!( "Payment status must be Uint, got {:?}", state ))), @@ -301,85 +321,31 @@ impl EthCoin { if args.maker_secret.len() != 32 { return Err(TransactionErr::Plain(ERRL!("maker_secret must be 32 bytes"))); } + + let (send_func, index_bytes) = match contract_type { + ContractType::Erc1155 => (try_tx_s!(ERC1155_CONTRACT.function("safeTransferFrom")), 4), + ContractType::Erc721 => (try_tx_s!(self.erc721_transfer_with_data()), 3), + }; + let decoded = try_tx_s!(decode_contract_call(send_func, &args.maker_payment_tx.data)); + let (state, htlc_params) = try_tx_s!( + self.status_and_htlc_params_from_tx_data( + etomic_swap_contract, + &NFT_SWAP_CONTRACT, + &decoded, + index_bytes, + StateType::MakerPayments, + ) + .await + ); + match self.coin_type { - EthCoinType::Nft { .. } => match contract_type { - ContractType::Erc1155 => { - let spend_func = try_tx_s!(NFT_SWAP_CONTRACT.function("spendErc1155MakerPayment")); - let send_func = try_tx_s!(ERC1155_CONTRACT.function("safeTransferFrom")); - let decoded = try_tx_s!(decode_contract_call(send_func, &args.maker_payment_tx.data)); - let (state, htlc_params) = try_tx_s!( - self.status_and_htlc_params_from_tx_data( - etomic_swap_contract, - &NFT_SWAP_CONTRACT, - &decoded, - 4, - StateType::MakerPayments, - ) - .await - ); - if state != U256::from(MakerPaymentStateV2::PaymentSent as u8) { - return Err(TransactionErr::Plain(ERRL!( - "Payment {:?} state is not PAYMENT_STATE_SENT, got {}", - args.maker_payment_tx, - state - ))); - } - let data = try_tx_s!(spend_func.encode_input(&[ - htlc_params[0].clone(), // swap_id - Token::Address(args.maker_payment_tx.sender()), - Token::FixedBytes(args.taker_secret_hash.to_vec()), - Token::FixedBytes(args.maker_secret.to_vec()), - htlc_params[2].clone(), // tokenAddress - decoded[2].clone(), // tokenId - decoded[3].clone(), // amount - ])); - self.sign_and_send_transaction( - 0.into(), - Action::Call(etomic_swap_contract), - data, - U256::from(ETH_GAS), - ) - .compat() - .await - }, - ContractType::Erc721 => { - let spend_func = try_tx_s!(NFT_SWAP_CONTRACT.function("spendErc721MakerPayment")); - let send_func = try_tx_s!(self.erc721_transfer_with_data()); - let decoded = try_tx_s!(decode_contract_call(send_func, &args.maker_payment_tx.data)); - let (state, htlc_params) = try_tx_s!( - self.status_and_htlc_params_from_tx_data( - etomic_swap_contract, - &NFT_SWAP_CONTRACT, - &decoded, - 3, - StateType::MakerPayments, - ) - .await - ); - if state != U256::from(MakerPaymentStateV2::PaymentSent as u8) { - return Err(TransactionErr::Plain(ERRL!( - "Payment {:?} state is not PAYMENT_STATE_SENT, got {}", - args.maker_payment_tx, - state - ))); - } - let data = try_tx_s!(spend_func.encode_input(&[ - htlc_params[0].clone(), // swap_id - Token::Address(args.maker_payment_tx.sender()), - Token::FixedBytes(args.taker_secret_hash.to_vec()), - Token::FixedBytes(args.maker_secret.to_vec()), - htlc_params[2].clone(), // tokenAddress - decoded[2].clone(), // tokenId - ])); - self.sign_and_send_transaction( - 0.into(), - Action::Call(etomic_swap_contract), - data, - U256::from(ETH_GAS), - ) + EthCoinType::Nft { .. } => { + let data = + try_tx_s!(self.prepare_spend_nft_maker_v2_data(contract_type, &args, decoded, htlc_params, state)); + + self.sign_and_send_transaction(0.into(), Action::Call(etomic_swap_contract), data, U256::from(ETH_GAS)) .compat() .await - }, }, EthCoinType::Eth | EthCoinType::Erc20 { .. } => Err(TransactionErr::ProtocolNotSupported( "ETH and ERC20 Protocols are not supported for NFT Swaps".to_string(), @@ -387,6 +353,51 @@ impl EthCoin { } } + fn prepare_spend_nft_maker_v2_data( + &self, + contract_type: ContractType, + args: &SpendNftMakerPaymentArgs<'_, Self>, + decoded: Vec, + htlc_params: Vec, + state: U256, + ) -> Result, PrepareTxDataError> { + let spend_func = match contract_type { + ContractType::Erc1155 => NFT_SWAP_CONTRACT.function("spendErc1155MakerPayment")?, + ContractType::Erc721 => NFT_SWAP_CONTRACT.function("spendErc721MakerPayment")?, + }; + + if state != U256::from(MakerPaymentStateV2::PaymentSent as u8) { + return Err(PrepareTxDataError::Internal(ERRL!( + "Payment {:?} state is not PAYMENT_STATE_SENT, got {}", + args.maker_payment_tx, + state + ))); + } + + let input_tokens = match contract_type { + ContractType::Erc1155 => vec![ + htlc_params[0].clone(), // swap_id + Token::Address(args.maker_payment_tx.sender()), + Token::FixedBytes(args.taker_secret_hash.to_vec()), + Token::FixedBytes(args.maker_secret.to_vec()), + htlc_params[2].clone(), // tokenAddress + decoded[2].clone(), // tokenId + decoded[3].clone(), // amount + ], + ContractType::Erc721 => vec![ + htlc_params[0].clone(), // swap_id + Token::Address(args.maker_payment_tx.sender()), + Token::FixedBytes(args.taker_secret_hash.to_vec()), + Token::FixedBytes(args.maker_secret.to_vec()), + htlc_params[2].clone(), // tokenAddress + decoded[2].clone(), // tokenId + ], + }; + + let data = spend_func.encode_input(&input_tokens)?; + Ok(data) + } + async fn status_and_htlc_params_from_tx_data( &self, swap_contract: Address, From 5978908c5b69a3d35bcff71f0afda1be3fe7c3a0 Mon Sep 17 00:00:00 2001 From: laruh Date: Tue, 2 Apr 2024 23:32:12 +0700 Subject: [PATCH 61/80] simplify validate_nft_maker_payment_v2_impl, add doc comms --- mm2src/coins/coin_errors.rs | 5 +- mm2src/coins/eth.rs | 2 + mm2src/coins/nft/trading_proto_v2/mod.rs | 157 ++++++++++++----------- 3 files changed, 86 insertions(+), 78 deletions(-) diff --git a/mm2src/coins/coin_errors.rs b/mm2src/coins/coin_errors.rs index 7eff697c62..9c5598ffb5 100644 --- a/mm2src/coins/coin_errors.rs +++ b/mm2src/coins/coin_errors.rs @@ -1,5 +1,5 @@ use crate::eth::{CoinAssocTypesError, NftAssocTypesError, Web3RpcError}; -use crate::nft::trading_proto_v2::errors::{Erc721FunctionError, HtlcParamsError, PaymentStatusErr}; +use crate::nft::trading_proto_v2::errors::{Erc721FunctionError, HtlcParamsError, PaymentStatusErr, PrepareTxDataError}; use crate::{utxo::rpc_clients::UtxoRpcError, NumConversError, UnexpectedDerivationMethod}; use enum_derives::EnumFromStringify; use futures01::Future; @@ -22,7 +22,8 @@ pub enum ValidatePaymentError { "NftAssocTypesError", "NumConversError", "UnexpectedDerivationMethod", - "keys::Error" + "keys::Error", + "PrepareTxDataError" )] InternalError(String), /// Problem with deserializing the transaction, or one of the transaction parts is invalid. diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index ff798f8d34..abc4935476 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -148,6 +148,7 @@ pub enum PaymentState { Spent, Refunded, } + #[allow(dead_code)] pub(crate) enum MakerPaymentStateV2 { Uninitialized, @@ -155,6 +156,7 @@ pub(crate) enum MakerPaymentStateV2 { TakerSpent, MakerRefunded, } + #[allow(dead_code)] pub(crate) enum TakerPaymentStateV2 { Uninitialized, diff --git a/mm2src/coins/nft/trading_proto_v2/mod.rs b/mm2src/coins/nft/trading_proto_v2/mod.rs index 3ab33bf8ce..798c01c4b0 100644 --- a/mm2src/coins/nft/trading_proto_v2/mod.rs +++ b/mm2src/coins/nft/trading_proto_v2/mod.rs @@ -6,7 +6,7 @@ use futures::compat::Future01CompatExt; use mm2_err_handle::prelude::{MapToMmResult, MmError, MmResult}; use mm2_number::BigDecimal; use std::convert::TryInto; -use web3::types::TransactionId; +use web3::types::{Transaction as Web3Tx, TransactionId}; pub(crate) mod errors; use errors::{Erc721FunctionError, HtlcParamsError, PaymentStatusErr}; @@ -168,6 +168,35 @@ impl EthCoin { Ok(function) } + async fn validate_from_to_and_maker_status( + &self, + tx_from_rpc: &Web3Tx, + expected_from: Address, + expected_to: Address, + maker_status: U256, + ) -> ValidatePaymentResult<()> { + if maker_status != U256::from(MakerPaymentStateV2::PaymentSent as u8) { + return MmError::err(ValidatePaymentError::UnexpectedPaymentState(format!( + "NFT Maker Payment state is not PAYMENT_STATE_SENT, got {}", + maker_status + ))); + } + if tx_from_rpc.from != Some(expected_from) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment tx {:?} was sent from wrong address, expected {:?}", + tx_from_rpc, expected_from + ))); + } + // As NFT owner calls "safeTransferFrom" directly, then in Transaction 'to' field we expect token_address + if tx_from_rpc.to != Some(expected_to) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment tx {:?} was sent to wrong address, expected {:?}", + tx_from_rpc, expected_to, + ))); + } + Ok(()) + } + pub(crate) async fn validate_nft_maker_payment_v2_impl( &self, args: ValidateNftMakerPaymentArgs<'_, Self>, @@ -196,12 +225,6 @@ impl EthCoin { StateType::MakerPayments, ) .await?; - if maker_status != U256::from(MakerPaymentStateV2::PaymentSent as u8) { - return MmError::err(ValidatePaymentError::UnexpectedPaymentState(format!( - "NFT Maker Payment state is not PAYMENT_STATE_SENT, got {}", - maker_status - ))); - } let tx_from_rpc = self .transaction(TransactionId::Hash(args.maker_payment_tx.hash)) .await?; @@ -211,73 +234,38 @@ impl EthCoin { args.maker_payment_tx.hash )) })?; - if tx_from_rpc.from != Some(maker_address) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment tx {:?} was sent from wrong address, expected {:?}", - tx_from_rpc, maker_address - ))); - } - // As NFT owner calls "safeTransferFrom" directly, then in Transaction 'to' field we expect token_address - if tx_from_rpc.to != Some(token_address) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment tx {:?} was sent to wrong address, expected {:?}", - tx_from_rpc, token_address, - ))); - } + self.validate_from_to_and_maker_status(tx_from_rpc, maker_address, token_address, maker_status) + .await?; match self.coin_type { - EthCoinType::Nft { .. } => match contract_type { - ContractType::Erc1155 => { - let function = ERC1155_CONTRACT - .function("safeTransferFrom") - .map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; - let decoded = decode_contract_call(function, &tx_from_rpc.input.0) - .map_to_mm(|err| ValidatePaymentError::TxDeserializationError(err.to_string()))?; - - let validation_params = ValidationParams { - maker_address, - etomic_swap_contract, - token_id: args.token_id, - amount: Some(args.amount.to_string()), - }; - validate_decoded_data(&decoded, &validation_params)?; + EthCoinType::Nft { .. } => { + let (decoded, index_bytes) = + self.get_decoded_tx_data_and_index_bytes(&contract_type, &tx_from_rpc.input.0)?; - let taker_address = - addr_from_raw_pubkey(args.taker_pub).map_to_mm(ValidatePaymentError::InternalError)?; - let htlc_params = ExpectedHtlcParams { - swap_id, - taker_address, - token_address, - taker_secret_hash: args.taker_secret_hash.to_vec(), - maker_secret_hash: args.maker_secret_hash.to_vec(), - time_lock: U256::from(args.time_lock), - }; - decode_and_validate_htlc_params(decoded, 4, htlc_params)?; - }, - ContractType::Erc721 => { - let function = self.erc721_transfer_with_data()?; - let decoded = decode_contract_call(function, &tx_from_rpc.input.0) - .map_to_mm(|err| ValidatePaymentError::TxDeserializationError(err.to_string()))?; + let amount = if matches!(contract_type, ContractType::Erc1155) { + Some(args.amount.to_string()) + } else { + None + }; - let validation_params = ValidationParams { - maker_address, - etomic_swap_contract, - token_id: args.token_id, - amount: None, - }; - validate_decoded_data(&decoded, &validation_params)?; + let validation_params = ValidationParams { + maker_address, + etomic_swap_contract, + token_id: args.token_id, + amount, + }; + validate_decoded_data(&decoded, &validation_params)?; - let taker_address = - addr_from_raw_pubkey(args.taker_pub).map_to_mm(ValidatePaymentError::InternalError)?; - let htlc_params = ExpectedHtlcParams { - swap_id, - taker_address, - token_address, - taker_secret_hash: args.taker_secret_hash.to_vec(), - maker_secret_hash: args.maker_secret_hash.to_vec(), - time_lock: U256::from(args.time_lock), - }; - decode_and_validate_htlc_params(decoded, 3, htlc_params)?; - }, + let taker_address = + addr_from_raw_pubkey(args.taker_pub).map_to_mm(ValidatePaymentError::InternalError)?; + let htlc_params = ExpectedHtlcParams { + swap_id, + taker_address, + token_address, + taker_secret_hash: args.taker_secret_hash.to_vec(), + maker_secret_hash: args.maker_secret_hash.to_vec(), + time_lock: U256::from(args.time_lock), + }; + decode_and_validate_htlc_params(decoded, index_bytes, htlc_params)?; }, EthCoinType::Eth | EthCoinType::Erc20 { .. } => { return MmError::err(ValidatePaymentError::InternalError( @@ -288,6 +276,7 @@ impl EthCoin { Ok(()) } + /// Retrieves the payment status from a given smart contract based on the swap ID and state type. async fn payment_status_v2( &self, swap_contract: Address, @@ -312,6 +301,22 @@ impl EthCoin { } } + /// Identifies the correct "safeTransferFrom" function based on the contract type (either ERC1155 or ERC721) + /// and decodes the provided contract call bytes using the ABI of the identified function. Additionally, it returns + /// the index position of the "bytes" field within the function's parameters. + pub(crate) fn get_decoded_tx_data_and_index_bytes( + &self, + contract_type: &ContractType, + contract_call_bytes: &[u8], + ) -> Result<(Vec, usize), PrepareTxDataError> { + let (send_func, index_bytes) = match contract_type { + ContractType::Erc1155 => (ERC1155_CONTRACT.function("safeTransferFrom")?, 4), + ContractType::Erc721 => (self.erc721_transfer_with_data()?, 3), + }; + let decoded = decode_contract_call(send_func, contract_call_bytes)?; + Ok((decoded, index_bytes)) + } + pub(crate) async fn spend_nft_maker_payment_v2_impl( &self, args: SpendNftMakerPaymentArgs<'_, Self>, @@ -321,12 +326,9 @@ impl EthCoin { if args.maker_secret.len() != 32 { return Err(TransactionErr::Plain(ERRL!("maker_secret must be 32 bytes"))); } + let (decoded, index_bytes) = + try_tx_s!(self.get_decoded_tx_data_and_index_bytes(&contract_type, &args.maker_payment_tx.data)); - let (send_func, index_bytes) = match contract_type { - ContractType::Erc1155 => (try_tx_s!(ERC1155_CONTRACT.function("safeTransferFrom")), 4), - ContractType::Erc721 => (try_tx_s!(self.erc721_transfer_with_data()), 3), - }; - let decoded = try_tx_s!(decode_contract_call(send_func, &args.maker_payment_tx.data)); let (state, htlc_params) = try_tx_s!( self.status_and_htlc_params_from_tx_data( etomic_swap_contract, @@ -337,7 +339,6 @@ impl EthCoin { ) .await ); - match self.coin_type { EthCoinType::Nft { .. } => { let data = @@ -353,6 +354,10 @@ impl EthCoin { } } + /// Prepares the encoded transaction data for spending a maker's NFT payment on the blockchain. + /// + /// This function selects the appropriate contract function based on the NFT's contract type (ERC1155 or ERC721) + /// and encodes the input parameters required for the blockchain transaction. fn prepare_spend_nft_maker_v2_data( &self, contract_type: ContractType, From eaf9f74ae5bd6e64f805c9ea5963e52db30482c4 Mon Sep 17 00:00:00 2001 From: laruh Date: Wed, 3 Apr 2024 15:54:57 +0700 Subject: [PATCH 62/80] move _v2_impl functions to the beginning --- mm2src/coins/nft/trading_proto_v2/mod.rs | 252 +++++++++++------------ 1 file changed, 126 insertions(+), 126 deletions(-) diff --git a/mm2src/coins/nft/trading_proto_v2/mod.rs b/mm2src/coins/nft/trading_proto_v2/mod.rs index 798c01c4b0..5cff3cd271 100644 --- a/mm2src/coins/nft/trading_proto_v2/mod.rs +++ b/mm2src/coins/nft/trading_proto_v2/mod.rs @@ -59,6 +59,132 @@ impl EthCoin { } } + pub(crate) async fn validate_nft_maker_payment_v2_impl( + &self, + args: ValidateNftMakerPaymentArgs<'_, Self>, + ) -> ValidatePaymentResult<()> { + let contract_type = self.parse_contract_type(args.contract_type)?; + self.validate_payment_args( + args.taker_secret_hash, + args.maker_secret_hash, + &args.amount, + &contract_type, + ) + .map_err(ValidatePaymentError::InternalError)?; + let etomic_swap_contract = self.parse_contract_address(args.swap_contract_address)?; + let token_address = self.parse_contract_address(args.token_address)?; + let maker_address = addr_from_raw_pubkey(args.maker_pub).map_to_mm(ValidatePaymentError::InternalError)?; + let time_lock_u32 = args + .time_lock + .try_into() + .map_err(ValidatePaymentError::TimelockOverflow)?; + let swap_id = self.etomic_swap_id(time_lock_u32, args.maker_secret_hash); + let maker_status = self + .payment_status_v2( + etomic_swap_contract, + Token::FixedBytes(swap_id.clone()), + &NFT_SWAP_CONTRACT, + StateType::MakerPayments, + ) + .await?; + let tx_from_rpc = self + .transaction(TransactionId::Hash(args.maker_payment_tx.hash)) + .await?; + let tx_from_rpc = tx_from_rpc.as_ref().ok_or_else(|| { + ValidatePaymentError::TxDoesNotExist(format!( + "Didn't find provided tx {:?} on ETH node", + args.maker_payment_tx.hash + )) + })?; + self.validate_from_to_and_maker_status(tx_from_rpc, maker_address, token_address, maker_status) + .await?; + match self.coin_type { + EthCoinType::Nft { .. } => { + let (decoded, index_bytes) = + self.get_decoded_tx_data_and_index_bytes(&contract_type, &tx_from_rpc.input.0)?; + + let amount = if matches!(contract_type, ContractType::Erc1155) { + Some(args.amount.to_string()) + } else { + None + }; + + let validation_params = ValidationParams { + maker_address, + etomic_swap_contract, + token_id: args.token_id, + amount, + }; + validate_decoded_data(&decoded, &validation_params)?; + + let taker_address = + addr_from_raw_pubkey(args.taker_pub).map_to_mm(ValidatePaymentError::InternalError)?; + let htlc_params = ExpectedHtlcParams { + swap_id, + taker_address, + token_address, + taker_secret_hash: args.taker_secret_hash.to_vec(), + maker_secret_hash: args.maker_secret_hash.to_vec(), + time_lock: U256::from(args.time_lock), + }; + decode_and_validate_htlc_params(decoded, index_bytes, htlc_params)?; + }, + EthCoinType::Eth | EthCoinType::Erc20 { .. } => { + return MmError::err(ValidatePaymentError::InternalError( + "EthCoinType must be Nft".to_string(), + )) + }, + } + Ok(()) + } + + pub(crate) async fn spend_nft_maker_payment_v2_impl( + &self, + args: SpendNftMakerPaymentArgs<'_, Self>, + ) -> Result { + let contract_type = try_tx_s!(self.parse_contract_type(args.contract_type)); + let etomic_swap_contract = try_tx_s!(self.parse_contract_address(args.swap_contract_address)); + if args.maker_secret.len() != 32 { + return Err(TransactionErr::Plain(ERRL!("maker_secret must be 32 bytes"))); + } + let (decoded, index_bytes) = + try_tx_s!(self.get_decoded_tx_data_and_index_bytes(&contract_type, &args.maker_payment_tx.data)); + + let (state, htlc_params) = try_tx_s!( + self.status_and_htlc_params_from_tx_data( + etomic_swap_contract, + &NFT_SWAP_CONTRACT, + &decoded, + index_bytes, + StateType::MakerPayments, + ) + .await + ); + match self.coin_type { + EthCoinType::Nft { .. } => { + let data = + try_tx_s!(self.prepare_spend_nft_maker_v2_data(contract_type, &args, decoded, htlc_params, state)); + + self.sign_and_send_transaction(0.into(), Action::Call(etomic_swap_contract), data, U256::from(ETH_GAS)) + .compat() + .await + }, + EthCoinType::Eth | EthCoinType::Erc20 { .. } => Err(TransactionErr::ProtocolNotSupported( + "ETH and ERC20 Protocols are not supported for NFT Swaps".to_string(), + )), + } + } + + pub(crate) async fn refund_nft_maker_payment_v2_timelock_impl( + &self, + args: RefundPaymentArgs<'_>, + ) -> Result { + let _etomic_swap_contract = try_tx_s!(args.swap_contract_address.try_to_address()); + let tx: UnverifiedTransaction = try_tx_s!(rlp::decode(args.payment_tx)); + let _payment = try_tx_s!(SignedEthTx::new(tx)); + todo!() + } + fn prepare_nft_maker_payment_v2_data( &self, contract_type: ContractType, @@ -197,85 +323,6 @@ impl EthCoin { Ok(()) } - pub(crate) async fn validate_nft_maker_payment_v2_impl( - &self, - args: ValidateNftMakerPaymentArgs<'_, Self>, - ) -> ValidatePaymentResult<()> { - let contract_type = self.parse_contract_type(args.contract_type)?; - self.validate_payment_args( - args.taker_secret_hash, - args.maker_secret_hash, - &args.amount, - &contract_type, - ) - .map_err(ValidatePaymentError::InternalError)?; - let etomic_swap_contract = self.parse_contract_address(args.swap_contract_address)?; - let token_address = self.parse_contract_address(args.token_address)?; - let maker_address = addr_from_raw_pubkey(args.maker_pub).map_to_mm(ValidatePaymentError::InternalError)?; - let time_lock_u32 = args - .time_lock - .try_into() - .map_err(ValidatePaymentError::TimelockOverflow)?; - let swap_id = self.etomic_swap_id(time_lock_u32, args.maker_secret_hash); - let maker_status = self - .payment_status_v2( - etomic_swap_contract, - Token::FixedBytes(swap_id.clone()), - &NFT_SWAP_CONTRACT, - StateType::MakerPayments, - ) - .await?; - let tx_from_rpc = self - .transaction(TransactionId::Hash(args.maker_payment_tx.hash)) - .await?; - let tx_from_rpc = tx_from_rpc.as_ref().ok_or_else(|| { - ValidatePaymentError::TxDoesNotExist(format!( - "Didn't find provided tx {:?} on ETH node", - args.maker_payment_tx.hash - )) - })?; - self.validate_from_to_and_maker_status(tx_from_rpc, maker_address, token_address, maker_status) - .await?; - match self.coin_type { - EthCoinType::Nft { .. } => { - let (decoded, index_bytes) = - self.get_decoded_tx_data_and_index_bytes(&contract_type, &tx_from_rpc.input.0)?; - - let amount = if matches!(contract_type, ContractType::Erc1155) { - Some(args.amount.to_string()) - } else { - None - }; - - let validation_params = ValidationParams { - maker_address, - etomic_swap_contract, - token_id: args.token_id, - amount, - }; - validate_decoded_data(&decoded, &validation_params)?; - - let taker_address = - addr_from_raw_pubkey(args.taker_pub).map_to_mm(ValidatePaymentError::InternalError)?; - let htlc_params = ExpectedHtlcParams { - swap_id, - taker_address, - token_address, - taker_secret_hash: args.taker_secret_hash.to_vec(), - maker_secret_hash: args.maker_secret_hash.to_vec(), - time_lock: U256::from(args.time_lock), - }; - decode_and_validate_htlc_params(decoded, index_bytes, htlc_params)?; - }, - EthCoinType::Eth | EthCoinType::Erc20 { .. } => { - return MmError::err(ValidatePaymentError::InternalError( - "EthCoinType must be Nft".to_string(), - )) - }, - } - Ok(()) - } - /// Retrieves the payment status from a given smart contract based on the swap ID and state type. async fn payment_status_v2( &self, @@ -317,43 +364,6 @@ impl EthCoin { Ok((decoded, index_bytes)) } - pub(crate) async fn spend_nft_maker_payment_v2_impl( - &self, - args: SpendNftMakerPaymentArgs<'_, Self>, - ) -> Result { - let contract_type = try_tx_s!(self.parse_contract_type(args.contract_type)); - let etomic_swap_contract = try_tx_s!(self.parse_contract_address(args.swap_contract_address)); - if args.maker_secret.len() != 32 { - return Err(TransactionErr::Plain(ERRL!("maker_secret must be 32 bytes"))); - } - let (decoded, index_bytes) = - try_tx_s!(self.get_decoded_tx_data_and_index_bytes(&contract_type, &args.maker_payment_tx.data)); - - let (state, htlc_params) = try_tx_s!( - self.status_and_htlc_params_from_tx_data( - etomic_swap_contract, - &NFT_SWAP_CONTRACT, - &decoded, - index_bytes, - StateType::MakerPayments, - ) - .await - ); - match self.coin_type { - EthCoinType::Nft { .. } => { - let data = - try_tx_s!(self.prepare_spend_nft_maker_v2_data(contract_type, &args, decoded, htlc_params, state)); - - self.sign_and_send_transaction(0.into(), Action::Call(etomic_swap_contract), data, U256::from(ETH_GAS)) - .compat() - .await - }, - EthCoinType::Eth | EthCoinType::Erc20 { .. } => Err(TransactionErr::ProtocolNotSupported( - "ETH and ERC20 Protocols are not supported for NFT Swaps".to_string(), - )), - } - } - /// Prepares the encoded transaction data for spending a maker's NFT payment on the blockchain. /// /// This function selects the appropriate contract function based on the NFT's contract type (ERC1155 or ERC721) @@ -428,16 +438,6 @@ impl EthCoin { ))) } } - - pub(crate) async fn refund_nft_maker_payment_v2_timelock_impl( - &self, - args: RefundPaymentArgs<'_>, - ) -> Result { - let _etomic_swap_contract = try_tx_s!(args.swap_contract_address.try_to_address()); - let tx: UnverifiedTransaction = try_tx_s!(rlp::decode(args.payment_tx)); - let _payment = try_tx_s!(SignedEthTx::new(tx)); - todo!() - } } /// Validates decoded data from tx input, related to `safeTransferFrom` contract call From e1dbbdf04cc64b8fa6dd63d0a12630c1639be438 Mon Sep 17 00:00:00 2001 From: laruh Date: Thu, 4 Apr 2024 16:38:51 +0700 Subject: [PATCH 63/80] use NftSwapInfo in swap args --- mm2src/coins/lp_coins.rs | 32 ++++++++--------- mm2src/coins/nft/nft_structs.rs | 13 ------- mm2src/coins/nft/trading_proto_v2/mod.rs | 16 ++++----- .../tests/docker_tests/eth_docker_tests.rs | 36 ++++++++++--------- 4 files changed, 43 insertions(+), 54 deletions(-) diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 03bbd0f4be..efc2a96a4b 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -1496,6 +1496,18 @@ pub struct SendMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { pub swap_unique_data: &'a [u8], } +/// Structure representing necessary NFT info for Swap +pub struct NftSwapInfo<'a> { + /// The address of the NFT token + pub token_address: &'a [u8], + /// The ID of the NFT token. + pub token_id: &'a [u8], + /// The type of smart contract that governs this NFT + pub contract_type: &'a [u8], + /// Etomic swap contract address + pub swap_contract_address: &'a [u8], +} + pub struct SendNftMakerPaymentArgs<'a, Coin: CoinAssocTypes + NftAssocTypes + ?Sized> { /// Maker will be able to refund the payment after this timestamp pub time_lock: u64, @@ -1509,14 +1521,8 @@ pub struct SendNftMakerPaymentArgs<'a, Coin: CoinAssocTypes + NftAssocTypes + ?S pub taker_pub: &'a Coin::Pubkey, /// Unique data of specific swap pub swap_unique_data: &'a [u8], - /// The address of the NFT token - pub token_address: &'a [u8], - /// The ID of the NFT token. - pub token_id: &'a [u8], - /// The type of smart contract that governs this NFT - pub contract_type: &'a [u8], - /// Etomic swap contract address - pub swap_contract_address: &'a [u8], + /// Structure representing necessary NFT info for Swap + pub nft_swap_info: &'a NftSwapInfo<'a>, } pub struct ValidateMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { @@ -1553,14 +1559,8 @@ pub struct ValidateNftMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { pub maker_pub: &'a Coin::Pubkey, /// Unique data of specific swap pub swap_unique_data: &'a [u8], - /// The address of the NFT token - pub token_address: &'a [u8], - /// The ID of the NFT token. - pub token_id: &'a [u8], - /// The type of smart contract that governs this NFT - pub contract_type: &'a [u8], - /// Etomic swap contract address - pub swap_contract_address: &'a [u8], + /// Structure representing necessary NFT info for Swap + pub nft_swap_info: &'a NftSwapInfo<'a>, } pub struct RefundMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { diff --git a/mm2src/coins/nft/nft_structs.rs b/mm2src/coins/nft/nft_structs.rs index 9755bd7367..0096e8f2fe 100644 --- a/mm2src/coins/nft/nft_structs.rs +++ b/mm2src/coins/nft/nft_structs.rs @@ -829,16 +829,3 @@ pub struct NftInfo { /// where a single token ID can represent multiple assets. pub amount: BigDecimal, } - -/// Represents the Swap information about a Non-Fungible Token (NFT). -#[derive(Clone, Debug, Serialize)] -pub struct NftSwapInfo { - /// The address of the NFT token. - pub(crate) token_address: Address, - /// The ID of the NFT token. - pub(crate) token_id: BigUint, - /// The blockchain where the NFT exists. - pub(crate) chain: Chain, - /// The type of smart contract that governs this NFT. - pub(crate) contract_type: ContractType, -} diff --git a/mm2src/coins/nft/trading_proto_v2/mod.rs b/mm2src/coins/nft/trading_proto_v2/mod.rs index 5cff3cd271..3842c32ef9 100644 --- a/mm2src/coins/nft/trading_proto_v2/mod.rs +++ b/mm2src/coins/nft/trading_proto_v2/mod.rs @@ -25,7 +25,7 @@ impl EthCoin { &self, args: SendNftMakerPaymentArgs<'_, Self>, ) -> Result { - let contract_type = try_tx_s!(self.parse_contract_type(args.contract_type)); + let contract_type = try_tx_s!(self.parse_contract_type(args.nft_swap_info.contract_type)); try_tx_s!(self.validate_payment_args( args.taker_secret_hash, args.maker_secret_hash, @@ -34,10 +34,10 @@ impl EthCoin { )); let taker_address = try_tx_s!(addr_from_raw_pubkey(args.taker_pub)); - let token_address = try_tx_s!(self.parse_contract_address(args.token_address)); - let swap_contract_address = try_tx_s!(self.parse_contract_address(args.swap_contract_address)); + let token_address = try_tx_s!(self.parse_contract_address(args.nft_swap_info.token_address)); + let swap_contract_address = try_tx_s!(self.parse_contract_address(args.nft_swap_info.swap_contract_address)); let time_lock_u32 = try_tx_s!(args.time_lock.try_into()); - let token_id_u256 = U256::from(args.token_id); + let token_id_u256 = U256::from(args.nft_swap_info.token_id); let htlc_data = self.prepare_htlc_data(&args, taker_address, token_address, time_lock_u32); match &self.coin_type { @@ -63,7 +63,7 @@ impl EthCoin { &self, args: ValidateNftMakerPaymentArgs<'_, Self>, ) -> ValidatePaymentResult<()> { - let contract_type = self.parse_contract_type(args.contract_type)?; + let contract_type = self.parse_contract_type(args.nft_swap_info.contract_type)?; self.validate_payment_args( args.taker_secret_hash, args.maker_secret_hash, @@ -71,8 +71,8 @@ impl EthCoin { &contract_type, ) .map_err(ValidatePaymentError::InternalError)?; - let etomic_swap_contract = self.parse_contract_address(args.swap_contract_address)?; - let token_address = self.parse_contract_address(args.token_address)?; + let etomic_swap_contract = self.parse_contract_address(args.nft_swap_info.swap_contract_address)?; + let token_address = self.parse_contract_address(args.nft_swap_info.token_address)?; let maker_address = addr_from_raw_pubkey(args.maker_pub).map_to_mm(ValidatePaymentError::InternalError)?; let time_lock_u32 = args .time_lock @@ -112,7 +112,7 @@ impl EthCoin { let validation_params = ValidationParams { maker_address, etomic_swap_contract, - token_id: args.token_id, + token_id: args.nft_swap_info.token_id, amount, }; validate_decoded_data(&decoded, &validation_params)?; diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index 605e6cc873..92de4fed18 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -6,7 +6,7 @@ use bitcrypto::{dhash160, sha256}; use coins::eth::{checksum_address, eth_addr_to_hex, eth_coin_from_conf_and_request, EthCoin, ERC20_ABI}; use coins::nft::nft_structs::{Chain, ContractType, NftInfo}; use coins::{CoinAssocTypes, CoinProtocol, ConfirmPaymentInput, FoundSwapTxSpend, MakerNftSwapOpsV2, MarketCoinOps, - PrivKeyBuildPolicy, RefundPaymentArgs, SearchForSwapTxSpendInput, SendNftMakerPaymentArgs, + NftSwapInfo, PrivKeyBuildPolicy, RefundPaymentArgs, SearchForSwapTxSpendInput, SendNftMakerPaymentArgs, SendPaymentArgs, SpendNftMakerPaymentArgs, SpendPaymentArgs, SwapOps, SwapTxTypeWithSecretHash, ToBytes, Transaction, ValidateNftMakerPaymentArgs}; use common::{block_on, now_sec}; @@ -650,6 +650,13 @@ fn send_and_spend_erc721_maker_payment() { let maker_secret = &[1; 32]; let maker_secret_hash = sha256(maker_secret).to_vec(); + let nft_swap_info = NftSwapInfo { + token_address: &erc721_contract().to_bytes(), + token_id: &BigUint::from(2u32).to_bytes(), + contract_type: &ContractType::Erc721.to_bytes(), + swap_contract_address: &nft_swap_contract().to_bytes(), + }; + let send_payment_args: SendNftMakerPaymentArgs = SendNftMakerPaymentArgs { time_lock, taker_secret_hash: &[0; 32], @@ -657,10 +664,7 @@ fn send_and_spend_erc721_maker_payment() { amount: 1.into(), taker_pub: &taker_global_nft.parse_pubkey(&taker_pubkey).unwrap(), swap_unique_data: &[], - token_address: &erc721_contract().to_bytes(), - token_id: &BigUint::from(2u32).to_bytes(), - contract_type: &ContractType::Erc721.to_bytes(), - swap_contract_address: &nft_swap_contract().to_bytes(), + nft_swap_info: &nft_swap_info, }; let maker_payment = block_on(maker_global_nft.send_nft_maker_payment_v2(send_payment_args)).unwrap(); println!("Maker sent ERC721 NFT Payment tx hash {:02x}", maker_payment.tx_hash()); @@ -683,10 +687,7 @@ fn send_and_spend_erc721_maker_payment() { taker_pub: &taker_global_nft.parse_pubkey(&taker_pubkey).unwrap(), maker_pub: &maker_global_nft.parse_pubkey(&maker_pubkey).unwrap(), swap_unique_data: &[], - token_address: &erc721_contract().to_bytes(), - token_id: &BigUint::from(2u32).to_bytes(), - contract_type: &ContractType::Erc721.to_bytes(), - swap_contract_address: &nft_swap_contract().to_bytes(), + nft_swap_info: &nft_swap_info, }; block_on(maker_global_nft.validate_nft_maker_payment_v2(validate_args)).unwrap(); @@ -730,6 +731,13 @@ fn send_and_spend_erc1155_maker_payment() { let maker_secret = &[1; 32]; let maker_secret_hash = sha256(maker_secret).to_vec(); + let nft_swap_info = NftSwapInfo { + token_address: &erc1155_contract().to_bytes(), + token_id: &BigUint::from(4u32).to_bytes(), + contract_type: &ContractType::Erc1155.to_bytes(), + swap_contract_address: &nft_swap_contract().to_bytes(), + }; + let send_payment_args: SendNftMakerPaymentArgs = SendNftMakerPaymentArgs { time_lock, taker_secret_hash: &[0; 32], @@ -737,10 +745,7 @@ fn send_and_spend_erc1155_maker_payment() { amount: 3.into(), taker_pub: &taker_global_nft.parse_pubkey(&taker_pubkey).unwrap(), swap_unique_data: &[], - token_address: &erc1155_contract().to_bytes(), - token_id: &BigUint::from(4u32).to_bytes(), - contract_type: &ContractType::Erc1155.to_bytes(), - swap_contract_address: &nft_swap_contract().to_bytes(), + nft_swap_info: &nft_swap_info, }; let maker_payment = block_on(maker_global_nft.send_nft_maker_payment_v2(send_payment_args)).unwrap(); println!("Maker sent ERC1155 NFT Payment tx hash {:02x}", maker_payment.tx_hash()); @@ -763,10 +768,7 @@ fn send_and_spend_erc1155_maker_payment() { taker_pub: &taker_global_nft.parse_pubkey(&taker_pubkey).unwrap(), maker_pub: &maker_global_nft.parse_pubkey(&maker_pubkey).unwrap(), swap_unique_data: &[], - token_address: &erc1155_contract().to_bytes(), - token_id: &BigUint::from(4u32).to_bytes(), - contract_type: &ContractType::Erc1155.to_bytes(), - swap_contract_address: &nft_swap_contract().to_bytes(), + nft_swap_info: &nft_swap_info, }; block_on(maker_global_nft.validate_nft_maker_payment_v2(validate_args)).unwrap(); From 23d1c994e15eab82cd47fdf880a7ef81e7c6091c Mon Sep 17 00:00:00 2001 From: laruh Date: Fri, 5 Apr 2024 14:12:51 +0700 Subject: [PATCH 64/80] fix: improve fields names swap_address and contract_abi, make doc comment --- mm2src/coins/nft/trading_proto_v2/mod.rs | 36 +++++++++---------- .../tests/docker_tests/eth_docker_tests.rs | 12 +++---- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/mm2src/coins/nft/trading_proto_v2/mod.rs b/mm2src/coins/nft/trading_proto_v2/mod.rs index 3842c32ef9..0a6405d6b0 100644 --- a/mm2src/coins/nft/trading_proto_v2/mod.rs +++ b/mm2src/coins/nft/trading_proto_v2/mod.rs @@ -323,18 +323,18 @@ impl EthCoin { Ok(()) } - /// Retrieves the payment status from a given smart contract based on the swap ID and state type. + /// Retrieves the payment status from a given smart contract address based on the swap ID and state type. async fn payment_status_v2( &self, - swap_contract: Address, + swap_address: Address, swap_id: Token, - contract: &Contract, + contract_abi: &Contract, state_type: StateType, ) -> Result { let function_name = state_type.as_str(); - let function = contract.function(function_name)?; + let function = contract_abi.function(function_name)?; let data = function.encode_input(&[swap_id])?; - let bytes = self.call_request(swap_contract, None, Some(data.into())).await?; + let bytes = self.call_request(swap_address, None, Some(data.into())).await?; let decoded_tokens = function.decode_output(&bytes.0)?; let state = decoded_tokens .get(2) @@ -415,8 +415,8 @@ impl EthCoin { async fn status_and_htlc_params_from_tx_data( &self, - swap_contract: Address, - contract: &Contract, + swap_address: Address, + contract_abi: &Contract, decoded_data: &[Token], index: usize, state_type: StateType, @@ -424,7 +424,7 @@ impl EthCoin { if let Some(Token::Bytes(data_bytes)) = decoded_data.get(index) { if let Ok(htlc_params) = ethabi::decode(htlc_params(), data_bytes) { let state = self - .payment_status_v2(swap_contract, htlc_params[0].clone(), contract, state_type) + .payment_status_v2(swap_address, htlc_params[0].clone(), contract_abi, state_type) .await?; Ok((state, htlc_params)) } else { @@ -539,16 +539,16 @@ fn decode_and_validate_htlc_params( Ok(()) } -// Representation of the Solidity HTLCParams struct. -// -// struct HTLCParams { -// bytes32 id; -// address taker; -// address tokenAddress; -// bytes32 takerSecretHash; -// bytes32 makerSecretHash; -// uint32 paymentLockTime; -// } +/// Representation of the Solidity HTLCParams struct. +/// +/// struct HTLCParams { +/// bytes32 id; +/// address taker; +/// address tokenAddress; +/// bytes32 takerSecretHash; +/// bytes32 makerSecretHash; +/// uint32 paymentLockTime; +/// } fn htlc_params() -> &'static [ethabi::ParamType] { &[ ethabi::ParamType::FixedBytes(32), diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index 92de4fed18..46bd2b3d15 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -223,13 +223,13 @@ pub(crate) async fn fill_erc721_info(eth_coin: &EthCoin, tokens_id: u32) { } /// Creates ETH protocol coin supplied with 100 ETH -pub fn eth_coin_with_random_privkey(swap_contract: Address) -> EthCoin { +pub fn eth_coin_with_random_privkey(swap_contract_address: Address) -> EthCoin { let eth_conf = eth_dev_conf(); let req = json!({ "method": "enable", "coin": "ETH", "urls": ["http://127.0.0.1:8545"], - "swap_contract_address": swap_contract, + "swap_contract_address": swap_contract_address, }); let secret = random_secp256k1_secret(); @@ -250,13 +250,13 @@ pub fn eth_coin_with_random_privkey(swap_contract: Address) -> EthCoin { } /// Creates ERC20 protocol coin supplied with 1 ETH and 100 token -pub fn erc20_coin_with_random_privkey(swap_contract: Address) -> EthCoin { +pub fn erc20_coin_with_random_privkey(swap_contract_address: Address) -> EthCoin { let erc20_conf = erc20_dev_conf(&erc20_contract_checksum()); let req = json!({ "method": "enable", "coin": "ERC20DEV", "urls": ["http://127.0.0.1:8545"], - "swap_contract_address": swap_contract, + "swap_contract_address": swap_contract_address, }); let erc20_coin = block_on(eth_coin_from_conf_and_request( @@ -288,13 +288,13 @@ pub enum TestNftType { /// Generates a global NFT coin instance with a random private key and an initial 100 ETH balance. /// Optionally mints a specified NFT (either ERC721 or ERC1155) to the global NFT address, /// with details recorded in the `nfts_infos` field based on the provided `nft_type`. -pub fn global_nft_with_random_privkey(swap_contract: Address, nft_type: Option) -> EthCoin { +pub fn global_nft_with_random_privkey(swap_contract_address: Address, nft_type: Option) -> EthCoin { let nft_conf = nft_dev_conf(); let req = json!({ "method": "enable", "coin": "NFT_ETH", "urls": ["http://127.0.0.1:8545"], - "swap_contract_address": swap_contract, + "swap_contract_address": swap_contract_address, }); let global_nft = block_on(eth_coin_from_conf_and_request( From 0aa30339ae6b884c051cb8bb83b5ce3a0bcd41fa Mon Sep 17 00:00:00 2001 From: laruh Date: Fri, 5 Apr 2024 15:43:39 +0700 Subject: [PATCH 65/80] fix: refactor todo comment about etomic swap contract implementation strategy --- mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index 46bd2b3d15..aa43065fd3 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -634,9 +634,10 @@ fn send_and_spend_erc20_maker_payment() { #[test] fn send_and_spend_erc721_maker_payment() { - // in prod we will need to enable global NFT for taker or add new field (for nft swap address) in EthCoin, - // as EtomicSwapNft will have its own contract address, due to EIP-170 contract size limitations. - // TODO need to add NFT conf in coin conf and refactor enable nft a bit + // TODO: Evaluate implementation strategy — either employing separate contracts for maker and taker + // functionalities for both coins and NFTs, or utilizing the Diamond Standard (EIP-2535) for a unified contract approach. + // Decision will inform whether to maintain multiple "swap_contract_address" fields in `EthCoin` for distinct contract types + // or a singular field for a Diamond Standard-compatible contract address. let erc721_nft = TestNftType::Erc721 { token_id: 2 }; From 15c8a314734c947cb312c022f8f1ad94a9388c75 Mon Sep 17 00:00:00 2001 From: laruh Date: Fri, 5 Apr 2024 16:42:18 +0700 Subject: [PATCH 66/80] fix: provide field types &'a Coin::ContractType, &'a Coin::TokenContractAddr --- mm2src/coins/lp_coins.rs | 18 ++++---- mm2src/coins/nft/trading_proto_v2/mod.rs | 42 +++++++++---------- .../tests/docker_tests/eth_docker_tests.rs | 16 +++---- 3 files changed, 37 insertions(+), 39 deletions(-) diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index efc2a96a4b..5d0193044b 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -1497,15 +1497,15 @@ pub struct SendMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { } /// Structure representing necessary NFT info for Swap -pub struct NftSwapInfo<'a> { +pub struct NftSwapInfo<'a, Coin: CoinAssocTypes + NftAssocTypes + ?Sized> { /// The address of the NFT token - pub token_address: &'a [u8], + pub token_address: &'a Coin::TokenContractAddr, /// The ID of the NFT token. pub token_id: &'a [u8], /// The type of smart contract that governs this NFT - pub contract_type: &'a [u8], + pub contract_type: &'a Coin::ContractType, /// Etomic swap contract address - pub swap_contract_address: &'a [u8], + pub swap_contract_address: &'a Coin::TokenContractAddr, } pub struct SendNftMakerPaymentArgs<'a, Coin: CoinAssocTypes + NftAssocTypes + ?Sized> { @@ -1522,7 +1522,7 @@ pub struct SendNftMakerPaymentArgs<'a, Coin: CoinAssocTypes + NftAssocTypes + ?S /// Unique data of specific swap pub swap_unique_data: &'a [u8], /// Structure representing necessary NFT info for Swap - pub nft_swap_info: &'a NftSwapInfo<'a>, + pub nft_swap_info: &'a NftSwapInfo<'a, Coin>, } pub struct ValidateMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { @@ -1542,7 +1542,7 @@ pub struct ValidateMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { pub swap_unique_data: &'a [u8], } -pub struct ValidateNftMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { +pub struct ValidateNftMakerPaymentArgs<'a, Coin: CoinAssocTypes + NftAssocTypes + ?Sized> { /// Maker payment tx pub maker_payment_tx: &'a Coin::Tx, /// Maker will be able to refund the payment after this timestamp @@ -1560,7 +1560,7 @@ pub struct ValidateNftMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { /// Unique data of specific swap pub swap_unique_data: &'a [u8], /// Structure representing necessary NFT info for Swap - pub nft_swap_info: &'a NftSwapInfo<'a>, + pub nft_swap_info: &'a NftSwapInfo<'a, Coin>, } pub struct RefundMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { @@ -1597,7 +1597,7 @@ pub struct SpendMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { pub swap_unique_data: &'a [u8], } -pub struct SpendNftMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { +pub struct SpendNftMakerPaymentArgs<'a, Coin: CoinAssocTypes + NftAssocTypes + ?Sized> { /// Maker payment tx pub maker_payment_tx: &'a Coin::Tx, /// Maker will be able to refund the payment after this timestamp @@ -1613,7 +1613,7 @@ pub struct SpendNftMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { /// Unique data of specific swap pub swap_unique_data: &'a [u8], /// The type of smart contract that governs this NFT - pub contract_type: &'a [u8], + pub contract_type: &'a Coin::ContractType, /// Etomic swap contract address pub swap_contract_address: &'a [u8], } diff --git a/mm2src/coins/nft/trading_proto_v2/mod.rs b/mm2src/coins/nft/trading_proto_v2/mod.rs index 0a6405d6b0..12e6150a0c 100644 --- a/mm2src/coins/nft/trading_proto_v2/mod.rs +++ b/mm2src/coins/nft/trading_proto_v2/mod.rs @@ -25,31 +25,29 @@ impl EthCoin { &self, args: SendNftMakerPaymentArgs<'_, Self>, ) -> Result { - let contract_type = try_tx_s!(self.parse_contract_type(args.nft_swap_info.contract_type)); try_tx_s!(self.validate_payment_args( args.taker_secret_hash, args.maker_secret_hash, &args.amount, - &contract_type, + args.nft_swap_info.contract_type, )); let taker_address = try_tx_s!(addr_from_raw_pubkey(args.taker_pub)); - let token_address = try_tx_s!(self.parse_contract_address(args.nft_swap_info.token_address)); - let swap_contract_address = try_tx_s!(self.parse_contract_address(args.nft_swap_info.swap_contract_address)); let time_lock_u32 = try_tx_s!(args.time_lock.try_into()); let token_id_u256 = U256::from(args.nft_swap_info.token_id); - let htlc_data = self.prepare_htlc_data(&args, taker_address, token_address, time_lock_u32); + let token_address = args.nft_swap_info.token_address; + let htlc_data = self.prepare_htlc_data(&args, taker_address, *token_address, time_lock_u32); match &self.coin_type { EthCoinType::Nft { .. } => { let data = try_tx_s!(self.prepare_nft_maker_payment_v2_data( - contract_type, - swap_contract_address, + args.nft_swap_info.contract_type, + *args.nft_swap_info.swap_contract_address, token_id_u256, &args, htlc_data )); - self.sign_and_send_transaction(0.into(), Action::Call(token_address), data, U256::from(ETH_GAS)) + self.sign_and_send_transaction(0.into(), Action::Call(*token_address), data, U256::from(ETH_GAS)) .compat() .await }, @@ -63,16 +61,16 @@ impl EthCoin { &self, args: ValidateNftMakerPaymentArgs<'_, Self>, ) -> ValidatePaymentResult<()> { - let contract_type = self.parse_contract_type(args.nft_swap_info.contract_type)?; + let contract_type = args.nft_swap_info.contract_type; self.validate_payment_args( args.taker_secret_hash, args.maker_secret_hash, &args.amount, - &contract_type, + contract_type, ) .map_err(ValidatePaymentError::InternalError)?; - let etomic_swap_contract = self.parse_contract_address(args.nft_swap_info.swap_contract_address)?; - let token_address = self.parse_contract_address(args.nft_swap_info.token_address)?; + let etomic_swap_contract = args.nft_swap_info.swap_contract_address; + let token_address = args.nft_swap_info.token_address; let maker_address = addr_from_raw_pubkey(args.maker_pub).map_to_mm(ValidatePaymentError::InternalError)?; let time_lock_u32 = args .time_lock @@ -81,7 +79,7 @@ impl EthCoin { let swap_id = self.etomic_swap_id(time_lock_u32, args.maker_secret_hash); let maker_status = self .payment_status_v2( - etomic_swap_contract, + *etomic_swap_contract, Token::FixedBytes(swap_id.clone()), &NFT_SWAP_CONTRACT, StateType::MakerPayments, @@ -96,14 +94,14 @@ impl EthCoin { args.maker_payment_tx.hash )) })?; - self.validate_from_to_and_maker_status(tx_from_rpc, maker_address, token_address, maker_status) + self.validate_from_to_and_maker_status(tx_from_rpc, maker_address, *token_address, maker_status) .await?; match self.coin_type { EthCoinType::Nft { .. } => { let (decoded, index_bytes) = - self.get_decoded_tx_data_and_index_bytes(&contract_type, &tx_from_rpc.input.0)?; + self.get_decoded_tx_data_and_index_bytes(contract_type, &tx_from_rpc.input.0)?; - let amount = if matches!(contract_type, ContractType::Erc1155) { + let amount = if matches!(contract_type, &ContractType::Erc1155) { Some(args.amount.to_string()) } else { None @@ -111,7 +109,7 @@ impl EthCoin { let validation_params = ValidationParams { maker_address, - etomic_swap_contract, + etomic_swap_contract: *etomic_swap_contract, token_id: args.nft_swap_info.token_id, amount, }; @@ -122,7 +120,7 @@ impl EthCoin { let htlc_params = ExpectedHtlcParams { swap_id, taker_address, - token_address, + token_address: *token_address, taker_secret_hash: args.taker_secret_hash.to_vec(), maker_secret_hash: args.maker_secret_hash.to_vec(), time_lock: U256::from(args.time_lock), @@ -142,13 +140,13 @@ impl EthCoin { &self, args: SpendNftMakerPaymentArgs<'_, Self>, ) -> Result { - let contract_type = try_tx_s!(self.parse_contract_type(args.contract_type)); let etomic_swap_contract = try_tx_s!(self.parse_contract_address(args.swap_contract_address)); if args.maker_secret.len() != 32 { return Err(TransactionErr::Plain(ERRL!("maker_secret must be 32 bytes"))); } + let contract_type = args.contract_type; let (decoded, index_bytes) = - try_tx_s!(self.get_decoded_tx_data_and_index_bytes(&contract_type, &args.maker_payment_tx.data)); + try_tx_s!(self.get_decoded_tx_data_and_index_bytes(contract_type, &args.maker_payment_tx.data)); let (state, htlc_params) = try_tx_s!( self.status_and_htlc_params_from_tx_data( @@ -187,7 +185,7 @@ impl EthCoin { fn prepare_nft_maker_payment_v2_data( &self, - contract_type: ContractType, + contract_type: &ContractType, swap_contract_address: Address, token_id: U256, args: &SendNftMakerPaymentArgs<'_, Self>, @@ -370,7 +368,7 @@ impl EthCoin { /// and encodes the input parameters required for the blockchain transaction. fn prepare_spend_nft_maker_v2_data( &self, - contract_type: ContractType, + contract_type: &ContractType, args: &SpendNftMakerPaymentArgs<'_, Self>, decoded: Vec, htlc_params: Vec, diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index aa43065fd3..43965f3289 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -652,10 +652,10 @@ fn send_and_spend_erc721_maker_payment() { let maker_secret_hash = sha256(maker_secret).to_vec(); let nft_swap_info = NftSwapInfo { - token_address: &erc721_contract().to_bytes(), + token_address: &erc721_contract(), token_id: &BigUint::from(2u32).to_bytes(), - contract_type: &ContractType::Erc721.to_bytes(), - swap_contract_address: &nft_swap_contract().to_bytes(), + contract_type: &ContractType::Erc721, + swap_contract_address: &nft_swap_contract(), }; let send_payment_args: SendNftMakerPaymentArgs = SendNftMakerPaymentArgs { @@ -700,7 +700,7 @@ fn send_and_spend_erc721_maker_payment() { maker_secret, maker_pub: &maker_global_nft.parse_pubkey(&maker_pubkey).unwrap(), swap_unique_data: &[], - contract_type: &ContractType::Erc721.to_bytes(), + contract_type: &ContractType::Erc721, swap_contract_address: &nft_swap_contract().to_bytes(), }; let spend_tx = block_on(taker_global_nft.spend_nft_maker_payment_v2(spend_payment_args)).unwrap(); @@ -733,10 +733,10 @@ fn send_and_spend_erc1155_maker_payment() { let maker_secret_hash = sha256(maker_secret).to_vec(); let nft_swap_info = NftSwapInfo { - token_address: &erc1155_contract().to_bytes(), + token_address: &erc1155_contract(), token_id: &BigUint::from(4u32).to_bytes(), - contract_type: &ContractType::Erc1155.to_bytes(), - swap_contract_address: &nft_swap_contract().to_bytes(), + contract_type: &ContractType::Erc1155, + swap_contract_address: &nft_swap_contract(), }; let send_payment_args: SendNftMakerPaymentArgs = SendNftMakerPaymentArgs { @@ -781,7 +781,7 @@ fn send_and_spend_erc1155_maker_payment() { maker_secret, maker_pub: &maker_global_nft.parse_pubkey(&maker_pubkey).unwrap(), swap_unique_data: &[], - contract_type: &ContractType::Erc1155.to_bytes(), + contract_type: &ContractType::Erc1155, swap_contract_address: &nft_swap_contract().to_bytes(), }; let spend_tx = block_on(taker_global_nft.spend_nft_maker_payment_v2(spend_payment_args)).unwrap(); From 977cf40af09bfb0046b306565dfdf68b99a79929 Mon Sep 17 00:00:00 2001 From: laruh Date: Fri, 5 Apr 2024 17:50:40 +0700 Subject: [PATCH 67/80] fix: avoid nesting code --- mm2src/coins/nft/trading_proto_v2/mod.rs | 156 +++++++++++------------ 1 file changed, 71 insertions(+), 85 deletions(-) diff --git a/mm2src/coins/nft/trading_proto_v2/mod.rs b/mm2src/coins/nft/trading_proto_v2/mod.rs index 12e6150a0c..2ae6226de6 100644 --- a/mm2src/coins/nft/trading_proto_v2/mod.rs +++ b/mm2src/coins/nft/trading_proto_v2/mod.rs @@ -419,48 +419,49 @@ impl EthCoin { index: usize, state_type: StateType, ) -> Result<(U256, Vec), PaymentStatusErr> { - if let Some(Token::Bytes(data_bytes)) = decoded_data.get(index) { - if let Ok(htlc_params) = ethabi::decode(htlc_params(), data_bytes) { - let state = self - .payment_status_v2(swap_address, htlc_params[0].clone(), contract_abi, state_type) - .await?; - Ok((state, htlc_params)) - } else { - Err(PaymentStatusErr::TxDeserializationError(ERRL!( + let data_bytes = match decoded_data.get(index) { + Some(Token::Bytes(data_bytes)) => data_bytes, + _ => { + return Err(PaymentStatusErr::TxDeserializationError(ERRL!( "Failed to decode HTLCParams from data_bytes" ))) - } - } else { - Err(PaymentStatusErr::TxDeserializationError(ERRL!( - "Failed to decode HTLCParams from data_bytes" - ))) - } + }, + }; + + let htlc_params = match ethabi::decode(htlc_params(), data_bytes) { + Ok(htlc_params) => htlc_params, + Err(_) => { + return Err(PaymentStatusErr::TxDeserializationError(ERRL!( + "Failed to decode HTLCParams from data_bytes" + ))) + }, + }; + + let state = self + .payment_status_v2(swap_address, htlc_params[0].clone(), contract_abi, state_type) + .await?; + + Ok((state, htlc_params)) } } /// Validates decoded data from tx input, related to `safeTransferFrom` contract call fn validate_decoded_data(decoded: &[Token], params: &ValidationParams) -> Result<(), MmError> { - if decoded[0] != Token::Address(params.maker_address) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment `maker_address` {:?} is invalid, expected {:?}", - decoded[0], - Token::Address(params.maker_address) - ))); - } - if decoded[1] != Token::Address(params.etomic_swap_contract) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment `etomic_swap_contract` {:?} is invalid, expected address {:?}", - decoded[1], - Token::Address(params.etomic_swap_contract) - ))); - } - let token_id = U256::from(params.token_id); - if decoded[2] != Token::Uint(token_id) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment `token_id` {:?} is invalid, expected {:?}", - decoded[2], - Token::Uint(token_id) - ))); + let checks = vec![ + (0, Token::Address(params.maker_address), "maker_address"), + (1, Token::Address(params.etomic_swap_contract), "etomic_swap_contract"), + (2, Token::Uint(U256::from(params.token_id)), "token_id"), + ]; + + for (index, expected_token, field_name) in checks { + if decoded.get(index) != Some(&expected_token) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment `{}` {:?} is invalid, expected {:?}", + field_name, + decoded.get(index), + expected_token + ))); + } } if let Some(amount) = ¶ms.amount { let value = U256::from_dec_str(amount).map_to_mm(|e| ValidatePaymentError::InternalError(e.to_string()))?; @@ -480,60 +481,45 @@ fn decode_and_validate_htlc_params( index: usize, expected_params: ExpectedHtlcParams, ) -> MmResult<(), HtlcParamsError> { - if let Some(Token::Bytes(data_bytes)) = decoded.get(index) { - if let Ok(decoded_params) = ethabi::decode(htlc_params(), data_bytes) { - if decoded_params[0] != Token::FixedBytes(expected_params.swap_id.clone()) { - return MmError::err(HtlcParamsError::WrongPaymentTx(format!( - "Invalid 'swap_id' {:?}, expected {:?}", - decoded_params[0], - Token::FixedBytes(expected_params.swap_id) - ))); - } - if decoded_params[1] != Token::Address(expected_params.taker_address) { - return MmError::err(HtlcParamsError::WrongPaymentTx(format!( - "Invalid `taker_address` {:?}, expected {:?}", - decoded_params[1], - Token::Address(expected_params.taker_address) - ))); - } - if decoded_params[2] != Token::Address(expected_params.token_address) { - return MmError::err(HtlcParamsError::WrongPaymentTx(format!( - "Invalid `token_address` {:?}, expected {:?}", - decoded_params[2], - Token::Address(expected_params.token_address) - ))); - } - if decoded_params[3] != Token::FixedBytes(expected_params.taker_secret_hash.clone()) { - return MmError::err(HtlcParamsError::WrongPaymentTx(format!( - "Invalid 'taker_secret_hash' {:?}, expected {:?}", - decoded_params[3], - Token::FixedBytes(expected_params.taker_secret_hash) - ))); - } - if decoded_params[4] != Token::FixedBytes(expected_params.maker_secret_hash.clone()) { - return MmError::err(HtlcParamsError::WrongPaymentTx(format!( - "Invalid 'maker_secret_hash' {:?}, expected {:?}", - decoded_params[4], - Token::FixedBytes(expected_params.maker_secret_hash) - ))); - } - if decoded_params[5] != Token::Uint(expected_params.time_lock) { - return MmError::err(HtlcParamsError::WrongPaymentTx(format!( - "Invalid 'time_lock' {:?}, expected {:?}", - decoded_params[5], - Token::Uint(expected_params.time_lock) - ))); - } - } else { + let data_bytes = match decoded.get(index) { + Some(Token::Bytes(bytes)) => bytes, + _ => { + return MmError::err(HtlcParamsError::TxDeserializationError( + "Expected Bytes for HTLCParams data".to_string(), + )) + }, + }; + + let decoded_params = match ethabi::decode(htlc_params(), data_bytes) { + Ok(params) => params, + Err(_) => { return MmError::err(HtlcParamsError::TxDeserializationError( "Failed to decode HTLCParams from data_bytes".to_string(), - )); + )) + }, + }; + + let expected_taker_secret_hash = Token::FixedBytes(expected_params.taker_secret_hash.clone()); + let expected_maker_secret_hash = Token::FixedBytes(expected_params.maker_secret_hash.clone()); + + let checks = vec![ + (0, Token::FixedBytes(expected_params.swap_id.clone()), "swap_id"), + (1, Token::Address(expected_params.taker_address), "taker_address"), + (2, Token::Address(expected_params.token_address), "token_address"), + (3, expected_taker_secret_hash, "taker_secret_hash"), + (4, expected_maker_secret_hash, "maker_secret_hash"), + (5, Token::Uint(expected_params.time_lock), "time_lock"), + ]; + + for (index, expected_token, param_name) in checks.into_iter() { + if decoded_params[index] != expected_token { + return MmError::err(HtlcParamsError::WrongPaymentTx(format!( + "Invalid '{}' {:?}, expected {:?}", + param_name, decoded_params[index], expected_token + ))); } - } else { - return MmError::err(HtlcParamsError::TxDeserializationError( - "Expected Bytes for HTLCParams data".to_string(), - )); } + Ok(()) } From 2d022800b358f5c8cba172ef322ef5e2ddb6d54b Mon Sep 17 00:00:00 2001 From: laruh Date: Fri, 5 Apr 2024 19:33:08 +0700 Subject: [PATCH 68/80] fix: remove unneeded trait constraint CoinAssocTypes --- mm2src/coins/lp_coins.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 5d0193044b..abb3fd0380 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -1497,7 +1497,7 @@ pub struct SendMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { } /// Structure representing necessary NFT info for Swap -pub struct NftSwapInfo<'a, Coin: CoinAssocTypes + NftAssocTypes + ?Sized> { +pub struct NftSwapInfo<'a, Coin: NftAssocTypes + ?Sized> { /// The address of the NFT token pub token_address: &'a Coin::TokenContractAddr, /// The ID of the NFT token. From 8b5476b8d55aeebfb5cf38aebf8757c9f75b0090 Mon Sep 17 00:00:00 2001 From: laruh Date: Fri, 5 Apr 2024 21:19:39 +0700 Subject: [PATCH 69/80] fix: use args:SendNftMakerPaymentArgs instead, use generic and trait ContractValidation in validate_payment_args --- mm2src/coins/nft/trading_proto_v2/mod.rs | 193 +++++++++++++---------- 1 file changed, 113 insertions(+), 80 deletions(-) diff --git a/mm2src/coins/nft/trading_proto_v2/mod.rs b/mm2src/coins/nft/trading_proto_v2/mod.rs index 2ae6226de6..4c2125bb3e 100644 --- a/mm2src/coins/nft/trading_proto_v2/mod.rs +++ b/mm2src/coins/nft/trading_proto_v2/mod.rs @@ -17,39 +17,28 @@ use super::ContractType; use crate::eth::{addr_from_raw_pubkey, decode_contract_call, EthCoin, EthCoinType, MakerPaymentStateV2, SignedEthTx, TryToAddress, ERC1155_CONTRACT, ERC721_CONTRACT, ETH_GAS, NFT_SWAP_CONTRACT}; use crate::nft::trading_proto_v2::errors::PrepareTxDataError; -use crate::{NftAssocTypes, RefundPaymentArgs, SendNftMakerPaymentArgs, SpendNftMakerPaymentArgs, TransactionErr, - ValidateNftMakerPaymentArgs}; +use crate::{CoinAssocTypes, NftAssocTypes, RefundPaymentArgs, SendNftMakerPaymentArgs, SpendNftMakerPaymentArgs, + TransactionErr, ValidateNftMakerPaymentArgs}; impl EthCoin { pub(crate) async fn send_nft_maker_payment_v2_impl( &self, args: SendNftMakerPaymentArgs<'_, Self>, ) -> Result { - try_tx_s!(self.validate_payment_args( - args.taker_secret_hash, - args.maker_secret_hash, - &args.amount, - args.nft_swap_info.contract_type, - )); - - let taker_address = try_tx_s!(addr_from_raw_pubkey(args.taker_pub)); - let time_lock_u32 = try_tx_s!(args.time_lock.try_into()); - let token_id_u256 = U256::from(args.nft_swap_info.token_id); - let token_address = args.nft_swap_info.token_address; - let htlc_data = self.prepare_htlc_data(&args, taker_address, *token_address, time_lock_u32); + try_tx_s!(validate_payment_args(PaymentValidationParams::from(&args))); + let htlc_data = try_tx_s!(self.prepare_htlc_data(&args)); match &self.coin_type { EthCoinType::Nft { .. } => { - let data = try_tx_s!(self.prepare_nft_maker_payment_v2_data( - args.nft_swap_info.contract_type, - *args.nft_swap_info.swap_contract_address, - token_id_u256, - &args, - htlc_data - )); - self.sign_and_send_transaction(0.into(), Action::Call(*token_address), data, U256::from(ETH_GAS)) - .compat() - .await + let data = try_tx_s!(self.prepare_nft_maker_payment_v2_data(&args, htlc_data)); + self.sign_and_send_transaction( + 0.into(), + Action::Call(*args.nft_swap_info.token_address), + data, + U256::from(ETH_GAS), + ) + .compat() + .await }, EthCoinType::Eth | EthCoinType::Erc20 { .. } => Err(TransactionErr::ProtocolNotSupported( "ETH and ERC20 Protocols are not supported for NFT Swaps".to_string(), @@ -62,13 +51,7 @@ impl EthCoin { args: ValidateNftMakerPaymentArgs<'_, Self>, ) -> ValidatePaymentResult<()> { let contract_type = args.nft_swap_info.contract_type; - self.validate_payment_args( - args.taker_secret_hash, - args.maker_secret_hash, - &args.amount, - contract_type, - ) - .map_err(ValidatePaymentError::InternalError)?; + validate_payment_args(PaymentValidationParams::from(&args)).map_err(ValidatePaymentError::InternalError)?; let etomic_swap_contract = args.nft_swap_info.swap_contract_address; let token_address = args.nft_swap_info.token_address; let maker_address = addr_from_raw_pubkey(args.maker_pub).map_to_mm(ValidatePaymentError::InternalError)?; @@ -185,21 +168,18 @@ impl EthCoin { fn prepare_nft_maker_payment_v2_data( &self, - contract_type: &ContractType, - swap_contract_address: Address, - token_id: U256, args: &SendNftMakerPaymentArgs<'_, Self>, htlc_data: Vec, ) -> Result, PrepareTxDataError> { - match contract_type { + match args.nft_swap_info.contract_type { ContractType::Erc1155 => { let function = ERC1155_CONTRACT.function("safeTransferFrom")?; let amount_u256 = U256::from_dec_str(&args.amount.to_string()) .map_err(|e| PrepareTxDataError::Internal(e.to_string()))?; let data = function.encode_input(&[ Token::Address(self.my_address), - Token::Address(swap_contract_address), - Token::Uint(token_id), + Token::Address(*args.nft_swap_info.swap_contract_address), + Token::Uint(U256::from(args.nft_swap_info.token_id)), Token::Uint(amount_u256), Token::Bytes(htlc_data), ])?; @@ -209,8 +189,8 @@ impl EthCoin { let function = self.erc721_transfer_with_data()?; let data = function.encode_input(&[ Token::Address(self.my_address), - Token::Address(swap_contract_address), - Token::Uint(token_id), + Token::Address(*args.nft_swap_info.swap_contract_address), + Token::Uint(U256::from(args.nft_swap_info.token_id)), Token::Bytes(htlc_data), ])?; Ok(data) @@ -218,51 +198,23 @@ impl EthCoin { } } - fn validate_payment_args<'a>( - &self, - taker_secret_hash: &'a [u8], - maker_secret_hash: &'a [u8], - amount: &BigDecimal, - contract_type: &ContractType, - ) -> Result<(), String> { - match contract_type { - ContractType::Erc1155 => { - if !is_positive_integer(amount) { - return Err("ERC-1155 amount must be a positive integer".to_string()); - } - }, - ContractType::Erc721 => { - if amount != &BigDecimal::from(1) { - return Err("ERC-721 amount must be 1".to_string()); - } - }, - } - if taker_secret_hash.len() != 32 { - return Err("taker_secret_hash must be 32 bytes".to_string()); - } - if maker_secret_hash.len() != 32 { - return Err("maker_secret_hash must be 32 bytes".to_string()); - } - - Ok(()) - } - - fn prepare_htlc_data( - &self, - args: &SendNftMakerPaymentArgs<'_, Self>, - taker_address: Address, - token_address: Address, - time_lock: u32, - ) -> Vec { - let id = self.etomic_swap_id(time_lock, args.maker_secret_hash); - ethabi::encode(&[ + fn prepare_htlc_data(&self, args: &SendNftMakerPaymentArgs<'_, Self>) -> Result, PrepareTxDataError> { + let taker_address = + addr_from_raw_pubkey(args.taker_pub).map_err(|e| PrepareTxDataError::Internal(ERRL!("{}", e)))?; + let time_lock_u32 = args + .time_lock + .try_into() + .map_err(|e| PrepareTxDataError::Internal(ERRL!("{}", e)))?; + let id = self.etomic_swap_id(time_lock_u32, args.maker_secret_hash); + let encoded = ethabi::encode(&[ Token::FixedBytes(id), Token::Address(taker_address), - Token::Address(token_address), + Token::Address(*args.nft_swap_info.token_address), Token::FixedBytes(args.taker_secret_hash.to_vec()), Token::FixedBytes(args.maker_secret_hash.to_vec()), - Token::Uint(U256::from(time_lock)), - ]) + Token::Uint(U256::from(time_lock_u32)), + ]); + Ok(encoded) } /// ERC721 contract has overloaded versions of the `safeTransferFrom` function, @@ -547,3 +499,84 @@ fn htlc_params() -> &'static [ethabi::ParamType] { /// function to check if BigDecimal is a positive integer #[inline(always)] fn is_positive_integer(amount: &BigDecimal) -> bool { amount == &amount.with_scale(0) && amount > &BigDecimal::from(0) } + +struct PaymentValidationParams<'a, T> +where + T: ContractValidation, +{ + taker_secret_hash: &'a [u8], + maker_secret_hash: &'a [u8], + amount: &'a BigDecimal, + contract_type: &'a T, +} + +impl<'a, Coin> From<&'a ValidateNftMakerPaymentArgs<'a, Coin>> for PaymentValidationParams<'a, Coin::ContractType> +where + Coin: CoinAssocTypes + NftAssocTypes + ?Sized, + ::ContractType: ContractValidation, +{ + fn from(args: &'a ValidateNftMakerPaymentArgs<'a, Coin>) -> Self { + Self { + taker_secret_hash: args.taker_secret_hash, + maker_secret_hash: args.maker_secret_hash, + amount: &args.amount, + contract_type: args.nft_swap_info.contract_type, + } + } +} + +impl<'a, Coin> From<&'a SendNftMakerPaymentArgs<'a, Coin>> for PaymentValidationParams<'a, Coin::ContractType> +where + Coin: CoinAssocTypes + NftAssocTypes + ?Sized, + ::ContractType: ContractValidation, +{ + fn from(args: &'a SendNftMakerPaymentArgs<'a, Coin>) -> Self { + Self { + taker_secret_hash: args.taker_secret_hash, + maker_secret_hash: args.maker_secret_hash, + amount: &args.amount, + contract_type: args.nft_swap_info.contract_type, + } + } +} + +pub trait ContractValidation { + fn validate(&self, amount: &BigDecimal) -> Result<(), String>; +} + +impl ContractValidation for ContractType { + fn validate(&self, amount: &BigDecimal) -> Result<(), String> { + match self { + ContractType::Erc1155 => { + if !is_positive_integer(amount) { + Err("ERC-1155 amount must be a positive integer".to_string()) + } else { + Ok(()) + } + }, + ContractType::Erc721 => { + if amount != &BigDecimal::from(1) { + Err("ERC-721 amount must be 1".to_string()) + } else { + Ok(()) + } + }, + } + } +} + +fn validate_payment_args<'a, T>(args: PaymentValidationParams<'a, T>) -> Result<(), String> +where + T: ContractValidation + 'a, +{ + args.contract_type.validate(args.amount)?; + + if args.taker_secret_hash.len() != 32 { + return Err("taker_secret_hash must be 32 bytes".to_string()); + } + if args.maker_secret_hash.len() != 32 { + return Err("maker_secret_hash must be 32 bytes".to_string()); + } + + Ok(()) +} From 5d99c3433b6769678aa9364dfc3474044ea1f22e Mon Sep 17 00:00:00 2001 From: laruh Date: Fri, 5 Apr 2024 21:46:09 +0700 Subject: [PATCH 70/80] fix: provide swap_contract_address: &'a Coin::ContractAddress --- mm2src/coins/eth.rs | 10 +++++----- mm2src/coins/lp_coins.rs | 14 +++++++------- mm2src/coins/nft/trading_proto_v2/mod.rs | 6 +++--- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index abc4935476..0bfd975bc2 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -6299,8 +6299,8 @@ impl ToBytes for ContractType { } impl NftAssocTypes for EthCoin { - type TokenContractAddr = Address; - type TokenContractAddrParseError = NftAssocTypesError; + type ContractAddress = Address; + type ContractAddrParseError = NftAssocTypesError; type TokenId = BigUint; type TokenIdParseError = NftAssocTypesError; type ContractType = ContractType; @@ -6308,9 +6308,9 @@ impl NftAssocTypes for EthCoin { fn parse_contract_address( &self, - token_contract_addr: &[u8], - ) -> Result { - token_contract_addr + contract_address: &[u8], + ) -> Result { + contract_address .try_to_address() .map_err(NftAssocTypesError::ParseTokenContractError) } diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index abb3fd0380..16a8ec5e5e 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -1464,8 +1464,8 @@ pub trait CoinAssocTypes { /// Defines associated types specific to Non-Fungible Tokens (Token Address, Token Id, etc.) pub trait NftAssocTypes { - type TokenContractAddr: Send + Sync + fmt::Display; - type TokenContractAddrParseError: fmt::Debug + Send + fmt::Display; + type ContractAddress: Send + Sync + fmt::Display; + type ContractAddrParseError: fmt::Debug + Send + fmt::Display; type TokenId: ToBytes + Send + Sync; type TokenIdParseError: fmt::Debug + Send + fmt::Display; type ContractType: ToBytes + Send + Sync; @@ -1473,8 +1473,8 @@ pub trait NftAssocTypes { fn parse_contract_address( &self, - token_contract_addr: &[u8], - ) -> Result; + contract_address: &[u8], + ) -> Result; fn parse_token_id(&self, token_id: &[u8]) -> Result; @@ -1499,13 +1499,13 @@ pub struct SendMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { /// Structure representing necessary NFT info for Swap pub struct NftSwapInfo<'a, Coin: NftAssocTypes + ?Sized> { /// The address of the NFT token - pub token_address: &'a Coin::TokenContractAddr, + pub token_address: &'a Coin::ContractAddress, /// The ID of the NFT token. pub token_id: &'a [u8], /// The type of smart contract that governs this NFT pub contract_type: &'a Coin::ContractType, /// Etomic swap contract address - pub swap_contract_address: &'a Coin::TokenContractAddr, + pub swap_contract_address: &'a Coin::ContractAddress, } pub struct SendNftMakerPaymentArgs<'a, Coin: CoinAssocTypes + NftAssocTypes + ?Sized> { @@ -1615,7 +1615,7 @@ pub struct SpendNftMakerPaymentArgs<'a, Coin: CoinAssocTypes + NftAssocTypes + ? /// The type of smart contract that governs this NFT pub contract_type: &'a Coin::ContractType, /// Etomic swap contract address - pub swap_contract_address: &'a [u8], + pub swap_contract_address: &'a Coin::ContractAddress, } /// Operations specific to maker coin in [Trading Protocol Upgrade implementation](https://github.com/KomodoPlatform/komodo-defi-framework/issues/1895) diff --git a/mm2src/coins/nft/trading_proto_v2/mod.rs b/mm2src/coins/nft/trading_proto_v2/mod.rs index 4c2125bb3e..73782fd650 100644 --- a/mm2src/coins/nft/trading_proto_v2/mod.rs +++ b/mm2src/coins/nft/trading_proto_v2/mod.rs @@ -123,7 +123,7 @@ impl EthCoin { &self, args: SpendNftMakerPaymentArgs<'_, Self>, ) -> Result { - let etomic_swap_contract = try_tx_s!(self.parse_contract_address(args.swap_contract_address)); + let etomic_swap_contract = args.swap_contract_address; if args.maker_secret.len() != 32 { return Err(TransactionErr::Plain(ERRL!("maker_secret must be 32 bytes"))); } @@ -133,7 +133,7 @@ impl EthCoin { let (state, htlc_params) = try_tx_s!( self.status_and_htlc_params_from_tx_data( - etomic_swap_contract, + *etomic_swap_contract, &NFT_SWAP_CONTRACT, &decoded, index_bytes, @@ -146,7 +146,7 @@ impl EthCoin { let data = try_tx_s!(self.prepare_spend_nft_maker_v2_data(contract_type, &args, decoded, htlc_params, state)); - self.sign_and_send_transaction(0.into(), Action::Call(etomic_swap_contract), data, U256::from(ETH_GAS)) + self.sign_and_send_transaction(0.into(), Action::Call(*etomic_swap_contract), data, U256::from(ETH_GAS)) .compat() .await }, From f7c8863099ed50747445c2eda135771937acd097 Mon Sep 17 00:00:00 2001 From: laruh Date: Fri, 5 Apr 2024 21:49:16 +0700 Subject: [PATCH 71/80] fix: reuse args: &SpendNftMakerPaymentArgs in prepare_spend_nft_maker_v2_data --- mm2src/coins/nft/trading_proto_v2/mod.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/mm2src/coins/nft/trading_proto_v2/mod.rs b/mm2src/coins/nft/trading_proto_v2/mod.rs index 73782fd650..f86e8d0358 100644 --- a/mm2src/coins/nft/trading_proto_v2/mod.rs +++ b/mm2src/coins/nft/trading_proto_v2/mod.rs @@ -144,7 +144,7 @@ impl EthCoin { match self.coin_type { EthCoinType::Nft { .. } => { let data = - try_tx_s!(self.prepare_spend_nft_maker_v2_data(contract_type, &args, decoded, htlc_params, state)); + try_tx_s!(self.prepare_spend_nft_maker_v2_data(&args, decoded, htlc_params, state)); self.sign_and_send_transaction(0.into(), Action::Call(*etomic_swap_contract), data, U256::from(ETH_GAS)) .compat() @@ -320,13 +320,12 @@ impl EthCoin { /// and encodes the input parameters required for the blockchain transaction. fn prepare_spend_nft_maker_v2_data( &self, - contract_type: &ContractType, args: &SpendNftMakerPaymentArgs<'_, Self>, decoded: Vec, htlc_params: Vec, state: U256, ) -> Result, PrepareTxDataError> { - let spend_func = match contract_type { + let spend_func = match args.contract_type { ContractType::Erc1155 => NFT_SWAP_CONTRACT.function("spendErc1155MakerPayment")?, ContractType::Erc721 => NFT_SWAP_CONTRACT.function("spendErc721MakerPayment")?, }; @@ -339,7 +338,7 @@ impl EthCoin { ))); } - let input_tokens = match contract_type { + let input_tokens = match args.contract_type { ContractType::Erc1155 => vec![ htlc_params[0].clone(), // swap_id Token::Address(args.maker_payment_tx.sender()), From 5fcdab1fdeb8c50c07e3f1d51090bdb742da7fc1 Mon Sep 17 00:00:00 2001 From: laruh Date: Fri, 5 Apr 2024 21:53:01 +0700 Subject: [PATCH 72/80] fix fmt --- mm2src/coins/nft/trading_proto_v2/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mm2src/coins/nft/trading_proto_v2/mod.rs b/mm2src/coins/nft/trading_proto_v2/mod.rs index f86e8d0358..ab03b4409a 100644 --- a/mm2src/coins/nft/trading_proto_v2/mod.rs +++ b/mm2src/coins/nft/trading_proto_v2/mod.rs @@ -143,9 +143,7 @@ impl EthCoin { ); match self.coin_type { EthCoinType::Nft { .. } => { - let data = - try_tx_s!(self.prepare_spend_nft_maker_v2_data(&args, decoded, htlc_params, state)); - + let data = try_tx_s!(self.prepare_spend_nft_maker_v2_data(&args, decoded, htlc_params, state)); self.sign_and_send_transaction(0.into(), Action::Call(*etomic_swap_contract), data, U256::from(ETH_GAS)) .compat() .await From defb7bb6f27270c07ebf2a88505aaebce8f696c9 Mon Sep 17 00:00:00 2001 From: laruh Date: Fri, 5 Apr 2024 21:59:25 +0700 Subject: [PATCH 73/80] fix: self.my_addr() for Token::Address --- mm2src/coins/nft/trading_proto_v2/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm2src/coins/nft/trading_proto_v2/mod.rs b/mm2src/coins/nft/trading_proto_v2/mod.rs index ab03b4409a..fe7fb20c16 100644 --- a/mm2src/coins/nft/trading_proto_v2/mod.rs +++ b/mm2src/coins/nft/trading_proto_v2/mod.rs @@ -175,7 +175,7 @@ impl EthCoin { let amount_u256 = U256::from_dec_str(&args.amount.to_string()) .map_err(|e| PrepareTxDataError::Internal(e.to_string()))?; let data = function.encode_input(&[ - Token::Address(self.my_address), + Token::Address(*self.my_addr()), Token::Address(*args.nft_swap_info.swap_contract_address), Token::Uint(U256::from(args.nft_swap_info.token_id)), Token::Uint(amount_u256), @@ -186,7 +186,7 @@ impl EthCoin { ContractType::Erc721 => { let function = self.erc721_transfer_with_data()?; let data = function.encode_input(&[ - Token::Address(self.my_address), + Token::Address(*self.my_addr()), Token::Address(*args.nft_swap_info.swap_contract_address), Token::Uint(U256::from(args.nft_swap_info.token_id)), Token::Bytes(htlc_data), From b596d1dee83dfa3eb3debd7c07c1d303b3a00424 Mon Sep 17 00:00:00 2001 From: laruh Date: Fri, 5 Apr 2024 22:09:12 +0700 Subject: [PATCH 74/80] fix linter in tests --- mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index 43965f3289..e00ef6f568 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -701,7 +701,7 @@ fn send_and_spend_erc721_maker_payment() { maker_pub: &maker_global_nft.parse_pubkey(&maker_pubkey).unwrap(), swap_unique_data: &[], contract_type: &ContractType::Erc721, - swap_contract_address: &nft_swap_contract().to_bytes(), + swap_contract_address: &nft_swap_contract(), }; let spend_tx = block_on(taker_global_nft.spend_nft_maker_payment_v2(spend_payment_args)).unwrap(); @@ -782,7 +782,7 @@ fn send_and_spend_erc1155_maker_payment() { maker_pub: &maker_global_nft.parse_pubkey(&maker_pubkey).unwrap(), swap_unique_data: &[], contract_type: &ContractType::Erc1155, - swap_contract_address: &nft_swap_contract().to_bytes(), + swap_contract_address: &nft_swap_contract(), }; let spend_tx = block_on(taker_global_nft.spend_nft_maker_payment_v2(spend_payment_args)).unwrap(); From 71db8d77cdfd02b73d21bb4124bd7f28a1f8f1de Mon Sep 17 00:00:00 2001 From: laruh Date: Sun, 7 Apr 2024 13:27:55 +0700 Subject: [PATCH 75/80] fix: simplify validate_payment_args func, make it standalone non public --- mm2src/coins/eth.rs | 1 + mm2src/coins/nft/trading_proto_v2/mod.rs | 106 +++++++---------------- 2 files changed, 33 insertions(+), 74 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 0bfd975bc2..2f43517b5d 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -141,6 +141,7 @@ const ERC721_ABI: &str = include_str!("eth/erc721_abi.json"); /// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md const ERC1155_ABI: &str = include_str!("eth/erc1155_abi.json"); const NFT_SWAP_CONTRACT_ABI: &str = include_str!("eth/nft_swap_contract_abi.json"); + /// Payment states from etomic swap smart contract: https://github.com/artemii235/etomic-swap/blob/master/contracts/EtomicSwap.sol#L5 pub enum PaymentState { Uninitialized, diff --git a/mm2src/coins/nft/trading_proto_v2/mod.rs b/mm2src/coins/nft/trading_proto_v2/mod.rs index fe7fb20c16..f7a2bdaf44 100644 --- a/mm2src/coins/nft/trading_proto_v2/mod.rs +++ b/mm2src/coins/nft/trading_proto_v2/mod.rs @@ -17,15 +17,20 @@ use super::ContractType; use crate::eth::{addr_from_raw_pubkey, decode_contract_call, EthCoin, EthCoinType, MakerPaymentStateV2, SignedEthTx, TryToAddress, ERC1155_CONTRACT, ERC721_CONTRACT, ETH_GAS, NFT_SWAP_CONTRACT}; use crate::nft::trading_proto_v2::errors::PrepareTxDataError; -use crate::{CoinAssocTypes, NftAssocTypes, RefundPaymentArgs, SendNftMakerPaymentArgs, SpendNftMakerPaymentArgs, - TransactionErr, ValidateNftMakerPaymentArgs}; +use crate::{CoinAssocTypes, RefundPaymentArgs, SendNftMakerPaymentArgs, SpendNftMakerPaymentArgs, TransactionErr, + ValidateNftMakerPaymentArgs}; impl EthCoin { pub(crate) async fn send_nft_maker_payment_v2_impl( &self, args: SendNftMakerPaymentArgs<'_, Self>, ) -> Result { - try_tx_s!(validate_payment_args(PaymentValidationParams::from(&args))); + try_tx_s!(validate_payment_args( + args.taker_secret_hash, + args.maker_secret_hash, + &args.amount, + args.nft_swap_info.contract_type + )); let htlc_data = try_tx_s!(self.prepare_htlc_data(&args)); match &self.coin_type { @@ -51,7 +56,13 @@ impl EthCoin { args: ValidateNftMakerPaymentArgs<'_, Self>, ) -> ValidatePaymentResult<()> { let contract_type = args.nft_swap_info.contract_type; - validate_payment_args(PaymentValidationParams::from(&args)).map_err(ValidatePaymentError::InternalError)?; + validate_payment_args( + args.taker_secret_hash, + args.maker_secret_hash, + &args.amount, + contract_type, + ) + .map_err(ValidatePaymentError::InternalError)?; let etomic_swap_contract = args.nft_swap_info.swap_contract_address; let token_address = args.nft_swap_info.token_address; let maker_address = addr_from_raw_pubkey(args.maker_pub).map_to_mm(ValidatePaymentError::InternalError)?; @@ -497,81 +508,28 @@ fn htlc_params() -> &'static [ethabi::ParamType] { #[inline(always)] fn is_positive_integer(amount: &BigDecimal) -> bool { amount == &amount.with_scale(0) && amount > &BigDecimal::from(0) } -struct PaymentValidationParams<'a, T> -where - T: ContractValidation, -{ +fn validate_payment_args<'a>( taker_secret_hash: &'a [u8], maker_secret_hash: &'a [u8], - amount: &'a BigDecimal, - contract_type: &'a T, -} - -impl<'a, Coin> From<&'a ValidateNftMakerPaymentArgs<'a, Coin>> for PaymentValidationParams<'a, Coin::ContractType> -where - Coin: CoinAssocTypes + NftAssocTypes + ?Sized, - ::ContractType: ContractValidation, -{ - fn from(args: &'a ValidateNftMakerPaymentArgs<'a, Coin>) -> Self { - Self { - taker_secret_hash: args.taker_secret_hash, - maker_secret_hash: args.maker_secret_hash, - amount: &args.amount, - contract_type: args.nft_swap_info.contract_type, - } - } -} - -impl<'a, Coin> From<&'a SendNftMakerPaymentArgs<'a, Coin>> for PaymentValidationParams<'a, Coin::ContractType> -where - Coin: CoinAssocTypes + NftAssocTypes + ?Sized, - ::ContractType: ContractValidation, -{ - fn from(args: &'a SendNftMakerPaymentArgs<'a, Coin>) -> Self { - Self { - taker_secret_hash: args.taker_secret_hash, - maker_secret_hash: args.maker_secret_hash, - amount: &args.amount, - contract_type: args.nft_swap_info.contract_type, - } - } -} - -pub trait ContractValidation { - fn validate(&self, amount: &BigDecimal) -> Result<(), String>; -} - -impl ContractValidation for ContractType { - fn validate(&self, amount: &BigDecimal) -> Result<(), String> { - match self { - ContractType::Erc1155 => { - if !is_positive_integer(amount) { - Err("ERC-1155 amount must be a positive integer".to_string()) - } else { - Ok(()) - } - }, - ContractType::Erc721 => { - if amount != &BigDecimal::from(1) { - Err("ERC-721 amount must be 1".to_string()) - } else { - Ok(()) - } - }, - } + amount: &BigDecimal, + contract_type: &ContractType, +) -> Result<(), String> { + match contract_type { + ContractType::Erc1155 => { + if !is_positive_integer(amount) { + return Err("ERC-1155 amount must be a positive integer".to_string()); + } + }, + ContractType::Erc721 => { + if amount != &BigDecimal::from(1) { + return Err("ERC-721 amount must be 1".to_string()); + } + }, } -} - -fn validate_payment_args<'a, T>(args: PaymentValidationParams<'a, T>) -> Result<(), String> -where - T: ContractValidation + 'a, -{ - args.contract_type.validate(args.amount)?; - - if args.taker_secret_hash.len() != 32 { + if taker_secret_hash.len() != 32 { return Err("taker_secret_hash must be 32 bytes".to_string()); } - if args.maker_secret_hash.len() != 32 { + if maker_secret_hash.len() != 32 { return Err("maker_secret_hash must be 32 bytes".to_string()); } From 71f4df5076c911f085b6a3d50d8f22320b261e18 Mon Sep 17 00:00:00 2001 From: laruh Date: Sun, 7 Apr 2024 13:51:16 +0700 Subject: [PATCH 76/80] fix: make validate_from_to_and_maker_status, get_decoded_tx_data_and_index_bytes, erc721_transfer_with_data standalone non public --- mm2src/coins/nft/trading_proto_v2/mod.rs | 156 +++++++++++------------ 1 file changed, 77 insertions(+), 79 deletions(-) diff --git a/mm2src/coins/nft/trading_proto_v2/mod.rs b/mm2src/coins/nft/trading_proto_v2/mod.rs index f7a2bdaf44..dbd0cc5bda 100644 --- a/mm2src/coins/nft/trading_proto_v2/mod.rs +++ b/mm2src/coins/nft/trading_proto_v2/mod.rs @@ -88,12 +88,10 @@ impl EthCoin { args.maker_payment_tx.hash )) })?; - self.validate_from_to_and_maker_status(tx_from_rpc, maker_address, *token_address, maker_status) - .await?; + validate_from_to_and_maker_status(tx_from_rpc, maker_address, *token_address, maker_status).await?; match self.coin_type { EthCoinType::Nft { .. } => { - let (decoded, index_bytes) = - self.get_decoded_tx_data_and_index_bytes(contract_type, &tx_from_rpc.input.0)?; + let (decoded, index_bytes) = get_decoded_tx_data_and_index_bytes(contract_type, &tx_from_rpc.input.0)?; let amount = if matches!(contract_type, &ContractType::Erc1155) { Some(args.amount.to_string()) @@ -139,8 +137,10 @@ impl EthCoin { return Err(TransactionErr::Plain(ERRL!("maker_secret must be 32 bytes"))); } let contract_type = args.contract_type; - let (decoded, index_bytes) = - try_tx_s!(self.get_decoded_tx_data_and_index_bytes(contract_type, &args.maker_payment_tx.data)); + let (decoded, index_bytes) = try_tx_s!(get_decoded_tx_data_and_index_bytes( + contract_type, + &args.maker_payment_tx.data + )); let (state, htlc_params) = try_tx_s!( self.status_and_htlc_params_from_tx_data( @@ -195,7 +195,7 @@ impl EthCoin { Ok(data) }, ContractType::Erc721 => { - let function = self.erc721_transfer_with_data()?; + let function = erc721_transfer_with_data()?; let data = function.encode_input(&[ Token::Address(*self.my_addr()), Token::Address(*args.nft_swap_info.swap_contract_address), @@ -226,62 +226,6 @@ impl EthCoin { Ok(encoded) } - /// ERC721 contract has overloaded versions of the `safeTransferFrom` function, - /// but `Contract::function` method returns only the first if there are overloaded versions of the same function. - /// Provided function retrieves the `safeTransferFrom` variant that includes a `bytes` parameter. - /// This variant is specifically used for transferring ERC721 tokens with additional data. - fn erc721_transfer_with_data(&self) -> Result<ðabi::Function, Erc721FunctionError> { - let functions = ERC721_CONTRACT - .functions_by_name("safeTransferFrom") - .map_err(|e| Erc721FunctionError::AbiError(ERRL!("{}", e)))?; - - // Find the correct function variant by inspecting the input parameters. - let function = functions - .iter() - .find(|f| { - f.inputs.len() == 4 - && matches!( - f.inputs.last().map(|input| &input.kind), - Some(ðabi::ParamType::Bytes) - ) - }) - .ok_or_else(|| { - Erc721FunctionError::FunctionNotFound( - "Failed to find the correct safeTransferFrom function variant".to_string(), - ) - })?; - Ok(function) - } - - async fn validate_from_to_and_maker_status( - &self, - tx_from_rpc: &Web3Tx, - expected_from: Address, - expected_to: Address, - maker_status: U256, - ) -> ValidatePaymentResult<()> { - if maker_status != U256::from(MakerPaymentStateV2::PaymentSent as u8) { - return MmError::err(ValidatePaymentError::UnexpectedPaymentState(format!( - "NFT Maker Payment state is not PAYMENT_STATE_SENT, got {}", - maker_status - ))); - } - if tx_from_rpc.from != Some(expected_from) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment tx {:?} was sent from wrong address, expected {:?}", - tx_from_rpc, expected_from - ))); - } - // As NFT owner calls "safeTransferFrom" directly, then in Transaction 'to' field we expect token_address - if tx_from_rpc.to != Some(expected_to) { - return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( - "NFT Maker Payment tx {:?} was sent to wrong address, expected {:?}", - tx_from_rpc, expected_to, - ))); - } - Ok(()) - } - /// Retrieves the payment status from a given smart contract address based on the swap ID and state type. async fn payment_status_v2( &self, @@ -307,22 +251,6 @@ impl EthCoin { } } - /// Identifies the correct "safeTransferFrom" function based on the contract type (either ERC1155 or ERC721) - /// and decodes the provided contract call bytes using the ABI of the identified function. Additionally, it returns - /// the index position of the "bytes" field within the function's parameters. - pub(crate) fn get_decoded_tx_data_and_index_bytes( - &self, - contract_type: &ContractType, - contract_call_bytes: &[u8], - ) -> Result<(Vec, usize), PrepareTxDataError> { - let (send_func, index_bytes) = match contract_type { - ContractType::Erc1155 => (ERC1155_CONTRACT.function("safeTransferFrom")?, 4), - ContractType::Erc721 => (self.erc721_transfer_with_data()?, 3), - }; - let decoded = decode_contract_call(send_func, contract_call_bytes)?; - Ok((decoded, index_bytes)) - } - /// Prepares the encoded transaction data for spending a maker's NFT payment on the blockchain. /// /// This function selects the appropriate contract function based on the NFT's contract type (ERC1155 or ERC721) @@ -535,3 +463,73 @@ fn validate_payment_args<'a>( Ok(()) } + +async fn validate_from_to_and_maker_status( + tx_from_rpc: &Web3Tx, + expected_from: Address, + expected_to: Address, + maker_status: U256, +) -> ValidatePaymentResult<()> { + if maker_status != U256::from(MakerPaymentStateV2::PaymentSent as u8) { + return MmError::err(ValidatePaymentError::UnexpectedPaymentState(format!( + "NFT Maker Payment state is not PAYMENT_STATE_SENT, got {}", + maker_status + ))); + } + if tx_from_rpc.from != Some(expected_from) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment tx {:?} was sent from wrong address, expected {:?}", + tx_from_rpc, expected_from + ))); + } + // As NFT owner calls "safeTransferFrom" directly, then in Transaction 'to' field we expect token_address + if tx_from_rpc.to != Some(expected_to) { + return MmError::err(ValidatePaymentError::WrongPaymentTx(format!( + "NFT Maker Payment tx {:?} was sent to wrong address, expected {:?}", + tx_from_rpc, expected_to, + ))); + } + Ok(()) +} + +/// Identifies the correct "safeTransferFrom" function based on the contract type (either ERC1155 or ERC721) +/// and decodes the provided contract call bytes using the ABI of the identified function. Additionally, it returns +/// the index position of the "bytes" field within the function's parameters. +pub(crate) fn get_decoded_tx_data_and_index_bytes( + contract_type: &ContractType, + contract_call_bytes: &[u8], +) -> Result<(Vec, usize), PrepareTxDataError> { + let (send_func, index_bytes) = match contract_type { + ContractType::Erc1155 => (ERC1155_CONTRACT.function("safeTransferFrom")?, 4), + ContractType::Erc721 => (erc721_transfer_with_data()?, 3), + }; + let decoded = decode_contract_call(send_func, contract_call_bytes)?; + Ok((decoded, index_bytes)) +} + +/// ERC721 contract has overloaded versions of the `safeTransferFrom` function, +/// but `Contract::function` method returns only the first if there are overloaded versions of the same function. +/// Provided function retrieves the `safeTransferFrom` variant that includes a `bytes` parameter. +/// This variant is specifically used for transferring ERC721 tokens with additional data. +fn erc721_transfer_with_data<'a>() -> Result<&'a ethabi::Function, Erc721FunctionError> { + let functions = ERC721_CONTRACT + .functions_by_name("safeTransferFrom") + .map_err(|e| Erc721FunctionError::AbiError(ERRL!("{}", e)))?; + + // Find the correct function variant by inspecting the input parameters. + let function = functions + .iter() + .find(|f| { + f.inputs.len() == 4 + && matches!( + f.inputs.last().map(|input| &input.kind), + Some(ðabi::ParamType::Bytes) + ) + }) + .ok_or_else(|| { + Erc721FunctionError::FunctionNotFound( + "Failed to find the correct safeTransferFrom function variant".to_string(), + ) + })?; + Ok(function) +} From 8e6183cfd2e1723d4b53e82554ccd52787b7d121 Mon Sep 17 00:00:00 2001 From: laruh Date: Sun, 7 Apr 2024 14:29:35 +0700 Subject: [PATCH 77/80] fix: provide nft_swap_v2 module in eth --- mm2src/coins/coin_errors.rs | 2 +- mm2src/coins/eth.rs | 3 ++- .../{nft/trading_proto_v2 => eth/nft_swap_v2}/errors.rs | 0 .../coins/{nft/trading_proto_v2 => eth/nft_swap_v2}/mod.rs | 5 ++--- .../{nft/trading_proto_v2 => eth/nft_swap_v2}/structs.rs | 0 mm2src/coins/nft.rs | 1 - 6 files changed, 5 insertions(+), 6 deletions(-) rename mm2src/coins/{nft/trading_proto_v2 => eth/nft_swap_v2}/errors.rs (100%) rename mm2src/coins/{nft/trading_proto_v2 => eth/nft_swap_v2}/mod.rs (99%) rename mm2src/coins/{nft/trading_proto_v2 => eth/nft_swap_v2}/structs.rs (100%) diff --git a/mm2src/coins/coin_errors.rs b/mm2src/coins/coin_errors.rs index 9c5598ffb5..e6f02ea369 100644 --- a/mm2src/coins/coin_errors.rs +++ b/mm2src/coins/coin_errors.rs @@ -1,5 +1,5 @@ +use crate::eth::nft_swap_v2::errors::{Erc721FunctionError, HtlcParamsError, PaymentStatusErr, PrepareTxDataError}; use crate::eth::{CoinAssocTypesError, NftAssocTypesError, Web3RpcError}; -use crate::nft::trading_proto_v2::errors::{Erc721FunctionError, HtlcParamsError, PaymentStatusErr, PrepareTxDataError}; use crate::{utxo::rpc_clients::UtxoRpcError, NumConversError, UnexpectedDerivationMethod}; use enum_derives::EnumFromStringify; use futures01::Future; diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 2f43517b5d..e31b93bf0a 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -117,15 +117,16 @@ mod eth_balance_events; mod eth_rpc; #[cfg(test)] mod eth_tests; #[cfg(target_arch = "wasm32")] mod eth_wasm_tests; +pub(crate) mod nft_swap_v2; mod web3_transport; #[path = "eth/v2_activation.rs"] pub mod v2_activation; -use crate::nft::WithdrawNftResult; use v2_activation::{build_address_and_priv_key_policy, EthActivationV2Error}; mod nonce; use crate::coin_errors::ValidatePaymentResult; use crate::nft::nft_errors::{GetNftInfoError, ParseContractTypeError}; +use crate::nft::WithdrawNftResult; use crate::{PrivKeyPolicy, TransactionResult, WithdrawFrom}; use nonce::ParityNonce; diff --git a/mm2src/coins/nft/trading_proto_v2/errors.rs b/mm2src/coins/eth/nft_swap_v2/errors.rs similarity index 100% rename from mm2src/coins/nft/trading_proto_v2/errors.rs rename to mm2src/coins/eth/nft_swap_v2/errors.rs diff --git a/mm2src/coins/nft/trading_proto_v2/mod.rs b/mm2src/coins/eth/nft_swap_v2/mod.rs similarity index 99% rename from mm2src/coins/nft/trading_proto_v2/mod.rs rename to mm2src/coins/eth/nft_swap_v2/mod.rs index dbd0cc5bda..07a1bba16b 100644 --- a/mm2src/coins/nft/trading_proto_v2/mod.rs +++ b/mm2src/coins/eth/nft_swap_v2/mod.rs @@ -9,14 +9,13 @@ use std::convert::TryInto; use web3::types::{Transaction as Web3Tx, TransactionId}; pub(crate) mod errors; -use errors::{Erc721FunctionError, HtlcParamsError, PaymentStatusErr}; -pub(crate) mod structs; +use errors::{Erc721FunctionError, HtlcParamsError, PaymentStatusErr, PrepareTxDataError}; +mod structs; use structs::{ExpectedHtlcParams, StateType, ValidationParams}; use super::ContractType; use crate::eth::{addr_from_raw_pubkey, decode_contract_call, EthCoin, EthCoinType, MakerPaymentStateV2, SignedEthTx, TryToAddress, ERC1155_CONTRACT, ERC721_CONTRACT, ETH_GAS, NFT_SWAP_CONTRACT}; -use crate::nft::trading_proto_v2::errors::PrepareTxDataError; use crate::{CoinAssocTypes, RefundPaymentArgs, SendNftMakerPaymentArgs, SpendNftMakerPaymentArgs, TransactionErr, ValidateNftMakerPaymentArgs}; diff --git a/mm2src/coins/nft/trading_proto_v2/structs.rs b/mm2src/coins/eth/nft_swap_v2/structs.rs similarity index 100% rename from mm2src/coins/nft/trading_proto_v2/structs.rs rename to mm2src/coins/eth/nft_swap_v2/structs.rs diff --git a/mm2src/coins/nft.rs b/mm2src/coins/nft.rs index e6ee1b8659..8e73e2b272 100644 --- a/mm2src/coins/nft.rs +++ b/mm2src/coins/nft.rs @@ -7,7 +7,6 @@ pub mod nft_structs; pub(crate) mod storage; #[cfg(any(test, target_arch = "wasm32"))] mod nft_tests; -pub(crate) mod trading_proto_v2; use crate::{coin_conf, get_my_address, lp_coinfind_or_err, CoinsContext, MarketCoinOps, MmCoinEnum, MmCoinStruct, MyAddressReq, WithdrawError}; From 76af66892d06e7051d2b6e92818bbf1a463d4dc8 Mon Sep 17 00:00:00 2001 From: laruh Date: Tue, 9 Apr 2024 04:39:34 +0700 Subject: [PATCH 78/80] fix review notes --- mm2src/coins/eth.rs | 17 +++++++++-------- mm2src/coins/eth/nft_swap_v2/mod.rs | 10 +++++----- mm2src/coins/eth/nft_swap_v2/structs.rs | 8 ++++---- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index e31b93bf0a..6bf9c2a7b1 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -167,6 +167,7 @@ pub(crate) enum TakerPaymentStateV2 { MakerSpent, TakerRefunded, } + // Ethgasstation API returns response in 10^8 wei units. So 10 from their API mean 1 gwei const ETH_GAS_STATION_DECIMALS: u8 = 8; const GAS_PRICE_PERCENT: u64 = 10; @@ -6276,15 +6277,15 @@ impl CoinAssocTypes for EthCoin { fn parse_preimage(&self, tx: &[u8]) -> Result { self.parse_tx(tx) } fn parse_signature(&self, sig: &[u8]) -> Result { - if sig.len() == 65 { - let mut arr = [0; 65]; - arr.copy_from_slice(sig); - Ok(Signature::from(arr)) // Assuming `Signature::from([u8; 65])` exists - } else { - MmError::err(CoinAssocTypesError::ParseSignatureError( + if sig.len() != 65 { + return MmError::err(CoinAssocTypesError::ParseSignatureError( "Signature slice is not 65 bytes long".to_string(), - )) - } + )); + }; + + let mut arr = [0; 65]; + arr.copy_from_slice(sig); + Ok(Signature::from(arr)) // Assuming `Signature::from([u8; 65])` exists } } diff --git a/mm2src/coins/eth/nft_swap_v2/mod.rs b/mm2src/coins/eth/nft_swap_v2/mod.rs index 07a1bba16b..f416d785e3 100644 --- a/mm2src/coins/eth/nft_swap_v2/mod.rs +++ b/mm2src/coins/eth/nft_swap_v2/mod.rs @@ -11,7 +11,7 @@ use web3::types::{Transaction as Web3Tx, TransactionId}; pub(crate) mod errors; use errors::{Erc721FunctionError, HtlcParamsError, PaymentStatusErr, PrepareTxDataError}; mod structs; -use structs::{ExpectedHtlcParams, StateType, ValidationParams}; +use structs::{ExpectedHtlcParams, PaymentType, ValidationParams}; use super::ContractType; use crate::eth::{addr_from_raw_pubkey, decode_contract_call, EthCoin, EthCoinType, MakerPaymentStateV2, SignedEthTx, @@ -75,7 +75,7 @@ impl EthCoin { *etomic_swap_contract, Token::FixedBytes(swap_id.clone()), &NFT_SWAP_CONTRACT, - StateType::MakerPayments, + PaymentType::MakerPayments, ) .await?; let tx_from_rpc = self @@ -147,7 +147,7 @@ impl EthCoin { &NFT_SWAP_CONTRACT, &decoded, index_bytes, - StateType::MakerPayments, + PaymentType::MakerPayments, ) .await ); @@ -231,7 +231,7 @@ impl EthCoin { swap_address: Address, swap_id: Token, contract_abi: &Contract, - state_type: StateType, + state_type: PaymentType, ) -> Result { let function_name = state_type.as_str(); let function = contract_abi.function(function_name)?; @@ -304,7 +304,7 @@ impl EthCoin { contract_abi: &Contract, decoded_data: &[Token], index: usize, - state_type: StateType, + state_type: PaymentType, ) -> Result<(U256, Vec), PaymentStatusErr> { let data_bytes = match decoded_data.get(index) { Some(Token::Bytes(data_bytes)) => data_bytes, diff --git a/mm2src/coins/eth/nft_swap_v2/structs.rs b/mm2src/coins/eth/nft_swap_v2/structs.rs index 673124d8c8..a0c129bf4b 100644 --- a/mm2src/coins/eth/nft_swap_v2/structs.rs +++ b/mm2src/coins/eth/nft_swap_v2/structs.rs @@ -18,16 +18,16 @@ pub(crate) struct ValidationParams<'a> { } #[allow(dead_code)] -pub(crate) enum StateType { +pub(crate) enum PaymentType { MakerPayments, TakerPayments, } -impl StateType { +impl PaymentType { pub(crate) fn as_str(&self) -> &'static str { match self { - StateType::MakerPayments => "makerPayments", - StateType::TakerPayments => "takerPayments", + PaymentType::MakerPayments => "makerPayments", + PaymentType::TakerPayments => "takerPayments", } } } From 95411dc54ea85d814820fdde90bbcc5985c91d95 Mon Sep 17 00:00:00 2001 From: laruh Date: Tue, 9 Apr 2024 14:26:50 +0700 Subject: [PATCH 79/80] fix: provide one err type in NftAssocTypes trait, rename errors --- mm2src/coins/coin_errors.rs | 6 ++--- mm2src/coins/eth.rs | 52 ++++++++++++++++++------------------- mm2src/coins/lp_coins.rs | 10 +++---- 3 files changed, 32 insertions(+), 36 deletions(-) diff --git a/mm2src/coins/coin_errors.rs b/mm2src/coins/coin_errors.rs index e6f02ea369..5c86537a46 100644 --- a/mm2src/coins/coin_errors.rs +++ b/mm2src/coins/coin_errors.rs @@ -1,5 +1,5 @@ use crate::eth::nft_swap_v2::errors::{Erc721FunctionError, HtlcParamsError, PaymentStatusErr, PrepareTxDataError}; -use crate::eth::{CoinAssocTypesError, NftAssocTypesError, Web3RpcError}; +use crate::eth::{EthAssocTypesError, EthNftAssocTypesError, Web3RpcError}; use crate::{utxo::rpc_clients::UtxoRpcError, NumConversError, UnexpectedDerivationMethod}; use enum_derives::EnumFromStringify; use futures01::Future; @@ -17,9 +17,9 @@ pub type ValidatePaymentResult = Result>; pub enum ValidatePaymentError { /// Should be used to indicate internal MM2 state problems (e.g., DB errors, etc.). #[from_stringify( - "CoinAssocTypesError", + "EthAssocTypesError", "Erc721FunctionError", - "NftAssocTypesError", + "EthNftAssocTypesError", "NumConversError", "UnexpectedDerivationMethod", "keys::Error", diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 6bf9c2a7b1..2faa0286e3 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -6221,64 +6221,64 @@ impl ToBytes for SignedEthTx { } #[derive(Debug, Display)] -pub enum CoinAssocTypesError { +pub enum EthAssocTypesError { InvalidHexString(String), TxParseError(String), ParseSignatureError(String), KeysError(keys::Error), } -impl From for CoinAssocTypesError { - fn from(e: DecoderError) -> Self { CoinAssocTypesError::TxParseError(e.to_string()) } +impl From for EthAssocTypesError { + fn from(e: DecoderError) -> Self { EthAssocTypesError::TxParseError(e.to_string()) } } -impl From for CoinAssocTypesError { - fn from(e: keys::Error) -> Self { CoinAssocTypesError::KeysError(e) } +impl From for EthAssocTypesError { + fn from(e: keys::Error) -> Self { EthAssocTypesError::KeysError(e) } } #[derive(Debug, Display)] -pub enum NftAssocTypesError { +pub enum EthNftAssocTypesError { Utf8Error(String), ParseContractTypeError(ParseContractTypeError), ParseTokenContractError(String), } -impl From for NftAssocTypesError { - fn from(e: ParseContractTypeError) -> Self { NftAssocTypesError::ParseContractTypeError(e) } +impl From for EthNftAssocTypesError { + fn from(e: ParseContractTypeError) -> Self { EthNftAssocTypesError::ParseContractTypeError(e) } } impl CoinAssocTypes for EthCoin { type Address = Address; - type AddressParseError = MmError; + type AddressParseError = MmError; type Pubkey = HtlcPubKey; - type PubkeyParseError = MmError; + type PubkeyParseError = MmError; type Tx = SignedEthTx; - type TxParseError = MmError; + type TxParseError = MmError; type Preimage = SignedEthTx; - type PreimageParseError = MmError; + type PreimageParseError = MmError; type Sig = Signature; - type SigParseError = MmError; + type SigParseError = MmError; fn my_addr(&self) -> &Self::Address { &self.my_address } fn parse_address(&self, address: &str) -> Result { - Address::from_str(address).map_to_mm(|e| CoinAssocTypesError::InvalidHexString(e.to_string())) + Address::from_str(address).map_to_mm(|e| EthAssocTypesError::InvalidHexString(e.to_string())) } fn parse_pubkey(&self, pubkey: &[u8]) -> Result { - HtlcPubKey::from_slice(pubkey).map_to_mm(CoinAssocTypesError::from) + HtlcPubKey::from_slice(pubkey).map_to_mm(EthAssocTypesError::from) } fn parse_tx(&self, tx: &[u8]) -> Result { - let unverified: UnverifiedTransaction = rlp::decode(tx).map_err(CoinAssocTypesError::from)?; - SignedEthTx::new(unverified).map_to_mm(|e| CoinAssocTypesError::TxParseError(e.to_string())) + let unverified: UnverifiedTransaction = rlp::decode(tx).map_err(EthAssocTypesError::from)?; + SignedEthTx::new(unverified).map_to_mm(|e| EthAssocTypesError::TxParseError(e.to_string())) } fn parse_preimage(&self, tx: &[u8]) -> Result { self.parse_tx(tx) } fn parse_signature(&self, sig: &[u8]) -> Result { if sig.len() != 65 { - return MmError::err(CoinAssocTypesError::ParseSignatureError( + return MmError::err(EthAssocTypesError::ParseSignatureError( "Signature slice is not 65 bytes long".to_string(), )); }; @@ -6303,28 +6303,26 @@ impl ToBytes for ContractType { impl NftAssocTypes for EthCoin { type ContractAddress = Address; - type ContractAddrParseError = NftAssocTypesError; type TokenId = BigUint; - type TokenIdParseError = NftAssocTypesError; type ContractType = ContractType; - type ContractTypeParseError = NftAssocTypesError; + type NftAssocTypesError = MmError; fn parse_contract_address( &self, contract_address: &[u8], - ) -> Result { + ) -> Result { contract_address .try_to_address() - .map_err(NftAssocTypesError::ParseTokenContractError) + .map_to_mm(EthNftAssocTypesError::ParseTokenContractError) } - fn parse_token_id(&self, token_id: &[u8]) -> Result { + fn parse_token_id(&self, token_id: &[u8]) -> Result { Ok(BigUint::from_bytes_be(token_id)) } - fn parse_contract_type(&self, contract_type: &[u8]) -> Result { - let contract_str = from_utf8(contract_type).map_err(|e| NftAssocTypesError::Utf8Error(e.to_string()))?; - ContractType::from_str(contract_str).map_err(NftAssocTypesError::from) + fn parse_contract_type(&self, contract_type: &[u8]) -> Result { + let contract_str = from_utf8(contract_type).map_err(|e| EthNftAssocTypesError::Utf8Error(e.to_string()))?; + ContractType::from_str(contract_str).map_to_mm(EthNftAssocTypesError::from) } } diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 16a8ec5e5e..6ec2613659 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -1465,20 +1465,18 @@ pub trait CoinAssocTypes { /// Defines associated types specific to Non-Fungible Tokens (Token Address, Token Id, etc.) pub trait NftAssocTypes { type ContractAddress: Send + Sync + fmt::Display; - type ContractAddrParseError: fmt::Debug + Send + fmt::Display; type TokenId: ToBytes + Send + Sync; - type TokenIdParseError: fmt::Debug + Send + fmt::Display; type ContractType: ToBytes + Send + Sync; - type ContractTypeParseError: fmt::Debug + Send + fmt::Display; + type NftAssocTypesError: fmt::Debug + Send + fmt::Display; fn parse_contract_address( &self, contract_address: &[u8], - ) -> Result; + ) -> Result; - fn parse_token_id(&self, token_id: &[u8]) -> Result; + fn parse_token_id(&self, token_id: &[u8]) -> Result; - fn parse_contract_type(&self, contract_type: &[u8]) -> Result; + fn parse_contract_type(&self, contract_type: &[u8]) -> Result; } pub struct SendMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { From 014552deda35c8d072b48ff14a112dc1d64a4b86 Mon Sep 17 00:00:00 2001 From: laruh Date: Tue, 9 Apr 2024 18:25:45 +0700 Subject: [PATCH 80/80] fix: rename assoc types traits --- mm2src/coins/eth.rs | 6 +- mm2src/coins/eth/nft_swap_v2/mod.rs | 2 +- mm2src/coins/lp_coins.rs | 42 ++++----- mm2src/coins/test_coin.rs | 10 +- mm2src/coins/utxo.rs | 4 +- mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs | 57 +++++------ mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs | 94 ++++++++++--------- .../tests/docker_tests/eth_docker_tests.rs | 8 +- .../tests/docker_tests/swap_proto_v2_tests.rs | 9 +- 9 files changed, 117 insertions(+), 115 deletions(-) diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index 2faa0286e3..84431b7f12 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -26,7 +26,7 @@ use crate::eth::web3_transport::websocket_transport::{WebsocketTransport, Websoc use crate::lp_price::get_base_price_in_rel; use crate::nft::nft_structs::{ContractType, ConvertChain, NftInfo, TransactionNftDetails, WithdrawErc1155, WithdrawErc721}; -use crate::{CoinAssocTypes, DexFee, MakerNftSwapOpsV2, NftAssocTypes, RefundMakerPaymentArgs, RpcCommonOps, +use crate::{DexFee, MakerNftSwapOpsV2, ParseCoinAssocTypes, ParseNftAssocTypes, RefundMakerPaymentArgs, RpcCommonOps, SendNftMakerPaymentArgs, SpendNftMakerPaymentArgs, ToBytes, ValidateNftMakerPaymentArgs, ValidateWatcherSpendInput, WatcherSpendType}; use async_trait::async_trait; @@ -6247,7 +6247,7 @@ impl From for EthNftAssocTypesError { fn from(e: ParseContractTypeError) -> Self { EthNftAssocTypesError::ParseContractTypeError(e) } } -impl CoinAssocTypes for EthCoin { +impl ParseCoinAssocTypes for EthCoin { type Address = Address; type AddressParseError = MmError; type Pubkey = HtlcPubKey; @@ -6301,7 +6301,7 @@ impl ToBytes for ContractType { fn to_bytes(&self) -> Vec { self.to_string().into_bytes() } } -impl NftAssocTypes for EthCoin { +impl ParseNftAssocTypes for EthCoin { type ContractAddress = Address; type TokenId = BigUint; type ContractType = ContractType; diff --git a/mm2src/coins/eth/nft_swap_v2/mod.rs b/mm2src/coins/eth/nft_swap_v2/mod.rs index f416d785e3..83488deada 100644 --- a/mm2src/coins/eth/nft_swap_v2/mod.rs +++ b/mm2src/coins/eth/nft_swap_v2/mod.rs @@ -16,7 +16,7 @@ use structs::{ExpectedHtlcParams, PaymentType, ValidationParams}; use super::ContractType; use crate::eth::{addr_from_raw_pubkey, decode_contract_call, EthCoin, EthCoinType, MakerPaymentStateV2, SignedEthTx, TryToAddress, ERC1155_CONTRACT, ERC721_CONTRACT, ETH_GAS, NFT_SWAP_CONTRACT}; -use crate::{CoinAssocTypes, RefundPaymentArgs, SendNftMakerPaymentArgs, SpendNftMakerPaymentArgs, TransactionErr, +use crate::{ParseCoinAssocTypes, RefundPaymentArgs, SendNftMakerPaymentArgs, SpendNftMakerPaymentArgs, TransactionErr, ValidateNftMakerPaymentArgs}; impl EthCoin { diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 6ec2613659..fd6b20c80b 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -1238,7 +1238,7 @@ pub struct SendTakerFundingArgs<'a> { } /// Helper struct wrapping arguments for [TakerCoinSwapOpsV2::refund_taker_funding_secret] -pub struct RefundFundingSecretArgs<'a, Coin: CoinAssocTypes + ?Sized> { +pub struct RefundFundingSecretArgs<'a, Coin: ParseCoinAssocTypes + ?Sized> { pub funding_tx: &'a Coin::Tx, pub time_lock: u64, pub maker_pubkey: &'a Coin::Pubkey, @@ -1250,7 +1250,7 @@ pub struct RefundFundingSecretArgs<'a, Coin: CoinAssocTypes + ?Sized> { } /// Helper struct wrapping arguments for [TakerCoinSwapOpsV2::gen_taker_funding_spend_preimage] -pub struct GenTakerFundingSpendArgs<'a, Coin: CoinAssocTypes + ?Sized> { +pub struct GenTakerFundingSpendArgs<'a, Coin: ParseCoinAssocTypes + ?Sized> { /// Taker payment transaction serialized to raw bytes pub funding_tx: &'a Coin::Tx, /// Maker's pubkey @@ -1268,7 +1268,7 @@ pub struct GenTakerFundingSpendArgs<'a, Coin: CoinAssocTypes + ?Sized> { } /// Helper struct wrapping arguments for [TakerCoinSwapOpsV2::validate_taker_funding] -pub struct ValidateTakerFundingArgs<'a, Coin: CoinAssocTypes + ?Sized> { +pub struct ValidateTakerFundingArgs<'a, Coin: ParseCoinAssocTypes + ?Sized> { /// Taker funding transaction pub funding_tx: &'a Coin::Tx, /// Taker will be able to refund the payment after this timestamp @@ -1290,7 +1290,7 @@ pub struct ValidateTakerFundingArgs<'a, Coin: CoinAssocTypes + ?Sized> { /// Helper struct wrapping arguments for taker payment's spend generation, used in /// [TakerCoinSwapOpsV2::gen_taker_payment_spend_preimage], [TakerCoinSwapOpsV2::validate_taker_payment_spend_preimage] and /// [TakerCoinSwapOpsV2::sign_and_broadcast_taker_payment_spend] -pub struct GenTakerPaymentSpendArgs<'a, Coin: CoinAssocTypes + ?Sized> { +pub struct GenTakerPaymentSpendArgs<'a, Coin: ParseCoinAssocTypes + ?Sized> { /// Taker payment transaction serialized to raw bytes pub taker_tx: &'a Coin::Tx, /// Taker will be able to refund the payment after this timestamp @@ -1314,7 +1314,7 @@ pub struct GenTakerPaymentSpendArgs<'a, Coin: CoinAssocTypes + ?Sized> { } /// Taker payment spend preimage with taker's signature -pub struct TxPreimageWithSig { +pub struct TxPreimageWithSig { /// The preimage, might be () for certain coin types (only signature might be used) pub preimage: Coin::Preimage, /// Taker's signature @@ -1437,7 +1437,7 @@ pub trait ToBytes { } /// Defines associated types specific to each coin (Pubkey, Address, etc.) -pub trait CoinAssocTypes { +pub trait ParseCoinAssocTypes { type Address: Send + Sync + fmt::Display; type AddressParseError: fmt::Debug + Send + fmt::Display; type Pubkey: ToBytes + Send + Sync; @@ -1463,7 +1463,7 @@ pub trait CoinAssocTypes { } /// Defines associated types specific to Non-Fungible Tokens (Token Address, Token Id, etc.) -pub trait NftAssocTypes { +pub trait ParseNftAssocTypes { type ContractAddress: Send + Sync + fmt::Display; type TokenId: ToBytes + Send + Sync; type ContractType: ToBytes + Send + Sync; @@ -1479,7 +1479,7 @@ pub trait NftAssocTypes { fn parse_contract_type(&self, contract_type: &[u8]) -> Result; } -pub struct SendMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { +pub struct SendMakerPaymentArgs<'a, Coin: ParseCoinAssocTypes + ?Sized> { /// Maker will be able to refund the payment after this timestamp pub time_lock: u64, /// The hash of the secret generated by taker, this is used for immediate refund @@ -1495,7 +1495,7 @@ pub struct SendMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { } /// Structure representing necessary NFT info for Swap -pub struct NftSwapInfo<'a, Coin: NftAssocTypes + ?Sized> { +pub struct NftSwapInfo<'a, Coin: ParseNftAssocTypes + ?Sized> { /// The address of the NFT token pub token_address: &'a Coin::ContractAddress, /// The ID of the NFT token. @@ -1506,7 +1506,7 @@ pub struct NftSwapInfo<'a, Coin: NftAssocTypes + ?Sized> { pub swap_contract_address: &'a Coin::ContractAddress, } -pub struct SendNftMakerPaymentArgs<'a, Coin: CoinAssocTypes + NftAssocTypes + ?Sized> { +pub struct SendNftMakerPaymentArgs<'a, Coin: ParseCoinAssocTypes + ParseNftAssocTypes + ?Sized> { /// Maker will be able to refund the payment after this timestamp pub time_lock: u64, /// The hash of the secret generated by taker, this is used for immediate refund @@ -1523,7 +1523,7 @@ pub struct SendNftMakerPaymentArgs<'a, Coin: CoinAssocTypes + NftAssocTypes + ?S pub nft_swap_info: &'a NftSwapInfo<'a, Coin>, } -pub struct ValidateMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { +pub struct ValidateMakerPaymentArgs<'a, Coin: ParseCoinAssocTypes + ?Sized> { /// Maker payment tx pub maker_payment_tx: &'a Coin::Tx, /// Maker will be able to refund the payment after this timestamp @@ -1540,7 +1540,7 @@ pub struct ValidateMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { pub swap_unique_data: &'a [u8], } -pub struct ValidateNftMakerPaymentArgs<'a, Coin: CoinAssocTypes + NftAssocTypes + ?Sized> { +pub struct ValidateNftMakerPaymentArgs<'a, Coin: ParseCoinAssocTypes + ParseNftAssocTypes + ?Sized> { /// Maker payment tx pub maker_payment_tx: &'a Coin::Tx, /// Maker will be able to refund the payment after this timestamp @@ -1561,7 +1561,7 @@ pub struct ValidateNftMakerPaymentArgs<'a, Coin: CoinAssocTypes + NftAssocTypes pub nft_swap_info: &'a NftSwapInfo<'a, Coin>, } -pub struct RefundMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { +pub struct RefundMakerPaymentArgs<'a, Coin: ParseCoinAssocTypes + ?Sized> { /// Maker payment tx pub maker_payment_tx: &'a Coin::Tx, /// Maker will be able to refund the payment after this timestamp @@ -1578,7 +1578,7 @@ pub struct RefundMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { pub swap_unique_data: &'a [u8], } -pub struct SpendMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { +pub struct SpendMakerPaymentArgs<'a, Coin: ParseCoinAssocTypes + ?Sized> { /// Maker payment tx pub maker_payment_tx: &'a Coin::Tx, /// Maker will be able to refund the payment after this timestamp @@ -1595,7 +1595,7 @@ pub struct SpendMakerPaymentArgs<'a, Coin: CoinAssocTypes + ?Sized> { pub swap_unique_data: &'a [u8], } -pub struct SpendNftMakerPaymentArgs<'a, Coin: CoinAssocTypes + NftAssocTypes + ?Sized> { +pub struct SpendNftMakerPaymentArgs<'a, Coin: ParseCoinAssocTypes + ParseNftAssocTypes + ?Sized> { /// Maker payment tx pub maker_payment_tx: &'a Coin::Tx, /// Maker will be able to refund the payment after this timestamp @@ -1618,7 +1618,7 @@ pub struct SpendNftMakerPaymentArgs<'a, Coin: CoinAssocTypes + NftAssocTypes + ? /// Operations specific to maker coin in [Trading Protocol Upgrade implementation](https://github.com/KomodoPlatform/komodo-defi-framework/issues/1895) #[async_trait] -pub trait MakerCoinSwapOpsV2: CoinAssocTypes + Send + Sync + 'static { +pub trait MakerCoinSwapOpsV2: ParseCoinAssocTypes + Send + Sync + 'static { /// Generate and broadcast maker payment transaction async fn send_maker_payment_v2(&self, args: SendMakerPaymentArgs<'_, Self>) -> Result; @@ -1639,7 +1639,7 @@ pub trait MakerCoinSwapOpsV2: CoinAssocTypes + Send + Sync + 'static { } #[async_trait] -pub trait MakerNftSwapOpsV2: CoinAssocTypes + NftAssocTypes + Send + Sync + 'static { +pub trait MakerNftSwapOpsV2: ParseCoinAssocTypes + ParseNftAssocTypes + Send + Sync + 'static { async fn send_nft_maker_payment_v2( &self, args: SendNftMakerPaymentArgs<'_, Self>, @@ -1705,8 +1705,8 @@ impl From for WaitForTakerPaymentSpendError { /// Enum representing different ways a funding transaction can be spent. /// -/// This enum is generic over types that implement the `CoinAssocTypes` trait. -pub enum FundingTxSpend { +/// This enum is generic over types that implement the `ParseCoinAssocTypes` trait. +pub enum FundingTxSpend { /// Variant indicating that the funding transaction has been spent through a timelock path. RefundedTimelock(T::Tx), /// Variant indicating that the funding transaction has been spent by revealing a taker's secret (immediate refund path). @@ -1721,7 +1721,7 @@ pub enum FundingTxSpend { TransferredToTakerPayment(T::Tx), } -impl fmt::Debug for FundingTxSpend { +impl fmt::Debug for FundingTxSpend { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { FundingTxSpend::RefundedTimelock(tx) => { @@ -1752,7 +1752,7 @@ pub enum SearchForFundingSpendErr { /// Operations specific to taker coin in [Trading Protocol Upgrade implementation](https://github.com/KomodoPlatform/komodo-defi-framework/issues/1895) #[async_trait] -pub trait TakerCoinSwapOpsV2: CoinAssocTypes + Send + Sync + 'static { +pub trait TakerCoinSwapOpsV2: ParseCoinAssocTypes + Send + Sync + 'static { /// Generate and broadcast taker funding transaction that includes dex fee, maker premium and actual trading volume. /// Funding tx can be reclaimed immediately if maker back-outs (doesn't send maker payment) async fn send_taker_funding(&self, args: SendTakerFundingArgs<'_>) -> Result; diff --git a/mm2src/coins/test_coin.rs b/mm2src/coins/test_coin.rs index 5ac52ef31d..3d7ca55ed5 100644 --- a/mm2src/coins/test_coin.rs +++ b/mm2src/coins/test_coin.rs @@ -4,10 +4,10 @@ use super::{CoinBalance, FundingTxSpend, HistorySyncState, MarketCoinOps, MmCoin RawTransactionRequest, SearchForFundingSpendErr, SwapOps, TradeFee, TransactionEnum, TransactionFut, WaitForTakerPaymentSpendError}; use crate::coin_errors::ValidatePaymentResult; -use crate::{coin_errors::MyAddressError, BalanceFut, CanRefundHtlc, CheckIfMyPaymentSentArgs, CoinAssocTypes, - CoinFutSpawner, ConfirmPaymentInput, FeeApproxStage, FoundSwapTxSpend, GenPreimageResult, - GenTakerFundingSpendArgs, GenTakerPaymentSpendArgs, MakerSwapTakerCoin, MmCoinEnum, - NegotiateSwapContractAddrErr, PaymentInstructionArgs, PaymentInstructions, PaymentInstructionsErr, +use crate::{coin_errors::MyAddressError, BalanceFut, CanRefundHtlc, CheckIfMyPaymentSentArgs, CoinFutSpawner, + ConfirmPaymentInput, FeeApproxStage, FoundSwapTxSpend, GenPreimageResult, GenTakerFundingSpendArgs, + GenTakerPaymentSpendArgs, MakerSwapTakerCoin, MmCoinEnum, NegotiateSwapContractAddrErr, + ParseCoinAssocTypes, PaymentInstructionArgs, PaymentInstructions, PaymentInstructionsErr, RawTransactionResult, RefundFundingSecretArgs, RefundPaymentArgs, RefundResult, SearchForSwapTxSpendInput, SendMakerPaymentSpendPreimageInput, SendPaymentArgs, SendTakerFundingArgs, SignRawTransactionRequest, SignatureResult, SpendPaymentArgs, TakerCoinSwapOpsV2, TakerSwapMakerCoin, TradePreimageFut, @@ -425,7 +425,7 @@ impl ToBytes for TestSig { fn to_bytes(&self) -> Vec { vec![] } } -impl CoinAssocTypes for TestCoin { +impl ParseCoinAssocTypes for TestCoin { type Address = String; type AddressParseError = String; type Pubkey = TestPubkey; diff --git a/mm2src/coins/utxo.rs b/mm2src/coins/utxo.rs index 1bba5184c2..033f496a72 100644 --- a/mm2src/coins/utxo.rs +++ b/mm2src/coins/utxo.rs @@ -114,7 +114,7 @@ use crate::hd_wallet::{HDAccountOps, HDAccountsMutex, HDAddress, HDAddressId, HD InvalidBip44ChainError}; use crate::hd_wallet_storage::{HDAccountStorageItem, HDWalletCoinStorage, HDWalletStorageError, HDWalletStorageResult}; use crate::utxo::tx_cache::UtxoVerboseCacheShared; -use crate::{CoinAssocTypes, ToBytes}; +use crate::{ParseCoinAssocTypes, ToBytes}; pub mod tx_cache; @@ -1048,7 +1048,7 @@ impl ToBytes for Signature { fn to_bytes(&self) -> Vec { self.to_vec() } } -impl CoinAssocTypes for T { +impl ParseCoinAssocTypes for T { type Address = Address; type AddressParseError = MmError; type Pubkey = Public; diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs index 77ce092be1..b21947792a 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap_v2.rs @@ -8,8 +8,8 @@ use crate::mm2::lp_swap::{broadcast_swap_v2_msg_every, check_balance_for_maker_s SwapConfirmationsSettings, TransactionIdentifier, MAKER_SWAP_V2_TYPE, MAX_STARTED_AT_DIFF}; use async_trait::async_trait; use bitcrypto::{dhash160, sha256}; -use coins::{CanRefundHtlc, CoinAssocTypes, ConfirmPaymentInput, DexFee, FeeApproxStage, FundingTxSpend, - GenTakerFundingSpendArgs, GenTakerPaymentSpendArgs, MakerCoinSwapOpsV2, MmCoin, RefundMakerPaymentArgs, +use coins::{CanRefundHtlc, ConfirmPaymentInput, DexFee, FeeApproxStage, FundingTxSpend, GenTakerFundingSpendArgs, + GenTakerPaymentSpendArgs, MakerCoinSwapOpsV2, MmCoin, ParseCoinAssocTypes, RefundMakerPaymentArgs, RefundPaymentArgs, SearchForFundingSpendErr, SendMakerPaymentArgs, SwapTxTypeWithSecretHash, TakerCoinSwapOpsV2, ToBytes, TradePreimageValue, Transaction, TxPreimageWithSig, ValidateTakerFundingArgs}; use common::executor::abortable_queue::AbortableQueue; @@ -1004,7 +1004,7 @@ impl { +struct NegotiationData { taker_payment_locktime: u64, taker_funding_locktime: u64, maker_coin_htlc_pub_from_taker: MakerCoin::Pubkey, @@ -1014,7 +1014,7 @@ struct NegotiationData { taker_secret_hash: Vec, } -impl NegotiationData { +impl NegotiationData { fn to_stored_data(&self) -> StoredNegotiationData { StoredNegotiationData { taker_payment_locktime: self.taker_payment_locktime, @@ -1048,14 +1048,14 @@ impl NegotiationData { +struct WaitingForTakerFunding { maker_coin_start_block: u64, taker_coin_start_block: u64, negotiation_data: NegotiationData, maker_payment_trade_fee: SavedTradeFee, } -impl TransitionFrom> +impl TransitionFrom> for WaitingForTakerFunding { } @@ -1133,7 +1133,7 @@ impl { +struct TakerFundingReceived { maker_coin_start_block: u64, taker_coin_start_block: u64, negotiation_data: NegotiationData, @@ -1141,8 +1141,8 @@ struct TakerFundingReceived TransitionFrom> - for TakerFundingReceived +impl + TransitionFrom> for TakerFundingReceived { } @@ -1245,7 +1245,7 @@ impl { +struct MakerPaymentSentFundingSpendGenerated { maker_coin_start_block: u64, taker_coin_start_block: u64, negotiation_data: NegotiationData, @@ -1254,7 +1254,8 @@ struct MakerPaymentSentFundingSpendGenerated TransitionFrom> +impl + TransitionFrom> for MakerPaymentSentFundingSpendGenerated { } @@ -1414,7 +1415,7 @@ pub enum MakerPaymentRefundReason { ErrorOnTakerFundingSpendSearch(String), } -struct MakerPaymentRefundRequired { +struct MakerPaymentRefundRequired { maker_coin_start_block: u64, taker_coin_start_block: u64, negotiation_data: NegotiationData, @@ -1422,12 +1423,12 @@ struct MakerPaymentRefundRequired +impl TransitionFrom> for MakerPaymentRefundRequired { } -impl +impl TransitionFrom> for MakerPaymentRefundRequired { } @@ -1548,7 +1549,7 @@ impl { +struct TakerPaymentReceived { maker_coin_start_block: u64, taker_coin_start_block: u64, maker_payment: MakerCoin::Tx, @@ -1556,7 +1557,7 @@ struct TakerPaymentReceived, } -impl +impl TransitionFrom> for TakerPaymentReceived { @@ -1728,7 +1729,7 @@ impl { +struct TakerPaymentSpent { maker_coin_start_block: u64, taker_coin_start_block: u64, maker_payment: MakerCoin::Tx, @@ -1736,8 +1737,8 @@ struct TakerPaymentSpent { taker_payment_spend: TakerCoin::Tx, } -impl TransitionFrom> - for TakerPaymentSpent +impl + TransitionFrom> for TakerPaymentSpent { } @@ -1844,15 +1845,15 @@ impl TransitionFrom> for Aborted {} impl TransitionFrom> for Aborted {} -impl TransitionFrom> - for Aborted +impl + TransitionFrom> for Aborted { } -impl TransitionFrom> - for Aborted +impl + TransitionFrom> for Aborted { } -impl +impl TransitionFrom> for Aborted { } @@ -1893,12 +1894,12 @@ impl TransitionFrom> - for Completed +impl + TransitionFrom> for Completed { } -struct MakerPaymentRefunded { +struct MakerPaymentRefunded { taker_coin: PhantomData, maker_payment: MakerCoin::Tx, maker_payment_refund: MakerCoin::Tx, @@ -1942,7 +1943,7 @@ impl +impl TransitionFrom> for MakerPaymentRefunded { } diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs b/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs index ec5c88c0c5..77b34e476f 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap_v2.rs @@ -8,10 +8,11 @@ use crate::mm2::lp_swap::{broadcast_swap_v2_msg_every, check_balance_for_taker_s TAKER_SWAP_V2_TYPE}; use async_trait::async_trait; use bitcrypto::{dhash160, sha256}; -use coins::{CanRefundHtlc, CoinAssocTypes, ConfirmPaymentInput, DexFee, FeeApproxStage, GenTakerFundingSpendArgs, - GenTakerPaymentSpendArgs, MakerCoinSwapOpsV2, MmCoin, RefundFundingSecretArgs, RefundPaymentArgs, - SendTakerFundingArgs, SpendMakerPaymentArgs, SwapTxTypeWithSecretHash, TakerCoinSwapOpsV2, ToBytes, - TradeFee, TradePreimageValue, Transaction, TxPreimageWithSig, ValidateMakerPaymentArgs}; +use coins::{CanRefundHtlc, ConfirmPaymentInput, DexFee, FeeApproxStage, GenTakerFundingSpendArgs, + GenTakerPaymentSpendArgs, MakerCoinSwapOpsV2, MmCoin, ParseCoinAssocTypes, RefundFundingSecretArgs, + RefundPaymentArgs, SendTakerFundingArgs, SpendMakerPaymentArgs, SwapTxTypeWithSecretHash, + TakerCoinSwapOpsV2, ToBytes, TradeFee, TradePreimageValue, Transaction, TxPreimageWithSig, + ValidateMakerPaymentArgs}; use common::executor::abortable_queue::AbortableQueue; use common::executor::{AbortableSystem, Timer}; use common::log::{debug, error, info, warn}; @@ -1153,7 +1154,7 @@ impl { +struct NegotiationData { maker_secret_hash: Vec, maker_payment_locktime: u64, maker_coin_htlc_pub_from_maker: MakerCoin::Pubkey, @@ -1163,7 +1164,7 @@ struct NegotiationData { taker_coin_maker_address: TakerCoin::Address, } -impl NegotiationData { +impl NegotiationData { fn to_stored_data(&self) -> StoredNegotiationData { StoredNegotiationData { maker_payment_locktime: self.maker_payment_locktime, @@ -1199,7 +1200,7 @@ impl NegotiationData { +struct Negotiated { maker_coin_start_block: u64, taker_coin_start_block: u64, negotiation_data: NegotiationData, @@ -1207,7 +1208,7 @@ struct Negotiated { maker_payment_spend_fee: SavedTradeFee, } -impl TransitionFrom> +impl TransitionFrom> for Negotiated { } @@ -1270,7 +1271,7 @@ impl { +struct TakerFundingSent { maker_coin_start_block: u64, taker_coin_start_block: u64, taker_funding: TakerCoin::Tx, @@ -1388,7 +1389,7 @@ impl TransitionFrom> +impl TransitionFrom> for TakerFundingSent { } @@ -1411,7 +1412,7 @@ impl { +struct MakerPaymentAndFundingSpendPreimgReceived { maker_coin_start_block: u64, taker_coin_start_block: u64, negotiation_data: NegotiationData, @@ -1420,7 +1421,8 @@ struct MakerPaymentAndFundingSpendPreimgReceived TransitionFrom> +impl + TransitionFrom> for MakerPaymentAndFundingSpendPreimgReceived { } @@ -1585,7 +1587,7 @@ impl { +struct TakerPaymentSent { maker_coin_start_block: u64, taker_coin_start_block: u64, taker_payment: TakerCoin::Tx, @@ -1593,11 +1595,11 @@ struct TakerPaymentSent { negotiation_data: NegotiationData, } -impl TransitionFrom> - for TakerPaymentSent +impl + TransitionFrom> for TakerPaymentSent { } -impl +impl TransitionFrom> for TakerPaymentSent { @@ -1750,7 +1752,7 @@ pub enum TakerFundingRefundReason { MakerPaymentNotConfirmedInTime(String), } -struct TakerFundingRefundRequired { +struct TakerFundingRefundRequired { maker_coin_start_block: u64, taker_coin_start_block: u64, taker_funding: TakerCoin::Tx, @@ -1758,17 +1760,17 @@ struct TakerFundingRefundRequired TransitionFrom> - for TakerFundingRefundRequired +impl + TransitionFrom> for TakerFundingRefundRequired { } -impl +impl TransitionFrom> for TakerFundingRefundRequired { } -impl TransitionFrom> - for TakerFundingRefundRequired +impl + TransitionFrom> for TakerFundingRefundRequired { } @@ -1842,18 +1844,18 @@ pub enum TakerPaymentRefundReason { MakerDidNotSpendInTime(String), } -struct TakerPaymentRefundRequired { +struct TakerPaymentRefundRequired { taker_payment: TakerCoin::Tx, negotiation_data: NegotiationData, reason: TakerPaymentRefundReason, } -impl TransitionFrom> - for TakerPaymentRefundRequired +impl + TransitionFrom> for TakerPaymentRefundRequired { } -impl TransitionFrom> - for TakerPaymentRefundRequired +impl + TransitionFrom> for TakerPaymentRefundRequired { } @@ -1939,7 +1941,7 @@ impl { +struct MakerPaymentConfirmed { maker_coin_start_block: u64, taker_coin_start_block: u64, maker_payment: MakerCoin::Tx, @@ -1948,7 +1950,7 @@ struct MakerPaymentConfirmed, } -impl +impl TransitionFrom> for MakerPaymentConfirmed { @@ -2035,7 +2037,7 @@ impl { +struct TakerPaymentSpent { maker_coin_start_block: u64, taker_coin_start_block: u64, maker_payment: MakerCoin::Tx, @@ -2044,8 +2046,8 @@ struct TakerPaymentSpent { negotiation_data: NegotiationData, } -impl TransitionFrom> - for TakerPaymentSpent +impl + TransitionFrom> for TakerPaymentSpent { } @@ -2134,7 +2136,7 @@ impl { +struct MakerPaymentSpent { maker_coin_start_block: u64, taker_coin_start_block: u64, maker_payment: MakerCoin::Tx, @@ -2143,8 +2145,8 @@ struct MakerPaymentSpent { maker_payment_spend: MakerCoin::Tx, } -impl TransitionFrom> - for MakerPaymentSpent +impl + TransitionFrom> for MakerPaymentSpent { } @@ -2255,19 +2257,19 @@ impl TransitionFrom> for Aborted {} impl TransitionFrom> for Aborted {} -impl TransitionFrom> +impl TransitionFrom> for Aborted { } -impl TransitionFrom> - for Aborted +impl + TransitionFrom> for Aborted { } -impl +impl TransitionFrom> for Aborted { } -impl +impl TransitionFrom> for Aborted { } @@ -2308,12 +2310,12 @@ impl TransitionFrom> - for Completed +impl + TransitionFrom> for Completed { } -struct TakerFundingRefunded { +struct TakerFundingRefunded { maker_coin: PhantomData, funding_tx: TakerCoin::Tx, funding_refund_tx: TakerCoin::Tx, @@ -2357,12 +2359,12 @@ impl +impl TransitionFrom> for TakerFundingRefunded { } -struct TakerPaymentRefunded { +struct TakerPaymentRefunded { maker_coin: PhantomData, taker_payment: TakerCoin::Tx, taker_payment_refund: TransactionIdentifier, @@ -2403,7 +2405,7 @@ impl +impl TransitionFrom> for TakerPaymentRefunded { } diff --git a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs index e00ef6f568..a8125ef3b0 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -5,10 +5,10 @@ use super::docker_tests_common::{random_secp256k1_secret, ERC1155_TEST_ABI, ERC7 use bitcrypto::{dhash160, sha256}; use coins::eth::{checksum_address, eth_addr_to_hex, eth_coin_from_conf_and_request, EthCoin, ERC20_ABI}; use coins::nft::nft_structs::{Chain, ContractType, NftInfo}; -use coins::{CoinAssocTypes, CoinProtocol, ConfirmPaymentInput, FoundSwapTxSpend, MakerNftSwapOpsV2, MarketCoinOps, - NftSwapInfo, PrivKeyBuildPolicy, RefundPaymentArgs, SearchForSwapTxSpendInput, SendNftMakerPaymentArgs, - SendPaymentArgs, SpendNftMakerPaymentArgs, SpendPaymentArgs, SwapOps, SwapTxTypeWithSecretHash, ToBytes, - Transaction, ValidateNftMakerPaymentArgs}; +use coins::{CoinProtocol, ConfirmPaymentInput, FoundSwapTxSpend, MakerNftSwapOpsV2, MarketCoinOps, NftSwapInfo, + ParseCoinAssocTypes, PrivKeyBuildPolicy, RefundPaymentArgs, SearchForSwapTxSpendInput, + SendNftMakerPaymentArgs, SendPaymentArgs, SpendNftMakerPaymentArgs, SpendPaymentArgs, SwapOps, + SwapTxTypeWithSecretHash, ToBytes, Transaction, ValidateNftMakerPaymentArgs}; use common::{block_on, now_sec}; use ethereum_types::U256; use futures01::Future; diff --git a/mm2src/mm2_main/tests/docker_tests/swap_proto_v2_tests.rs b/mm2src/mm2_main/tests/docker_tests/swap_proto_v2_tests.rs index 202d6697f6..0dbadb9cb4 100644 --- a/mm2src/mm2_main/tests/docker_tests/swap_proto_v2_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/swap_proto_v2_tests.rs @@ -1,11 +1,10 @@ use crate::{generate_utxo_coin_with_random_privkey, MYCOIN, MYCOIN1}; use bitcrypto::dhash160; use coins::utxo::UtxoCommonOps; -use coins::{CoinAssocTypes, ConfirmPaymentInput, DexFee, FundingTxSpend, GenTakerFundingSpendArgs, - GenTakerPaymentSpendArgs, MakerCoinSwapOpsV2, MarketCoinOps, RefundFundingSecretArgs, - RefundMakerPaymentArgs, RefundPaymentArgs, SendMakerPaymentArgs, SendTakerFundingArgs, - SwapTxTypeWithSecretHash, TakerCoinSwapOpsV2, Transaction, ValidateMakerPaymentArgs, - ValidateTakerFundingArgs}; +use coins::{ConfirmPaymentInput, DexFee, FundingTxSpend, GenTakerFundingSpendArgs, GenTakerPaymentSpendArgs, + MakerCoinSwapOpsV2, MarketCoinOps, ParseCoinAssocTypes, RefundFundingSecretArgs, RefundMakerPaymentArgs, + RefundPaymentArgs, SendMakerPaymentArgs, SendTakerFundingArgs, SwapTxTypeWithSecretHash, + TakerCoinSwapOpsV2, Transaction, ValidateMakerPaymentArgs, ValidateTakerFundingArgs}; use common::{block_on, now_sec, DEX_FEE_ADDR_RAW_PUBKEY}; use futures01::Future; use mm2_number::MmNumber;