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(tokens): custom token activation for evm #2141

Merged
merged 40 commits into from
Nov 18, 2024
Merged

Conversation

shamardy
Copy link
Collaborator

@shamardy shamardy commented Jun 12, 2024

Todo:

  • Make this PR for EVM only
  • Add get decimals and ticker/symbol RPC by contract address.
    • Can also add a balance API before token is activated to show balance in GUI, it can be a separate API or the same ticker/symbol RPC. Token should be activated to get the balances of all addresses and scan for addresses to show accurate balance. If it's not imported, it can be disabled again. This way we also call balances only one on import instead of twice.
    • Token logo can be returned as well, but we need to check the url for phishing and sanitize it. Will be handled from GUI.
  • Move RPC request/response and code to lp_commands
  • Return wallet_only as true if coin is not in config.
  • Add test coverage
    • Enabling and disabling custom token.
    • Test the new RPC for decimal and symbol
    • Enabling with a contract that is in config
    • Enabling with a contract that has another coin enabled
    • Using a different ticker than the one in config
  • Docs issue and To Test comment

Next PR:

  • Custom token config storage and deletion. Deletion should be when token is deactivated. Will be handled from GUI.
    • An RPC to get previously enabled custom tokens Will be handled from GUI.

To Test (WIP):

  • Custom token required_confirmations should equal to platform's if not set in activation request.

@shamardy shamardy added the in progress Changes will be made from the author label Jun 12, 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.

First review iteration

mm2src/coins_activation/src/l2/init_l2_error.rs Outdated Show resolved Hide resolved
mm2src/coins_activation/src/init_token.rs Outdated Show resolved Hide resolved
pub struct TendermintTokenProtocolInfo {
pub platform: String,
// Todo: can decimals be gotten from rpc call for custom tokens?
Copy link
Member

Choose a reason for hiding this comment

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

There is denoms_metadata endpoint available on tendermint, but I am not sure if it works with the custom tokens.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thanks for the hint, will give it a look.

mm2src/coins_activation/src/init_token.rs Outdated Show resolved Hide resolved
mm2src/coins_activation/src/prelude.rs Outdated Show resolved Hide resolved
mm2src/coins_activation/src/token.rs Show resolved Hide resolved
@shamardy
Copy link
Collaborator Author

@mariocynicys all the nits are fixed and Qs answered. I will merge this PR once CI passes and docs issue is open.

mariocynicys
mariocynicys previously approved these changes Nov 11, 2024
Copy link
Member

@onur-ozkan onur-ozkan left a comment

Choose a reason for hiding this comment

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

Q: Did you think about populating coins file for custom/unsupported coins? For example, we could provide an RPC interface where people can add any custom coin to our coins file and that eventually would allow them to enable and use that coin in KDF. Wouldn't that be much simpler to handle and maintain in KDF? And that would work fine for any of our supported protocols (e.g., cosmos, evm, etc.).

Comment on lines 37 to 52
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?;
match tokens[0] {
Token::Uint(dec) => Ok(dec.as_u64() as u8),
_ => ERR!("Invalid decimals type {:?}", tokens),
}
}

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?;
match &tokens[0] {
Token::String(symbol) => Ok(symbol.clone()),
_ => ERR!("Invalid symbol type {:?}", tokens),
}
}
Copy link
Member

Choose a reason for hiding this comment

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

I wouldn't try to access index 0 directly as it would panic when tokens is empty.

Copy link
Collaborator

Choose a reason for hiding this comment

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

unfortunately, we seem to have these all over the eth code (e.g. \[\d\] in eth_taker_swap_v2.rs), and we consider this safe for some reason :/.
i verified how such vecs come and their sizes in a previous PR, but i would still be on the safe side and not have them addressed like that. also reducing tragic effects from dev errors.

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 wouldn't try to access index 0 directly as it would panic when tokens is empty.

Missed this when copying the code. Will fix only the instances in this PR and fix all others in another PR.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed here f38fc3f

@shamardy
Copy link
Collaborator Author

Q: Did you think about populating coins file for custom/unsupported coins? For example, we could provide an RPC interface where people can add any custom coin to our coins file and that eventually would allow them to enable and use that coin in KDF. Wouldn't that be much simpler to handle and maintain in KDF? And that would work fine for any of our supported protocols (e.g., cosmos, evm, etc.).

I did consider this and can be part of the next PR mentioned here #2141 (comment)

Next PR:

  • Custom token config storage and deletion. Deletion should be when token is deactivated.
    • An RPC to get previously enabled custom tokens

But I think separating them is better so that updating the coins file is simple since it will remain static.

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! some notes

mm2src/coins/eth/erc20.rs Outdated Show resolved Hide resolved
mm2src/coins/eth/erc20.rs Outdated Show resolved Hide resolved
mm2src/coins/eth/erc20.rs Outdated Show resolved Hide resolved
@onur-ozkan
Copy link
Member

Q: Did you think about populating coins file for custom/unsupported coins? For example, we could provide an RPC interface where people can add any custom coin to our coins file and that eventually would allow them to enable and use that coin in KDF. Wouldn't that be much simpler to handle and maintain in KDF? And that would work fine for any of our supported protocols (e.g., cosmos, evm, etc.).

I did consider this and can be part of the next PR mentioned here #2141 (comment)

Next PR:

  • Custom token config storage and deletion. Deletion should be when token is deactivated.

    • An RPC to get previously enabled custom tokens

But I think separating them is better so that updating the coins file is simple since it will remain static.

I would have consider this seriously before making further progress I guess. For example, this PR is EVM only and already adds ~1k diff on the codebase and it will increase even more once we start supporting other protocols and adding a support for custom coin. All that would be dead simple with adding an RPC function for populating the coins file. If we don't want to make modifications on the coins file, I guess that's fine; we could save them in-memory (the value where we search/find coins from) without modifying the actual file on FS. Is there any big advantage that current approach brings compare to what I just suggested?

@shamardy
Copy link
Collaborator Author

shamardy commented Nov 14, 2024

I would have consider this seriously before making further progress I guess. For example, this PR is EVM only and already adds ~1k diff on the codebase and it will increase even more once we start supporting other protocols and adding a support for custom coin.

If we didn't count refactors and tests, it's only ~500 diff, the token info RPC code will be reusable across protocols as well and it's absolutely needed for GUI ref. #2141 (comment), same for CustomTokenError,impl CoinProtocol,fn create_custom_token_config. Implementations are done for the generic init_token function and for any other token protocol we will add the protocol specific implementations only and the rest should work.

All that would be dead simple with adding an RPC function for populating the coins file. If we don't want to make modifications on the coins file, I guess that's fine; we could save them in-memory (the value where we search/find coins from) without modifying the actual file on FS.

The custom config need to be persisted across restarts, which leaves us with two options: modifying the coins file or creating dedicated storage/DB for custom tokens. The process requires more than just adding an RPC function for coins file population - we need comprehensive validation for duplicate tickers, contracts, and other potential conflicts. Most of the validation logic will be necessary regardless of approach. We will also need to make coins config a struct and not just json to deserialize it probably, I reused the CoinProtocol to make it a similar approach as part of the coin config structure is used in the RPC which is an approach that is different but not by too much.

I am not against changing the whole approach if it's clear how it will be implemented, but I can't be sure that using the coins file will not bring more complications of it's own that we didn't anticipate.

@onur-ozkan
Copy link
Member

I would have consider this seriously before making further progress I guess. For example, this PR is EVM only and already adds ~1k diff on the codebase and it will increase even more once we start supporting other protocols and adding a support for custom coin.

If we didn't count refactors and tests, it's only ~500 diff, the token info RPC code will be reusable across protocols as well and it's absolutely needed for GUI ref. #2141 (comment), same for CustomTokenError,impl CoinProtocol,fn create_custom_token_config. Implementations are done for the generic init_token function and for any other token protocol we will add the protocol specific implementations only and the rest should work.

All that would be dead simple with adding an RPC function for populating the coins file. If we don't want to make modifications on the coins file, I guess that's fine; we could save them in-memory (the value where we search/find coins from) without modifying the actual file on FS.

The custom config need to be persisted across restarts, which leaves us with two options: modifying the coins file or creating dedicated storage/DB for custom tokens. The process requires more than just adding an RPC function for coins file population - we need comprehensive validation for duplicate tickers, contracts, and other potential conflicts. Most of the validation logic will be necessary regardless of approach. We will also need to make coins config a struct and not just json to deserialize it probably, I reused the CoinProtocol to make it a similar approach as part of the coin config structure is used in the RPC which is an approach that is different but not by too much.

I am not against changing the whole approach if it's clear how it will be implemented, but I can't be sure that using the coins file will not bring more complications of it's own that we didn't anticipate.

I am suggesting that because in the PR it says "for EVM", and in one of the notes there is a comment says something like "we support tokens only for now, not coins". Because of that, I am suggesting that we can handle every coin, token and protocol in a same way we do with coins file, so we don't need to worry about type of the protocol/coin/token. If it needs to be persistent, we could create another file next to coins file called custom_coins and populate that one. As for the validations, I think they should be done on coins file too. IMO there shouldn't be any difference on parsing and validation custom and original coins values.

@shamardy
Copy link
Collaborator Author

and in one of the notes there is a comment says something like "we support tokens only for now, not coins"

At the current stage, adding custom coins should never be supported as it can be dangerous and shouldn't be allowed to be added by the normal user. @cipig does a lot of checks and tests before adding a coin to coins config repo. It's also the reason why custom tokens will be added as wallet only since there are a lot of non standard tokens that will not work right with swaps.

Because of that, I am suggesting that we can handle every coin, token and protocol in a same way we do with coins file, so we don't need to worry about type of the protocol/coin/token.

I am not against that ref. #2141 (comment)

if it needs to be persistent, we could create another file next to coins file called custom_coins and populate that one.

This will be done in the next PR maybe with the refactors for coin config structs. Should we use a file or db, we have to use db for wasm though.

As for the validations, I think they should be done on coins file too. IMO there shouldn't be any difference on parsing and validation custom and original coins values.

Agreed and I actually thought of this :)

As I said, adding custom coins is dangerous but we should add some validations such as (for utxo):

1 - Transactions/blocks deserializations
2 - Fee validation from a transaction fetched from chain
3 - Validation of address formats and encodings
4- Transaction signing validation, etc..

This is to make sure the coin will work fine for all wallet functionalities, it will also require adding the RPC urls by the user. For swaps, it's a different thing and will require more thinking about.

Can I do this in a later PR? right now EVM custom tokens are needed to be released with 1inch integration so that users can swap any token, wallet only means not working for our cross chain swaps only but will be allowed to work with same chain dexes.

@dimxy
Copy link
Collaborator

dimxy commented Nov 15, 2024

Q: Did you think about populating coins file for custom/unsupported coins? For example, we could provide an RPC

I think it's better to store customs tokens in a separate file/db (and retain the original coins file intact).
So if installation gets corrupted the user can reinstall the app to repair (including the original coins file).
I think reinstallation should preserve the custom coins data but users should also have a option to clear app's data to restore to the original state (there is also a question if the customs coins format has changed - we need to provide its upgrade on reinstall)

Copy link
Collaborator

@dimxy dimxy left a comment

Choose a reason for hiding this comment

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

LGTM

@shamardy shamardy merged commit 22719c0 into dev Nov 18, 2024
23 of 28 checks passed
@shamardy shamardy deleted the feat-custom-evm-token branch November 18, 2024 18:12
dimxy added a commit that referenced this pull request Nov 26, 2024
* 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)
Alrighttt pushed a commit that referenced this pull request Nov 26, 2024
Adds support for enabling custom EVM (ERC20, PLG20, etc..) tokens without requiring them to be in the coins config. This allows users to interact with any ERC20 token by providing the contract address.
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