Definition#
struct PoslExtData { // borsh encoding, in this order
kind: u8, // 1 transact, 2 lock, 3 unlock, 4 claim stake, 5 claim volume
recipient: Pubkey,
ext_amount: i64,
fee: u64,
fee_recipient: Pubkey,
mint: Pubkey,
encrypted_output1: Vec<u8>,
encrypted_output2: Vec<u8>,
extra: [u8; 64],
}
extDataHash = sha256(borsh(PoslExtData)) read little-endian, reduced mod r (BN254),
passed big-endian as a public inputWhat each instruction puts in it#
| Instruction | recipient | ext_amount / fee | fee_recipient | outputs | extra |
|---|---|---|---|---|---|
| transact | recipient token account | as given | fee recipient account | both encrypted outputs | credit pubkey | credit blinding |
| lock | default | 0 / fee | fee recipient account | change, locked | zero |
| unlock | default | 0 / fee | fee recipient account | output, empty | zero |
| claim stake, claim volume | default | 0 / 0 | default | reward, empty | zero |
Why it matters#
- The kind stops a proof made for one instruction from being replayed on another.
- Recipient and fee recipient are the accounts actually passed to the instruction. A relayer that swaps either one makes the proof fail (
InvalidProof, tested). - The mint is the pool's, from its state: a proof cannot be moved to another pool.
- Encrypted outputs are bound too, so nobody can replace the copy a wallet needs to find its note.
- Credit key and blinding (transact) are bound, so a relayer cannot redirect the volume credit to itself.
The SDK computes the same value in extDataHash() (sdk/src/posl.mjs) to build the proof.