---
id: TIP-1064
title: StablecoinDEX Order Storage Credits
description: Adds per-order reusable storage accounting to the StablecoinDEX, using TIP-1060 precompile storage gas tokens to charge storage creation costs to the user who expands order-attributable DEX state.
authors: Dankrad Feist
status: Draft
related: TIP-1000, TIP-1058, TIP-1060
protocolVersion: T5
---

# TIP-1064: StablecoinDEX Order Storage Credits

## Abstract

This TIP adds user-level reusable storage accounting for StablecoinDEX order storage. When a DEX operation deletes physical order-record storage clearly attributable to one order, the DEX credits that order's maker with storage credits. When a maker later actively creates physical storage for their own order, the DEX consumes that maker's credits before allowing TIP-1060 precompile storage gas tokens to offset the TIP-1000 storage creation cost.

This gives makers credit for order-record slots they previously freed, while still relying on TIP-1060 for the underlying precompile-level gas token balance.

## Motivation

TIP-1060 gives the StablecoinDEX a precompile-level storage gas token balance. That prevents repeated DEX storage churn from being charged as net-new state growth, but it does not decide which user should receive the benefit when one user deletes storage and another user later creates storage.

The StablecoinDEX exposes user-driven storage creation and deletion through order placement, order filling, order cancellation, client order IDs, balances, and orderbook maintenance. Some of this storage is clearly attributable to a single order and its maker. Other storage, such as tick-level records, bitmap words, orderbook records, and internal accounting fields, can be shared by many orders or users.

Without user-level accounting, an operation that creates new order state could consume storage gas tokens minted by another user's order deletion. However, attributing shared accounting storage to the user whose operation happens to clear it can create windfall credits. For example, the user who removes the last order at a tick should not receive an extra user credit merely because the DEX can clear a shared tick-level record or bitmap word.

This TIP creates the user-level accounting suggested by TIP-1058 for the StablecoinDEX only.

---

# Specification

## Terminology

- **DEX storage credit**: A protocol-maintained `uint64` counter associated with one user address in the StablecoinDEX.
- **Reusable order storage**: StablecoinDEX-owned physical storage slots in an encoded order record that are non-empty and clearly attributable to that order for storage creation and deletion accounting.
- **Storage owner**: The user address credited when a reusable order storage slot is deleted, and whose credits may be consumed when they actively create storage for their own order.
- **TIP-1060 token**: A precompile-level storage gas token minted or consumed by the StablecoinDEX under TIP-1060.

## State

The StablecoinDEX MUST maintain:

```text
dex_storage_credits: mapping(address user => uint64 credits)
```

The `dex_storage_credits` mapping is StablecoinDEX precompile state. Creating or updating a user's `dex_storage_credits` counter, including the first creation of that counter's backing storage slot, is subject to normal TIP-1000 state gas and TIP-1060 rules. The StablecoinDEX MUST consume a TIP-1060 storage token to change the `dex_storage_credits[U]` mapping entry from `0` to `1`. Inversely it will obtain a TIP-1060 storage credit when `dex_storage_credits[U]` returns to its zero value. One of user `U`'s storage credits is effectively stored in the slot occupied by the `dex_storage_credits[U]` value.

If `dex_storage_credits[user] == type(uint64).max`, additional credits for that user MUST saturate at `type(uint64).max`.

## Reusable Order Storage

The following StablecoinDEX storage is reusable order storage:

1. Non-empty physical storage slots of active order records keyed by `orderId`.

Reusable order storage is counted at the physical slot level, not as a flat one-credit-per-order abstraction. An order record contributes one credit for each non-empty encoded `Order` slot attributed to that order. Clearing one field in a packed order slot only credits storage if the entire physical slot changes from nonzero to zero. Regular tail orders do not occupy the final packed order slot, so they are worth one less credit than the full encoded order size. If a later order appends behind a tail order, the predecessor's `next` pointer makes that final slot nonzero; that additional non-empty slot belongs to the predecessor order and therefore credits the predecessor order's maker if it is later cleared. Its creation is paid by the appending operation, not by debiting the predecessor maker's existing DEX storage credits.

All other StablecoinDEX storage is non-creditable accounting storage under this TIP. This includes tick-level records, tick bitmap words, orderbook records, user internal balance slots, aggregate liquidity fields, book-key arrays, counters other than `dex_storage_credits`, and any other field that is not clearly attributable to one order.

Only storage owned by the StablecoinDEX is covered. TIP-20 token balances, allowances, policy state, EOA state, and ordinary smart-contract storage are outside this TIP's scope.

## Storage Owner Attribution

For each reusable order storage slot, the storage owner is:

| Storage | Storage owner |
|---------|---------------|
| Non-empty physical slot in an order record keyed by `orderId` | `order.maker` for that `orderId` |

When a single operation touches storage owned by multiple orders, each reusable order storage slot deletion MUST be attributed independently using this table. The transaction sender, taker, canceller, or order being newly placed is not necessarily the storage owner for every slot touched by the operation. For example, appending Bob's order behind Alice's tail order writes Alice's `next` pointer under Alice's order ID, so that slot belongs to Alice for later deletion credit. However, creation of linked-list metadata caused by another order is paid by the operation that creates or mutates it, and MUST NOT debit the predecessor maker's existing DEX storage credits. If Alice's now-non-tail order is later cancelled or filled, deletion of that slot credits Alice.

Storage that is not listed in this table MUST NOT mint, consume, credit, or debit DEX storage credits for any user. If a storage slot cannot be attributed to one order, it is non-creditable accounting storage even if the operation that creates or deletes it was initiated by a known user.

## Crediting Deleted Storage

When a StablecoinDEX operation changes reusable order storage owned by user `U` from nonzero to zero:

1. Apply the normal DEX state transition.
2. The TIP-1060 precompile automatically credits the StablecoinDEX with a storage token.
3. Increment `dex_storage_credits[U]` by one, saturating at `type(uint64).max`.

Deleting a reusable order storage slot credits exactly one DEX storage credit to the storage owner, regardless of the slot key, deleted value, transaction sender, or call path.

Deleting non-creditable accounting storage MUST NOT credit any user's `dex_storage_credits` balance. This rule applies even when the storage deletion is caused by removing the last order at a tick, clearing the last bit in a bitmap word, removing an orderbook, zeroing an internal balance, or updating any other DEX accounting field.

## Charging Created Storage

When a StablecoinDEX operation changes reusable order storage for a newly placed order by its maker `U` from zero to nonzero:

1. If `dex_storage_credits[U] > 0`:
   - Decrement `dex_storage_credits[U]` by one.
   - Execute the storage creation in TIP-1060 consume-token mode so one available StablecoinDEX TIP-1060 token is consumed instead of charging the TIP-1000 storage creation component.
2. Otherwise:
   - Leave `dex_storage_credits[U]` unchanged.
   - Execute the storage creation in TIP-1060 preserve-token mode so the transaction pays the full TIP-1000-mandated storage creation cost and the StablecoinDEX TIP-1060 token balance is not consumed.

The DEX storage credit debit, TIP-1060 mode selection, TIP-1060 token debit if any, and DEX storage write MUST be atomic. If the operation reverts, all credit and token changes made in the same execution scope MUST revert according to normal EVM revert semantics.

If an operation creates linked-list metadata in an existing order record owned by another maker, such as setting a predecessor order's `next` pointer while appending a new order, the existing order maker's `dex_storage_credits` balance MUST NOT be decremented. The storage creation is paid by the operation that caused it under the normal TIP-1000 and TIP-1060 rules. If that metadata is later cleared, the existing order maker receives the deletion credit because the slot belongs to their order record.

## Query Interface

The StablecoinDEX interface MUST expose:

```solidity
/// @notice Returns the number of reusable order storage credits owned by a user.
/// @param user The user whose DEX storage credit balance is queried.
/// @return credits The number of storage credits available to that user.
function storageCredits(address user) external view returns (uint64 credits);
```

This function is read-only and does not expose any ability to transfer, mint, burn, or set storage credits.

## Compatibility

This TIP changes gas costs for StablecoinDEX calls that create reusable order storage. Creating an order-record slot for a maker's own order may cost less because one of that maker's credits can consume a StablecoinDEX TIP-1060 token. If the maker has no credits, the transaction still pays the TIP-1000 storage creation cost for the new order-record slot.

Existing DEX functional behavior, matching behavior, order priority, balances, and events are unchanged except for the new `storageCredits(address)` view.

---

# Invariants

The following invariants MUST hold after every successful StablecoinDEX state transition and across every revert boundary:

1. **Global solvency**: the StablecoinDEX's TIP-1060 token balance MUST cover all outstanding user credits:

   ```text
   TIP1060.balanceOf(STABLECOIN_DEX_ADDRESS) >= sum(storageCredits(user) for all users)
   ```

   Equivalently, every outstanding DEX storage credit is backed by at least one StablecoinDEX-owned TIP-1060 token. This is the primary safety invariant: user-level credits MUST never promise more discounted reusable order storage creations than the DEX can fund with its TIP-1060 token balance.

2. **Per-slot conservation**: for every reusable order storage slot owned by user `U`, a nonzero-to-zero transition credits exactly one `storageCredits(U)` unit, unless `storageCredits(U)` is already saturated at `type(uint64).max`; a zero-to-nonzero transition for storage actively created by `U` for their own order debits exactly one `storageCredits(U)` unit if and only if that unit is used to consume exactly one StablecoinDEX TIP-1060 token. Linked-list metadata creation in another maker's existing order record does not debit that maker's credits.

3. **Maker attribution isolation**: deletion credits are applied only to the maker that owns the reusable order storage slot being deleted, and creation debits are applied only when a maker actively creates storage for their own order. When an order's reusable storage is cleared, the order's maker receives the resulting credits regardless of who submitted the transaction, matched the order, filled it, cancelled it, or otherwise caused the clearing path to run. DEX storage credits are not transferable, cannot be spent by any other user, and are not affected by transaction sender, taker, canceller, or call path except through the slot ownership rules in this TIP.

4. **Non-creditable storage exclusion**: storage that is not reusable order storage, including tick-level records, tick bitmap words, orderbook records, user internal balance slots, aggregate liquidity fields, book-key arrays, and counters other than `dex_storage_credits`, MUST NOT mint, consume, credit, or debit DEX storage credits.

5. **Atomicity and revert consistency**: the reusable storage write, any `storageCredits` update, and any TIP-1060 token consume/credit effect are one atomic state transition. If the execution scope reverts, all of these effects revert together; after the revert, all invariants above must still hold.
