-
Notifications
You must be signed in to change notification settings - Fork 8
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
fast-bridge: Add fast bridge contract #361
base: master
Are you sure you want to change the base?
Conversation
Co-authored-by: doradelta <[email protected] > "
Co-authored-by: doradelta <[email protected]>
Co-authored-by: dhruvja <[email protected]>
For cross domain transfers, an acknowledgement is sent from destination to source in form of a token transfer. The packet contains the memo that has the information about unlocking the funds. The source would then parse the memo and unlock the funds to the solver mentioned in the memo. Since we only have token transfers enabled and no cross chain messages, a token needs to be transferred. For this, we create a dummy token owned by the program which mints a token everytime and sends a transfer. The timeout of the transfer is set to infinite so that it always reaches the counterparty chain. Also the `on_receive_transfer` method accepts a memo which unlocks the funds to the solver. Right now it is being called by the auctioneer but once the hooks are enabled on `solana-ibc` program, this method would then be called by the `solana-ibc` program.
Emitting events for all instructions so that they can be parsed from the logs and be acted upon.
If the solver is not able to solve the intent, then the escrowed funds can be issued back to the user. In case of single domain intents, the funds just get transferred to the user from the escrow account. But for cross chain intents, a timeout message is sent to the other chain with a flag of `Timeout` and the user who should receive it. The intent should store the user on source chain so that during timeout, we know whom to refund the funds to. For the memo, it is the same format and only the receiver is changed to user address instead of solver. --------- Co-authored-by: doradelta <[email protected]>
pub fn escrow_and_store_intent( | ||
ctx: Context<EscrowAndStoreIntent>, | ||
amount: u64, | ||
new_intent: IntentPayload |
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.
Remove the winner_solver
and user_in
from payload so that u dont need the checks below. You can just assign these value below.
); | ||
|
||
intent.intent_id = new_intent.intent_id.clone(); | ||
intent.user_in = new_intent.user_in.clone(); |
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.
intent.user_in = new_intent.user_in.clone(); | |
intent.user_in = ctx.accounts.user.key(); |
intent.timeout_timestamp_in_sec = new_intent.timeout_timestamp_in_sec; | ||
intent.creation_timestamp_in_sec = current_timestamp; | ||
intent.amount_out = new_intent.amount_out.clone(); | ||
intent.winner_solver = new_intent.winner_solver; |
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.
intent.winner_solver = new_intent.winner_solver; | |
intent.winner_solver = String::default(); |
pub struct IntentPayload { | ||
pub intent_id: String, | ||
pub user_in: String, | ||
pub user_out: Pubkey, | ||
pub token_in: String, | ||
pub amount_in: u64, | ||
pub token_out: String, | ||
pub amount_out: String, | ||
pub winner_solver: Pubkey, | ||
pub timeout_timestamp_in_sec: u64, | ||
pub single_domain: bool, | ||
} |
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.
pub struct IntentPayload { | |
pub intent_id: String, | |
pub user_in: String, | |
pub user_out: Pubkey, | |
pub token_in: String, | |
pub amount_in: u64, | |
pub token_out: String, | |
pub amount_out: String, | |
pub winner_solver: Pubkey, | |
pub timeout_timestamp_in_sec: u64, | |
pub single_domain: bool, | |
} | |
pub struct IntentPayload { | |
pub intent_id: String, | |
pub user_out: Pubkey, | |
pub token_in: String, | |
pub amount_in: u64, | |
pub token_out: String, | |
pub amount_out: String, | |
pub timeout_timestamp_in_sec: u64, | |
pub single_domain: bool, | |
} |
require!( | ||
intent.intent_id == intent_id, | ||
ErrorCode::IntentDoesNotExist | ||
); |
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.
You are getting the intent PDA from intent_id
in the accounts below so this check might not be required.
let signer_seeds = core::slice::from_ref(&seeds); | ||
|
||
if withdraw_user_flag { | ||
// Case 1: User withdrawal |
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.
you should also check if the intent really timed out or not.
// bool withdraw_user, | ||
// string intentId, | ||
// string from, | ||
// string token, | ||
// string to, | ||
// string amount, | ||
// string solver_out |
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.
Should contain the timestamp at which the acknowledgement was sent so that if the bridge halts or smtg, it wont be considered as timeout even though the solver solved the intent.
// bool withdraw_user, | |
// string intentId, | |
// string from, | |
// string token, | |
// string to, | |
// string amount, | |
// string solver_out | |
// bool withdraw_user, | |
// string intentId, | |
// string from, | |
// string token, | |
// string to, | |
// string amount, | |
// string solver_out | |
// u64 current_timestamp |
})?; | ||
} else { | ||
// Send a cross domain message to the source chain to unlock the funds | ||
let my_custom_memo = format!( |
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 memo should contain the 7 parts as above ( 8 with timestamp ), since its the same method that receives the memo.
/// | ||
/// For the cross chain intents, a message is sent to the source chain to unlock | ||
/// the funds. | ||
pub fn user_cancel_intent( |
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 intent is stored on source chain, then the destination has no intent right? so how would this work?
#[instruction(intent_id: String)] | ||
pub struct SplTokenTransfer<'info> { | ||
// Intent reading | ||
#[account(mut, close = auctioneer, seeds = [INTENT_SEED, intent_id.as_bytes()], bump)] | ||
pub intent: Box<Account<'info, Intent>>, |
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 intent is not stored on destination chain, we cant get the intent account.
#[instruction(intent_id: String)] | |
pub struct SplTokenTransfer<'info> { | |
// Intent reading | |
#[account(mut, close = auctioneer, seeds = [INTENT_SEED, intent_id.as_bytes()], bump)] | |
pub intent: Box<Account<'info, Intent>>, | |
pub struct SplTokenTransfer<'info> { |
Has the escrow contract for fast bridge which would be used to escrow the funds of the solver and unescrow when it receives the acknowledgement through IBC.