@@ -205,36 +205,37 @@ pub enum ConfidentialTransferInstruction {
205
205
/// Withdraw SPL Tokens from the available balance of a confidential token
206
206
/// account.
207
207
///
208
+ /// In order for this instruction to be successfully processed, it must be accompanied by the
209
+ /// following list of `zk_elgamal_proof` program instructions:
210
+ /// - `VerifyCiphertextCommitmentEquality`
211
+ /// - `VerifyBatchedRangeProofU64`
212
+ /// These instructions can be accompanied in the same transaction or can be pre-verified into a
213
+ /// context state account, in which case, only their context state account address need to be
214
+ /// provided.
215
+ ///
208
216
/// Fails if the source or destination accounts are frozen.
209
217
/// Fails if the associated mint is extended as `NonTransferable`.
210
218
///
211
- /// In order for this instruction to be successfully processed, it must be
212
- /// accompanied by the `VerifyWithdraw` instruction of the
213
- /// `zk_token_proof` program in the same transaction or the address of a
214
- /// context state account for the proof must be provided.
215
- ///
216
219
/// Accounts expected by this instruction:
217
220
///
218
221
/// * Single owner/delegate
219
222
/// 0. `[writable]` The SPL Token account.
220
223
/// 1. `[]` The token mint.
221
- /// 2. `[]` Instructions sysvar if `VerifyWithdraw` is included in the
222
- /// same transaction or context state account if `VerifyWithdraw` is
223
- /// pre-verified into a context state account.
224
- /// 3. `[]` (Optional) Record account if the accompanying proof is to be
225
- /// read from a record account.
226
- /// 4. `[signer]` The single source account owner.
224
+ /// 2. `[]` (Optional) Instructions sysvar if at least one of the `zk_elgamal_proof`
225
+ /// instructions are included in the same transaction.
226
+ /// 3. `[]` (Optional) Equality proof record account or context state account.
227
+ /// 4. `[]` (Optional) Range proof record account or context state account.
228
+ /// 5. `[signer]` The single source account owner.
227
229
///
228
230
/// * Multisignature owner/delegate
229
231
/// 0. `[writable]` The SPL Token account.
230
232
/// 1. `[]` The token mint.
231
- /// 2. `[]` Instructions sysvar if `VerifyWithdraw` is included in the
232
- /// same transaction or context state account if `VerifyWithdraw` is
233
- /// pre-verified into a context state account.
234
- /// 3. `[]` (Optional) Record account if the accompanying proof is to be
235
- /// read from a record account.
236
- /// 4. `[]` The multisig source account owner.
237
- /// 5.. `[signer]` Required M signer accounts for the SPL Token Multisig
233
+ /// 2. `[]` (Optional) Instructions sysvar if at least one of the `zk_elgamal_proof`
234
+ /// instructions are included in the same transaction.
235
+ /// 3. `[]` (Optional) Equality proof record account or context state account.
236
+ /// 4. `[]` (Optional) Range proof record account or context state account.
237
+ /// 5. `[]` The multisig source account owner.
238
+ /// 6.. `[signer]` Required M signer accounts for the SPL Token Multisig
238
239
/// account.
239
240
///
240
241
/// Data expected by this instruction:
@@ -548,10 +549,14 @@ pub struct WithdrawInstructionData {
548
549
/// The new decryptable balance if the withdrawal succeeds
549
550
#[ cfg_attr( feature = "serde-traits" , serde( with = "aeciphertext_fromstr" ) ) ]
550
551
pub new_decryptable_available_balance : DecryptableBalance ,
551
- /// Relative location of the `ProofInstruction::VerifyWithdraw ` instruction
552
+ /// Relative location of the `ProofInstruction::VerifyCiphertextCommitmentEquality ` instruction
552
553
/// to the `Withdraw` instruction in the transaction. If the offset is
553
554
/// `0`, then use a context state account for the proof.
554
- pub proof_instruction_offset : i8 ,
555
+ pub equality_proof_instruction_offset : i8 ,
556
+ /// Relative location of the `ProofInstruction::BatchedRangeProofU64` instruction
557
+ /// to the `Withdraw` instruction in the transaction. If the offset is
558
+ /// `0`, then use a context state account for the proof.
559
+ pub range_proof_instruction_offset : i8 ,
555
560
}
556
561
557
562
/// Data expected by `ConfidentialTransferInstruction::Transfer`
@@ -948,17 +953,38 @@ pub fn inner_withdraw(
948
953
new_decryptable_available_balance : DecryptableBalance ,
949
954
authority : & Pubkey ,
950
955
multisig_signers : & [ & Pubkey ] ,
951
- proof_data_location : ProofLocation < WithdrawData > ,
956
+ equality_proof_data_location : ProofLocation < CiphertextCommitmentEqualityProofData > ,
957
+ range_proof_data_location : ProofLocation < BatchedRangeProofU64Data > ,
952
958
) -> Result < Instruction , ProgramError > {
953
959
check_program_account ( token_program_id) ?;
954
960
let mut accounts = vec ! [
955
961
AccountMeta :: new( * token_account, false ) ,
956
962
AccountMeta :: new_readonly( * mint, false ) ,
957
963
] ;
958
964
959
- let proof_instruction_offset = match proof_data_location {
965
+ // if at least one of the proof locations is an instruction offset, sysvar
966
+ // account is needed
967
+ if equality_proof_data_location. is_instruction_offset ( )
968
+ || range_proof_data_location. is_instruction_offset ( )
969
+ {
970
+ accounts. push ( AccountMeta :: new_readonly ( sysvar:: instructions:: id ( ) , false ) ) ;
971
+ }
972
+
973
+ let equality_proof_instruction_offset = match equality_proof_data_location {
974
+ ProofLocation :: InstructionOffset ( proof_instruction_offset, proof_data) => {
975
+ if let ProofData :: RecordAccount ( record_address, _) = proof_data {
976
+ accounts. push ( AccountMeta :: new_readonly ( * record_address, false ) ) ;
977
+ }
978
+ proof_instruction_offset. into ( )
979
+ }
980
+ ProofLocation :: ContextStateAccount ( context_state_account) => {
981
+ accounts. push ( AccountMeta :: new_readonly ( * context_state_account, false ) ) ;
982
+ 0
983
+ }
984
+ } ;
985
+
986
+ let range_proof_instruction_offset = match range_proof_data_location {
960
987
ProofLocation :: InstructionOffset ( proof_instruction_offset, proof_data) => {
961
- accounts. push ( AccountMeta :: new_readonly ( sysvar:: instructions:: id ( ) , false ) ) ;
962
988
if let ProofData :: RecordAccount ( record_address, _) = proof_data {
963
989
accounts. push ( AccountMeta :: new_readonly ( * record_address, false ) ) ;
964
990
}
@@ -988,7 +1014,8 @@ pub fn inner_withdraw(
988
1014
amount : amount. into ( ) ,
989
1015
decimals,
990
1016
new_decryptable_available_balance,
991
- proof_instruction_offset,
1017
+ equality_proof_instruction_offset,
1018
+ range_proof_instruction_offset,
992
1019
} ,
993
1020
) )
994
1021
}
@@ -1004,7 +1031,8 @@ pub fn withdraw(
1004
1031
new_decryptable_available_balance : PodAeCiphertext ,
1005
1032
authority : & Pubkey ,
1006
1033
multisig_signers : & [ & Pubkey ] ,
1007
- proof_data_location : ProofLocation < WithdrawData > ,
1034
+ equality_proof_data_location : ProofLocation < CiphertextCommitmentEqualityProofData > ,
1035
+ range_proof_data_location : ProofLocation < BatchedRangeProofU64Data > ,
1008
1036
) -> Result < Vec < Instruction > , ProgramError > {
1009
1037
let mut instructions = vec ! [ inner_withdraw(
1010
1038
token_program_id,
@@ -1015,24 +1043,41 @@ pub fn withdraw(
1015
1043
new_decryptable_available_balance. into( ) ,
1016
1044
authority,
1017
1045
multisig_signers,
1018
- proof_data_location,
1046
+ equality_proof_data_location,
1047
+ range_proof_data_location,
1019
1048
) ?] ;
1020
1049
1021
1050
if let ProofLocation :: InstructionOffset ( proof_instruction_offset, proof_data) =
1022
- proof_data_location
1051
+ equality_proof_data_location
1023
1052
{
1024
- // This constructor appends the proof instruction right after the `Withdraw`
1025
- // instruction. This means that the proof instruction offset must be
1026
- // always be 1. To use an arbitrary proof instruction offset, use the
1027
- // `inner_withdraw` constructor.
1028
1053
let proof_instruction_offset: i8 = proof_instruction_offset. into ( ) ;
1029
1054
if proof_instruction_offset != 1 {
1030
1055
return Err ( TokenError :: InvalidProofInstructionOffset . into ( ) ) ;
1031
1056
}
1032
1057
match proof_data {
1033
- ProofData :: InstructionData ( data) => instructions. push ( verify_withdraw ( None , data) ) ,
1058
+ ProofData :: InstructionData ( data) => instructions. push (
1059
+ ProofInstruction :: VerifyCiphertextCommitmentEquality
1060
+ . encode_verify_proof ( None , data) ,
1061
+ ) ,
1034
1062
ProofData :: RecordAccount ( address, offset) => instructions. push (
1035
- ProofInstruction :: VerifyWithdraw
1063
+ ProofInstruction :: VerifyCiphertextCommitmentEquality
1064
+ . encode_verify_proof_from_account ( None , address, offset) ,
1065
+ ) ,
1066
+ } ;
1067
+ } ;
1068
+
1069
+ if let ProofLocation :: InstructionOffset ( proof_instruction_offset, proof_data) =
1070
+ range_proof_data_location
1071
+ {
1072
+ let proof_instruction_offset: i8 = proof_instruction_offset. into ( ) ;
1073
+ if proof_instruction_offset != 2 {
1074
+ return Err ( TokenError :: InvalidProofInstructionOffset . into ( ) ) ;
1075
+ }
1076
+ match proof_data {
1077
+ ProofData :: InstructionData ( data) => instructions
1078
+ . push ( ProofInstruction :: VerifyBatchedRangeProofU64 . encode_verify_proof ( None , data) ) ,
1079
+ ProofData :: RecordAccount ( address, offset) => instructions. push (
1080
+ ProofInstruction :: VerifyBatchedRangeProofU64
1036
1081
. encode_verify_proof_from_account ( None , address, offset) ,
1037
1082
) ,
1038
1083
} ;
@@ -1120,6 +1165,10 @@ pub fn inner_transfer(
1120
1165
multisig_signers. is_empty ( ) ,
1121
1166
) ) ;
1122
1167
1168
+ for multisig_signer in multisig_signers. iter ( ) {
1169
+ accounts. push ( AccountMeta :: new_readonly ( * * multisig_signer, true ) ) ;
1170
+ }
1171
+
1123
1172
Ok ( encode_instruction (
1124
1173
token_program_id,
1125
1174
accounts,
@@ -1476,6 +1525,10 @@ pub fn inner_transfer_with_fee(
1476
1525
multisig_signers. is_empty ( ) ,
1477
1526
) ) ;
1478
1527
1528
+ for multisig_signer in multisig_signers. iter ( ) {
1529
+ accounts. push ( AccountMeta :: new_readonly ( * * multisig_signer, true ) ) ;
1530
+ }
1531
+
1479
1532
Ok ( encode_instruction (
1480
1533
token_program_id,
1481
1534
accounts,
0 commit comments