Skip to content

Commit

Permalink
fix review notes (including: rename approve to approve_token rpc, add…
Browse files Browse the repository at this point in the history
… check for same chain for 1inch swap, move 1inch to 'lp_commands/rpc')
  • Loading branch information
dimxy committed Nov 9, 2024
1 parent ce96d87 commit 65c4853
Show file tree
Hide file tree
Showing 12 changed files with 74 additions and 61 deletions.
7 changes: 7 additions & 0 deletions mm2src/coins/eth/eth_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1048,3 +1048,10 @@ fn test_gas_limit_conf() {
&& eth_coin.gas_limit.eth_max_trade_gas == 150_000
);
}

#[test]
fn test_h256_to_str() {
let h = H256::from_str("5136701f11060010841c9708c3eb26f6606a070b8ae43f4b98b6d7b10a545258").unwrap();
let b: BytesJson = h.0.to_vec().into();
println!("H256={}", format!("0x{:02x}", b));
}
1 change: 0 additions & 1 deletion mm2src/mm2_main/src/mm2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ use mm2_err_handle::prelude::*;

#[cfg(not(target_arch = "wasm32"))] pub mod database;

pub mod ext_api;
pub mod heartbeat_event;
pub mod lp_dispatcher;
pub mod lp_healthcheck;
Expand Down
17 changes: 10 additions & 7 deletions mm2src/mm2_main/src/rpc/dispatcher/dispatcher.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use super::{DispatcherError, DispatcherResult, PUBLIC_METHODS};
use crate::ext_api::one_inch::rpcs::{one_inch_v6_0_classic_swap_contract_rpc, one_inch_v6_0_classic_swap_create_rpc,
one_inch_v6_0_classic_swap_liquidity_sources_rpc,
one_inch_v6_0_classic_swap_quote_rpc, one_inch_v6_0_classic_swap_tokens_rpc};
use crate::lp_healthcheck::peer_connection_healthcheck_rpc;
use crate::lp_native_dex::init_hw::{cancel_init_trezor, init_trezor, init_trezor_status, init_trezor_user_action};
#[cfg(target_arch = "wasm32")]
Expand All @@ -10,12 +7,18 @@ use crate::lp_ordermatch::{best_orders_rpc_v2, orderbook_rpc_v2, start_simple_ma
stop_simple_market_maker_bot};
use crate::lp_swap::swap_v2_rpcs::{active_swaps_rpc, my_recent_swaps_rpc, my_swap_status_rpc};
use crate::lp_wallet::{get_mnemonic_rpc, get_wallet_names_rpc};
use crate::rpc::lp_commands::one_inch::rpcs::{one_inch_v6_0_classic_swap_contract_rpc,
one_inch_v6_0_classic_swap_create_rpc,
one_inch_v6_0_classic_swap_liquidity_sources_rpc,
one_inch_v6_0_classic_swap_quote_rpc,
one_inch_v6_0_classic_swap_tokens_rpc};
use crate::rpc::rate_limiter::{process_rate_limit, RateLimitContext};
use crate::{lp_stats::{add_node_to_version_stat, remove_node_from_version_stat, start_version_stat_collection,
stop_version_stat_collection, update_version_stat_collection},
lp_swap::{get_locked_amount_rpc, max_maker_vol, recreate_swap_data, trade_preimage_rpc},
rpc::lp_commands::{eth::{allowance_rpc, approve_rpc},
get_public_key, get_public_key_hash, get_shared_db_id, trezor_connection_status}};
rpc::lp_commands::{get_public_key, get_public_key_hash, get_shared_db_id,
tokens::{approve_token_rpc, get_token_allowance_rpc},
trezor_connection_status}};
use coins::eth::EthCoin;
use coins::my_tx_history_v2::my_tx_history_v2_rpc;
use coins::rpc_command::tendermint::{ibc_chains, ibc_transfer_channels};
Expand Down Expand Up @@ -163,8 +166,8 @@ async fn dispatcher_v2(request: MmRpcRequest, ctx: MmArc) -> DispatcherResult<Re
"active_swaps" => handle_mmrpc(ctx, request, active_swaps_rpc).await,
"add_delegation" => handle_mmrpc(ctx, request, add_delegation).await,
"add_node_to_version_stat" => handle_mmrpc(ctx, request, add_node_to_version_stat).await,
"approve" => handle_mmrpc(ctx, request, approve_rpc).await,
"allowance" => handle_mmrpc(ctx, request, allowance_rpc).await,
"approve_token" => handle_mmrpc(ctx, request, approve_token_rpc).await,
"get_token_allowance" => handle_mmrpc(ctx, request, get_token_allowance_rpc).await,
"best_orders" => handle_mmrpc(ctx, request, best_orders_rpc_v2).await,
"clear_nft_db" => handle_mmrpc(ctx, request, clear_nft_db).await,
"enable_bch_with_tokens" => handle_mmrpc(ctx, request, enable_platform_coin_with_tokens::<BchCoin>).await,
Expand Down
3 changes: 2 additions & 1 deletion mm2src/mm2_main/src/rpc/lp_commands/lp_commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ use mm2_err_handle::prelude::*;
use rpc::v1::types::H160 as H160Json;
use serde_json::Value as Json;

pub mod eth;
pub mod one_inch;
pub mod tokens;

pub type GetPublicKeyRpcResult<T> = Result<T, MmError<GetPublicKeyError>>;
pub type GetSharedDbIdResult<T> = Result<T, MmError<GetSharedDbIdError>>;
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ pub enum ApiIntegrationRpcError {
NftNotSupported,
#[display(fmt = "Chain not supported")]
ChainNotSupported,
#[display(fmt = "Must be same chain")]
DifferentChains,
#[from_stringify("coins::UnexpectedDerivationMethod")]
MyAddressError(String),
InvalidParam(String),
Expand Down Expand Up @@ -44,6 +46,7 @@ impl HttpStatusCode for ApiIntegrationRpcError {
ApiIntegrationRpcError::CoinTypeError
| ApiIntegrationRpcError::NftNotSupported
| ApiIntegrationRpcError::ChainNotSupported
| ApiIntegrationRpcError::DifferentChains
| ApiIntegrationRpcError::MyAddressError(_)
| ApiIntegrationRpcError::InvalidParam(_)
| ApiIntegrationRpcError::OutOfBounds { .. }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ pub async fn one_inch_v6_0_classic_swap_quote_rpc(
req: ClassicSwapQuoteRequest,
) -> MmResult<ClassicSwapResponse, ApiIntegrationRpcError> {
let (base, base_contract) = get_coin_for_one_inch(&ctx, &req.base).await?;
api_supports_coin(&base)?;
let (rel, rel_contract) = get_coin_for_one_inch(&ctx, &req.rel).await?;
api_supports_coin(&base, &rel)?;
let sell_amount = wei_from_big_decimal(&req.amount.to_decimal(), base.decimals())
.mm_err(|err| ApiIntegrationRpcError::InvalidParam(err.to_string()))?;
let query_params = ClassicSwapQuoteParams::new(base_contract, rel_contract, sell_amount.to_string())
Expand Down Expand Up @@ -64,9 +64,8 @@ pub async fn one_inch_v6_0_classic_swap_create_rpc(
req: ClassicSwapCreateRequest,
) -> MmResult<ClassicSwapResponse, ApiIntegrationRpcError> {
let (base, base_contract) = get_coin_for_one_inch(&ctx, &req.base).await?;
api_supports_coin(&base)?;
let (_, rel_contract) = get_coin_for_one_inch(&ctx, &req.rel).await?;

let (rel, rel_contract) = get_coin_for_one_inch(&ctx, &req.rel).await?;
api_supports_coin(&base, &rel)?;
let sell_amount = wei_from_big_decimal(&req.amount.to_decimal(), base.decimals())
.mm_err(|err| ApiIntegrationRpcError::InvalidParam(err.to_string()))?;
let single_address = base.derivation_method().single_addr_or_err().await?;
Expand Down Expand Up @@ -158,18 +157,21 @@ async fn get_coin_for_one_inch(ctx: &MmArc, ticker: &str) -> MmResult<(EthCoin,
}

#[allow(clippy::result_large_err)]
fn api_supports_coin(coin: &EthCoin) -> MmResult<(), ApiIntegrationRpcError> {
if ApiClient::is_chain_supported(coin.chain_id()) {
Ok(())
} else {
Err(MmError::new(ApiIntegrationRpcError::ChainNotSupported))
fn api_supports_coin(base: &EthCoin, rel: &EthCoin) -> MmResult<(), ApiIntegrationRpcError> {
if !ApiClient::is_chain_supported(base.chain_id()) {
return MmError::err(ApiIntegrationRpcError::ChainNotSupported);
}
if base.chain_id() != rel.chain_id() {
return MmError::err(ApiIntegrationRpcError::DifferentChains);
}
Ok(())
}

#[cfg(test)]
mod tests {
use crate::ext_api::one_inch::{rpcs::{one_inch_v6_0_classic_swap_create_rpc, one_inch_v6_0_classic_swap_quote_rpc},
types::{ClassicSwapCreateRequest, ClassicSwapQuoteRequest}};
use crate::rpc::lp_commands::one_inch::{rpcs::{one_inch_v6_0_classic_swap_create_rpc,
one_inch_v6_0_classic_swap_quote_rpc},
types::{ClassicSwapCreateRequest, ClassicSwapQuoteRequest}};
use coins::eth::EthCoin;
use coins_activation::platform_for_tests::init_platform_coin_with_tokens_loop;
use common::block_on;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::ext_api::one_inch::errors::FromApiValueError;
use crate::rpc::lp_commands::one_inch::errors::FromApiValueError;
use coins::eth::{u256_to_big_decimal, wei_to_gwei_decimal};
use common::true_f;
use ethereum_types::{Address, U256};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,6 @@ use http::StatusCode;
use mm2_core::mm_ctx::MmArc;
use mm2_err_handle::{mm_error::MmError, prelude::MmResult};
use mm2_number::BigDecimal;
use rpc::v1::types::Bytes as BytesJson;

#[derive(Debug, Deserialize)]
pub struct Erc20ApproveRequest {
coin: String,
spender: EthAddress,
amount: BigDecimal,
}

#[derive(Debug, Deserialize)]
pub struct Erc20AllowanceRequest {
coin: String,
spender: EthAddress,
}

#[derive(Debug, Deserialize, Display, EnumFromStringify, Serialize, SerializeErrorType)]
#[serde(tag = "error_type", content = "error_data")]
Expand Down Expand Up @@ -55,22 +41,35 @@ impl HttpStatusCode for Erc20CallError {
}
}

#[derive(Debug, Deserialize)]
pub struct Erc20AllowanceRequest {
coin: String,
spender: EthAddress,
}

/// Call allowance method for ERC20 tokens (see https://eips.ethereum.org/EIPS/eip-20#approve).
/// Returns BigDecimal allowance value.
pub async fn allowance_rpc(ctx: MmArc, req: Erc20AllowanceRequest) -> MmResult<BigDecimal, Erc20CallError> {
pub async fn get_token_allowance_rpc(ctx: MmArc, req: Erc20AllowanceRequest) -> MmResult<BigDecimal, Erc20CallError> {
let eth_coin = find_erc20_eth_coin(&ctx, &req.coin).await?;
let wei = eth_coin.allowance(req.spender).compat().await?;
let amount = u256_to_big_decimal(wei, eth_coin.decimals())?;
Ok(amount)
}

#[derive(Debug, Deserialize)]
pub struct Erc20ApproveRequest {
coin: String,
spender: EthAddress,
amount: BigDecimal,
}

/// Call approve method for ERC20 tokens (see https://eips.ethereum.org/EIPS/eip-20#allowance).
/// Returns approval transaction hash.
pub async fn approve_rpc(ctx: MmArc, req: Erc20ApproveRequest) -> MmResult<BytesJson, Erc20CallError> {
pub async fn approve_token_rpc(ctx: MmArc, req: Erc20ApproveRequest) -> MmResult<String, Erc20CallError> {
let eth_coin = find_erc20_eth_coin(&ctx, &req.coin).await?;
let amount = wei_from_big_decimal(&req.amount, eth_coin.decimals())?;
let tx = eth_coin.approve(req.spender, amount).compat().await?;
Ok(tx.tx_hash_as_bytes())
Ok(format!("0x{:02x}", tx.tx_hash_as_bytes()))
}

async fn find_erc20_eth_coin(ctx: &MmArc, coin: &str) -> Result<EthCoin, MmError<Erc20CallError>> {
Expand Down
38 changes: 16 additions & 22 deletions mm2src/mm2_main/tests/docker_tests/docker_tests_inner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use mm2_test_helpers::for_tests::{check_my_swap_status_amounts, disable_coin, di
enable_eth_with_tokens_v2, erc20_dev_conf, eth_dev_conf, get_locked_amount,
kmd_conf, max_maker_vol, mm_dump, mycoin1_conf, mycoin_conf, set_price, start_swaps,
wait_for_swap_contract_negotiation, wait_for_swap_negotiation_failure,
MarketMakerIt, Mm2TestConf};
MarketMakerIt, Mm2TestConf, DEFAULT_RPC_PASSWORD};
use mm2_test_helpers::{get_passphrase, structs::*};
use serde_json::Value as Json;
use std::collections::{HashMap, HashSet};
Expand Down Expand Up @@ -5525,22 +5525,14 @@ fn test_approve_erc20() {

let coins = json!([eth_dev_conf(), erc20_dev_conf(&erc20_contract_checksum())]);
let mm = MarketMakerIt::start(
json!({
"gui": "nogui",
"netid": 9000,
"dht": "on", // Enable DHT without delay.
"passphrase": format!("0x{}", hex::encode(privkey)),
"coins": coins,
"rpc_password": "pass",
"i_am_seed": true,
}),
"pass".to_string(),
Mm2TestConf::seednode(&format!("0x{}", hex::encode(privkey)), &coins).conf,
DEFAULT_RPC_PASSWORD.to_string(),
None,
)
.unwrap();

let (_mm_dump_log, _mm_dump_dashboard) = mm.mm_dump();
log!("Alice log path: {}", mm.log_path.display());
log!("Node log path: {}", mm.log_path.display());

let swap_contract = format!("0x{}", hex::encode(swap_contract()));
let _eth_enable = block_on(enable_eth_coin(
Expand All @@ -5562,39 +5554,41 @@ fn test_approve_erc20() {

let rc = block_on(mm.rpc(&json!({
"userpass": mm.userpass,
"method":"allowance",
"method":"approve_token",
"mmrpc":"2.0",
"id": 0,
"params":{
"coin": "ERC20DEV",
"spender": swap_contract,
"amount": BigDecimal::from_str("11.0").unwrap(),
}
})))
.unwrap();
assert!(rc.0.is_success(), "allowance error: {}", rc.1);
assert!(rc.0.is_success(), "approve_token error: {}", rc.1);
let res = serde_json::from_str::<Json>(&rc.1).unwrap();
assert!(
BigDecimal::from_str(res["result"].as_str().unwrap()).is_ok(),
"allowance result incorrect"
hex::decode(str_strip_0x!(res["result"].as_str().unwrap())).is_ok(),
"approve_token result incorrect"
);

let rc = block_on(mm.rpc(&json!({
"userpass": mm.userpass,
"method":"approve",
"method":"get_token_allowance",
"mmrpc":"2.0",
"id": 0,
"params":{
"coin": "ERC20DEV",
"spender": swap_contract,
"amount": BigDecimal::from_str("11.0").unwrap(),
}
})))
.unwrap();
assert!(rc.0.is_success(), "approve error: {}", rc.1);
assert!(rc.0.is_success(), "get_token_allowance error: {}", rc.1);
let res = serde_json::from_str::<Json>(&rc.1).unwrap();
assert!(
hex::decode(res["result"].as_str().unwrap()).is_ok(),
"approve result incorrect"
assert_eq!(
BigDecimal::from_str(res["result"].as_str().unwrap()).unwrap(),
BigDecimal::from_str("11.0").unwrap(),
"get_token_allowance result incorrect"
);

block_on(mm.stop()).unwrap();
}
3 changes: 3 additions & 0 deletions mm2src/trading_api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,8 @@ serde_derive = "1.0"
serde_json = { version = "1", features = ["preserve_order", "raw_value"] }
url = { version = "2.2.2", features = ["serde"] }

[features]
test-ext-api = [] # use test config to connect to an external api

[dev-dependencies]
mocktopus = { version = "0.8.0" }
4 changes: 3 additions & 1 deletion mm2src/trading_api/src/one_inch_api/client.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::errors::ApiClientError;
use crate::one_inch_api::errors::NativeError;
use common::StatusCode;
use lazy_static::lazy_static;
#[cfg(feature = "test-ext-api")] use lazy_static::lazy_static;
use mm2_core::mm_ctx::MmArc;
use mm2_err_handle::{map_mm_error::MapMmError,
map_to_mm::MapToMmResult,
Expand All @@ -25,6 +25,7 @@ const ONE_INCH_ETH_SPECIAL_CONTRACT: &str = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
#[cfg(test)]
const ONE_INCH_API_TEST_URL: &str = "https://api.1inch.dev";

#[cfg(feature = "test-ext-api")]
lazy_static! {
/// API key for testing
static ref ONE_INCH_API_TEST_AUTH: String = std::env::var("ONE_INCH_API_TEST_AUTH").unwrap_or_default();
Expand Down Expand Up @@ -123,6 +124,7 @@ impl ApiClient {

fn get_headers() -> Vec<(&'static str, &'static str)> {
vec![
#[cfg(feature = "test-ext-api")]
("Authorization", ONE_INCH_API_TEST_AUTH.as_str()),
("accept", "application/json"),
]
Expand Down

0 comments on commit 65c4853

Please sign in to comment.