diff --git a/mm2src/coins/eth.rs b/mm2src/coins/eth.rs index a61e4f4384..b5f5b0ecde 100644 --- a/mm2src/coins/eth.rs +++ b/mm2src/coins/eth.rs @@ -79,7 +79,7 @@ use instant::Instant; use keys::Public as HtlcPubKey; use mm2_core::mm_ctx::{MmArc, MmWeak}; use mm2_event_stream::behaviour::{EventBehaviour, EventInitStatus}; -use mm2_net::transport::{GuiAuthValidation, GuiAuthValidationGenerator}; +use mm2_net::transport::{KomodefiProxyAuthValidation, ProxyAuthValidationGenerator}; use mm2_number::bigdecimal_custom::CheckedDivision; use mm2_number::{BigDecimal, BigUint, MmNumber}; #[cfg(test)] use mocktopus::macros::*; @@ -172,6 +172,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"); +const NFT_MAKER_SWAP_V2_ABI: &str = include_str!("eth/nft_maker_swap_v2_abi.json"); /// Payment states from etomic swap smart contract: https://github.com/artemii235/etomic-swap/blob/master/contracts/EtomicSwap.sol#L5 pub enum PaymentState { @@ -289,8 +290,8 @@ impl Default for EthGasLimit { } } -/// Lifetime of generated signed message for gui-auth requests -const GUI_AUTH_SIGNED_MESSAGE_LIFETIME_SEC: i64 = 90; +/// Lifetime of generated signed message for proxy-auth requests +const PROXY_AUTH_SIGNED_MESSAGE_LIFETIME_SEC: i64 = 90; /// Max transaction type according to EIP-2718 const ETH_MAX_TX_TYPE: u64 = 0x7f; @@ -301,6 +302,7 @@ lazy_static! { 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 static ref NFT_MAKER_SWAP_V2: Contract = Contract::load(NFT_MAKER_SWAP_V2_ABI.as_bytes()).unwrap(); } pub type EthDerivationMethod = DerivationMethod; @@ -639,7 +641,7 @@ pub(crate) enum FeeEstimatorState { pub struct EthCoinImpl { ticker: String, pub coin_type: EthCoinType, - priv_key_policy: EthPrivKeyPolicy, + pub(crate) priv_key_policy: EthPrivKeyPolicy, /// Either an Iguana address or a 'EthHDWallet' instance. /// Arc is used to use the same hd wallet from platform coin if we need to. /// This allows the reuse of the same derived accounts/addresses of the @@ -3593,7 +3595,7 @@ impl EthCoin { impl EthCoin { /// Sign and send eth transaction. /// This function is primarily for swap transactions so internally it relies on the swap tx fee policy - pub(crate) fn sign_and_send_transaction(&self, value: U256, action: Action, data: Vec, gas: U256) -> EthTxFut { + pub fn sign_and_send_transaction(&self, value: U256, action: Action, data: Vec, gas: U256) -> EthTxFut { let coin = self.clone(); let fut = async move { match coin.priv_key_policy { @@ -5776,14 +5778,15 @@ impl TryToAddress for Option { } } -pub trait GuiAuthMessages { - fn gui_auth_sign_message_hash(message: String) -> Option<[u8; 32]>; - fn generate_gui_auth_signed_validation(generator: GuiAuthValidationGenerator) - -> SignatureResult; +pub trait KomodoDefiAuthMessages { + fn proxy_auth_sign_message_hash(message: String) -> Option<[u8; 32]>; + fn generate_proxy_auth_signed_validation( + generator: ProxyAuthValidationGenerator, + ) -> SignatureResult; } -impl GuiAuthMessages for EthCoin { - fn gui_auth_sign_message_hash(message: String) -> Option<[u8; 32]> { +impl KomodoDefiAuthMessages for EthCoin { + fn proxy_auth_sign_message_hash(message: String) -> Option<[u8; 32]> { let message_prefix = "atomicDEX Auth Ethereum Signed Message:\n"; let prefix_len = CompactInteger::from(message_prefix.len()); @@ -5796,16 +5799,16 @@ impl GuiAuthMessages for EthCoin { Some(keccak256(&stream.out()).take()) } - fn generate_gui_auth_signed_validation( - generator: GuiAuthValidationGenerator, - ) -> SignatureResult { - let timestamp_message = get_utc_timestamp() + GUI_AUTH_SIGNED_MESSAGE_LIFETIME_SEC; + fn generate_proxy_auth_signed_validation( + generator: ProxyAuthValidationGenerator, + ) -> SignatureResult { + let timestamp_message = get_utc_timestamp() + PROXY_AUTH_SIGNED_MESSAGE_LIFETIME_SEC; - let message_hash = - EthCoin::gui_auth_sign_message_hash(timestamp_message.to_string()).ok_or(SignatureError::PrefixNotFound)?; + let message_hash = EthCoin::proxy_auth_sign_message_hash(timestamp_message.to_string()) + .ok_or(SignatureError::PrefixNotFound)?; let signature = sign(&generator.secret, &H256::from(message_hash))?; - Ok(GuiAuthValidation { + Ok(KomodefiProxyAuthValidation { coin_ticker: generator.coin_ticker, address: generator.address, timestamp_message, diff --git a/mm2src/coins/eth/nft_maker_swap_v2_abi.json b/mm2src/coins/eth/nft_maker_swap_v2_abi.json new file mode 100644 index 0000000000..95def23766 --- /dev/null +++ b/mm2src/coins/eth/nft_maker_swap_v2_abi.json @@ -0,0 +1,462 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "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" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "makerPayments", + "outputs": [ + { + "internalType": "bytes20", + "name": "paymentHash", + "type": "bytes20" + }, + { + "internalType": "uint32", + "name": "paymentLockTime", + "type": "uint32" + }, + { + "internalType": "enum EtomicSwapMakerNftV2.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": "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" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "refundErc1155MakerPaymentSecret", + "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" + }, + { + "internalType": "uint256", + "name": "amount", + "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": "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" + }, + { + "internalType": "uint256", + "name": "amount", + "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": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/mm2src/coins/eth/nft_swap_v2/mod.rs b/mm2src/coins/eth/nft_swap_v2/mod.rs index 9e6afcbbcd..19f5caca7f 100644 --- a/mm2src/coins/eth/nft_swap_v2/mod.rs +++ b/mm2src/coins/eth/nft_swap_v2/mod.rs @@ -15,7 +15,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, NFT_SWAP_CONTRACT}; + TryToAddress, ERC1155_CONTRACT, ERC721_CONTRACT, NFT_MAKER_SWAP_V2}; use crate::{ParseCoinAssocTypes, RefundPaymentArgs, SendNftMakerPaymentArgs, SpendNftMakerPaymentArgs, TransactionErr, ValidateNftMakerPaymentArgs}; @@ -74,7 +74,7 @@ impl EthCoin { .payment_status_v2( *etomic_swap_contract, Token::FixedBytes(swap_id.clone()), - &NFT_SWAP_CONTRACT, + &NFT_MAKER_SWAP_V2, PaymentType::MakerPayments, ) .await?; @@ -144,7 +144,7 @@ impl EthCoin { let (state, htlc_params) = try_tx_s!( self.status_and_htlc_params_from_tx_data( *etomic_swap_contract, - &NFT_SWAP_CONTRACT, + &NFT_MAKER_SWAP_V2, &decoded, index_bytes, PaymentType::MakerPayments, @@ -269,8 +269,8 @@ impl EthCoin { state: U256, ) -> Result, PrepareTxDataError> { let spend_func = match args.contract_type { - ContractType::Erc1155 => NFT_SWAP_CONTRACT.function("spendErc1155MakerPayment")?, - ContractType::Erc721 => NFT_SWAP_CONTRACT.function("spendErc721MakerPayment")?, + ContractType::Erc1155 => NFT_MAKER_SWAP_V2.function("spendErc1155MakerPayment")?, + ContractType::Erc721 => NFT_MAKER_SWAP_V2.function("spendErc721MakerPayment")?, }; if state != U256::from(MakerPaymentStateV2::PaymentSent as u8) { diff --git a/mm2src/coins/eth/v2_activation.rs b/mm2src/coins/eth/v2_activation.rs index 2cf680b66f..e8bb6cebeb 100644 --- a/mm2src/coins/eth/v2_activation.rs +++ b/mm2src/coins/eth/v2_activation.rs @@ -89,6 +89,7 @@ impl From for EthActivationV2Error { EthTokenActivationError::UnexpectedDerivationMethod(err) => { EthActivationV2Error::UnexpectedDerivationMethod(err) }, + EthTokenActivationError::PrivKeyPolicyNotAllowed(e) => EthActivationV2Error::PrivKeyPolicyNotAllowed(e), } } } @@ -204,6 +205,7 @@ pub enum EthTokenActivationError { InvalidPayload(String), Transport(String), UnexpectedDerivationMethod(UnexpectedDerivationMethod), + PrivKeyPolicyNotAllowed(PrivKeyPolicyNotAllowed), } impl From for EthTokenActivationError { @@ -254,6 +256,36 @@ impl From for EthTokenActivationError { fn from(e: String) -> Self { EthTokenActivationError::InternalError(e) } } +impl From for EthTokenActivationError { + fn from(e: PrivKeyPolicyNotAllowed) -> Self { EthTokenActivationError::PrivKeyPolicyNotAllowed(e) } +} + +impl From for EthTokenActivationError { + fn from(e: GenerateSignedMessageError) -> Self { + match e { + GenerateSignedMessageError::InternalError(e) => EthTokenActivationError::InternalError(e), + GenerateSignedMessageError::PrivKeyPolicyNotAllowed(e) => { + EthTokenActivationError::PrivKeyPolicyNotAllowed(e) + }, + } + } +} + +#[derive(Display, Serialize)] +pub enum GenerateSignedMessageError { + #[display(fmt = "Internal: {}", _0)] + InternalError(String), + PrivKeyPolicyNotAllowed(PrivKeyPolicyNotAllowed), +} + +impl From for GenerateSignedMessageError { + fn from(e: PrivKeyPolicyNotAllowed) -> Self { GenerateSignedMessageError::PrivKeyPolicyNotAllowed(e) } +} + +impl From for GenerateSignedMessageError { + fn from(e: SignatureError) -> Self { GenerateSignedMessageError::InternalError(e.to_string()) } +} + /// Represents the parameters required for activating either an ERC-20 token or an NFT on the Ethereum platform. #[derive(Clone, Deserialize)] #[serde(untagged)] @@ -300,7 +332,11 @@ pub struct NftActivationRequest { #[derive(Clone, Deserialize)] #[serde(tag = "type", content = "info")] pub enum NftProviderEnum { - Moralis { url: Url }, + Moralis { + url: Url, + #[serde(default)] + proxy_auth: bool, + }, } /// Represents the protocol type for an Ethereum-based token, distinguishing between ERC-20 tokens and NFTs. @@ -368,7 +404,7 @@ impl EthCoin { .iter() .map(|node| { let mut transport = node.web3.transport().clone(); - if let Some(auth) = transport.gui_auth_validation_generator_as_mut() { + if let Some(auth) = transport.proxy_auth_validation_generator_as_mut() { auth.coin_ticker = ticker.clone(); } let web3 = Web3::new(transport); @@ -438,7 +474,11 @@ impl EthCoin { /// It fetches NFT details from a given URL to populate the `nfts_infos` field, which stores information about the user's NFTs. /// /// This setup allows the Global NFT to function like a coin, supporting swap operations and providing easy access to NFT details via `nfts_infos`. - pub async fn global_nft_from_platform_coin(&self, url: &Url) -> MmResult { + pub async fn global_nft_from_platform_coin( + &self, + original_url: &Url, + proxy_auth: &bool, + ) -> MmResult { let chain = Chain::from_ticker(self.ticker())?; let ticker = chain.to_nft_ticker().to_string(); @@ -454,7 +494,12 @@ impl EthCoin { // Todo: support HD wallet for NFTs, currently we get nfts for enabled address only and there might be some issues when activating NFTs while ETH is activated with HD wallet let my_address = self.derivation_method.single_addr_or_err().await?; - let nft_infos = get_nfts_for_activation(&chain, &my_address, url).await?; + + let my_address_str = display_eth_address(&my_address); + let signed_message = + generate_signed_message(*proxy_auth, &chain, my_address_str, self.priv_key_policy()).await?; + + let nft_infos = get_nfts_for_activation(&chain, &my_address, original_url, signed_message.as_ref()).await?; let coin_type = EthCoinType::Nft { platform: self.ticker.clone(), }; @@ -493,6 +538,28 @@ impl EthCoin { } } +pub(crate) async fn generate_signed_message( + proxy_auth: bool, + chain: &Chain, + my_address: String, + priv_key_policy: &EthPrivKeyPolicy, +) -> MmResult, GenerateSignedMessageError> { + if !proxy_auth { + return Ok(None); + } + + let secret = priv_key_policy.activated_key_or_err()?.secret().clone(); + let validation_generator = ProxyAuthValidationGenerator { + coin_ticker: chain.to_nft_ticker().to_string(), + secret, + address: my_address, + }; + + let signed_message = EthCoin::generate_proxy_auth_signed_validation(validation_generator)?; + + Ok(Some(signed_message)) +} + /// Activate eth coin from coin config and private key build policy, /// version 2 of the activation function, with no intrinsic tokens creation pub async fn eth_coin_from_conf_and_request_v2( @@ -776,7 +843,7 @@ async fn build_web3_instances( let mut websocket_transport = WebsocketTransport::with_event_handlers(node, event_handlers.clone()); if eth_node.gui_auth { - websocket_transport.gui_auth_validation_generator = Some(GuiAuthValidationGenerator { + websocket_transport.proxy_auth_validation_generator = Some(ProxyAuthValidationGenerator { coin_ticker: coin_ticker.clone(), secret: key_pair.secret().clone(), address: address.clone(), @@ -852,7 +919,7 @@ fn build_http_transport( let mut http_transport = HttpTransport::with_event_handlers(node, event_handlers); if gui_auth { - http_transport.gui_auth_validation_generator = Some(GuiAuthValidationGenerator { + http_transport.proxy_auth_validation_generator = Some(ProxyAuthValidationGenerator { coin_ticker, secret: key_pair.secret().clone(), address, diff --git a/mm2src/coins/eth/web3_transport/http_transport.rs b/mm2src/coins/eth/web3_transport/http_transport.rs index e722b16824..463e2455fa 100644 --- a/mm2src/coins/eth/web3_transport/http_transport.rs +++ b/mm2src/coins/eth/web3_transport/http_transport.rs @@ -1,9 +1,9 @@ -use crate::eth::web3_transport::handle_gui_auth_payload; +use crate::eth::web3_transport::handle_quicknode_payload; use crate::eth::{web3_transport::Web3SendOut, RpcTransportEventHandler, RpcTransportEventHandlerShared, Web3RpcError}; use common::APPLICATION_JSON; use http::header::CONTENT_TYPE; use jsonrpc_core::{Call, Response}; -use mm2_net::transport::{GuiAuthValidation, GuiAuthValidationGenerator}; +use mm2_net::transport::{KomodefiProxyAuthValidation, ProxyAuthValidationGenerator}; use serde_json::Value as Json; use std::ops::Deref; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; @@ -13,10 +13,10 @@ use web3::helpers::{build_request, to_result_from_output, to_string}; use web3::{RequestId, Transport}; #[derive(Clone, Serialize)] -pub struct AuthPayload<'a> { +pub struct QuicknodePayload<'a> { #[serde(flatten)] pub request: &'a Call, - pub signed_message: GuiAuthValidation, + pub signed_message: KomodefiProxyAuthValidation, } /// Deserialize bytes RPC response into `Result`. @@ -46,7 +46,7 @@ pub struct HttpTransport { pub(crate) last_request_failed: Arc, node: HttpTransportNode, event_handlers: Vec, - pub(crate) gui_auth_validation_generator: Option, + pub(crate) proxy_auth_validation_generator: Option, } #[derive(Clone, Debug)] @@ -63,7 +63,7 @@ impl HttpTransport { id: Arc::new(AtomicUsize::new(0)), node, event_handlers: Default::default(), - gui_auth_validation_generator: None, + proxy_auth_validation_generator: None, last_request_failed: Arc::new(AtomicBool::new(false)), } } @@ -74,7 +74,7 @@ impl HttpTransport { id: Arc::new(AtomicUsize::new(0)), node, event_handlers, - gui_auth_validation_generator: None, + proxy_auth_validation_generator: None, last_request_failed: Arc::new(AtomicBool::new(false)), } } @@ -111,7 +111,7 @@ async fn send_request(request: Call, transport: HttpTransport) -> Result serialized_request = r, Err(e) => { return Err(request_failed_error(request, e)); @@ -187,7 +187,7 @@ async fn send_request(request: Call, transport: HttpTransport) -> Result serialized_request = r, Err(e) => { return Err(request_failed_error( diff --git a/mm2src/coins/eth/web3_transport/mod.rs b/mm2src/coins/eth/web3_transport/mod.rs index dcbdf6ef90..421c9349a8 100644 --- a/mm2src/coins/eth/web3_transport/mod.rs +++ b/mm2src/coins/eth/web3_transport/mod.rs @@ -2,15 +2,15 @@ use ethereum_types::U256; use futures::future::BoxFuture; use jsonrpc_core::Call; #[cfg(target_arch = "wasm32")] use mm2_metamask::MetamaskResult; -use mm2_net::transport::GuiAuthValidationGenerator; +use mm2_net::transport::ProxyAuthValidationGenerator; use serde_json::Value as Json; use serde_json::Value; use std::sync::atomic::Ordering; use web3::helpers::to_string; use web3::{Error, RequestId, Transport}; -use self::http_transport::AuthPayload; -use super::{EthCoin, GuiAuthMessages, Web3RpcError}; +use self::http_transport::QuicknodePayload; +use super::{EthCoin, KomodoDefiAuthMessages, Web3RpcError}; use crate::RpcTransportEventHandlerShared; pub(crate) mod http_transport; @@ -67,10 +67,10 @@ impl Web3Transport { http_transport::HttpTransport::new(node).into() } - pub fn gui_auth_validation_generator_as_mut(&mut self) -> Option<&mut GuiAuthValidationGenerator> { + pub fn proxy_auth_validation_generator_as_mut(&mut self) -> Option<&mut ProxyAuthValidationGenerator> { match self { - Web3Transport::Http(http) => http.gui_auth_validation_generator.as_mut(), - Web3Transport::Websocket(websocket) => websocket.gui_auth_validation_generator.as_mut(), + Web3Transport::Http(http) => http.proxy_auth_validation_generator.as_mut(), + Web3Transport::Websocket(websocket) => websocket.proxy_auth_validation_generator.as_mut(), #[cfg(target_arch = "wasm32")] Web3Transport::Metamask(_) => None, } @@ -135,30 +135,22 @@ pub struct FeeHistoryResult { } /// Generates a signed message and inserts it into the request payload. -pub(super) fn handle_gui_auth_payload( - gui_auth_validation_generator: &Option, +pub(super) fn handle_quicknode_payload( + proxy_auth_validation_generator: &Option, request: &Call, ) -> Result { - let generator = match gui_auth_validation_generator.clone() { - Some(gen) => gen, - None => { - return Err(Web3RpcError::Internal( - "GuiAuthValidationGenerator is not provided for".to_string(), - )); - }, - }; - - let signed_message = match EthCoin::generate_gui_auth_signed_validation(generator) { - Ok(t) => t, - Err(e) => { - return Err(Web3RpcError::Internal(format!( - "GuiAuth signed message generation failed. Error: {:?}", - e - ))); - }, - }; - - let auth_request = AuthPayload { + let generator = proxy_auth_validation_generator + .clone() + .ok_or_else(|| Web3RpcError::Internal("ProxyAuthValidationGenerator is not provided for".to_string()))?; + + let signed_message = EthCoin::generate_proxy_auth_signed_validation(generator).map_err(|e| { + Web3RpcError::Internal(format!( + "KomodefiProxyAuthValidation signed message generation failed. Error: {:?}", + e + )) + })?; + + let auth_request = QuicknodePayload { request, signed_message, }; diff --git a/mm2src/coins/eth/web3_transport/websocket_transport.rs b/mm2src/coins/eth/web3_transport/websocket_transport.rs index f458aacc67..951ed4d2c6 100644 --- a/mm2src/coins/eth/web3_transport/websocket_transport.rs +++ b/mm2src/coins/eth/web3_transport/websocket_transport.rs @@ -5,7 +5,7 @@ //! less bandwidth. This efficiency is achieved by avoiding the handling of TCP handshakes (connection reusability) //! for each request. -use super::handle_gui_auth_payload; +use super::handle_quicknode_payload; use super::http_transport::de_rpc_response; use crate::eth::eth_rpc::ETH_RPC_REQUEST_TIMEOUT; use crate::eth::web3_transport::Web3SendOut; @@ -21,7 +21,7 @@ use futures_ticker::Ticker; use futures_util::{FutureExt, SinkExt, StreamExt}; use instant::{Duration, Instant}; use jsonrpc_core::Call; -use mm2_net::transport::GuiAuthValidationGenerator; +use mm2_net::transport::ProxyAuthValidationGenerator; use std::sync::atomic::AtomicBool; use std::sync::{atomic::{AtomicUsize, Ordering}, Arc}; @@ -46,7 +46,7 @@ pub struct WebsocketTransport { pub(crate) last_request_failed: Arc, node: WebsocketTransportNode, event_handlers: Vec, - pub(crate) gui_auth_validation_generator: Option, + pub(crate) proxy_auth_validation_generator: Option, controller_channel: Arc, connection_guard: Arc>, } @@ -93,7 +93,7 @@ impl WebsocketTransport { } .into(), connection_guard: Arc::new(AsyncMutex::new(())), - gui_auth_validation_generator: None, + proxy_auth_validation_generator: None, last_request_failed: Arc::new(AtomicBool::new(false)), } } @@ -343,7 +343,7 @@ async fn send_request( let mut serialized_request = to_string(&request); if transport.node.gui_auth { - match handle_gui_auth_payload(&transport.gui_auth_validation_generator, &request) { + match handle_quicknode_payload(&transport.proxy_auth_validation_generator, &request) { Ok(r) => serialized_request = r, Err(e) => { return Err(Error::Transport(TransportError::Message(format!( diff --git a/mm2src/coins/lp_coins.rs b/mm2src/coins/lp_coins.rs index 6d0e82c756..653237585b 100644 --- a/mm2src/coins/lp_coins.rs +++ b/mm2src/coins/lp_coins.rs @@ -56,7 +56,7 @@ use derive_more::Display; use enum_derives::{EnumFromStringify, EnumFromTrait}; use ethereum_types::H256; use futures::compat::Future01CompatExt; -use futures::lock::Mutex as AsyncMutex; +use futures::lock::{Mutex as AsyncMutex, MutexGuard as AsyncMutexGuard}; use futures::{FutureExt, TryFutureExt}; use futures01::Future; use hex::FromHexError; @@ -3561,7 +3561,7 @@ pub struct MmCoinStruct { } impl MmCoinStruct { - fn new(coin: MmCoinEnum) -> Self { + pub fn new(coin: MmCoinEnum) -> Self { Self { inner: coin, is_available: AtomicBool::new(true).into(), @@ -3834,6 +3834,9 @@ impl CoinsContext { async fn tx_history_db(&self) -> TxHistoryResult> { Ok(self.tx_history_db.get_or_initialize().await?) } + + #[inline(always)] + pub async fn lock_coins(&self) -> AsyncMutexGuard> { self.coins.lock().await } } /// This enum is used in coin activation requests. diff --git a/mm2src/coins/nft.rs b/mm2src/coins/nft.rs index 7002f97fbf..4d432235a9 100644 --- a/mm2src/coins/nft.rs +++ b/mm2src/coins/nft.rs @@ -23,12 +23,13 @@ use crate::nft::nft_structs::{build_nft_with_empty_meta, BuildNftFields, ClearNf NftTransferCommon, PhishingDomainReq, PhishingDomainRes, RefreshMetadataReq, SpamContractReq, SpamContractRes, TransferMeta, TransferStatus, UriMeta}; use crate::nft::storage::{NftListStorageOps, NftTransferHistoryStorageOps}; +use common::log::error; use common::parse_rfc3339_to_timestamp; use ethereum_types::{Address, H256}; use futures::compat::Future01CompatExt; use futures::future::try_join_all; use mm2_err_handle::map_to_mm::MapToMmResult; -use mm2_net::transport::send_post_request_to_uri; +use mm2_net::transport::{send_post_request_to_uri, KomodefiProxyAuthValidation}; use mm2_number::BigUint; use regex::Regex; use serde::Deserialize; @@ -41,10 +42,12 @@ use web3::types::TransactionId; #[cfg(not(target_arch = "wasm32"))] use mm2_net::native_http::send_request_to_uri; +use crate::eth::v2_activation::generate_signed_message; #[cfg(target_arch = "wasm32")] use mm2_net::wasm::http::send_request_to_uri; -const MORALIS_API_ENDPOINT: &str = "api/v2"; +const MORALIS_API: &str = "api"; +const MORALIS_ENDPOINT_V: &str = "v2"; /// query parameters for moralis request: The format of the token ID const MORALIS_FORMAT_QUERY_NAME: &str = "format"; const MORALIS_FORMAT_QUERY_VALUE: &str = "decimal"; @@ -224,6 +227,7 @@ pub async fn update_nft(ctx: MmArc, req: UpdateNftReq) -> MmResult<(), UpdateNft NftTransferHistoryStorageOps::init(&storage, chain).await?; None }; + // TODO activate and use global NFT instead of ETH coin after adding enable nft using coin conf support let coin_enum = lp_coinfind_or_err(&ctx, chain.to_ticker()).await?; let eth_coin = match coin_enum { MmCoinEnum::EthCoin(eth_coin) => eth_coin, @@ -233,26 +237,36 @@ pub async fn update_nft(ctx: MmArc, req: UpdateNftReq) -> MmResult<(), UpdateNft }) }, }; - let nft_transfers = get_moralis_nft_transfers(&ctx, chain, from_block, &req.url, eth_coin).await?; + let my_address = eth_coin.my_address()?; + let signed_message = + generate_signed_message(req.proxy_auth, chain, my_address, ð_coin.priv_key_policy).await?; + let wrapper = UrlSignWrapper { + chain, + orig_url: &req.url, + url_antispam: &req.url_antispam, + signed_message: signed_message.as_ref(), + }; + + let nft_transfers = get_moralis_nft_transfers(&ctx, from_block, eth_coin, &wrapper).await?; storage.add_transfers_to_history(*chain, nft_transfers).await?; let nft_block = match NftListStorageOps::get_last_block_number(&storage, chain).await { Ok(Some(block)) => block, Ok(None) => { // if there are no rows in NFT LIST table we can try to get nft list from moralis. - let nft_list = cache_nfts_from_moralis(&ctx, &storage, chain, &req.url, &req.url_antispam).await?; + let nft_list = cache_nfts_from_moralis(&ctx, &storage, &wrapper).await?; update_meta_in_transfers(&storage, chain, nft_list).await?; - update_transfers_with_empty_meta(&storage, chain, &req.url, &req.url_antispam).await?; + update_transfers_with_empty_meta(&storage, &wrapper).await?; update_spam(&storage, *chain, &req.url_antispam).await?; update_phishing(&storage, chain, &req.url_antispam).await?; continue; }, Err(_) => { - // if there is an error, then NFT LIST table doesnt exist, so we need to cache nft list from moralis. + // if there is an error, then NFT LIST table doesn't exist, so we need to cache nft list from moralis. NftListStorageOps::init(&storage, chain).await?; - let nft_list = cache_nfts_from_moralis(&ctx, &storage, chain, &req.url, &req.url_antispam).await?; + let nft_list = cache_nfts_from_moralis(&ctx, &storage, &wrapper).await?; update_meta_in_transfers(&storage, chain, nft_list).await?; - update_transfers_with_empty_meta(&storage, chain, &req.url, &req.url_antispam).await?; + update_transfers_with_empty_meta(&storage, &wrapper).await?; update_spam(&storage, *chain, &req.url_antispam).await?; update_phishing(&storage, chain, &req.url_antispam).await?; continue; @@ -273,17 +287,9 @@ pub async fn update_nft(ctx: MmArc, req: UpdateNftReq) -> MmResult<(), UpdateNft last_nft_block: nft_block.to_string(), }); } - update_nft_list( - ctx.clone(), - &storage, - chain, - scanned_block + 1, - &req.url, - &req.url_antispam, - ) - .await?; + update_nft_list(ctx.clone(), &storage, scanned_block + 1, &wrapper).await?; update_nft_global_in_coins_ctx(&ctx, &storage, *chain).await?; - update_transfers_with_empty_meta(&storage, chain, &req.url, &req.url_antispam).await?; + update_transfers_with_empty_meta(&storage, &wrapper).await?; update_spam(&storage, *chain, &req.url_antispam).await?; update_phishing(&storage, chain, &req.url_antispam).await?; } @@ -299,7 +305,7 @@ where T: NftListStorageOps + NftTransferHistoryStorageOps, { let coins_ctx = CoinsContext::from_ctx(ctx).map_to_mm(UpdateNftError::Internal)?; - let mut coins = coins_ctx.coins.lock().await; + let mut coins = coins_ctx.lock_coins().await; let ticker = chain.to_nft_ticker(); if let Some(MmCoinStruct { @@ -456,16 +462,29 @@ pub async fn refresh_nft_metadata(ctx: MmArc, req: RefreshMetadataReq) -> MmResu let nft_ctx = NftCtx::from_ctx(&ctx).map_to_mm(GetNftInfoError::Internal)?; let storage = nft_ctx.lock_db().await?; + + // TODO activate and use global NFT instead of ETH coin after adding enable nft using coin conf support + let coin_enum = lp_coinfind_or_err(&ctx, req.chain.to_ticker()).await?; + let eth_coin = match coin_enum { + MmCoinEnum::EthCoin(eth_coin) => eth_coin, + _ => { + return MmError::err(UpdateNftError::CoinDoesntSupportNft { + coin: coin_enum.ticker().to_owned(), + }) + }, + }; + let my_address = eth_coin.my_address()?; + let signed_message = + generate_signed_message(req.proxy_auth, &req.chain, my_address, ð_coin.priv_key_policy).await?; + let wrapper = UrlSignWrapper { + chain: &req.chain, + orig_url: &req.url, + url_antispam: &req.url_antispam, + signed_message: signed_message.as_ref(), + }; + let token_address_str = eth_addr_to_hex(&req.token_address); - let moralis_meta = match get_moralis_metadata( - token_address_str.clone(), - req.token_id.clone(), - &req.chain, - &req.url, - &req.url_antispam, - ) - .await - { + let mut moralis_meta = match get_moralis_metadata(token_address_str.clone(), req.token_id.clone(), &wrapper).await { Ok(moralis_meta) => moralis_meta, Err(_) => { storage @@ -486,10 +505,14 @@ pub async fn refresh_nft_metadata(ctx: MmArc, req: RefreshMetadataReq) -> MmResu })?; let token_uri = check_moralis_ipfs_bafy(moralis_meta.common.token_uri.as_deref()); let token_domain = get_domain_from_url(token_uri.as_deref()); + check_token_uri(&mut moralis_meta.common.possible_spam, token_uri.as_deref())?; + drop_mutability!(moralis_meta); let uri_meta = get_uri_meta( token_uri.as_deref(), moralis_meta.common.metadata.as_deref(), &req.url_antispam, + moralis_meta.common.possible_spam, + nft_db.possible_phishing, ) .await; // Gather domains for phishing checks @@ -600,23 +623,20 @@ where Ok(()) } -async fn get_moralis_nft_list( - ctx: &MmArc, - chain: &Chain, - url: &Url, - url_antispam: &Url, -) -> MmResult, GetNftInfoError> { +async fn get_moralis_nft_list(ctx: &MmArc, wrapper: &UrlSignWrapper<'_>) -> MmResult, GetNftInfoError> { let mut res_list = Vec::new(); + let chain = wrapper.chain; let ticker = chain.to_ticker(); let conf = coin_conf(ctx, ticker); let my_address = get_eth_address(ctx, &conf, ticker, &HDPathAccountToAddressId::default()).await?; - let uri_without_cursor = construct_moralis_uri_for_nft(url, &my_address.wallet_address, chain)?; + let uri_without_cursor = construct_moralis_uri_for_nft(wrapper.orig_url, &my_address.wallet_address, chain)?; // The cursor returned in the previous response (used for getting the next page). let mut cursor = String::new(); loop { + // Create a new URL instance from uri_without_cursor and modify its query to include the cursor if present let uri = format!("{}{}", uri_without_cursor, cursor); - let response = send_request_to_uri(uri.as_str()).await?; + let response = build_and_send_request(uri.as_str(), wrapper.signed_message).await?; if let Some(nfts_list) = response["result"].as_array() { for nft_json in nfts_list { let nft_moralis = NftFromMoralis::deserialize(nft_json)?; @@ -624,7 +644,7 @@ async fn get_moralis_nft_list( Some(contract_type) => contract_type, None => continue, }; - let mut nft = build_nft_from_moralis(*chain, nft_moralis, contract_type, url_antispam).await; + let mut nft = build_nft_from_moralis(*chain, nft_moralis, contract_type, wrapper.url_antispam).await; protect_from_nft_spam_links(&mut nft, false)?; // collect NFTs from the page res_list.push(nft); @@ -632,7 +652,7 @@ async fn get_moralis_nft_list( // if cursor is not null, there are other NFTs on next page, // and we need to send new request with cursor to get info from the next page. if let Some(cursor_res) = response["cursor"].as_str() { - cursor = format!("{}{}", "&cursor=", cursor_res); + cursor = format!("&cursor={}", cursor_res); continue; } else { break; @@ -647,22 +667,24 @@ async fn get_moralis_nft_list( pub(crate) async fn get_nfts_for_activation( chain: &Chain, my_address: &Address, - url: &Url, + orig_url: &Url, + signed_message: Option<&KomodefiProxyAuthValidation>, ) -> MmResult, GetNftInfoError> { let mut nfts_map = HashMap::new(); - let uri_without_cursor = construct_moralis_uri_for_nft(url, ð_addr_to_hex(my_address), chain)?; + let uri_without_cursor = construct_moralis_uri_for_nft(orig_url, ð_addr_to_hex(my_address), chain)?; // The cursor returned in the previous response (used for getting the next page). let mut cursor = String::new(); loop { + // Create a new URL instance from uri_without_cursor and modify its query to include the cursor if present let uri = format!("{}{}", uri_without_cursor, cursor); - let response = send_request_to_uri(uri.as_str()).await?; + let response = build_and_send_request(uri.as_str(), signed_message).await?; if let Some(nfts_list) = response["result"].as_array() { process_nft_list_for_activation(nfts_list, chain, &mut nfts_map)?; // if cursor is not null, there are other NFTs on next page, // and we need to send new request with cursor to get info from the next page. if let Some(cursor_res) = response["cursor"].as_str() { - cursor = format!("{}{}", "&cursor=", cursor_res); + cursor = format!("&cursor={}", cursor_res); continue; } else { break; @@ -701,21 +723,22 @@ fn process_nft_list_for_activation( async fn get_moralis_nft_transfers( ctx: &MmArc, - chain: &Chain, from_block: Option, - url: &Url, eth_coin: EthCoin, + wrapper: &UrlSignWrapper<'_>, ) -> MmResult, GetNftInfoError> { + let chain = wrapper.chain; let mut res_list = Vec::new(); let ticker = chain.to_ticker(); let conf = coin_conf(ctx, ticker); let my_address = get_eth_address(ctx, &conf, ticker, &HDPathAccountToAddressId::default()).await?; - let mut uri_without_cursor = url.clone(); - uri_without_cursor.set_path(MORALIS_API_ENDPOINT); + let mut uri_without_cursor = wrapper.orig_url.clone(); uri_without_cursor .path_segments_mut() .map_to_mm(|_| GetNftInfoError::Internal("Invalid URI".to_string()))? + .push(MORALIS_API) + .push(MORALIS_ENDPOINT_V) .push(&my_address.wallet_address) .push("nft") .push("transfers"); @@ -734,14 +757,15 @@ async fn get_moralis_nft_transfers( let mut cursor = String::new(); let wallet_address = my_address.wallet_address; loop { + // Create a new URL instance from uri_without_cursor and modify its query to include the cursor if present let uri = format!("{}{}", uri_without_cursor, cursor); - let response = send_request_to_uri(uri.as_str()).await?; + let response = build_and_send_request(uri.as_str(), wrapper.signed_message).await?; if let Some(transfer_list) = response["result"].as_array() { process_transfer_list(transfer_list, chain, wallet_address.as_str(), ð_coin, &mut res_list).await?; // if the cursor is not null, there are other NFTs transfers on next page, // and we need to send new request with cursor to get info from the next page. if let Some(cursor_res) = response["cursor"].as_str() { - cursor = format!("{}{}", "&cursor=", cursor_res); + cursor = format!("&cursor={}", cursor_res); continue; } else { break; @@ -857,18 +881,18 @@ async fn get_fee_details(eth_coin: &EthCoin, transaction_hash: &str) -> Option, ) -> MmResult { - let mut uri = url.clone(); - uri.set_path(MORALIS_API_ENDPOINT); + let mut uri = wrapper.orig_url.clone(); + let chain = wrapper.chain; uri.path_segments_mut() .map_to_mm(|_| GetNftInfoError::Internal("Invalid URI".to_string()))? + .push(MORALIS_API) + .push(MORALIS_ENDPOINT_V) .push("nft") .push(&token_address) .push(&token_id.to_string()); @@ -877,13 +901,13 @@ async fn get_moralis_metadata( .append_pair(MORALIS_FORMAT_QUERY_NAME, MORALIS_FORMAT_QUERY_VALUE); drop_mutability!(uri); - let response = send_request_to_uri(uri.as_str()).await?; + let response = build_and_send_request(uri.as_str(), wrapper.signed_message).await?; let nft_moralis: NftFromMoralis = serde_json::from_str(&response.to_string())?; let contract_type = match nft_moralis.contract_type { Some(contract_type) => contract_type, None => return MmError::err(GetNftInfoError::ContractTypeIsNull), }; - let mut nft_metadata = build_nft_from_moralis(*chain, nft_moralis, contract_type, url_antispam).await; + let mut nft_metadata = build_nft_from_moralis(*chain, nft_moralis, contract_type, wrapper.url_antispam).await; protect_from_nft_spam_links(&mut nft_metadata, false)?; Ok(nft_metadata) } @@ -920,14 +944,23 @@ fn check_moralis_ipfs_bafy(token_uri: Option<&str>) -> Option { }) } -async fn get_uri_meta(token_uri: Option<&str>, metadata: Option<&str>, url_antispam: &Url) -> UriMeta { +async fn get_uri_meta( + token_uri: Option<&str>, + metadata: Option<&str>, + url_antispam: &Url, + possible_spam: bool, + possible_phishing: bool, +) -> UriMeta { let mut uri_meta = UriMeta::default(); - // Fetching data from the URL if token_uri is provided - if let Some(token_uri) = token_uri { - if let Some(url) = construct_camo_url_with_token(token_uri, url_antispam) { - uri_meta = fetch_meta_from_url(url).await.unwrap_or_default(); + if !possible_spam && !possible_phishing { + // Fetching data from the URL if token_uri is provided + if let Some(token_uri) = token_uri { + if let Some(url) = construct_camo_url_with_token(token_uri, url_antispam) { + uri_meta = fetch_meta_from_url(url).await.unwrap_or_default(); + } } } + // Filling fields from metadata if provided if let Some(metadata) = metadata { if let Ok(meta_from_meta) = serde_json::from_str::(metadata) { @@ -946,7 +979,7 @@ fn construct_camo_url_with_token(token_uri: &str, url_antispam: &Url) -> Option< } async fn fetch_meta_from_url(url: Url) -> MmResult { - let response_meta = send_request_to_uri(url.as_str()).await?; + let response_meta = send_request_to_uri(url.as_str(), None).await?; serde_json::from_value(response_meta).map_err(|e| e.into()) } @@ -973,11 +1006,10 @@ fn get_transfer_status(my_wallet: &str, to_address: &str) -> TransferStatus { async fn update_nft_list( ctx: MmArc, storage: &T, - chain: &Chain, scan_from_block: u64, - url: &Url, - url_antispam: &Url, + wrapper: &UrlSignWrapper<'_>, ) -> MmResult<(), UpdateNftError> { + let chain = wrapper.chain; let transfers = storage.get_transfers_from_block(*chain, scan_from_block).await?; let req = MyAddressReq { coin: chain.to_ticker().to_string(), @@ -985,27 +1017,26 @@ async fn update_nft_list( }; let my_address = get_my_address(ctx.clone(), req).await?.wallet_address.to_lowercase(); for transfer in transfers.into_iter() { - handle_nft_transfer(storage, chain, url, url_antispam, transfer, &my_address).await?; + handle_nft_transfer(storage, wrapper, transfer, &my_address).await?; } Ok(()) } async fn handle_nft_transfer( storage: &T, - chain: &Chain, - url: &Url, - url_antispam: &Url, + wrapper: &UrlSignWrapper<'_>, transfer: NftTransferHistory, my_address: &str, ) -> MmResult<(), UpdateNftError> { + let chain = wrapper.chain; match (transfer.status, transfer.contract_type) { (TransferStatus::Send, ContractType::Erc721) => handle_send_erc721(storage, chain, transfer).await, (TransferStatus::Receive, ContractType::Erc721) => { - handle_receive_erc721(storage, chain, transfer, url, url_antispam, my_address).await + handle_receive_erc721(storage, transfer, wrapper, my_address).await }, (TransferStatus::Send, ContractType::Erc1155) => handle_send_erc1155(storage, chain, transfer).await, (TransferStatus::Receive, ContractType::Erc1155) => { - handle_receive_erc1155(storage, chain, transfer, url, url_antispam, my_address).await + handle_receive_erc1155(storage, transfer, wrapper, my_address).await }, } } @@ -1039,12 +1070,11 @@ async fn handle_send_erc721 async fn handle_receive_erc721( storage: &T, - chain: &Chain, transfer: NftTransferHistory, - url: &Url, - url_antispam: &Url, + wrapper: &UrlSignWrapper<'_>, my_address: &str, ) -> MmResult<(), UpdateNftError> { + let chain = wrapper.chain; let token_address_str = eth_addr_to_hex(&transfer.common.token_address); match storage .get_nft(chain, token_address_str.clone(), transfer.token_id.clone()) @@ -1065,14 +1095,8 @@ async fn handle_receive_erc721 { - let mut nft = match get_moralis_metadata( - token_address_str.clone(), - transfer.token_id.clone(), - chain, - url, - url_antispam, - ) - .await + let mut nft = match get_moralis_metadata(token_address_str.clone(), transfer.token_id.clone(), wrapper) + .await { Ok(mut moralis_meta) => { // sometimes moralis updates Get All NFTs (which also affects Get Metadata) later @@ -1132,12 +1156,11 @@ async fn handle_send_erc1155( storage: &T, - chain: &Chain, transfer: NftTransferHistory, - url: &Url, - url_antispam: &Url, + wrapper: &UrlSignWrapper<'_>, my_address: &str, ) -> MmResult<(), UpdateNftError> { + let chain = wrapper.chain; let token_address_str = eth_addr_to_hex(&transfer.common.token_address); let mut nft = match storage .get_nft(chain, token_address_str.clone(), transfer.token_id.clone()) @@ -1158,17 +1181,10 @@ async fn handle_receive_erc1155 { - let nft = match get_moralis_metadata( - token_address_str.clone(), - transfer.token_id.clone(), - chain, - url, - url_antispam, - ) - .await - { + let nft = match get_moralis_metadata(token_address_str.clone(), transfer.token_id.clone(), wrapper).await { Ok(moralis_meta) => { - create_nft_from_moralis_metadata(moralis_meta, &transfer, my_address, chain, url_antispam).await? + create_nft_from_moralis_metadata(moralis_meta, &transfer, my_address, chain, wrapper.url_antispam) + .await? }, Err(_) => { mark_as_spam_and_build_empty_meta(storage, chain, token_address_str, &transfer, my_address).await? @@ -1184,8 +1200,18 @@ async fn handle_receive_erc1155) -> MmResult<(), regex::Error> { + if let Some(uri) = token_uri { + if is_malicious(uri)? { + *possible_spam = true; + } + } + Ok(()) +} + async fn create_nft_from_moralis_metadata( - moralis_meta: Nft, + mut moralis_meta: Nft, transfer: &NftTransferHistory, my_address: &str, chain: &Chain, @@ -1193,10 +1219,13 @@ async fn create_nft_from_moralis_metadata( ) -> MmResult { let token_uri = check_moralis_ipfs_bafy(moralis_meta.common.token_uri.as_deref()); let token_domain = get_domain_from_url(token_uri.as_deref()); + check_token_uri(&mut moralis_meta.common.possible_spam, token_uri.as_deref())?; let uri_meta = get_uri_meta( token_uri.as_deref(), moralis_meta.common.metadata.as_deref(), url_antispam, + moralis_meta.common.possible_spam, + moralis_meta.possible_phishing, ) .await; let nft = Nft { @@ -1255,16 +1284,14 @@ async fn mark_as_spam_and_build_empty_meta( ctx: &MmArc, storage: &T, - chain: &Chain, - url: &Url, - url_antispam: &Url, + wrapper: &UrlSignWrapper<'_>, ) -> MmResult, UpdateNftError> { - let nft_list = get_moralis_nft_list(ctx, chain, url, url_antispam).await?; - let last_scanned_block = NftTransferHistoryStorageOps::get_last_block_number(storage, chain) + let nft_list = get_moralis_nft_list(ctx, wrapper).await?; + let last_scanned_block = NftTransferHistoryStorageOps::get_last_block_number(storage, wrapper.chain) .await? .unwrap_or(0); storage - .add_nfts_to_list(*chain, nft_list.clone(), last_scanned_block) + .add_nfts_to_list(*wrapper.chain, nft_list.clone(), last_scanned_block) .await?; Ok(nft_list) } @@ -1281,42 +1308,43 @@ where } /// `update_transfers_with_empty_meta` function updates empty metadata in transfers. -async fn update_transfers_with_empty_meta( - storage: &T, - chain: &Chain, - url: &Url, - url_antispam: &Url, -) -> MmResult<(), UpdateNftError> +async fn update_transfers_with_empty_meta(storage: &T, wrapper: &UrlSignWrapper<'_>) -> MmResult<(), UpdateNftError> where T: NftListStorageOps + NftTransferHistoryStorageOps, { + let chain = wrapper.chain; let token_addr_id = storage.get_transfers_with_empty_meta(*chain).await?; for addr_id_pair in token_addr_id.into_iter() { - let mut nft_meta = match get_moralis_metadata( - addr_id_pair.token_address.clone(), - addr_id_pair.token_id, - chain, - url, - url_antispam, - ) - .await - { - Ok(nft_meta) => nft_meta, - Err(_) => { - storage - .update_nft_spam_by_token_address(chain, addr_id_pair.token_address.clone(), true) - .await?; - storage - .update_transfer_spam_by_token_address(chain, addr_id_pair.token_address, true) - .await?; - continue; - }, - }; + let mut nft_meta = + match get_moralis_metadata(addr_id_pair.token_address.clone(), addr_id_pair.token_id, wrapper).await { + Ok(nft_meta) => nft_meta, + Err(_) => { + storage + .update_nft_spam_by_token_address(chain, addr_id_pair.token_address.clone(), true) + .await?; + storage + .update_transfer_spam_by_token_address(chain, addr_id_pair.token_address, true) + .await?; + continue; + }, + }; update_transfer_meta_using_nft(storage, chain, &mut nft_meta).await?; } Ok(()) } +/// Checks if the given URL is potentially malicious based on certain patterns. +fn is_malicious(token_uri: &str) -> MmResult { + let patterns = vec![r"\.(xyz|gq|top)(/|$)", r"\.(json|xml|jpg|png)[%?]"]; + for pattern in patterns { + let regex = Regex::new(pattern)?; + if regex.is_match(token_uri) { + return Ok(true); + } + } + Ok(false) +} + /// `contains_disallowed_scheme` function checks if the text contains some link. fn contains_disallowed_url(text: &str) -> Result { let url_regex = Regex::new( @@ -1421,15 +1449,20 @@ fn process_metadata_field( async fn build_nft_from_moralis( chain: Chain, - nft_moralis: NftFromMoralis, + mut nft_moralis: NftFromMoralis, contract_type: ContractType, url_antispam: &Url, ) -> Nft { let token_uri = check_moralis_ipfs_bafy(nft_moralis.common.token_uri.as_deref()); + if let Err(e) = check_token_uri(&mut nft_moralis.common.possible_spam, token_uri.as_deref()) { + error!("Error checking token URI: {}", e); + } let uri_meta = get_uri_meta( token_uri.as_deref(), nft_moralis.common.metadata.as_deref(), url_antispam, + nft_moralis.common.possible_spam, + false, ) .await; let token_domain = get_domain_from_url(token_uri.as_deref()); @@ -1513,11 +1546,12 @@ where Ok(()) } -fn construct_moralis_uri_for_nft(base_url: &Url, address: &str, chain: &Chain) -> MmResult { - let mut uri = base_url.clone(); - uri.set_path(MORALIS_API_ENDPOINT); +fn construct_moralis_uri_for_nft(orig_url: &Url, address: &str, chain: &Chain) -> MmResult { + let mut uri = orig_url.clone(); uri.path_segments_mut() .map_to_mm(|_| GetNftInfoError::Internal("Invalid URI".to_string()))? + .push(MORALIS_API) + .push(MORALIS_ENDPOINT_V) .push(address) .push("nft"); uri.query_pairs_mut() @@ -1525,3 +1559,20 @@ fn construct_moralis_uri_for_nft(base_url: &Url, address: &str, chain: &Chain) - .append_pair(MORALIS_FORMAT_QUERY_NAME, MORALIS_FORMAT_QUERY_VALUE); Ok(uri) } + +/// A wrapper struct for holding the chain identifier, original URL field from RPC, anti-spam URL and signed message. +struct UrlSignWrapper<'a> { + chain: &'a Chain, + orig_url: &'a Url, + url_antispam: &'a Url, + signed_message: Option<&'a KomodefiProxyAuthValidation>, +} + +async fn build_and_send_request( + uri: &str, + signed_message: Option<&KomodefiProxyAuthValidation>, +) -> MmResult { + let payload = signed_message.map(|msg| serde_json::to_string(&msg)).transpose()?; + let response = send_request_to_uri(uri, payload.as_deref()).await?; + Ok(response) +} diff --git a/mm2src/coins/nft/nft_errors.rs b/mm2src/coins/nft/nft_errors.rs index 5e35b138ff..12e8d326a0 100644 --- a/mm2src/coins/nft/nft_errors.rs +++ b/mm2src/coins/nft/nft_errors.rs @@ -1,8 +1,10 @@ +use crate::eth::v2_activation::GenerateSignedMessageError; use crate::eth::GetEthAddressError; #[cfg(target_arch = "wasm32")] use crate::nft::storage::wasm::WasmNftCacheError; use crate::nft::storage::NftStorageError; -use crate::{CoinFindError, GetMyAddressError, NumConversError, UnexpectedDerivationMethod, WithdrawError}; +use crate::{CoinFindError, GetMyAddressError, MyAddressError, NumConversError, PrivKeyPolicyNotAllowed, + UnexpectedDerivationMethod, WithdrawError}; use common::{HttpStatusCode, ParseRfc3339Err}; #[cfg(not(target_arch = "wasm32"))] use db_common::sqlite::rusqlite::Error as SqlError; @@ -155,6 +157,7 @@ pub enum UpdateNftError { #[from_stringify("LockDBError")] #[display(fmt = "DB error {}", _0)] DbError(String), + #[from_stringify("regex::Error", "MyAddressError")] #[display(fmt = "Internal: {}", _0)] Internal(String), GetNftInfoError(GetNftInfoError), @@ -212,6 +215,8 @@ pub enum UpdateNftError { CoinDoesntSupportNft { coin: String, }, + #[display(fmt = "Private key policy is not allowed: {}", _0)] + PrivKeyPolicyNotAllowed(PrivKeyPolicyNotAllowed), } impl From for UpdateNftError { @@ -246,6 +251,19 @@ impl From for UpdateNftError { } } +impl From for UpdateNftError { + fn from(e: PrivKeyPolicyNotAllowed) -> Self { Self::PrivKeyPolicyNotAllowed(e) } +} + +impl From for UpdateNftError { + fn from(e: GenerateSignedMessageError) -> Self { + match e { + GenerateSignedMessageError::InternalError(e) => UpdateNftError::Internal(e), + GenerateSignedMessageError::PrivKeyPolicyNotAllowed(e) => UpdateNftError::PrivKeyPolicyNotAllowed(e), + } + } +} + impl HttpStatusCode for UpdateNftError { fn status_code(&self) -> StatusCode { match self { @@ -264,7 +282,8 @@ impl HttpStatusCode for UpdateNftError { | UpdateNftError::SerdeError(_) | UpdateNftError::ProtectFromSpamError(_) | UpdateNftError::NoSuchCoin { .. } - | UpdateNftError::CoinDoesntSupportNft { .. } => StatusCode::INTERNAL_SERVER_ERROR, + | UpdateNftError::CoinDoesntSupportNft { .. } + | UpdateNftError::PrivKeyPolicyNotAllowed(_) => StatusCode::INTERNAL_SERVER_ERROR, } } } diff --git a/mm2src/coins/nft/nft_structs.rs b/mm2src/coins/nft/nft_structs.rs index 0096e8f2fe..92e9c62d30 100644 --- a/mm2src/coins/nft/nft_structs.rs +++ b/mm2src/coins/nft/nft_structs.rs @@ -98,6 +98,7 @@ pub struct RefreshMetadataReq { /// URL used to validate if the fetched contract addresses are associated /// with spam contracts or if domain fields in the fetched metadata match known phishing domains. pub(crate) url_antispam: Url, + pub(crate) proxy_auth: bool, } /// Represents blockchains which are supported by NFT feature. @@ -660,6 +661,7 @@ pub struct UpdateNftReq { /// URL used to validate if the fetched contract addresses are associated /// with spam contracts or if domain fields in the fetched metadata match known phishing domains. pub(crate) url_antispam: Url, + pub(crate) proxy_auth: bool, } /// Represents a unique identifier for an NFT, consisting of its token address and token ID. @@ -806,6 +808,7 @@ where #[derive(Debug, Deserialize)] pub struct ClearNftDbReq { /// Specifies the blockchain networks (e.g., Ethereum, BSC) to clear NFT data. + #[serde(default)] pub(crate) chains: Vec, /// If `true`, clears NFT data for all chains, ignoring the `chains` field. Defaults to `false`. #[serde(default)] diff --git a/mm2src/coins/nft/nft_tests.rs b/mm2src/coins/nft/nft_tests.rs index f0dd57603c..05f732a9ee 100644 --- a/mm2src/coins/nft/nft_tests.rs +++ b/mm2src/coins/nft/nft_tests.rs @@ -4,7 +4,7 @@ use crate::nft::nft_structs::{Chain, NftFromMoralis, NftListFilters, NftTransfer SpamContractRes, TransferMeta, UriMeta}; use crate::nft::storage::db_test_helpers::{get_nft_ctx, nft, nft_list, nft_transfer_history}; use crate::nft::storage::{NftListStorageOps, NftTransferHistoryStorageOps, RemoveNftResult}; -use crate::nft::{check_moralis_ipfs_bafy, get_domain_from_url, process_metadata_for_spam_link, +use crate::nft::{check_moralis_ipfs_bafy, get_domain_from_url, is_malicious, process_metadata_for_spam_link, process_text_for_spam_link}; use common::cross_test; use ethereum_types::Address; @@ -30,6 +30,14 @@ common::cfg_wasm32! { use mm2_net::wasm::http::send_request_to_uri; } +cross_test!(test_is_malicious, { + let token_uri = "https://btrgtrhbyjuyj.xyz/BABYDOGE.json"; + assert!(is_malicious(token_uri).unwrap()); + + let token_uri1 = "https://btrgtrhbyjuyj.com/BABYDOGE.json%00"; + assert!(is_malicious(token_uri1).unwrap()); +}); + cross_test!(test_moralis_ipfs_bafy, { let uri = "https://ipfs.moralis.io:2053/ipfs/bafybeifnek24coy5xj5qabdwh24dlp5omq34nzgvazkfyxgnqms4eidsiq/1.json"; let res_uri = check_moralis_ipfs_bafy(Some(uri)); @@ -86,7 +94,7 @@ cross_test!(test_moralis_requests, { "{}/{}/nft?chain=POLYGON&format=decimal", MORALIS_API_ENDPOINT_TEST, TEST_WALLET_ADDR_EVM ); - let response_nft_list = send_request_to_uri(uri_nft_list.as_str()).await.unwrap(); + let response_nft_list = send_request_to_uri(uri_nft_list.as_str(), None).await.unwrap(); let nfts_list = response_nft_list["result"].as_array().unwrap(); for nft_json in nfts_list { let nft_moralis: NftFromMoralis = serde_json::from_str(&nft_json.to_string()).unwrap(); @@ -97,7 +105,7 @@ cross_test!(test_moralis_requests, { "{}/{}/nft/transfers?chain=POLYGON&format=decimal", MORALIS_API_ENDPOINT_TEST, TEST_WALLET_ADDR_EVM ); - let response_transfer_history = send_request_to_uri(uri_history.as_str()).await.unwrap(); + let response_transfer_history = send_request_to_uri(uri_history.as_str(), None).await.unwrap(); let mut transfer_list = response_transfer_history["result"].as_array().unwrap().clone(); assert!(!transfer_list.is_empty()); let first_transfer = transfer_list.remove(transfer_list.len() - 1); @@ -111,7 +119,7 @@ cross_test!(test_moralis_requests, { "{}/nft/0xed55e4477b795eaa9bb4bca24df42214e1a05c18/1111777?chain=POLYGON&format=decimal", MORALIS_API_ENDPOINT_TEST ); - let response_meta = send_request_to_uri(uri_meta.as_str()).await.unwrap(); + let response_meta = send_request_to_uri(uri_meta.as_str(), None).await.unwrap(); let nft_moralis: NftFromMoralis = serde_json::from_str(&response_meta.to_string()).unwrap(); assert_eq!(42563567, nft_moralis.block_number.0); }); @@ -147,7 +155,7 @@ cross_test!(test_antispam_scan_endpoints, { cross_test!(test_camo, { let hex_token_uri = hex::encode("https://tikimetadata.s3.amazonaws.com/tiki_box.json"); let uri_decode = format!("{}/url/decode/{}", BLOCKLIST_API_ENDPOINT, hex_token_uri); - let decode_res = send_request_to_uri(&uri_decode).await.unwrap(); + let decode_res = send_request_to_uri(&uri_decode, None).await.unwrap(); let uri_meta: UriMeta = serde_json::from_value(decode_res).unwrap(); assert_eq!( uri_meta.raw_image_url.unwrap(), diff --git a/mm2src/coins/utxo/utxo_builder/utxo_conf_builder.rs b/mm2src/coins/utxo/utxo_builder/utxo_conf_builder.rs index befbae70f9..5ae7fcb405 100644 --- a/mm2src/coins/utxo/utxo_builder/utxo_conf_builder.rs +++ b/mm2src/coins/utxo/utxo_builder/utxo_conf_builder.rs @@ -210,10 +210,9 @@ impl<'a> UtxoConfBuilder<'a> { fn overwintered(&self) -> bool { self.conf["overwintered"].as_u64().unwrap_or(0) == 1 } fn tx_fee_volatility_percent(&self) -> f64 { - match self.conf["txfee_volatility_percent"].as_f64() { - Some(volatility) => volatility, - None => DEFAULT_DYNAMIC_FEE_VOLATILITY_PERCENT, - } + self.conf["txfee_volatility_percent"] + .as_f64() + .unwrap_or(DEFAULT_DYNAMIC_FEE_VOLATILITY_PERCENT) } fn version_group_id(&self, tx_version: i32, overwintered: bool) -> UtxoConfResult { diff --git a/mm2src/coins_activation/src/erc20_token_activation.rs b/mm2src/coins_activation/src/erc20_token_activation.rs index 664f2c22fd..82b89026bb 100644 --- a/mm2src/coins_activation/src/erc20_token_activation.rs +++ b/mm2src/coins_activation/src/erc20_token_activation.rs @@ -42,6 +42,7 @@ impl From for EnableTokenError { | EthTokenActivationError::ClientConnectionFailed(e) => EnableTokenError::Transport(e), EthTokenActivationError::InvalidPayload(e) => EnableTokenError::InvalidPayload(e), EthTokenActivationError::UnexpectedDerivationMethod(e) => EnableTokenError::UnexpectedDerivationMethod(e), + EthTokenActivationError::PrivKeyPolicyNotAllowed(e) => EnableTokenError::PrivKeyPolicyNotAllowed(e), } } } @@ -163,7 +164,9 @@ impl TokenActivationOps for EthCoin { )); } let nft_global = match &nft_init_params.provider { - NftProviderEnum::Moralis { url } => platform_coin.global_nft_from_platform_coin(url).await?, + NftProviderEnum::Moralis { url, proxy_auth } => { + platform_coin.global_nft_from_platform_coin(url, proxy_auth).await? + }, }; let nfts = nft_global.nfts_infos.lock().await.clone(); let init_result = EthTokenInitResult::Nft(NftInitResult { diff --git a/mm2src/coins_activation/src/eth_with_token_activation.rs b/mm2src/coins_activation/src/eth_with_token_activation.rs index 296cfcfd73..487745419a 100644 --- a/mm2src/coins_activation/src/eth_with_token_activation.rs +++ b/mm2src/coins_activation/src/eth_with_token_activation.rs @@ -117,6 +117,7 @@ impl From for InitTokensAsMmCoinsError { EthTokenActivationError::UnexpectedDerivationMethod(e) => { InitTokensAsMmCoinsError::UnexpectedDerivationMethod(e) }, + EthTokenActivationError::PrivKeyPolicyNotAllowed(e) => InitTokensAsMmCoinsError::Internal(e.to_string()), } } } @@ -288,13 +289,13 @@ impl PlatformCoinWithTokensActivationOps for EthCoin { &self, activation_request: &Self::ActivationRequest, ) -> Result, MmError> { - let url = match &activation_request.nft_req { + let (url, proxy_auth) = match &activation_request.nft_req { Some(nft_req) => match &nft_req.provider { - NftProviderEnum::Moralis { url } => url, + NftProviderEnum::Moralis { url, proxy_auth } => (url, proxy_auth), }, None => return Ok(None), }; - let nft_global = self.global_nft_from_platform_coin(url).await?; + let nft_global = self.global_nft_from_platform_coin(url, proxy_auth).await?; Ok(Some(MmCoinEnum::EthCoin(nft_global))) } diff --git a/mm2src/coins_activation/src/init_erc20_token_activation.rs b/mm2src/coins_activation/src/init_erc20_token_activation.rs index 5bc4e665ff..de322c9ee5 100644 --- a/mm2src/coins_activation/src/init_erc20_token_activation.rs +++ b/mm2src/coins_activation/src/init_erc20_token_activation.rs @@ -59,9 +59,9 @@ impl From for InitTokenError { impl From for InitErc20Error { fn from(e: EthTokenActivationError) -> Self { match e { - EthTokenActivationError::InternalError(_) | EthTokenActivationError::UnexpectedDerivationMethod(_) => { - InitErc20Error::Internal(e.to_string()) - }, + EthTokenActivationError::InternalError(_) + | EthTokenActivationError::UnexpectedDerivationMethod(_) + | EthTokenActivationError::PrivKeyPolicyNotAllowed(_) => InitErc20Error::Internal(e.to_string()), EthTokenActivationError::ClientConnectionFailed(_) | EthTokenActivationError::CouldNotFetchBalance(_) | EthTokenActivationError::InvalidPayload(_) diff --git a/mm2src/coins_activation/src/token.rs b/mm2src/coins_activation/src/token.rs index d1449dea8d..0493c68fdb 100644 --- a/mm2src/coins_activation/src/token.rs +++ b/mm2src/coins_activation/src/token.rs @@ -4,8 +4,8 @@ use crate::platform_coin_with_tokens::{self, RegisterTokenInfo}; use crate::prelude::*; use async_trait::async_trait; use coins::utxo::rpc_clients::UtxoRpcError; -use coins::{lp_coinfind, lp_coinfind_or_err, BalanceError, CoinProtocol, CoinsContext, MmCoinEnum, RegisterCoinError, - UnexpectedDerivationMethod}; +use coins::{lp_coinfind, lp_coinfind_or_err, BalanceError, CoinProtocol, CoinsContext, MmCoinEnum, + PrivKeyPolicyNotAllowed, RegisterCoinError, UnexpectedDerivationMethod}; use common::{HttpStatusCode, StatusCode}; use derive_more::Display; use mm2_core::mm_ctx::MmArc; @@ -63,6 +63,7 @@ pub enum EnableTokenError { Transport(String), Internal(String), InvalidPayload(String), + PrivKeyPolicyNotAllowed(PrivKeyPolicyNotAllowed), } impl From for EnableTokenError { @@ -170,7 +171,8 @@ impl HttpStatusCode for EnableTokenError { | EnableTokenError::Transport(_) | EnableTokenError::CouldNotFetchBalance(_) | EnableTokenError::InvalidConfig(_) - | EnableTokenError::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR, + | EnableTokenError::Internal(_) + | EnableTokenError::PrivKeyPolicyNotAllowed(_) => StatusCode::INTERNAL_SERVER_ERROR, } } } diff --git a/mm2src/common/common.rs b/mm2src/common/common.rs index 17ff8fe2da..6892b8f777 100644 --- a/mm2src/common/common.rs +++ b/mm2src/common/common.rs @@ -193,7 +193,7 @@ cfg_wasm32! { const KOMODO_DEFI_FRAMEWORK_DIR_NAME: &str = ".kdf"; pub const X_GRPC_WEB: &str = "x-grpc-web"; -pub const X_API_KEY: &str = "X-API-Key"; +pub const X_AUTH_PAYLOAD: &str = "X-Auth-Payload"; pub const APPLICATION_JSON: &str = "application/json"; pub const APPLICATION_GRPC_WEB: &str = "application/grpc-web"; pub const APPLICATION_GRPC_WEB_PROTO: &str = "application/grpc-web+proto"; diff --git a/mm2src/mm2_main/Cargo.toml b/mm2src/mm2_main/Cargo.toml index d7a1e33bd9..8be8b5ad3c 100644 --- a/mm2src/mm2_main/Cargo.toml +++ b/mm2src/mm2_main/Cargo.toml @@ -126,7 +126,7 @@ coins_activation = { path = "../coins_activation", features = ["for-tests"] } 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.20.0", default-features = false, features = ["http"] } +web3 = { git = "https://github.com/KomodoPlatform/rust-web3", tag = "v0.20.0", default-features = false, features = ["http-rustls-tls"] } ethabi = { version = "17.0.0" } rlp = { version = "0.5" } ethcore-transaction = { git = "https://github.com/KomodoPlatform/mm2-parity-ethereum.git", rev = "mm2-v2.1.1" } 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 2fe6450810..0066f00139 100644 --- a/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs +++ b/mm2src/mm2_main/tests/docker_tests/docker_tests_common.rs @@ -45,6 +45,7 @@ pub use std::env; use std::path::PathBuf; use std::process::Command; use std::process::Stdio; +use std::str::FromStr; use std::sync::Mutex; pub use std::thread; use std::time::Duration; @@ -52,6 +53,7 @@ use testcontainers::clients::Cli; use testcontainers::core::WaitFor; use testcontainers::{Container, GenericImage, RunnableImage}; use web3::transports::Http; +use web3::types::Address as EthAddress; use web3::types::{BlockId, BlockNumber, TransactionRequest}; use web3::Web3; @@ -66,9 +68,17 @@ lazy_static! { // Supply more privkeys when 18 will be not enough. pub static ref SLP_TOKEN_OWNERS: Mutex> = Mutex::new(Vec::with_capacity(18)); pub static ref MM_CTX: MmArc = MmCtxBuilder::new().into_mm_arc(); + /// We need a second `MmCtx` instance when we use the same private keys for Maker and Taker across various tests. + /// When enabling coins for both Maker and Taker, two distinct coin instances are created. + /// This means that different instances of the same coin should have separate global nonce locks. + /// Utilizing different `MmCtx` instances allows us to assign Maker and Taker coins to separate `CoinsCtx`. + /// This approach addresses the `replacement transaction` issue, which occurs when different transactions share the same nonce. + pub static ref MM_CTX1: MmArc = MmCtxBuilder::new().into_mm_arc(); pub static ref GETH_WEB3: Web3 = Web3::new(Http::new(GETH_RPC_URL).unwrap()); + pub static ref SEPOLIA_WEB3: Web3 = Web3::new(Http::new(SEPOLIA_RPC_URL).unwrap()); // Mutex used to prevent nonce re-usage during funding addresses used in tests pub static ref GETH_NONCE_LOCK: Mutex<()> = Mutex::new(()); + pub static ref SEPOLIA_NONCE_LOCK: Mutex<()> = Mutex::new(()); } pub static mut QICK_TOKEN_ADDRESS: Option = None; @@ -89,7 +99,16 @@ 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(); +/// NFT Maker Swap V2 contract address on Geth dev node +pub static mut GETH_NFT_MAKER_SWAP_V2: H160Eth = H160Eth::zero(); +/// NFT Maker Swap V2 contract address on Sepolia testnet +pub static mut SEPOLIA_ETOMIC_MAKER_NFT_SWAP_V2: H160Eth = H160Eth::zero(); +/// ERC721 token address on Sepolia testnet +pub static mut SEPOLIA_ERC721_CONTRACT: H160Eth = H160Eth::zero(); +/// ERC1155 token address on Sepolia testnet +pub static mut SEPOLIA_ERC1155_CONTRACT: H160Eth = H160Eth::zero(); pub static GETH_RPC_URL: &str = "http://127.0.0.1:8545"; +pub static SEPOLIA_RPC_URL: &str = "https://ethereum-sepolia-rpc.publicnode.com"; pub const UTXO_ASSET_DOCKER_IMAGE: &str = "docker.io/artempikulin/testblockchain"; pub const UTXO_ASSET_DOCKER_IMAGE_WITH_TAG: &str = "docker.io/artempikulin/testblockchain:multiarch"; @@ -118,6 +137,7 @@ pub const WATCHERS_SWAP_CONTRACT_BYTES: &str = "608060405234801561000f575f80fd5b pub const ERC721_TEST_TOKEN_BYTES: &str = "608060405234801562000010575f80fd5b50604051620022ac380380620022ac8339818101604052810190620000369190620001ea565b8181815f9081620000489190620004a4565b5080600190816200005a9190620004a4565b505050505062000588565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b620000c6826200007e565b810181811067ffffffffffffffff82111715620000e857620000e76200008e565b5b80604052505050565b5f620000fc62000065565b90506200010a8282620000bb565b919050565b5f67ffffffffffffffff8211156200012c576200012b6200008e565b5b62000137826200007e565b9050602081019050919050565b5f5b838110156200016357808201518184015260208101905062000146565b5f8484015250505050565b5f620001846200017e846200010f565b620000f1565b905082815260208101848484011115620001a357620001a26200007a565b5b620001b084828562000144565b509392505050565b5f82601f830112620001cf57620001ce62000076565b5b8151620001e18482602086016200016e565b91505092915050565b5f80604083850312156200020357620002026200006e565b5b5f83015167ffffffffffffffff81111562000223576200022262000072565b5b6200023185828601620001b8565b925050602083015167ffffffffffffffff81111562000255576200025462000072565b5b6200026385828601620001b8565b9150509250929050565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680620002bc57607f821691505b602082108103620002d257620002d162000277565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620003367fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620002f9565b620003428683620002f9565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f6200038c6200038662000380846200035a565b62000363565b6200035a565b9050919050565b5f819050919050565b620003a7836200036c565b620003bf620003b68262000393565b84845462000305565b825550505050565b5f90565b620003d5620003c7565b620003e28184846200039c565b505050565b5b818110156200040957620003fd5f82620003cb565b600181019050620003e8565b5050565b601f82111562000458576200042281620002d8565b6200042d84620002ea565b810160208510156200043d578190505b620004556200044c85620002ea565b830182620003e7565b50505b505050565b5f82821c905092915050565b5f6200047a5f19846008026200045d565b1980831691505092915050565b5f62000494838362000469565b9150826002028217905092915050565b620004af826200026d565b67ffffffffffffffff811115620004cb57620004ca6200008e565b5b620004d78254620002a4565b620004e48282856200040d565b5f60209050601f8311600181146200051a575f841562000505578287015190505b62000511858262000487565b86555062000580565b601f1984166200052a86620002d8565b5f5b8281101562000553578489015182556001820191506020850194506020810190506200052c565b868310156200057357848901516200056f601f89168262000469565b8355505b6001600288020188555050505b505050505050565b611d1680620005965f395ff3fe608060405234801561000f575f80fd5b50600436106100e8575f3560e01c80636352211e1161008a578063a22cb46511610064578063a22cb46514610258578063b88d4fde14610274578063c87b56dd14610290578063e985e9c5146102c0576100e8565b80636352211e146101da57806370a082311461020a57806395d89b411461023a576100e8565b8063095ea7b3116100c6578063095ea7b31461016a57806323b872dd1461018657806340c10f19146101a257806342842e0e146101be576100e8565b806301ffc9a7146100ec57806306fdde031461011c578063081812fc1461013a575b5f80fd5b610106600480360381019061010191906115a7565b6102f0565b60405161011391906115ec565b60405180910390f35b6101246103d1565b604051610131919061168f565b60405180910390f35b610154600480360381019061014f91906116e2565b610460565b604051610161919061174c565b60405180910390f35b610184600480360381019061017f919061178f565b61047b565b005b6101a0600480360381019061019b91906117cd565b610491565b005b6101bc60048036038101906101b7919061178f565b610590565b005b6101d860048036038101906101d391906117cd565b61059e565b005b6101f460048036038101906101ef91906116e2565b6105bd565b604051610201919061174c565b60405180910390f35b610224600480360381019061021f919061181d565b6105ce565b6040516102319190611857565b60405180910390f35b610242610684565b60405161024f919061168f565b60405180910390f35b610272600480360381019061026d919061189a565b610714565b005b61028e60048036038101906102899190611a04565b61072a565b005b6102aa60048036038101906102a591906116e2565b610747565b6040516102b7919061168f565b60405180910390f35b6102da60048036038101906102d59190611a84565b6107ad565b6040516102e791906115ec565b60405180910390f35b5f7f80ac58cd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806103ba57507f5b5e139f000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806103ca57506103c98261083b565b5b9050919050565b60605f80546103df90611aef565b80601f016020809104026020016040519081016040528092919081815260200182805461040b90611aef565b80156104565780601f1061042d57610100808354040283529160200191610456565b820191905f5260205f20905b81548152906001019060200180831161043957829003601f168201915b5050505050905090565b5f61046a826108a4565b506104748261092a565b9050919050565b61048d8282610488610963565b61096a565b5050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610501575f6040517f64a0ae920000000000000000000000000000000000000000000000000000000081526004016104f8919061174c565b60405180910390fd5b5f610514838361050f610963565b61097c565b90508373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461058a578382826040517f64283d7b00000000000000000000000000000000000000000000000000000000815260040161058193929190611b1f565b60405180910390fd5b50505050565b61059a8282610b87565b5050565b6105b883838360405180602001604052805f81525061072a565b505050565b5f6105c7826108a4565b9050919050565b5f8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361063f575f6040517f89c62b64000000000000000000000000000000000000000000000000000000008152600401610636919061174c565b60405180910390fd5b60035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b60606001805461069390611aef565b80601f01602080910402602001604051908101604052809291908181526020018280546106bf90611aef565b801561070a5780601f106106e15761010080835404028352916020019161070a565b820191905f5260205f20905b8154815290600101906020018083116106ed57829003601f168201915b5050505050905090565b61072661071f610963565b8383610c7a565b5050565b610735848484610491565b61074184848484610de3565b50505050565b6060610752826108a4565b505f61075c610f95565b90505f81511161077a5760405180602001604052805f8152506107a5565b8061078484610fab565b604051602001610795929190611b8e565b6040516020818303038152906040525b915050919050565b5f60055f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16905092915050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f806108af83611075565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361092157826040517f7e2732890000000000000000000000000000000000000000000000000000000081526004016109189190611857565b60405180910390fd5b80915050919050565b5f60045f8381526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b5f33905090565b61097783838360016110ae565b505050565b5f8061098784611075565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146109c8576109c781848661126d565b5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610a5357610a075f855f806110ae565b600160035f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825403925050819055505b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614610ad257600160035f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055505b8460025f8681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550838573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a4809150509392505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610bf7575f6040517f64a0ae92000000000000000000000000000000000000000000000000000000008152600401610bee919061174c565b60405180910390fd5b5f610c0383835f61097c565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610c75575f6040517f73c6ac6e000000000000000000000000000000000000000000000000000000008152600401610c6c919061174c565b60405180910390fd5b505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610cea57816040517f5b08ba18000000000000000000000000000000000000000000000000000000008152600401610ce1919061174c565b60405180910390fd5b8060055f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051610dd691906115ec565b60405180910390a3505050565b5f8373ffffffffffffffffffffffffffffffffffffffff163b1115610f8f578273ffffffffffffffffffffffffffffffffffffffff1663150b7a02610e26610963565b8685856040518563ffffffff1660e01b8152600401610e489493929190611c03565b6020604051808303815f875af1925050508015610e8357506040513d601f19601f82011682018060405250810190610e809190611c61565b60015b610f04573d805f8114610eb1576040519150601f19603f3d011682016040523d82523d5f602084013e610eb6565b606091505b505f815103610efc57836040517f64a0ae92000000000000000000000000000000000000000000000000000000008152600401610ef3919061174c565b60405180910390fd5b805181602001fd5b63150b7a0260e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614610f8d57836040517f64a0ae92000000000000000000000000000000000000000000000000000000008152600401610f84919061174c565b60405180910390fd5b505b50505050565b606060405180602001604052805f815250905090565b60605f6001610fb984611330565b0190505f8167ffffffffffffffff811115610fd757610fd66118e0565b5b6040519080825280601f01601f1916602001820160405280156110095781602001600182028036833780820191505090505b5090505f82602001820190505b60011561106a578080600190039150507f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a858161105f5761105e611c8c565b5b0494505f8503611016575b819350505050919050565b5f60025f8381526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b80806110e657505f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614155b15611218575f6110f5846108a4565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415801561115f57508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b8015611172575061117081846107ad565b155b156111b457826040517fa9fbf51f0000000000000000000000000000000000000000000000000000000081526004016111ab919061174c565b60405180910390fd5b811561121657838573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b8360045f8581526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505050565b611278838383611481565b61132b575f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036112ec57806040517f7e2732890000000000000000000000000000000000000000000000000000000081526004016112e39190611857565b60405180910390fd5b81816040517f177e802f000000000000000000000000000000000000000000000000000000008152600401611322929190611cb9565b60405180910390fd5b505050565b5f805f90507a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000831061138c577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000838161138257611381611c8c565b5b0492506040810190505b6d04ee2d6d415b85acef810000000083106113c9576d04ee2d6d415b85acef810000000083816113bf576113be611c8c565b5b0492506020810190505b662386f26fc1000083106113f857662386f26fc1000083816113ee576113ed611c8c565b5b0492506010810190505b6305f5e1008310611421576305f5e100838161141757611416611c8c565b5b0492506008810190505b612710831061144657612710838161143c5761143b611c8c565b5b0492506004810190505b60648310611469576064838161145f5761145e611c8c565b5b0492506002810190505b600a8310611478576001810190505b80915050919050565b5f8073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415801561153857508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614806114f957506114f884846107ad565b5b8061153757508273ffffffffffffffffffffffffffffffffffffffff1661151f8361092a565b73ffffffffffffffffffffffffffffffffffffffff16145b5b90509392505050565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61158681611552565b8114611590575f80fd5b50565b5f813590506115a18161157d565b92915050565b5f602082840312156115bc576115bb61154a565b5b5f6115c984828501611593565b91505092915050565b5f8115159050919050565b6115e6816115d2565b82525050565b5f6020820190506115ff5f8301846115dd565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561163c578082015181840152602081019050611621565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61166182611605565b61166b818561160f565b935061167b81856020860161161f565b61168481611647565b840191505092915050565b5f6020820190508181035f8301526116a78184611657565b905092915050565b5f819050919050565b6116c1816116af565b81146116cb575f80fd5b50565b5f813590506116dc816116b8565b92915050565b5f602082840312156116f7576116f661154a565b5b5f611704848285016116ce565b91505092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6117368261170d565b9050919050565b6117468161172c565b82525050565b5f60208201905061175f5f83018461173d565b92915050565b61176e8161172c565b8114611778575f80fd5b50565b5f8135905061178981611765565b92915050565b5f80604083850312156117a5576117a461154a565b5b5f6117b28582860161177b565b92505060206117c3858286016116ce565b9150509250929050565b5f805f606084860312156117e4576117e361154a565b5b5f6117f18682870161177b565b93505060206118028682870161177b565b9250506040611813868287016116ce565b9150509250925092565b5f602082840312156118325761183161154a565b5b5f61183f8482850161177b565b91505092915050565b611851816116af565b82525050565b5f60208201905061186a5f830184611848565b92915050565b611879816115d2565b8114611883575f80fd5b50565b5f8135905061189481611870565b92915050565b5f80604083850312156118b0576118af61154a565b5b5f6118bd8582860161177b565b92505060206118ce85828601611886565b9150509250929050565b5f80fd5b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61191682611647565b810181811067ffffffffffffffff82111715611935576119346118e0565b5b80604052505050565b5f611947611541565b9050611953828261190d565b919050565b5f67ffffffffffffffff821115611972576119716118e0565b5b61197b82611647565b9050602081019050919050565b828183375f83830152505050565b5f6119a86119a384611958565b61193e565b9050828152602081018484840111156119c4576119c36118dc565b5b6119cf848285611988565b509392505050565b5f82601f8301126119eb576119ea6118d8565b5b81356119fb848260208601611996565b91505092915050565b5f805f8060808587031215611a1c57611a1b61154a565b5b5f611a298782880161177b565b9450506020611a3a8782880161177b565b9350506040611a4b878288016116ce565b925050606085013567ffffffffffffffff811115611a6c57611a6b61154e565b5b611a78878288016119d7565b91505092959194509250565b5f8060408385031215611a9a57611a9961154a565b5b5f611aa78582860161177b565b9250506020611ab88582860161177b565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680611b0657607f821691505b602082108103611b1957611b18611ac2565b5b50919050565b5f606082019050611b325f83018661173d565b611b3f6020830185611848565b611b4c604083018461173d565b949350505050565b5f81905092915050565b5f611b6882611605565b611b728185611b54565b9350611b8281856020860161161f565b80840191505092915050565b5f611b998285611b5e565b9150611ba58284611b5e565b91508190509392505050565b5f81519050919050565b5f82825260208201905092915050565b5f611bd582611bb1565b611bdf8185611bbb565b9350611bef81856020860161161f565b611bf881611647565b840191505092915050565b5f608082019050611c165f83018761173d565b611c23602083018661173d565b611c306040830185611848565b8181036060830152611c428184611bcb565b905095945050505050565b5f81519050611c5b8161157d565b92915050565b5f60208284031215611c7657611c7561154a565b5b5f611c8384828501611c4d565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f604082019050611ccc5f83018561173d565b611cd96020830184611848565b939250505056fea26469706673582212207439b47c2a9a1624955997732075917bbf1da26949d000c778f561eb5687576164736f6c63430008180033"; pub const ERC1155_TEST_TOKEN_BYTES: &str = "608060405234801562000010575f80fd5b50604051620024eb380380620024eb8339818101604052810190620000369190620001ea565b8062000048816200005060201b60201c565b505062000554565b806002908162000061919062000470565b5050565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b620000c6826200007e565b810181811067ffffffffffffffff82111715620000e857620000e76200008e565b5b80604052505050565b5f620000fc62000065565b90506200010a8282620000bb565b919050565b5f67ffffffffffffffff8211156200012c576200012b6200008e565b5b62000137826200007e565b9050602081019050919050565b5f5b838110156200016357808201518184015260208101905062000146565b5f8484015250505050565b5f620001846200017e846200010f565b620000f1565b905082815260208101848484011115620001a357620001a26200007a565b5b620001b084828562000144565b509392505050565b5f82601f830112620001cf57620001ce62000076565b5b8151620001e18482602086016200016e565b91505092915050565b5f602082840312156200020257620002016200006e565b5b5f82015167ffffffffffffffff81111562000222576200022162000072565b5b6200023084828501620001b8565b91505092915050565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806200028857607f821691505b6020821081036200029e576200029d62000243565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620003027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82620002c5565b6200030e8683620002c5565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f62000358620003526200034c8462000326565b6200032f565b62000326565b9050919050565b5f819050919050565b620003738362000338565b6200038b62000382826200035f565b848454620002d1565b825550505050565b5f90565b620003a162000393565b620003ae81848462000368565b505050565b5b81811015620003d557620003c95f8262000397565b600181019050620003b4565b5050565b601f8211156200042457620003ee81620002a4565b620003f984620002b6565b8101602085101562000409578190505b620004216200041885620002b6565b830182620003b3565b50505b505050565b5f82821c905092915050565b5f620004465f198460080262000429565b1980831691505092915050565b5f62000460838362000435565b9150826002028217905092915050565b6200047b8262000239565b67ffffffffffffffff8111156200049757620004966200008e565b5b620004a3825462000270565b620004b0828285620003d9565b5f60209050601f831160018114620004e6575f8415620004d1578287015190505b620004dd858262000453565b8655506200054c565b601f198416620004f686620002a4565b5f5b828110156200051f57848901518255600182019150602085019450602081019050620004f8565b868310156200053f57848901516200053b601f89168262000435565b8355505b6001600288020188555050505b505050505050565b611f8980620005625f395ff3fe608060405234801561000f575f80fd5b5060043610610090575f3560e01c80634e1273f4116100645780634e1273f414610140578063731133e914610170578063a22cb4651461018c578063e985e9c5146101a8578063f242432a146101d857610090565b8062fdd58e1461009457806301ffc9a7146100c45780630e89341c146100f45780632eb2c2d614610124575b5f80fd5b6100ae60048036038101906100a991906113bd565b6101f4565b6040516100bb919061140a565b60405180910390f35b6100de60048036038101906100d99190611478565b610249565b6040516100eb91906114bd565b60405180910390f35b61010e600480360381019061010991906114d6565b61032a565b60405161011b919061158b565b60405180910390f35b61013e6004803603810190610139919061179b565b6103bc565b005b61015a60048036038101906101559190611926565b610463565b6040516101679190611a53565b60405180910390f35b61018a60048036038101906101859190611a73565b61056a565b005b6101a660048036038101906101a19190611b1d565b61057c565b005b6101c260048036038101906101bd9190611b5b565b610592565b6040516101cf91906114bd565b60405180910390f35b6101f260048036038101906101ed9190611b99565b610620565b005b5f805f8381526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905092915050565b5f7fd9b67a26000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061031357507f0e89341c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806103235750610322826106c7565b5b9050919050565b60606002805461033990611c59565b80601f016020809104026020016040519081016040528092919081815260200182805461036590611c59565b80156103b05780601f10610387576101008083540402835291602001916103b0565b820191905f5260205f20905b81548152906001019060200180831161039357829003601f168201915b50505050509050919050565b5f6103c5610730565b90508073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161415801561040a57506104088682610592565b155b1561044e5780866040517fe237d922000000000000000000000000000000000000000000000000000000008152600401610445929190611c98565b60405180910390fd5b61045b8686868686610737565b505050505050565b606081518351146104af57815183516040517f5b0599910000000000000000000000000000000000000000000000000000000081526004016104a6929190611cbf565b60405180910390fd5b5f835167ffffffffffffffff8111156104cb576104ca6115af565b5b6040519080825280602002602001820160405280156104f95781602001602082028036833780820191505090505b5090505f5b845181101561055f5761053561051d828761082b90919063ffffffff16565b610530838761083e90919063ffffffff16565b6101f4565b82828151811061054857610547611ce6565b5b6020026020010181815250508060010190506104fe565b508091505092915050565b61057684848484610851565b50505050565b61058e610587610730565b83836108e6565b5050565b5f60015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16905092915050565b5f610629610730565b90508073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161415801561066e575061066c8682610592565b155b156106b25780866040517fe237d9220000000000000000000000000000000000000000000000000000000081526004016106a9929190611c98565b60405180910390fd5b6106bf8686868686610a4f565b505050505050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f33905090565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036107a7575f6040517f57f447ce00000000000000000000000000000000000000000000000000000000815260040161079e9190611d13565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603610817575f6040517f01a8351400000000000000000000000000000000000000000000000000000000815260040161080e9190611d13565b60405180910390fd5b6108248585858585610b55565b5050505050565b5f60208202602084010151905092915050565b5f60208202602084010151905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036108c1575f6040517f57f447ce0000000000000000000000000000000000000000000000000000000081526004016108b89190611d13565b60405180910390fd5b5f806108cd8585610c01565b915091506108de5f87848487610b55565b505050505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610956575f6040517fced3e10000000000000000000000000000000000000000000000000000000000815260040161094d9190611d13565b60405180910390fd5b8060015f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051610a4291906114bd565b60405180910390a3505050565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603610abf575f6040517f57f447ce000000000000000000000000000000000000000000000000000000008152600401610ab69190611d13565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603610b2f575f6040517f01a83514000000000000000000000000000000000000000000000000000000008152600401610b269190611d13565b60405180910390fd5b5f80610b3b8585610c01565b91509150610b4c8787848487610b55565b50505050505050565b610b6185858585610c31565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614610bfa575f610b9d610730565b90506001845103610be9575f610bbc5f8661083e90919063ffffffff16565b90505f610bd25f8661083e90919063ffffffff16565b9050610be2838989858589610fc1565b5050610bf8565b610bf7818787878787611170565b5b505b5050505050565b60608060405191506001825283602083015260408201905060018152826020820152604081016040529250929050565b8051825114610c7b57815181516040517f5b059991000000000000000000000000000000000000000000000000000000008152600401610c72929190611cbf565b60405180910390fd5b5f610c84610730565b90505f5b8351811015610e80575f610ca5828661083e90919063ffffffff16565b90505f610cbb838661083e90919063ffffffff16565b90505f73ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614610dde575f805f8481526020019081526020015f205f8a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905081811015610d8a57888183856040517f03dee4c5000000000000000000000000000000000000000000000000000000008152600401610d819493929190611d2c565b60405180910390fd5b8181035f808581526020019081526020015f205f8b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550505b5f73ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614610e7357805f808481526020019081526020015f205f8973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610e6b9190611d9c565b925050819055505b5050806001019050610c88565b506001835103610f3b575f610e9e5f8561083e90919063ffffffff16565b90505f610eb45f8561083e90919063ffffffff16565b90508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628585604051610f2c929190611cbf565b60405180910390a45050610fba565b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8686604051610fb1929190611dcf565b60405180910390a45b5050505050565b5f8473ffffffffffffffffffffffffffffffffffffffff163b1115611168578373ffffffffffffffffffffffffffffffffffffffff1663f23a6e6187878686866040518663ffffffff1660e01b8152600401611021959493929190611e56565b6020604051808303815f875af192505050801561105c57506040513d601f19601f820116820180604052508101906110599190611ec2565b60015b6110dd573d805f811461108a576040519150601f19603f3d011682016040523d82523d5f602084013e61108f565b606091505b505f8151036110d557846040517f57f447ce0000000000000000000000000000000000000000000000000000000081526004016110cc9190611d13565b60405180910390fd5b805181602001fd5b63f23a6e6160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461116657846040517f57f447ce00000000000000000000000000000000000000000000000000000000815260040161115d9190611d13565b60405180910390fd5b505b505050505050565b5f8473ffffffffffffffffffffffffffffffffffffffff163b1115611317578373ffffffffffffffffffffffffffffffffffffffff1663bc197c8187878686866040518663ffffffff1660e01b81526004016111d0959493929190611eed565b6020604051808303815f875af192505050801561120b57506040513d601f19601f820116820180604052508101906112089190611ec2565b60015b61128c573d805f8114611239576040519150601f19603f3d011682016040523d82523d5f602084013e61123e565b606091505b505f81510361128457846040517f57f447ce00000000000000000000000000000000000000000000000000000000815260040161127b9190611d13565b60405180910390fd5b805181602001fd5b63bc197c8160e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161461131557846040517f57f447ce00000000000000000000000000000000000000000000000000000000815260040161130c9190611d13565b60405180910390fd5b505b505050505050565b5f604051905090565b5f80fd5b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61135982611330565b9050919050565b6113698161134f565b8114611373575f80fd5b50565b5f8135905061138481611360565b92915050565b5f819050919050565b61139c8161138a565b81146113a6575f80fd5b50565b5f813590506113b781611393565b92915050565b5f80604083850312156113d3576113d2611328565b5b5f6113e085828601611376565b92505060206113f1858286016113a9565b9150509250929050565b6114048161138a565b82525050565b5f60208201905061141d5f8301846113fb565b92915050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61145781611423565b8114611461575f80fd5b50565b5f813590506114728161144e565b92915050565b5f6020828403121561148d5761148c611328565b5b5f61149a84828501611464565b91505092915050565b5f8115159050919050565b6114b7816114a3565b82525050565b5f6020820190506114d05f8301846114ae565b92915050565b5f602082840312156114eb576114ea611328565b5b5f6114f8848285016113a9565b91505092915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561153857808201518184015260208101905061151d565b5f8484015250505050565b5f601f19601f8301169050919050565b5f61155d82611501565b611567818561150b565b935061157781856020860161151b565b61158081611543565b840191505092915050565b5f6020820190508181035f8301526115a38184611553565b905092915050565b5f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6115e582611543565b810181811067ffffffffffffffff82111715611604576116036115af565b5b80604052505050565b5f61161661131f565b905061162282826115dc565b919050565b5f67ffffffffffffffff821115611641576116406115af565b5b602082029050602081019050919050565b5f80fd5b5f61166861166384611627565b61160d565b9050808382526020820190506020840283018581111561168b5761168a611652565b5b835b818110156116b457806116a088826113a9565b84526020840193505060208101905061168d565b5050509392505050565b5f82601f8301126116d2576116d16115ab565b5b81356116e2848260208601611656565b91505092915050565b5f80fd5b5f67ffffffffffffffff821115611709576117086115af565b5b61171282611543565b9050602081019050919050565b828183375f83830152505050565b5f61173f61173a846116ef565b61160d565b90508281526020810184848401111561175b5761175a6116eb565b5b61176684828561171f565b509392505050565b5f82601f830112611782576117816115ab565b5b813561179284826020860161172d565b91505092915050565b5f805f805f60a086880312156117b4576117b3611328565b5b5f6117c188828901611376565b95505060206117d288828901611376565b945050604086013567ffffffffffffffff8111156117f3576117f261132c565b5b6117ff888289016116be565b935050606086013567ffffffffffffffff8111156118205761181f61132c565b5b61182c888289016116be565b925050608086013567ffffffffffffffff81111561184d5761184c61132c565b5b6118598882890161176e565b9150509295509295909350565b5f67ffffffffffffffff8211156118805761187f6115af565b5b602082029050602081019050919050565b5f6118a361189e84611866565b61160d565b905080838252602082019050602084028301858111156118c6576118c5611652565b5b835b818110156118ef57806118db8882611376565b8452602084019350506020810190506118c8565b5050509392505050565b5f82601f83011261190d5761190c6115ab565b5b813561191d848260208601611891565b91505092915050565b5f806040838503121561193c5761193b611328565b5b5f83013567ffffffffffffffff8111156119595761195861132c565b5b611965858286016118f9565b925050602083013567ffffffffffffffff8111156119865761198561132c565b5b611992858286016116be565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b6119ce8161138a565b82525050565b5f6119df83836119c5565b60208301905092915050565b5f602082019050919050565b5f611a018261199c565b611a0b81856119a6565b9350611a16836119b6565b805f5b83811015611a46578151611a2d88826119d4565b9750611a38836119eb565b925050600181019050611a19565b5085935050505092915050565b5f6020820190508181035f830152611a6b81846119f7565b905092915050565b5f805f8060808587031215611a8b57611a8a611328565b5b5f611a9887828801611376565b9450506020611aa9878288016113a9565b9350506040611aba878288016113a9565b925050606085013567ffffffffffffffff811115611adb57611ada61132c565b5b611ae78782880161176e565b91505092959194509250565b611afc816114a3565b8114611b06575f80fd5b50565b5f81359050611b1781611af3565b92915050565b5f8060408385031215611b3357611b32611328565b5b5f611b4085828601611376565b9250506020611b5185828601611b09565b9150509250929050565b5f8060408385031215611b7157611b70611328565b5b5f611b7e85828601611376565b9250506020611b8f85828601611376565b9150509250929050565b5f805f805f60a08688031215611bb257611bb1611328565b5b5f611bbf88828901611376565b9550506020611bd088828901611376565b9450506040611be1888289016113a9565b9350506060611bf2888289016113a9565b925050608086013567ffffffffffffffff811115611c1357611c1261132c565b5b611c1f8882890161176e565b9150509295509295909350565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680611c7057607f821691505b602082108103611c8357611c82611c2c565b5b50919050565b611c928161134f565b82525050565b5f604082019050611cab5f830185611c89565b611cb86020830184611c89565b9392505050565b5f604082019050611cd25f8301856113fb565b611cdf60208301846113fb565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f602082019050611d265f830184611c89565b92915050565b5f608082019050611d3f5f830187611c89565b611d4c60208301866113fb565b611d5960408301856113fb565b611d6660608301846113fb565b95945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f611da68261138a565b9150611db18361138a565b9250828201905080821115611dc957611dc8611d6f565b5b92915050565b5f6040820190508181035f830152611de781856119f7565b90508181036020830152611dfb81846119f7565b90509392505050565b5f81519050919050565b5f82825260208201905092915050565b5f611e2882611e04565b611e328185611e0e565b9350611e4281856020860161151b565b611e4b81611543565b840191505092915050565b5f60a082019050611e695f830188611c89565b611e766020830187611c89565b611e8360408301866113fb565b611e9060608301856113fb565b8181036080830152611ea28184611e1e565b90509695505050505050565b5f81519050611ebc8161144e565b92915050565b5f60208284031215611ed757611ed6611328565b5b5f611ee484828501611eae565b91505092915050565b5f60a082019050611f005f830188611c89565b611f0d6020830187611c89565b8181036040830152611f1f81866119f7565b90508181036060830152611f3381856119f7565b90508181036080830152611f478184611e1e565b9050969550505050505056fea26469706673582212203835581c6344b12728c44fa4d9e912cd60e64012c1b772bb703d1c36825c16fd64736f6c63430008180033"; pub const NFT_SWAP_CONTRACT_BYTES: &str = "60a060405234801562000010575f80fd5b50604051620055a2380380620055a2833981810160405281019062000036919062000147565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603620000a7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200009e90620001fb565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff1681525050506200021b565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6200011182620000e6565b9050919050565b620001238162000105565b81146200012e575f80fd5b50565b5f81519050620001418162000118565b92915050565b5f602082840312156200015f576200015e620000e2565b5b5f6200016e8482850162000131565b91505092915050565b5f82825260208201905092915050565b7f66656541646472657373206d757374206e6f74206265207a65726f20616464725f8201527f6573730000000000000000000000000000000000000000000000000000000000602082015250565b5f620001e360238362000177565b9150620001f08262000187565b604082019050919050565b5f6020820190508181035f8301526200021481620001d5565b9050919050565b608051615360620002425f395f8181612aef01528181612b8a0152612f4801526153605ff3fe608060405260043610610113575f3560e01c80639b4603f21161009f578063cc90c19911610063578063cc90c1991461038e578063d6a71eb4146103b6578063e06cf966146103de578063efccb9eb14610408578063f23a6e611461044657610113565b80639b4603f2146102be578063b27e46fb146102da578063bc197c8114610302578063c8d9009b1461033e578063c92cd12d1461036657610113565b8063150b7a02116100e6578063150b7a02146101cb5780633e6af5f21461020757806346b95ac71461022f57806365e266171461026e5780636e6bf6d21461029657610113565b806301ffc9a71461011757806305ec158d146101535780630f235fce1461017b578063146e5b24146101a3575b5f80fd5b348015610122575f80fd5b5061013d6004803603810190610138919061386f565b610482565b60405161014a91906138b4565b60405180910390f35b34801561015e575f80fd5b506101796004803603810190610174919061398d565b610563565b005b348015610186575f80fd5b506101a1600480360381019061019c9190613a2a565b610823565b005b3480156101ae575f80fd5b506101c960048036038101906101c49190613ab3565b610add565b005b3480156101d6575f80fd5b506101f160048036038101906101ec9190613bb1565b610cc3565b6040516101fe9190613c44565b60405180910390f35b348015610212575f80fd5b5061022d60048036038101906102289190613ab3565b611112565b005b34801561023a575f80fd5b5061025560048036038101906102509190613c5d565b611423565b6040516102659493929190613d53565b60405180910390f35b348015610279575f80fd5b50610294600480360381019061028f9190613ab3565b611485565b005b3480156102a1575f80fd5b506102bc60048036038101906102b79190613a2a565b6118e9565b005b6102d860048036038101906102d39190613dc0565b611ba4565b005b3480156102e5575f80fd5b5061030060048036038101906102fb919061398d565b611eda565b005b34801561030d575f80fd5b5061032860048036038101906103239190613eb2565b612199565b6040516103359190613c44565b60405180910390f35b348015610349575f80fd5b50610364600480360381019061035f9190613a2a565b6121d5565b005b348015610371575f80fd5b5061038c6004803603810190610387919061398d565b6124fe565b005b348015610399575f80fd5b506103b460048036038101906103af9190613ab3565b61282c565b005b3480156103c1575f80fd5b506103dc60048036038101906103d79190613f89565b612bdc565b005b3480156103e9575f80fd5b506103f2612f46565b6040516103ff919061405c565b60405180910390f35b348015610413575f80fd5b5061042e60048036038101906104299190613c5d565b612f6a565b60405161043d939291906140bb565b60405180910390f35b348015610451575f80fd5b5061046c600480360381019061046791906140f0565b612fb6565b6040516104799190613c44565b60405180910390f35b5f7f4e2312e0000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061054c57507f150b7a02000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061055c575061055b8261344a565b5b9050919050565b6001600381111561057757610576613ce0565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff1660038111156105a9576105a8613ce0565b5b146105e9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105e090614206565b60405180910390fd5b5f600387336002896040516020016106019190614244565b60405160208183030381529060405260405161061d91906142ca565b602060405180830381855afa158015610638573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061065b91906142f4565b888888886040516020016106759796959493929190614384565b60405160208183030381529060405260405161069191906142ca565b602060405180830381855afa1580156106ac573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610736576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161072d9061444e565b60405180910390fd5b60035f808a81526020019081526020015f205f0160186101000a81548160ff0219169083600381111561076c5761076b613ce0565b5b02179055507fac509cdcc7ddb189f81fff6f4824f5c95076e64c3bdce542c50feaa6779afd73886040516107a0919061447b565b60405180910390a15f8490508073ffffffffffffffffffffffffffffffffffffffff1663f242432a303387876040518563ffffffff1660e01b81526004016107eb94939291906144d6565b5f604051808303815f87803b158015610802575f80fd5b505af1158015610814573d5f803e3d5ffd5b50505050505050505050505050565b6001600381111561083757610836613ce0565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff16600381111561086957610868613ce0565b5b146108a9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108a090614206565b60405180910390fd5b5f60038633878787876040516020016108c79695949392919061452c565b6040516020818303038152906040526040516108e391906142ca565b602060405180830381855afa1580156108fe573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610988576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161097f9061444e565b60405180910390fd5b5f808881526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff164210156109f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109ea9061460b565b60405180910390fd5b60035f808981526020019081526020015f205f0160186101000a81548160ff02191690836003811115610a2957610a28613ce0565b5b02179055507f5dedc4f52b757d9112d09ca0b2f022927104d54e3f54da091587e8ad1921907287604051610a5d919061447b565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b8152600401610aa693929190614629565b5f604051808303815f87803b158015610abd575f80fd5b505af1158015610acf573d5f803e3d5ffd5b505050505050505050505050565b60016004811115610af157610af0613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff166004811115610b2457610b23613ce0565b5b14610b64576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b5b90614206565b60405180910390fd5b5f600387878733888888604051602001610b84979695949392919061465e565b604051602081830303815290604052604051610ba091906142ca565b602060405180830381855afa158015610bbb573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610c46576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c3d9061444e565b60405180910390fd5b600260015f8a81526020019081526020015f205f01601c6101000a81548160ff02191690836004811115610c7d57610c7c613ce0565b5b02179055507f9c45e43e2ef051f70491ffd5221bf02ab37e1324128714ef9610df5f24fc9fb588604051610cb1919061447b565b60405180910390a15050505050505050565b5f808383810190610cd49190614807565b90505f6003811115610ce957610ce8613ce0565b5b5f80835f015181526020019081526020015f205f0160189054906101000a900460ff166003811115610d1e57610d1d613ce0565b5b14610d5e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d55906148a2565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816020015173ffffffffffffffffffffffffffffffffffffffff1603610dd0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610dc79061490a565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816040015173ffffffffffffffffffffffffffffffffffffffff1603610e42576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e3990614972565b60405180910390fd5b806040015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610eb4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610eab90614a00565b60405180910390fd5b8573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614610f22576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f1990614a68565b60405180910390fd5b610f2f81602001516134b3565b15610f6f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f6690614ad0565b60405180910390fd5b5f60038260200151888460600151856080015186604001518b604051602001610f9d9695949392919061452c565b604051602081830303815290604052604051610fb991906142ca565b602060405180830381855afa158015610fd4573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018360a0015163ffffffff1681526020016001600381111561102457611023613ce0565b5b8152505f80845f015181526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548160ff021916908360038111156110bb576110ba613ce0565b5b02179055509050507ff1dc11bbb6d7542c4267ecf1d370ff4c7092518633ecae9939e8488f4e53d2ad825f01516040516110f5919061447b565b60405180910390a163150b7a0260e01b9250505095945050505050565b6001600481111561112657611125613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff16600481111561115957611158613ce0565b5b14611199576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161119090614206565b60405180910390fd5b5f6003878787336002896040516020016111b39190614244565b6040516020818303038152906040526040516111cf91906142ca565b602060405180830381855afa1580156111ea573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061120d91906142f4565b8888604051602001611225979695949392919061465e565b60405160208183030381529060405260405161124191906142ca565b602060405180830381855afa15801561125c573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146112e7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112de9061444e565b60405180910390fd5b600460015f8a81526020019081526020015f205f01601c6101000a81548160ff0219169083600481111561131e5761131d613ce0565b5b02179055507f45169a52eef651b20a81474b50b8a5d83225225fcd097ef3cf7952d9ab304f278885604051611354929190614aee565b60405180910390a15f86886113699190614b42565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036113e7573373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f193505050501580156113e1573d5f803e3d5ffd5b50611418565b5f83905061141633838373ffffffffffffffffffffffffffffffffffffffff166134c49092919063ffffffff16565b505b505050505050505050565b6001602052805f5260405f205f91509050805f015f9054906101000a900460601b90805f0160149054906101000a900463ffffffff1690805f0160189054906101000a900463ffffffff1690805f01601c9054906101000a900460ff16905084565b6001600481111561149957611498613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff1660048111156114cc576114cb613ce0565b5b148061151c5750600260048111156114e7576114e6613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff16600481111561151a57611519613ce0565b5b145b61155b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161155290614be5565b60405180910390fd5b5f60038787873388888860405160200161157b979695949392919061465e565b60405160208183030381529060405260405161159791906142ca565b602060405180830381855afa1580156115b2573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461163d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116349061444e565b60405180910390fd5b6002600481111561165157611650613ce0565b5b60015f8a81526020019081526020015f205f01601c9054906101000a900460ff16600481111561168457611683613ce0565b5b036116f65760015f8981526020019081526020015f205f0160189054906101000a900463ffffffff1663ffffffff164210156116f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116ec9061460b565b60405180910390fd5b5b6001600481111561170a57611709613ce0565b5b60015f8a81526020019081526020015f205f01601c9054906101000a900460ff16600481111561173d5761173c613ce0565b5b036117af5760015f8981526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff164210156117ae576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117a590614c73565b60405180910390fd5b5b600460015f8a81526020019081526020015f205f01601c6101000a81548160ff021916908360048111156117e6576117e5613ce0565b5b02179055507fbdd7a4be6d82798a500b59077706b12d3f45acf5504828919f92501307b2b9538860405161181a919061447b565b60405180910390a15f868861182f9190614b42565b90505f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036118ad573373ffffffffffffffffffffffffffffffffffffffff166108fc8290811502906040515f60405180830381858888f193505050501580156118a7573d5f803e3d5ffd5b506118de565b5f8390506118dc33838373ffffffffffffffffffffffffffffffffffffffff166134c49092919063ffffffff16565b505b505050505050505050565b600160038111156118fd576118fc613ce0565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff16600381111561192f5761192e613ce0565b5b1461196f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161196690614206565b60405180910390fd5b5f600386336002886040516020016119879190614244565b6040516020818303038152906040526040516119a391906142ca565b602060405180830381855afa1580156119be573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906119e191906142f4565b8787876040516020016119f99695949392919061452c565b604051602081830303815290604052604051611a1591906142ca565b602060405180830381855afa158015611a30573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614611aba576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ab19061444e565b60405180910390fd5b60035f808981526020019081526020015f205f0160186101000a81548160ff02191690836003811115611af057611aef613ce0565b5b02179055507fac509cdcc7ddb189f81fff6f4824f5c95076e64c3bdce542c50feaa6779afd7387604051611b24919061447b565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b8152600401611b6d93929190614629565b5f604051808303815f87803b158015611b84575f80fd5b505af1158015611b96573d5f803e3d5ffd5b505050505050505050505050565b5f6004811115611bb757611bb6613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff166004811115611bea57611be9613ce0565b5b14611c2a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c2190614d01565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603611c98576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c8f90614d8f565b60405180910390fd5b5f3411611cda576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611cd190614e1d565b60405180910390fd5b853411611d1c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d1390614eab565b60405180910390fd5b5f60038734611d2b9190614ec9565b88883389895f604051602001611d47979695949392919061465e565b604051602081830303815290604052604051611d6391906142ca565b602060405180830381855afa158015611d7e573d5f803e3d5ffd5b5050506040515160601b90506040518060800160405280826bffffffffffffffffffffffff191681526020018463ffffffff1681526020018363ffffffff16815260200160016004811115611dd657611dd5613ce0565b5b81525060015f8a81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548163ffffffff021916908363ffffffff1602179055506060820151815f01601c6101000a81548160ff02191690836004811115611e9157611e90613ce0565b5b02179055509050507ffc6cdccd1d98ded12074a9ebc7f6ab74fed1814ff57f4fb5202464d8938bd93588604051611ec8919061447b565b60405180910390a15050505050505050565b60016003811115611eee57611eed613ce0565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff166003811115611f2057611f1f613ce0565b5b14611f60576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f5790614206565b60405180910390fd5b5f600387338888888888604051602001611f809796959493929190614384565b604051602081830303815290604052604051611f9c91906142ca565b602060405180830381855afa158015611fb7573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614612041576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120389061444e565b60405180910390fd5b5f808981526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff164210156120ac576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120a39061460b565b60405180910390fd5b60035f808a81526020019081526020015f205f0160186101000a81548160ff021916908360038111156120e2576120e1613ce0565b5b02179055507f5dedc4f52b757d9112d09ca0b2f022927104d54e3f54da091587e8ad1921907288604051612116919061447b565b60405180910390a15f8490508073ffffffffffffffffffffffffffffffffffffffff1663f242432a303387876040518563ffffffff1660e01b815260040161216194939291906144d6565b5f604051808303815f87803b158015612178575f80fd5b505af115801561218a573d5f803e3d5ffd5b50505050505050505050505050565b5f6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016121cc90614f46565b60405180910390fd5b600160038111156121e9576121e8613ce0565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff16600381111561221b5761221a613ce0565b5b1461225b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161225290614206565b60405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146122c9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122c090614fae565b60405180910390fd5b5f60033387876002886040516020016122e29190614244565b6040516020818303038152906040526040516122fe91906142ca565b602060405180830381855afa158015612319573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061233c91906142f4565b87876040516020016123539695949392919061452c565b60405160208183030381529060405260405161236f91906142ca565b602060405180830381855afa15801561238a573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614612414576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161240b9061444e565b60405180910390fd5b60025f808981526020019081526020015f205f0160186101000a81548160ff0219169083600381111561244a57612449613ce0565b5b02179055507fad62ed075fe8969df63026f45152d6e996a0697a736a8de92ee85ae9c9958cf08760405161247e919061447b565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b81526004016124c793929190614629565b5f604051808303815f87803b1580156124de575f80fd5b505af11580156124f0573d5f803e3d5ffd5b505050505050505050505050565b6001600381111561251257612511613ce0565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff16600381111561254457612543613ce0565b5b14612584576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161257b90614206565b60405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146125f2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016125e990614fae565b60405180910390fd5b5f600333888860028960405160200161260b9190614244565b60405160208183030381529060405260405161262791906142ca565b602060405180830381855afa158015612642573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061266591906142f4565b88888860405160200161267e9796959493929190614384565b60405160208183030381529060405260405161269a91906142ca565b602060405180830381855afa1580156126b5573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461273f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016127369061444e565b60405180910390fd5b60025f808a81526020019081526020015f205f0160186101000a81548160ff0219169083600381111561277557612774613ce0565b5b02179055507fad62ed075fe8969df63026f45152d6e996a0697a736a8de92ee85ae9c9958cf0886040516127a9919061447b565b60405180910390a15f8490508073ffffffffffffffffffffffffffffffffffffffff1663f242432a303387876040518563ffffffff1660e01b81526004016127f494939291906144d6565b5f604051808303815f87803b15801561280b575f80fd5b505af115801561281d573d5f803e3d5ffd5b50505050505050505050505050565b600260048111156128405761283f613ce0565b5b60015f8981526020019081526020015f205f01601c9054906101000a900460ff16600481111561287357612872613ce0565b5b146128b3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016128aa9061503c565b60405180910390fd5b5f600387873388886002896040516020016128ce9190614244565b6040516020818303038152906040526040516128ea91906142ca565b602060405180830381855afa158015612905573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061292891906142f4565b8860405160200161293f979695949392919061465e565b60405160208183030381529060405260405161295b91906142ca565b602060405180830381855afa158015612976573d5f803e3d5ffd5b5050506040515160601b905060015f8981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614612a01576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129f89061444e565b60405180910390fd5b600360015f8a81526020019081526020015f205f01601c6101000a81548160ff02191690836004811115612a3857612a37613ce0565b5b02179055507f0d0da0df275f85bed3a5fe7ae79f3559341a3f9ccd8e010133438135bda00a878884604051612a6e929190614aee565b60405180910390a15f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612b56573373ffffffffffffffffffffffffffffffffffffffff166108fc8890811502906040515f60405180830381858888f19350505050158015612aec573d5f803e3d5ffd5b507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166108fc8790811502906040515f60405180830381858888f19350505050158015612b50573d5f803e3d5ffd5b50612bd2565b5f829050612b8533898373ffffffffffffffffffffffffffffffffffffffff166134c49092919063ffffffff16565b612bd07f0000000000000000000000000000000000000000000000000000000000000000888373ffffffffffffffffffffffffffffffffffffffff166134c49092919063ffffffff16565b505b5050505050505050565b5f6004811115612bef57612bee613ce0565b5b60015f8b81526020019081526020015f205f01601c9054906101000a900460ff166004811115612c2257612c21613ce0565b5b14612c62576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c59906150ca565b60405180910390fd5b5f8811612ca4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c9b90615132565b60405180910390fd5b5f8711612ce6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612cdd9061519a565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603612d54576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612d4b90614d8f565b60405180910390fd5b5f60038989883389898d604051602001612d74979695949392919061465e565b604051602081830303815290604052604051612d9091906142ca565b602060405180830381855afa158015612dab573d5f803e3d5ffd5b5050506040515160601b90506040518060800160405280826bffffffffffffffffffffffff191681526020018463ffffffff1681526020018363ffffffff16815260200160016004811115612e0357612e02613ce0565b5b81525060015f8c81526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548163ffffffff021916908363ffffffff1602179055506060820151815f01601c6101000a81548160ff02191690836004811115612ebe57612ebd613ce0565b5b02179055509050507ffc6cdccd1d98ded12074a9ebc7f6ab74fed1814ff57f4fb5202464d8938bd9358a604051612ef5919061447b565b60405180910390a15f879050612f3933308b8d612f129190614b42565b8473ffffffffffffffffffffffffffffffffffffffff16613543909392919063ffffffff16565b5050505050505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b5f602052805f5260405f205f91509050805f015f9054906101000a900460601b90805f0160149054906101000a900463ffffffff1690805f0160189054906101000a900460ff16905083565b5f808383810190612fc79190614807565b90505f6003811115612fdc57612fdb613ce0565b5b5f80835f015181526020019081526020015f205f0160189054906101000a900460ff16600381111561301157613010613ce0565b5b14613051576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161304890615228565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816020015173ffffffffffffffffffffffffffffffffffffffff16036130c3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016130ba9061490a565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816040015173ffffffffffffffffffffffffffffffffffffffff1603613135576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161312c90614972565b60405180910390fd5b806040015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146131a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161319e90614a00565b60405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614613215576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161320c90614a68565b60405180910390fd5b5f8511613257576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161324e90615290565b60405180910390fd5b61326481602001516134b3565b156132a4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161329b90614ad0565b60405180910390fd5b5f60038260200151898460600151856080015186604001518c8c6040516020016132d49796959493929190614384565b6040516020818303038152906040526040516132f091906142ca565b602060405180830381855afa15801561330b573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018360a0015163ffffffff1681526020016001600381111561335b5761335a613ce0565b5b8152505f80845f015181526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548160ff021916908360038111156133f2576133f1613ce0565b5b02179055509050507ff1dc11bbb6d7542c4267ecf1d370ff4c7092518633ecae9939e8488f4e53d2ad825f015160405161342c919061447b565b60405180910390a163f23a6e6160e01b925050509695505050505050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f80823b90505f8111915050919050565b61353e838473ffffffffffffffffffffffffffffffffffffffff1663a9059cbb85856040516024016134f79291906152ae565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506135c5565b505050565b6135bf848573ffffffffffffffffffffffffffffffffffffffff166323b872dd86868660405160240161357893929190614629565b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506135c5565b50505050565b5f6135ef828473ffffffffffffffffffffffffffffffffffffffff1661365a90919063ffffffff16565b90505f81511415801561361357508080602001905181019061361191906152ff565b155b1561365557826040517f5274afe700000000000000000000000000000000000000000000000000000000815260040161364c919061405c565b60405180910390fd5b505050565b606061366783835f61366f565b905092915050565b6060814710156136b657306040517fcd7860590000000000000000000000000000000000000000000000000000000081526004016136ad919061405c565b60405180910390fd5b5f808573ffffffffffffffffffffffffffffffffffffffff1684866040516136de91906142ca565b5f6040518083038185875af1925050503d805f8114613718576040519150601f19603f3d011682016040523d82523d5f602084013e61371d565b606091505b509150915061372d868383613738565b925050509392505050565b60608261374d57613748826137c5565b6137bd565b5f825114801561377357505f8473ffffffffffffffffffffffffffffffffffffffff163b145b156137b557836040517f9996b3150000000000000000000000000000000000000000000000000000000081526004016137ac919061405c565b60405180910390fd5b8190506137be565b5b9392505050565b5f815111156137d75780518082602001fd5b6040517f1425ea4200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61384e8161381a565b8114613858575f80fd5b50565b5f8135905061386981613845565b92915050565b5f6020828403121561388457613883613812565b5b5f6138918482850161385b565b91505092915050565b5f8115159050919050565b6138ae8161389a565b82525050565b5f6020820190506138c75f8301846138a5565b92915050565b5f819050919050565b6138df816138cd565b81146138e9575f80fd5b50565b5f813590506138fa816138d6565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61392982613900565b9050919050565b6139398161391f565b8114613943575f80fd5b50565b5f8135905061395481613930565b92915050565b5f819050919050565b61396c8161395a565b8114613976575f80fd5b50565b5f8135905061398781613963565b92915050565b5f805f805f805f60e0888a0312156139a8576139a7613812565b5b5f6139b58a828b016138ec565b97505060206139c68a828b01613946565b96505060406139d78a828b016138ec565b95505060606139e88a828b016138ec565b94505060806139f98a828b01613946565b93505060a0613a0a8a828b01613979565b92505060c0613a1b8a828b01613979565b91505092959891949750929550565b5f805f805f8060c08789031215613a4457613a43613812565b5b5f613a5189828a016138ec565b9650506020613a6289828a01613946565b9550506040613a7389828a016138ec565b9450506060613a8489828a016138ec565b9350506080613a9589828a01613946565b92505060a0613aa689828a01613979565b9150509295509295509295565b5f805f805f805f60e0888a031215613ace57613acd613812565b5b5f613adb8a828b016138ec565b9750506020613aec8a828b01613979565b9650506040613afd8a828b01613979565b9550506060613b0e8a828b01613946565b9450506080613b1f8a828b016138ec565b93505060a0613b308a828b016138ec565b92505060c0613b418a828b01613946565b91505092959891949750929550565b5f80fd5b5f80fd5b5f80fd5b5f8083601f840112613b7157613b70613b50565b5b8235905067ffffffffffffffff811115613b8e57613b8d613b54565b5b602083019150836001820283011115613baa57613ba9613b58565b5b9250929050565b5f805f805f60808688031215613bca57613bc9613812565b5b5f613bd788828901613946565b9550506020613be888828901613946565b9450506040613bf988828901613979565b935050606086013567ffffffffffffffff811115613c1a57613c19613816565b5b613c2688828901613b5c565b92509250509295509295909350565b613c3e8161381a565b82525050565b5f602082019050613c575f830184613c35565b92915050565b5f60208284031215613c7257613c71613812565b5b5f613c7f848285016138ec565b91505092915050565b5f7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b613cbc81613c88565b82525050565b5f63ffffffff82169050919050565b613cda81613cc2565b82525050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60058110613d1e57613d1d613ce0565b5b50565b5f819050613d2e82613d0d565b919050565b5f613d3d82613d21565b9050919050565b613d4d81613d33565b82525050565b5f608082019050613d665f830187613cb3565b613d736020830186613cd1565b613d806040830185613cd1565b613d8d6060830184613d44565b95945050505050565b613d9f81613cc2565b8114613da9575f80fd5b50565b5f81359050613dba81613d96565b92915050565b5f805f805f805f60e0888a031215613ddb57613dda613812565b5b5f613de88a828b016138ec565b9750506020613df98a828b01613979565b9650506040613e0a8a828b01613946565b9550506060613e1b8a828b016138ec565b9450506080613e2c8a828b016138ec565b93505060a0613e3d8a828b01613dac565b92505060c0613e4e8a828b01613dac565b91505092959891949750929550565b5f8083601f840112613e7257613e71613b50565b5b8235905067ffffffffffffffff811115613e8f57613e8e613b54565b5b602083019150836020820283011115613eab57613eaa613b58565b5b9250929050565b5f805f805f805f8060a0898b031215613ece57613ecd613812565b5b5f613edb8b828c01613946565b9850506020613eec8b828c01613946565b975050604089013567ffffffffffffffff811115613f0d57613f0c613816565b5b613f198b828c01613e5d565b9650965050606089013567ffffffffffffffff811115613f3c57613f3b613816565b5b613f488b828c01613e5d565b9450945050608089013567ffffffffffffffff811115613f6b57613f6a613816565b5b613f778b828c01613b5c565b92509250509295985092959890939650565b5f805f805f805f805f6101208a8c031215613fa757613fa6613812565b5b5f613fb48c828d016138ec565b9950506020613fc58c828d01613979565b9850506040613fd68c828d01613979565b9750506060613fe78c828d01613946565b9650506080613ff88c828d01613946565b95505060a06140098c828d016138ec565b94505060c061401a8c828d016138ec565b93505060e061402b8c828d01613dac565b92505061010061403d8c828d01613dac565b9150509295985092959850929598565b6140568161391f565b82525050565b5f60208201905061406f5f83018461404d565b92915050565b6004811061408657614085613ce0565b5b50565b5f81905061409682614075565b919050565b5f6140a582614089565b9050919050565b6140b58161409b565b82525050565b5f6060820190506140ce5f830186613cb3565b6140db6020830185613cd1565b6140e860408301846140ac565b949350505050565b5f805f805f8060a0878903121561410a57614109613812565b5b5f61411789828a01613946565b965050602061412889828a01613946565b955050604061413989828a01613979565b945050606061414a89828a01613979565b935050608087013567ffffffffffffffff81111561416b5761416a613816565b5b61417789828a01613b5c565b92509250509295509295509295565b5f82825260208201905092915050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520505f8201527f61796d656e7453656e7400000000000000000000000000000000000000000000602082015250565b5f6141f0602a83614186565b91506141fb82614196565b604082019050919050565b5f6020820190508181035f83015261421d816141e4565b9050919050565b5f819050919050565b61423e614239826138cd565b614224565b82525050565b5f61424f828461422d565b60208201915081905092915050565b5f81519050919050565b5f81905092915050565b5f5b8381101561428f578082015181840152602081019050614274565b5f8484015250505050565b5f6142a48261425e565b6142ae8185614268565b93506142be818560208601614272565b80840191505092915050565b5f6142d5828461429a565b915081905092915050565b5f815190506142ee816138d6565b92915050565b5f6020828403121561430957614308613812565b5b5f614316848285016142e0565b91505092915050565b5f8160601b9050919050565b5f6143358261431f565b9050919050565b5f6143468261432b565b9050919050565b61435e6143598261391f565b61433c565b82525050565b5f819050919050565b61437e6143798261395a565b614364565b82525050565b5f61438f828a61434d565b60148201915061439f828961434d565b6014820191506143af828861422d565b6020820191506143bf828761422d565b6020820191506143cf828661434d565b6014820191506143df828561436d565b6020820191506143ef828461436d565b60208201915081905098975050505050505050565b7f496e76616c6964207061796d656e7448617368000000000000000000000000005f82015250565b5f614438601383614186565b915061444382614404565b602082019050919050565b5f6020820190508181035f8301526144658161442c565b9050919050565b614475816138cd565b82525050565b5f60208201905061448e5f83018461446c565b92915050565b61449d8161395a565b82525050565b5f82825260208201905092915050565b50565b5f6144c15f836144a3565b91506144cc826144b3565b5f82019050919050565b5f60a0820190506144e95f83018761404d565b6144f6602083018661404d565b6145036040830185614494565b6145106060830184614494565b8181036080830152614521816144b6565b905095945050505050565b5f614537828961434d565b601482019150614547828861434d565b601482019150614557828761422d565b602082019150614567828661422d565b602082019150614577828561434d565b601482019150614587828461436d565b602082019150819050979650505050505050565b7f43757272656e742074696d657374616d70206469646e277420657863656564205f8201527f7061796d656e7420726566756e64206c6f636b2074696d650000000000000000602082015250565b5f6145f5603883614186565b91506146008261459b565b604082019050919050565b5f6020820190508181035f830152614622816145e9565b9050919050565b5f60608201905061463c5f83018661404d565b614649602083018561404d565b6146566040830184614494565b949350505050565b5f614669828a61436d565b602082019150614679828961436d565b602082019150614689828861434d565b601482019150614699828761434d565b6014820191506146a9828661422d565b6020820191506146b9828561422d565b6020820191506146c9828461434d565b60148201915081905098975050505050505050565b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b614728826146e2565b810181811067ffffffffffffffff82111715614747576147466146f2565b5b80604052505050565b5f614759613809565b9050614765828261471f565b919050565b5f60c0828403121561477f5761477e6146de565b5b61478960c0614750565b90505f614798848285016138ec565b5f8301525060206147ab84828501613946565b60208301525060406147bf84828501613946565b60408301525060606147d3848285016138ec565b60608301525060806147e7848285016138ec565b60808301525060a06147fb84828501613dac565b60a08301525092915050565b5f60c0828403121561481c5761481b613812565b5b5f6148298482850161476a565b91505092915050565b7f4d616b657220455243373231207061796d656e74206d75737420626520556e695f8201527f6e697469616c697a656400000000000000000000000000000000000000000000602082015250565b5f61488c602a83614186565b915061489782614832565b604082019050919050565b5f6020820190508181035f8301526148b981614880565b9050919050565b7f54616b6572206d757374206e6f74206265207a65726f206164647265737300005f82015250565b5f6148f4601e83614186565b91506148ff826148c0565b602082019050919050565b5f6020820190508181035f830152614921816148e8565b9050919050565b7f546f6b656e206d757374206e6f74206265207a65726f206164647265737300005f82015250565b5f61495c601e83614186565b915061496782614928565b602082019050919050565b5f6020820190508181035f83015261498981614950565b9050919050565b7f546f6b656e206164647265737320646f6573206e6f74206d617463682073656e5f8201527f6465720000000000000000000000000000000000000000000000000000000000602082015250565b5f6149ea602383614186565b91506149f582614990565b604082019050919050565b5f6020820190508181035f830152614a17816149de565b9050919050565b7f4f70657261746f72206d757374206265207468652073656e64657200000000005f82015250565b5f614a52601b83614186565b9150614a5d82614a1e565b602082019050919050565b5f6020820190508181035f830152614a7f81614a46565b9050919050565b7f54616b65722063616e6e6f74206265206120636f6e74726163740000000000005f82015250565b5f614aba601a83614186565b9150614ac582614a86565b602082019050919050565b5f6020820190508181035f830152614ae781614aae565b9050919050565b5f604082019050614b015f83018561446c565b614b0e602083018461446c565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f614b4c8261395a565b9150614b578361395a565b9250828201905080821115614b6f57614b6e614b15565b5b92915050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520505f8201527f61796d656e7453656e74206f722054616b6572417070726f7665640000000000602082015250565b5f614bcf603b83614186565b9150614bda82614b75565b604082019050919050565b5f6020820190508181035f830152614bfc81614bc3565b9050919050565b7f43757272656e742074696d657374616d70206469646e277420657863656564205f8201527f7061796d656e74207072652d617070726f7665206c6f636b2074696d65000000602082015250565b5f614c5d603d83614186565b9150614c6882614c03565b604082019050919050565b5f6020820190508181035f830152614c8a81614c51565b9050919050565b7f54616b6572207061796d656e7420697320616c726561647920696e697469616c5f8201527f697a656400000000000000000000000000000000000000000000000000000000602082015250565b5f614ceb602483614186565b9150614cf682614c91565b604082019050919050565b5f6020820190508181035f830152614d1881614cdf565b9050919050565b7f5265636569766572206d757374206e6f74206265207a65726f206164647265735f8201527f7300000000000000000000000000000000000000000000000000000000000000602082015250565b5f614d79602183614186565b9150614d8482614d1f565b604082019050919050565b5f6020820190508181035f830152614da681614d6d565b9050919050565b7f4554482076616c7565206d7573742062652067726561746572207468616e207a5f8201527f65726f0000000000000000000000000000000000000000000000000000000000602082015250565b5f614e07602383614186565b9150614e1282614dad565b604082019050919050565b5f6020820190508181035f830152614e3481614dfb565b9050919050565b7f4554482076616c7565206d7573742062652067726561746572207468616e20645f8201527f6578206665650000000000000000000000000000000000000000000000000000602082015250565b5f614e95602683614186565b9150614ea082614e3b565b604082019050919050565b5f6020820190508181035f830152614ec281614e89565b9050919050565b5f614ed38261395a565b9150614ede8361395a565b9250828203905081811115614ef657614ef5614b15565b5b92915050565b7f4261746368207472616e7366657273206e6f7420737570706f727465640000005f82015250565b5f614f30601d83614186565b9150614f3b82614efc565b602082019050919050565b5f6020820190508181035f830152614f5d81614f24565b9050919050565b7f43616c6c6572206d75737420626520616e20454f4100000000000000000000005f82015250565b5f614f98601583614186565b9150614fa382614f64565b602082019050919050565b5f6020820190508181035f830152614fc581614f8c565b9050919050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520545f8201527f616b6572417070726f7665640000000000000000000000000000000000000000602082015250565b5f615026602c83614186565b915061503182614fcc565b604082019050919050565b5f6020820190508181035f8301526150538161501a565b9050919050565b7f4552433230207632207061796d656e7420697320616c726561647920696e69745f8201527f69616c697a656400000000000000000000000000000000000000000000000000602082015250565b5f6150b4602783614186565b91506150bf8261505a565b604082019050919050565b5f6020820190508181035f8301526150e1816150a8565b9050919050565b7f416d6f756e74206d757374206e6f74206265207a65726f0000000000000000005f82015250565b5f61511c601783614186565b9150615127826150e8565b602082019050919050565b5f6020820190508181035f83015261514981615110565b9050919050565b7f44657820666565206d757374206e6f74206265207a65726f00000000000000005f82015250565b5f615184601883614186565b915061518f82615150565b602082019050919050565b5f6020820190508181035f8301526151b181615178565b9050919050565b7f4d616b65722045524331313535207061796d656e74206d75737420626520556e5f8201527f696e697469616c697a6564000000000000000000000000000000000000000000602082015250565b5f615212602b83614186565b915061521d826151b8565b604082019050919050565b5f6020820190508181035f83015261523f81615206565b9050919050565b7f56616c7565206d7573742062652067726561746572207468616e2030000000005f82015250565b5f61527a601c83614186565b915061528582615246565b602082019050919050565b5f6020820190508181035f8301526152a78161526e565b9050919050565b5f6040820190506152c15f83018561404d565b6152ce6020830184614494565b9392505050565b6152de8161389a565b81146152e8575f80fd5b50565b5f815190506152f9816152d5565b92915050565b5f6020828403121561531457615313613812565b5b5f615321848285016152eb565b9150509291505056fea26469706673582212200d86b0f6898fb823c55626c3b02a7098bc8622606b092e0f458df6c86ce2967864736f6c63430008180033"; +pub const NFT_MAKER_SWAP_V2_BYTES: &str = "6080604052348015600e575f80fd5b50612ffd8061001c5f395ff3fe608060405234801561000f575f80fd5b50600436106100a7575f3560e01c8063b27e46fb1161006f578063b27e46fb1461015f578063bc197c811461017b578063c8d9009b146101ab578063c92cd12d146101c7578063efccb9eb146101e3578063f23a6e6114610215576100a7565b806301ffc9a7146100ab57806305ec158d146100db5780630f235fce146100f7578063150b7a02146101135780636e6bf6d214610143575b5f80fd5b6100c560048036038101906100c09190611ebc565b610245565b6040516100d29190611f01565b60405180910390f35b6100f560048036038101906100f09190611fda565b610326565b005b610111600480360381019061010c9190612077565b6105e6565b005b61012d60048036038101906101289190612161565b6108a0565b60405161013a91906121f4565b60405180910390f35b61015d60048036038101906101589190612077565b610cef565b005b61017960048036038101906101749190611fda565b610faa565b005b61019560048036038101906101909190612262565b611269565b6040516101a291906121f4565b60405180910390f35b6101c560048036038101906101c09190612077565b6112a5565b005b6101e160048036038101906101dc9190611fda565b6115ce565b005b6101fd60048036038101906101f89190612339565b6118fc565b60405161020c9392919061242f565b60405180910390f35b61022f600480360381019061022a9190612464565b611948565b60405161023c91906121f4565b60405180910390f35b5f7f4e2312e0000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061030f57507f150b7a02000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061031f575061031e82611ddc565b5b9050919050565b6001600381111561033a576103396123bc565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff16600381111561036c5761036b6123bc565b5b146103ac576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103a39061257a565b60405180910390fd5b5f600387336002896040516020016103c491906125b8565b6040516020818303038152906040526040516103e09190612624565b602060405180830381855afa1580156103fb573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061041e919061264e565b8888888860405160200161043897969594939291906126de565b6040516020818303038152906040526040516104549190612624565b602060405180830381855afa15801561046f573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146104f9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104f0906127a8565b60405180910390fd5b60035f808a81526020019081526020015f205f0160186101000a81548160ff0219169083600381111561052f5761052e6123bc565b5b02179055507fac509cdcc7ddb189f81fff6f4824f5c95076e64c3bdce542c50feaa6779afd738860405161056391906127d5565b60405180910390a15f8490508073ffffffffffffffffffffffffffffffffffffffff1663f242432a303387876040518563ffffffff1660e01b81526004016105ae949392919061283f565b5f604051808303815f87803b1580156105c5575f80fd5b505af11580156105d7573d5f803e3d5ffd5b50505050505050505050505050565b600160038111156105fa576105f96123bc565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff16600381111561062c5761062b6123bc565b5b1461066c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106639061257a565b60405180910390fd5b5f600386338787878760405160200161068a96959493929190612895565b6040516020818303038152906040526040516106a69190612624565b602060405180830381855afa1580156106c1573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461074b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610742906127a8565b60405180910390fd5b5f808881526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff164210156107b6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107ad90612974565b60405180910390fd5b60035f808981526020019081526020015f205f0160186101000a81548160ff021916908360038111156107ec576107eb6123bc565b5b02179055507f5dedc4f52b757d9112d09ca0b2f022927104d54e3f54da091587e8ad192190728760405161082091906127d5565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b815260040161086993929190612992565b5f604051808303815f87803b158015610880575f80fd5b505af1158015610892573d5f803e3d5ffd5b505050505050505050505050565b5f8083838101906108b19190612b1a565b90505f60038111156108c6576108c56123bc565b5b5f80835f015181526020019081526020015f205f0160189054906101000a900460ff1660038111156108fb576108fa6123bc565b5b1461093b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161093290612bb5565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816020015173ffffffffffffffffffffffffffffffffffffffff16036109ad576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109a490612c1d565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816040015173ffffffffffffffffffffffffffffffffffffffff1603610a1f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a1690612c85565b60405180910390fd5b806040015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610a91576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a8890612d13565b60405180910390fd5b8573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614610aff576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610af690612d7b565b60405180910390fd5b610b0c8160200151611e45565b15610b4c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b4390612de3565b60405180910390fd5b5f60038260200151888460600151856080015186604001518b604051602001610b7a96959493929190612895565b604051602081830303815290604052604051610b969190612624565b602060405180830381855afa158015610bb1573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018360a0015163ffffffff16815260200160016003811115610c0157610c006123bc565b5b8152505f80845f015181526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548160ff02191690836003811115610c9857610c976123bc565b5b02179055509050507ff1dc11bbb6d7542c4267ecf1d370ff4c7092518633ecae9939e8488f4e53d2ad825f0151604051610cd291906127d5565b60405180910390a163150b7a0260e01b9250505095945050505050565b60016003811115610d0357610d026123bc565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff166003811115610d3557610d346123bc565b5b14610d75576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d6c9061257a565b60405180910390fd5b5f60038633600288604051602001610d8d91906125b8565b604051602081830303815290604052604051610da99190612624565b602060405180830381855afa158015610dc4573d5f803e3d5ffd5b5050506040513d601f19601f82011682018060405250810190610de7919061264e565b878787604051602001610dff96959493929190612895565b604051602081830303815290604052604051610e1b9190612624565b602060405180830381855afa158015610e36573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614610ec0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610eb7906127a8565b60405180910390fd5b60035f808981526020019081526020015f205f0160186101000a81548160ff02191690836003811115610ef657610ef56123bc565b5b02179055507fac509cdcc7ddb189f81fff6f4824f5c95076e64c3bdce542c50feaa6779afd7387604051610f2a91906127d5565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b8152600401610f7393929190612992565b5f604051808303815f87803b158015610f8a575f80fd5b505af1158015610f9c573d5f803e3d5ffd5b505050505050505050505050565b60016003811115610fbe57610fbd6123bc565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff166003811115610ff057610fef6123bc565b5b14611030576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110279061257a565b60405180910390fd5b5f60038733888888888860405160200161105097969594939291906126de565b60405160208183030381529060405260405161106c9190612624565b602060405180830381855afa158015611087573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff191614611111576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611108906127a8565b60405180910390fd5b5f808981526020019081526020015f205f0160149054906101000a900463ffffffff1663ffffffff1642101561117c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161117390612974565b60405180910390fd5b60035f808a81526020019081526020015f205f0160186101000a81548160ff021916908360038111156111b2576111b16123bc565b5b02179055507f5dedc4f52b757d9112d09ca0b2f022927104d54e3f54da091587e8ad19219072886040516111e691906127d5565b60405180910390a15f8490508073ffffffffffffffffffffffffffffffffffffffff1663f242432a303387876040518563ffffffff1660e01b8152600401611231949392919061283f565b5f604051808303815f87803b158015611248575f80fd5b505af115801561125a573d5f803e3d5ffd5b50505050505050505050505050565b5f6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161129c90612e4b565b60405180910390fd5b600160038111156112b9576112b86123bc565b5b5f808881526020019081526020015f205f0160189054906101000a900460ff1660038111156112eb576112ea6123bc565b5b1461132b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113229061257a565b60405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611399576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161139090612eb3565b60405180910390fd5b5f60033387876002886040516020016113b291906125b8565b6040516020818303038152906040526040516113ce9190612624565b602060405180830381855afa1580156113e9573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061140c919061264e565b878760405160200161142396959493929190612895565b60405160208183030381529060405260405161143f9190612624565b602060405180830381855afa15801561145a573d5f803e3d5ffd5b5050506040515160601b90505f808881526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff1916146114e4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114db906127a8565b60405180910390fd5b60025f808981526020019081526020015f205f0160186101000a81548160ff0219169083600381111561151a576115196123bc565b5b02179055507fad62ed075fe8969df63026f45152d6e996a0697a736a8de92ee85ae9c9958cf08760405161154e91906127d5565b60405180910390a15f8390508073ffffffffffffffffffffffffffffffffffffffff166342842e0e3033866040518463ffffffff1660e01b815260040161159793929190612992565b5f604051808303815f87803b1580156115ae575f80fd5b505af11580156115c0573d5f803e3d5ffd5b505050505050505050505050565b600160038111156115e2576115e16123bc565b5b5f808981526020019081526020015f205f0160189054906101000a900460ff166003811115611614576116136123bc565b5b14611654576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161164b9061257a565b60405180910390fd5b3273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146116c2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116b990612eb3565b60405180910390fd5b5f60033388886002896040516020016116db91906125b8565b6040516020818303038152906040526040516116f79190612624565b602060405180830381855afa158015611712573d5f803e3d5ffd5b5050506040513d601f19601f82011682018060405250810190611735919061264e565b88888860405160200161174e97969594939291906126de565b60405160208183030381529060405260405161176a9190612624565b602060405180830381855afa158015611785573d5f803e3d5ffd5b5050506040515160601b90505f808981526020019081526020015f205f015f9054906101000a900460601b6bffffffffffffffffffffffff1916816bffffffffffffffffffffffff19161461180f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611806906127a8565b60405180910390fd5b60025f808a81526020019081526020015f205f0160186101000a81548160ff02191690836003811115611845576118446123bc565b5b02179055507fad62ed075fe8969df63026f45152d6e996a0697a736a8de92ee85ae9c9958cf08860405161187991906127d5565b60405180910390a15f8490508073ffffffffffffffffffffffffffffffffffffffff1663f242432a303387876040518563ffffffff1660e01b81526004016118c4949392919061283f565b5f604051808303815f87803b1580156118db575f80fd5b505af11580156118ed573d5f803e3d5ffd5b50505050505050505050505050565b5f602052805f5260405f205f91509050805f015f9054906101000a900460601b90805f0160149054906101000a900463ffffffff1690805f0160189054906101000a900460ff16905083565b5f8083838101906119599190612b1a565b90505f600381111561196e5761196d6123bc565b5b5f80835f015181526020019081526020015f205f0160189054906101000a900460ff1660038111156119a3576119a26123bc565b5b146119e3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119da90612f41565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816020015173ffffffffffffffffffffffffffffffffffffffff1603611a55576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a4c90612c1d565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff16816040015173ffffffffffffffffffffffffffffffffffffffff1603611ac7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611abe90612c85565b60405180910390fd5b806040015173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611b39576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b3090612d13565b60405180910390fd5b8673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614611ba7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b9e90612d7b565b60405180910390fd5b5f8511611be9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611be090612fa9565b60405180910390fd5b611bf68160200151611e45565b15611c36576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c2d90612de3565b60405180910390fd5b5f60038260200151898460600151856080015186604001518c8c604051602001611c6697969594939291906126de565b604051602081830303815290604052604051611c829190612624565b602060405180830381855afa158015611c9d573d5f803e3d5ffd5b5050506040515160601b90506040518060600160405280826bffffffffffffffffffffffff191681526020018360a0015163ffffffff16815260200160016003811115611ced57611cec6123bc565b5b8152505f80845f015181526020019081526020015f205f820151815f015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c02179055506020820151815f0160146101000a81548163ffffffff021916908363ffffffff1602179055506040820151815f0160186101000a81548160ff02191690836003811115611d8457611d836123bc565b5b02179055509050507ff1dc11bbb6d7542c4267ecf1d370ff4c7092518633ecae9939e8488f4e53d2ad825f0151604051611dbe91906127d5565b60405180910390a163f23a6e6160e01b925050509695505050505050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f80823b90505f8111915050919050565b5f604051905090565b5f80fd5b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b611e9b81611e67565b8114611ea5575f80fd5b50565b5f81359050611eb681611e92565b92915050565b5f60208284031215611ed157611ed0611e5f565b5b5f611ede84828501611ea8565b91505092915050565b5f8115159050919050565b611efb81611ee7565b82525050565b5f602082019050611f145f830184611ef2565b92915050565b5f819050919050565b611f2c81611f1a565b8114611f36575f80fd5b50565b5f81359050611f4781611f23565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f611f7682611f4d565b9050919050565b611f8681611f6c565b8114611f90575f80fd5b50565b5f81359050611fa181611f7d565b92915050565b5f819050919050565b611fb981611fa7565b8114611fc3575f80fd5b50565b5f81359050611fd481611fb0565b92915050565b5f805f805f805f60e0888a031215611ff557611ff4611e5f565b5b5f6120028a828b01611f39565b97505060206120138a828b01611f93565b96505060406120248a828b01611f39565b95505060606120358a828b01611f39565b94505060806120468a828b01611f93565b93505060a06120578a828b01611fc6565b92505060c06120688a828b01611fc6565b91505092959891949750929550565b5f805f805f8060c0878903121561209157612090611e5f565b5b5f61209e89828a01611f39565b96505060206120af89828a01611f93565b95505060406120c089828a01611f39565b94505060606120d189828a01611f39565b93505060806120e289828a01611f93565b92505060a06120f389828a01611fc6565b9150509295509295509295565b5f80fd5b5f80fd5b5f80fd5b5f8083601f84011261212157612120612100565b5b8235905067ffffffffffffffff81111561213e5761213d612104565b5b60208301915083600182028301111561215a57612159612108565b5b9250929050565b5f805f805f6080868803121561217a57612179611e5f565b5b5f61218788828901611f93565b955050602061219888828901611f93565b94505060406121a988828901611fc6565b935050606086013567ffffffffffffffff8111156121ca576121c9611e63565b5b6121d68882890161210c565b92509250509295509295909350565b6121ee81611e67565b82525050565b5f6020820190506122075f8301846121e5565b92915050565b5f8083601f84011261222257612221612100565b5b8235905067ffffffffffffffff81111561223f5761223e612104565b5b60208301915083602082028301111561225b5761225a612108565b5b9250929050565b5f805f805f805f8060a0898b03121561227e5761227d611e5f565b5b5f61228b8b828c01611f93565b985050602061229c8b828c01611f93565b975050604089013567ffffffffffffffff8111156122bd576122bc611e63565b5b6122c98b828c0161220d565b9650965050606089013567ffffffffffffffff8111156122ec576122eb611e63565b5b6122f88b828c0161220d565b9450945050608089013567ffffffffffffffff81111561231b5761231a611e63565b5b6123278b828c0161210c565b92509250509295985092959890939650565b5f6020828403121561234e5761234d611e5f565b5b5f61235b84828501611f39565b91505092915050565b5f7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b61239881612364565b82525050565b5f63ffffffff82169050919050565b6123b68161239e565b82525050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b600481106123fa576123f96123bc565b5b50565b5f81905061240a826123e9565b919050565b5f612419826123fd565b9050919050565b6124298161240f565b82525050565b5f6060820190506124425f83018661238f565b61244f60208301856123ad565b61245c6040830184612420565b949350505050565b5f805f805f8060a0878903121561247e5761247d611e5f565b5b5f61248b89828a01611f93565b965050602061249c89828a01611f93565b95505060406124ad89828a01611fc6565b94505060606124be89828a01611fc6565b935050608087013567ffffffffffffffff8111156124df576124de611e63565b5b6124eb89828a0161210c565b92509250509295509295509295565b5f82825260208201905092915050565b7f496e76616c6964207061796d656e742073746174652e204d75737420626520505f8201527f61796d656e7453656e7400000000000000000000000000000000000000000000602082015250565b5f612564602a836124fa565b915061256f8261250a565b604082019050919050565b5f6020820190508181035f83015261259181612558565b9050919050565b5f819050919050565b6125b26125ad82611f1a565b612598565b82525050565b5f6125c382846125a1565b60208201915081905092915050565b5f81519050919050565b5f81905092915050565b8281835e5f83830152505050565b5f6125fe826125d2565b61260881856125dc565b93506126188185602086016125e6565b80840191505092915050565b5f61262f82846125f4565b915081905092915050565b5f8151905061264881611f23565b92915050565b5f6020828403121561266357612662611e5f565b5b5f6126708482850161263a565b91505092915050565b5f8160601b9050919050565b5f61268f82612679565b9050919050565b5f6126a082612685565b9050919050565b6126b86126b382611f6c565b612696565b82525050565b5f819050919050565b6126d86126d382611fa7565b6126be565b82525050565b5f6126e9828a6126a7565b6014820191506126f982896126a7565b60148201915061270982886125a1565b60208201915061271982876125a1565b60208201915061272982866126a7565b60148201915061273982856126c7565b60208201915061274982846126c7565b60208201915081905098975050505050505050565b7f496e76616c6964207061796d656e7448617368000000000000000000000000005f82015250565b5f6127926013836124fa565b915061279d8261275e565b602082019050919050565b5f6020820190508181035f8301526127bf81612786565b9050919050565b6127cf81611f1a565b82525050565b5f6020820190506127e85f8301846127c6565b92915050565b6127f781611f6c565b82525050565b61280681611fa7565b82525050565b5f82825260208201905092915050565b50565b5f61282a5f8361280c565b91506128358261281c565b5f82019050919050565b5f60a0820190506128525f8301876127ee565b61285f60208301866127ee565b61286c60408301856127fd565b61287960608301846127fd565b818103608083015261288a8161281f565b905095945050505050565b5f6128a082896126a7565b6014820191506128b082886126a7565b6014820191506128c082876125a1565b6020820191506128d082866125a1565b6020820191506128e082856126a7565b6014820191506128f082846126c7565b602082019150819050979650505050505050565b7f43757272656e742074696d657374616d70206469646e277420657863656564205f8201527f7061796d656e7420726566756e64206c6f636b2074696d650000000000000000602082015250565b5f61295e6038836124fa565b915061296982612904565b604082019050919050565b5f6020820190508181035f83015261298b81612952565b9050919050565b5f6060820190506129a55f8301866127ee565b6129b260208301856127ee565b6129bf60408301846127fd565b949350505050565b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b612a11826129cb565b810181811067ffffffffffffffff82111715612a3057612a2f6129db565b5b80604052505050565b5f612a42611e56565b9050612a4e8282612a08565b919050565b612a5c8161239e565b8114612a66575f80fd5b50565b5f81359050612a7781612a53565b92915050565b5f60c08284031215612a9257612a916129c7565b5b612a9c60c0612a39565b90505f612aab84828501611f39565b5f830152506020612abe84828501611f93565b6020830152506040612ad284828501611f93565b6040830152506060612ae684828501611f39565b6060830152506080612afa84828501611f39565b60808301525060a0612b0e84828501612a69565b60a08301525092915050565b5f60c08284031215612b2f57612b2e611e5f565b5b5f612b3c84828501612a7d565b91505092915050565b7f4d616b657220455243373231207061796d656e74206d75737420626520556e695f8201527f6e697469616c697a656400000000000000000000000000000000000000000000602082015250565b5f612b9f602a836124fa565b9150612baa82612b45565b604082019050919050565b5f6020820190508181035f830152612bcc81612b93565b9050919050565b7f54616b6572206d757374206e6f74206265207a65726f206164647265737300005f82015250565b5f612c07601e836124fa565b9150612c1282612bd3565b602082019050919050565b5f6020820190508181035f830152612c3481612bfb565b9050919050565b7f546f6b656e206d757374206e6f74206265207a65726f206164647265737300005f82015250565b5f612c6f601e836124fa565b9150612c7a82612c3b565b602082019050919050565b5f6020820190508181035f830152612c9c81612c63565b9050919050565b7f546f6b656e206164647265737320646f6573206e6f74206d617463682073656e5f8201527f6465720000000000000000000000000000000000000000000000000000000000602082015250565b5f612cfd6023836124fa565b9150612d0882612ca3565b604082019050919050565b5f6020820190508181035f830152612d2a81612cf1565b9050919050565b7f4f70657261746f72206d757374206265207468652073656e64657200000000005f82015250565b5f612d65601b836124fa565b9150612d7082612d31565b602082019050919050565b5f6020820190508181035f830152612d9281612d59565b9050919050565b7f54616b65722063616e6e6f74206265206120636f6e74726163740000000000005f82015250565b5f612dcd601a836124fa565b9150612dd882612d99565b602082019050919050565b5f6020820190508181035f830152612dfa81612dc1565b9050919050565b7f4261746368207472616e7366657273206e6f7420737570706f727465640000005f82015250565b5f612e35601d836124fa565b9150612e4082612e01565b602082019050919050565b5f6020820190508181035f830152612e6281612e29565b9050919050565b7f43616c6c6572206d75737420626520616e20454f4100000000000000000000005f82015250565b5f612e9d6015836124fa565b9150612ea882612e69565b602082019050919050565b5f6020820190508181035f830152612eca81612e91565b9050919050565b7f4d616b65722045524331313535207061796d656e74206d75737420626520556e5f8201527f696e697469616c697a6564000000000000000000000000000000000000000000602082015250565b5f612f2b602b836124fa565b9150612f3682612ed1565b604082019050919050565b5f6020820190508181035f830152612f5881612f1f565b9050919050565b7f56616c7565206d7573742062652067726561746572207468616e2030000000005f82015250565b5f612f93601c836124fa565b9150612f9e82612f5f565b602082019050919050565b5f6020820190508181035f830152612fc081612f87565b905091905056fea26469706673582212204e239c256ffaf5624f6d55ae2e9f8afd626e0e129a36ff33221d4b2fe58f6b5a64736f6c63430008190033"; pub trait CoinDockerOps { fn rpc_client(&self) -> &UtxoRpcClientEnum; @@ -1153,6 +1173,8 @@ pub fn wait_until_relayer_container_is_ready(container_id: &str) { pub fn init_geth_node() { unsafe { block_on(get_current_gas_limit(&GETH_WEB3)); + let gas_price = block_on(GETH_WEB3.eth().gas_price()).unwrap(); + log!("Current gas price: {:?}", gas_price); let accounts = block_on(GETH_WEB3.eth().accounts()).unwrap(); GETH_ACCOUNT = accounts[0]; log!("GETH ACCOUNT {:?}", GETH_ACCOUNT); @@ -1269,6 +1291,97 @@ pub fn init_geth_node() { thread::sleep(Duration::from_millis(100)); } + let tx_request_deploy_nft_maker_swap_v2_contract = TransactionRequest { + from: GETH_ACCOUNT, + to: None, + gas: None, + gas_price: None, + value: None, + data: Some(hex::decode(NFT_MAKER_SWAP_V2_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_maker_swap_v2_tx_hash = block_on( + GETH_WEB3 + .eth() + .send_transaction(tx_request_deploy_nft_maker_swap_v2_contract), + ) + .unwrap(); + log!( + "Sent deploy nft maker swap v2 contract transaction {:?}", + deploy_nft_maker_swap_v2_tx_hash + ); + + loop { + let deploy_nft_maker_swap_v2_tx_receipt = + match block_on(GETH_WEB3.eth().transaction_receipt(deploy_nft_maker_swap_v2_tx_hash)) { + Ok(receipt) => receipt, + Err(_) => { + thread::sleep(Duration::from_millis(100)); + continue; + }, + }; + + if let Some(receipt) = deploy_nft_maker_swap_v2_tx_receipt { + GETH_NFT_MAKER_SWAP_V2 = receipt.contract_address.unwrap(); + log!( + "GETH_NFT_MAKER_SWAP_V2 {:?}, receipt.status {:?}", + GETH_NFT_MAKER_SWAP_V2, + receipt.status + ); + break; + } + thread::sleep(Duration::from_millis(100)); + } + + 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)); + + 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_data).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 {:?}, receipt.status {:?}", + GETH_NFT_SWAP_CONTRACT, + receipt.status + ); + break; + } + thread::sleep(Duration::from_millis(100)); + } + let name = Token::String("MyNFT".into()); let symbol = Token::String("MNFT".into()); let params = ethabi::encode(&[name, symbol]); @@ -1347,45 +1460,9 @@ pub fn init_geth_node() { thread::sleep(Duration::from_millis(100)); } - 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)); - - 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_data).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)); - } + SEPOLIA_ETOMIC_MAKER_NFT_SWAP_V2 = EthAddress::from_str("0x9eb88cd58605d8fb9b14652d6152727f7e95fb4d").unwrap(); + SEPOLIA_ERC721_CONTRACT = EthAddress::from_str("0xbac1c9f2087f39caaa4e93412c6412809186870e").unwrap(); + SEPOLIA_ERC1155_CONTRACT = EthAddress::from_str("0xfb53b8764be6033d89ceacafa36631b09d60a1d2").unwrap(); let alice_passphrase = get_passphrase!(".env.client", "ALICE_PASSPHRASE").unwrap(); let alice_keypair = key_pair_from_seed(&alice_passphrase).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 1109e9f159..a61c0f2690 100644 --- a/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/eth_docker_tests.rs @@ -1,26 +1,35 @@ 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_RPC_URL, GETH_SWAP_CONTRACT, - GETH_WATCHERS_SWAP_CONTRACT, GETH_WEB3, MM_CTX}; + GETH_NFT_MAKER_SWAP_V2, GETH_NFT_SWAP_CONTRACT, GETH_NONCE_LOCK, GETH_RPC_URL, + GETH_SWAP_CONTRACT, GETH_WATCHERS_SWAP_CONTRACT, GETH_WEB3, MM_CTX, MM_CTX1, + SEPOLIA_ERC1155_CONTRACT, SEPOLIA_ERC721_CONTRACT, SEPOLIA_ETOMIC_MAKER_NFT_SWAP_V2, + SEPOLIA_NONCE_LOCK, SEPOLIA_RPC_URL, SEPOLIA_WEB3}; +use crate::common::Future01CompatExt; use bitcrypto::{dhash160, sha256}; -use coins::eth::{checksum_address, eth_addr_to_hex, 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, SignedEthTx, ERC20_ABI}; use coins::nft::nft_structs::{Chain, ContractType, NftInfo}; -use coins::{CoinProtocol, CoinWithDerivationMethod, ConfirmPaymentInput, DerivationMethod, Eip1559Ops, - FoundSwapTxSpend, MakerNftSwapOpsV2, MarketCoinOps, NftSwapInfo, ParseCoinAssocTypes, PrivKeyBuildPolicy, - RefundPaymentArgs, SearchForSwapTxSpendInput, SendNftMakerPaymentArgs, SendPaymentArgs, - SpendNftMakerPaymentArgs, SpendPaymentArgs, SwapOps, SwapTxFeePolicy, SwapTxTypeWithSecretHash, ToBytes, - Transaction, ValidateNftMakerPaymentArgs}; +use coins::{lp_coinfind, CoinProtocol, CoinWithDerivationMethod, CoinsContext, ConfirmPaymentInput, DerivationMethod, + Eip1559Ops, FoundSwapTxSpend, MakerNftSwapOpsV2, MarketCoinOps, MmCoinEnum, MmCoinStruct, NftSwapInfo, + ParseCoinAssocTypes, PrivKeyBuildPolicy, RefundPaymentArgs, SearchForSwapTxSpendInput, + SendNftMakerPaymentArgs, SendPaymentArgs, SpendNftMakerPaymentArgs, SpendPaymentArgs, SwapOps, + SwapTxFeePolicy, SwapTxTypeWithSecretHash, ToBytes, Transaction, ValidateNftMakerPaymentArgs}; use common::{block_on, now_sec}; use crypto::Secp256k1Secret; +use ethcore_transaction::Action; 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 mm2_test_helpers::for_tests::{erc20_dev_conf, eth_dev_conf, nft_dev_conf, nft_sepolia_conf}; use std::thread; use std::time::Duration; use web3::contract::{Contract, Options}; use web3::ethabi::Token; -use web3::types::{Address, TransactionRequest, H256}; +use web3::types::{Address, BlockNumber, TransactionRequest, H256}; + +const SEPOLIA_MAKER_PRIV: &str = "6e2f3a6223b928a05a3a3622b0c3f3573d03663b704a61a6eb73326de0487928"; +const SEPOLIA_TAKER_PRIV: &str = "e0be82dca60ff7e4c6d6db339ac9e1ae249af081dba2110bddd281e711608f16"; +const NFT_ETH: &str = "NFT_ETH"; /// # Safety /// @@ -32,11 +41,18 @@ pub 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 } } +#[allow(dead_code)] /// # Safety /// /// GETH_NFT_SWAP_CONTRACT is set once during initialization before tests start pub fn nft_swap_contract() -> Address { unsafe { GETH_NFT_SWAP_CONTRACT } } +#[allow(dead_code)] +/// # Safety +/// +/// GETH_NFT_MAKER_SWAP_V2 is set once during initialization before tests start +pub fn nft_maker_swap_v2() -> Address { unsafe { GETH_NFT_MAKER_SWAP_V2 } } + /// # Safety /// /// GETH_WATCHERS_SWAP_CONTRACT is set once during initialization before tests start @@ -50,16 +66,33 @@ 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())) } +#[allow(dead_code)] /// # Safety /// /// GETH_ERC721_CONTRACT is set once during initialization before tests start pub fn erc721_contract() -> Address { unsafe { GETH_ERC721_CONTRACT } } +#[allow(dead_code)] /// # Safety /// /// GETH_ERC1155_CONTRACT is set once during initialization before tests start pub fn erc1155_contract() -> Address { unsafe { GETH_ERC1155_CONTRACT } } +/// # Safety +/// +/// SEPOLIA_ETOMIC_MAKER_NFT_SWAP_V2 address is set once during initialization before tests start +pub fn sepolia_etomic_maker_nft() -> Address { unsafe { SEPOLIA_ETOMIC_MAKER_NFT_SWAP_V2 } } + +/// # Safety +/// +/// SEPOLIA_ERC721_CONTRACT address is set once during initialization before tests start +pub fn sepolia_erc721() -> Address { unsafe { SEPOLIA_ERC721_CONTRACT } } + +/// # Safety +/// +/// SEPOLIA_ERC1155_CONTRACT address is set once during initialization before tests start +pub fn sepolia_erc1155() -> Address { unsafe { SEPOLIA_ERC1155_CONTRACT } } + fn wait_for_confirmation(tx_hash: H256) { thread::sleep(Duration::from_millis(2000)); loop { @@ -109,7 +142,8 @@ fn fill_erc20(to_addr: Address, amount: U256) { wait_for_confirmation(tx_hash); } -pub(crate) fn mint_erc721(to_addr: Address, token_id: U256) { +#[allow(dead_code)] +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(); @@ -138,12 +172,14 @@ 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(); + let _guard = SEPOLIA_NONCE_LOCK.lock().unwrap(); + let erc721_contract = + Contract::from_json(SEPOLIA_WEB3.eth(), sepolia_erc721(), 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) { +#[allow(dead_code)] +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(); @@ -180,9 +216,9 @@ 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 _guard = SEPOLIA_NONCE_LOCK.lock().unwrap(); let erc1155_contract = - Contract::from_json(GETH_WEB3.eth(), erc1155_contract(), ERC1155_TEST_ABI.as_bytes()).unwrap(); + Contract::from_json(SEPOLIA_WEB3.eth(), sepolia_erc1155(), ERC1155_TEST_ABI.as_bytes()).unwrap(); block_on(erc1155_contract.query( "balanceOf", (Token::Address(wallet_addr), Token::Uint(token_id)), @@ -193,35 +229,35 @@ fn erc1155_balance(wallet_addr: Address, token_id: U256) -> U256 { .unwrap() } -pub(crate) async fn fill_erc1155_info(eth_coin: &EthCoin, tokens_id: u32, amount: u32) { +pub(crate) async fn fill_erc1155_info(eth_coin: &EthCoin, token_address: Address, token_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), + token_address, + token_id: BigUint::from(token_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); + let erc1155_address_str = eth_addr_to_hex(&token_address); + let erc1155_key = format!("{},{}", erc1155_address_str, token_id); nft_infos.insert(erc1155_key, erc1155_nft_info); } -pub(crate) async fn fill_erc721_info(eth_coin: &EthCoin, tokens_id: u32) { +pub(crate) async fn fill_erc721_info(eth_coin: &EthCoin, token_address: Address, token_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_id), + token_address, + token_id: BigUint::from(token_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_id); + let erc721_address_str = eth_addr_to_hex(&token_address); + let erc721_key = format!("{},{}", erc721_address_str, token_id); nft_infos.insert(erc721_key, erc721_nft_info); } @@ -298,6 +334,7 @@ pub fn erc20_coin_with_random_privkey(swap_contract_address: Address) -> EthCoin erc20_coin } +#[derive(Clone, Copy, Debug)] pub enum TestNftType { Erc1155 { token_id: u32, amount: u32 }, Erc721 { token_id: u32 }, @@ -306,6 +343,7 @@ 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`. +#[allow(dead_code)] pub fn global_nft_with_random_privkey(swap_contract_address: Address, nft_type: Option) -> EthCoin { let nft_conf = nft_dev_conf(); let req = json!({ @@ -334,11 +372,11 @@ pub fn global_nft_with_random_privkey(swap_contract_address: Address, nft_type: match nft_type { TestNftType::Erc1155 { token_id, amount } => { mint_erc1155(my_address, U256::from(token_id), U256::from(amount)); - block_on(fill_erc1155_info(&global_nft, token_id, amount)); + block_on(fill_erc1155_info(&global_nft, erc1155_contract(), token_id, amount)); }, TestNftType::Erc721 { token_id } => { mint_erc721(my_address, U256::from(token_id)); - block_on(fill_erc721_info(&global_nft, token_id)); + block_on(fill_erc721_info(&global_nft, erc721_contract(), token_id)); }, } } @@ -346,6 +384,104 @@ pub fn global_nft_with_random_privkey(swap_contract_address: Address, nft_type: global_nft } +fn global_nft_from_privkey( + ctx: &MmArc, + swap_contract_address: Address, + secret: &'static str, + nft_type: Option, +) -> EthCoin { + let nft_conf = nft_sepolia_conf(); + let req = json!({ + "method": "enable", + "coin": "NFT_ETH", + "urls": [SEPOLIA_RPC_URL], + "swap_contract_address": swap_contract_address, + }); + + let priv_key = Secp256k1Secret::from(secret); + 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(); + + let coins_ctx = CoinsContext::from_ctx(ctx).unwrap(); + let mut coins = block_on(coins_ctx.lock_coins()); + coins.insert( + global_nft.ticker().into(), + MmCoinStruct::new(MmCoinEnum::EthCoin(global_nft.clone())), + ); + + if let Some(nft_type) = nft_type { + match nft_type { + TestNftType::Erc1155 { token_id, amount } => { + block_on(fill_erc1155_info(&global_nft, sepolia_erc1155(), token_id, amount)); + }, + TestNftType::Erc721 { token_id } => { + block_on(fill_erc721_info(&global_nft, sepolia_erc721(), token_id)); + }, + } + } + + global_nft +} + +fn send_safe_transfer_from( + global_nft: &EthCoin, + token_address: Address, + from_address: Address, + to_address: Address, + nft_type: TestNftType, +) -> web3::Result { + let _guard = GETH_NONCE_LOCK.lock().unwrap(); + + let contract = match nft_type { + TestNftType::Erc1155 { .. } => { + Contract::from_json(SEPOLIA_WEB3.eth(), token_address, ERC1155_TEST_ABI.as_bytes()).unwrap() + }, + TestNftType::Erc721 { .. } => { + Contract::from_json(SEPOLIA_WEB3.eth(), token_address, ERC721_TEST_ABI.as_bytes()).unwrap() + }, + }; + let tokens = match nft_type { + TestNftType::Erc1155 { token_id, amount } => vec![ + Token::Address(from_address), + Token::Address(to_address), + Token::Uint(U256::from(token_id)), + Token::Uint(U256::from(amount)), + Token::Bytes(vec![]), + ], + TestNftType::Erc721 { token_id } => vec![ + Token::Address(from_address), + Token::Address(to_address), + Token::Uint(U256::from(token_id)), + ], + }; + + let data = contract + .abi() + .function("safeTransferFrom") + .unwrap() + .encode_input(&tokens) + .unwrap(); + + let result = block_on( + global_nft + .sign_and_send_transaction(0.into(), Action::Call(token_address), data, U256::from(150_000)) + .compat(), + ) + .unwrap(); + + log!("Transaction sent: {:?}", result); + Ok(result) +} + /// Fills the private key's public address with ETH and ERC20 tokens pub fn fill_eth_erc20_with_private_key(priv_key: Secp256k1Secret) { let eth_conf = eth_dev_conf(); @@ -733,19 +869,52 @@ fn send_and_spend_erc20_maker_payment_priority_fee() { send_and_spend_erc20_maker_payment_impl(SwapTxFeePolicy::Medium); } +/// Wait for all pending transactions for the given address to be confirmed +fn wait_pending_transactions(wallet_address: Address) { + let _guard = SEPOLIA_NONCE_LOCK.lock().unwrap(); + let web3 = SEPOLIA_WEB3.clone(); + + loop { + let latest_nonce = block_on(web3.eth().transaction_count(wallet_address, Some(BlockNumber::Latest))).unwrap(); + let pending_nonce = block_on(web3.eth().transaction_count(wallet_address, Some(BlockNumber::Pending))).unwrap(); + + if latest_nonce == pending_nonce { + log!("All pending transactions have been confirmed."); + break; + } else { + log!( + "Waiting for pending transactions to confirm... Current nonce: {}, Pending nonce: {}", + latest_nonce, + pending_nonce + ); + thread::sleep(Duration::from_secs(1)); + } + } +} + +fn get_or_create_nft(ctx: &MmArc, priv_key: &'static str, nft_type: Option) -> EthCoin { + match block_on(lp_coinfind(ctx, NFT_ETH)).unwrap() { + None => global_nft_from_privkey(ctx, sepolia_etomic_maker_nft(), priv_key, nft_type), + Some(mm_coin) => match mm_coin { + MmCoinEnum::EthCoin(nft) => nft, + _ => panic!("Unexpected coin type found. Expected MmCoinEnum::EthCoin"), + }, + } +} + #[test] fn send_and_spend_erc721_maker_payment() { - // 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. + // Sepolia Maker owns tokenId = 1 - let erc721_nft = TestNftType::Erc721 { token_id: 2 }; + 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 maker_global_nft = get_or_create_nft(&MM_CTX, SEPOLIA_MAKER_PRIV, Some(erc721_nft)); + let taker_global_nft = get_or_create_nft(&MM_CTX1, SEPOLIA_TAKER_PRIV, None); - let time_lock = now_sec() + 1000; + let maker_address = block_on(maker_global_nft.my_addr()); + wait_pending_transactions(maker_address); + + let time_lock = now_sec() + 1001; let maker_pubkey = maker_global_nft.derive_htlc_pubkey(&[]); let taker_pubkey = taker_global_nft.derive_htlc_pubkey(&[]); @@ -753,10 +922,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(), - token_id: &BigUint::from(2u32).to_bytes(), + token_address: &sepolia_erc721(), + token_id: &BigUint::from(1u32).to_bytes(), contract_type: &ContractType::Erc721, - swap_contract_address: &nft_swap_contract(), + swap_contract_address: &sepolia_etomic_maker_nft(), }; let send_payment_args: SendNftMakerPaymentArgs = SendNftMakerPaymentArgs { @@ -770,15 +939,15 @@ fn send_and_spend_erc721_maker_payment() { }; let maker_payment = block_on(maker_global_nft.send_nft_maker_payment_v2(send_payment_args)).unwrap(); log!( - "Maker sent ERC721 NFT Payment tx hash {:02x}", - maker_payment.tx_hash_as_bytes() + "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, + wait_until: now_sec() + 150, check_every: 1, }; maker_global_nft.wait_for_confirmations(confirm_input).wait().unwrap(); @@ -805,30 +974,61 @@ 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(), + swap_contract_address: &sepolia_etomic_maker_nft(), }; let spend_tx = block_on(taker_global_nft.spend_nft_maker_payment_v2(spend_payment_args)).unwrap(); + log!( + "Taker spent ERC721 NFT Maker payment, tx hash: {:02x}", + spend_tx.tx_hash() + ); let confirm_input = ConfirmPaymentInput { payment_tx: spend_tx.tx_hex(), confirmations: 1, requires_nota: false, - wait_until: now_sec() + 70, + wait_until: now_sec() + 150, check_every: 1, }; taker_global_nft.wait_for_confirmations(confirm_input).wait().unwrap(); - let new_owner = erc712_owner(U256::from(2)); - let my_address = block_on(taker_global_nft.my_addr()); - assert_eq!(new_owner, my_address); + let new_owner = erc712_owner(U256::from(1)); + let taker_address = block_on(taker_global_nft.my_addr()); + assert_eq!(new_owner, taker_address); + + // send nft back to maker + let send_back_tx = send_safe_transfer_from( + &taker_global_nft, + sepolia_erc721(), + taker_address, + maker_address, + erc721_nft, + ) + .unwrap(); + log!( + "Taker sent ERC721 NFT back to Maker, tx hash: {:02x}", + send_back_tx.tx_hash() + ); + let confirm_input = ConfirmPaymentInput { + payment_tx: send_back_tx.tx_hex(), + confirmations: 1, + requires_nota: false, + wait_until: now_sec() + 150, + check_every: 1, + }; + taker_global_nft.wait_for_confirmations(confirm_input).wait().unwrap(); + + let new_owner = erc712_owner(U256::from(1)); + assert_eq!(new_owner, maker_address); } #[test] fn send_and_spend_erc1155_maker_payment() { - let erc1155_nft = TestNftType::Erc1155 { token_id: 4, amount: 3 }; + // Sepolia Maker owns tokenId = 1, amount = 3 + + 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 maker_global_nft = get_or_create_nft(&MM_CTX, SEPOLIA_MAKER_PRIV, Some(erc1155_nft)); + let taker_global_nft = get_or_create_nft(&MM_CTX1, SEPOLIA_TAKER_PRIV, None); let time_lock = now_sec() + 1000; let maker_pubkey = maker_global_nft.derive_htlc_pubkey(&[]); @@ -838,10 +1038,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(), - token_id: &BigUint::from(4u32).to_bytes(), + token_address: &sepolia_erc1155(), + token_id: &BigUint::from(1u32).to_bytes(), contract_type: &ContractType::Erc1155, - swap_contract_address: &nft_swap_contract(), + swap_contract_address: &sepolia_etomic_maker_nft(), }; let send_payment_args: SendNftMakerPaymentArgs = SendNftMakerPaymentArgs { @@ -855,15 +1055,15 @@ fn send_and_spend_erc1155_maker_payment() { }; let maker_payment = block_on(maker_global_nft.send_nft_maker_payment_v2(send_payment_args)).unwrap(); log!( - "Maker sent ERC1155 NFT Payment tx hash {:02x}", - maker_payment.tx_hash_as_bytes() + "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, + wait_until: now_sec() + 80, check_every: 1, }; maker_global_nft.wait_for_confirmations(confirm_input).wait().unwrap(); @@ -890,21 +1090,51 @@ 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(), + swap_contract_address: &sepolia_etomic_maker_nft(), }; let spend_tx = block_on(taker_global_nft.spend_nft_maker_payment_v2(spend_payment_args)).unwrap(); + log!( + "Taker spent ERC1155 NFT Maker payment, tx hash: {:02x}", + spend_tx.tx_hash() + ); let confirm_input = ConfirmPaymentInput { payment_tx: spend_tx.tx_hex(), confirmations: 1, requires_nota: false, - wait_until: now_sec() + 60, + wait_until: now_sec() + 80, + check_every: 1, + }; + taker_global_nft.wait_for_confirmations(confirm_input).wait().unwrap(); + + let taker_address = block_on(taker_global_nft.my_addr()); + let balance = erc1155_balance(taker_address, U256::from(1)); + assert_eq!(balance, U256::from(3)); + + // send nft back to maker + let maker_address = block_on(maker_global_nft.my_addr()); + let send_back_tx = send_safe_transfer_from( + &taker_global_nft, + sepolia_erc1155(), + taker_address, + maker_address, + erc1155_nft, + ) + .unwrap(); + log!( + "Taker sent ERC1155 NFT back to Maker, tx hash: {:02x}", + send_back_tx.tx_hash() + ); + let confirm_input = ConfirmPaymentInput { + payment_tx: send_back_tx.tx_hex(), + confirmations: 1, + requires_nota: false, + wait_until: now_sec() + 80, check_every: 1, }; taker_global_nft.wait_for_confirmations(confirm_input).wait().unwrap(); - let my_address = block_on(taker_global_nft.my_addr()); - let balance = erc1155_balance(my_address, U256::from(4)); + let balance = erc1155_balance(maker_address, U256::from(1)); assert_eq!(balance, U256::from(3)); } @@ -924,7 +1154,6 @@ fn test_nonce_several_urls() { #[test] fn test_nonce_lock() { - use crate::common::Future01CompatExt; use futures::future::join_all; let coin = eth_coin_with_random_privkey(swap_contract()); diff --git a/mm2src/mm2_main/tests/docker_tests_main.rs b/mm2src/mm2_main/tests/docker_tests_main.rs index 8ad39bf7cd..d9c64039a0 100644 --- a/mm2src/mm2_main/tests/docker_tests_main.rs +++ b/mm2src/mm2_main/tests/docker_tests_main.rs @@ -22,10 +22,12 @@ extern crate serde_json; #[cfg(test)] extern crate ser_error_derive; #[cfg(test)] extern crate test; +use common::custom_futures::timeout::FutureTimerExt; use std::env; use std::io::{BufRead, BufReader}; use std::path::PathBuf; use std::process::Command; +use std::time::Duration; use test::{test_main, StaticBenchFn, StaticTestFn, TestDescAndFn}; use testcontainers::clients::Cli; @@ -86,6 +88,7 @@ pub fn docker_tests_runner(tests: &[&TestDescAndFn]) { utxo_ops.wait_ready(4); utxo_ops1.wait_ready(4); + wait_for_geth_node_ready(); init_geth_node(); wait_until_relayer_container_is_ready(ibc_relayer_node.container.id()); @@ -118,6 +121,29 @@ pub fn docker_tests_runner(tests: &[&TestDescAndFn]) { test_main(&args, owned_tests, None); } +fn wait_for_geth_node_ready() { + let mut attempts = 0; + loop { + if attempts >= 5 { + panic!("Failed to connect to Geth node after several attempts."); + } + match block_on(GETH_WEB3.eth().block_number().timeout(Duration::from_secs(6))) { + Ok(Ok(block_number)) => { + log!("Geth node is ready, latest block number: {:?}", block_number); + break; + }, + Ok(Err(e)) => { + log!("Failed to connect to Geth node: {:?}, retrying...", e); + }, + Err(_) => { + log!("Connection to Geth node timed out, retrying..."); + }, + } + attempts += 1; + thread::sleep(Duration::from_secs(1)); + } +} + fn pull_docker_image(name: &str) { Command::new("docker") .arg("pull") diff --git a/mm2src/mm2_net/src/native_http.rs b/mm2src/mm2_net/src/native_http.rs index 924b4e8448..94f37ef65c 100644 --- a/mm2src/mm2_net/src/native_http.rs +++ b/mm2src/mm2_net/src/native_http.rs @@ -13,7 +13,6 @@ use async_trait::async_trait; use futures::channel::oneshot::Canceled; -use http::header::ACCEPT; use http::{header, HeaderValue, Request}; use hyper::client::connect::Connect; use hyper::client::ResponseFuture; @@ -21,7 +20,7 @@ use hyper::{Body, Client}; use serde_json::Value as Json; use common::wio::{drive03, HYPER}; -use common::APPLICATION_JSON; +use common::{APPLICATION_JSON, X_AUTH_PAYLOAD}; use mm2_err_handle::prelude::*; use super::transport::{GetInfoFromUriError, SlurpError, SlurpResult, SlurpResultJson}; @@ -158,8 +157,7 @@ pub trait SlurpHttpClient { let body_bytes = hyper::body::to_bytes(response.into_body()) .await .map_to_mm(|e| SlurpError::from_hyper_error(e, uri.clone()))?; - let body_str = String::from_utf8(body_bytes.to_vec()).map_to_mm(|e| SlurpError::Internal(e.to_string()))?; - let body: Json = serde_json::from_str(&body_str)?; + let body: Json = serde_json::from_slice(&body_bytes)?; Ok((status, headers, body)) } @@ -237,12 +235,15 @@ impl From for SlurpError { /// # Errors /// /// Returns an error if the HTTP status code of the response is not in the 2xx range. -pub async fn send_request_to_uri(uri: &str) -> MmResult { - let request = http::Request::builder() +pub async fn send_request_to_uri(uri: &str, auth_header: Option<&str>) -> MmResult { + let mut request_builder = http::Request::builder() .method("GET") .uri(uri) - .header(ACCEPT, HeaderValue::from_static(APPLICATION_JSON)) - .body(hyper::Body::from(""))?; + .header(header::ACCEPT, HeaderValue::from_static(APPLICATION_JSON)); + if let Some(auth_header) = auth_header { + request_builder = request_builder.header(X_AUTH_PAYLOAD, HeaderValue::from_str(auth_header)?); + } + let request = request_builder.body(Body::empty())?; let (status, _header, body) = slurp_req_body(request).await?; if !status.is_success() { diff --git a/mm2src/mm2_net/src/transport.rs b/mm2src/mm2_net/src/transport.rs index 3774001b35..dd966feb84 100644 --- a/mm2src/mm2_net/src/transport.rs +++ b/mm2src/mm2_net/src/transport.rs @@ -70,15 +70,16 @@ where } #[derive(Clone, Debug)] -pub struct GuiAuthValidationGenerator { +pub struct ProxyAuthValidationGenerator { pub coin_ticker: String, pub secret: Secret, pub address: String, } -/// gui-auth specific data-type that needed in order to perform gui-auth calls +/// Proxy-auth specific data-type that needed in order to perform proxy-auth calls. +/// Represents a signed message used for authenticating and validating requests processed by the proxy. #[derive(Clone, Serialize)] -pub struct GuiAuthValidation { +pub struct KomodefiProxyAuthValidation { pub coin_ticker: String, pub address: String, pub timestamp_message: i64, @@ -119,6 +120,11 @@ impl From for GetInfoFromUriError { } } +#[cfg(not(target_arch = "wasm32"))] +impl From for GetInfoFromUriError { + fn from(e: hyper::header::InvalidHeaderValue) -> Self { GetInfoFromUriError::Internal(e.to_string()) } +} + /// Sends a POST request to the given URI and expects a 2xx status code in response. /// /// # Errors diff --git a/mm2src/mm2_net/src/wasm/http.rs b/mm2src/mm2_net/src/wasm/http.rs index e836da8c68..4795af346c 100644 --- a/mm2src/mm2_net/src/wasm/http.rs +++ b/mm2src/mm2_net/src/wasm/http.rs @@ -1,7 +1,7 @@ use crate::transport::{GetInfoFromUriError, SlurpError, SlurpResult}; use crate::wasm::body_stream::ResponseBody; use common::executor::spawn_local; -use common::{drop_mutability, stringify_js_error, APPLICATION_JSON}; +use common::{drop_mutability, stringify_js_error, APPLICATION_JSON, X_AUTH_PAYLOAD}; use futures::channel::oneshot; use gstuff::ERRL; use http::header::{ACCEPT, CONTENT_TYPE}; @@ -384,7 +384,7 @@ impl RequestBody { /// # Errors /// /// Returns an error if the HTTP status code of the response is not in the 2xx range. -pub async fn send_request_to_uri(uri: &str) -> MmResult { +pub async fn send_request_to_uri(uri: &str, auth_header: Option<&str>) -> MmResult { macro_rules! try_or { ($exp:expr, $errtype:ident) => { match $exp { @@ -394,10 +394,12 @@ pub async fn send_request_to_uri(uri: &str) -> MmResult Json { }) } +/// global NFT configuration used for Sepolia testnet +pub fn nft_sepolia_conf() -> Json { + json!({ + "coin": "NFT_ETH", + "name": "nftdev", + "chain_id": 11155111, + "mm2": 1, + "derivation_path": "m/44'/60'", + "protocol": { + "type": "NFT", + "protocol_data": { + "platform": "ETH" + } + } + }) +} + pub fn eth_sepolia_conf() -> Json { json!({ "coin": "ETH",