Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions clients/js/src/generated/instructions/confidentialTransfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,12 @@ import { getAccountMetaFactory, type ResolvedAccount } from '../shared';
import {
getDecryptableBalanceDecoder,
getDecryptableBalanceEncoder,
getEncryptedBalanceDecoder,
getEncryptedBalanceEncoder,
type DecryptableBalance,
type DecryptableBalanceArgs,
type EncryptedBalance,
type EncryptedBalanceArgs,
} from '../types';

export const CONFIDENTIAL_TRANSFER_DISCRIMINATOR = 27;
Expand Down Expand Up @@ -90,6 +94,16 @@ export type ConfidentialTransferInstructionData = {
confidentialTransferDiscriminator: number;
/** The new source decryptable balance if the transfer succeeds. */
newSourceDecryptableAvailableBalance: DecryptableBalance;
/**
* The low 16 bits of the transfer amount encrypted under the auditor
* ElGamal public key.
*/
transferAmountAuditorCiphertextLo: EncryptedBalance;
/**
* The high 32 bits of the transfer amount encrypted under the auditor
* ElGamal public key.
*/
transferAmountAuditorCiphertextHi: EncryptedBalance;
/**
* Relative location of the
* `ProofInstruction::VerifyCiphertextCommitmentEquality` instruction
Expand All @@ -115,6 +129,16 @@ export type ConfidentialTransferInstructionData = {
export type ConfidentialTransferInstructionDataArgs = {
/** The new source decryptable balance if the transfer succeeds. */
newSourceDecryptableAvailableBalance: DecryptableBalanceArgs;
/**
* The low 16 bits of the transfer amount encrypted under the auditor
* ElGamal public key.
*/
transferAmountAuditorCiphertextLo: EncryptedBalanceArgs;
/**
* The high 32 bits of the transfer amount encrypted under the auditor
* ElGamal public key.
*/
transferAmountAuditorCiphertextHi: EncryptedBalanceArgs;
/**
* Relative location of the
* `ProofInstruction::VerifyCiphertextCommitmentEquality` instruction
Expand Down Expand Up @@ -143,6 +167,8 @@ export function getConfidentialTransferInstructionDataEncoder(): FixedSizeEncode
['discriminator', getU8Encoder()],
['confidentialTransferDiscriminator', getU8Encoder()],
['newSourceDecryptableAvailableBalance', getDecryptableBalanceEncoder()],
['transferAmountAuditorCiphertextLo', getEncryptedBalanceEncoder()],
['transferAmountAuditorCiphertextHi', getEncryptedBalanceEncoder()],
['equalityProofInstructionOffset', getI8Encoder()],
['ciphertextValidityProofInstructionOffset', getI8Encoder()],
['rangeProofInstructionOffset', getI8Encoder()],
Expand All @@ -160,6 +186,8 @@ export function getConfidentialTransferInstructionDataDecoder(): FixedSizeDecode
['discriminator', getU8Decoder()],
['confidentialTransferDiscriminator', getU8Decoder()],
['newSourceDecryptableAvailableBalance', getDecryptableBalanceDecoder()],
['transferAmountAuditorCiphertextLo', getEncryptedBalanceDecoder()],
['transferAmountAuditorCiphertextHi', getEncryptedBalanceDecoder()],
['equalityProofInstructionOffset', getI8Decoder()],
['ciphertextValidityProofInstructionOffset', getI8Decoder()],
['rangeProofInstructionOffset', getI8Decoder()],
Expand Down Expand Up @@ -207,6 +235,8 @@ export type ConfidentialTransferInput<
/** The source account's owner/delegate or its multisignature account. */
authority: Address<TAccountAuthority> | TransactionSigner<TAccountAuthority>;
newSourceDecryptableAvailableBalance: ConfidentialTransferInstructionDataArgs['newSourceDecryptableAvailableBalance'];
transferAmountAuditorCiphertextLo: ConfidentialTransferInstructionDataArgs['transferAmountAuditorCiphertextLo'];
transferAmountAuditorCiphertextHi: ConfidentialTransferInstructionDataArgs['transferAmountAuditorCiphertextHi'];
equalityProofInstructionOffset: ConfidentialTransferInstructionDataArgs['equalityProofInstructionOffset'];
ciphertextValidityProofInstructionOffset: ConfidentialTransferInstructionDataArgs['ciphertextValidityProofInstructionOffset'];
rangeProofInstructionOffset: ConfidentialTransferInstructionDataArgs['rangeProofInstructionOffset'];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { address, generateKeyPairSigner } from '@solana/kit';
import test from 'ava';
import { getConfidentialTransferInstruction, parseConfidentialTransferInstruction } from '../../../src';

const SOURCE_AUDITOR_CIPHERTEXT_LO = new Uint8Array(64).fill(0xab);
const SOURCE_AUDITOR_CIPHERTEXT_HI = new Uint8Array(64).fill(0xcd);
const NEW_SOURCE_DECRYPTABLE_BALANCE = new Uint8Array(36).fill(0xef);

test('it encodes the auditor ciphertext fields into the Transfer instruction data', async t => {
const [sourceToken, mint, destinationToken, authority] = await Promise.all([
generateKeyPairSigner(),
generateKeyPairSigner(),
generateKeyPairSigner(),
generateKeyPairSigner(),
]);

const instruction = getConfidentialTransferInstruction({
sourceToken: sourceToken.address,
mint: mint.address,
destinationToken: destinationToken.address,
instructionsSysvar: address('Sysvar1nstructions1111111111111111111111111'),
authority,
newSourceDecryptableAvailableBalance: NEW_SOURCE_DECRYPTABLE_BALANCE,
transferAmountAuditorCiphertextLo: SOURCE_AUDITOR_CIPHERTEXT_LO,
transferAmountAuditorCiphertextHi: SOURCE_AUDITOR_CIPHERTEXT_HI,
equalityProofInstructionOffset: 1,
ciphertextValidityProofInstructionOffset: 2,
rangeProofInstructionOffset: 3,
});

const parsed = parseConfidentialTransferInstruction(instruction);

t.deepEqual(parsed.data.transferAmountAuditorCiphertextLo, SOURCE_AUDITOR_CIPHERTEXT_LO);
t.deepEqual(parsed.data.transferAmountAuditorCiphertextHi, SOURCE_AUDITOR_CIPHERTEXT_HI);
t.deepEqual(parsed.data.newSourceDecryptableAvailableBalance, NEW_SOURCE_DECRYPTABLE_BALANCE);
t.is(parsed.data.equalityProofInstructionOffset, 1);
t.is(parsed.data.ciphertextValidityProofInstructionOffset, 2);
t.is(parsed.data.rangeProofInstructionOffset, 3);
});

test('it encodes the auditor ciphertexts at the documented byte offsets', async t => {
const [sourceToken, mint, destinationToken, authority] = await Promise.all([
generateKeyPairSigner(),
generateKeyPairSigner(),
generateKeyPairSigner(),
generateKeyPairSigner(),
]);

const instruction = getConfidentialTransferInstruction({
sourceToken: sourceToken.address,
mint: mint.address,
destinationToken: destinationToken.address,
instructionsSysvar: address('Sysvar1nstructions1111111111111111111111111'),
authority,
newSourceDecryptableAvailableBalance: NEW_SOURCE_DECRYPTABLE_BALANCE,
transferAmountAuditorCiphertextLo: SOURCE_AUDITOR_CIPHERTEXT_LO,
transferAmountAuditorCiphertextHi: SOURCE_AUDITOR_CIPHERTEXT_HI,
equalityProofInstructionOffset: 0,
ciphertextValidityProofInstructionOffset: 0,
rangeProofInstructionOffset: 0,
});

// Data layout: 1 byte outer disc + 1 byte inner disc + 36 bytes AE balance
// = 38 bytes before the lo ciphertext, 102 bytes before the hi ciphertext.
t.deepEqual(instruction.data.slice(38, 102), SOURCE_AUDITOR_CIPHERTEXT_LO);
t.deepEqual(instruction.data.slice(102, 166), SOURCE_AUDITOR_CIPHERTEXT_HI);
});
24 changes: 24 additions & 0 deletions interface/idl.json
Original file line number Diff line number Diff line change
Expand Up @@ -4002,6 +4002,30 @@
"name": "decryptableBalance"
}
},
{
"kind": "instructionArgumentNode",
"name": "transferAmountAuditorCiphertextLo",
"docs": [
"The low 16 bits of the transfer amount encrypted under the auditor",
"ElGamal public key."
],
"type": {
"kind": "definedTypeLinkNode",
"name": "encryptedBalance"
}
},
{
"kind": "instructionArgumentNode",
"name": "transferAmountAuditorCiphertextHi",
"docs": [
"The high 32 bits of the transfer amount encrypted under the auditor",
"ElGamal public key."
],
"type": {
"kind": "definedTypeLinkNode",
"name": "encryptedBalance"
}
},
{
"kind": "instructionArgumentNode",
"name": "equalityProofInstructionOffset",
Expand Down