Skip to content

docs(tip-1028): rewrite for clarity#3782

Closed
0xrusowsky wants to merge 11 commits intotip/1028from
rus/tip-1028-rewrite
Closed

docs(tip-1028): rewrite for clarity#3782
0xrusowsky wants to merge 11 commits intotip/1028from
rus/tip-1028-rewrite

Conversation

@0xrusowsky
Copy link
Copy Markdown
Contributor

rewrite for clarity

@0xrusowsky 0xrusowsky force-pushed the rus/tip-1028-rewrite branch 2 times, most recently from cc7e14b to 58eccc3 Compare April 30, 2026 17:49
@0xrusowsky 0xrusowsky force-pushed the rus/tip-1028-rewrite branch from 58eccc3 to 5e77486 Compare April 30, 2026 17:50
Comment thread tips/tip-1028.md Outdated
Comment on lines +15 to +23
This TIP introduces receiver-controlled inbound policies for TIP-20 tokens. Today, only token issuers (via TIP-403 / TIP-1015) decide who may move a token; receivers cannot independently filter what arrives in their balance. This TIP adds:

The escrow precompile stores only one keyed amount for each open blocked receipt. The rest of the receipt identity — receipt version, requested recipient, block reason, transfer-vs-mint kind, memo, timestamp, and nonce — is authenticated by the receipt witness and emitted in the blocked event. Claims may unwind to the receiver or reroute elsewhere; claim-to-receiver is an unwind, while reroutes are new spends. This TIP applies only to TIP-20 precompile flows; ordinary ERC-20 contracts remain out of scope.
1. **Token sets** — a new TIP-403 primitive that lets any address declare which TIP-20 token addresses may credit it.
2. **Address-level receive policies** — a per-address configuration on the TIP-403 registry that filters inbound TIP-20 credits by originator and by token, with an optional dedicated recovery contract.
3. **An escrow precompile** — a new precompile that records a fine-grained receipt for each blocked inbound TIP-20 transfer, and lets the receiver (or its designated recovery contract) claim or reroute the funds later.

A blocked inbound never reverts: the funds are credited to a reserved `ESCROW_ADDRESS` inside the TIP-20 token, one receipt bucket is recorded by the escrow precompile, and a blocked-inbound event is emitted that authenticates the receipt witness. Pre-existing token-level (issuer-side) failures continue to revert exactly as today.

This TIP applies only to TIP-20 precompile flows; ordinary ERC-20 contracts deployed as userland code remain out of scope.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont think we need to mention token sets, other types or other types in the abstract. A high level summary should do for this section IMO. Something like:

Suggested change
This TIP introduces receiver-controlled inbound policies for TIP-20 tokens. Today, only token issuers (via TIP-403 / TIP-1015) decide who may move a token; receivers cannot independently filter what arrives in their balance. This TIP adds:
The escrow precompile stores only one keyed amount for each open blocked receipt. The rest of the receipt identity — receipt version, requested recipient, block reason, transfer-vs-mint kind, memo, timestamp, and nonce — is authenticated by the receipt witness and emitted in the blocked event. Claims may unwind to the receiver or reroute elsewhere; claim-to-receiver is an unwind, while reroutes are new spends. This TIP applies only to TIP-20 precompile flows; ordinary ERC-20 contracts remain out of scope.
1. **Token sets** — a new TIP-403 primitive that lets any address declare which TIP-20 token addresses may credit it.
2. **Address-level receive policies** — a per-address configuration on the TIP-403 registry that filters inbound TIP-20 credits by originator and by token, with an optional dedicated recovery contract.
3. **An escrow precompile** — a new precompile that records a fine-grained receipt for each blocked inbound TIP-20 transfer, and lets the receiver (or its designated recovery contract) claim or reroute the funds later.
A blocked inbound never reverts: the funds are credited to a reserved `ESCROW_ADDRESS` inside the TIP-20 token, one receipt bucket is recorded by the escrow precompile, and a blocked-inbound event is emitted that authenticates the receipt witness. Pre-existing token-level (issuer-side) failures continue to revert exactly as today.
This TIP applies only to TIP-20 precompile flows; ordinary ERC-20 contracts deployed as userland code remain out of scope.
TIP-1028 extends TIP-403 with address-level receive policies and token sets, allowing a receiver to control which originators and which TIP-20 tokens may credit it. When a receive policy blocks an inbound transfer or mint, the operation still succeeds at the protocol level, but the funds are credited to `ESCROW_ADDRESS` instead of the receiver and a corresponding escrow receipt is recorded.
The receiver or a designated recovery contract may later claim these escrowed funds. Claims back to the receiver act as an unwind of the original inbound, while claims to other addresses are treated as new transfers.
Token-level authorization remains unchanged and continues to revert on failure. This behavior applies only to TIP-20 precompile flows; ordinary contracts and other precompiles are unaffected.

Comment thread tips/tip-1028.md Outdated
Comment on lines +27 to +36
TIP-403 is an issuer-side authorization layer: the token issuer decides who may send, who may receive, and who may mint to whom. It cannot answer the receiver's question, *"do I want to be exposed to this counterparty or this token at all?"*

Plain receiver-side reverts are not a viable substitute. Once an issuer–receiver–counterparty relationship exists, a receiver that later changes a revert-based policy can break in-flight flows and recurring inbounds across the entire system. Reverting receivers also create an asymmetric DoS surface against issuers, integrations, and protocol-owned distribution paths (DEX payouts, fee distributions, AMM outputs).

The design choice in TIP-1028 is therefore:

- **Token-level / issuer-side failures keep reverting.** Issuers retain full control of the token's authorization model; nothing in their semantics changes.
- **Receiver-side failures escrow instead of reverting.** Senders, mints, DEX payouts, and fee distributions still succeed at the protocol layer; the asset is held in `ESCROW_ADDRESS` until the receiver (or its recovery contract) claims it.

This TIP keeps issuer-side semantics unchanged and changes only receiver-side failure handling. Token-level failures still revert; receiver-side failures are escrowed instead. The escrow representation must preserve more than an aggregate amount because TIP-1022 virtual addresses carry attribution in the literal `to` address, memo-bearing transfers carry memo data, recovery contracts may want time-based or memo-based rules, and offchain recovery flows need the original sender identity.
Escrowed funds must carry enough metadata to be programmatically recoverable. An aggregate "amount blocked per (token, receiver)" bucket cannot express TIP-1022 attribution, memo routing, originator-based recovery rules, or transfer-vs-mint provenance. Therefore, the escrow precompile stores one keyed amount per blocked inbound, with ALL the receipt identity (version, requested recipient, block reason, kind, memo, timestamp, nonce) authenticated by the receipt witness and emitted in the blocked event — keeping persistent state to a single slot per receipt while preserving full attribution offchain.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Consider simplifying a bit. Feel free to accept or ignore the following suggestion:

Suggested change
TIP-403 is an issuer-side authorization layer: the token issuer decides who may send, who may receive, and who may mint to whom. It cannot answer the receiver's question, *"do I want to be exposed to this counterparty or this token at all?"*
Plain receiver-side reverts are not a viable substitute. Once an issuer–receiver–counterparty relationship exists, a receiver that later changes a revert-based policy can break in-flight flows and recurring inbounds across the entire system. Reverting receivers also create an asymmetric DoS surface against issuers, integrations, and protocol-owned distribution paths (DEX payouts, fee distributions, AMM outputs).
The design choice in TIP-1028 is therefore:
- **Token-level / issuer-side failures keep reverting.** Issuers retain full control of the token's authorization model; nothing in their semantics changes.
- **Receiver-side failures escrow instead of reverting.** Senders, mints, DEX payouts, and fee distributions still succeed at the protocol layer; the asset is held in `ESCROW_ADDRESS` until the receiver (or its recovery contract) claims it.
This TIP keeps issuer-side semantics unchanged and changes only receiver-side failure handling. Token-level failures still revert; receiver-side failures are escrowed instead. The escrow representation must preserve more than an aggregate amount because TIP-1022 virtual addresses carry attribution in the literal `to` address, memo-bearing transfers carry memo data, recovery contracts may want time-based or memo-based rules, and offchain recovery flows need the original sender identity.
Escrowed funds must carry enough metadata to be programmatically recoverable. An aggregate "amount blocked per (token, receiver)" bucket cannot express TIP-1022 attribution, memo routing, originator-based recovery rules, or transfer-vs-mint provenance. Therefore, the escrow precompile stores one keyed amount per blocked inbound, with ALL the receipt identity (version, requested recipient, block reason, kind, memo, timestamp, nonce) authenticated by the receipt witness and emitted in the blocked event — keeping persistent state to a single slot per receipt while preserving full attribution offchain.
TIP-403 allows token issuers to control who may use a token, but it does not give receivers control over which inbounds they accept. Some applications require receivers to restrict incoming transfers or mints based on the originator or token.
A revert-based receiver policy introduces a liveness problem: once a sender relationship exists, a receiver can later change its policy and cause future transfers or mints to revert, breaking integrations and making delivery unreliable.
TIP-1028 introduces receiver-side controls while preserving liveness. Instead of reverting when a receiver blocks an inbound, the transfer or mint succeeds at the protocol level and the funds are escrowed.
Blocked inbounds remain recoverable and attributable, allowing receivers (or their recovery contracts) to claim funds while preserving context needed for offchain handling.

Comment thread tips/tip-1028.md Outdated
Comment on lines +38 to +46
## Assumptions

- **TIP-403 registry exists and is extensible.** Token sets and address-level receive policies are added as new state and new entrypoints on the existing TIP-403 precompile registry, alongside its current address-policy surface. This TIP does not modify the existing TIP-403 address-policy ABI.
- **TIP-1015 compound policies are unchanged.** Receiver-side address-level controls evaluate exactly one axis (originator → receiver), and never cross-validate against the issuer's `transfer_recipient` / `mint_recipient` roles.
- **TIP-1022 resolution is available at TIP-20 inbound time.** Virtual-address resolution runs before TIP-1028 receiver-side checks; failed resolution still reverts.
- **TIP-1016 gas model.** Cost analysis uses the storage-cost model from TIP-1016 (fresh slot ≈ 250k gas, hot slot update ≈ 2.9k gas, baseline TIP-20 transfer ≈ 50k gas).
- **`ESCROW_ADDRESS` is reserved at protocol level.** No TIP-20 implementation, system contract, or user may treat `ESCROW_ADDRESS` as an ordinary holder. Userland transfers and mints to it MUST revert.
- **Reward state never lives at `ESCROW_ADDRESS`.** Implementations rely on treating the escrow sink as a reward-exempt always-opted-out address; violating this assumption silently corrupts the opted-in supply for reward distribution.
- **Backwards compatibility.** Addresses with no configured receive controls behave exactly as today. The only new ambient cost on existing flows is one cold storage read of the receiver's packed receive config slot.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section is a bit confusing, several of these read like core design constraints or requirements (e.g. TIP-403 extension, ESCROW_ADDRESS semantics, reward handling), rather than assumptions. It’s not clear what is truly assumed vs what this TIP enforces. Might be worth tightening this or removing.

Comment thread tips/tip-1028.md Outdated
Comment thread tips/tip-1028.md Outdated
Comment thread tips/tip-1028.md

The escrow precompile and the TIP-403 registry are independent: the escrow precompile authenticates claims using the receipt witness and the receipt's snapshotted recovery contract, and does **not** read the receiver's current TIP-403 receive config when claiming. The TIP-403 registry, conversely, has no knowledge of escrowed amounts: it only answers `verifyAddressInbound(...)` and exposes the current `recoveryContract` of an address.

### 1.2 End-to-End Flow Overview
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: remove this

Comment thread tips/tip-1028.md Outdated
Comment thread tips/tip-1028.md Outdated
Comment thread tips/tip-1028.md Outdated
Escrow-->>Claimer: success<br/>(emit BlockedReceiptClaimed)
```

### 1.3 Scope
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would update to TIP-20 Affected Paths or similar.

Comment thread tips/tip-1028.md Outdated
Comment thread tips/tip-1028.md Outdated
DEX internal balances are not TIP-20 wallet balances and are not subject to address-level receive checks until withdrawn back onto the TIP-20 ledger.
- `approve` / `permit` / `burn`
- fee refunds via `transfer_fee_post_tx`
- non-TIP-20 tokens deployed as ordinary contracts
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont think its necessary to mention this again. We should mention that "TIP-1028 only applies to TIP-20 precompile flows; ordinary contracts and other precompiles are unaffected" once in the overview, rather than restate this throughout the doc.

Comment thread tips/tip-1028.md Outdated
- `approve` / `permit` / `burn`
- fee refunds via `transfer_fee_post_tx`
- non-TIP-20 tokens deployed as ordinary contracts
- future recipient-bearing system-credit paths that do not identify a concrete originator
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is an example of this? When would there not be an originator?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't have any concrete example, let's delete for the sake of simplicity

Comment thread tips/tip-1028.md Outdated
- fee refunds via `transfer_fee_post_tx`
- non-TIP-20 tokens deployed as ordinary contracts
- future recipient-bearing system-credit paths that do not identify a concrete originator
- DEX *internal* balances. Gating only kicks in when funds are withdrawn back onto the TIP-20 ledger
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to the comment above, I think we can remove this if already specifying that TIP-1028 only applies to TIP20. This implies DEX internal balance is not included in scope.

Comment thread tips/tip-1028.md Outdated
@0xrusowsky 0xrusowsky changed the title fix(primitives): make reth feature imply serde (#3149) docs(tip-1028): rewrite for clarity May 1, 2026
0xrusowsky and others added 8 commits May 1, 2026 08:23
Co-authored-by: 0xKitsune <77890308+0xKitsune@users.noreply.github.com>
Co-authored-by: 0xKitsune <77890308+0xKitsune@users.noreply.github.com>
Co-authored-by: 0xKitsune <77890308+0xKitsune@users.noreply.github.com>
Co-authored-by: 0xKitsune <77890308+0xKitsune@users.noreply.github.com>
Co-authored-by: 0xKitsune <77890308+0xKitsune@users.noreply.github.com>
Co-authored-by: 0xKitsune <77890308+0xKitsune@users.noreply.github.com>
- Simplify Abstract per suggestion (high-level summary, no component list)
- Simplify Motivation per suggestion (remove design-choice bullets, streamline)
- Remove Assumptions section (items were design constraints, not assumptions)
- Remove redundant intro sentence in System Architecture
- Rename Section 1.3 to 'TIP-20 Affected Paths'
- Remove redundant scope bullets (non-TIP-20, no-originator, DEX internals)
  already covered by Abstract's 'only TIP-20 precompile flows' statement

Amp-Thread-ID: https://ampcode.com/threads/T-019de20c-08f4-7330-8f51-c6f45b8b89fb
Co-authored-by: Amp <amp@ampcode.com>
@0xrusowsky
Copy link
Copy Markdown
Contributor Author

closing in favor of #3791

@0xrusowsky 0xrusowsky closed this May 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants