TypeSOLPerformance report2026-10-29
Technical report · Benchmarks

TypeSOL Performance Report

Compute cost and program size of Solana programs compiled from TypeScript, measured against Anchor, native Rust and Pinocchio, and verified on mainnet.

Published
2026-10-29
Measured
2026-10-28
Mainnet run
2026-10-27
Compiler
@typesol/[email protected]
620711c
Compared with
Anchor 1.0.2
Pinocchio 0.10.2 · solana-program 5.1.0
Data
typesol/benchmarks v0.1.1
20 rounds per scenario

Contents

  1. Executive summary
  2. 1Scope and method
  3. 2Compute units
  4. 3Program size
  5. 4Independent programs
  6. 5Mainnet verification
  7. 6Correctness and assurance
  8. 7Limitations and disclosures
  9. AAppendix A · Per-example detail
  10. BAppendix B · Toolchain and reproduction

Executive summary

TypeSOL compiles a subset of TypeScript straight to Solana bytecode, without Rust in between. On identical programs it uses less compute than Anchor on every instruction measured, less than hand-tuned Pinocchio on 9 of 9, and produces the smallest binaries of the four.

  1. 17.9%

    of Anchor's compute units, as the geometric mean over 9 instructions of a counter, a vault and an escrow. Every instruction falls between 4.7% and 31.9%. Pinocchio reaches 22.2%, native Rust 55.4%.

  2. 10.7×

    smaller binaries than Anchor: 46.4 KB for the three programs against 494.8 KB, and 35% smaller than Pinocchio's 71.9 KB.

  3. 26 / 26

    official example instructions cheaper than both Anchor and native Rust. Programs from solana-developers/program-examples, built unmodified, against TypeSOL ports. Lowest of all four on 13.

  4. 61% less

    compute on mainnet than Anchor across the same 4 escrow transactions (56,067 against 142,707 CU). All 16 transactions are public and listed with their Solscan links in section 5.

Table 1. Summary of results. Best value in each row underlined (lowest cost, or most instructions won); TypeSOL in bold.

MeasureTypeSOLPinocchioNative RustAnchor
Compute units, share of Anchorgeometric mean, 9 instructions17.9%22.2%55.4%100.0%
Lowest compute units of the fourof 9 instructions9000
Binary size, three programsKB46.471.9109.4494.8
Official examples, lowest of the fourof 26 instructions131300
Official examples, binary sizeKB, 17 programs228.3270.91,434.02,590.5
Mainnet escrow, total compute units4 transactions each56,06777,883112,239142,707

1Scope and method

The report answers one question: what does a Solana program cost to run and to deploy when it is written in TypeSOL instead of Anchor, native Rust or Pinocchio? It measures compute units per instruction and the size of the deployed program. It does not measure developer time, tooling or ecosystem.

1.1 Programs

Three programs (counter, vault, escrow) are written four times with the same instruction encoding, account layout and checks, so one client drives all four. Seventeen further programs come from solana-developers/program-examples at commit de09019; their Anchor, native and Pinocchio versions are built unmodified and compared with TypeSOL ports of the Anchor versions (section 4).

1.2 Equal outcome before any number

Every implementation receives identical transactions in LiteSVM. A number is reported only when the final account state is identical across all four and the same hostile calls are refused: a stranger signing, an overflow, a withdrawal below rent, a fake maker. Where implementations knowingly differ, the difference is recorded (Appendix A).

1.3 Equal conditions

All four run at the same program address with the same deterministic wallets, so program-derived addresses and bump searches cost the same. Compute units are means over 20 rounds; sizes are those of the deployed .so file.

1.4 Pinned and public

The compiler is installed from npm at a fixed version, with its sources from that version's tag. Every result records its toolchain (Appendix B), and the continuous-integration run of typesol/benchmarks reproduces the figures exactly.

2Compute units

Each instruction runs alone in its transaction. Compute units are what Solana meters and what priority fees are priced against; a lower figure means a cheaper and more schedulable transaction.

TypeSOLPinocchioNative RustAnchor
counterinitialize1,8663,1864,6016,573counterincrement1101138572,323vaultopen1,8853,1854,6136,627vaultdeposit1,3141,3772,8324,355vaultwithdraw3153701,1763,628vaultshut1611679502,024escrowmake3,6056,1799,24013,304escrowtake4,0194,0518,50014,365escrowrefund2,6962,7695,6958,449
Figure 1. Mean compute units per call over 20 rounds in LiteSVM. Bars share one scale. Lower is better.

Table 2. Compute units per instruction. The last two columns give TypeSOL's figure as a share of Anchor's and its difference from Pinocchio's.

InstructionTypeSOLPinocchioNative RustAnchorTypeSOL vs AnchorTypeSOL vs Pinocchio
counterinitialize1,8663,1864,6016,57328.4%−41.4%
counterincrement1101138572,3234.7%−2.7%
vaultopen1,8853,1854,6136,62728.4%−40.8%
vaultdeposit1,3141,3772,8324,35530.2%−4.6%
vaultwithdraw3153701,1763,6288.7%−14.9%
vaultshut1611679502,0248.0%−3.6%
escrowmake3,6056,1799,24013,30427.1%−41.7%
escrowtake4,0194,0518,50014,36528.0%−0.8%
escrowrefund2,6962,7695,6958,44931.9%−2.6%
Geometric mean, share of Anchor17.9%22.2%55.4%100.0%

TypeSOL is the lowest of the four on all 9 instructions. The gap to Anchor is widest on small instructions (counter increment at 4.7%), where Anchor's fixed per-instruction work dominates, and narrowest on instructions that create accounts or call other programs, where shared runtime costs dominate.

3Program size

Deploying a program locks rent in proportion to its size, and larger programs take longer to load. TypeSOL emits C through one shared runtime header, so only what a program uses is linked.

TypeSOLPinocchioNative RustAnchor
counter11.0 KB19.6 KB27.9 KB145.2 KBvault14.1 KB22.9 KB35.0 KB158.9 KBescrow21.3 KB29.4 KB46.5 KB190.7 KB
Figure 2. Size of the built .so in KB (1,024 bytes). Rust programs built with cargo-build-sbf in release mode.

Table 3. Binary size per program, in KB.

Program (KB)TypeSOLPinocchioNative RustAnchorAnchor ÷ TypeSOL
counter11.019.627.9145.213.2×
vault14.122.935.0158.911.3×
escrow21.329.446.5190.79.0×
Total46.471.9109.4494.810.7×

4Independent programs

To rule out benchmarks written in TypeSOL's favour, the same comparison runs on programs TypeSOL did not write: 17 examples from solana-developers/program-examples (de09019, MIT), 26 instructions in total. Each example's observable outcome must match across all four implementations before any of its numbers is reported.

Cheaper than Anchor
26 of 26 instructions
Cheaper than native Rust
26 of 26 instructions
Cheaper than Pinocchio
13 of 26 instructions
Total binary size
TypeSOL 228.3 KB · Pinocchio 270.9 KB · native Rust 1,434.0 KB · Anchor 2,590.5 KB

Reading the Pinocchio column. These native and Pinocchio examples are teaching code. Many omit owner, type, PDA or signer checks that Anchor and TypeSOL make, or take a bump from the client instead of searching for it. Their figures include that difference. Appendix A lists, per example, what each version checks and how it handled the hostile calls.

Table 4. Compute units per instruction, official examples. Labels ending in (tx) cover the whole transaction where the versions split one job differently between client and program. Example names link to Appendix A.

Example · instructionTypeSOLPinocchioNative RustAnchor
basics/account-datacreate_address_info (tx)2,1761,4184,9586,212
basics/checking-accountscheck_accounts1154,3005,2251,686
basics/close-accountcreate_user2,4611,4087,5748,866
basics/close-accountclose_user7123,6594,8293,795
basics/counterincrement742951,0101,469
basics/create-accountcreate_system_account4,0564,1346,7827,873
basics/cross-program-invocationinitialize (tx)1,4751,3703,1894,777
basics/cross-program-invocationpull_lever1,6961,4973,6085,765
basics/favoritesset_favorites (create)6,5663,02116,13016,980
basics/pda-rent-payerinit_rent_vault1,9292,9686,7576,058
basics/pda-rent-payercreate_new_account2,1241,7804,3707,178
basics/processing-instructionsgo_to_park372420808955
basics/program-derived-addressescreate_page_visits2,1651,4093,8807,836
basics/program-derived-addressesincrement_page_visits481479953,452
basics/transfer-soltransfer_sol_with_cpi1,2691,2332,8953,005
basics/transfer-soltransfer_sol_with_program104678381,102
tokens/create-tokencreate_token_mint41,09639,07650,89151,089
tokens/escrowmake_offer19,67420,58133,20635,726
tokens/escrowtake_offer7,04421,60624,99529,235
tokens/escrowrefund_offer4,2718,13712,47715,326
tokens/transfer-tokensmint_token6,48613,1796,87618,635
tokens/transfer-tokenstransfer_tokens8,3677,25913,13123,526
tokens/transfer-tokenstransfer_tokens (new account)24,69218,44734,51146,929
tokens/token-2022/default-account-stateinitialize + update_default_state (tx)8,5199,29215,86815,712
tokens/token-2022/mint-close-authorityinitialize6,3457,06012,92714,169
tokens/token-2022/non-transferableinitialize6,1256,91012,61710,046

5Mainnet verification

The official escrow was deployed to Solana mainnet-beta in all four versions and called with the same mints, amounts and accounts, one instruction per transaction: make an offer and take it, then make a second offer and refund it. All 16 transactions succeeded between 13:13:35 and 13:13:54 UTC on 2026-10-27, in slots 462,083,319 to 462,083,407. Every figure below was read back from the chain and can be checked on Solscan.

TypeSOLPinocchioNative RustAnchorPrograms called (ATA, SPL Token)
make_offer, offer 1TypeSOL20,304Pinocchio19,645Native Rust30,698Anchor38,648take_offer, offer 1TypeSOL7,998Pinocchio25,206Native Rust28,612Anchor32,835make_offer, offer 2TypeSOL21,804Pinocchio19,645Native Rust35,198Anchor47,648refund_offer, offer 2TypeSOL5,961Pinocchio13,387Native Rust17,731Anchor23,576
Figure 3. Compute units of each mainnet transaction. The solid part is the escrow program itself; the hatched part is the programs it called, as their own log lines report.

Table 5. Transaction ledger, 2026-10-27. Each row is one confirmed mainnet transaction; the line beneath it is its Solscan page. ATA: Associated Token Account program; Token: SPL Token program.

ImplementationCompute unitsEscrow program¹Called programs (logged)CPIsSlotTime (UTC)
make_offer, offer 1
TypeSOL20,3046,719ATA 13,480 · Token 1053462,083,31913:13:35
https://solscan.io/tx/32PVva77dT1rSWrMWX2sHTMPZiwztdEZYtpANaxrsuJxPcd3hnV6pDgJJaV4LkL3bX6ALDoHMNF8fjngtodYHBS1
Pinocchio19,6456,051ATA 13,518 · Token 763462,083,38713:13:50
https://solscan.io/tx/528BdMTrnLWauSXVh2vaFfy4XwKFpbyt95hQ6w3fwjtpkT85RPkRhGydunAizNDRqTTLPxcEVMrdcDvRer4H9LRE
Native Rust30,69817,043ATA 13,510 · Token 1453462,083,36513:13:45
https://solscan.io/tx/4MQgt75MvojaAkfxnvrE2yJWabGpE8bsZhNq2CeGJxHZg6uD6A64Kv71JmrsgiGnaEovvv8K34DYL49owLjhs4QJ
Anchor38,64825,033ATA 13,510 · Token 1053462,083,34213:13:40
https://solscan.io/tx/9T1ZY9JaSMb1GMqv1i22AuZuJQN6B5XcgqeDv5tGqEm5Uox3MBTdXsECt59GwcXkFG9QKgXJyqndTEzpSXhbAVM
take_offer, offer 1
TypeSOL7,9987,670Token 3283462,083,32413:13:36
https://solscan.io/tx/49EQwgnKShFdsAs37AEzYmv6tLY8DipcCjmRgqwj4fVTFEgVVWdEXw5AvuEufL5ymJYs4T4hVFdkENW9XK9een5m
Pinocchio25,20610,161ATA 14,775 · Token 2705462,083,39213:13:51
https://solscan.io/tx/21MGkXpKRe4c7EeA1hC6JHevsk78xUdbcWmyqG47EbLeCNKSMTzTjkJQqtydnQmV8uHPmr6bJHnvQmmQTSZB7Am2
Native Rust28,61228,203Token 4093462,083,37113:13:46
https://solscan.io/tx/B1hu1EL4Y5vWhBVWdyZEpzRNJb8kd6G9CgN7KtyNNGpQ84o9dfn1sdy9Z1UCHECNtp24Mw8bEH2iYz2YADdEUjx
Anchor32,83532,507Token 3283462,083,34813:13:41
https://solscan.io/tx/3ZLuQQz7Bx5YdgmFXpVQWHn5kyc8v39jr2BnfofH6sqenzfJpAdVm4h38uYcHwYygnfso92kJe7HRHeASsABoKPQ
make_offer, offer 2
TypeSOL21,8046,719ATA 14,980 · Token 1053462,083,33013:13:37
https://solscan.io/tx/xuu9KXbZvzGDpTEEcDE9LYvBqmPen81y6ty92e6crRxT8m4Mc4XyxhjWHbjVNsr9RE3QY4M1j1Sw9cH7PRMKKuc
Pinocchio19,6456,051ATA 13,518 · Token 763462,083,39813:13:52
https://solscan.io/tx/LLzS13AJrqACGoT1VHZN278ij39pNkttb1Z4Wh2AYXknWxwjaiaiMeD7WZomjP6TBv18RHfQHUfogQzApvXr2mC
Native Rust35,19821,543ATA 13,510 · Token 1453462,083,37713:13:47
https://solscan.io/tx/4xiKfzyccVatef1T52tZ3VAJwcx5R7iWgHWezBzZ3p2WpvoLzMp1PSUgr7x3sspE53mDE5JaghaNPKuUohVgPuwc
Anchor47,64831,033ATA 16,510 · Token 1053462,083,35413:13:42
https://solscan.io/tx/4mxW8D5zpY8t4fL8JRbvhp6ejU6CUvB3iWmFjACipzexW6tZfFeatfnEnDTX3Y97BxsvAftoX9eQauiVu84xrLxh
refund_offer, offer 2
TypeSOL5,9615,738Token 2232462,083,33613:13:39
https://solscan.io/tx/4kY7s3y95Lrd2WGCWGPWW3zFBVtEKH6EskdscuYmRCRRgPt2rJTZ1CmZMGUUkHs7aai9AygEiTSUG23EMUrFr7rg
Pinocchio13,38713,193Token 1942462,083,40713:13:54
https://solscan.io/tx/QUXWwdbKRcT6WhZvSe4U8nxr4GAMaPNV6pZ1fwrC28kRxdJm7HKXVr2DFRuKD9bEzoS6hFdiA2rLr1mQWyrN3oz
Native Rust17,73117,468Token 2632462,083,38313:13:48
https://solscan.io/tx/5zj7E4c61j1JzUsUPC1fNs9ECFLVmCug9rsdYsVLn7YD1RSxdbAJUQDam1BX3epTzW6ed2uFGwTiNhwaYo7vqdwm
Anchor23,57623,353Token 2232462,083,36013:13:43
https://solscan.io/tx/5Kjwnq5tN8mzj5s67VGxSry4kRzZk6HLdgXW65FyTvpUeC1D7aQoDGTwzrA7kqyYEvV9y9znnZmLaqU98zFrJJo4

¹ Total compute units minus those the called programs log for themselves. It includes the cost of making each CPI and of System program calls, which do not log their own consumption.

Most of make_offer is the Associated Token Account program creating the vault, about 13,500 CU in every version. It searches for the vault address's bump itself at 1,500 CU a try, so its cost moves between offers: TypeSOL's second make_offer cost 1,500 more than the first while the escrow program's own part stayed at 6,719 CU both times. Anchor's and native Rust's own parts grew between the two offers, by 6,000 and 4,500 CU. The Pinocchio version takes the offer's bump from the client instead of searching for it, and its take_offer also calls the Associated Token Account program.

The escrow program's own part, summed over the four transactions: TypeSOL 26,846 CU, Pinocchio 35,456, native Rust 84,257, Anchor 111,926.

These programs were built with an earlier TypeSOL than the one measured in sections 2 to 4, so their figures differ from LiteSVM's. The deployed programs match their builds byte for byte (typesol verify for TypeSOL).

Table 6. The four deployed programs.

6Correctness and assurance

Lower cost is worth nothing if the program is wrong. The figures above sit on the following test base, all in the public typesol/typesol repository.

556 tests
Programs compiled and run in LiteSVM, compile-time diagnostics, generated clients against real programs, and on-chain tooling.
Differential testing
The same transactions go to TypeSOL and to Anchor twins of each example. Outcomes, account contents and balances must match after every step.
Fuzzing
Arithmetic at every integer width is checked against BigInt. Random honest and hostile actions are checked against a reference model, and token supply and SOL are conserved.
46 ported programs
Every program in solana-developers/program-examples is ported: 30 run the original tests' flows unchanged, and 16 have documented differences.
Anchor compatibility
Anchor's IDL format, discriminators and error codes, so existing Anchor and Codama clients work with TypeSOL programs.
Verifiable builds
typesol verify rebuilds a program and compares it byte for byte with what is deployed.

7Limitations and disclosures

Authorship
This report is prepared by the TypeSOL project, which has an interest in its results. For that reason every input, script and result is public and reproducible (Appendix B).
Security audit
TypeSOL has had internal security reviews but no external audit yet. Programs holding significant value should wait for one.
What is measured
Compute units and binary size measure cost. They do not measure developer time, documentation or ecosystem maturity, where Anchor has a lead of years.
Environment
LiteSVM uses the mainnet cost model, but programs reached through CPI (SPL Token, Token Metadata) are whichever version is loaded. Token Metadata is taken from mainnet-beta and its hash recorded.
Teaching code
The official native and Pinocchio examples do less checking than Anchor and TypeSOL in several places (section 4, Appendix A).

APer-example detail

For each official example: compute units and binary size per version, the hostile or edge calls the benchmark makes and whether each version refused or accepted them, and how the versions differ. Accepted calls are in italics; not every acceptance is a flaw (a second set_favorites is an update in Anchor's version).

A.1account-data basics/account-data

Instruction (compute units)TypeSOLPinocchioNative RustAnchor
create_address_info (tx)2,1761,4184,9586,212
Binary size (KB)11.312.782.5131.3

Measured as the whole creating transaction; every variant creates the keypair account with a CPI inside the instruction. Account layouts differ (Anchor and TypeSOL: Borsh Strings in 171 bytes; native: Borsh sized to the data; Pinocchio: fixed 51-byte record with 16-byte fields); the decoded fields are compared. The native version does not check the system program account; Pinocchio caps each string at 16 bytes.

A.2checking-accounts basics/checking-accounts

Instruction (compute units)TypeSOLPinocchioNative RustAnchor
check_accounts1154,3005,2251,686
Binary size (KB)2.913.628.761.8

Hostile and edge calls

CallTypeSOLPinocchioNative RustAnchor
account to change owned by the System Programrefusedrefusedrefusedrefused
account to create already holds lamportsacceptedrefusedrefusedaccepted

The native and Pinocchio versions also log both account addresses and require the account to create to hold no lamports; Anchor (and the TypeSOL port) leave that account unchecked. The native version does not check that the payer signed.

A.3close-account basics/close-account

Instruction (compute units)TypeSOLPinocchioNative RustAnchor
create_user2,4611,4087,5748,866
close_user7123,6594,8293,795
Binary size (KB)14.315.087.5151.9

Hostile and edge calls

CallTypeSOLPinocchioNative RustAnchor
stranger closes another user's accountrefusedrefusedrefusedrefused

The native and Pinocchio versions store only the name (Pinocchio: a fixed 16-byte field, with the bump passed by the client), not the bump and user key Anchor stores; on close they keep the rent of an empty account in it (0 bytes, owned by the System Program) where Anchor and TypeSOL close it entirely. Pinocchio's create_user signs with the bump the client passes and does not search for it (the others derive the canonical bump on chain, a find_program_address of several thousand CU); its close_user does the search. Compared: the stored name, and that the closed account holds no data and is no longer owned by the program.

A.4counter basics/counter

Instruction (compute units)TypeSOLPinocchioNative RustAnchor
increment742951,0101,469
Binary size (KB)8.812.538.4136.4

Hostile and edge calls

CallTypeSOLPinocchioNative RustAnchor
increment past u64::MAXrefusedrefusedrefusedrefused

Only increment is compared: the native and Pinocchio versions have no initialize (the client creates a zeroed 8-byte account), while Anchor's initialize_counter creates the account itself. The native and Pinocchio increment do not check the account's owner or type.

A.5create-account basics/create-account

Instruction (compute units)TypeSOLPinocchioNative RustAnchor
create_system_account4,0564,1346,7827,873
Binary size (KB)13.512.081.5127.3

The native and Pinocchio versions size the account by the instruction data length and do not decode it. Anchor, native and TypeSOL log the new address as base58 (Anchor and native via to_string).

A.6cross-program-invocation basics/cross-program-invocation

Instruction (compute units)TypeSOLPinocchioNative RustAnchor
initialize (tx)1,4751,3703,1894,777
pull_lever1,6961,4973,6085,765
Binary size (KB)15.922.3135.7250.2

Hostile and edge calls

CallTypeSOLPinocchioNative RustAnchor
pull_lever on an account lever does not ownrefusedrefusedrefusedrefused

Binary sizes are hand + lever. initialize (tx) is the whole transaction that creates and initializes the power account: every variant creates it inside lever's initialize (CreateAccount CPI). pull_lever includes the CPI into lever. Anchor and TypeSOL hand check that power is a lever PowerStatus account before the CPI; the native and Pinocchio hand forward any account (lever's own data parsing and the runtime's owner rule still stop a foreign account).

A.7favorites basics/favorites

Instruction (compute units)TypeSOLPinocchioNative RustAnchor
set_favorites (create)6,5663,02116,13016,980
Binary size (KB)23.423.6101.4160.2

Hostile and edge calls

CallTypeSOLPinocchioNative RustAnchor
a second set_favorites (update)acceptedrefusedrefusedaccepted
set_favorites by another signer on this user's PDArefusedrefusedrefusedrefused

Only the first set_favorites, which creates the user's PDA, is compared: the native and Pinocchio versions refuse to write an existing account (Anchor and TypeSOL overwrite it), and they have no update. The variants store different layouts: Anchor and TypeSOL 344 bytes with Borsh strings, native exactly the Borsh size, Pinocchio 80 bytes of fixed fields (color 8 bytes, 4 hobbies of 16) with the bump passed by the client (no on-chain bump search); the PDA seed is "favorites" in Anchor/TypeSOL and "favorite" in native/Pinocchio. Pinocchio does not check that the instruction data fits its layout beyond the copy.

A.8pda-rent-payer basics/pda-rent-payer

Instruction (compute units)TypeSOLPinocchioNative RustAnchor
init_rent_vault1,9292,9686,7576,058
create_new_account2,1241,7804,3707,178
Binary size (KB)8.815.877.1115.6

Hostile and edge calls

CallTypeSOLPinocchioNative RustAnchor
create_new_account without the new account's signaturerefusedacceptedacceptedrefused

The same observable result by different means: Anchor and TypeSOL fund a System-owned vault with a System Transfer and pay for each new account with a signed System CreateAccount CPI; native and Pinocchio create the vault as a program-owned account (CreateAccount CPI) and move lamports out of it directly (no CPI) in create_new_account. The vault's owner is therefore not compared (its balance is). Native searches the bump on chain in both instructions; Pinocchio takes it from the client and checks it with create_program_address; Anchor and TypeSOL find the canonical bump on chain while checking the vault. The native and Pinocchio create_new_account do not require the new account's signature.

A.9processing-instructions basics/processing-instructions

Instruction (compute units)TypeSOLPinocchioNative RustAnchor
go_to_park372420808955
Binary size (KB)4.014.046.682.8

The Pinocchio version takes the name as a fixed 8-byte field (shorter names are zero-padded) instead of a Borsh String.

A.10program-derived-addresses basics/program-derived-addresses

Instruction (compute units)TypeSOLPinocchioNative RustAnchor
create_page_visits2,1651,4093,8807,836
increment_page_visits481479953,452
Binary size (KB)10.512.971.8141.9

Hostile and edge calls

CallTypeSOLPinocchioNative RustAnchor
increment_page_visits naming another userrefusedacceptedacceptedrefused

Anchor and TypeSOL find the canonical bump on chain at creation, store it, and check the PDA against the user and the stored bump on every increment; the native and Pinocchio versions sign with the bump the client sends, do not store it (their account stays zeroed until the first increment), and their increment checks neither the address nor the owner of the account. The stored bump is therefore not compared, only the visit count.

A.11transfer-sol basics/transfer-sol

Instruction (compute units)TypeSOLPinocchioNative RustAnchor
transfer_sol_with_cpi1,2691,2332,8953,005
transfer_sol_with_program104678381,102
Binary size (KB)4.712.569.0107.3

Hostile and edge calls

CallTypeSOLPinocchioNative RustAnchor
transfer_sol_with_program without the paying account's signaturerefusedrefusedrefusedrefused

Anchor and TypeSOL also check that the recipient is a System-owned account and that the paying account of transfer_sol_with_program is owned by the program; the native and Pinocchio versions check only the signature and leave ownership to the runtime.

A.12create-token tokens/create-token

Instruction (compute units)TypeSOLPinocchioNative RustAnchor
create_token_mint41,09639,07650,89151,089
Binary size (KB)15.917.199.0171.0

Each call creates a mint and its Metaplex metadata account; most of the cost is the Token Metadata CPI. The native and Pinocchio versions also set the mint authority as freeze authority (Anchor and TypeSOL leave it unset); the freeze authority is not part of the compared outcome. The native and Pinocchio versions do not check the metadata PDA, the program accounts or the mint authority themselves (the token and metadata programs do); the native one uses InitializeMint with the rent sysvar, the others InitializeMint2.

A.13escrow tokens/escrow

Instruction (compute units)TypeSOLPinocchioNative RustAnchor
make_offer19,67420,58133,20635,726
take_offer7,04421,60624,99529,235
refund_offer4,2718,13712,47715,326
Binary size (KB)32.025.1120.4244.5

Hostile and edge calls

CallTypeSOLPinocchioNative RustAnchor
take naming the taker as the makerrefusedrefusedrefusedrefused
refund signed by someone other than the makerrefusedrefusedrefusedrefused

The taker's mint A and the maker's mint B token accounts exist before take_offer, so no implementation creates them there. Anchor and TypeSOL move tokens with TransferChecked and check the mints' token program and the offer's account type; the native and Pinocchio versions use Transfer, read the offer without an owner or type check, and send the vault's rent to the taker and the offer's to the payer (Anchor: both to the maker). Pinocchio takes the offer's bump from the client instead of searching for it.

A.14transfer-tokens tokens/transfer-tokens

Instruction (compute units)TypeSOLPinocchioNative RustAnchor
mint_token6,48613,1796,87618,635
transfer_tokens8,3677,25913,13123,526
transfer_tokens (new account)24,69218,44734,51146,929
Binary size (KB)28.813.9117.7238.3

Hostile and edge calls

CallTypeSOLPinocchioNative RustAnchor
transfer above the balancerefusedrefusedrefusedrefused
transfer from another wallet's accountrefusedrefusedrefusedrefused

create_token is not compared: the Pinocchio version creates only the mint, without the Metaplex metadata account the others create (the metadata is not part of the compared outcome). mint_token and transfer_tokens go to existing associated token accounts; 'transfer_tokens (new account)' sends to wallets whose associated token account the instruction creates. Anchor and TypeSOL take whole-token amounts and scale them by the mint's decimals; the native and Pinocchio versions take base units. The native and Pinocchio versions leave the associated-token-account and owner checks to the token programs. Anchor, TypeSOL and native skip the associated token account program for an existing account; Pinocchio calls CreateIdempotent every time.

A.15default-account-state tokens/token-2022/default-account-state

Instruction (compute units)TypeSOLPinocchioNative RustAnchor
initialize + update_default_state (tx)8,5199,29215,86815,712
Binary size (KB)11.316.294.6157.1

One transaction per variant reaching the same mint: Anchor and TypeSOL send initialize (create, DefaultAccountState Frozen, InitializeMint2) and update_default_state(Initialized) as two instructions of that transaction; the native and Pinocchio versions do the same four steps in their single instruction. Anchor and TypeSOL check the mint's freeze authority in update_default_state; the native and Pinocchio versions leave the checks to Token-2022.

A.16mint-close-authority tokens/token-2022/mint-close-authority

Instruction (compute units)TypeSOLPinocchioNative RustAnchor
initialize6,3457,06012,92714,169
Binary size (KB)13.116.091.0194.1

Only initialize is compared: the native and Pinocchio versions have no close instruction. Their mint also gets the mint authority as freeze authority, where Anchor and TypeSOL set none (the freeze authority is left out of the compared outcome); Anchor and TypeSOL also read the extension back after creating the mint and check its close authority.

A.17non-transferable tokens/token-2022/non-transferable

Instruction (compute units)TypeSOLPinocchioNative RustAnchor
initialize6,1256,91012,61710,046
Binary size (KB)9.115.791.1118.8

The native and Pinocchio versions take the mint authority as an account and do not check the payer's or the token program's identity (the CPIs fail on a wrong one); Anchor and TypeSOL check the token and system programs by address.

BToolchain and reproduction

TypeSOL
@typesol/[email protected] · commit 620711c5d494da5f78ea52223329bb14991e3aa0
Anchor
anchor-lang 1.0.2
Pinocchio
0.10.2
Native Rust
solana-program 5.1.0
Build
solana-cargo-build-sbf 3.1.10, platform-tools v1.52, rustc 1.89.0
Runner
Node.js v25.9.0, LiteSVM
Token Metadata
sha256 31f0a627dba051a938de650464e55cc5397a4be0fd496929c1f9cf02fe5e9011
Official examples
https://github.com/solana-developers/program-examples/tree/de09019

Reproduce

git clone https://github.com/typesol/benchmarks
cd benchmarks
npm ci && bash scripts/setup.sh
node run.ts                                   # Tables 2 and 3
bash official/build.sh && node official.ts    # Table 4, Appendix A

The mainnet run is mainnet-escrow.ts in the same repository. Running it again spends real SOL; the transactions in Table 5 can instead be checked directly on Solscan.

End of report