Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
126 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
6aaeeb0
fix(drive-abci)!: record and check the nullifiers of shielding transi…
QuantumExplorer Sep 26, 2026
de7ba02
Merge remote-tracking branch 'origin/v4.2-dev' into claude/strange-el…
QuantumExplorer Sep 26, 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
6017d9e
Merge #4760 (token shielded pools) into the nullifier recording branch
shumkov Sep 26, 2026
1caa49e
test(drive-abci): a batch does need the is_allowed check on this branch
shumkov Sep 26, 2026
8d13671
test(drive-abci): prove each shield's bundle against the funder that …
shumkov Sep 26, 2026
37fe378
Merge the is_allowed fixture correction from #4760
shumkov Sep 26, 2026
39f4916
test(drive): drop four evonode reward-ratio tests that test only them…
shumkov Sep 26, 2026
8216d2f
test(drive-abci): put the shield repeat back on the block path
shumkov Sep 26, 2026
92e2d55
test(drive-abci): pin the boundary the below-range arm reports
shumkov Sep 27, 2026
93fa8d6
test(drive-abci): keep platform_version last and drop a shadowing import
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
b1c7bb1
test(drive-abci): drop an assertion that could not fire
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
bcc91b6
Merge the token shielded pools branch into the nullifier recording br…
shumkov Sep 29, 2026
cc34e92
Merge v5.0-dev into the nullifier recording branch
shumkov Oct 3, 2026
9b176c5
fix(dpp): preserve shielded token purchase fees
shumkov Oct 4, 2026
ee44bba
fix!: cover identity shield admission estimates
shumkov Oct 4, 2026
d20652a
chore: merge v5.0-dev into shielding nullifier fix
shumkov Oct 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 52 additions & 42 deletions book/src/fees/shielded-fees.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,14 @@ is funded by a consumed asset lock with no metering anchor, so it pays the flat
is the on-wire action count of the bundle (a single-output, spends-disabled Orchard bundle
pads to 2 actions, so the minimum is the 2-action fee).

Every action of an outputs-only bundle still reveals a nullifier, that of a dummy spend,
which becomes the new note's `rho`. From protocol version 14 the entry transitions record
those nullifiers and refuse one repeated inside the bundle or already recorded
(`NullifierAlreadySpentError`), as the spends do, so every revealed nullifier is recorded
once. `Shield` and `ShieldFromIdentity` meter the nullifier writes like the rest of their
storage; `ShieldFromAssetLock`'s flat fee already prices a note and a nullifier write per
action (see [Per-Action Storage Fee](#3-per-action-storage-fee)).

Comment thread
shumkov marked this conversation as resolved.
### Shield

`Shield` is charged like any other address-funded transition: GroveDB **meters** the
Expand Down Expand Up @@ -135,8 +143,8 @@ compute` funding gate is `validate_fees_of_event`.
`ShieldFromIdentity` (protocol version 14) is `Shield` with the identity balance as
the funding side. It is identity-signed (TRANSFER key, identity nonce) like
`IdentityCreditTransferToAddresses`, and carries the same outputs-only Orchard bundle
as `Shield`. The fee model is identical to `Shield`'s: GroveDB meters the note
inserts and the identity balance and nonce writes, and the shielded compute fee is
as `Shield`. The fee model is identical to `Shield`'s: GroveDB meters the note and
nullifier inserts and the identity balance and nonce writes, and the shielded compute fee is
added as `additional_fixed_fee_cost`:

```
Expand All @@ -146,13 +154,18 @@ identity_balance_after = identity_balance_before - amount - fee

`user_fee_increase` applies to the metered processing portion. The stateless
floor requires `identity_balance >= amount + compute_shielded_identity_balance_write_fee`,
the conservative complete fee (`compute_minimum_shielded_fee` plus the flat
`SHIELDED_IDENTITY_BALANCE_WRITE_STORAGE_BYTES` identity-write component at the
storage rate: 20 effective bytes covering the nonce and balance rewrites, which add no
storage but replace 883 bytes of Merk path for a measured 466,760 credits of
processing, folded into one flat figure with headroom like the other shielded
components), so an identity that could not pay the complete fee is refused before the
Orchard proof is verified. The authoritative gate is the identity-paid fee
the conservative complete admission estimate: `compute_minimum_shielded_fee`, plus
PV14's versioned `shielded_identity_action_write_storage_bytes` (400 effective
bytes per action) and `shielded_identity_balance_write_storage_bytes` (500 flat
bytes), each priced at the storage rate. The allowances cover the complete
execution-event estimate: note/nullifier writes at the estimator's depth 16,
identity nonce/balance writes at its maximum-element depth, and the signature
and state-read validation context. They are admission reserves, not physical
payload sizes or changes to the actual metered charge. For two actions the
base wallet estimate is `114,140,000 + (2 × 400 + 500) × 27,400 = 149,760,000`
credits. Historical tables preserve the preceding zero per-action and 20-byte
flat allowance. An identity that could not pay the
complete fee is therefore refused before the Orchard proof is verified. The authoritative gate is the identity-paid fee
validation of the execution event (`Paid`), which rejects with
`IdentityInsufficientBalanceError`. The identity balance and the pool total are
both terms of the block conservation equation, so the converter emits no
Expand Down Expand Up @@ -225,11 +238,10 @@ min_fee = proof_verification_fee + num_actions × (processing_fee + storage_fee)
### 1. Proof Verification Fee (per bundle)

A single Halo 2 ZK proof covers the entire bundle regardless of action count.
Verifying it is the most expensive operation — benchmarked at approximately
30× the cost of a per-action signature verification. This is a fixed cost per
bundle.
The bundle's base verification work is benchmarked at approximately 5 ms.
This is a fixed cost per bundle.

**Current value:** `100,000,000` credits (100M)
**Protocol version 14 value:** `40,000,000` credits (40M)

### 2. Per-Action Processing Fee

Expand All @@ -241,17 +253,14 @@ batch verification. For a spend-bearing action that marginal work includes:
- Nullifier duplicate check (hash + tree lookup)
- Note commitment insertion into the Sinsemilla-based Merkle tree

Output-only entry transitions (Shield / ShieldFromAssetLock) do no spends or
nullifier checks, but each output action still enlarges the proof and so carries
Output-only entry transitions (Shield / ShieldFromAssetLock / ShieldFromIdentity) do
no spends, but each output action still enlarges the proof and so carries
the same per-action processing charge — this fee tracks the marginal verification
work, not a fixed per-action checklist.
work, not a fixed per-action checklist. From protocol version 14 it also prices the
check of the nullifier each of their actions reveals.

The fee is calibrated at roughly a 4.5:1 ratio against the fixed
proof-verification fee (100M : 22M) rather than the looser ratio used before the
recalibration. (Note the two ratios on this page use different baselines: the
“30×” in §1 is the proof fee relative to a single RedPallas signature
verification, whereas this 4.5:1 is the proof fee relative to the per-action
processing fee.)
At protocol version 14, the proof and per-action fees are versioned independently.
Their numerical ratio is about 1.8:1 (40M : 22M).

**Current value:** `22,000,000` credits (22M)

Expand All @@ -261,33 +270,33 @@ Each action permanently stores data in two places:

| Storage | Bytes | Contents |
|---|---|---|
| BulkAppendTree (commitment tree) | 280 | 32 cmx + 32 rho + 216 encrypted note |
| BulkAppendTree (commitment tree) | 312 | 32 cmx + 32 rho + 32 cv_net + 216 encrypted note |
| Nullifier tree | 32 | nullifier key (value is empty) |
| **Total** | **312** | |
| **Total physical payload** | **344** | |

The storage fee is derived from the platform's existing per-byte storage rates:
Protocol version 14 prices a 550-byte allowance per action, covering the physical
payload and database framing, at the platform's per-byte storage rates:

```
storage_fee_per_action = 312 × (storage_disk_usage_credit_per_byte
storage_fee_per_action = 550 × (storage_disk_usage_credit_per_byte
+ storage_processing_credit_per_byte)
= 312 × (27,000 + 400)
= 312 × 27,400
= 8,548,800
= 550 × (27,000 + 400)
= 550 × 27,400
= 15,070,000
```

This is not a separate constant — it is computed dynamically from the storage fee
version, ensuring shielded storage costs stay consistent with transparent storage
costs as fee parameters evolve.
The byte allowance is versioned. Its per-byte rates come from the storage fee
version, so the fee tracks changes to those rates.

## Fee Table

Combining all three components:
Combining all three components at protocol version 14:

| Actions | Proof Fee | Processing | Storage | Total Minimum Fee |
|---|---|---|---|---|
| 2 | 100,000,000 | 44,000,000 | 17,097,600 | **161,097,600** |
| 3 | 100,000,000 | 66,000,000 | 25,646,400 | **191,646,400** |
| 4 | 100,000,000 | 88,000,000 | 34,195,200 | **222,195,200** |
| 2 | 40,000,000 | 44,000,000 | 30,140,000 | **114,140,000** |
| 3 | 40,000,000 | 66,000,000 | 45,210,000 | **151,210,000** |
| 4 | 40,000,000 | 88,000,000 | 60,280,000 | **188,280,000** |

Note: The Orchard protocol requires a minimum of 2 actions per bundle for privacy
(even a single-input single-output transfer produces 2 actions with a dummy padding
Expand All @@ -300,13 +309,13 @@ add a flat component on top of this base:
- **`Unshield` adds the output-address write cost**: a flat
`unshield_address_storage_fee = 222 × per_byte_rate = 222 × 27,400 = 6,082,800` credits,
independent of action count. So the 2-action Unshield fee is
`161,097,600 + 6,082,800 = 167,180,400` credits (and likewise `+6,082,800` at every action
`114,140,000 + 6,082,800 = 120,222,800` credits (and likewise `+6,082,800` at every action
count). See the [Fee Extraction](#fee-extraction-by-transition-type) Unshield row for why this
component exists.
- **`ShieldedWithdrawal` adds the Core withdrawal-document storage cost**: a flat
`withdrawal_document_storage_fee = 4100 × per_byte_rate = 4100 × 27,400 = 112,340,000` credits,
independent of action count. So the 2-action ShieldedWithdrawal fee is
`161,097,600 + 112,340,000 = 273,437,600` credits (and likewise `+112,340,000` at every action
`114,140,000 + 112,340,000 = 226,480,000` credits (and likewise `+112,340,000` at every action
count). See the [Fee Extraction](#fee-extraction-by-transition-type) ShieldedWithdrawal row for
why this component exists.
- **`IdentityTopUpFromShieldedPool` adds the identity balance write cost**: a flat
Expand Down Expand Up @@ -360,8 +369,9 @@ pub struct DriveAbciValidationConstants {
pub minimum_pool_notes_for_outgoing: u64,
pub shielded_anchor_retention_blocks: u64,
pub shielded_anchor_pruning_interval: u64,
pub shielded_proof_verification_fee: u64, // 100_000_000
pub shielded_proof_verification_fee: u64, // 40_000_000 at protocol 14
pub shielded_per_action_processing_fee: u64, // 22_000_000
pub shielded_storage_bytes_per_action: u64, // 550 at protocol 14
pub shielded_implicit_fee_cap: u64, // 20_000_000_000 (0.2 DASH)
}
```
Expand All @@ -370,15 +380,15 @@ The `shielded_implicit_fee_cap` bounds the surplus that a `ShieldFromAssetLock`
implicitly donate to the fee pools when no `surplus_output` is set (see
[Entry-Transition Fees](#entry-transition-fees-shield-shieldfromassetlock-and-shieldfromidentity)).

The storage component is not a separate constant — it is derived at runtime from
The storage component is derived at runtime from
`fee_version.storage.storage_disk_usage_credit_per_byte` and
`fee_version.storage.storage_processing_credit_per_byte`, multiplied by the
constant `SHIELDED_STORAGE_BYTES_PER_ACTION = 312`.
versioned `shielded_storage_bytes_per_action` allowance.

This design means:
- **Proof and processing fees** can be tuned independently via version bumps
- **Storage fees** automatically track changes to the platform-wide storage rates
- No "magic number" for storage cost exists in the version constants
- **Storage allowances** can be calibrated independently of the per-byte rates

## How Fees Flow After Validation

Expand Down
45 changes: 37 additions & 8 deletions packages/rs-dpp/src/shielded/compute_minimum_shielded_fee/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ mod v0;

use crate::fee::Credits;
use crate::shielded::{
SHIELDED_IDENTITY_BALANCE_WRITE_STORAGE_BYTES, SHIELDED_IDENTITY_TOP_UP_BALANCE_STORAGE_BYTES,
SHIELDED_TOKEN_BALANCE_INSERT_STORAGE_BYTES,
SHIELDED_IDENTITY_TOP_UP_BALANCE_STORAGE_BYTES, SHIELDED_TOKEN_BALANCE_INSERT_STORAGE_BYTES,
SHIELDED_TOKEN_PURCHASE_OWNER_BALANCE_STORAGE_BYTES,
};
use crate::ProtocolError;
use platform_version::version::PlatformVersion;
Expand Down Expand Up @@ -140,11 +140,11 @@ pub fn compute_shielded_unshield_fee(
}
}

/// Computes the conservative **admission floor** (in credits) of a shielded transition that also
/// writes an identity balance (`ShieldFromIdentity`): [`compute_minimum_shielded_fee`] plus the
/// flat identity-write component (`SHIELDED_IDENTITY_BALANCE_WRITE_STORAGE_BYTES` effective bytes
/// at the per-byte storage rate: the nonce and balance rewrites' replace-only tree work, folded
/// into one flat figure like the other shielded components).
/// Computes the conservative **admission floor** (in credits) for `ShieldFromIdentity`:
/// [`compute_minimum_shielded_fee`] plus the versioned per-action and flat
/// identity-write allowances, priced at the per-byte storage rate. The allowances
/// cover the complete execution-event admission estimate, including the estimated
/// note/nullifier and identity writes and the validation context.
///
/// The transition's authoritative fee is metered at execution; this floor stands in for it where
/// state is not yet available, so that an identity that could not pay the complete fee is refused
Expand Down Expand Up @@ -300,8 +300,37 @@ pub fn compute_token_purchase_from_shielded_pool_fee(
compute_token_pool_paid_shielded_fee(
token_actions,
fee_actions,
SHIELDED_IDENTITY_BALANCE_WRITE_STORAGE_BYTES
SHIELDED_TOKEN_PURCHASE_OWNER_BALANCE_STORAGE_BYTES
.saturating_add(SHIELDED_IDENTITY_TOP_UP_BALANCE_STORAGE_BYTES),
platform_version,
)
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn should_preserve_token_purchase_fee_when_identity_shield_floor_changes() {
let platform_version = PlatformVersion::latest();
for (token_actions, fee_actions) in [(2, 2), (3, 4), (16, 16)] {
let historical_fee = compute_token_pool_paid_shielded_fee(
token_actions,
fee_actions,
28,
platform_version,
)
.expect("historical token purchase fee");
assert_eq!(
compute_token_purchase_from_shielded_pool_fee(
token_actions,
fee_actions,
platform_version,
)
.expect("token purchase fee"),
historical_fee,
"identity shielding must not change the token purchase allowance"
);
}
}
}
Loading
Loading