pWrap is the k256-maintained fork of the Solana Program Token Wrap implementation. It converts an existing SPL Token or Token-2022 mint into a deterministic wrapped representation backed by on-chain escrow.
| Item | Value |
|---|---|
| pWrap program ID | pWrapnbzNPTx9aZPAp3gpxAUrs3H4QQ1GHWMPMbDba2 |
| Devnet | Live; slot 484920383; authority G1kdS4CCCKZFKzupAm9N5ZLMvx5bgfzpUx9xkmt1KxYR |
| Mainnet | Live; slot 440055335; authority EDJwdLWCgUdFMdcxqXNYjvB9EvF6qkAwcwYdwzjgU4TC |
| Testnet | Not deployed |
| ProgramData, each cluster | DJ7bADfr6LxWQsyzRGJXRwieXB4CmkRioTLpMoPvMhW1 |
| Deployed ELF | 436,360 bytes; SHA-256 fb64746885e19cd5a8a1f4f40c8a6dfff8183cc3d8e30b40a120a1d4dee7eb49 |
| K256 fork | https://github.com/quiknode-labs/token-wrap |
| Upstream | https://github.com/solana-program/token-wrap |
| Upstream baseline | 81adb66daa1405eb1568af8b74f5c30924655bd6 |
| IDL | idl.json |
pWrapnbzNPTx9aZPAp3gpxAUrs3H4QQ1GHWMPMbDba2 is the permanent address on both deployed clusters. The matching program-account keypair was used once per cluster for the initial deployment. Every later upgrade targets the literal public address and never replaces it. Program and ProgramData accounts are cluster-local even though their deterministic addresses are the same.
The Devnet program deployment is recorded in DEVNET_DEPLOYMENT.md. The Mainnet deployment is recorded in MAINNET_DEPLOYMENT.md. No K256 Mainnet asset mapping was initialized. Deployment nevertheless makes the permissionless CreateMint instruction available to third parties; the program has no on-chain asset allowlist or global pause.
The upstream TwRapQCDhWkZRrDaHfZGuHxkZ91gHDRkyuzNqeU5MgR address is not used by pWrap. Changing the program ID changes every program-derived wrapped mint, authority, backpointer, canonical pointer, and escrow address.
The program-account and upgrade-authority keypairs are operator key material. They must stay outside this public repository. The program-account keypair is retained as durable identity material, but it cannot recreate a closed program; it is not the fee payer or upgrade authority and is not used for upgrades.
All Rust, IDL, JavaScript, CLI, and PDA derivations remain pinned to the pWrap address above. The supported lifecycle is the completed initial deployment on each live cluster followed only by upgrades of that same address. A replacement program ID is not a pWrap upgrade.
The program must remain upgradeable, so neither deployment with --final nor removal of the upgrade authority is allowed. Any solana program close operation targeting the pWrap Program or ProgramData accounts is forbidden. CloseStuckEscrow is unrelated: it can close only a zero-balance token escrow ATA after validating the documented stuck-escrow conditions; it cannot close the program.
The upgradeable loader does not provide a permission that allows upgrades while cryptographically forbidding closure. A raw upgrade-authority signer can technically upgrade, rotate, finalize, or close the program. Until that authority is transferred to a governance controller that enforces a narrower policy, “never close” is a key-custody and operator invariant. Authority loss makes future upgrades impossible; compromise exposes the program-controlled escrow and issuance logic.
This fork deliberately starts from the latest upstream main, not the older released program snapshot:
- latest upstream program release:
program@v1.0.0at4e4e1d0(2025-09-11); - latest audit listed by upstream: Runtime Verification at
228dc97(2025-10-30); - fork baseline:
81adb66(2026-08-17).
Upstream added SetCanonicalPointer and upgraded core Solana dependencies after the latest listed audit. The pWrap program-ID change also produces a distinct binary. The historical audits are useful lineage, not an audit of the current pWrap binary. Mainnet deployment does not make the binary audited and does not authorize K256 support for any Mainnet asset.
The latest Runtime Verification report leaves acknowledged findings around freeze-authority coordination, loss of an underlying confidential auditor policy, transparent wrap amounts, and partial metadata synchronization. pWrap also remains permissionless and upgradeable. The current existing-asset plan does not claim those general risks are fixed.
pWrap keeps one deterministic relationship between an unwrapped mint and a wrapped mint for a selected token program:
CreateMintcreates the wrapped mint and its backpointer PDA.Wraptransfers unwrapped tokens into the escrow ATA and mints the backed wrapped amount.Unwrapburns wrapped tokens and atomically releases the same underlying amount from escrow.CloseStuckEscrowcloses a zero-balance escrow whose account extensions no longer match a recreated mint.SyncMetadataToToken2022copies supported metadata into a wrapped Token-2022 mint.SyncMetadataToSplTokencopies supported metadata into the wrapped SPL Token mint's Metaplex account.SetCanonicalPointerlets an unwrapped mint authority publish its preferred Token Wrap deployment.
The wrapped mint, mint authority, backpointer, canonical pointer, and escrow addresses are program-derived. Users retain ownership of their token accounts. The wrapper controls escrow release and wrapped issuance through its deployed code, so the program upgrade authority is a real economic authority and must be governed accordingly.
When the wrapped mint uses Token-2022, the default mint customizer initializes:
ConfidentialTransferMintwith automatic account approval;- no confidential-transfer authority;
- no auditor;
MetadataPointercontrolled by the wrapped-mint authority PDA;- decimals and the current freeze-authority address copied once from the unwrapped mint at W creation; later U/W authority changes are not synchronized.
pWrap itself implements public wrap and unwrap. Configure-account, deposit, confidential transfer, apply-pending-balance, and withdraw are Token-2022 operations and use the relevant proof programs. Moving into or out of pWrap escrow is public; the wrapper does not make the boundary transaction confidential.
K256 tests only exact underlying mints that already exist independently of K256. K256 must not create an underlying mint for product or lifecycle testing. Official Circle test USDC on Devnet, mint 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU, is the first selected asset; its pWrap relationship and lifecycle are not yet created or proven. No official Solana Devnet USDT mint has been verified, and native SOL requires a separate canonical-WSOL decision. The permissionless program has no on-chain asset allowlist, so this is a K256 operating contract rather than a restriction on third-party invocation. See DEVNET_EXISTING_ASSET_TEST.md.
Required toolchains are pinned in the repository:
- Rust
1.93.1(rust-toolchain.toml); - Rust nightly
nightly-2026-01-22for the repository test/lint gates (Makefile); - Solana CLI
4.1.0(Cargo.tomlworkspace metadata andMakefile); - pnpm
10.15.1(package.json).
pnpm install --frozen-lockfile
pnpm generate:clients
cargo check --workspace --all-targets --locked
make build-sbf-program
make build-sbf-program-test-metadata-owner
make build-sbf-program-test-transfer-hook
make test-program
cargo test -p spl-token-wrap-cli --bin spl-token-wrap
cargo test -p spl-token-wrap-cli --test runner
pnpm --dir clients/js test
pnpm --dir clients/js buildpnpm generate:clients regenerates idl.json and the JavaScript client from program/idl.ts. The generated client packages retain their upstream-compatible names but are marked private in this fork; no K256 package publication contract exists yet.
Unlike the upstream snapshot, the generated contract and CLI both expose SetCanonicalPointer. The JavaScript test is no longer a no-op: it verifies the pWrap identity, all seven discriminators, the instruction/account codecs, and a canonical-pointer PDA against an independent Solana CLI derivation.
CLI dry runs fail closed: a simulation error returns a nonzero exit and includes the RPC simulation logs instead of producing a success-shaped transaction result.
For Devnet operations, see DEPLOYMENT.md. For Mainnet upgrades, see MAINNET_RUNBOOK.md. The immutable deployment records are DEVNET_DEPLOYMENT.md and MAINNET_DEPLOYMENT.md.
The local checkout uses origin for the k256 fork and upstream for the Solana Program repository. Review upstream changes before merging them; program behavior, IDL, generated clients, audits, and the pWrap address must remain one coherent release.
git fetch upstream --tags
git log --oneline --left-right main...upstream/main
git merge upstream/mainAfter every upstream merge, restore and verify the pWrap program ID, regenerate clients, run the full checks above, and produce a new binary hash and security review scope. Any deployment is a separately approved upgrade of the existing address on one explicitly selected cluster.
| Auditor | Date | Upstream version | Report |
|---|---|---|---|
| Zellic | 2025-05-16 | 75c5529 |
|
| Runtime Verification | 2025-06-11 | dd71fc1 |
|
| Runtime Verification | 2025-10-30 | 228dc97 |
Apache License 2.0. See LICENSE. Upstream history and attribution are preserved by the GitHub fork.