@@ -73,8 +73,11 @@ fn test_transfer_fee_config_with_keypairs() -> TransferFeeConfigWithKeypairs {
73
73
}
74
74
75
75
struct TokenWithAccounts {
76
+ context : TestContext ,
76
77
token : Token < ProgramBanksClientProcessTransaction , Keypair > ,
77
78
transfer_fee_config : TransferFeeConfig ,
79
+ withdraw_withheld_authority : Keypair ,
80
+ freeze_authority : Keypair ,
78
81
alice : Keypair ,
79
82
alice_account : Pubkey ,
80
83
bob_account : Pubkey ,
@@ -96,7 +99,7 @@ async fn create_mint_with_accounts(alice_amount: u64) -> TokenWithAccounts {
96
99
) ;
97
100
let maximum_fee = u64:: from ( transfer_fee_config. newer_transfer_fee . maximum_fee ) ;
98
101
context
99
- . init_token_with_mint ( vec ! [ ExtensionInitializationParams :: TransferFeeConfig {
102
+ . init_token_with_freezing_mint ( vec ! [ ExtensionInitializationParams :: TransferFeeConfig {
100
103
transfer_fee_config_authority: transfer_fee_config_authority. pubkey( ) . into( ) ,
101
104
withdraw_withheld_authority: withdraw_withheld_authority. pubkey( ) . into( ) ,
102
105
transfer_fee_basis_points,
@@ -107,11 +110,12 @@ async fn create_mint_with_accounts(alice_amount: u64) -> TokenWithAccounts {
107
110
let TokenContext {
108
111
decimals,
109
112
mint_authority,
113
+ freeze_authority,
110
114
token,
111
115
alice,
112
116
bob,
113
117
..
114
- } = context. token_context . unwrap ( ) ;
118
+ } = context. token_context . take ( ) . unwrap ( ) ;
115
119
116
120
// token account is self-owned just to test another case
117
121
let alice_account = token
@@ -130,8 +134,11 @@ async fn create_mint_with_accounts(alice_amount: u64) -> TokenWithAccounts {
130
134
. await
131
135
. unwrap ( ) ;
132
136
TokenWithAccounts {
137
+ context,
133
138
token,
134
139
transfer_fee_config,
140
+ withdraw_withheld_authority,
141
+ freeze_authority : freeze_authority. unwrap ( ) ,
135
142
alice,
136
143
alice_account,
137
144
bob_account,
@@ -407,6 +414,17 @@ async fn fail_unsupported_mint() {
407
414
TransactionError :: InstructionError ( 0 , InstructionError :: InvalidAccountData )
408
415
) ) )
409
416
) ;
417
+ let error = token
418
+ . withdraw_withheld_tokens_from_mint ( & Pubkey :: new_unique ( ) , & mint_authority)
419
+ . await
420
+ . err ( )
421
+ . unwrap ( ) ;
422
+ assert_eq ! (
423
+ error,
424
+ TokenClientError :: Client ( Box :: new( TransportError :: TransactionError (
425
+ TransactionError :: InstructionError ( 0 , InstructionError :: InvalidAccountData )
426
+ ) ) )
427
+ ) ;
410
428
}
411
429
412
430
#[ tokio:: test]
@@ -997,49 +1015,17 @@ async fn create_and_transfer_to_account(
997
1015
998
1016
#[ tokio:: test]
999
1017
async fn harvest_withheld_tokens_to_mint ( ) {
1000
- let TransferFeeConfigWithKeypairs {
1001
- transfer_fee_config_authority,
1002
- withdraw_withheld_authority,
1003
- transfer_fee_config,
1004
- ..
1005
- } = test_transfer_fee_config_with_keypairs ( ) ;
1006
- let mut context = TestContext :: new ( ) . await ;
1007
- let transfer_fee_basis_points = u16:: from (
1008
- transfer_fee_config
1009
- . newer_transfer_fee
1010
- . transfer_fee_basis_points ,
1011
- ) ;
1012
- let maximum_fee = u64:: from ( transfer_fee_config. newer_transfer_fee . maximum_fee ) ;
1013
- context
1014
- . init_token_with_mint ( vec ! [ ExtensionInitializationParams :: TransferFeeConfig {
1015
- transfer_fee_config_authority: transfer_fee_config_authority. pubkey( ) . into( ) ,
1016
- withdraw_withheld_authority: withdraw_withheld_authority. pubkey( ) . into( ) ,
1017
- transfer_fee_basis_points,
1018
- maximum_fee,
1019
- } ] )
1020
- . await
1021
- . unwrap ( ) ;
1022
- let TokenContext {
1023
- decimals,
1024
- mint_authority,
1018
+ let amount = TEST_MAXIMUM_FEE ;
1019
+ let alice_amount = amount * 100 ;
1020
+ let TokenWithAccounts {
1021
+ mut context,
1025
1022
token,
1023
+ transfer_fee_config,
1026
1024
alice,
1025
+ alice_account,
1026
+ decimals,
1027
1027
..
1028
- } = context. token_context . as_ref ( ) . unwrap ( ) ;
1029
-
1030
- let alice_account = Keypair :: new ( ) ;
1031
- let alice_account = token
1032
- . create_auxiliary_token_account ( & alice_account, & alice. pubkey ( ) )
1033
- . await
1034
- . unwrap ( ) ;
1035
-
1036
- // mint a lot of tokens
1037
- let amount = maximum_fee;
1038
- let alice_amount = amount * 100 ;
1039
- token
1040
- . mint_to ( & alice_account, mint_authority, alice_amount)
1041
- . await
1042
- . unwrap ( ) ;
1028
+ } = create_mint_with_accounts ( alice_amount) . await ;
1043
1029
1044
1030
// harvest from zero accounts
1045
1031
token. harvest_withheld_tokens_to_mint ( & [ ] ) . await . unwrap ( ) ;
@@ -1050,12 +1036,12 @@ async fn harvest_withheld_tokens_to_mint() {
1050
1036
// harvest from one account
1051
1037
let accumulated_fees = transfer_fee_config. calculate_epoch_fee ( 0 , amount) . unwrap ( ) ;
1052
1038
let account = create_and_transfer_to_account (
1053
- token,
1039
+ & token,
1054
1040
& alice_account,
1055
- alice,
1041
+ & alice,
1056
1042
& alice. pubkey ( ) ,
1057
1043
amount,
1058
- * decimals,
1044
+ decimals,
1059
1045
)
1060
1046
. await ;
1061
1047
token
@@ -1084,24 +1070,24 @@ async fn harvest_withheld_tokens_to_mint() {
1084
1070
// no fail harvesting from account belonging to different mint, but nothing
1085
1071
// happens
1086
1072
let account = create_and_transfer_to_account (
1087
- token,
1073
+ & token,
1088
1074
& alice_account,
1089
- alice,
1075
+ & alice,
1090
1076
& alice. pubkey ( ) ,
1091
1077
amount,
1092
- * decimals,
1078
+ decimals,
1093
1079
)
1094
1080
. await ;
1095
1081
context
1096
1082
. init_token_with_mint ( vec ! [ ExtensionInitializationParams :: TransferFeeConfig {
1097
- transfer_fee_config_authority: transfer_fee_config_authority . pubkey ( ) . into ( ) ,
1098
- withdraw_withheld_authority: withdraw_withheld_authority . pubkey ( ) . into ( ) ,
1099
- transfer_fee_basis_points,
1100
- maximum_fee,
1083
+ transfer_fee_config_authority: Some ( Pubkey :: new_unique ( ) ) ,
1084
+ withdraw_withheld_authority: Some ( Pubkey :: new_unique ( ) ) ,
1085
+ transfer_fee_basis_points: TEST_FEE_BASIS_POINTS ,
1086
+ maximum_fee: TEST_MAXIMUM_FEE ,
1101
1087
} ] )
1102
1088
. await
1103
1089
. unwrap ( ) ;
1104
- let TokenContext { token, .. } = context. token_context . unwrap ( ) ;
1090
+ let TokenContext { token, .. } = context. token_context . take ( ) . unwrap ( ) ;
1105
1091
token
1106
1092
. harvest_withheld_tokens_to_mint ( & [ & account] )
1107
1093
. await
@@ -1156,3 +1142,156 @@ async fn max_harvest_withheld_tokens_to_mint() {
1156
1142
let extension = state. get_extension :: < TransferFeeConfig > ( ) . unwrap ( ) ;
1157
1143
assert_eq ! ( extension. withheld_amount, accumulated_fees. into( ) ) ;
1158
1144
}
1145
+
1146
+ #[ tokio:: test]
1147
+ async fn withdraw_withheld_tokens_from_mint ( ) {
1148
+ let amount = TEST_MAXIMUM_FEE ;
1149
+ let alice_amount = amount * 100 ;
1150
+ let TokenWithAccounts {
1151
+ mut context,
1152
+ token,
1153
+ transfer_fee_config,
1154
+ withdraw_withheld_authority,
1155
+ freeze_authority,
1156
+ alice,
1157
+ alice_account,
1158
+ decimals,
1159
+ bob_account,
1160
+ ..
1161
+ } = create_mint_with_accounts ( alice_amount) . await ;
1162
+
1163
+ // no tokens withheld on mint
1164
+ token
1165
+ . withdraw_withheld_tokens_from_mint ( & alice_account, & withdraw_withheld_authority)
1166
+ . await
1167
+ . unwrap ( ) ;
1168
+ let state = token. get_account_info ( & alice_account) . await . unwrap ( ) ;
1169
+ assert_eq ! ( state. base. amount, alice_amount) ;
1170
+ let extension = state. get_extension :: < TransferFeeAmount > ( ) . unwrap ( ) ;
1171
+ assert_eq ! ( extension. withheld_amount, 0 . into( ) ) ;
1172
+ let state = token. get_mint_info ( ) . await . unwrap ( ) ;
1173
+ let extension = state. get_extension :: < TransferFeeConfig > ( ) . unwrap ( ) ;
1174
+ assert_eq ! ( extension. withheld_amount, 0 . into( ) ) ;
1175
+
1176
+ // transfer + harvest to mint
1177
+ let fee = transfer_fee_config. calculate_epoch_fee ( 0 , amount) . unwrap ( ) ;
1178
+ let account = create_and_transfer_to_account (
1179
+ & token,
1180
+ & alice_account,
1181
+ & alice,
1182
+ & alice. pubkey ( ) ,
1183
+ amount,
1184
+ decimals,
1185
+ )
1186
+ . await ;
1187
+
1188
+ let state = token. get_account_info ( & account) . await . unwrap ( ) ;
1189
+ let extension = state. get_extension :: < TransferFeeAmount > ( ) . unwrap ( ) ;
1190
+ assert_eq ! ( extension. withheld_amount, fee. into( ) ) ;
1191
+
1192
+ token
1193
+ . harvest_withheld_tokens_to_mint ( & [ & account] )
1194
+ . await
1195
+ . unwrap ( ) ;
1196
+
1197
+ let state = token. get_mint_info ( ) . await . unwrap ( ) ;
1198
+ let extension = state. get_extension :: < TransferFeeConfig > ( ) . unwrap ( ) ;
1199
+ assert_eq ! ( extension. withheld_amount, fee. into( ) ) ;
1200
+
1201
+ // success
1202
+ token
1203
+ . withdraw_withheld_tokens_from_mint ( & bob_account, & withdraw_withheld_authority)
1204
+ . await
1205
+ . unwrap ( ) ;
1206
+ let state = token. get_account_info ( & bob_account) . await . unwrap ( ) ;
1207
+ assert_eq ! ( state. base. amount, fee) ;
1208
+ let state = token. get_account_info ( & account) . await . unwrap ( ) ;
1209
+ let extension = state. get_extension :: < TransferFeeAmount > ( ) . unwrap ( ) ;
1210
+ assert_eq ! ( extension. withheld_amount, 0 . into( ) ) ;
1211
+ let state = token. get_mint_info ( ) . await . unwrap ( ) ;
1212
+ let extension = state. get_extension :: < TransferFeeConfig > ( ) . unwrap ( ) ;
1213
+ assert_eq ! ( extension. withheld_amount, 0 . into( ) ) ;
1214
+
1215
+ // fail wrong signer
1216
+ let error = token
1217
+ . withdraw_withheld_tokens_from_mint ( & alice_account, & alice)
1218
+ . await
1219
+ . unwrap_err ( ) ;
1220
+ assert_eq ! (
1221
+ error,
1222
+ TokenClientError :: Client ( Box :: new( TransportError :: TransactionError (
1223
+ TransactionError :: InstructionError (
1224
+ 0 ,
1225
+ InstructionError :: Custom ( TokenError :: OwnerMismatch as u32 )
1226
+ )
1227
+ ) ) )
1228
+ ) ;
1229
+
1230
+ // fail frozen account
1231
+ token
1232
+ . freeze_account ( & bob_account, & freeze_authority)
1233
+ . await
1234
+ . unwrap ( ) ;
1235
+ let error = token
1236
+ . withdraw_withheld_tokens_from_mint ( & bob_account, & withdraw_withheld_authority)
1237
+ . await
1238
+ . unwrap_err ( ) ;
1239
+ assert_eq ! (
1240
+ error,
1241
+ TokenClientError :: Client ( Box :: new( TransportError :: TransactionError (
1242
+ TransactionError :: InstructionError (
1243
+ 0 ,
1244
+ InstructionError :: Custom ( TokenError :: AccountFrozen as u32 )
1245
+ )
1246
+ ) ) )
1247
+ ) ;
1248
+
1249
+ // set to none, fail
1250
+ token
1251
+ . set_authority (
1252
+ token. get_address ( ) ,
1253
+ None ,
1254
+ instruction:: AuthorityType :: WithheldWithdraw ,
1255
+ & withdraw_withheld_authority,
1256
+ )
1257
+ . await
1258
+ . unwrap ( ) ;
1259
+ let error = token
1260
+ . withdraw_withheld_tokens_from_mint ( & alice_account, & withdraw_withheld_authority)
1261
+ . await
1262
+ . unwrap_err ( ) ;
1263
+ assert_eq ! (
1264
+ error,
1265
+ TokenClientError :: Client ( Box :: new( TransportError :: TransactionError (
1266
+ TransactionError :: InstructionError (
1267
+ 0 ,
1268
+ InstructionError :: Custom ( TokenError :: NoAuthorityExists as u32 )
1269
+ )
1270
+ ) ) )
1271
+ ) ;
1272
+
1273
+ // fail on new mint with mint mismatch
1274
+ context
1275
+ . init_token_with_mint ( vec ! [ ExtensionInitializationParams :: TransferFeeConfig {
1276
+ transfer_fee_config_authority: Some ( Pubkey :: new_unique( ) ) ,
1277
+ withdraw_withheld_authority: Some ( withdraw_withheld_authority. pubkey( ) ) ,
1278
+ transfer_fee_basis_points: TEST_FEE_BASIS_POINTS ,
1279
+ maximum_fee: TEST_MAXIMUM_FEE ,
1280
+ } ] )
1281
+ . await
1282
+ . unwrap ( ) ;
1283
+ let TokenContext { token, .. } = context. token_context . take ( ) . unwrap ( ) ;
1284
+ let error = token
1285
+ . withdraw_withheld_tokens_from_mint ( & account, & withdraw_withheld_authority)
1286
+ . await
1287
+ . unwrap_err ( ) ;
1288
+ assert_eq ! (
1289
+ error,
1290
+ TokenClientError :: Client ( Box :: new( TransportError :: TransactionError (
1291
+ TransactionError :: InstructionError (
1292
+ 0 ,
1293
+ InstructionError :: Custom ( TokenError :: MintMismatch as u32 )
1294
+ )
1295
+ ) ) )
1296
+ ) ;
1297
+ }
0 commit comments