Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
134 commits
Select commit Hold shift + click to select a range
64d5905
feat(platform)!: token shielded pools
QuantumExplorer Sep 15, 2026
c040457
fix(dpp): append the token pool state error as the last StateError va…
QuantumExplorer Sep 15, 2026
150ce15
feat(dpp): require a pooled token to disable freeze and confiscation …
QuantumExplorer Sep 15, 2026
8f47d59
feat(platform): mint, burn, claim and purchase into token shielded pools
QuantumExplorer Sep 16, 2026
6a85f42
feat(platform)!: gate token shielded pools on protocol version 15 and…
QuantumExplorer Sep 16, 2026
6de6ff3
fix(platform): box the shielded token payment and clone the payment i…
QuantumExplorer Sep 16, 2026
9f636ba
feat(platform)!: identity-less token pool transitions paid from the c…
QuantumExplorer Sep 16, 2026
c46dfd8
fix(drive-abci): drop trailing whitespace rustfmt refused in the pool…
QuantumExplorer Sep 16, 2026
f67c8e4
fix(platform): bind a group burn from the pool to its proposer and ha…
QuantumExplorer Sep 18, 2026
5f53958
fix(platform): reconcile token pools with protocol 14 changes
QuantumExplorer Sep 21, 2026
faf5fa1
fix!: address token shielded pool review findings
QuantumExplorer Sep 21, 2026
a4ee83d
fix(platform)!: pin mint-to-pool destinations, drop pool frozen check…
QuantumExplorer Sep 21, 2026
c1ba639
fix(drive): stop pricing an existing token pool in contract update es…
QuantumExplorer Sep 21, 2026
039ac9f
fix(platform): count a pool purchase in the batch's required balance,…
QuantumExplorer Sep 21, 2026
f539bfa
fix(platform)!: land token shielded pools in protocol version 14
shumkov Sep 22, 2026
cad8634
test(drive-abci): pin the token pool admission and anchor bookkeeping…
shumkov Sep 22, 2026
f963665
chore(platform): tighten the token pool freeze tests, comments and co…
shumkov Sep 22, 2026
7e142c7
fix(drive-abci)!: make the unreleased shielded proof dispatchers exha…
shumkov Sep 22, 2026
52facec
test(drive-abci): pin that a token pool's anchors and nullifiers are …
shumkov Sep 22, 2026
adde743
docs(platform): correct two claims the token pool chapter contradicts…
shumkov Sep 22, 2026
bda2cf0
fix(drive): describe the GroveDB root the same way in both shielded p…
shumkov Sep 22, 2026
efc3983
Merge v4.2-dev into the token shielded pools branch
shumkov Sep 23, 2026
5d9b500
Merge remote-tracking branch 'origin/v4.2-dev' into claude/tokens-shi…
shumkov Sep 23, 2026
4f82752
fix(platform): bind the pool and kind into outputs-only token bundle …
shumkov Sep 23, 2026
4cb0576
fix(platform): correct the outputs-only bundle tag rationale, docs an…
shumkov Sep 23, 2026
2f94a4e
Merge v4.2-dev into the token shielded pools branch
shumkov Sep 24, 2026
1e1a635
Merge v4.2-dev into the token shielded pools branch
shumkov Sep 24, 2026
c3070c7
fix(drive-abci): give the seven document base action constructors the…
shumkov Sep 24, 2026
9b68f9c
Merge remote-tracking branch 'origin/v4.2-dev' into claude/tokens-shi…
shumkov Sep 24, 2026
d7ebc84
style(dpp): drop the stray blank line the manual enum tail moves left…
shumkov Sep 24, 2026
6b1559b
docs(dpp): say what the outputs-only sighash actually binds and what …
shumkov Sep 24, 2026
0658194
fix(platform)!: record and check the dummy nullifiers of outputs-only…
shumkov Sep 24, 2026
ac0661b
feat(platform)!: let a token set how few notes its shielded pool may …
shumkov Sep 24, 2026
b84ed91
test(wallet): pin that two notes sharing a nullifier count once
shumkov Sep 24, 2026
45c9ff8
fix(platform): name what the batch cap protects and stop a group chec…
shumkov Sep 24, 2026
8b4c29f
feat(platform)!: bind the owner into outputs-only token pool bundle s…
shumkov Sep 24, 2026
f1d007e
docs(drive): say at the pool writers that they rely on the caller's d…
shumkov Sep 24, 2026
b73f92f
feat(platform)!: give the credit pool's outputs-only bundles a sighas…
shumkov Sep 24, 2026
604cd1e
Merge remote-tracking branch 'origin/v4.2-dev' into claude/tokens-shi…
shumkov Sep 26, 2026
a07d5d2
fix(drive-abci): report the boundary a transition version actually mi…
shumkov Sep 26, 2026
1caa49e
test(drive-abci): a batch does need the is_allowed check on this branch
shumkov Sep 26, 2026
39f4916
test(drive): drop four evonode reward-ratio tests that test only them…
shumkov Sep 26, 2026
92e2d55
test(drive-abci): pin the boundary the below-range arm reports
shumkov Sep 27, 2026
b55bba7
docs(platform): say why each shipped generation this edits stays iner…
shumkov Sep 27, 2026
b166742
fix(dpp): tell the two sides of an inactive version apart in the message
shumkov Sep 27, 2026
e98f147
test(drive-abci): stop a transition kind from losing its is_allowed p…
shumkov Sep 27, 2026
1793ba1
fix(drive): let a wallet verify a proof of a token pool transition
shumkov Sep 27, 2026
b76c536
test(drive-abci): pin the per-token namespace for a bundle's dummy nu…
shumkov Sep 27, 2026
030ea54
style(drive-abci): wrap the dummy nullifier collection as rustfmt asks
shumkov Sep 27, 2026
ead553e
fix(drive-abci)!: hold a shielded-pool purchase to the pool's anonymi…
shumkov Sep 27, 2026
c66ceb5
fix(dpp): drop a token config validator nothing calls, and the claim …
shumkov Sep 27, 2026
256fe51
fix(drive-abci): answer not-found for a shielded pool the chain does …
shumkov Sep 27, 2026
3341739
fix(dpp)!: refuse a token configuration key its format version does n…
shumkov Sep 27, 2026
4dab688
fix(dpp): show a pool mint or burn's public note on a pending group a…
shumkov Sep 27, 2026
15043e4
Merge the shielded query not-found fix
shumkov Sep 27, 2026
c8370ce
fix(drive-abci)!: bound a token pool mint by the supply's sum-item ce…
shumkov Sep 27, 2026
d44efba
Merge the token pool mint supply-ceiling fix
shumkov Sep 27, 2026
c8cc388
Merge the token configuration strictness and pool note fixes
shumkov Sep 27, 2026
d5dcf15
fix(dpp)!: price a token unshield's balance write as the insert it is
shumkov Sep 27, 2026
bd707cc
docs(drive): put two detached doc paragraphs back on the code they de…
shumkov Sep 27, 2026
eab906b
Merge the unshield new-holder storage fee fix
shumkov Sep 27, 2026
4fb3a18
fix(dpp): decode a shielded payment's byte fields from base64, not ba…
shumkov Sep 27, 2026
3c467a8
Merge v4.2-dev into the token shielded pools branch
shumkov Sep 27, 2026
dfe2d36
fix(wasm-dpp2): name the TokenEvent fields the serializer actually emits
shumkov Sep 27, 2026
b460834
refactor(dpp): give the token shielded pool kinds one home
shumkov Sep 27, 2026
bd8e2ce
Merge the client-facing encoding and field-name fixes
shumkov Sep 27, 2026
65a9bc7
fix(drive): verify a token pool group action's proof while it is stil…
shumkov Sep 27, 2026
d9f638f
fix(dpp): name a batch's shielded pool nullifiers among its mempool i…
shumkov Sep 27, 2026
36ba9e8
Merge the pool group-action proof fixes
shumkov Sep 27, 2026
6951d7c
test(drive-abci): name the credit pool in the encrypted notes tests
shumkov Sep 27, 2026
9b4eaf0
fix(drive): meter a token pool's total-balance read when estimating
shumkov Sep 27, 2026
6e9cc74
docs(platform): record why each in-place edit to a shipped generation…
shumkov Sep 27, 2026
ea57df6
Merge the audit of in-place edits to shipped generations
shumkov Sep 27, 2026
1c159fc
docs(drive): state why two shipped verifier edits cannot move consensus
shumkov Sep 27, 2026
f7f73dc
Merge the pool total read's fee estimate
shumkov Sep 27, 2026
f4896bc
fix(drive-abci): read a token pool's spent nullifiers before verifyin…
shumkov Sep 27, 2026
3954a98
fix(drive-abci): evict a batch from the mempool once its pool note is…
shumkov Sep 27, 2026
25bf31a
refactor(drive-abci): gate every token shielded pool kind from one qu…
shumkov Sep 27, 2026
f8fb7fc
test(drive-abci): pin that an absent token pool reads as nothing spent
shumkov Sep 27, 2026
f187212
Merge the pool nullifier mempool and CheckTx fixes
shumkov Sep 27, 2026
2c322ed
Merge the is_allowed pool-kind conversion and the GroveDB absence tests
shumkov Sep 27, 2026
75a423c
fix(drive-abci): drop a pool-existence read the nullifier check does …
shumkov Sep 27, 2026
d9f5e1f
Merge v4.2-dev into the token shielded pools branch
shumkov Sep 27, 2026
f78f4cb
style(drive-abci): put the credit pool path import in rustfmt order
shumkov Sep 27, 2026
d3f8d91
docs(dpp): correct five comments that justified an edit by an untrue …
shumkov Sep 27, 2026
2477312
docs: stop four comments claiming more than is true or tested
shumkov Sep 27, 2026
b153be9
Revert "test(drive): drop four evonode reward-ratio tests that test o…
shumkov Sep 27, 2026
7da8622
fix(dpp): keep the pool result variants out of the TryInto derive
shumkov Sep 27, 2026
ae86bd0
test(drive-abci): compare the Tokens Merk's own shape, not only its c…
shumkov Sep 27, 2026
1ff727f
refactor(wasm-dpp): report shielded-pool token transitions as unsuppo…
shumkov Sep 27, 2026
e63e1eb
fix(dpp): refuse a fresh mint-to-pool bundle for a group co-signer
shumkov Sep 27, 2026
fe2f812
Merge the legacy wasm-dpp trim
shumkov Sep 27, 2026
0396ed9
test(dpp): decode the whole StateError discriminant, not its first byte
shumkov Sep 27, 2026
1b17e20
fix(drive): make the token example contract fixture decodable again
shumkov Sep 27, 2026
9f64005
test(drive): cover the evonode claim's epoch cap at the drive method
shumkov Sep 27, 2026
24e177a
Merge direct coverage of the epoch-capped evonode reward claim
shumkov Sep 27, 2026
0f73b27
docs(drive-abci): record that the token format predicate is the only …
shumkov Sep 27, 2026
d81e2eb
Merge four small fixes found by reviewing this branch
shumkov Sep 27, 2026
819ac00
fix(dpp): name the discriminator these deserializers actually accept
shumkov Sep 27, 2026
a0c5e40
fix(drive): refuse a token nullifier spend status for a pool the chai…
shumkov Sep 27, 2026
b236bd5
Merge a pool the chain does not have being provably unspent
shumkov Sep 27, 2026
2fcd709
fix(drive-abci): reserve the shielded compute fee in the batch balanc…
shumkov Sep 27, 2026
26104d6
Merge the shielded compute fee into the batch balance pre-check
shumkov Sep 27, 2026
a0837c2
test: make the token shielded pool tests able to fail
shumkov Sep 27, 2026
c8b5cb3
Merge honest replacements for tests that could not fail
shumkov Sep 27, 2026
586c465
docs(book): state the deadline a group burn from a pool inherits
shumkov Sep 27, 2026
3ab258d
fix(dpp)!: refuse an unrecognized token configuration key at format v…
shumkov Sep 28, 2026
b46f473
docs(dpp): say why the payment info accessor clones
shumkov Sep 29, 2026
74822b0
feat(wasm-dpp2): set a token's shielded pool notes threshold at creation
shumkov Sep 29, 2026
0911847
Merge the pool note threshold onto the JavaScript surface
shumkov Sep 29, 2026
3789286
Merge origin/v4.2-dev into the token shielded pools branch
shumkov Sep 29, 2026
3d52fee
fix(dpp): check the balance allowance ordering when the crate is built
shumkov Sep 29, 2026
dde09b1
chore(dapi-grpc): regenerate the python client for the token shielded…
shumkov Sep 29, 2026
be97cbe
docs(book): say what one pool per token costs, not only what it buys
shumkov Sep 30, 2026
e62b2b9
docs(dpp): say the action digest layout is frozen and why versioning …
shumkov Sep 30, 2026
b72e288
refactor(dpp): drop the by-value token payment info getter
shumkov Sep 30, 2026
5ea56c4
Merge the by-value token payment info getter removal
shumkov Sep 30, 2026
5c4fe70
Merge v4.2-dev into the token shielded pools branch
shumkov Sep 30, 2026
4367916
fix(drive-abci): give the derived index value test the shielded payme…
shumkov Oct 1, 2026
575f525
Merge v5.0-dev into the token shielded pools branch
shumkov Oct 1, 2026
98eb774
refactor(platform-version)!: drop the shielded pool notes threshold n…
shumkov Oct 1, 2026
5c911ba
docs(book): say what a token pool's outgoing floor actually is
shumkov Oct 1, 2026
3e2b7ca
docs: correct six comments that state what the code does not do
shumkov Oct 1, 2026
7e941b2
Merge v5.0-dev into the token shielded pools branch
shumkov Oct 1, 2026
8c4301c
fix(drive-abci): judge an insisting gas sponsor before verifying the …
shumkov Oct 1, 2026
ef68eeb
fix(drive)!: stop calling spent pool nullifiers proof of a particular…
shumkov Oct 1, 2026
964ab25
fix(sdk): return an error instead of panicking on an unproved token p…
shumkov Oct 1, 2026
a23d46d
docs(book): explain the outgoing notes threshold and who records a pool
shumkov Oct 1, 2026
68aefab
fix(drive)!: let the batch guard see what a token pool operation writes
shumkov Oct 2, 2026
559e3e6
fix(drive-abci): make a sponsored signer hold what the bundles cost t…
shumkov Oct 2, 2026
93236aa
fix(dpp): raise the batch balance floor by the fee increase the signe…
shumkov Oct 2, 2026
856b790
fix(drive)!: a document proof does not prove which shielded payment p…
shumkov Oct 2, 2026
1173c70
fix(dpp): keep the chosen fee increase out of the floor released vers…
shumkov Oct 2, 2026
cb7386b
fix(dpp): fund the whole of a failed event, not just the bundle that ran
shumkov Oct 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
- [Contested Documents](data-model/contested-documents.md)
- [Identities](data-model/identities.md)
- [Key Budgets and Expiry](data-model/key-limits.md)
- [Token Shielded Pools](data-model/token-shielded-pools.md)

# Contract Keywords

Expand Down
21 changes: 18 additions & 3 deletions book/src/addresses/platform-addresses.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ pub struct ShieldedWithdrawalTransitionV0 {

An asset lock proof from the Core chain funds the shielded pool directly. The recipient is an `OrchardAddress` inside the Orchard bundle. No `PlatformAddress` inputs are needed -- the asset lock proof substitutes for them.

The transition also carries an optional `surplus_output: Option<PlatformAddress>`. When the consumed asset lock exceeds `shield_amount + pool_fee`, the leftover *surplus* is credited to this platform address; if it is unset, the surplus folds into the fee pools (bounded by `shielded_implicit_fee_cap`). See [Entry-Transition Fees](../fees/shielded-fees.md#entry-transition-fees-shield-and-shieldfromassetlock). Unlike the transparent recipients of `Unshield`/`ShieldedWithdrawal` (which are bound through the Orchard sighash `extra_data` above), `surplus_output` is bound through the state transition's **own** `platform_signable` signature -- it sits before the `signature` field, so it is part of the signed payload and cannot be substituted or truncated after signing. The Orchard `extra_data` therefore remains empty for this transition.
The transition also carries an optional `surplus_output: Option<PlatformAddress>`. When the consumed asset lock exceeds `shield_amount + pool_fee`, the leftover *surplus* is credited to this platform address; if it is unset, the surplus folds into the fee pools (bounded by `shielded_implicit_fee_cap`). See [Entry-Transition Fees](../fees/shielded-fees.md#entry-transition-fees-shield-and-shieldfromassetlock). Unlike the transparent recipients of `Unshield`/`ShieldedWithdrawal` (which are bound through the Orchard sighash `extra_data` above), `surplus_output` is bound through the state transition's **own** `platform_signable` signature -- it sits before the `signature` field, so it is part of the signed payload and cannot be substituted or truncated after signing. The Orchard `extra_data` therefore does not carry it; what it binds instead is the asset lock itself (see [below](#the-platform-sighash)).

## The Platform Sighash

Expand All @@ -248,14 +248,29 @@ The `bundle_commitment` is a BLAKE2b-256 hash of the Orchard bundle (per ZIP-244

| Transition | extra_data |
|-----------|------------|
| Shield | empty |
| Shield | `0x84 \|\| SHA-256(input addresses)` |
| Shield From Identity | `0x85 \|\| identity_id` |
| Shielded Transfer | empty |
| Unshield | `output_address.to_bytes() \|\| amount.to_le_bytes()` |
| Shielded Withdrawal | `output_script.as_bytes()` |
| Shield From Asset Lock | empty |
| Shield From Asset Lock | `0x86 \|\| asset lock identifier` |

This binding is critical for security. Without it, an attacker who intercepts an unshield transition could substitute the `output_address` while reusing the valid Orchard proof and signatures. The sighash ensures the Orchard bundle's spend authorization signatures commit to the specific transparent recipient.

The three transitions that only create notes bind something for a different reason. Their bundles have no spends, so they carry no anchor of their own: the proof and the binding signature verify wherever the bundle is submitted. Left unbound, the authorized bundle is a self-contained object anybody could lift out of the mempool and wrap in a transition of their own, paid with their own credits, and any bundle ever published could be replayed. The copier gains nothing — they pay the full amount to the original recipient — but the copy lands a second note with the same commitment and the same nullifier in the credit pool, so only one of the two can ever be spent.

Each of these bundles therefore binds a kind tag and its owner, the thing that funds it and that a third party cannot authorize:

- **Shield**: the SHA-256 of its input addresses, each in its 21-byte encoding (`PlatformAddress::to_bytes`), in the order the transition serializes its inputs. The nonces and contributed amounts are not included: the owner says who funds the bundle, not which transition carries it.
- **Shield From Identity**: the identity id.
- **Shield From Asset Lock**: the asset lock identifier, the double SHA-256 of the locked 36-byte outpoint (the same value an identity created from that lock would get as its id; the tag keeps the two apart). Because a successful shield consumes the whole lock, a bundle bound to it can land at most once, even when its own sender resubmits it. Binding only the transaction id would not do this, and would let the holder of another credit output of the same lock transaction lift the bundle.

The tags `0x84`, `0x85` and `0x86` sit above the state transition type range, next to the token pools' outputs-only tags `0x80`–`0x83`. The binding starts at protocol version 14; at earlier protocol versions `Shield` and `Shield From Asset Lock` bind nothing, and a client building for one of those versions must bind nothing too. Both sides read the choice from the same version field (`dpp.methods.credit_pool_bundle_binding`), so a client that builds with the network's protocol version produces what that network verifies.

`Shield From Asset Lock` also changes its transition version at protocol version 14: version 1 carries the bound bundle and is the only version 14 admits, while version 0, whose bundle binds nothing, is admitted only up to 13. A version 0 presented at 14, such as one still waiting in the mempool when 14 activates, is refused on its version byte when the transition is decoded, before any proof is verified: nothing is charged and its asset lock stays unspent, so its sender can resubmit it as version 1 from the same lock. Checking its unbound bundle against the bound preimage instead would fail the proof and burn the proof-failure penalty from an honest lock.

The binding does not prevent Faerie Gold. The `rho` of an outputs-only note is the nullifier of its bundle's dummy spend, so a sender who builds and signs a fresh bundle reusing the same dummy spend note and `rseed` gets the same commitment and the same nullifier whatever the preimage binds, and a recipient that counts deposits by commitment credits two payments where only one can be spent. Nor does it stop a `Shield` or `Shield From Identity` funder landing their own bundle twice through a new transition, as a client retrying with a fresh nonce does. Neither is closed: that would need the bundles' dummy nullifiers recorded and checked, which the platform does not do.

The same `compute_platform_sighash` function is used on both sides: the client uses it when signing the bundle, and the platform uses it when verifying.

## Trial Decryption and Address Privacy
Expand Down
Loading
Loading