Addresses the following review comment:
- "I think this should be a constructor `AccountId::for_private_pda`.
Consider also removing the existing `impl From<(ProgramId, Seed)> for
AccountId` for public pdas in favor of a `AccountId::for_public_pda`
to have a unified way of constructing pdas"
I replaced `impl From<(&ProgramId, &PdaSeed)> for AccountId` with
`AccountId::for_public_pda(program_id: &ProgramId, seed: &PdaSeed) ->
Self` and replaced the free function `private_pda_account_id(...)`
with `AccountId::for_private_pda(program_id: &ProgramId, seed:
&PdaSeed, npk: &NullifierPublicKey) -> Self`. Both live in an inherent
`impl AccountId` block in nssa/core/src/program.rs next to the PDA
derivation logic. Migrated all call sites across nssa/core,
nssa/src/state.rs, nssa/src/validated_state_diff.rs,
program_methods/guest/src/bin/privacy_preserving_circuit.rs,
programs/amm/core, programs/associated_token_account/core, the example
tail-call binary, and the ATA tutorial doc. Test function names that
referenced the old free function were also renamed
(private_pda_account_id_* to for_private_pda_*).
Introduce the ATA program, which derives deterministic per-token holding
accounts from (owner, token_definition) via SHA256, eliminating the need
to manually create and track holding account IDs.
Program (programs/associated_token_account/):
- Create, Transfer, and Burn instructions with PDA-based authorization
- Deterministic address derivation: SHA256(owner || definition) → seed → AccountId
- Idempotent Create (no-op if ATA already exists)
Wallet CLI (`wallet ata`):
- `address` — derive ATA address locally (no network call)
- `create` — initialize an ATA on-chain
- `send` — transfer tokens from owner's ATA to a recipient
- `burn` — burn tokens from owner's ATA
- `list` — query ATAs across multiple token definitions
Usage:
wallet deploy-program artifacts/program_methods/associated_token_account.bin
wallet ata address --owner <ID> --token-definition <DEF_ID>
wallet ata create --owner Public/<ID> --token-definition <DEF_ID>
wallet ata send --from Public/<ID> --token-definition <DEF_ID> --to <RECIPIENT> --amount 100
wallet ata burn --holder Public/<ID> --token-definition <DEF_ID> --amount 50
wallet ata list --owner <ID> --token-definition <DEF1> <DEF2>
Includes tutorial: docs/LEZ testnet v0.1 tutorials/associated-token-accounts.md