Skip to content
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

feat(trading-proto-upgrade): locked amounts, kmd burn and other impl #2046

Merged
merged 60 commits into from
Feb 21, 2024
Merged
Show file tree
Hide file tree
Changes from 56 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
f5eb0fc
WIP. Implementing locked amounts for upgraded swaps.
artemii235 Dec 6, 2023
2e3f79b
WIP. Experiments for locked amount handling.
Dec 6, 2023
8b1676b
WIP. Implementing locked amounts for upgraded swaps.
artemii235 Dec 7, 2023
ec6d5e2
WIP. Locked amounts handling.
Dec 8, 2023
15aca49
WIP. Locked amounts handling.
Dec 8, 2023
1f2de9b
WIP. Locked amounts handling after kickstart.
Dec 8, 2023
eaf0ace
WIP. Implementing locked amounts on kickstart.
artemii235 Dec 11, 2023
e8b99a3
WIP. Locked amounts handling after kickstart.
Dec 11, 2023
0464eec
WIP. Implementing locked amounts handling on kickstart.
artemii235 Dec 12, 2023
fd60519
Locked amounts handling partially implemented.
Dec 12, 2023
d9ff38e
Implemented active_swaps V2 RPC.
artemii235 Dec 13, 2023
c361507
Handling accept_only_from in progress.
artemii235 Dec 13, 2023
94dee63
Handling accept_only_from in progress.
Dec 13, 2023
fbf9650
Finish accept_only_from handling. Include uuid in swap messages payload.
artemii235 Dec 14, 2023
6c9ab43
Implementing immediate refund for maker + refactor.
Dec 15, 2023
e1d4908
Implementing immediate refund for maker + refactor.
Dec 16, 2023
98493fb
Implementing maker payment immediate refund.
Dec 18, 2023
fd53c39
Implementing immediate refund for maker + refactor.
Dec 18, 2023
a5fffe7
Implementing maker payment immediate refund.
Dec 19, 2023
d684fa7
Implementing immediate refund for maker.
Dec 19, 2023
1f109f1
Implementing maker payment immediate refund.
artemii235 Dec 20, 2023
7bd7755
Implementing immediate refund for maker.
Dec 20, 2023
a8969b3
Finished maker payment immediate refund.
artemii235 Dec 21, 2023
be9d8d9
Implementing KMD burn.
artemii235 Dec 22, 2023
5c7e43c
Fixes after cherry pick.
Dec 25, 2023
8b9fb7a
Implementing dex fee burn.
Dec 25, 2023
d745e73
Implementing dex fee burn.
Dec 26, 2023
46a91b7
Dex fee burn finished.
Dec 27, 2023
222813a
Fixing clippy.
artemii235 Jan 8, 2024
a1aeb96
Fixing clippy.
artemii235 Jan 8, 2024
ee098d3
Fixing wasm.
artemii235 Jan 8, 2024
55ed473
Fixed WASM.
artemii235 Jan 9, 2024
d719246
Switching to the latest version of testcontainers.
Jan 10, 2024
186064c
Adding Geth dev node usage in docker tests.
artemii235 Jan 11, 2024
d8dbb18
Adding Geth dev node usage in docker tests.
artemii235 Jan 11, 2024
afcc59b
Adding Geth dev node usage in docker tests.
artemii235 Jan 12, 2024
4cb48af
Adding Geth dev node usage in docker tests.
artemii235 Jan 12, 2024
88d279b
Adding Geth dev node usage in docker tests.
artemii235 Jan 15, 2024
b500c81
Fixing swap watcher tests.
Jan 16, 2024
6b7e5ba
Debugging watcher tests.
artemii235 Jan 17, 2024
2efddbd
Review fixes.
artemii235 Jan 18, 2024
e44fc68
Debugging and fixing watcher tests.
artemii235 Jan 18, 2024
6bb2c27
Merge remote-tracking branch 'origin/dev' into swap-proto-upgrade-ite…
Jan 19, 2024
7a0756d
Review fixes.
Jan 19, 2024
1e76676
Debugging and fixing watcher tests.
artemii235 Jan 22, 2024
b924154
Debugging and fixing watcher tests.
Jan 22, 2024
3578c17
Debugging and fixing watcher tests.
Jan 23, 2024
4a5c7b2
Debugging and fixing watcher tests.
Jan 23, 2024
b746028
Debugging and fixing watcher tests.
Jan 24, 2024
e04ff1a
All watcher tests are green (at least locally)
artemii235 Jan 25, 2024
9071b1a
Do not panick on tx receipt error.
artemii235 Jan 25, 2024
8369d90
Impl op_return_data instead of add_op_return_data.
artemii235 Jan 29, 2024
79768b4
Use .map_err(MmError::from) instead of Ok(res?).
Jan 30, 2024
e02ed59
Fix typos and add missing doc comments.
Jan 30, 2024
57352d2
Use ETH_DECIMALS and tweak ETH docker tests.
Jan 30, 2024
c6ea8fa
Tweak watchers tests to be more stable.
Jan 30, 2024
52aaa16
Remove push_bytes and use push_data instead.
Feb 1, 2024
442e759
Remove unneeded coerce_unsized.
artemii235 Feb 2, 2024
e1b42aa
Merge remote-tracking branch 'origin/dev' into swap-proto-upgrade-ite…
Feb 21, 2024
3d76e08
Fixes after merging with dev.
Feb 21, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
475 changes: 196 additions & 279 deletions Cargo.lock
shamardy marked this conversation as resolved.
Show resolved Hide resolved

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 @@ -111,16 +111,17 @@ use crate::nft::{find_wallet_nft_amount, WithdrawNftResult};
use v2_activation::{build_address_and_priv_key_policy, EthActivationV2Error};

mod nonce;
use crate::coin_errors::ValidatePaymentResult;
use crate::{PrivKeyPolicy, TransactionResult, WithdrawFrom};
use nonce::ParityNonce;

/// https://github.com/artemii235/etomic-swap/blob/master/contracts/EtomicSwap.sol
/// 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 @@ -417,7 +418,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 @@ -1128,13 +1129,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 @@ -1481,7 +1482,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 @@ -1659,10 +1660,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 @@ -1737,7 +1740,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 @@ -1781,7 +1783,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 @@ -1992,7 +1994,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 @@ -2002,7 +2003,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 @@ -3365,7 +3366,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 @@ -3403,14 +3404,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()
}
Comment on lines +3430 to +3438
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please specify which tests pass? As I can see when RewardTarget is PaymentReceiver

let reward_target = RewardTarget::PaymentReceiver;

send_contract_reward_on_spend is always false
let send_contract_reward_on_spend = false;

The RewardTarget::PaymentReceiver variant seems to be used for UTXO coins only for the case of UTXO taker / ETH maker - UTXO taker / ERC20 maker here #1750 (comment) this is probably why this check was not needed in eth code.
P.S. I think watchers code needs a lot of refactors to separate it from default swap case logic.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC, all watcher tests were passing with old testnet environment but started to fail after switching to dockerized Geth. send_contract_reward_on_spend can be true in get_maker_watcher_reward if other_coin.is_eth():

let send_contract_reward_on_spend = other_coin.is_eth();

And when it's true, the contract attempts to send additional ETH, which isn't available on its balance. With this change, the reward ETH is also transferred to a contract during payment, making ETH/ERC20 watcher tests pass.

P.S. I think watchers code needs a lot of refactors to separate it from default swap case logic.

I agree with this. My goal was to make tests green and learn ETH watchers code/understand it better. It seems that RewardTarget and send_contract_reward_on_spend can be removed to handle most of the logic on smart contract side. I would like to either work on it myself in the future or guide the developer who will take the task.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

send_contract_reward_on_spend can be true in get_maker_watcher_reward if other_coin.is_eth()

Yeah, missed this since I was looking for cases with RewardTarget::PaymentReceive as looking for None case is not logical.

I would like to either work on it myself in the future or guide the developer who will take the task.

Sure. Thanks a lot for offering your help on this :)

},
};

try_tx_fus!(function.encode_input(&[
Expand Down Expand Up @@ -4319,7 +4339,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 @@ -4407,7 +4431,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 @@ -4428,7 +4468,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 @@ -4442,7 +4486,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 @@ -4579,8 +4623,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 @@ -5598,7 +5642,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
Loading