-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[token-2022] Update confidential transfer fee extension for solana 1.16 #4896
[token-2022] Update confidential transfer fee extension for solana 1.16 #4896
Conversation
21545f8
to
995e1a7
Compare
995e1a7
to
e4869dd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks really great overall! The core logic is good, just a few little things to sort out
token/program-2022/src/extension/confidential_transfer_fee/account_info.rs
Outdated
Show resolved
Hide resolved
token/program-2022/src/extension/confidential_transfer_fee/mod.rs
Outdated
Show resolved
Hide resolved
impl ConfidentialTransferFeeConfig { | ||
/// Return the account information needed to construct a `WithdrawWithheldTokensFromMint` | ||
/// instruction. | ||
#[cfg(not(target_os = "solana"))] | ||
pub fn withheld_tokens_info(&self) -> WithheldTokensInfo { | ||
WithheldTokensInfo { | ||
withheld_amount: self.withheld_amount, | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this seems a bit backwards -- how about having a function on WithheldTokensInfo
that takes &ConfidentialTransferFeeConfig
? That way you can keep the #[cfg(not(target_os = "solana"))]
bits all in account_info.rs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that is actually a good idea. Since WithheldTokensInfo
just has one field withheld_amount
, I think we can just work with the existing constructor new(withheld_amount: EncryptedWithheldAmount) -> Self
rather than taking in the entire confidential transfer fee config.
But the suggestion appiles for the account info types in the regular confidential transfer extension, so I will apply the suggestion there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
token/program-2022/src/extension/confidential_transfer_fee/instruction.rs
Outdated
Show resolved
Hide resolved
token/program-2022/src/extension/confidential_transfer_fee/instruction.rs
Outdated
Show resolved
Hide resolved
token/program-2022/src/extension/confidential_transfer_fee/processor.rs
Outdated
Show resolved
Hide resolved
if !authority_info.is_signer { | ||
return Err(ProgramError::MissingRequiredSignature); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment mentions that this works with multisigs, but this check means that it only works with single authorities. It's fine if we don't want to support multisigs, but we should be clear in the instruction interface
if !authority_info.is_signer { | ||
return Err(ProgramError::MissingRequiredSignature); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here
@@ -367,41 +468,28 @@ pub(crate) fn process_instruction( | |||
) | |||
} | |||
ConfidentialTransferFeeInstruction::WithdrawWithheldTokensFromMint => { | |||
msg!("ConfidentialTransferInstruction::WithdrawWithheldTokensFromMint"); | |||
#[cfg(all(feature = "zk-ops", feature = "proof-program"))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This removes the featurizing on zk-ops
, so I think it'll fail to build with zk-ops
disabled. I think we might need one more release using the feature off unfortunately, so could you restore that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, sorry I missed this!
} | ||
ConfidentialTransferFeeInstruction::WithdrawWithheldTokensFromAccounts => { | ||
msg!("ConfidentialTransferInstruction::WithdrawWithheldTokensFromAccounts"); | ||
#[cfg(all(feature = "zk-ops", feature = "proof-program"))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, please restore the feature check
Co-authored-by: Jon Cinque <[email protected]>
4c8d552
to
2cb1575
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just one last little nit, then this is good to go!
#[cfg(not(all(feature = "zk-ops", feature = "proof_program")))] | ||
{ | ||
Err(ProgramError::InvalidInstructionData) | ||
) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You'll also need the Error variant if the feature is off
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh sorry I missed it!
#[cfg(not(all(feature = "zk-ops", feature = "proof_program")))] | ||
{ | ||
Err(ProgramError::InvalidInstructionData) | ||
) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You'll also need the error variant if the feature is off
Pull request has been modified.
Problem
The confidential transfer fee extension is not updated for solana 1.16
Summary of changes
The most importants changes in the first, second, and last commits.
b96f57a: Updated the
WithdrawWithheldTokensFromMint
instruction for Solana 1.16 and for it to support context states. This is pretty straightforward except for the part about adding the withheld feeds directly into a destination available balance.The original plan (#4817) was to divide the withheld amount into low and high parts. Transfer amounts and fees in the instruction are divided into low and high bits so that they are easier to decrypt. When the transfer amount is accumulated into a destination account, the transfer amounts are added into the lo and hi pending balance fields. However, for the case of fees, they are merged and added to the single withheld fees field. Similarly, when these withheld fees are harvest into the mint, it is added to a single withheld fee field. If the withheld fees grow large then it could be inefficient for a withdraw withheld authority to decrypt the ciphertext.
We can choose to also break up the withheld fees into lo and hi parts like the pending balance to make it easier for withdraw withheld authority to decrypt the withheld fees in an account for mint. However, I ended up deciding against it because
WithdrawWithheldTokensFromMint
requires aCiphertextCiphertextEqualityProof
. If there are two ciphertexts for withheld fees, then we have to either attach two instances of this zkp or batch them, which would require a new instruction in the proof program.Previously, when the withheld fees in the mint are withdrawn to an account, they were added into the "lo" part of the pending balance of the destination account. This is fine, but a little unnatural. If the fees are already merged, then it should really be added into the available balance. So in this PR, I made the change. Since we are making changes to the available balance, I also added the new decryptable available balance field in the instruction.
e64c9f0: Updated the
WithdrawWithheldTokensFromAccount
instruction for Solana 1.16 and for it to support context states as above.0ed218e: Small PR to unfeaturize the client function for
HarvestWithheldTokensToMint
instruction.dcc8574: Updated the tests for the
WithdrawWithheldTokensFromMint
instruction. I added theConfidentialTokenAccountMeta
helper struct intests/confidential_transfer_fee.rs
, which is a stripped down version ofConfidentialTokensAccountMeta
intests/confidential_transfer.rs
. I can re-use the helper struct fromtests/confidential_transfer.rs
, but I decided to just have a separate helper struct intest/confidential_transfer_fee.rs
that does not deal with fields like memo. The rest of the tests were straightforward.c582a53: Updated the tests for the
WithdrawWithheldTokensFromAccounts
instruction.a00c50e: Added tests that deal with context states for the
WithdrawWithheldTokensFromMint
andWithdrawWithheldTokensFromAccounts
instructions.3a6b3e0: Right now, the instruction
WithdrawWithheldTokensFromMint
could be susceptible to front-running. The zero-knowledge proof that is needed for the instruction depends on the currently withheld amount ciphertext in the mint. If the withheld amount is constantly harvested into the mint, the zkp can be nullified.This PR added
EnableHarvestToMint
andDisableHarvestToMint
, which acts like{Enable,Disable}ConfidentialTransfers
and{Enable,Disable}NonConfidentialTransfers
for harvest. If the harvest fails due to front-running, the harvest authority can disable harvest, withdraw withheld tokens, and then enable harvest.