-
Notifications
You must be signed in to change notification settings - Fork 114
fix(tpu-v2): fix tpu-v2 wait for payment spend and extract secret #2261
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 9 commits
9d7f476
de3a970
ea5475b
934a2f0
ca0ee56
9449cca
2e65abf
43a1baf
c700b59
8d5ed46
707946a
1e7a197
fb383fb
9ec0bab
6c8b2c1
6dcb1c3
f817f5c
ddac3c8
f437dde
02736e4
a08b500
24cb4c3
5f666f3
47f904c
2056f9b
0b3ab9a
cf76cab
c1a5063
43c2d94
0ffffd9
c60a06f
7160045
6201aae
0877d06
d3e6ae1
90b80a3
17b1c94
2df4dd9
a2a448f
95a2b2b
673cd11
e3b4132
9007f12
9d5beeb
5bd4ee2
2d80017
46212fa
ae56f2d
b9cef2b
ac9a5a3
ab56a12
0ca61fd
653e074
f8ba975
0a5ff84
df7778c
f65d6a2
676d09c
09b4b6b
1065997
c214726
ec0d13c
b04f217
a9f481c
67321a6
41f20f9
3c625be
43a0b8b
bbe2f5c
d48cc25
49f46e0
869019b
5750415
0f31d07
62afdff
a1bb59f
1a12a20
b8c5b35
56492ea
2b3a158
b679cd3
f670147
2b496f2
3277eb5
4ccb764
e114b94
1edb188
4bfe410
a91331d
6fe47dd
91fea90
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,13 @@ | ||
| use super::{check_decoded_length, validate_amount, validate_from_to_and_status, validate_payment_state, | ||
| EthPaymentType, PaymentMethod, PrepareTxDataError, ZERO_VALUE}; | ||
| use crate::eth::{decode_contract_call, get_function_input_data, wei_from_big_decimal, EthCoin, EthCoinType, | ||
| ParseCoinAssocTypes, RefundFundingSecretArgs, RefundTakerPaymentArgs, SendTakerFundingArgs, | ||
| SignedEthTx, SwapTxTypeWithSecretHash, TakerPaymentStateV2, TransactionErr, ValidateSwapV2TxError, | ||
| ValidateSwapV2TxResult, ValidateTakerFundingArgs, TAKER_SWAP_V2}; | ||
| use crate::{FundingTxSpend, GenTakerFundingSpendArgs, GenTakerPaymentSpendArgs, SearchForFundingSpendErr, | ||
| WaitForPaymentSpendError}; | ||
| use crate::eth::{decode_contract_call, get_function_input_data, signed_tx_from_web3_tx, wei_from_big_decimal, EthCoin, | ||
| EthCoinType, ParseCoinAssocTypes, RefundFundingSecretArgs, RefundTakerPaymentArgs, | ||
| SendTakerFundingArgs, SignedEthTx, SwapTxTypeWithSecretHash, TakerPaymentStateV2, TransactionErr, | ||
| ValidateSwapV2TxError, ValidateSwapV2TxResult, ValidateTakerFundingArgs, TAKER_SWAP_V2}; | ||
| use crate::{FindPaymentSpendError, FundingTxSpend, GenTakerFundingSpendArgs, GenTakerPaymentSpendArgs, MarketCoinOps, | ||
| SearchForFundingSpendErr}; | ||
| use common::executor::Timer; | ||
| use common::log::{error, info}; | ||
| use common::now_sec; | ||
| use ethabi::{Function, Token}; | ||
| use ethcore_transaction::Action; | ||
|
|
@@ -15,7 +16,7 @@ use ethkey::public_to_address; | |
| use futures::compat::Future01CompatExt; | ||
| use mm2_err_handle::prelude::{MapToMmResult, MmError, MmResult}; | ||
| use std::convert::TryInto; | ||
| use web3::types::TransactionId; | ||
| use web3::types::{BlockNumber, FilterBuilder, Log, TransactionId}; | ||
|
|
||
| const ETH_TAKER_PAYMENT: &str = "ethTakerPayment"; | ||
| const ERC20_TAKER_PAYMENT: &str = "erc20TakerPayment"; | ||
|
|
@@ -457,37 +458,111 @@ impl EthCoin { | |
| Ok(spend_payment_tx) | ||
| } | ||
|
|
||
| /// Checks that taker payment state is `MakerSpent`. | ||
| /// Accepts maker spent payment transaction and returns it if payment status is correct. | ||
| pub(crate) async fn wait_for_taker_payment_spend_impl( | ||
| pub(crate) async fn find_taker_payment_spend_tx_impl( | ||
shamardy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| &self, | ||
| taker_payment: &SignedEthTx, | ||
| taker_payment: &SignedEthTx, // it's approve_tx in Eth case, as in sign_and_send_taker_funding_spend we return approve_tx tx for it | ||
| from_block: u64, | ||
| wait_until: u64, | ||
| ) -> MmResult<SignedEthTx, WaitForPaymentSpendError> { | ||
| let (decoded, taker_swap_v2_contract) = self | ||
| .get_decoded_and_swap_contract(taker_payment, "spendTakerPayment") | ||
| .await?; | ||
| check_every: f64, | ||
| ) -> MmResult<SignedEthTx, FindPaymentSpendError> { | ||
| let taker_swap_v2_contract = self | ||
| .swap_v2_contracts | ||
| .as_ref() | ||
| .map(|contracts| contracts.taker_swap_v2_contract) | ||
| .ok_or_else(|| { | ||
| FindPaymentSpendError::Internal("Expected swap_v2_contracts to be Some, but found None".to_string()) | ||
| })?; | ||
borngraced marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| let approve_func = TAKER_SWAP_V2.function(TAKER_PAYMENT_APPROVE)?; | ||
| let decoded = decode_contract_call(approve_func, taker_payment.unsigned().data())?; | ||
| let id = match decoded.first() { | ||
| Some(Token::FixedBytes(bytes)) => bytes, | ||
| invalid_token => { | ||
| return MmError::err(FindPaymentSpendError::InvalidData(format!( | ||
| "Expected Token::FixedBytes, got {:?}", | ||
| invalid_token | ||
| ))) | ||
| }, | ||
| }; | ||
| // loop to find maker's spendTakerPayment transaction | ||
| loop { | ||
| let taker_status = self | ||
| .payment_status_v2( | ||
| taker_swap_v2_contract, | ||
| decoded[0].clone(), // id from spendTakerPayment | ||
| &TAKER_SWAP_V2, | ||
| EthPaymentType::TakerPayments, | ||
| TAKER_PAYMENT_STATE_INDEX, | ||
| ) | ||
| .await?; | ||
| if taker_status == U256::from(TakerPaymentStateV2::MakerSpent as u8) { | ||
| return Ok(taker_payment.clone()); | ||
| } | ||
| let now = now_sec(); | ||
| if now > wait_until { | ||
| return MmError::err(WaitForPaymentSpendError::Timeout { wait_until, now }); | ||
| return MmError::err(FindPaymentSpendError::Timeout { wait_until, now }); | ||
| } | ||
|
|
||
| let current_block = match self.current_block().compat().await { | ||
| Ok(b) => b, | ||
| Err(e) => { | ||
| error!("Error getting block number: {}", e); | ||
| Timer::sleep(5.).await; | ||
| continue; | ||
| }, | ||
| }; | ||
|
|
||
| // get all logged TakerPaymentSpent events from `from_block` till current block | ||
| let events = match self | ||
| .events_from_block(taker_swap_v2_contract, "TakerPaymentSpent", from_block, current_block) | ||
|
||
| .await | ||
| { | ||
| Ok(events) => events, | ||
| Err(e) => { | ||
| error!( | ||
| "Error getting TakerPaymentSpent events from {} block: {}", | ||
| from_block, e | ||
| ); | ||
| Timer::sleep(5.).await; | ||
| continue; | ||
| }, | ||
| }; | ||
|
|
||
| // this is how spent event looks like in EtomicSwapTakerV2: event TakerPaymentSpent(bytes32 id, bytes32 secret) | ||
| let found_event = events.into_iter().find(|event| &event.data.0[..32] == id.as_slice()); | ||
dimxy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| if let Some(event) = found_event { | ||
| if let Some(tx_hash) = event.transaction_hash { | ||
|
||
| let transaction = match self.transaction(TransactionId::Hash(tx_hash)).await { | ||
| Ok(Some(t)) => t, | ||
| Ok(None) => { | ||
| info!("Tx {} not found yet", tx_hash); | ||
dimxy marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Timer::sleep(check_every).await; | ||
| continue; | ||
mariocynicys marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| }, | ||
| Err(e) => { | ||
| error!("Get tx {} error: {}", tx_hash, e); | ||
| Timer::sleep(check_every).await; | ||
| continue; | ||
| }, | ||
| }; | ||
| let result = signed_tx_from_web3_tx(transaction).map_err(FindPaymentSpendError::Internal)?; | ||
| return Ok(result); | ||
| } | ||
| } | ||
| Timer::sleep(10.).await; | ||
|
|
||
| Timer::sleep(5.).await; | ||
| } | ||
| } | ||
|
|
||
| async fn events_from_block( | ||
| &self, | ||
| swap_contract_address: Address, | ||
| event_name: &str, | ||
| from_block: u64, | ||
| to_block: u64, | ||
| ) -> MmResult<Vec<Log>, FindPaymentSpendError> { | ||
| let contract_event = TAKER_SWAP_V2.event(event_name)?; | ||
| let filter = FilterBuilder::default() | ||
| .topics(Some(vec![contract_event.signature()]), None, None, None) | ||
| .from_block(BlockNumber::Number(from_block.into())) | ||
| .to_block(BlockNumber::Number(to_block.into())) | ||
| .address(vec![swap_contract_address]) | ||
| .build(); | ||
| let events_logs = self | ||
| .logs(filter) | ||
| .await | ||
| .map_err(|e| FindPaymentSpendError::Transport(e.to_string()))?; | ||
| Ok(events_logs) | ||
| } | ||
|
|
||
| /// Prepares data for EtomicSwapTakerV2 contract [ethTakerPayment](https://github.com/KomodoPlatform/etomic-swap/blob/5e15641cbf41766cd5b37b4d71842c270773f788/contracts/EtomicSwapTakerV2.sol#L44) method | ||
| async fn prepare_taker_eth_funding_data(&self, args: &TakerFundingArgs) -> Result<Vec<u8>, PrepareTxDataError> { | ||
| let function = TAKER_SWAP_V2.function(ETH_TAKER_PAYMENT)?; | ||
|
|
@@ -692,6 +767,46 @@ impl EthCoin { | |
|
|
||
| Ok((decoded, taker_swap_v2_contract)) | ||
| } | ||
|
|
||
| /// Extracts the maker's secret from the input of transaction that calls the `spendTakerPayment` smart contract method. | ||
| /// | ||
| /// function spendTakerPayment( | ||
| /// bytes32 id, | ||
| /// uint256 amount, | ||
| /// uint256 dexFee, | ||
| /// address taker, | ||
| /// bytes32 takerSecretHash, | ||
| /// bytes32 makerSecret, | ||
| /// address tokenAddress | ||
| /// ) | ||
| pub(crate) async fn extract_secret_v2_impl( | ||
| &self, | ||
| _secret_hash: &[u8], | ||
| spend_tx: &SignedEthTx, | ||
| ) -> Result<Vec<u8>, String> { | ||
| let function = try_s!(TAKER_SWAP_V2.function("spendTakerPayment")); | ||
| // should be 0xcc90c199 | ||
| let expected_signature = function.short_signature(); | ||
| let signature = &spend_tx.unsigned().data()[0..4]; | ||
| if signature != expected_signature { | ||
| return ERR!( | ||
| "Expected 'spendTakerPayment' contract call signature: {:?}, found {:?}", | ||
| expected_signature, | ||
| signature | ||
| ); | ||
| }; | ||
| let decoded = try_s!(decode_contract_call(function, spend_tx.unsigned().data())); | ||
| if decoded.len() < 7 { | ||
| return ERR!("Invalid arguments in 'spendTakerPayment' call: {:?}", decoded); | ||
| } | ||
| match &decoded[5] { | ||
| Token::FixedBytes(secret) => Ok(secret.to_vec()), | ||
| _ => ERR!( | ||
| "Expected secret to be fixed bytes, but decoded function data is {:?}", | ||
| decoded | ||
| ), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// Validation function for ETH taker payment data | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.