-
Notifications
You must be signed in to change notification settings - Fork 56
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: add determinstic deposit hash & new exclusivity logic #759
Changes from 19 commits
fb9e9cf
934bc1e
6c36c37
5a0f1ef
464ea67
5c7d618
c1e509c
eff54eb
24e7d06
4578f2d
c00b4f2
ab9fe88
96038be
ab1e5c4
b549bdb
77761fa
631818d
12dc015
0bff963
3b66b7e
bef1c46
0c5ee38
12d8588
7c7ebf6
3301986
66df531
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,8 @@ | ||
use anchor_lang::prelude::*; | ||
use anchor_lang::{prelude::*, solana_program::keccak}; | ||
use anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface}; | ||
|
||
use crate::{ | ||
constants::{MAX_EXCLUSIVITY_PERIOD_SECONDS, ZERO_DEPOSIT_ID}, | ||
error::{CommonError, SvmError}, | ||
event::V3FundsDeposited, | ||
get_current_time, | ||
|
@@ -63,7 +64,7 @@ pub struct DepositV3<'info> { | |
pub token_program: Interface<'info, TokenInterface>, | ||
} | ||
|
||
pub fn deposit_v3( | ||
pub fn _deposit_v3( | ||
ctx: Context<DepositV3>, | ||
depositor: Pubkey, | ||
recipient: Pubkey, | ||
|
@@ -73,9 +74,10 @@ pub fn deposit_v3( | |
output_amount: u64, | ||
destination_chain_id: u64, | ||
exclusive_relayer: Pubkey, | ||
deposit_id: [u8; 32], | ||
quote_timestamp: u32, | ||
fill_deadline: u32, | ||
exclusivity_period: u32, | ||
exclusivity_parameter: u32, | ||
message: Vec<u8>, | ||
) -> Result<()> { | ||
let state = &mut ctx.accounts.state; | ||
|
@@ -90,6 +92,17 @@ pub fn deposit_v3( | |
return err!(CommonError::InvalidFillDeadline); | ||
} | ||
|
||
let mut exclusivity_deadline = exclusivity_parameter; | ||
if exclusivity_deadline > 0 { | ||
if exclusivity_deadline <= MAX_EXCLUSIVITY_PERIOD_SECONDS { | ||
exclusivity_deadline += current_time; | ||
} | ||
|
||
if exclusive_relayer == Pubkey::default() { | ||
return err!(CommonError::InvalidExclusiveRelayer); | ||
} | ||
} | ||
|
||
// Depositor must have delegated input_amount to the state PDA. | ||
transfer_from( | ||
&ctx.accounts.depositor_token_account, | ||
|
@@ -101,18 +114,23 @@ pub fn deposit_v3( | |
&ctx.accounts.token_program, | ||
)?; | ||
|
||
state.number_of_deposits += 1; // Increment number of deposits | ||
let mut applied_deposit_id = deposit_id; | ||
// If the passed in deposit_id is all zeros, then we use the state's number of deposits as deposit_id. | ||
if deposit_id == ZERO_DEPOSIT_ID { | ||
state.number_of_deposits += 1; | ||
applied_deposit_id[..4].copy_from_slice(&state.number_of_deposits.to_le_bytes()); | ||
} | ||
|
||
emit_cpi!(V3FundsDeposited { | ||
input_token, | ||
output_token, | ||
input_amount, | ||
output_amount, | ||
destination_chain_id, | ||
deposit_id: state.number_of_deposits, | ||
deposit_id: applied_deposit_id, | ||
quote_timestamp, | ||
fill_deadline, | ||
exclusivity_deadline: current_time + exclusivity_period, | ||
exclusivity_deadline, | ||
depositor, | ||
recipient, | ||
exclusive_relayer, | ||
|
@@ -122,6 +140,41 @@ pub fn deposit_v3( | |
Ok(()) | ||
} | ||
|
||
pub fn deposit_v3( | ||
ctx: Context<DepositV3>, | ||
depositor: Pubkey, | ||
recipient: Pubkey, | ||
input_token: Pubkey, | ||
output_token: Pubkey, | ||
input_amount: u64, | ||
output_amount: u64, | ||
destination_chain_id: u64, | ||
exclusive_relayer: Pubkey, | ||
quote_timestamp: u32, | ||
fill_deadline: u32, | ||
exclusivity_parameter: u32, | ||
message: Vec<u8>, | ||
) -> Result<()> { | ||
_deposit_v3( | ||
ctx, | ||
depositor, | ||
recipient, | ||
input_token, | ||
output_token, | ||
input_amount, | ||
output_amount, | ||
destination_chain_id, | ||
exclusive_relayer, | ||
ZERO_DEPOSIT_ID, // ZERO_DEPOSIT_ID informs internal function to use state.number_of_deposits as id. | ||
quote_timestamp, | ||
fill_deadline, | ||
exclusivity_parameter, | ||
message, | ||
)?; | ||
|
||
Ok(()) | ||
} | ||
|
||
pub fn deposit_v3_now( | ||
ctx: Context<DepositV3>, | ||
depositor: Pubkey, | ||
|
@@ -156,3 +209,52 @@ pub fn deposit_v3_now( | |
|
||
Ok(()) | ||
} | ||
|
||
pub fn unsafe_deposit_v3( | ||
ctx: Context<DepositV3>, | ||
depositor: Pubkey, | ||
recipient: Pubkey, | ||
input_token: Pubkey, | ||
output_token: Pubkey, | ||
input_amount: u64, | ||
output_amount: u64, | ||
destination_chain_id: u64, | ||
exclusive_relayer: Pubkey, | ||
deposit_nonce: u64, | ||
quote_timestamp: u32, | ||
fill_deadline: u32, | ||
exclusivity_parameter: u32, | ||
message: Vec<u8>, | ||
) -> Result<()> { | ||
// Calculate the unsafe deposit ID as a [u8; 32] | ||
let deposit_id = get_unsafe_deposit_id(ctx.accounts.signer.key(), depositor, deposit_nonce); | ||
_deposit_v3( | ||
ctx, | ||
depositor, | ||
recipient, | ||
input_token, | ||
output_token, | ||
input_amount, | ||
output_amount, | ||
destination_chain_id, | ||
exclusive_relayer, | ||
deposit_id, | ||
quote_timestamp, | ||
fill_deadline, | ||
exclusivity_parameter, | ||
message, | ||
)?; | ||
|
||
Ok(()) | ||
} | ||
|
||
// Define a dummy context struct so we can export this as a view function in lib. | ||
#[derive(Accounts)] | ||
pub struct Null {} | ||
pub fn get_unsafe_deposit_id(msg_sender: Pubkey, depositor: Pubkey, deposit_nonce: u64) -> [u8; 32] { | ||
let mut data = Vec::new(); | ||
// Use AnchorSerialize to serialize the tuple of values | ||
(msg_sender, depositor, deposit_nonce).serialize(&mut data).unwrap(); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. note that this is not AnchorSerialize wrapper (like mentioned in comment above), but using borch directly. Though, I guess functionally its the same in this case. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done. |
||
keccak::hash(&data).to_bytes() | ||
} |
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 you think it makes sense to expose this? Are we planning to use it off-chain, or should we implement a similar function in TS for efficiency?
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, I think having it exposed is useful. it's done in solidity and it's good to not force users to have to do this in js. for example say you wanted to do the deposit with etherscan for example. i don't think there is any downside in having it public. do you agree?