Now AccountWithMetadata.owner_program_id is set from the account's
actual program_owner when building pre_states for execution.
Programs can now reliably check account ownership:
if let Some(owner) = account.owner_program_id {
assert_eq!(owner, SELF_PROGRAM_ID);
}
Refs #347
Programs can now verify that input accounts are owned by themselves,
preventing spoofing attacks where malicious programs pass fake accounts
with matching data layouts.
Changes:
- Add optional owner_program_id field to AccountWithMetadata
- Add with_owner_program_id() builder method
- Backward compatible: serde(default) = None for existing data
Usage in programs:
if let Some(owner) = account.owner_program_id {
assert_eq!(owner, SELF_PROGRAM_ID, 'account not owned by this program');
}
Fixes#347
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