From 9584ebdd8d99ee309747a8241393c188af40ef52 Mon Sep 17 00:00:00 2001 From: armandocodecr Date: Fri, 11 Sep 2026 11:38:10 -0600 Subject: [PATCH] correct v2 protocol profile against contract source audit Co-Authored-By: Claude Fable 5 --- constitution.md | 2 +- skills/protocol/v2.md | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/constitution.md b/constitution.md index dfe3187..81ff369 100644 --- a/constitution.md +++ b/constitution.md @@ -77,7 +77,7 @@ Both versions are explained here so an agent can reason about either one and rec **Role overlap.** Now contract-enforced rather than a configurator choice: `disputeResolvers` may not overlap any other role, including `platform` and any milestone receiver, and `admin` may not be a payee. `admin` and `platform` may deliberately share an address — that pair is a capability distinction, not an address-separation rule. -**Operations.** Adds batch approval, approve-and-release in one transaction, and milestone management after creation. Escrow properties and roles can only change while the balance is zero. `withdraw-remaining-funds` is narrowed to genuinely terminal states, unlike V1 which also permits it during an open dispute. +**Operations.** Adds batch approval, approve-and-release in one transaction, and milestone management after creation (append or edit — never remove). Escrow properties, roles and milestone edits freeze at the **first `fund` call** — the lock is the cumulative funded amount, which never decreases, not the live balance; appending milestones stays allowed after funding. `withdraw-remaining-funds` is narrowed to genuinely terminal states, unlike V1 which also permits it during an open dispute, and must sweep the entire remaining balance, unlike V1 which allowed partial withdrawals. #### Recognizing a version in existing code diff --git a/skills/protocol/v2.md b/skills/protocol/v2.md index c82eb83..3dc3fd8 100644 --- a/skills/protocol/v2.md +++ b/skills/protocol/v2.md @@ -21,9 +21,9 @@ Read [constitution.md](../../constitution.md) first for the universal laws and t | Admin | `admin` (single) | Initialize the escrow, update escrow properties, manage milestones, extend contract TTL | | Approvers | `approvers` (array) | Approve milestones; approve-and-release; raise a dispute | | Service providers | `serviceProviders` (array) | Change milestone status and evidence; raise a dispute | -| Release signers | `releaseSigners` (array) | Release funds; approve-and-release | +| Release signers | `releaseSigners` (array) | Release funds; approve-and-release; raise a dispute | | Dispute resolvers | `disputeResolvers` (array) | Resolve disputes; withdraw remaining funds | -| Platform | `platform` (single) | Receive the platform fee at release | +| Platform | `platform` (single) | Receive the platform fee at release; raise a dispute | | Receiver | `receiver` (single) | Receive the net amount at release; raise a dispute. **Single Release only** — in Multi Release each milestone carries its own `receiver` | | Observers | `observers` (array) | Read-only. Implemented in V2; in V1 it was only a product concept | @@ -52,6 +52,7 @@ Each milestone declares how many approvals it requires. Approvers vote individua - The target must be greater than zero and no greater than the number of approvers. - A target of 1 reproduces V1 behavior, but the field is still an approvals structure, never a boolean. - Approval remains irreversible; there is no unapprove. +- A single-release escrow deployed **without milestones cannot release** (`NoMilestoneDefined`) until milestones are added through manage-milestones. --- @@ -72,16 +73,24 @@ Beyond the V1 set, V2 adds: - **Batch approval** — approve several milestones in one call. - **Approve-and-release** — collapse approval and release into a single transaction. The caller must satisfy both the approver and release-signer requirements. -- **Manage milestones** — add, edit or remove milestones after creation, signed by `admin`. +- **Manage milestones** — append new milestones or edit existing ones after creation, signed by `admin`. There is **no remove**: a milestone can never be deleted. Single-release edits change the description; multi-release edits change the description and the amount. -**[ENFORCED] Mutability rule.** Escrow properties and roles can only be changed while the contract balance is **zero**, and only by the `admin`. Once funded, roles are effectively frozen, and `admin` and `platform` are immutable from initialization. Role mistakes are not recoverable after funding. +**[ENFORCED] Mutability rule.** The lock is the escrow's **cumulative funded amount** (`FundedAmount`, increased by every `fund` call), not its token balance — this differs from V1, which checked the live balance. Consequences: + +- The **first** successful `fund` freezes escrow properties, roles and milestone **edits** permanently. Releasing funds does not unfreeze them: the funded amount never decreases. +- Tokens sent straight to the contract without calling `fund` do **not** trigger the lock. +- **Appending** new milestones stays allowed after funding, until the escrow is released, disputed or resolved. Only edits to existing milestones and property updates are blocked. +- All of it is `admin`-only, updates are also rejected while a dispute is open, and `admin` and `platform` are immutable from initialization. Role mistakes are not recoverable after funding. **[ENFORCED] `withdraw-remaining-funds`** narrows the V1 precondition. "Fully processed" in V2 means: - **Single Release:** `released || dispute.resolved`. - **Multi Release:** every milestone satisfies `released || dispute.resolved`. -An open, unresolved dispute no longer qualifies, unlike V1. Authorization, the 50-distribution cap, the positive-amount and balance checks, and the pro-rata fee deduction match V1. Both escrow types emit a withdrawal event in V2. +An open, unresolved dispute no longer qualifies, unlike V1. Two more rules: + +- **Distributions must sum to the entire remaining balance** — V2 withdraw is a full sweep. V1 allowed partial withdrawals; V2 rejects them (`DistributionsMustEqualEscrowBalance`). +- Authorization (one of `disputeResolvers`), the 50-distribution cap, positive amounts and the pro-rata fee deduction match V1. Both escrow types emit a withdrawal event in V2. **[FACT]** V2 adds a reentrancy guard that V1 does not have.