Skip to content

add pinocchio create-token example#599

Merged
dev-jodee merged 5 commits into
solana-foundation:mainfrom
MarkFeder:tokens-create-token-pinocchio
Jul 15, 2026
Merged

add pinocchio create-token example#599
dev-jodee merged 5 commits into
solana-foundation:mainfrom
MarkFeder:tokens-create-token-pinocchio

Conversation

@MarkFeder

Copy link
Copy Markdown
Contributor

Adds a Pinocchio implementation of tokens/create-token, continuing the Pinocchio token-examples lane after transfer-tokens (#596) and escrow (#598).

What it does

Creates an SPL Token mint and attaches an on-chain Metaplex metadata account (name, symbol, URI) — the same flow as the existing anchor and native options.

Notes

  • The Metaplex Token Metadata program has no typed Pinocchio crate, so the CreateMetadataAccountV3 CPI is built by hand (raw InstructionView / cpi::invoke), matching the on-chain wire format.
  • Single instruction, no discriminator byte — the instruction data is Borsh [name, symbol, uri, decimals], identical to the native example's wire format.
  • The bankrun test loads the Metaplex program from a mainnet-dumped token_metadata.so fixture via a postinstall script, the same approach as the anchor example.
  • The mint authority is passed as a non-signer and aliased to the payer (which signs), mirroring the native example.

Files

  • New: tokens/create-token/pinocchio/ (program + bankrun test)
  • Edited: root Cargo.toml (workspace member), README.md (pinocchio link), Cargo.lock

@greptile-apps

greptile-apps Bot commented Jul 8, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds a Pinocchio implementation of the tokens/create-token example, building a program that creates an SPL Token mint and attaches a Metaplex metadata account using a hand-serialized CreateMetadataAccountV3 CPI — since no typed Pinocchio crate exists for Metaplex.

  • Program logic (create_token.rs): Creates the mint via CreateAccount/InitializeMint2, then serializes and invokes the Metaplex CPI manually using InstructionView. Rent is computed with integer arithmetic (ACCOUNT_STORAGE_OVERHEAD + Mint::LEN) rather than Rent::try_minimum_balance to avoid a floating-point BPF instruction that breaks the bankrun VM.
  • Metaplex CPI helpers (util_metaplex.rs, util.rs): Hand-builds the CreateMetadataAccountV3 Borsh payload into a fixed-size stack buffer (METADATA_DATA_MAX = 262 bytes) so the program stays alloc-free. The serialization — discriminator 33, DataV2 struct, is_mutable: false, collection_details: None — matches the mainnet wire format.
  • Test (tests/test.ts): Uses bankrun with a mainnet-dumped Metaplex binary (fetched by prepare.mjs in postinstall), exercising both a fungible token and an NFT. The instruction wire format is positionally identical to the native example even though field names differ across languages.

Confidence Score: 5/5

Safe to merge — the Metaplex CPI wire format, account ordering, and Borsh serialization are all correct, and the bankrun test exercises both the fungible and NFT creation paths against the actual mainnet program binary.

The hand-rolled Metaplex serialization (discriminator 33, DataV2 layout, is_mutable, collection_details) matches the on-chain spec. The alloc-free, fixed-buffer design is sound: every write is bounds-checked before advancing the offset, and the buffer is sized to the exact Metaplex field maxima. No correctness issues were found.

No files require special attention.

Important Files Changed

Filename Overview
tokens/create-token/pinocchio/program/src/instructions/create_token.rs Core instruction handler — account destructuring, rent calculation, mint creation, and Metaplex CPI are all correct. mint_authority appears twice in the invoke accounts list (pos 2 and 4) intentionally since it doubles as update authority.
tokens/create-token/pinocchio/program/src/instructions/util_metaplex.rs Metaplex wire-format builder: discriminator (33), DataV2 fields, and both trailing booleans/options are serialized correctly. METADATA_DATA_MAX = 262 tightly covers the maximum-length case.
tokens/create-token/pinocchio/program/src/instructions/util.rs Borsh read/write helpers are bounds-safe: overflow is prevented by data.get(range).ok_or(...) before any arithmetic, and all paths return InvalidInstructionData on failure.
tokens/create-token/pinocchio/tests/test.ts Bankrun test exercises both fungible and NFT creation paths and verifies owner pubkeys and name presence in the metadata account data.
tokens/create-token/pinocchio/prepare.mjs Dumps the mainnet Metaplex binary via solana program dump; arguments are fully hardcoded so no injection risk. Errors are caught and logged but not fatal.
tokens/create-token/pinocchio/program/src/lib.rs Correct no_std/no_alloc setup with program_entrypoint!, no_allocator!, and nostd_panic_handler! macros.
tokens/create-token/pinocchio/program/Cargo.toml Dependencies delegated to workspace; cdylib + lib crate types are correct for a Solana program that also needs to be tested as a library.

Reviews (6): Last reviewed commit: "create-token pinocchio: move Metaplex he..." | Re-trigger Greptile

Comment thread tokens/create-token/pinocchio/tests/test.ts
@MarkFeder
MarkFeder force-pushed the tokens-create-token-pinocchio branch from e995793 to ac589b7 Compare July 9, 2026 07:38
@MarkFeder

Copy link
Copy Markdown
Contributor Author

@Perelyn-sama @dev-jodee — rebased onto latest main (picks up the ASM sbpf/Solana pin from #625), CI is now fully green. Ready for review whenever you have a chance 🙏

@dev-jodee dev-jodee left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the work, couple of comments !

Comment thread tokens/create-token/pinocchio/prepare.mjs Outdated
Comment thread tokens/create-token/pinocchio/program/src/instructions/mod.rs Outdated
Comment thread tokens/create-token/pinocchio/program/src/instructions/mod.rs Outdated
Comment thread tokens/create-token/pinocchio/program/src/instructions/mod.rs Outdated
Comment thread tokens/create-token/pinocchio/tests/test.ts Outdated
@MarkFeder

Copy link
Copy Markdown
Contributor Author

@dev-jodee thanks for the review! Pushed a commit addressing all five points:

  • prepare.mjs dumps via solana program dump -um instead of mutating the CLI config
  • reuse pinocchio_token::state::Mint::LEN instead of a custom MINT_SIZE
  • CreateTokenArgs moved into create_token.rs; borsh string helpers moved to a util.rs; mod.rs is now just wiring
  • test setup moved into a before() hook so the it blocks actually run

Ready for another look when you have a moment.

@MarkFeder
MarkFeder requested a review from dev-jodee July 13, 2026 19:47

@dev-jodee dev-jodee left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fixes ! just a couple more :)

Comment thread tokens/create-token/pinocchio/program/src/instructions/create_token.rs Outdated
@MarkFeder

Copy link
Copy Markdown
Contributor Author

@dev-jodee thanks for the second pass! Pushed 2027b84:

  • Metaplex cohesion — moved all Metaplex bits (program ID, discriminator, data-size bound, instruction-data builder) into a new util_metaplex.rs; create_token.rs is now just the account/CPI flow.
  • Rent — replied inline: your suggestion is what I'd default to, but try_minimum_balance compiles an f64 branch that solana-bankrun's VM rejects (verified it flips the tests red/green), and pinocchio 0.10.2 doesn't expose the rent fields for an integer path. Kept pinocchio's own ACCOUNT_STORAGE_OVERHEAD/DEFAULT_LAMPORTS_PER_BYTE constants (same lamport value). Glad to switch if you'd prefer Rent::get() and dropping that assertion.
  • log! CU — good call, noted; kept them here since it's an example and clarity wins.

Rebuilt with cargo build-sbf + bankrun (2 passing), fmt/clippy clean.

@MarkFeder
MarkFeder requested a review from dev-jodee July 14, 2026 19:09
@dev-jodee

Copy link
Copy Markdown
Collaborator

lgtm, just realized commits aren't signed :') so can't merge it, can you re-sign the commits ? will merge after thanks

MarkFeder and others added 5 commits July 15, 2026 11:40
- prepare.mjs: dump program via 'solana program dump -um' instead of
  mutating the user's Solana CLI config
- reuse pinocchio_token Mint::LEN instead of a hand-rolled MINT_SIZE const
- move CreateTokenArgs into create_token.rs (ix-specific) and the borsh
  string helpers into a util module; slim mod.rs to module wiring
- tests: run async bankrun setup in a before() hook so the it() blocks
  actually register (a describe callback runs synchronously)
…g tests

The tests were previously registered inside an async describe callback, so
mocha ran 0 of them and CI passed without ever executing the program. With
the before() hook they actually run — and surfaced a real failure:

  Program log: Instruction: CreateToken
  failed: unsupported BPF instruction

Root cause: Rent::try_minimum_balance() takes a floating-point path for the
exemption threshold (an f64), which the current platform-tools lower to a
float instruction the solana-bankrun VM rejects. Compute the rent-exempt
minimum with integer math using pinocchio's default rent constants instead
(DEFAULT_LAMPORTS_PER_BYTE already folds in the 2-year threshold).

While here, make the program alloc-free: build the Metaplex instruction data
in a fixed stack buffer and switch to program_entrypoint! + no_allocator!,
matching the other pinocchio examples.

Verified with cargo build-sbf (Solana 4.1.1 / platform-tools v1.54) + the
bankrun test: both cases pass.
Address review feedback: the Metaplex Token Metadata program ID, the
CreateMetadataAccountV3 discriminator, the metadata-data size bound, and
the instruction-data builder now live in util_metaplex.rs, keeping
create_token.rs focused on the account/CPI flow.
@MarkFeder
MarkFeder force-pushed the tokens-create-token-pinocchio branch from 2027b84 to b83e6b8 Compare July 15, 2026 09:40
@MarkFeder

Copy link
Copy Markdown
Contributor Author

@dev-jodee the branch is now re-signed — all commits show as Verified on GitHub. Ready to merge whenever you get a chance. Thanks!

@dev-jodee

Copy link
Copy Markdown
Collaborator

thanks for the work @MarkFeder

@dev-jodee
dev-jodee merged commit d293362 into solana-foundation:main Jul 15, 2026
25 checks passed
MarkFeder added a commit to MarkFeder/program-examples that referenced this pull request Jul 15, 2026
Move the async bankrun setup out of the `describe` callback and into a
`before` hook so Mocha collects the `it` block (an async `describe` body
registers tests after the suite is already collected, so nothing ran).

With the test now executing, replace `Rent::try_minimum_balance` with the
integer rent formula: its floating-point exemption-threshold path emits an
opcode the bankrun VM rejects ("unsupported BPF instruction"). Matches the
create-token example (solana-foundation#599).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants