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(LRAPI): add 1inch classic swap rpc #2222

Open
wants to merge 8 commits into
base: dev
Choose a base branch
from
Open

Conversation

dimxy
Copy link
Collaborator

@dimxy dimxy commented Sep 16, 2024

This PR adds:

  • initial code to connect to 1inch Liquidity Routing API (LRAPI) provider (see new trading_api crate)
  • two new RPCs to use 1inch classic swap API
  • 'approve' and 'allowance' RPCs (for ERC20 tokens)

@dimxy dimxy added the in progress Changes will be made from the author label Sep 16, 2024
}

/// "1inch_classic_swap_create" rpc impl
pub async fn one_inch_v6_0_classic_swap_create_rpc(
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Note, that this rpc actually creates a transaction to call the swap aggregation contract. It is supposed that the GUI should sign it and send. We don't verify the tx in any way and trust the 1inch api.

Copy link
Member

Choose a reason for hiding this comment

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

Then lest add this clarification to doc comment

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

done

Copy link
Member

@laruh laruh left a comment

Choose a reason for hiding this comment

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

Great start! Here is the 1st review iteration

mm2src/mm2_main/src/ext_api/one_inch.rs Outdated Show resolved Hide resolved
mm2src/mm2_main/src/ext_api.rs Outdated Show resolved Hide resolved
mm2src/trading_api/src/one_inch_api.rs Outdated Show resolved Hide resolved
mm2src/trading_api/src/one_inch_api/types.rs Outdated Show resolved Hide resolved
mm2src/trading_api/src/lib.rs Outdated Show resolved Hide resolved
mm2src/mm2_main/src/ext_api/one_inch/types.rs Show resolved Hide resolved
mm2src/trading_api/src/one_inch_api/types.rs Outdated Show resolved Hide resolved
mm2src/trading_api/src/one_inch_api/types.rs Show resolved Hide resolved
pub struct ClassicSwapQuoteRequest {
pub base: String,
pub rel: String,
pub amount: BigDecimal,
Copy link
Member

Choose a reason for hiding this comment

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

What do you think about using the U256 type for the "amount" from the beginning? We don’t have a 1inch coin, in wallet or our own trading protocol features, so we are free to use coin-specific types for external third-party trading

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I used BigDecimal to make it like most our other rpcs do (for e.g. withdraw).
But now I see I probably should use MmNumber as those classic swap rpcs are close to our "buy" and "sell" methods

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I made the swap amount as MmNumber (like in our own swap rpcs). I hope this is consistent

Copy link
Member

@laruh laruh Sep 22, 2024

Choose a reason for hiding this comment

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

I made the swap amount as MmNumber (like in our own swap rpcs). I hope this is consistent

Hmm, I think yes. We use MmNumber type for atomic swaps and, as 1inch is a trading aggregator, then we can do the same for it.

I will leave comment as unresolved, so other people can find this.

mm2src/mm2_main/src/ext_api/one_inch/rpcs.rs Outdated Show resolved Hide resolved
@dimxy dimxy added under review and removed in progress Changes will be made from the author labels Sep 18, 2024
Copy link
Collaborator

@mariocynicys mariocynicys left a comment

Choose a reason for hiding this comment

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

Thanks :)
First review iteration.

mm2src/mm2_main/src/ext_api.rs Outdated Show resolved Hide resolved
mm2src/mm2_main/src/ext_api/one_inch.rs Outdated Show resolved Hide resolved
mm2src/mm2_main/src/ext_api/one_inch/types.rs Outdated Show resolved Hide resolved
mm2src/mm2_main/src/ext_api/one_inch/types.rs Outdated Show resolved Hide resolved
mm2src/mm2_main/src/ext_api/one_inch/rpcs.rs Outdated Show resolved Hide resolved
mm2src/mm2_main/src/ext_api/one_inch/types.rs Outdated Show resolved Hide resolved
mm2src/mm2_main/src/ext_api/one_inch/rpcs.rs Outdated Show resolved Hide resolved
mm2src/trading_api/src/one_inch_api.rs Outdated Show resolved Hide resolved
mm2src/trading_api/src/one_inch_api/types.rs Outdated Show resolved Hide resolved
mm2src/mm2_main/src/ext_api/one_inch/errors.rs Outdated Show resolved Hide resolved
mm2src/trading_api/src/one_inch_api/client.rs Outdated Show resolved Hide resolved
Comment on lines 56 to 99
pub fn with_fee(mut self, fee: Option<f32>) -> Self {
self.fee = fee;
self
}
pub fn with_protocols(mut self, protocols: Option<String>) -> Self {
self.protocols = protocols;
self
}
pub fn with_gas_price(mut self, gas_price: Option<String>) -> Self {
self.gas_price = gas_price;
self
}
pub fn with_complexity_level(mut self, complexity_level: Option<u32>) -> Self {
self.complexity_level = complexity_level;
self
}
pub fn with_parts(mut self, parts: Option<u32>) -> Self {
self.parts = parts;
self
}
pub fn with_main_route_parts(mut self, main_route_parts: Option<u32>) -> Self {
self.main_route_parts = main_route_parts;
self
}
pub fn with_gas_limit(mut self, gas_limit: Option<u128>) -> Self {
self.gas_limit = gas_limit;
self
}
pub fn with_include_tokens_info(mut self, include_tokens_info: Option<bool>) -> Self {
self.include_tokens_info = include_tokens_info;
self
}
pub fn with_include_protocols(mut self, include_protocols: Option<bool>) -> Self {
self.include_protocols = include_protocols;
self
}
pub fn with_include_gas(mut self, include_gas: Option<bool>) -> Self {
self.include_gas = include_gas;
self
}
pub fn with_connector_tokens(mut self, connector_tokens: Option<String>) -> Self {
self.connector_tokens = connector_tokens;
self
}
Copy link
Member

Choose a reason for hiding this comment

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

I am not a fan of this pattern personally, but if we really want to do this I guess the best way would be creating macro which implements this pattern automatically without taking too much space in the module.

Copy link
Member

Choose a reason for hiding this comment

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

I am not a fan of this pattern personally, but if we really want to do this I guess the best way would be creating macro which implements this pattern automatically without taking too much space in the module.

really like this idea

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

made a macro, great idea, ty

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member

@borngraced borngraced left a comment

Choose a reason for hiding this comment

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

great work! couple notes for first review

mm2src/trading_api/src/one_inch_api/types.rs Outdated Show resolved Hide resolved
mm2src/trading_api/src/one_inch_api/client.rs Outdated Show resolved Hide resolved
mm2src/trading_api/src/one_inch_api/client.rs Outdated Show resolved Hide resolved
@@ -866,6 +852,8 @@ impl EthCoinImpl {
let guard = self.erc20_tokens_infos.lock().unwrap();
(*guard).clone()
}

pub fn chain_id(&self) -> u64 { self.chain_id }
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
pub fn chain_id(&self) -> u64 { self.chain_id }
#[inline(always)]
pub fn chain_id(&self) -> u64 { self.chain_id }

Comment on lines 244 to +245
/// Get chain id
pub(crate) async fn chain_id(&self) -> Result<U256, web3::Error> {
pub(crate) async fn network_chain_id(&self) -> Result<U256, web3::Error> {
Copy link
Member

Choose a reason for hiding this comment

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

nit: I guess we should either remove the doc-comment (as function name is already clear) or update it with "Get network chain id".

Comment on lines +5775 to +5781
#[display(fmt = "No such coin {}", coin)]
NoSuchCoin { coin: String },
#[display(fmt = "Coin not supported {}", coin)]
CoinNotSupported { coin: String },
#[from_stringify("NumConversError")]
#[display(fmt = "Invalid param: {}", _0)]
InvalidParam(String),
Copy link
Member

Choose a reason for hiding this comment

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

nit: I would use the same pattern from NoSuchCoin and CoinNotSupported for InvalidParam (e.g., InvalidParam { param: String }) to make it more explicit. Right now it's not clear what this error takes as a String value.

Comment on lines +5805 to +5806
/// Call allowance for ERC20 tokens
/// Returns BigDecimal value
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
/// Call allowance for ERC20 tokens
/// Returns BigDecimal value
/// Call allowance for ERC20 tokens.
/// Returns BigDecimal value.

Copy link
Member

Choose a reason for hiding this comment

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

Can we add a ref link (like this) for "allowance" and "approve"?

Comment on lines +5821 to +5822
/// Call approve for ERC20 coins
/// Returns signed transaction to send to the chain
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
/// Call approve for ERC20 coins
/// Returns signed transaction to send to the chain
/// Call approve for ERC20 coins.
/// Returns signed transaction to send to the chain.

Comment on lines +5808 to +5818
let coin = lp_coinfind_or_err(&ctx, &req.coin)
.await
.mm_err(|_| Erc20CallError::NoSuchCoin { coin: req.coin.clone() })?;
match coin {
MmCoinEnum::EthCoin(eth_coin) => {
let wei = eth_coin.allowance(req.spender).compat().await?;
let amount = u256_to_big_decimal(wei, eth_coin.decimals())?;
Ok(amount)
},
_ => Err(MmError::new(Erc20CallError::CoinNotSupported { coin: req.coin })),
}
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
let coin = lp_coinfind_or_err(&ctx, &req.coin)
.await
.mm_err(|_| Erc20CallError::NoSuchCoin { coin: req.coin.clone() })?;
match coin {
MmCoinEnum::EthCoin(eth_coin) => {
let wei = eth_coin.allowance(req.spender).compat().await?;
let amount = u256_to_big_decimal(wei, eth_coin.decimals())?;
Ok(amount)
},
_ => Err(MmError::new(Erc20CallError::CoinNotSupported { coin: req.coin })),
}
match lp_coinfind_or_err(&ctx, &req.coin).await {
Ok(MmCoinEnum::EthCoin(eth_coin)) => {
let wei = eth_coin.allowance(req.spender).compat().await?;
let amount = u256_to_big_decimal(wei, eth_coin.decimals())?;
Ok(amount)
},
Ok(_) => Err(MmError::new(Erc20CallError::CoinNotSupported { coin: req.coin })),
Err(_) => Err(MmError::new(Erc20CallError::NoSuchCoin { coin: req.coin.clone() })),
}

Comment on lines +5824 to +5826
let coin = lp_coinfind_or_err(&ctx, &req.coin)
.await
.mm_err(|_| Erc20CallError::NoSuchCoin { coin: req.coin.clone() })?;
Copy link
Member

Choose a reason for hiding this comment

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

The suggestion above could be applied to here as well.

Comment on lines +5802 to +5803
type Erc20AllowanceResult = MmResult<BigDecimal, Erc20CallError>;
type Erc20ApproveResult = MmResult<BytesJson, Erc20CallError>;
Copy link
Member

Choose a reason for hiding this comment

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

Actual results are already quite clear, why is this needed?

Copy link
Collaborator

@mariocynicys mariocynicys left a comment

Choose a reason for hiding this comment

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

Thanks!
LGTM :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants