Conversation
Signed-off-by: Onur Özkan <work@onurozkan.dev>
Signed-off-by: Onur Özkan <work@onurozkan.dev>
Signed-off-by: Onur Özkan <work@onurozkan.dev>
Signed-off-by: Onur Özkan <work@onurozkan.dev>
Signed-off-by: Onur Özkan <work@onurozkan.dev>
Signed-off-by: Onur Özkan <work@onurozkan.dev>
Signed-off-by: Onur Özkan <work@onurozkan.dev>
Signed-off-by: Onur Özkan <work@onurozkan.dev>
Signed-off-by: Onur Özkan <work@onurozkan.dev>
|
|
||
| #[cfg(test)] | ||
| pub mod tendermint_falsecoin_tests { | ||
| pub mod tests { |
There was a problem hiding this comment.
This seems like was renamed unintentionally in #2223.
Signed-off-by: Onur Özkan <work@onurozkan.dev>
Signed-off-by: Onur Özkan <work@onurozkan.dev>
Signed-off-by: Onur Özkan <work@onurozkan.dev>
Signed-off-by: Onur Özkan <work@onurozkan.dev>
… into solana-withdraw
Signed-off-by: Onur Özkan <work@onurozkan.dev>
Signed-off-by: Onur Özkan <work@onurozkan.dev>
shamardy
left a comment
There was a problem hiding this comment.
Thanks for the PR! First review iteration from my side!
mm2src/coins/solana/solana_token.rs
Outdated
| instructions.push(create_associated_token_account( | ||
| &coin.address, | ||
| &to, | ||
| &token.protocol_info.mint_address, | ||
| &spl_token_program::id(), | ||
| )); |
There was a problem hiding this comment.
shouldn't we make sure we can cover the rent in such case? We should also account for the rent as part of the fee or add it to SolanaFeeDetails which makes more sense.
There was a problem hiding this comment.
I don't know what the rent is. I need to learn it first.
There was a problem hiding this comment.
I would've preferred it in this PR as it's related to withdraw, but it can be in a small PR next before transaction history.
Signed-off-by: Onur Özkan <work@onurozkan.dev>
Signed-off-by: Onur Özkan <work@onurozkan.dev>
Signed-off-by: Onur Özkan <work@onurozkan.dev>
Signed-off-by: Onur Özkan <work@onurozkan.dev>
72bbfea to
3dbc4b8
Compare
mariocynicys
left a comment
There was a problem hiding this comment.
awesome work!
first iter from my side, mostly questions xD
mm2src/coins/solana/solana_coin.rs
Outdated
| if lamports == 0 { | ||
| return MmError::err(WithdrawError::AmountTooLow { | ||
| amount: req.amount, | ||
| threshold: coin.min_tx_amount(), | ||
| }); | ||
| } |
There was a problem hiding this comment.
it won't == 0, we do that check above in calculate-withdraw_amount (checking with coin.min_tx_amount())
There was a problem hiding this comment.
Yes but it's hard to track (if we change calculate_withdraw_amount we will most likely forget to add the check in withdraw). So for the sake of safety/explicitly I would still keep it here to ensure everything is guaranteed.
mm2src/coins/solana/solana_coin.rs
Outdated
| let fee = rpc | ||
| .get_fee_for_message(tx.message()) | ||
| .map_err(|e| WithdrawError::Transport(e.to_string()))?; |
There was a problem hiding this comment.
cant we calculate the tx fee internally without invoking the rpc?
also im not sure if this method does an estimation or query the fee for this specific transaction from the blockchain?
nvm, i thought that solana_system_transaction::transfer sends the transaction on-chain.
but then i got a Q: does this mean that the tx fee is calculated dynamically based on the blockchain conditions? do we have any control/limit over the fees that could be spent from out account at the time of tx publishing?
There was a problem hiding this comment.
Q: does this mean that the tx fee is calculated dynamically based on the blockchain conditions?
Yes.
Do we have any control/limit over the fees that could be spent from out account at the time of tx publishing?
Well, we see the fee before we broadcasting it, so there is a bit of control.
| fn token_id(&self) -> RpcBytes { | ||
| sha256(self.ticker().to_lowercase().as_bytes()).to_vec().into() | ||
| } |
There was a problem hiding this comment.
don't we want to relate token_id to the mint address rather than the ticker, as the ticker might change, no?
or two tokens might have the same ticker?
There was a problem hiding this comment.
I am not sure if it's ever possible to be 2 different tokens with the same ticker on the same chain. But I do liked using the mint address more.
mm2src/coins/solana/solana_token.rs
Outdated
| if let Err(e) = rpc.get_account(&to_token_account) { | ||
| if !e.kind.to_string().contains("AccountNotFound") { | ||
| return MmError::err(WithdrawError::Transport(e.to_string())); | ||
| } | ||
|
|
||
| instructions.push(create_associated_token_account( | ||
| &coin.address, |
There was a problem hiding this comment.
Q: what happens if when publishing the tx we found out that the account has already been created? will the tx fail or this instruction get ignored?
There was a problem hiding this comment.
I guess you are referring to the account being created between the transaction generation and the sending phase? In that case the transaction would fail. There is another function that allows it to succeed even if the account already exists, I can use that too if we don't want TX to fail.
|
|
||
| if let Err(e) = rpc.get_account(&to_token_account) { | ||
| if !e.kind.to_string().contains("AccountNotFound") { | ||
| return MmError::err(WithdrawError::Transport(e.to_string())); |
There was a problem hiding this comment.
I'd like to remind that it's preferable to return error codes rather string messages,
especially when it is important to show errors translated into the user native language.
Here user probably would like to get a message in their native language that the destination account is not found?
I see in the KW repo they have a framework for error translation by error codes. So I think we should return more error codes.
(I guess we should return string descriptions (non-translatable) only when we get unrecoverable internal errors).
There was a problem hiding this comment.
We are not sending custom string message here. The whole error converted into string so we can use it in WithdrawError. User will see the complete error message including the error code (if there are any) wrapped with KDF WithdrawError.
There was a problem hiding this comment.
@onur-ozkan we can match the .kind field instead of serializing it and perform the contains() check.
Signed-off-by: Onur Özkan <work@onurozkan.dev>
07c6762 to
4c39cb3
Compare
Signed-off-by: Onur Özkan <work@onurozkan.dev>
4c39cb3 to
dd8eccf
Compare
shamardy
left a comment
There was a problem hiding this comment.
I left some nits and things to do in a subsequent PR or here, whatever you prefer. Other than that, LGTM!
| pub(crate) async fn rpc_client(&self) -> MmResult<Arc<RpcClient>, String> { | ||
| let mut rpcs = self.rpc_clients.lock().await; | ||
|
|
||
| if let Some(index) = rpcs.iter().position(|rpc| rpc.get_health().is_ok()) { | ||
| // Put healthy one to the front. | ||
| rpcs.rotate_left(index); | ||
|
|
||
| return Ok(rpcs[0].clone()); | ||
| for (index, rpc) in rpcs.iter().enumerate() { | ||
| if rpc.get_health().await.is_ok() { | ||
| rpcs.rotate_left(index); | ||
| return Ok(rpcs[0].clone()); | ||
| } | ||
| } |
There was a problem hiding this comment.
A comment for next PRs, please think about randomizing RPCs order on coin activation.
There was a problem hiding this comment.
What do you mean? Why should we randomize RPCs order?
There was a problem hiding this comment.
To not let all users use the first one and overload it, load should be distributed. At least it was done like that for EVMs. c.c. @cipig I would like his opinion on this.
But for GUI authenticated RPCs, we can have randomization as optional or we have a preferred primary RPC selected if needed.
There was a problem hiding this comment.
To not let all users use the first one and overload it, load should be distributed. At least it was done like that for EVMs.
This would kill the ability of controlling the prioritization of the nodes we add to the application (e.g., having the paid node as the last backup and the most stable one as the primary/main node).
There was a problem hiding this comment.
I understand this, we should also have a way to prioritize them into primary and secondary, there was an issue for this for other coins #1520
But all this is very low priority, so keep it as is for now.
mm2src/coins/solana/solana_token.rs
Outdated
| instructions.push(create_associated_token_account( | ||
| &coin.address, | ||
| &to, | ||
| &token.protocol_info.mint_address, | ||
| &spl_token_program::id(), | ||
| )); |
There was a problem hiding this comment.
I would've preferred it in this PR as it's related to withdraw, but it can be in a small PR next before transaction history.
mm2src/coins/solana/solana_token.rs
Outdated
| &coin.address, | ||
| &to, | ||
| &token.protocol_info.mint_address, | ||
| &spl_token_program::id(), |
There was a problem hiding this comment.
spl_token_program::id() shouldn't be used IMHO, there is Token-2022 standard with different program id. Can be fixed in the rent followup PR as well. Not only here but in other places e.g. use get_associated_token_address_with_program_id instead of get_associated_token_address etc..
There was a problem hiding this comment.
get_associated_token_address_with_program_id doesn't return program id, it takes it. I guess the best we can do is to put that value into the coins file in this case.
There was a problem hiding this comment.
get_associated_token_address_with_program_id doesn't return program id, it takes it
I am aware, I mean to pass the right program id by using get_associated_token_address_with_program_id instead of get_associated_token_address
There was a problem hiding this comment.
I guess the best we can do is to put that value into the coins file in this case.
There should be a token type / standard in coins file, as for imported tokens in the future, there are ways to detect which token standard it uses.
There was a problem hiding this comment.
I think we can safely use them statically in the coins file without needing a dynamic detection logic, what do you think? Adding an extra field to coins file for tokens shouldn't do any harm. I made it here.
There was a problem hiding this comment.
I think we can safely use them statically in the coins file without needing a dynamic detection logic, what do you think?
For Solana it's different and most wallets do dynamic detection if I am not mistaken, Phantom even detects any coin you have in your wallet that is not a scam / spam (their spam detection fails sometimes and have a way for users to mark tokens as spam). Please check industry standards for this and choose what is a right fit for Solana.
Signed-off-by: Onur Özkan <work@onurozkan.dev>
Signed-off-by: Onur Özkan <work@onurozkan.dev>
Signed-off-by: Onur Özkan <work@onurozkan.dev>
Signed-off-by: Onur Özkan <work@onurozkan.dev>
| } | ||
|
|
||
| rent_lamports = rpc | ||
| .get_minimum_balance_for_rent_exemption(spl_token::state::Account::LEN) |
There was a problem hiding this comment.
I believe the length may differ for Token-2022 as they can add optional extensions however they like, so the rent exemption calculation will be a bit more complicated by checking each token for which extensions enabled, etc..
Implements
withdrawandsend_raw_transactionRPCs (covered with an integration test) for Solana coin and tokens along with some other minor parts.Previous implementations: