Skip to content

Commit e582cb7

Browse files
authored
Merge branch 'master' into svm-dev
2 parents aa48a3d + ca8e78b commit e582cb7

23 files changed

+637
-178
lines changed

programs/svm-spoke/src/instructions/admin.rs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ use crate::{
1111
event::{
1212
EmergencyDeleteRootBundle, EnabledDepositRoute, PausedDeposits, PausedFills, RelayedRootBundle, SetXDomainAdmin,
1313
},
14-
initialize_current_time, set_seed,
1514
state::{RootBundle, Route, State},
15+
utils::{initialize_current_time, set_seed},
1616
};
1717

1818
#[derive(Accounts)]
@@ -35,13 +35,13 @@ pub struct Initialize<'info> {
3535

3636
pub fn initialize(
3737
ctx: Context<Initialize>,
38-
seed: u64,
39-
initial_number_of_deposits: u32,
40-
chain_id: u64, // Across definition of chainId for Solana.
41-
remote_domain: u32, // CCTP domain for Mainnet Ethereum.
42-
cross_domain_admin: Pubkey, // HubPool on Mainnet Ethereum.
43-
deposit_quote_time_buffer: u32, // Deposit quote times can't be set more than this amount into the past/future.
44-
fill_deadline_buffer: u32, // Fill deadlines can't be set more than this amount into the future.
38+
seed: u64, // Seed used to derive a new state to enable testing to reset between runs.
39+
initial_number_of_deposits: u32, // Starting number of deposits to offset deposit_id.
40+
chain_id: u64, // Across definition of chainId for Solana.
41+
remote_domain: u32, // CCTP domain for Mainnet Ethereum.
42+
cross_domain_admin: Pubkey, // HubPool on Mainnet Ethereum.
43+
deposit_quote_time_buffer: u32, // Deposit quote times can't be set more than this amount into the past/future.
44+
fill_deadline_buffer: u32, // Fill deadlines can't be set more than this amount into the future.
4545
) -> Result<()> {
4646
let state = &mut ctx.accounts.state;
4747
state.owner = *ctx.accounts.signer.key;
@@ -99,11 +99,11 @@ pub fn pause_fills(ctx: Context<PauseFills>, pause: bool) -> Result<()> {
9999

100100
#[derive(Accounts)]
101101
pub struct TransferOwnership<'info> {
102-
#[account(mut, seeds = [b"state", state.seed.to_le_bytes().as_ref()], bump)]
103-
pub state: Account<'info, State>,
104-
105102
#[account(address = state.owner @ SvmError::NotOwner)]
106103
pub signer: Signer<'info>,
104+
105+
#[account(mut, seeds = [b"state", state.seed.to_le_bytes().as_ref()], bump)]
106+
pub state: Account<'info, State>,
107107
}
108108

109109
pub fn transfer_ownership(ctx: Context<TransferOwnership>, new_owner: Pubkey) -> Result<()> {
@@ -158,7 +158,7 @@ pub struct SetEnableRoute<'info> {
158158
],
159159
bump
160160
)]
161-
pub route: Account<'info, Route>,
161+
pub route: Account<'info, Route>, // PDA to store route information for this particular token & chainId pair.
162162

163163
#[account(
164164
init_if_needed,
@@ -167,11 +167,11 @@ pub struct SetEnableRoute<'info> {
167167
associated_token::authority = state,
168168
associated_token::token_program = token_program
169169
)]
170-
pub vault: InterfaceAccount<'info, TokenAccount>,
170+
pub vault: InterfaceAccount<'info, TokenAccount>, // ATA, owned by the state, to store the origin token for spoke.
171171

172172
#[account(
173173
mint::token_program = token_program,
174-
// IDL build fails when requiring `address = origin_token` for mint, thus using a custom constraint.
174+
// IDL build fails when requiring address = origin_token for mint, thus using a custom constraint.
175175
constraint = origin_token_mint.key() == origin_token @ SvmError::InvalidMint
176176
)]
177177
pub origin_token_mint: InterfaceAccount<'info, Mint>,
@@ -211,7 +211,7 @@ pub struct RelayRootBundle<'info> {
211211
pub state: Account<'info, State>,
212212

213213
#[account(
214-
init, // Init to create root bundle account. Prevents re-initialization.
214+
init, // Init to create root bundle account. Prevents re-initialization for a given root..
215215
payer = payer,
216216
space = DISCRIMINATOR_SIZE + RootBundle::INIT_SPACE,
217217
seeds = [b"root_bundle", state.seed.to_le_bytes().as_ref(), state.root_bundle_id.to_le_bytes().as_ref()],

programs/svm-spoke/src/instructions/bundle.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,15 @@ pub struct ExecuteRelayerRefundLeaf<'info> {
1919
pub signer: Signer<'info>,
2020

2121
#[account(seeds = [b"instruction_params", signer.key().as_ref()], bump)]
22-
pub instruction_params: Account<'info, ExecuteRelayerRefundLeafParams>,
22+
pub instruction_params: Account<'info, ExecuteRelayerRefundLeafParams>, // Contains all leaf & proof information.
2323

2424
#[account(seeds = [b"state", state.seed.to_le_bytes().as_ref()], bump)]
2525
pub state: Account<'info, State>,
2626

2727
#[account(
2828
mut,
2929
seeds = [b"root_bundle", state.seed.to_le_bytes().as_ref(), instruction_params.root_bundle_id.to_le_bytes().as_ref()], bump,
30+
// Realloc to let the size of the dynamic array within root_bundle to grow as leafs are executed.
3031
realloc = std::cmp::max(
3132
DISCRIMINATOR_SIZE + RootBundle::INIT_SPACE + instruction_params.relayer_refund_leaf.leaf_id as usize / 8,
3233
root_bundle.to_account_info().data_len()
@@ -39,7 +40,7 @@ pub struct ExecuteRelayerRefundLeaf<'info> {
3940
#[account(
4041
mut,
4142
associated_token::mint = mint,
42-
associated_token::authority = state,
43+
associated_token::authority = state, // Ensure owner is the state.
4344
associated_token::token_program = token_program
4445
)]
4546
pub vault: InterfaceAccount<'info, TokenAccount>,
@@ -51,7 +52,7 @@ pub struct ExecuteRelayerRefundLeaf<'info> {
5152
pub mint: InterfaceAccount<'info, Mint>,
5253

5354
#[account(
54-
init_if_needed,
55+
init_if_needed, // If first time creating, initialize the liability tracker, else re-use.
5556
payer = signer,
5657
space = DISCRIMINATOR_SIZE + TransferLiability::INIT_SPACE,
5758
seeds = [b"transfer_liability", mint.key().as_ref()],
@@ -64,7 +65,6 @@ pub struct ExecuteRelayerRefundLeaf<'info> {
6465
pub system_program: Program<'info, System>,
6566
}
6667

67-
// TODO: update UMIP to consider different encoding for different chains (evm and svm).
6868
#[derive(AnchorSerialize, AnchorDeserialize, Clone, InitSpace)]
6969
pub struct RelayerRefundLeaf {
7070
pub amount_to_return: u64,
@@ -104,7 +104,7 @@ pub fn execute_relayer_refund_leaf<'c, 'info>(
104104
deferred_refunds: bool,
105105
) -> Result<()>
106106
where
107-
'c: 'info, // The lifetime constraint `'c: 'info` ensures that the lifetime `'c` is at least as long as `'info`.
107+
'c: 'info, // The lifetime constraint 'c: 'info ensures that the lifetime 'c is at least as long as 'info.
108108
{
109109
// Get pre-loaded instruction parameters.
110110
let instruction_params = &ctx.accounts.instruction_params;
@@ -155,7 +155,6 @@ where
155155
ctx.accounts.transfer_liability.pending_to_hub_pool += relayer_refund_leaf.amount_to_return;
156156
}
157157

158-
// Emit the ExecutedRelayerRefundRoot event
159158
emit_cpi!(ExecutedRelayerRefundRoot {
160159
amount_to_return: relayer_refund_leaf.amount_to_return,
161160
chain_id: relayer_refund_leaf.chain_id,

programs/svm-spoke/src/instructions/deposit.rs

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
use anchor_lang::{prelude::*, solana_program::keccak};
1+
use anchor_lang::prelude::*;
22
use anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface};
33

44
use crate::{
55
constants::{MAX_EXCLUSIVITY_PERIOD_SECONDS, ZERO_DEPOSIT_ID},
66
error::{CommonError, SvmError},
77
event::V3FundsDeposited,
8-
get_current_time,
98
state::{Route, State},
10-
utils::transfer_from,
9+
utils::{get_current_time, get_unsafe_deposit_id, transfer_from},
1110
};
1211

1312
#[event_cpi]
@@ -50,7 +49,7 @@ pub struct DepositV3<'info> {
5049
#[account(
5150
mut,
5251
associated_token::mint = mint,
53-
associated_token::authority = state,
52+
associated_token::authority = state, // Ensure owner is the state as tokens are sent here on deposit.
5453
associated_token::token_program = token_program
5554
)]
5655
pub vault: InterfaceAccount<'info, TokenAccount>,
@@ -247,14 +246,3 @@ pub fn unsafe_deposit_v3(
247246

248247
Ok(())
249248
}
250-
251-
// Define a dummy context struct so we can export this as a view function in lib.
252-
#[derive(Accounts)]
253-
pub struct Null {}
254-
pub fn get_unsafe_deposit_id(msg_sender: Pubkey, depositor: Pubkey, deposit_nonce: u64) -> [u8; 32] {
255-
let mut data = Vec::new();
256-
257-
AnchorSerialize::serialize(&(msg_sender, depositor, deposit_nonce), &mut data).unwrap();
258-
259-
keccak::hash(&data).to_bytes()
260-
}

programs/svm-spoke/src/instructions/fill.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,8 @@ use crate::{
1010
constraints::is_relay_hash_valid,
1111
error::{CommonError, SvmError},
1212
event::{FillType, FilledV3Relay, V3RelayExecutionEventInfo},
13-
get_current_time,
1413
state::{FillStatus, FillStatusAccount, State},
15-
utils::{hash_non_empty_message, invoke_handler, transfer_from},
14+
utils::{get_current_time, hash_non_empty_message, invoke_handler, transfer_from},
1615
};
1716

1817
#[event_cpi]
@@ -33,20 +32,20 @@ pub struct FillV3Relay<'info> {
3332
mint::token_program = token_program,
3433
address = relay_data.output_token @ SvmError::InvalidMint
3534
)]
36-
pub mint_account: InterfaceAccount<'info, Mint>,
35+
pub mint: InterfaceAccount<'info, Mint>,
3736

3837
#[account(
3938
mut,
40-
token::mint = mint_account,
39+
token::mint = mint,
4140
token::authority = signer,
4241
token::token_program = token_program
4342
)]
4443
pub relayer_token_account: InterfaceAccount<'info, TokenAccount>,
4544

4645
#[account(
4746
mut,
48-
associated_token::mint = mint_account,
49-
associated_token::authority = relay_data.recipient,
47+
associated_token::mint = mint,
48+
associated_token::authority = relay_data.recipient, // Ensures tokens go to ATA owned by the recipient.
5049
associated_token::token_program = token_program
5150
)]
5251
pub recipient_token_account: InterfaceAccount<'info, TokenAccount>,
@@ -108,7 +107,7 @@ pub fn fill_v3_relay<'info>(
108107
relay_data.output_amount,
109108
state,
110109
ctx.bumps.state,
111-
&ctx.accounts.mint_account,
110+
&ctx.accounts.mint,
112111
&ctx.accounts.token_program,
113112
)?;
114113
}
@@ -125,7 +124,6 @@ pub fn fill_v3_relay<'info>(
125124
)?;
126125
}
127126

128-
// Emit the FilledV3Relay event
129127
// Empty message is not hashed and emits zeroed bytes32 for easier human observability.
130128
let message_hash = hash_non_empty_message(&relay_data.message);
131129

@@ -169,7 +167,6 @@ pub struct CloseFillPda<'info> {
169167
seeds = [b"fills", relay_hash.as_ref()],
170168
bump,
171169
close = signer,
172-
// Make sure caller provided relay_hash used in PDA seeds is valid.
173170
constraint = is_relay_hash_valid(&relay_hash, &relay_data, &state) @ SvmError::InvalidRelayHash
174171
)]
175172
pub fill_status: Account<'info, FillStatusAccount>,

programs/svm-spoke/src/instructions/handle_receive_message.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,14 @@ use crate::{
77
constants::MESSAGE_TRANSMITTER_PROGRAM_ID,
88
error::{CallDataError, SvmError},
99
program::SvmSpoke,
10+
state::State,
1011
utils::{self, EncodeInstructionData},
11-
State,
1212
};
1313

1414
#[derive(Accounts)]
1515
#[instruction(params: HandleReceiveMessageParams)]
1616
pub struct HandleReceiveMessage<'info> {
17-
// authority_pda is a Signer to ensure that this instruction
18-
// can only be called by Message Transmitter
17+
// authority_pda is a Signer to ensure that this instruction can only be called by the Message Transmitter.
1918
#[account(
2019
seeds = [b"message_transmitter_authority", SvmSpoke::id().as_ref()],
2120
bump = params.authority_bump,

programs/svm-spoke/src/instructions/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ mod handle_receive_message;
77
mod instruction_params;
88
mod refund_claims;
99
mod slow_fill;
10-
mod testable;
1110
mod token_bridge;
1211

1312
pub use admin::*;
@@ -19,5 +18,4 @@ pub use handle_receive_message::*;
1918
pub use instruction_params::*;
2019
pub use refund_claims::*;
2120
pub use slow_fill::*;
22-
pub use testable::*;
2321
pub use token_bridge::*;

programs/svm-spoke/src/instructions/refund_claims.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,6 @@ pub fn claim_relayer_refund(ctx: Context<ClaimRelayerRefund>) -> Result<()> {
9999
);
100100
transfer_checked(cpi_context, claim_amount, ctx.accounts.mint.decimals)?;
101101

102-
// Emit the ClaimedRelayerRefund event.
103102
emit_cpi!(ClaimedRelayerRefund {
104103
l2_token_address: ctx.accounts.mint.key(),
105104
claim_amount,
@@ -181,15 +180,13 @@ pub fn claim_relayer_refund_for(ctx: Context<ClaimRelayerRefundFor>, refund_addr
181180
);
182181
transfer_checked(cpi_context, claim_amount, ctx.accounts.mint.decimals)?;
183182

184-
// Emit the ClaimedRelayerRefund event.
185183
emit_cpi!(ClaimedRelayerRefund {
186184
l2_token_address: ctx.accounts.mint.key(),
187185
claim_amount,
188186
refund_address,
189187
});
190188

191189
// There is no need to reset the claim amount as the account will be closed at the end of instruction.
192-
193190
Ok(())
194191
}
195192

programs/svm-spoke/src/instructions/slow_fill.rs

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,20 @@
11
use anchor_lang::{prelude::*, solana_program::keccak};
22
use anchor_spl::token_interface::{transfer_checked, Mint, TokenAccount, TokenInterface, TransferChecked};
33

4+
use crate::event::{FillType, FilledV3Relay, RequestedV3SlowFill, V3RelayExecutionEventInfo};
45
use crate::{
56
common::V3RelayData,
67
constants::DISCRIMINATOR_SIZE,
78
constraints::is_relay_hash_valid,
89
error::{CommonError, SvmError},
9-
get_current_time,
1010
state::{FillStatus, FillStatusAccount, RootBundle, State},
11-
utils::{hash_non_empty_message, invoke_handler, verify_merkle_proof},
11+
utils::{get_current_time, hash_non_empty_message, invoke_handler, verify_merkle_proof},
1212
};
1313

14-
use crate::event::{FillType, FilledV3Relay, RequestedV3SlowFill, V3RelayExecutionEventInfo};
15-
1614
#[event_cpi]
1715
#[derive(Accounts)]
1816
#[instruction(relay_hash: [u8; 32], relay_data: V3RelayData)]
19-
pub struct SlowFillV3Relay<'info> {
17+
pub struct RequestV3SlowFill<'info> {
2018
#[account(mut)]
2119
pub signer: Signer<'info>,
2220

@@ -33,14 +31,13 @@ pub struct SlowFillV3Relay<'info> {
3331
space = DISCRIMINATOR_SIZE + FillStatusAccount::INIT_SPACE,
3432
seeds = [b"fills", relay_hash.as_ref()],
3533
bump,
36-
// Make sure caller provided relay_hash used in PDA seeds is valid.
3734
constraint = is_relay_hash_valid(&relay_hash, &relay_data, &state) @ SvmError::InvalidRelayHash
3835
)]
3936
pub fill_status: Account<'info, FillStatusAccount>,
4037
pub system_program: Program<'info, System>,
4138
}
4239

43-
pub fn request_v3_slow_fill(ctx: Context<SlowFillV3Relay>, relay_data: V3RelayData) -> Result<()> {
40+
pub fn request_v3_slow_fill(ctx: Context<RequestV3SlowFill>, relay_data: V3RelayData) -> Result<()> {
4441
let state = &ctx.accounts.state;
4542

4643
let current_time = get_current_time(state)?;
@@ -53,18 +50,16 @@ pub fn request_v3_slow_fill(ctx: Context<SlowFillV3Relay>, relay_data: V3RelayDa
5350
return err!(CommonError::ExpiredFillDeadline);
5451
}
5552

56-
// Check the fill status
53+
// Check the fill status is unfilled.
5754
let fill_status_account = &mut ctx.accounts.fill_status;
5855
if fill_status_account.status != FillStatus::Unfilled {
5956
return err!(CommonError::InvalidSlowFillRequest);
6057
}
6158

62-
// Update the fill status to RequestedSlowFill
63-
fill_status_account.status = FillStatus::RequestedSlowFill;
59+
fill_status_account.status = FillStatus::RequestedSlowFill; // Update the fill status to RequestedSlowFill
6460
fill_status_account.relayer = ctx.accounts.signer.key();
6561

66-
// Emit the RequestedV3SlowFill event
67-
// Empty message is not hashed and emits zeroed bytes32 for easier human observability.
62+
// Emit the RequestedV3SlowFill event. Empty message is not hashed and emits zeroed bytes32 for easier observability
6863
let message_hash = hash_non_empty_message(&relay_data.message);
6964

7065
emit_cpi!(RequestedV3SlowFill {
@@ -85,7 +80,6 @@ pub fn request_v3_slow_fill(ctx: Context<SlowFillV3Relay>, relay_data: V3RelayDa
8580
Ok(())
8681
}
8782

88-
// Define the V3SlowFill struct
8983
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
9084
pub struct V3SlowFill {
9185
pub relay_data: V3RelayData,
@@ -112,7 +106,6 @@ impl V3SlowFill {
112106
}
113107
}
114108

115-
// Define the V3SlowFill struct
116109
#[event_cpi]
117110
#[derive(Accounts)]
118111
#[instruction(relay_hash: [u8; 32], slow_fill_leaf: V3SlowFill, root_bundle_id: u32)]
@@ -223,7 +216,6 @@ pub fn execute_v3_slow_relay_leaf<'info>(
223216
)?;
224217
}
225218

226-
// Emit the FilledV3Relay event
227219
// Empty message is not hashed and emits zeroed bytes32 for easier human observability.
228220
let message_hash = hash_non_empty_message(&relay_data.message);
229221

0 commit comments

Comments
 (0)