3
3
mod program_test;
4
4
use {
5
5
program_test:: { TestContext , TokenContext } ,
6
- solana_program_test:: tokio,
7
- solana_sdk:: { pubkey:: Pubkey , signature:: Signer } ,
8
- spl_token_2022:: extension:: { memo_transfer:: MemoTransfer , ExtensionType } ,
6
+ solana_program_test:: {
7
+ tokio:: { self , sync:: Mutex } ,
8
+ ProgramTestContext ,
9
+ } ,
10
+ solana_sdk:: {
11
+ instruction:: InstructionError ,
12
+ pubkey:: Pubkey ,
13
+ signature:: Signer ,
14
+ system_instruction,
15
+ transaction:: { Transaction , TransactionError } ,
16
+ transport:: TransportError ,
17
+ } ,
18
+ spl_token_2022:: {
19
+ error:: TokenError ,
20
+ extension:: { memo_transfer:: MemoTransfer , ExtensionType } ,
21
+ } ,
22
+ spl_token_client:: token:: TokenError as TokenClientError ,
23
+ std:: sync:: Arc ,
9
24
} ;
10
25
11
26
async fn test_memo_transfers (
27
+ context : Arc < Mutex < ProgramTestContext > > ,
12
28
token_context : TokenContext ,
13
29
alice_account : Pubkey ,
14
30
bob_account : Pubkey ,
@@ -38,14 +54,102 @@ async fn test_memo_transfers(
38
54
assert ! ( bool :: from( extension. require_incoming_transfer_memos) ) ;
39
55
40
56
// attempt to transfer from alice to bob without memo
41
- // TODO: should fail when token/program-2022/src/processor.rs#L376 is completed
57
+ let err = token
58
+ . transfer_unchecked ( & alice_account, & bob_account, & alice, 10 )
59
+ . await
60
+ . unwrap_err ( ) ;
61
+ assert_eq ! (
62
+ err,
63
+ TokenClientError :: Client ( Box :: new( TransportError :: TransactionError (
64
+ TransactionError :: InstructionError (
65
+ 0 ,
66
+ InstructionError :: Custom ( TokenError :: NoMemo as u32 )
67
+ )
68
+ ) ) )
69
+ ) ;
70
+ let bob_state = token. get_account_info ( & bob_account) . await . unwrap ( ) ;
71
+ assert_eq ! ( bob_state. base. amount, 0 ) ;
72
+
73
+ // attempt to transfer from alice to bob with misplaced memo, v1 and current
74
+ let mut memo_ix = spl_memo:: build_memo ( & [ 240 , 159 , 166 , 150 ] , & [ ] ) ;
75
+ for program_id in [ spl_memo:: id ( ) , spl_memo:: v1:: id ( ) ] {
76
+ let mut ctx = context. lock ( ) . await ;
77
+ memo_ix. program_id = program_id;
78
+ #[ allow( deprecated) ]
79
+ let instructions = vec ! [
80
+ memo_ix. clone( ) ,
81
+ system_instruction:: transfer( & ctx. payer. pubkey( ) , & alice. pubkey( ) , 42 ) ,
82
+ spl_token_2022:: instruction:: transfer(
83
+ & spl_token_2022:: id( ) ,
84
+ & alice_account,
85
+ & bob_account,
86
+ & alice. pubkey( ) ,
87
+ & [ ] ,
88
+ 10 ,
89
+ )
90
+ . unwrap( ) ,
91
+ ] ;
92
+ let tx = Transaction :: new_signed_with_payer (
93
+ & instructions,
94
+ Some ( & ctx. payer . pubkey ( ) ) ,
95
+ & [ & ctx. payer , & alice] ,
96
+ ctx. last_blockhash ,
97
+ ) ;
98
+ let err: TransactionError = ctx
99
+ . banks_client
100
+ . process_transaction ( tx)
101
+ . await
102
+ . unwrap_err ( )
103
+ . unwrap ( )
104
+ . into ( ) ;
105
+ drop ( ctx) ;
106
+ assert_eq ! (
107
+ err,
108
+ TransactionError :: InstructionError (
109
+ 2 ,
110
+ InstructionError :: Custom ( TokenError :: NoMemo as u32 )
111
+ )
112
+ ) ;
113
+ let bob_state = token. get_account_info ( & bob_account) . await . unwrap ( ) ;
114
+ assert_eq ! ( bob_state. base. amount, 0 ) ;
115
+ }
116
+
117
+ // transfer with memo
42
118
token
119
+ . with_memo ( "🦖" )
43
120
. transfer_unchecked ( & alice_account, & bob_account, & alice, 10 )
44
121
. await
45
122
. unwrap ( ) ;
46
123
let bob_state = token. get_account_info ( & bob_account) . await . unwrap ( ) ;
47
124
assert_eq ! ( bob_state. base. amount, 10 ) ;
48
125
126
+ // transfer with memo v1
127
+ let mut ctx = context. lock ( ) . await ;
128
+ memo_ix. program_id = spl_memo:: v1:: id ( ) ;
129
+ #[ allow( deprecated) ]
130
+ let instructions = vec ! [
131
+ memo_ix,
132
+ spl_token_2022:: instruction:: transfer(
133
+ & spl_token_2022:: id( ) ,
134
+ & alice_account,
135
+ & bob_account,
136
+ & alice. pubkey( ) ,
137
+ & [ ] ,
138
+ 11 ,
139
+ )
140
+ . unwrap( ) ,
141
+ ] ;
142
+ let tx = Transaction :: new_signed_with_payer (
143
+ & instructions,
144
+ Some ( & ctx. payer . pubkey ( ) ) ,
145
+ & [ & ctx. payer , & alice] ,
146
+ ctx. last_blockhash ,
147
+ ) ;
148
+ ctx. banks_client . process_transaction ( tx) . await . unwrap ( ) ;
149
+ drop ( ctx) ;
150
+ let bob_state = token. get_account_info ( & bob_account) . await . unwrap ( ) ;
151
+ assert_eq ! ( bob_state. base. amount, 21 ) ;
152
+
49
153
// stop requiring memo transfers into bob_account
50
154
token
51
155
. disable_required_transfer_memos ( & bob_account, & bob)
@@ -54,11 +158,11 @@ async fn test_memo_transfers(
54
158
55
159
// transfer from alice to bob without memo
56
160
token
57
- . transfer_unchecked ( & alice_account, & bob_account, & alice, 11 )
161
+ . transfer_unchecked ( & alice_account, & bob_account, & alice, 12 )
58
162
. await
59
163
. unwrap ( ) ;
60
164
let bob_state = token. get_account_info ( & bob_account) . await . unwrap ( ) ;
61
- assert_eq ! ( bob_state. base. amount, 21 ) ;
165
+ assert_eq ! ( bob_state. base. amount, 33 ) ;
62
166
}
63
167
64
168
#[ tokio:: test]
@@ -83,7 +187,7 @@ async fn require_memo_transfers_without_realloc() {
83
187
. await
84
188
. unwrap ( ) ;
85
189
86
- test_memo_transfers ( token_context, alice_account, bob_account) . await ;
190
+ test_memo_transfers ( context . context , token_context, alice_account, bob_account) . await ;
87
191
}
88
192
89
193
#[ tokio:: test]
@@ -113,5 +217,5 @@ async fn require_memo_transfers_with_realloc() {
113
217
. await
114
218
. unwrap ( ) ;
115
219
116
- test_memo_transfers ( token_context, alice_account, bob_account) . await ;
220
+ test_memo_transfers ( context . context , token_context, alice_account, bob_account) . await ;
117
221
}
0 commit comments