@@ -22,31 +22,30 @@ fn processInstruction(program_id: *align(1) PublicKey, accounts: []sol.Account,
2222 if (accounts .len < 2 ) {
2323 return TokenError .NotEnoughAccountKeys ;
2424 }
25- const init : * align (1 ) const ix.InitializeMintData = @ptrCast (data [1.. ]);
25+ const ix_data : * align (1 ) const ix.InitializeMintData = @ptrCast (data [1.. ]);
2626 const mint_account = accounts [0 ];
2727 const rent_sysvar = accounts [1 ];
28- if (! rent_sysvar .id ().equals (Rent .id )) {
29- return TokenError .InvalidAccountData ;
30- }
3128
29+ var mint : * align (1 ) state.Mint = @ptrCast (mint_account .data ());
3230 if (mint_account .dataLen () != state .Mint .len ) {
3331 return TokenError .InvalidAccountData ;
3432 }
35-
36- var mint : * align (1 ) state.Mint = @ptrCast (mint_account .data ());
3733 if (mint .is_initialized == 1 ) {
3834 return TokenError .AlreadyInUse ;
3935 }
4036
4137 const rent : * align (1 ) Rent.Data = @ptrCast (rent_sysvar .data ());
38+ if (! rent_sysvar .id ().equals (Rent .id )) {
39+ return TokenError .InvalidAccountData ;
40+ }
4241 if (! rent .isExempt (mint_account .lamports ().* , mint_account .dataLen ())) {
4342 return TokenError .NotRentExempt ;
4443 }
4544
46- mint .mint_authority = state .COption (PublicKey ).fromValue (init .mint_authority );
47- mint .decimals = init .decimals ;
45+ mint .mint_authority = state .COption (PublicKey ).fromValue (ix_data .mint_authority );
46+ mint .decimals = ix_data .decimals ;
4847 mint .is_initialized = 1 ;
49- mint .freeze_authority = init .freeze_authority .toCOption ();
48+ mint .freeze_authority = ix_data .freeze_authority .toCOption ();
5049 },
5150 ix .InstructionDiscriminant .initialize_account = > {
5251 //sol.log("Instruction: InitializeAccount");
@@ -59,14 +58,13 @@ fn processInstruction(program_id: *align(1) PublicKey, accounts: []sol.Account,
5958 const rent_sysvar = accounts [3 ];
6059 const rent : * align (1 ) Rent.Data = @ptrCast (rent_sysvar .data ());
6160
61+ var account : * align (1 ) state.Account = @ptrCast (token_account .data ());
6262 if (token_account .dataLen () != state .Account .len ) {
6363 return TokenError .InvalidAccountData ;
6464 }
65- var account : * align (1 ) state.Account = @ptrCast (token_account .data ());
6665 if (account .state != state .Account .State .uninitialized ) {
6766 return TokenError .AlreadyInUse ;
6867 }
69-
7068 if (! rent .isExempt (token_account .lamports ().* , token_account .dataLen ())) {
7169 return TokenError .NotRentExempt ;
7270 }
@@ -80,11 +78,10 @@ fn processInstruction(program_id: *align(1) PublicKey, accounts: []sol.Account,
8078 if (mint_account .id ().equals (native_mint_id )) {
8179 const rent_exempt_reserve = rent .getMinimumBalance (token_account .dataLen ());
8280 account .is_native = state .COption (u64 ).fromValue (rent_exempt_reserve );
83- const amount = @subWithOverflow (token_account .lamports ().* , rent_exempt_reserve );
84- if (amount [1 ] != 0 ) {
81+ if (rent_exempt_reserve > token_account .lamports ().* ) {
8582 return TokenError .Overflow ;
8683 }
87- account .amount = amount [ 0 ] ;
84+ account .amount = token_account . lamports () .* - rent_exempt_reserve ;
8885 } else {
8986 if (! mint_account .ownerId ().equals (program_id .* )) {
9087 return TokenError .IllegalOwner ;
@@ -109,41 +106,40 @@ fn processInstruction(program_id: *align(1) PublicKey, accounts: []sol.Account,
109106 if (accounts .len < 3 ) {
110107 return TokenError .NotEnoughAccountKeys ;
111108 }
112- const transfer_data : * align (1 ) const ix.AmountData = @ptrCast (data [1.. ]);
109+ const ix_data : * align (1 ) const ix.AmountData = @ptrCast (data [1.. ]);
113110 const source_account = accounts [0 ];
114111 const destination_account = accounts [1 ];
115112 const authority_account = accounts [2 ];
116113
114+ var source : * align (1 ) state.Account = @ptrCast (source_account .data ());
117115 if (source_account .dataLen () != state .Account .len ) {
118116 return TokenError .InvalidAccountData ;
119117 }
120- var source : * align (1 ) state.Account = @ptrCast (source_account .data ());
121118 if (source .state == state .Account .State .uninitialized ) {
122119 return TokenError .UninitializedState ;
123120 }
124121 if (source .state == state .Account .State .frozen ) {
125122 return TokenError .AccountFrozen ;
126123 }
127124
125+ var destination : * align (1 ) state.Account = @ptrCast (destination_account .data ());
128126 if (destination_account .dataLen () != state .Account .len ) {
129127 return TokenError .InvalidAccountData ;
130128 }
131- var destination : * align (1 ) state.Account = @ptrCast (destination_account .data ());
132129 if (destination .state == state .Account .State .uninitialized ) {
133130 return TokenError .UninitializedState ;
134131 }
135132 if (destination .state == state .Account .State .frozen ) {
136133 return TokenError .AccountFrozen ;
137134 }
138135
139- if (source .amount < transfer_data .amount ) {
136+ if (source .amount < ix_data .amount ) {
140137 return TokenError .InsufficientFunds ;
141138 }
142139 if (! source .mint .equals (destination .mint )) {
143140 return TokenError .MintMismatch ;
144141 }
145142
146- const self_transfer = source_account .id ().equals (destination_account .id ());
147143 //match source_account.delegate {
148144 // COption::Some(ref delegate) if Self::cmp_pubkeys(authority_info.key, delegate) => {
149145 // Self::validate_owner(
@@ -172,22 +168,23 @@ fn processInstruction(program_id: *align(1) PublicKey, accounts: []sol.Account,
172168 accounts [3.. ],
173169 );
174170
175- if (self_transfer or transfer_data .amount == 0 ) {
171+ const pre_amount = source .amount ;
172+ source .amount -= ix_data .amount ;
173+ destination .amount += ix_data .amount ;
174+
175+ if (source .isNative ()) {
176+ source_account .lamports ().* -= ix_data .amount ;
177+ destination_account .lamports ().* += ix_data .amount ;
178+ }
179+
180+ if (pre_amount == source .amount ) {
181+ // self transfer or 0 token amount, check owners for safety
176182 if (! source_account .ownerId ().equals (program_id .* )) {
177183 return TokenError .IllegalOwner ;
178184 }
179185 if (! destination_account .ownerId ().equals (program_id .* )) {
180186 return TokenError .IllegalOwner ;
181187 }
182- return ;
183- }
184-
185- source .amount -= transfer_data .amount ;
186- destination .amount += transfer_data .amount ;
187-
188- if (source .isNative ()) {
189- source_account .lamports ().* -= transfer_data .amount ;
190- destination_account .lamports ().* += transfer_data .amount ;
191188 }
192189 },
193190 ix .InstructionDiscriminant .approve = > {
@@ -208,28 +205,28 @@ fn processInstruction(program_id: *align(1) PublicKey, accounts: []sol.Account,
208205 const mint_account = accounts [0 ];
209206 const destination_account = accounts [1 ];
210207 const authority_account = accounts [2 ];
208+
209+ var destination : * align (1 ) state.Account = @ptrCast (destination_account .data ());
211210 if (destination_account .dataLen () != state .Account .len ) {
212211 return TokenError .InvalidAccountData ;
213212 }
214- var destination : * align (1 ) state.Account = @ptrCast (destination_account .data ());
215213 if (destination .state == state .Account .State .uninitialized ) {
216214 return TokenError .UninitializedState ;
217215 }
218216 if (destination .state == state .Account .State .frozen ) {
219217 return TokenError .AccountFrozen ;
220218 }
221-
222219 if (destination .isNative ()) {
223220 return TokenError .NativeNotSupported ;
224221 }
225222 if (! mint_account .id ().equals (destination .mint )) {
226223 return TokenError .MintMismatch ;
227224 }
228225
226+ var mint : * align (1 ) state.Mint = @ptrCast (mint_account .data ());
229227 if (mint_account .dataLen () != state .Mint .len ) {
230228 return TokenError .InvalidAccountData ;
231229 }
232- var mint : * align (1 ) state.Mint = @ptrCast (mint_account .data ());
233230 if (mint .is_initialized != 1 ) {
234231 return TokenError .UninitializedState ;
235232 }
@@ -274,15 +271,15 @@ fn processInstruction(program_id: *align(1) PublicKey, accounts: []sol.Account,
274271 if (accounts .len < 3 ) {
275272 return TokenError .NotEnoughAccountKeys ;
276273 }
277- const burn_data : * align (1 ) const ix.AmountData = @ptrCast (data [1.. ]);
274+ const ix_data : * align (1 ) const ix.AmountData = @ptrCast (data [1.. ]);
278275 const source_account = accounts [0 ];
279276 const mint_account = accounts [1 ];
280277 const authority_account = accounts [2 ];
281278
279+ var source : * align (1 ) state.Account = @ptrCast (source_account .data ());
282280 if (source_account .dataLen () != state .Account .len ) {
283281 return TokenError .InvalidAccountData ;
284282 }
285- var source : * align (1 ) state.Account = @ptrCast (source_account .data ());
286283 if (source .state == state .Account .State .uninitialized ) {
287284 return TokenError .UninitializedState ;
288285 }
@@ -297,15 +294,15 @@ fn processInstruction(program_id: *align(1) PublicKey, accounts: []sol.Account,
297294 return TokenError .MintMismatch ;
298295 }
299296
297+ var mint : * align (1 ) state.Mint = @ptrCast (mint_account .data ());
300298 if (mint_account .dataLen () != state .Mint .len ) {
301299 return TokenError .InvalidAccountData ;
302300 }
303- var mint : * align (1 ) state.Mint = @ptrCast (mint_account .data ());
304301 if (mint .is_initialized != 1 ) {
305302 return TokenError .UninitializedState ;
306303 }
307304
308- if (source .amount < burn_data .amount ) {
305+ if (source .amount < ix_data .amount ) {
309306 return TokenError .InsufficientFunds ;
310307 }
311308
@@ -345,7 +342,7 @@ fn processInstruction(program_id: *align(1) PublicKey, accounts: []sol.Account,
345342 accounts [3.. ],
346343 );
347344
348- if (burn_data .amount == 0 ) {
345+ if (ix_data .amount == 0 ) {
349346 if (! mint_account .ownerId ().equals (program_id .* )) {
350347 return TokenError .IllegalOwner ;
351348 }
@@ -354,8 +351,8 @@ fn processInstruction(program_id: *align(1) PublicKey, accounts: []sol.Account,
354351 }
355352 }
356353
357- source .amount -= burn_data .amount ;
358- mint .supply -= burn_data .amount ;
354+ source .amount -= ix_data .amount ;
355+ mint .supply -= ix_data .amount ;
359356 },
360357 ix .InstructionDiscriminant .close_account = > {
361358 if (accounts .len < 3 ) {
@@ -365,19 +362,16 @@ fn processInstruction(program_id: *align(1) PublicKey, accounts: []sol.Account,
365362 const destination_account = accounts [1 ];
366363 const authority_account = accounts [2 ];
367364
365+ var source : * align (1 ) state.Account = @ptrCast (source_account .data ());
368366 if (source_account .dataLen () != state .Account .len ) {
369367 return TokenError .InvalidAccountData ;
370368 }
371- var source : * align (1 ) state.Account = @ptrCast (source_account .data ());
372369 if (source .state == state .Account .State .uninitialized ) {
373370 return TokenError .UninitializedState ;
374371 }
375372 if (source .state == state .Account .State .frozen ) {
376373 return TokenError .AccountFrozen ;
377374 }
378- if (source_account .id ().equals (destination_account .id ())) {
379- return TokenError .InvalidAccountData ;
380- }
381375 if (! source .isNative () and source .amount != 0 ) {
382376 return TokenError .NonNativeHasBalance ;
383377 }
@@ -409,6 +403,12 @@ fn processInstruction(program_id: *align(1) PublicKey, accounts: []sol.Account,
409403 source_account .lamports ().* = 0 ;
410404 source_account .assign (system_program_id );
411405 source_account .reallocUnchecked (0 );
406+
407+ // if the destination has no more lamports, then this was a self-close,
408+ // which is not allowed
409+ if (destination_account .lamports ().* == 0 ) {
410+ return TokenError .InvalidAccountData ;
411+ }
412412 },
413413 ix .InstructionDiscriminant .freeze_account = > {
414414 return TokenError .InvalidState ;
@@ -467,7 +467,7 @@ fn validateOwner(
467467 if (! expected_owner .equals (owner_account .id ())) {
468468 return TokenError .OwnerMismatch ;
469469 }
470- if (program_id . equals ( owner_account .ownerId ()) and owner_account . dataLen () == state .Multisig .len ) {
470+ if (owner_account .dataLen () == state .Multisig .len and program_id . equals ( owner_account . ownerId ()) ) {
471471 //let multisig = Multisig::unpack(&owner_account_info.data.borrow())?;
472472 //let mut num_signers = 0;
473473 //let mut matched = [false; MAX_SIGNERS];
0 commit comments