Skip to content

Commit

Permalink
Merge branch 'dev' into 1inch-classic-swap
Browse files Browse the repository at this point in the history
* dev:
  chore(release): update v2.2.0-beta date (#2277)
  chore(release): add changelog entries for v2.2.0-beta (#2240)
  fix(watchers): align taker fee validation retries with makers (#2263)
  feat(tokens): custom token activation for evm (#2141)
  use safer subtraction on healthcheck expiration check (#2272)
  fix(hd-wallet): correctly display evm addr in `get_new_address` response (#2264)
  • Loading branch information
dimxy committed Nov 26, 2024
2 parents 7b5bed3 + af89011 commit 0e2680a
Show file tree
Hide file tree
Showing 43 changed files with 1,214 additions and 340 deletions.
89 changes: 89 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,92 @@
## v2.2.0-beta - 2024-11-22

**Features:**
- Connection Healthcheck
- Connection healthcheck implementation for peers was introduced. [#2194](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2194)
- Custom Tokens Activation
- Support for enabling custom EVM (ERC20, PLG20, etc..) tokens without requiring them to be in the coins config was added. [#2141](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2141)
- This allows users to interact with any ERC20 token by providing the contract address.

**Enhancements/Fixes:**
- Trading Protocol Upgrade [#1895](https://github.com/KomodoPlatform/atomicDEX-API/issues/1895)
- EVM TPU taker methods were implemented and enhancements were made to ETH docker tests. [#2169](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2169)
- EVM TPU maker methods were implemented. [#2211](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2211)
- NFT integration [#900](https://github.com/KomodoPlatform/atomicDEX-API/issues/900)
- Refund methods for NFT swaps were completed. [#2129](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2129)
- `token_id` field was added to the tx history primary key. [#2209](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2209)
- Graceful Shutdown
- CTRL-C signal handling with graceful shutdown was implemented. [#2213](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2213)
- Seed Management [#1939](https://github.com/KomodoPlatform/komodo-defi-framework/issues/1939)
- A new `get_wallet_names` RPC was added to retrieve information about all wallet names and the currently active one. [#2202](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2202)
- Cosmos Integration [#1432](https://github.com/KomodoPlatform/atomicDEX-API/issues/1432)
- Cosmos tx broadcasting error was fixed by upgrading cosmrs to version 15. [#2238](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2238)
- Cosmos transaction history implementation was incorrectly parsing addresses (using the relayer address instead of the cross-chain address) from IBC transactions. The address parsing logic was fixed in [#2245](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2245)
- Order Management
- Cancel order race condition was addressed using time-based cache. [#2232](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2232)
- Swap Improvements
- A legacy swap issue was resolved where taker spent maker payment transactions were sometimes incorrectly marked as successful when they were actually reverted or not confirmed, particularly in EVM-based swaps. [#2199](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2199)
- Two new events were added: "MakerPaymentSpendConfirmed" and "MakerPaymentSpendConfirmFailed"
- A fix was introduced where Takers don't need to confirm their own payment as they can wait for the spending of it straight away. [#2249](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2249)
- This invalidates this fix [#1442](https://github.com/KomodoPlatform/komodo-defi-framework/issues/1442), a better solution will be introduced where taker rebroadcasts their transaction if it's not on the chain.
- A fix was introduced for recover funds for takers when the swap was marked as unsuccessful due to the maker payment spend transaction not being confirmed. [#2242](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2242)
- The required confirmations from coin config for taker/maker payment spend are now used instead of using 1 confirmation max. This is because some chains require more than 1 confirmation for finality, e.g. Polygon.
- Swap watchers [#1431](https://github.com/KomodoPlatform/atomicDEX-API/issues/1431)
- Taker fee validation retries now work the same way as for makers. [#2263](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2263)
- Electrum Client
- Electrum client was refactored to add min/max connection controls, with server priority based on list order. [#1966](https://github.com/KomodoPlatform/komodo-defi-framework/pull/1966)
- Electrum client can now operate in single-server mode (1,1) to reduce resource usage (especially beneficial for mobile) or multi-server (legacy) mode for reliability.
- Higher priority servers automatically replace lower priority ones when reconnecting during periodic retries or when connection count drops below minimum.
- Coins Activation
- EVM addresses are now displayed in full in iguana v2 activation response. [#2254](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2254)
- HD Wallet [#1838](https://github.com/KomodoPlatform/komodo-defi-framework/issues/1838)
- Balance is now returned as `CoinBalanceMap` for both UTXOs and QTUM. [#2259](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2259)
- This is to return the same type/json across all coins for GUIs since EVM uses `CoinBalanceMap`.
- EVM addresses are displayed in full in `get_new_address` response after [#2264](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2264)
- RPC Service
- A fix was introduced to run rpc request futures till completion in [#1966](https://github.com/KomodoPlatform/komodo-defi-framework/pull/1966)
- This ensures RPC request futures complete fully even if clients disconnect, preventing partial state updates and maintaining data consistency.
- Security Enhancements
- Message lifetime overflows were added to prevent creating messages for proxy with too long lifetimes. [#2233](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2233)
- Remote files are now handled in a safer way in CI. [#2217](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2217)
- Build Process
- `wasm-opt` overriding was removed. [#2200](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2200)
- Escaped response body in native RPC was removed. [#2219](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2219)
- Creation of the all-zeroes dir on KDF start was stopped. [#2218](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2218)
- OPTIONS requests to KDF server were added. [#2191](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2191)

**Removals:**
- Solana Support [#1085](https://github.com/KomodoPlatform/komodo-defi-framework/issues/1085)
- Solana implementation was removed until it can be redone using the latest Solana SDK. [#2239](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2239)
- Adex-CLI [#1682](https://github.com/KomodoPlatform/atomicDEX-API/issues/1682)
- adex-cli was deprecated pending work on a simpler, more maintainable implementation. [#2234](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2234)

**Other Changes:**
- Documentation
- Issue link in README was updated. [#2227](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2227)
- Commit badges were updated to use dev branch in README. [#2193](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2193)
- Leftover subcommands were removed from help message. [#2235](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2235) [#2270](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2270)
- Code Structure
- lib.rs was replaced by mm2.rs as the root lib for mm2_main. [#2178](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2178)
- Code Improvements
- P2P feature was added to mm2_net dependency to allow the coins crate to be compiled and tested independently. [#2210](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2210)
- Coins mod clippy warnings in WASM were fixed. [#2224](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2224)
- Nonsense CLI arguments were removed. [#2216](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2216)
- Tests
- Tendermint IBC tests were fixed by preparing IBC channels inside the container. [#2246](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2246)
- `.wait()` usage was replaced with `block_on` in tests to ensure consistent runtime usage, fixing issues with tokio TCP streams in non-tokio runtimes. [#2220](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2220)
- Debug assertions for tests were enabled. [#2204](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2204)
- More Sepolia test endpoints were added in [#2262](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2262)

**NB - Backwards compatibility breaking changes:**
- RPC Renaming
- `get_peers_info` RPC was renamed to `get_directly_connected_peers`. [#2195](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2195)
- Cosmos Integration [#1432](https://github.com/KomodoPlatform/atomicDEX-API/issues/1432)
- Updates to Tendermint activation payloads:
- 'rpc_urls' field (previously a list of plain string values) is replaced with 'nodes' (a list of JSON objects). [#2173](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2173)
- Komodo DeFi Proxy
- All RPC methods fields controlling komodo-defi-proxy are renamed to 'komodo_proxy', affecting various activations, including ETH/EVM. [#2173](https://github.com/KomodoPlatform/komodo-defi-framework/pull/2173)


## v2.1.0-beta - 2024-07-31

**Features:**
Expand Down
37 changes: 7 additions & 30 deletions mm2src/coins/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ pub(crate) use eip1559_gas_fee::FeePerGasEstimated;
use eip1559_gas_fee::{BlocknativeGasApiCaller, FeePerGasSimpleEstimator, GasApiConfig, GasApiProvider,
InfuraGasApiCaller};

pub mod erc20;
use erc20::get_token_decimals;

pub(crate) mod eth_swap_v2;
use eth_swap_v2::{EthPaymentType, PaymentMethod};

Expand Down Expand Up @@ -869,7 +872,7 @@ pub struct EthCoinImpl {
/// and unlocked once the transaction is confirmed. This prevents nonce conflicts when multiple transactions
/// are initiated concurrently from the same address.
address_nonce_locks: Arc<AsyncMutex<HashMap<String, Arc<AsyncMutex<()>>>>>,
erc20_tokens_infos: Arc<Mutex<HashMap<String, Erc20TokenInfo>>>,
erc20_tokens_infos: Arc<Mutex<HashMap<String, Erc20TokenDetails>>>,
/// Stores information about NFTs owned by the user. Each entry in the HashMap is uniquely identified by a composite key
/// consisting of the token address and token ID, separated by a comma. This field is essential for tracking the NFT assets
/// information (chain & contract type, amount etc.), where ownership and amount, in ERC1155 case, might change over time.
Expand All @@ -893,7 +896,7 @@ pub struct Web3Instance {

/// Information about a token that follows the ERC20 protocol on an EVM-based network.
#[derive(Clone, Debug)]
pub struct Erc20TokenInfo {
pub struct Erc20TokenDetails {
/// The contract address of the token on the EVM-based network.
pub token_address: Address,
/// The number of decimal places the token uses.
Expand Down Expand Up @@ -1054,14 +1057,14 @@ impl EthCoinImpl {
}
}

pub fn add_erc_token_info(&self, ticker: String, info: Erc20TokenInfo) {
pub fn add_erc_token_info(&self, ticker: String, info: Erc20TokenDetails) {
self.erc20_tokens_infos.lock().unwrap().insert(ticker, info);
}

/// # Warning
/// Be very careful using this function since it returns dereferenced clone
/// of value behind the MutexGuard and makes it non-thread-safe.
pub fn get_erc_tokens_infos(&self) -> HashMap<String, Erc20TokenInfo> {
pub fn get_erc_tokens_infos(&self) -> HashMap<String, Erc20TokenDetails> {
let guard = self.erc20_tokens_infos.lock().unwrap();
(*guard).clone()
}
Expand Down Expand Up @@ -6313,32 +6316,6 @@ fn signed_tx_from_web3_tx(transaction: Web3Transaction) -> Result<SignedEthTx, S
Ok(try_s!(SignedEthTx::new(unverified)))
}

async fn get_token_decimals(web3: &Web3<Web3Transport>, token_addr: Address) -> Result<u8, String> {
let function = try_s!(ERC20_CONTRACT.function("decimals"));
let data = try_s!(function.encode_input(&[]));
let request = CallRequest {
from: Some(Address::default()),
to: Some(token_addr),
gas: None,
gas_price: None,
value: Some(0.into()),
data: Some(data.into()),
..CallRequest::default()
};

let res = web3
.eth()
.call(request, Some(BlockId::Number(BlockNumber::Latest)))
.map_err(|e| ERRL!("{}", e))
.await?;
let tokens = try_s!(function.decode_output(&res.0));
let decimals = match tokens[0] {
Token::Uint(dec) => dec.as_u64(),
_ => return ERR!("Invalid decimals type {:?}", tokens),
};
Ok(decimals as u8)
}

pub fn valid_addr_from_str(addr_str: &str) -> Result<Address, String> {
let addr = try_s!(addr_from_str(addr_str));
if !is_valid_checksum_addr(addr_str) {
Expand Down
107 changes: 107 additions & 0 deletions mm2src/coins/eth/erc20.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
use crate::eth::web3_transport::Web3Transport;
use crate::eth::{EthCoin, ERC20_CONTRACT};
use crate::{CoinsContext, MmCoinEnum};
use ethabi::Token;
use ethereum_types::Address;
use futures_util::TryFutureExt;
use mm2_core::mm_ctx::MmArc;
use mm2_err_handle::mm_error::MmResult;
use web3::types::{BlockId, BlockNumber, CallRequest};
use web3::{Transport, Web3};

async fn call_erc20_function<T: Transport>(
web3: &Web3<T>,
token_addr: Address,
function_name: &str,
) -> Result<Vec<Token>, String> {
let function = try_s!(ERC20_CONTRACT.function(function_name));
let data = try_s!(function.encode_input(&[]));
let request = CallRequest {
from: Some(Address::default()),
to: Some(token_addr),
gas: None,
gas_price: None,
value: Some(0.into()),
data: Some(data.into()),
..CallRequest::default()
};

let res = web3
.eth()
.call(request, Some(BlockId::Number(BlockNumber::Latest)))
.map_err(|e| ERRL!("{}", e))
.await?;
function.decode_output(&res.0).map_err(|e| ERRL!("{}", e))
}

pub(crate) async fn get_token_decimals(web3: &Web3<Web3Transport>, token_addr: Address) -> Result<u8, String> {
let tokens = call_erc20_function(web3, token_addr, "decimals").await?;
let Some(token) = tokens.into_iter().next() else {
return ERR!("No value returned from decimals() call");
};
let Token::Uint(dec) = token else {
return ERR!("Expected Uint token for decimals, got {:?}", token);
};
Ok(dec.as_u64() as u8)
}

async fn get_token_symbol(coin: &EthCoin, token_addr: Address) -> Result<String, String> {
let web3 = try_s!(coin.web3().await);
let tokens = call_erc20_function(&web3, token_addr, "symbol").await?;
let Some(token) = tokens.into_iter().next() else {
return ERR!("No value returned from symbol() call");
};
let Token::String(symbol) = token else {
return ERR!("Expected String token for symbol, got {:?}", token);
};
Ok(symbol)
}

#[derive(Serialize)]
pub struct Erc20TokenInfo {
pub symbol: String,
pub decimals: u8,
}

pub async fn get_erc20_token_info(coin: &EthCoin, token_addr: Address) -> Result<Erc20TokenInfo, String> {
let symbol = get_token_symbol(coin, token_addr).await?;
let web3 = try_s!(coin.web3().await);
let decimals = get_token_decimals(&web3, token_addr).await?;
Ok(Erc20TokenInfo { symbol, decimals })
}

/// Finds if an ERC20 token is in coins config by its contract address and returns its ticker.
pub fn get_erc20_ticker_by_contract_address(ctx: &MmArc, platform: &str, contract_address: &str) -> Option<String> {
ctx.conf["coins"].as_array()?.iter().find_map(|coin| {
let protocol = coin.get("protocol")?;
let protocol_type = protocol.get("type")?.as_str()?;
if protocol_type != "ERC20" {
return None;
}
let protocol_data = protocol.get("protocol_data")?;
let coin_platform = protocol_data.get("platform")?.as_str()?;
let coin_contract_address = protocol_data.get("contract_address")?.as_str()?;

if coin_platform == platform && coin_contract_address == contract_address {
coin.get("coin")?.as_str().map(|s| s.to_string())
} else {
None
}
})
}

/// Finds an enabled ERC20 token by its contract address and returns it as `MmCoinEnum`.
pub async fn get_enabled_erc20_by_contract(
ctx: &MmArc,
contract_address: Address,
) -> MmResult<Option<MmCoinEnum>, String> {
let cctx = CoinsContext::from_ctx(ctx)?;
let coins = cctx.coins.lock().await;

Ok(coins.values().find_map(|coin| match &coin.inner {
MmCoinEnum::EthCoin(eth_coin) if eth_coin.erc20_token_address() == Some(contract_address) => {
Some(coin.inner.clone())
},
_ => None,
}))
}
8 changes: 4 additions & 4 deletions mm2src/coins/eth/eth_balance_events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use mm2_number::BigDecimal;
use std::collections::{HashMap, HashSet};

use super::EthCoin;
use crate::{eth::{u256_to_big_decimal, Erc20TokenInfo},
use crate::{eth::{u256_to_big_decimal, Erc20TokenDetails},
BalanceError, CoinWithDerivationMethod, MmCoin};

struct BalanceData {
Expand All @@ -40,9 +40,9 @@ async fn get_all_balance_results_concurrently(coin: &EthCoin, addresses: HashSet
//
// Unlike tokens, the platform coin length is constant (=1). Instead of creating a generic
// type and mapping the platform coin and the entire token list (which can grow at any time), we map
// the platform coin to Erc20TokenInfo so that we can use the token list right away without
// the platform coin to Erc20TokenDetails so that we can use the token list right away without
// additional mapping.
tokens.insert(coin.ticker.clone(), Erc20TokenInfo {
tokens.insert(coin.ticker.clone(), Erc20TokenDetails {
// This is a dummy value, since there is no token address for the platform coin.
// In the fetch_balance function, we check if the token_ticker is equal to this
// coin's ticker to avoid using token_address to fetch the balance
Expand Down Expand Up @@ -72,7 +72,7 @@ async fn fetch_balance(
coin: &EthCoin,
address: Address,
token_ticker: String,
info: &Erc20TokenInfo,
info: &Erc20TokenDetails,
) -> Result<BalanceData, BalanceFetchError> {
let (balance_as_u256, decimals) = if token_ticker == coin.ticker {
(
Expand Down
Loading

0 comments on commit 0e2680a

Please sign in to comment.