CHIP-0062: The Forge — Weighted N-Asset AMM - #217
Conversation
Proposes a weighted constant-function market maker in which one singleton holds any number of assets, each in its own reserve coin, at weights fixed at pool creation. Built on CHIP-0050's action layer; authorizations are CHIP-0025 messages whose receiver coin id the pool derives rather than accepts. Informational / Puzzle. Requires CHIP-0025 and CHIP-0050. Supporting material — the full specification, architecture, a written CLVM pass over every leaf, security notes, and a comparison against publicly documented AMM failures — is referenced from the public forge-puzzles repository, alongside the implementation it describes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 9713658. Configure here.
| | DAO fee | Lowers the DAO rate on a message from the configured recipient. The new rate MUST be strictly lower than the current one. | | ||
|
|
||
| One or more leaves may run in a single spend; the action layer threads state from | ||
| each to the next, and the finalizer commits the last. |
There was a problem hiding this comment.
Empty action spend not forbidden
High Severity
The design uses CHIP-0050's action layer and a finalizer that recreates all N reserves on every spend, but it never requires the inner puzzle to run at least one leaf. The action-layer rule is that a singleton must not be spendable with an empty action list, because a prior CHIP-0050 attempt to block no-action spends failed review.
Additional Locations (1)
Triggered by learned rule: Action layer and slots security
Reviewed by Cursor Bugbot for commit 9713658. Configure here.
|
This CHIP is now a |
|
@awizardxch Thanks for creating this CHIP. I have updated the file name and added myself as a reviewer. Otherwise, I haven't made any changes. You may want to update the formatting to remove the mid-paragraph new line characters, as well as the non-standard U+2014 characters. |
greimela
left a comment
There was a problem hiding this comment.
Daybreak Blue security review
These findings come from a ChatGPT Daybreak Blue review of PR head 29203bd and Forge implementation f8fbcaa.
| Severity | Finding |
|---|---|
| P0 | Genesis can authorize more LP tokens than pool state records |
| P1 | Successive singleton generations can backfill oracle time |
| P1 | The final LP position cannot redeem |
| P1 | The protocol-fee units disagree |
| P1 | Reserve receiver derivation trusts solution data |
The first two issues were reproduced with spend bundles accepted by consensus validation. The terminal-LP and reserve-substitution cases were tested against the compiled puzzles.
| | A substituted coin satisfying an authorization | Derived receiver ids; CHIP-0025 mode binds sender puzzle and receiver coin at consensus | | ||
| | Value extracted by chaining actions in one spend | The invariant holds per action; suites value the actor's closing position at pre-sequence prices | | ||
| | A negative or reversed trade amount, reversing the fee | Sign assertions in the leaf, and an invariant unsatisfiable for such inputs | | ||
| | LP minted or melted without the pool's consent | The TAIL requires a message from the pool and a CAT parent; the melt inner's only behaviour is to destroy its whole amount | |
There was a problem hiding this comment.
P0: Bind genesis issuance to a single LP eve
Impact: A pool creator or keyless router can mint LP tokens that the pool state does not record, wait for users to deposit, then redeem the hidden supply for reserve assets.
Attack path
- The TAIL genesis branch accepts the singleton launcher coin announcement instead of a pool message.
- That announcement does not commit to the LP eve coin making the assertion.
- Multiple independently funded eves can reuse the announcement in one bundle.
Reproduction: A complete registered-pool bundle passed consensus validation. Pool state recorded 5,000,000 LP, while two eves minted 10,000,000 LP in total.
Required change: Bind genesis authorization to exactly one derived LP eve coin ID. Add a regression test that rejects duplicate eves.
| | LP minted or melted without the pool's consent | The TAIL requires a message from the pool and a CAT parent; the melt inner's only behaviour is to destroy its whole amount | | ||
| | An LP token used against a pool of a different revision | The TAIL asserts the protocol version | | ||
| | Two pools claiming the same market | The sorted registry | | ||
| | Oracle manipulation within one spend | The accumulator advances on pre-spend prices, with the height pinned across every action in a bundle | |
There was a problem hiding this comment.
P1: Prevent cross-generation oracle backfilling
Impact: An attacker can make the oracle report elapsed blocks at a manipulated price even though no block elapsed. A downstream contract that releases assets based on this TWAP can be drained.
Attack path
- Spend the pool at declared height
H - 31and perform a swap. - In the same bundle, spend the ephemeral successor at declared height
Hand observe the new price. - The same-height guard only covers leaves within one action-layer spend, so the cross-generation pair passes.
Reproduction: The compiled bundle passed consensus validation and recorded 31 blocks at the manipulated price at one actual height. Spot moved from 1, while the claimed 32-block TWAP became 3.9004.
Required change: Bind elapsed time to actual coin birth heights across singleton generations. If the puzzle cannot enforce that relationship, remove the oracle from this proposal.
| |---|---| | ||
| | `swap` | One reserve rises, one falls. Requires a positive input and a positive claimed output, distinct in-range asset indices, and an exact invariant match. The protocol and DAO slices are taken from the output and accrued in state. | | ||
| | `add` | Deposits to one or more reserves, minting LP. Requires a positive LP delta, non-negative deposits, and at least one positive deposit. | | ||
| | `remove` | Burns LP and pays a proportional share of every reserve. Requires the burn to be positive and strictly less than total LP, so the pool outlives every withdrawal. | |
There was a problem hiding this comment.
P1: Provide a redeemable terminal state
Impact: The final LP holder cannot withdraw their share of the reserves. Another holder can redeem all but the victim's final LP unit and leave that share permanently trapped.
Cause: The rule burn < total_lp forbids burning the remaining LP supply, while the registry accepts any positive supply without requiring a minimum relationship to the reserves.
Reproduction: A compiled pool registered successfully with reserves of 10,000,000 and 20,000,000 and total_lp = 1. Its only LP unit could not be burned.
Required change: Add a terminal close path. Alternatively, define a bounded minimum-liquidity amount, lock it deliberately at genesis, and enforce that invariant during registration.
|
|
||
| **Configuration** is curried and therefore immutable for the life of a pool: | ||
| asset ids in canonical order, the weight of each, the trade fee in basis points, | ||
| the protocol fee in parts per million, the LP TAIL hash, and the DAO recipient's |
There was a problem hiding this comment.
P1: Use one protocol-fee unit
Impact: A wallet following the CHIP can authorize a fee 100 times larger than intended, diverting the difference to the protocol recipient.
| Source | Stated unit | Denominator |
|---|---|---|
| This CHIP | Parts per million | 1,000,000 |
| Referenced Forge specification and code | Basis points | 10,000 |
For example, a value of 5 means 5 ppm under this text but 5 bps in the puzzle.
Required change: Choose one unit, denominator, and maximum. State them normatively and use the same names in the implementation.
| ### Authorization | ||
|
|
||
| Every reserve release and every LP mint or melt is a CHIP-0025 `SendMessage` with | ||
| mode `SENDER_PUZZLE | RECEIVER_COIN`. The receiver's coin id MUST be derived by |
There was a problem hiding this comment.
P1: Commit the canonical reserve parent
Impact: An attacker can replace the expected reserve successor and strand the canonical reserve, breaking the proposal's anti-substitution guarantee. This is not a free drain by itself because the attacker must provide replacement value.
Cause: The reference finalizer accepts reserve_parent_ids from its solution and uses those values in coinid(...). The pool does not independently commit to or authenticate them.
Reproduction: An attacker-created reserve with the same puzzle and amount satisfied the message and became the successor while the canonical reserve remained unspent.
Required change: Commit the reserve parent or full coin ID in pool state, or prove its lineage before deriving the receiver.


Proposes a weighted constant-function market maker in which one singleton holds any number of assets, each in its own reserve coin, at weights fixed at pool creation. Built on CHIP-0050's action layer; authorizations are CHIP-0025 messages whose receiver coin id the pool derives rather than accepts.
Informational / Puzzle. Requires CHIP-0025 and CHIP-0050.
Supporting material — the full specification, architecture, a written CLVM pass over every leaf, security notes, and a comparison against publicly documented AMM failures — is referenced from the public forge-puzzles repository, alongside the implementation it describes.
Note
Low Risk
Documentation-only addition of a draft CHIP; no runtime, consensus, or dependency changes in this repository.
Overview
Adds CHIP-0062 (Draft, Informational / Puzzle) documenting The Forge: a weighted N-asset constant-function AMM built as a CHIP-0050 action-layer singleton with per-asset reserve coins and pool-authorized LP CAT.
The new spec defines pool configuration/state, the weighted product invariant, action leaves (
swap,add,remove,collect,observe, DAO fee decrease), CHIP-0025 authorizations with derived receiver coin ids (not solution-supplied), a sorted on-chain registry, and security/testing expectations. It requires CHIP-0025 and CHIP-0050, states no consensus change, and points normative detail and the reference implementation to the externalforge-puzzlesrepo (testnet11 deployment noted).Note:
Comments-URIreferences PR #217 while linking topull/192— likely a metadata typo for editors to fix.Reviewed by Cursor Bugbot for commit 29203bd. Bugbot is set up for automated code reviews on this repo. Configure here.