Skip to content

Commit

Permalink
feat(trading-proto-upgrade): locked amounts, kmd burn and other impl (#…
Browse files Browse the repository at this point in the history
…2046)

What's done:
- Locked amount handling for UTXO swaps (more work will be needed for ETH/ERC20)
- Implemented conditional wait for maker payment confirmation before signing funding tx spend preimage on taker's side.
- active_swaps V2 RPC
- Handling accept_only_from for swap messages (validation of the sender)
- Added swap_uuid for swap v2 messages to avoid reusage of the messages generated for other swaps
- Implemented maker payment immediate refund path handling
- Implemented KMD dex fee burn for upgraded swaps
- Added dockerized Geth node for ETH-related integration tests (more to be done in the next sprints)
- Fixed ETH watcher tests

Updated deps:
- test-containers (other Cargo.lock updates are triggered by it). The purpose is to rely on the official version instead of using the fork. The fork also didn't allow passing additional arguments to the image (only `docker run` options were available).
  • Loading branch information
artemii235 authored Feb 21, 2024
1 parent f2dedc2 commit af57160
Show file tree
Hide file tree
Showing 61 changed files with 4,448 additions and 2,121 deletions.
475 changes: 196 additions & 279 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions mm2src/coins/coin_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use std::num::TryFromIntError;

/// Helper type used as result for swap payment validation function(s)
pub type ValidatePaymentFut<T> = Box<dyn Future<Item = T, Error = MmError<ValidatePaymentError>> + Send>;
/// Helper type used as result for swap payment validation function(s)
pub type ValidatePaymentResult<T> = Result<T, MmError<ValidatePaymentError>>;

/// Enum covering possible error cases of swap payment validation
#[derive(Debug, Display)]
Expand Down
102 changes: 73 additions & 29 deletions mm2src/coins/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ use crate::nft::WithdrawNftResult;
use v2_activation::{build_address_and_priv_key_policy, EthActivationV2Error};

mod nonce;
use crate::coin_errors::ValidatePaymentResult;
use crate::nft::nft_errors::GetNftInfoError;
use crate::{PrivKeyPolicy, TransactionResult, WithdrawFrom};
use nonce::ParityNonce;
Expand All @@ -121,9 +122,9 @@ use nonce::ParityNonce;
/// Dev chain (195.201.137.5:8565) contract address: 0x83965C539899cC0F918552e5A26915de40ee8852
/// Ropsten: https://ropsten.etherscan.io/address/0x7bc1bbdd6a0a722fc9bffc49c921b685ecb84b94
/// ETH mainnet: https://etherscan.io/address/0x8500AFc0bc5214728082163326C2FF0C73f4a871
const SWAP_CONTRACT_ABI: &str = include_str!("eth/swap_contract_abi.json");
pub const SWAP_CONTRACT_ABI: &str = include_str!("eth/swap_contract_abi.json");
/// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
const ERC20_ABI: &str = include_str!("eth/erc20_abi.json");
pub const ERC20_ABI: &str = include_str!("eth/erc20_abi.json");
/// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
const ERC721_ABI: &str = include_str!("eth/erc721_abi.json");
/// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md
Expand Down Expand Up @@ -420,7 +421,7 @@ pub struct EthCoinImpl {
ticker: String,
pub coin_type: EthCoinType,
priv_key_policy: EthPrivKeyPolicy,
my_address: Address,
pub my_address: Address,
sign_message_prefix: Option<String>,
swap_contract_address: Address,
fallback_swap_contract: Option<Address>,
Expand Down Expand Up @@ -1134,13 +1135,13 @@ impl SwapOps for EthCoin {
}

#[inline]
fn validate_maker_payment(&self, input: ValidatePaymentInput) -> ValidatePaymentFut<()> {
self.validate_payment(input)
async fn validate_maker_payment(&self, input: ValidatePaymentInput) -> ValidatePaymentResult<()> {
self.validate_payment(input).compat().await
}

#[inline]
fn validate_taker_payment(&self, input: ValidatePaymentInput) -> ValidatePaymentFut<()> {
self.validate_payment(input)
async fn validate_taker_payment(&self, input: ValidatePaymentInput) -> ValidatePaymentResult<()> {
self.validate_payment(input).compat().await
}

fn check_if_my_payment_sent(
Expand Down Expand Up @@ -1487,7 +1488,7 @@ impl WatcherOps for EthCoin {
.watcher_reward
.clone()
.ok_or_else(|| ValidatePaymentError::WatcherRewardError("Watcher reward not found".to_string())));
let expected_reward_amount = try_f!(wei_from_big_decimal(&watcher_reward.amount, self.decimals));
let expected_reward_amount = try_f!(wei_from_big_decimal(&watcher_reward.amount, ETH_DECIMALS));

let expected_swap_contract_address = try_f!(input
.swap_contract_address
Expand Down Expand Up @@ -1665,10 +1666,12 @@ impl WatcherOps for EthCoin {
.map_to_mm(ValidatePaymentError::TxDeserializationError)?;
let total_amount = match input.spend_type {
WatcherSpendType::MakerPaymentSpend => {
if let RewardTarget::None = watcher_reward.reward_target {
trade_amount
} else {
if !matches!(watcher_reward.reward_target, RewardTarget::None)
|| watcher_reward.send_contract_reward_on_spend
{
trade_amount + expected_reward_amount
} else {
trade_amount
}
},
WatcherSpendType::TakerPaymentRefund => trade_amount + expected_reward_amount,
Expand Down Expand Up @@ -1743,7 +1746,6 @@ impl WatcherOps for EthCoin {
};
let expected_swap_contract_address = self.swap_contract_address;
let fallback_swap_contract = self.fallback_swap_contract;
let decimals = self.decimals;

let fut = async move {
let tx_from_rpc = selfi.web3.eth().transaction(TransactionId::Hash(tx.hash)).await?;
Expand Down Expand Up @@ -1787,7 +1789,7 @@ impl WatcherOps for EthCoin {
.get_taker_watcher_reward(&input.maker_coin, None, None, None, input.wait_until)
.await
.map_err(|err| ValidatePaymentError::WatcherRewardError(err.into_inner().to_string()))?;
let expected_reward_amount = wei_from_big_decimal(&watcher_reward.amount, decimals)?;
let expected_reward_amount = wei_from_big_decimal(&watcher_reward.amount, ETH_DECIMALS)?;

match &selfi.coin_type {
EthCoinType::Eth => {
Expand Down Expand Up @@ -1998,7 +2000,6 @@ impl WatcherOps for EthCoin {
RewardTarget::PaymentSender
};

let is_exact_amount = reward_amount.is_some();
let amount = match reward_amount {
Some(amount) => amount,
None => self.get_watcher_reward_amount(wait_until).await?,
Expand All @@ -2008,7 +2009,7 @@ impl WatcherOps for EthCoin {

Ok(WatcherReward {
amount,
is_exact_amount,
is_exact_amount: false,
reward_target,
send_contract_reward_on_spend,
})
Expand Down Expand Up @@ -3371,7 +3372,7 @@ impl EthCoin {
let data = match &args.watcher_reward {
Some(reward) => {
let reward_amount = try_tx_fus!(wei_from_big_decimal(&reward.amount, self.decimals));
if !matches!(reward.reward_target, RewardTarget::None) {
if !matches!(reward.reward_target, RewardTarget::None) || reward.send_contract_reward_on_spend {
value += reward_amount;
}

Expand Down Expand Up @@ -3409,14 +3410,33 @@ impl EthCoin {
let mut value = U256::from(0);
let mut amount = trade_amount;

debug!("Using watcher reward {:?} for swap payment", args.watcher_reward);

let data = match args.watcher_reward {
Some(reward) => {
let reward_amount = try_tx_fus!(wei_from_big_decimal(&reward.amount, self.decimals));

match reward.reward_target {
RewardTarget::Contract | RewardTarget::PaymentSender => value += reward_amount,
RewardTarget::PaymentSpender => amount += reward_amount,
_ => (),
let reward_amount = match reward.reward_target {
RewardTarget::Contract | RewardTarget::PaymentSender => {
let eth_reward_amount = try_tx_fus!(wei_from_big_decimal(&reward.amount, ETH_DECIMALS));
value += eth_reward_amount;
eth_reward_amount
},
RewardTarget::PaymentSpender => {
let token_reward_amount =
try_tx_fus!(wei_from_big_decimal(&reward.amount, self.decimals));
amount += token_reward_amount;
token_reward_amount
},
_ => {
// TODO tests passed without this change, need to research on how it worked
if reward.send_contract_reward_on_spend {
let eth_reward_amount =
try_tx_fus!(wei_from_big_decimal(&reward.amount, ETH_DECIMALS));
value += eth_reward_amount;
eth_reward_amount
} else {
0.into()
}
},
};

try_tx_fus!(function.encode_input(&[
Expand Down Expand Up @@ -4378,7 +4398,11 @@ impl EthCoin {
)?;

match watcher_reward.reward_target {
RewardTarget::None | RewardTarget::PaymentReceiver => (),
RewardTarget::None | RewardTarget::PaymentReceiver => {
if watcher_reward.send_contract_reward_on_spend {
expected_value += actual_reward_amount
}
},
RewardTarget::PaymentSender | RewardTarget::PaymentSpender | RewardTarget::Contract => {
expected_value += actual_reward_amount
},
Expand Down Expand Up @@ -4466,7 +4490,23 @@ impl EthCoin {
)));
}

let expected_reward_amount = wei_from_big_decimal(&watcher_reward.amount, decimals)?;
let expected_reward_amount = match watcher_reward.reward_target {
RewardTarget::Contract | RewardTarget::PaymentSender => {
wei_from_big_decimal(&watcher_reward.amount, ETH_DECIMALS)?
},
RewardTarget::PaymentSpender => {
wei_from_big_decimal(&watcher_reward.amount, selfi.decimals)?
},
_ => {
// TODO tests passed without this change, need to research on how it worked
if watcher_reward.send_contract_reward_on_spend {
wei_from_big_decimal(&watcher_reward.amount, ETH_DECIMALS)?
} else {
0.into()
}
},
};

let actual_reward_amount = get_function_input_data(&decoded, function, 8)
.map_to_mm(ValidatePaymentError::TxDeserializationError)?
.into_uint()
Expand All @@ -4487,7 +4527,11 @@ impl EthCoin {
expected_value += actual_reward_amount
},
RewardTarget::PaymentSpender => expected_amount += actual_reward_amount,
_ => (),
_ => {
if watcher_reward.send_contract_reward_on_spend {
expected_value += actual_reward_amount
}
},
};

if decoded[1] != Token::Uint(expected_amount) {
Expand All @@ -4501,7 +4545,7 @@ impl EthCoin {
if tx_from_rpc.value != expected_value {
return MmError::err(ValidatePaymentError::WrongPaymentTx(format!(
"Payment tx value arg {:?} is invalid, expected {:?}",
tx_from_rpc.value, trade_amount
tx_from_rpc.value, expected_value
)));
}
},
Expand Down Expand Up @@ -4638,8 +4682,8 @@ impl EthCoin {
.map_err(|_| WatcherRewardError::RPCError("Error getting the gas price".to_string()))?;

let gas_cost_wei = U256::from(REWARD_GAS_AMOUNT) * gas_price;
let gas_cost_eth =
u256_to_big_decimal(gas_cost_wei, 18).map_err(|e| WatcherRewardError::InternalError(e.to_string()))?;
let gas_cost_eth = u256_to_big_decimal(gas_cost_wei, ETH_DECIMALS)
.map_err(|e| WatcherRewardError::InternalError(e.to_string()))?;
Ok(gas_cost_eth)
}

Expand Down Expand Up @@ -5670,7 +5714,7 @@ pub async fn eth_coin_from_conf_and_request(

/// Displays the address in mixed-case checksum form
/// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md
fn checksum_address(addr: &str) -> String {
pub fn checksum_address(addr: &str) -> String {
let mut addr = addr.to_lowercase();
if addr.starts_with("0x") {
addr.replace_range(..2, "");
Expand Down
Loading

0 comments on commit af57160

Please sign in to comment.