-
Notifications
You must be signed in to change notification settings - Fork 52
/
Copy pathrelease_inbound.rs
171 lines (149 loc) · 5.93 KB
/
release_inbound.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
170
171
use anchor_lang::prelude::*;
use anchor_spl::token_interface;
use ntt_messages::mode::Mode;
use crate::{
config::*,
error::NTTError,
queue::inbox::{InboxItem, ReleaseStatus},
};
#[derive(Accounts)]
pub struct ReleaseInbound<'info> {
#[account(mut)]
pub payer: Signer<'info>,
pub config: NotPausedConfig<'info>,
#[account(mut)]
pub inbox_item: Account<'info, InboxItem>,
#[account(
mut,
associated_token::authority = inbox_item.recipient_address,
associated_token::mint = mint,
associated_token::token_program = token_program,
)]
pub recipient: InterfaceAccount<'info, token_interface::TokenAccount>,
#[account(
seeds = [crate::TOKEN_AUTHORITY_SEED],
bump,
)]
pub token_authority: AccountInfo<'info>,
#[account(
mut,
address = config.mint,
)]
/// CHECK: the mint address matches the config
pub mint: InterfaceAccount<'info, token_interface::Mint>,
pub token_program: Interface<'info, token_interface::TokenInterface>,
}
#[derive(AnchorDeserialize, AnchorSerialize)]
pub struct ReleaseInboundArgs {
pub revert_when_not_ready: bool,
}
// Burn/mint
#[derive(Accounts)]
pub struct ReleaseInboundMint<'info> {
common: ReleaseInbound<'info>,
}
/// Release an inbound transfer and mint the tokens to the recipient.
/// When `revert_when_not_ready` is true, the transaction will revert if the
/// release timestamp has not been reached. When `revert_when_not_ready` is false, the
/// transaction succeeds, but the minting is not performed.
/// Setting this flag to `false` is useful when bundling this instruction
/// together with [`crate::instructions::redeem`] in a transaction, so that the minting
/// is attempted optimistically.
pub fn release_inbound_mint(
ctx: Context<ReleaseInboundMint>,
args: ReleaseInboundArgs,
) -> Result<()> {
let inbox_item = &mut ctx.accounts.common.inbox_item;
let released = inbox_item.try_release()?;
if !released {
if args.revert_when_not_ready {
match inbox_item.release_status {
ReleaseStatus::NotApproved => return Err(NTTError::TransferNotApproved.into()),
ReleaseStatus::ReleaseAfter(_) => return Err(NTTError::CantReleaseYet.into()),
// Unreachable: if released, [`InboxItem::try_release`] will return an Error immediately
// rather than Ok(bool).
ReleaseStatus::Released => return Err(NTTError::TransferAlreadyRedeemed.into()),
}
} else {
return Ok(());
}
}
assert!(inbox_item.release_status == ReleaseStatus::Released);
match ctx.accounts.common.config.mode {
Mode::Burning => token_interface::mint_to(
CpiContext::new_with_signer(
ctx.accounts.common.token_program.to_account_info(),
token_interface::MintTo {
mint: ctx.accounts.common.mint.to_account_info(),
to: ctx.accounts.common.recipient.to_account_info(),
authority: ctx.accounts.common.token_authority.clone(),
},
&[&[
crate::TOKEN_AUTHORITY_SEED,
&[ctx.bumps.common.token_authority],
]],
),
inbox_item.amount,
),
Mode::Locking => Err(NTTError::InvalidMode.into()),
}
}
// Lock/unlock
#[derive(Accounts)]
pub struct ReleaseInboundUnlock<'info> {
common: ReleaseInbound<'info>,
/// CHECK: the token program checks if this indeed the right authority for the mint
#[account(
mut,
address = common.config.custody
)]
pub custody: InterfaceAccount<'info, token_interface::TokenAccount>,
}
/// Release an inbound transfer and unlock the tokens to the recipient.
/// When `revert_when_not_ready` is true, the transaction will revert if the
/// release timestamp has not been reached. When `revert_when_not_ready` is false, the
/// transaction succeeds, but the unlocking is not performed.
/// Setting this flag to `false` is useful when bundling this instruction
/// together with [`crate::instructions::redeem`], so that the unlocking
/// is attempted optimistically.
pub fn release_inbound_unlock(
ctx: Context<ReleaseInboundUnlock>,
args: ReleaseInboundArgs,
) -> Result<()> {
let inbox_item = &mut ctx.accounts.common.inbox_item;
let released = inbox_item.try_release()?;
if !released {
if args.revert_when_not_ready {
match inbox_item.release_status {
ReleaseStatus::NotApproved => return Err(NTTError::TransferNotApproved.into()),
ReleaseStatus::ReleaseAfter(_) => return Err(NTTError::CantReleaseYet.into()),
// Unreachable: if released, [`InboxItem::try_release`] will return an Error immediately
// rather than Ok(bool).
ReleaseStatus::Released => return Err(NTTError::TransferAlreadyRedeemed.into()),
}
} else {
return Ok(());
}
}
assert!(inbox_item.release_status == ReleaseStatus::Released);
match ctx.accounts.common.config.mode {
Mode::Burning => Err(NTTError::InvalidMode.into()),
Mode::Locking => token_interface::transfer_checked(
CpiContext::new_with_signer(
ctx.accounts.common.token_program.to_account_info(),
token_interface::TransferChecked {
from: ctx.accounts.custody.to_account_info(),
to: ctx.accounts.common.recipient.to_account_info(),
authority: ctx.accounts.common.token_authority.clone(),
mint: ctx.accounts.common.mint.to_account_info(),
},
&[&[
crate::TOKEN_AUTHORITY_SEED,
&[ctx.bumps.common.token_authority],
]],
),
inbox_item.amount,
ctx.accounts.common.mint.decimals,
),
}
}