-
Notifications
You must be signed in to change notification settings - Fork 52
/
Copy pathinitialize.rs
169 lines (148 loc) · 5.29 KB
/
initialize.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
use anchor_lang::prelude::*;
use anchor_spl::{associated_token::AssociatedToken, token_interface};
use ntt_messages::{chain_id::ChainId, mode::Mode};
use wormhole_solana_utils::cpi::bpf_loader_upgradeable::BpfLoaderUpgradeable;
#[cfg(feature = "idl-build")]
use crate::messages::Hack;
use crate::{
bitmap::Bitmap,
error::NTTError,
queue::{outbox::OutboxRateLimit, rate_limit::RateLimitState},
spl_multisig::SplMultisig,
};
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(mut)]
pub payer: Signer<'info>,
#[account(address = program_data.upgrade_authority_address.unwrap_or_default())]
pub deployer: Signer<'info>,
#[account(
seeds = [crate::ID.as_ref()],
bump,
seeds::program = bpf_loader_upgradeable_program,
)]
program_data: Account<'info, ProgramData>,
#[account(
init,
space = 8 + crate::config::Config::INIT_SPACE,
payer = payer,
seeds = [crate::config::Config::SEED_PREFIX],
bump
)]
pub config: Box<Account<'info, crate::config::Config>>,
// NOTE: this account is unconstrained and is the responsibility of the
// handler to constrain it
pub mint: Box<InterfaceAccount<'info, token_interface::Mint>>,
#[account(
init,
payer = payer,
space = 8 + OutboxRateLimit::INIT_SPACE,
seeds = [OutboxRateLimit::SEED_PREFIX],
bump,
)]
pub rate_limit: Account<'info, OutboxRateLimit>,
#[account(
seeds = [crate::TOKEN_AUTHORITY_SEED],
bump,
)]
/// CHECK: [`token_authority`] is checked against the custody account and the [`mint`]'s mint_authority
/// In any case, this function is used to set the Config and initialize the program so we
/// assume the caller of this function will have total control over the program.
///
/// TODO: Using `UncheckedAccount` here leads to "Access violation in stack frame ...".
/// Could refactor code to use `Box<_>` to reduce stack size.
pub token_authority: AccountInfo<'info>,
#[account(
init_if_needed,
payer = payer,
associated_token::mint = mint,
associated_token::authority = token_authority,
associated_token::token_program = token_program,
)]
/// The custody account that holds tokens in locking mode and temporarily
/// holds tokens in burning mode.
/// CHECK: Use init_if_needed here to prevent a denial-of-service of the [`initialize`]
/// function if the token account has already been created.
pub custody: InterfaceAccount<'info, token_interface::TokenAccount>,
/// CHECK: checked to be the appropriate token program when initialising the
/// associated token account for the given mint.
pub token_program: Interface<'info, token_interface::TokenInterface>,
pub associated_token_program: Program<'info, AssociatedToken>,
bpf_loader_upgradeable_program: Program<'info, BpfLoaderUpgradeable>,
system_program: Program<'info, System>,
}
#[derive(AnchorSerialize, AnchorDeserialize)]
pub struct InitializeArgs {
pub chain_id: u16,
pub limit: u64,
pub mode: ntt_messages::mode::Mode,
}
pub fn initialize(ctx: Context<Initialize>, args: InitializeArgs) -> Result<()> {
// NOTE: this check was moved into the function body to reuse the `Initialize` struct
// in the multisig variant while preserving ABI
if args.mode == Mode::Burning
&& ctx.accounts.mint.mint_authority.unwrap() != ctx.accounts.token_authority.key()
{
return Err(NTTError::InvalidMintAuthority.into());
}
initialize_config_and_rate_limit(
ctx.accounts,
ctx.bumps.config,
args.chain_id,
args.limit,
args.mode,
)
}
#[derive(Accounts)]
#[instruction(args: InitializeArgs)]
pub struct InitializeMultisig<'info> {
#[account(
constraint =
args.mode == Mode::Locking
|| common.mint.mint_authority.unwrap() == multisig.key()
@ NTTError::InvalidMintAuthority,
)]
pub common: Initialize<'info>,
#[account(
constraint =
multisig.m == 1 && multisig.signers.contains(&common.token_authority.key())
@ NTTError::InvalidMultisig,
)]
pub multisig: InterfaceAccount<'info, SplMultisig>,
}
pub fn initialize_multisig(ctx: Context<InitializeMultisig>, args: InitializeArgs) -> Result<()> {
initialize_config_and_rate_limit(
&mut ctx.accounts.common,
ctx.bumps.common.config,
args.chain_id,
args.limit,
args.mode,
)
}
fn initialize_config_and_rate_limit(
common: &mut Initialize<'_>,
config_bump: u8,
chain_id: u16,
limit: u64,
mode: ntt_messages::mode::Mode,
) -> Result<()> {
common.config.set_inner(crate::config::Config {
bump: config_bump,
mint: common.mint.key(),
token_program: common.token_program.key(),
mode,
chain_id: ChainId { id: chain_id },
owner: common.deployer.key(),
pending_owner: None,
paused: false,
next_transceiver_id: 0,
// NOTE: can be changed via `set_threshold` ix
threshold: 1,
enabled_transceivers: Bitmap::new(),
custody: common.custody.key(),
});
common.rate_limit.set_inner(OutboxRateLimit {
rate_limit: RateLimitState::new(limit),
});
Ok(())
}