@@ -363,6 +363,22 @@ fn token_client_from_config(
363
363
}
364
364
}
365
365
366
+ fn native_token_client_from_config ( config : & Config < ' _ > ) -> Token < ProgramRpcClientSendTransaction > {
367
+ let token = Token :: new_native (
368
+ config. program_client . clone ( ) ,
369
+ & config. program_id ,
370
+ config. fee_payer . clone ( ) ,
371
+ ) ;
372
+
373
+ if let ( Some ( nonce_account) , Some ( nonce_authority) ) =
374
+ ( config. nonce_account , config. nonce_authority )
375
+ {
376
+ token. with_nonce ( & nonce_account, & nonce_authority)
377
+ } else {
378
+ token
379
+ }
380
+ }
381
+
366
382
#[ allow( clippy:: too_many_arguments) ]
367
383
async fn command_create_token (
368
384
config : & Config < ' _ > ,
@@ -508,7 +524,7 @@ async fn command_create_account(
508
524
let token = token_client_from_config ( config, & token_pubkey) ;
509
525
let mut extensions = vec ! [ ] ;
510
526
511
- let ( account, associated ) = if let Some ( account) = maybe_account {
527
+ let ( account, is_associated ) = if let Some ( account) = maybe_account {
512
528
( account, false )
513
529
} else {
514
530
( token. get_associated_token_address ( & owner) , true )
@@ -518,7 +534,7 @@ async fn command_create_account(
518
534
519
535
if !config. sign_only {
520
536
if let Some ( account_data) = config. program_client . get_account ( account) . await ? {
521
- if account_data. owner != system_program:: id ( ) || !associated {
537
+ if account_data. owner != system_program:: id ( ) || !is_associated {
522
538
return Err ( format ! ( "Error: Account already exists: {}" , account) . into ( ) ) ;
523
539
}
524
540
}
@@ -531,7 +547,7 @@ async fn command_create_account(
531
547
config. program_id
532
548
)
533
549
. into ( ) ) ;
534
- } else if associated {
550
+ } else if is_associated {
535
551
println_display (
536
552
config,
537
553
"Note: --immutable specified, but Token-2022 ATAs are always immutable" . to_string ( ) ,
@@ -541,7 +557,7 @@ async fn command_create_account(
541
557
}
542
558
}
543
559
544
- let res = if associated {
560
+ let res = if is_associated {
545
561
token. create_associated_token_account ( & owner) . await
546
562
} else {
547
563
let signer = bulk_signers
@@ -1189,17 +1205,6 @@ async fn command_thaw(
1189
1205
} )
1190
1206
}
1191
1207
1192
- // XXX TODO remove this when functionality moved into client
1193
- fn native_mint ( program_id : & Pubkey ) -> Result < Pubkey , Error > {
1194
- if program_id == & spl_token_2022:: id ( ) {
1195
- Ok ( spl_token_2022:: native_mint:: id ( ) )
1196
- } else if program_id == & spl_token:: id ( ) {
1197
- Ok ( spl_token:: native_mint:: id ( ) )
1198
- } else {
1199
- Err ( format ! ( "Error: unknown token program id {}" , program_id) . into ( ) )
1200
- }
1201
- }
1202
-
1203
1208
async fn command_wrap (
1204
1209
config : & Config < ' _ > ,
1205
1210
sol : f64 ,
@@ -1208,15 +1213,12 @@ async fn command_wrap(
1208
1213
bulk_signers : BulkSigners ,
1209
1214
) -> CommandResult {
1210
1215
let lamports = sol_to_lamports ( sol) ;
1211
- // XXX TODO i think i want a Token fn `new_native` that encapsulates the `native_mint` logic in one place
1212
- // also a function on it `is_native` maybe
1213
- let native_mint = native_mint ( & config. program_id ) ?;
1214
- let token = token_client_from_config ( config, & native_mint) ;
1216
+ let token = native_token_client_from_config ( config) ;
1215
1217
1216
1218
let account = wrapped_sol_account. unwrap_or_else ( || {
1217
1219
get_associated_token_address_with_program_id (
1218
1220
& wallet_address,
1219
- & native_mint ,
1221
+ token . get_address ( ) ,
1220
1222
& config. program_id ,
1221
1223
)
1222
1224
} ) ;
@@ -1251,19 +1253,22 @@ async fn command_wrap(
1251
1253
async fn command_unwrap (
1252
1254
config : & Config < ' _ > ,
1253
1255
wallet_address : Pubkey ,
1254
- account : Option < Pubkey > ,
1256
+ maybe_account : Option < Pubkey > ,
1255
1257
bulk_signers : BulkSigners ,
1256
1258
) -> CommandResult {
1257
- let use_associated_account = account. is_none ( ) ;
1258
- let native_mint = native_mint ( & config. program_id ) ?;
1259
- let account = account. unwrap_or_else ( || {
1259
+ let use_associated_account = maybe_account. is_none ( ) ;
1260
+ let token = native_token_client_from_config ( config) ;
1261
+
1262
+ let account = maybe_account. unwrap_or_else ( || {
1260
1263
get_associated_token_address_with_program_id (
1261
1264
& wallet_address,
1262
- & native_mint ,
1265
+ token . get_address ( ) ,
1263
1266
& config. program_id ,
1264
1267
)
1265
1268
} ) ;
1269
+
1266
1270
println_display ( config, format ! ( "Unwrapping {}" , account) ) ;
1271
+
1267
1272
if !config. sign_only {
1268
1273
let lamports = config. rpc_client . get_balance ( & account) . await ?;
1269
1274
if lamports == 0 {
@@ -1273,30 +1278,29 @@ async fn command_unwrap(
1273
1278
return Err ( format ! ( "No wrapped SOL in {}" , account) . into ( ) ) ;
1274
1279
}
1275
1280
}
1281
+
1276
1282
println_display (
1277
1283
config,
1278
1284
format ! ( " Amount: {} SOL" , lamports_to_sol( lamports) ) ,
1279
1285
) ;
1286
+
1287
+ if !use_associated_account {
1288
+ let account_data = config. get_account_checked ( & account) . await ?;
1289
+ let account_state = StateWithExtensionsOwned :: < Account > :: unpack ( account_data. data ) ?;
1290
+
1291
+ if account_state. base . mint != * token. get_address ( ) {
1292
+ return Err ( format ! ( "{} is not a native token account" , account) . into ( ) ) ;
1293
+ }
1294
+ }
1280
1295
}
1296
+
1281
1297
println_display ( config, format ! ( " Recipient: {}" , & wallet_address) ) ;
1282
1298
1283
- let instructions = vec ! [ close_account(
1284
- & config. program_id,
1285
- & account,
1286
- & wallet_address,
1287
- & wallet_address,
1288
- & config. multisigner_pubkeys,
1289
- ) ?] ;
1290
- let tx_return = handle_tx (
1291
- & CliSignerInfo {
1292
- signers : bulk_signers,
1293
- } ,
1294
- config,
1295
- false ,
1296
- 0 ,
1297
- instructions,
1298
- )
1299
- . await ?;
1299
+ let res = token
1300
+ . close_account ( & account, & wallet_address, & wallet_address, & bulk_signers)
1301
+ . await ?;
1302
+
1303
+ let tx_return = finish_tx ( config, & res, false ) . await ?;
1300
1304
Ok ( match tx_return {
1301
1305
TransactionReturnData :: CliSignature ( signature) => {
1302
1306
config. output_format . formatted_string ( & signature)
@@ -1811,25 +1815,20 @@ async fn command_gc(
1811
1815
Ok ( result)
1812
1816
}
1813
1817
1814
- async fn command_sync_native (
1815
- native_account_address : Pubkey ,
1816
- bulk_signers : Vec < Arc < dyn Signer > > ,
1817
- config : & Config < ' _ > ,
1818
- ) -> CommandResult {
1818
+ async fn command_sync_native ( config : & Config < ' _ > , native_account_address : Pubkey ) -> CommandResult {
1819
+ let token = native_token_client_from_config ( config) ;
1820
+
1819
1821
if !config. sign_only {
1820
- config. get_account_checked ( & native_account_address) . await ?;
1822
+ let account_data = config. get_account_checked ( & native_account_address) . await ?;
1823
+ let account_state = StateWithExtensionsOwned :: < Account > :: unpack ( account_data. data ) ?;
1824
+
1825
+ if account_state. base . mint != * token. get_address ( ) {
1826
+ return Err ( format ! ( "{} is not a native token account" , native_account_address) . into ( ) ) ;
1827
+ }
1821
1828
}
1822
1829
1823
- let tx_return = handle_tx (
1824
- & CliSignerInfo {
1825
- signers : bulk_signers,
1826
- } ,
1827
- config,
1828
- false ,
1829
- 0 ,
1830
- vec ! [ sync_native( & config. program_id, & native_account_address) ?] ,
1831
- )
1832
- . await ?;
1830
+ let res = token. sync_native ( & native_account_address) . await ?;
1831
+ let tx_return = finish_tx ( config, & res, false ) . await ?;
1833
1832
Ok ( match tx_return {
1834
1833
TransactionReturnData :: CliSignature ( signature) => {
1835
1834
config. output_format . formatted_string ( & signature)
@@ -3437,8 +3436,7 @@ async fn process_command<'a>(
3437
3436
. await
3438
3437
}
3439
3438
( CommandName :: SyncNative , arg_matches) => {
3440
- let program_id = config. program_id ;
3441
- let native_mint = native_mint ( & program_id) ?;
3439
+ let native_mint = * native_token_client_from_config ( config) . get_address ( ) ;
3442
3440
let address = config
3443
3441
. associated_token_address_for_token_or_override (
3444
3442
arg_matches,
@@ -3447,7 +3445,7 @@ async fn process_command<'a>(
3447
3445
Some ( native_mint) ,
3448
3446
)
3449
3447
. await ;
3450
- command_sync_native ( address , bulk_signers , config ) . await
3448
+ command_sync_native ( config , address ) . await
3451
3449
}
3452
3450
( CommandName :: EnableRequiredTransferMemos , arg_matches) => {
3453
3451
let ( owner_signer, owner) =
@@ -3599,6 +3597,16 @@ mod tests {
3599
3597
tempfile:: NamedTempFile ,
3600
3598
} ;
3601
3599
3600
+ fn native_mint ( program_id : & Pubkey ) -> Result < Pubkey , Error > {
3601
+ if program_id == & spl_token_2022:: id ( ) {
3602
+ Ok ( spl_token_2022:: native_mint:: id ( ) )
3603
+ } else if program_id == & spl_token:: id ( ) {
3604
+ Ok ( spl_token:: native_mint:: id ( ) )
3605
+ } else {
3606
+ Err ( format ! ( "Error: unknown token program id {}" , program_id) . into ( ) )
3607
+ }
3608
+ }
3609
+
3602
3610
fn clone_keypair ( keypair : & Keypair ) -> Keypair {
3603
3611
Keypair :: from_bytes ( & keypair. to_bytes ( ) ) . unwrap ( )
3604
3612
}
0 commit comments