Skip to main content

hopper_native/
token.rs

1//! SPL Token program CPI instructions.
2//!
3//! Provides Transfer, MintTo, Burn, CloseAccount, Approve, and Revoke
4//! builders that invoke the SPL Token program via `sol_invoke_signed_c`.
5
6use crate::account_view::AccountView;
7use crate::address::Address;
8use crate::instruction::{CpiAccount, Signer};
9use crate::ProgramResult;
10
11/// SPL Token program address.
12pub const TOKEN_PROGRAM_ID: Address =
13    crate::address!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
14
15// ---------------------------------------------------------------------
16
17/// Builder for SPL Token Transfer (instruction index 3).
18pub struct Transfer<'a> {
19    pub from: &'a AccountView<'a>,
20    pub to: &'a AccountView<'a>,
21    pub authority: &'a AccountView<'a>,
22    pub amount: u64,
23}
24
25impl Transfer<'_> {
26    #[inline]
27    pub fn invoke(&self) -> ProgramResult {
28        self.invoke_signed(&[])
29    }
30
31    #[inline]
32    pub fn invoke_signed(&self, signers: &[Signer<'_, '_>]) -> ProgramResult {
33        let mut data = [0u8; 9];
34        data[0] = 3;
35        data[1..9].copy_from_slice(&self.amount.to_le_bytes());
36
37        let accounts = [
38            CpiAccount::from(self.from),
39            CpiAccount::from(self.to),
40            CpiAccount::from(self.authority),
41        ];
42
43        invoke_token(&data, &accounts, 0b011, 0b100, signers)
44    }
45}
46
47// ---------------------------------------------------------------------
48
49/// Builder for SPL Token MintTo (instruction index 7).
50pub struct MintTo<'a> {
51    pub mint: &'a AccountView<'a>,
52    pub account: &'a AccountView<'a>,
53    pub mint_authority: &'a AccountView<'a>,
54    pub amount: u64,
55}
56
57impl MintTo<'_> {
58    #[inline]
59    pub fn invoke(&self) -> ProgramResult {
60        self.invoke_signed(&[])
61    }
62
63    #[inline]
64    pub fn invoke_signed(&self, signers: &[Signer<'_, '_>]) -> ProgramResult {
65        let mut data = [0u8; 9];
66        data[0] = 7;
67        data[1..9].copy_from_slice(&self.amount.to_le_bytes());
68
69        let accounts = [
70            CpiAccount::from(self.mint),
71            CpiAccount::from(self.account),
72            CpiAccount::from(self.mint_authority),
73        ];
74
75        invoke_token(&data, &accounts, 0b011, 0b100, signers)
76    }
77}
78
79// ---------------------------------------------------------------------
80
81/// Builder for SPL Token Burn (instruction index 8).
82pub struct Burn<'a> {
83    pub account: &'a AccountView<'a>,
84    pub mint: &'a AccountView<'a>,
85    pub authority: &'a AccountView<'a>,
86    pub amount: u64,
87}
88
89impl Burn<'_> {
90    #[inline]
91    pub fn invoke(&self) -> ProgramResult {
92        self.invoke_signed(&[])
93    }
94
95    #[inline]
96    pub fn invoke_signed(&self, signers: &[Signer<'_, '_>]) -> ProgramResult {
97        let mut data = [0u8; 9];
98        data[0] = 8;
99        data[1..9].copy_from_slice(&self.amount.to_le_bytes());
100
101        let accounts = [
102            CpiAccount::from(self.account),
103            CpiAccount::from(self.mint),
104            CpiAccount::from(self.authority),
105        ];
106
107        invoke_token(&data, &accounts, 0b011, 0b100, signers)
108    }
109}
110
111// ---------------------------------------------------------------------
112
113/// Builder for SPL Token CloseAccount (instruction index 9).
114pub struct CloseAccount<'a> {
115    pub account: &'a AccountView<'a>,
116    pub destination: &'a AccountView<'a>,
117    pub authority: &'a AccountView<'a>,
118}
119
120impl CloseAccount<'_> {
121    #[inline]
122    pub fn invoke(&self) -> ProgramResult {
123        self.invoke_signed(&[])
124    }
125
126    #[inline]
127    pub fn invoke_signed(&self, signers: &[Signer<'_, '_>]) -> ProgramResult {
128        let data = [9u8];
129
130        let accounts = [
131            CpiAccount::from(self.account),
132            CpiAccount::from(self.destination),
133            CpiAccount::from(self.authority),
134        ];
135
136        invoke_token(&data, &accounts, 0b011, 0b100, signers)
137    }
138}
139
140// ---------------------------------------------------------------------
141
142/// Builder for SPL Token Approve (instruction index 4).
143pub struct Approve<'a> {
144    pub source: &'a AccountView<'a>,
145    pub delegate: &'a AccountView<'a>,
146    pub authority: &'a AccountView<'a>,
147    pub amount: u64,
148}
149
150impl Approve<'_> {
151    #[inline]
152    pub fn invoke(&self) -> ProgramResult {
153        self.invoke_signed(&[])
154    }
155
156    #[inline]
157    pub fn invoke_signed(&self, signers: &[Signer<'_, '_>]) -> ProgramResult {
158        let mut data = [0u8; 9];
159        data[0] = 4;
160        data[1..9].copy_from_slice(&self.amount.to_le_bytes());
161
162        let accounts = [
163            CpiAccount::from(self.source),
164            CpiAccount::from(self.delegate),
165            CpiAccount::from(self.authority),
166        ];
167
168        invoke_token(&data, &accounts, 0b001, 0b100, signers)
169    }
170}
171
172// ---------------------------------------------------------------------
173
174/// Builder for SPL Token Revoke (instruction index 5).
175pub struct Revoke<'a> {
176    pub source: &'a AccountView<'a>,
177    pub authority: &'a AccountView<'a>,
178}
179
180impl Revoke<'_> {
181    #[inline]
182    pub fn invoke(&self) -> ProgramResult {
183        self.invoke_signed(&[])
184    }
185
186    #[inline]
187    pub fn invoke_signed(&self, signers: &[Signer<'_, '_>]) -> ProgramResult {
188        let data = [5u8];
189
190        let accounts = [
191            CpiAccount::from(self.source),
192            CpiAccount::from(self.authority),
193        ];
194
195        invoke_token(&data, &accounts, 0b01, 0b10, signers)
196    }
197}
198
199// ---------------------------------------------------------------------
200
201#[inline]
202fn invoke_token<'a, const ACCOUNTS: usize>(
203    data: &[u8],
204    accounts: &[CpiAccount<'a>; ACCOUNTS],
205    writable_mask: usize,
206    signer_mask: usize,
207    signers: &[Signer<'_, '_>],
208) -> ProgramResult {
209    crate::cpi::invoke_specialized_signed(
210        &TOKEN_PROGRAM_ID,
211        data,
212        accounts,
213        writable_mask,
214        signer_mask,
215        signers,
216    )
217}
218
219/// Compatibility re-exports matching `pinocchio_token::instructions::*`.
220pub mod instructions {
221    pub use super::{Approve, Burn, CloseAccount, MintTo, Revoke, Transfer};
222}