-
Notifications
You must be signed in to change notification settings - Fork 4
Fast transfers from UTXO chains #417
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
base: main
Are you sure you want to change the base?
Conversation
81bffe2
to
a0e51cc
Compare
// Verify this is indeed a UTXO chain token | ||
let _ = self | ||
.get_utxo_chain_by_token(&token_id) | ||
.sdk_expect("ERR_TOKEN_NOT_FROM_UTXO_CHAIN"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The utxo_transfer_msg
contains the Omni token address:
- This address can be used to optimize the
get_utxo_chain_by_token
call. - We have to verify that the token address in the msg is correct to avoid vulnerabilities
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is actually a mistake, I believe we can remove the OmniAddress. Sender doesn't have to know what the address on Near is
near/omni-bridge/src/lib.rs
Outdated
fee: utxo_transfer_msg.fee, | ||
native_fee: U128(0), | ||
}, | ||
sender: OmniAddress::Near(env::predecessor_account_id()), // TODO who is the sender? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now, the UTXO connector address could be the sender.
Later we can consider to add the sender to the msg, this will be needed if external actions is needed to be done by the user (eg sign custom message using Zcash wallet like in near-intents)
near/omni-bridge/src/lib.rs
Outdated
if self.is_transfer_finalised(fast_transfer.transfer_id) { | ||
env::panic_str("ERR_TRANSFER_ALREADY_FINALISED"); | ||
} | ||
// if self.is_transfer_finalised(fast_transfer.transfer_id) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This check should be done for both "to near" and "to other chain". The transaction can be delayed due to networks or chains issues, so we have to protect the relayer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Brought it back 8449952. Two points:
- It's convenient to have it at this level but there is a small chance of race condition because fast transfer will be executed in the next block (due to storage check)
- We currently don't need to store UTXO transfer id because duplicates are checked on connector level. But we have to add it for this part of the code if we want extra protection
|
||
#[near(serializers=[borsh, json])] | ||
#[derive(Debug, Clone)] | ||
pub enum UnifiedTransferId { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@frolvanya please look into this new structure if it fits the indexer requirements
near/omni-bridge/src/lib.rs
Outdated
return self | ||
.send_tokens(token_id, status.relayer, amount, &String::new()) | ||
.into(); | ||
} | ||
|
||
if let OmniAddress::Near(recipient) = utxo_transfer_msg.recipient { | ||
// Fast transfer didn't happen so we send the user full amount including fee | ||
return self | ||
.send_tokens(token_id, recipient, amount, &utxo_transfer_msg.msg) | ||
.into(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The send_tokens
call isn't async, this mean that it's results affect the refund for the top ft_tranasfer_call
.
For example if the msg
is empty then the last promise will be ft_transfer
with empty results.
Also there are edge cases for ft_transfer_call
panics and returned values.
We have to cover all of that with tests.
Also it will be good to verify the storage deposit for the the recipient
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the call fails we are okay to refund the tokens.
Two questions to answer here are:
- What happens if empty result is returned
- Whether we can use
ft_transfer_call
return value. I believe here the answer isno
because it will returnused_amount
while we want to return 0 in case of success
Is my understanding correct? If so, I'll add a callback to handle it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added some changes here 2537719
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need to validate storage for the recipient? If the transfer fails we would handle the refund properly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need to validate storage for the recipient? If the transfer fails we would handle the refund properly
Not really, depends on how you are going to handle the refund.
For example for the ft_transfer it is ok to refund if the receipt failed, but it isn't safe to refund if the ft_transfer_call failed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And it isn't safe because of potential out of gas issue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, correct. We have 2 options here:
- verify the storage deposit before the ft_transfer_call.
- modify the token contract, so the ft_transfer_call will returns value instead of panic of the account isn't registered
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added ade99b2
pub fee: U128, | ||
pub native_token_fee: U128, | ||
pub msg: Option<String>, | ||
pub msg: String, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why msg not Option?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not option in InitTransferMessage
either. We use empty strings
near/omni-bridge/src/lib.rs
Outdated
BridgeOnTransferMsg::FastFinTransfer(fast_fin_transfer_msg) => { | ||
self.fast_fin_transfer(token_id, amount, signer_id, fast_fin_transfer_msg) | ||
} | ||
BridgeOnTransferMsg::UtxoTransfer(utxo_transfer_msg) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BridgeOnTransferMsg::UtxoTransfer(utxo_transfer_msg) => { | |
BridgeOnTransferMsg::TransferFromUtxo(utxo_transfer_msg) => { |
What about a name like this? Otherwise, it seems like these arguments need to be passed when transferring to a UTXO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed yours is better. Also thinking about UtxoFinTransfer
or FinTransferFromUtxo
No description provided.