Smart Contract Reference

zKPnote uses an Anchor-based Solana program (zkpnote) for per-note proof registration and marketplace payments.

Program ID: Ad67RwgTaeh77UQ5oZXAwt3fTvg3u5oNxNfcc3tGJLbc Anchor Version: 0.31.1 Solana Version: 2.x

Instructions

The program has 4 instructions: register_proof, initialize_config, update_config, and execute_sale.

register_proof

Registers a per-note proof on-chain. The proof PDA is derived from the note's SHA-256 hash, establishing first-to-register ownership of the content.

ParameterTypeDescription
note_hash[u8; 32]SHA-256 hash of the note (title + "\n" + content)

Accounts:

AccountTypeDescription
proofPDA ["proof", note_hash]NoteProof account (init)
ownerSigner, mutWallet registering the proof
system_programProgramSystem program

Errors:

  • ZkpnoteError::InvalidHash — hash must be exactly 32 bytes

initialize_config

One-time initialization of the marketplace configuration. The caller becomes the authority (admin).

ParameterTypeDescription
treasuryPubkeyWallet that receives marketplace fees
fee_basis_pointsu16Fee in basis points (200 = 2%)

Accounts:

AccountTypeDescription
configPDA ["config"]Config account (init)
authoritySigner, mutAdmin wallet
system_programProgramSystem program

update_config

Updates the treasury address and/or fee. Authority only.

ParameterTypeDescription
treasuryPubkeyNew treasury address
fee_basis_pointsu16New fee in basis points

Accounts:

AccountTypeDescription
configPDA ["config"]Config account (mut, has_one = authority)
authoritySignerAdmin wallet

execute_sale

Executes a marketplace sale with atomic payment splitting. Sends (100% - fee) to seller and fee to treasury in a single transaction.

ParameterTypeDescription
price_lamportsu64Total price in lamports

Accounts:

AccountTypeDescription
configPDA ["config"]Config account (read-only)
buyerSigner, mutBuyer wallet
sellerAccountInfo, mutSeller wallet
treasuryAccountInfo, mutTreasury (must match config.treasury)
system_programProgramSystem program

Fee Calculation:

fee = price_lamports * fee_basis_points / 10000
seller_amount = price_lamports - fee

Uses checked arithmetic (checked_mul, checked_sub) for overflow protection.

Account Structures

NoteProof (73 bytes + 8 discriminator)

FieldTypeSizeDescription
ownerPubkey32Wallet that registered this proof
note_hash[u8; 32]32SHA-256 hash of the note content
created_ati648Unix timestamp of proof registration
bumpu81PDA bump seed

PDA Seeds: [b"proof", note_hash.as_ref()]

ProgramConfig (67 bytes + 8 discriminator)

FieldTypeSizeDescription
authorityPubkey32Admin wallet
treasuryPubkey32Fee recipient wallet
fee_basis_pointsu162Fee percentage (200 = 2%)
bumpu81PDA bump seed

Error Codes

CodeNameMessage
6000InvalidHashHash must be 32 bytes
6001InvalidTreasuryInvalid treasury account
6002InvalidPricePrice must be greater than zero

Security Properties

  • PDA-based proof uniqueness: NoteProof accounts are derived from ["proof", note_hash], ensuring exactly one proof can exist per unique hash. The first wallet to register a hash owns the proof.
  • Authority enforcement: Config updates require the original authority signer via has_one constraint
  • Treasury validation: execute_sale validates the treasury account matches the on-chain config via constraint
  • Atomic transfers: Payment splitting happens in a single transaction; if either transfer fails, both revert
  • Overflow protection: All fee math uses checked arithmetic