Abstract
This ERC specifies ORDER_AMENDMENT_V1, a profile over ERC-8001 for bilateral changes to an existing service order. Both parties accept a complete replacement terms commitment tied to the current order revision and amendment nonce. Supplemental funding and revision activation succeed together or leave the order and funds unchanged. Coordination-attempt status remains distinct from successful application of the amendment.
Motivation
After a buyer orders a report covering three projects for 100 units, the parties may agree to ten projects for 180 units and a later deadline. A new catalogue listing or a conversation does not identify which existing agreement changed or authorize the additional 80 units. Generic multi-party consent does not define the base order, the funding delta, the competing-revision rule, or how a failed application affects retries. Those bindings are necessary for independent clients and order applications to interpret the same amendment.
Specification
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.
Scope and authoritative order
This profile MUST use one chain, one buyer, one provider, one immutable ERC-20 payment asset per order, and a combined coordinator/order contract. An order's identity, counterparties and asset MUST NOT change through an amendment. The coordinator MUST implement ERC-8001's interface, hashes, domain and lifecycle, subject to the additional profile restrictions below. EIP-712, ERC-1271 and ERC-2098 provide the referenced signature mechanisms.
The order application MUST make the authoritative buyer, provider, asset, revision, terms hash, complete current terms, amendment nonce and amendment eligibility inspectable. The initial order API and its storage layout are application-defined; this profile does not define a universal order-creation or settlement interface. The application MUST read the authoritative state during execution rather than relying on a client's cached view.
The buyer and provider MUST be distinct nonzero addresses. Allowed amendments MUST have a positive, unchanged or increased total price, an unchanged or extended deadline, and no previously submitted deliverable. Scope and acceptance commitments MAY change. A successful amendment MUST change the full terms hash. Scope and acceptance hashes MUST be nonzero commitments to exact document bytes; they do not guarantee availability or work quality. Signers SHOULD obtain those documents and a readable comparison before accepting.
Price decreases, deadline shortening, post-submission amendments, partial-delivery adjustments, provider or asset replacement and cross-chain application are outside this profile. No discovery record, award, allowance, preflight result or budget grant substitutes for the two parties' explicit consent. Conversely, consent does not reserve capacity under an external funding policy.
All prices and supplements MUST use the payment asset's raw integer units, without decimal conversion. Deadlines, validUntil, intent expiry and acceptance expiry MUST be Unix timestamps in seconds. An order is active only after its initial agreement is effective, while it is neither cancelled nor settled and has no submitted work; the application MUST NOT report an order as eligible merely because it holds tokens.
Signed representation
The EIP-712 domain MUST be:
{ name: "ERC-8001", version: "1", chainId, verifyingContract }verifyingContract MUST also be AmendmentData.orderContract. The payment asset and order counterparties MUST be immutable within that contract's order state.
Identifiers are Keccak-256 of the exact UTF-8 strings:
coordinationType = keccak256("ORDER_AMENDMENT_V1")
payload.version = keccak256("ORDER_AMENDMENT_PAYLOAD_V1")Terms use the struct hash for this exact EIP-712 type (no domain prefix in a terms hash):
Terms(bytes32 scopeHash,bytes32 acceptanceHash,uint256 totalPrice,uint64 deadline)CoordinationPayload.coordinationData is abi.encode(AmendmentData) using this field order:
struct Terms {
bytes32 scopeHash;
bytes32 acceptanceHash;
uint256 totalPrice;
uint64 deadline;
}
struct AmendmentData {
address orderContract;
bytes32 orderId;
uint64 baseRevision;
bytes32 baseTermsHash;
uint256 amendmentNonce;
bytes32 newTermsHash;
Terms newTerms;
uint64 validUntil;
}All fields in this tuple are static ABI values, including the nested terms tuple. Encoding is 11 consecutive 32-byte slots (352 bytes); no dynamic tuple offset. Decode/re-encode equality rejects trailing bytes and noncanonical representations. newTermsHash MUST equal the struct hash of the complete newTerms.
The payload hash is:
keccak256(abi.encode(
payload.version,
payload.coordinationType,
payload.coordinationData,
payload.conditionsHash,
payload.timestamp,
payload.metadata
))The payload MUST have conditionsHash == bytes32(0) and empty metadata. timestamp is informational and signed through the payload hash; it does not establish execution time. Acceptance criteria belong in Terms.acceptanceHash, not in an ignored opaque condition field.
AgentIntent and AcceptanceAttestation use ERC-8001's type strings. getIntentHash returns the struct hash, not the full domain-prefixed digest. Each acceptance contains that struct hash and is signed under its own EIP-712 digest.
| Field | Profile rule |
|---|---|
| intent.participants | Exactly the authoritative buyer and provider, sorted ascending by address and distinct |
| intent.agentId | One of those two participants |
| intent.nonce | uint64, strictly greater than the coordinator's stored nonce for this initiator |
| intent.coordinationType | ORDER_AMENDMENT_V1 identifier |
| intent.coordinationValue | Zero; funding is computed from current order terms, not this informational field |
| acceptance.nonce | Zero; optional Core acceptance nonces are not enabled |
| acceptance.conditionsHash | Zero; nonzero constraints are rejected rather than silently ignored |
| acceptance.participant | One of the two authoritative participants; its signature MUST validate |
| acceptCoordination caller | MUST be a listed participant; one participant may submit the other's valid attestation |
| executionData | MUST be empty; no unsigned target, price, recipient or terms override |
JSON vectors serialize integers as base-10 strings. Hashes and addresses are hexadecimal strings. JSON text itself is not the hashed message.
Consent and application
Both participants, including the initiator, MUST explicitly accept. Proposing does not count as an acceptance. Proposals and acceptances do not alter the order, secure extra funds or establish that execution will succeed.
The coordinator implements the Core status values None, Proposed, Ready, Executed, Cancelled, Expired. Core signature nonces, order revisions and order amendment nonces have distinct meanings:
- A new Core intent advances its initiator's nonce. It does not revoke all older pending intents.
- An applied amendment increments the order revision and amendment nonce.
- Either buyer or provider can call
invalidateAmendments(orderId)on an active, unexpired order. It increments only the order amendment nonce and leaves existing terms/funds intact. It does not rewrite Core status to Cancelled. - Before intent expiry, only its proposer may invoke Core cancellation. At or after intent expiry, anyone can cancel it. Executed and cancelled intents are terminal.
At execution, Core first verifies Ready status, intent and acceptance freshness, payload hash and empty executionData. Invalid outer inputs revert without consuming the intent. Valid outer inputs begin one execution attempt and consume it.
An isolated EVM self-call then checks:
- The signed order contract, payload version, profile and full new-terms commitment.
- The order is Active, and
block.timestamp < currentTerms.deadline. block.timestamp < validUntil.- The current revision, terms hash and amendment nonce match the signed base state.
- Price/deadline restrictions and nonempty scope/acceptance commitments.
- The supplemental transfer is exactly
newTerms.totalPrice - currentTerms.totalPrice.
The transfer, escrow accounting, terms replacement, revision/nonce increments and OrderAmendmentApplied event MUST all occur in this isolated call. A successful application MUST return abi.encode(orderId, revision, newTermsHash, supplement) using types (bytes32, uint64, bytes32, uint256). The application MUST verify the exact buyer and escrow token-balance deltas and reject mismatches. This does not establish safe support for arbitrary malicious, rebasing or fee-charging tokens.
Execution and invalidation are ordered by transactions. Invalidation does not undo an already applied change. At most one amendment can apply against a given base revision. After a deadline extension, later amendments use the new current deadline.
Failure and retry
| Failure stage | Core outcome | Order and funds |
|---|---|---|
| Invalid Core state, expired intent/acceptance, payload mismatch or nonempty executionData | Outer call reverts | Unchanged |
| Stale order revision/nonce, ineligible order, expired amendment, failed funding or out-of-profile terms | Executed, success=false | All application-call writes and logs rolled back |
| Successful application | Executed, success=true, plus OrderAmendmentApplied | New authoritative revision and additional escrow |
Consumers MUST inspect success and the authoritative order/application event. Ready is consent readiness; Executed alone is not proof of successful amendment.
A failed application consumes the Core intent but does not increment the order nonce/revision. A retry requires a new Core intent nonce/hash and new acceptances from both parties. It can reference the same order base state if that state is still authoritative. Implementations MUST NOT automatically reuse acceptances of the consumed intent for the retry.
Implementations MUST allow any caller to execute a Ready coordination, including a relayer. Consequently, an execution attempt during temporary funding failure can consume the intent before the parties want to retry; gas constraints can also affect attempts. This profile accepts that liveness tradeoff and does not provide griefing-resistant scheduling. An implementation that requires additional execution authorization implements a different execution policy and MUST NOT silently treat it as this profile.
The same rollback boundary covers a token that moves funds and then returns false. Implementations MUST prevent reentrant public mutations and MUST restrict the application helper to calls from the coordinator itself.
Submission and signatures
An application accepting a delivery MUST restrict submission to the recorded provider before the current order deadline and MUST require the exact current revision, terms hash and a nonzero result hash. A valid submission MUST make the order ineligible for all subsequent amendments in this profile. This rule does not prescribe the submission method's selector or a global order-status enum.
Implementations MUST support low-s 65-byte ECDSA and compact 64-byte ERC-2098 signatures for EOAs and ERC-1271 signatures for contract signers, using STATICCALL for contract validation. Invalid signatures MUST be rejected. Signatures MUST be validated at proposal/acceptance time; this profile MUST NOT revalidate a mutable ERC-1271 signing policy at execution time. To withdraw an already accepted amendment, use the explicit order invalidation operation while eligible.
Application events and invalidation
Implementations MUST expose the following invalidation function and emit the following application events with these signatures. Order creation, work submission and settlement methods remain application-defined.
function invalidateAmendments(bytes32 orderId) external;
event AmendmentsInvalidated(
bytes32 indexed orderId,
address indexed participant,
uint256 amendmentNonce
);
event OrderAmendmentApplied(
bytes32 indexed intentHash,
bytes32 indexed orderId,
uint64 revision,
bytes32 previousTermsHash,
bytes32 newTermsHash,
uint256 supplement
);invalidateAmendments MUST be restricted to the recorded buyer or provider while the order is active, has no submitted work, and is before its current deadline. It MUST advance only the order amendment nonce, MUST NOT change current terms or funds, and MUST emit AmendmentsInvalidated. A successful amendment MUST increment both the revision and amendment nonce once and emit OrderAmendmentApplied with the applied revision, previous and new terms hashes and actual supplement. Overflow MUST revert rather than wrap. An unsuccessful application MUST NOT leave that event in the transaction receipt.
Rationale
A profile instead of changing generic coordination
ERC-8001 already supplies multi-party agreement, replay domains and coordination status. The additional interoperability boundary is the order-specific signed payload and the relationship between consent, the current agreement and supplemental funding. This proposal leaves generic coordination unchanged. It is a candidate separate specification of that profile, not a new version or reassignment of ERC-8001.
Complete terms and separate nonces
Signing complete replacement terms avoids conflicting interpretations of a textual delta. The base revision and terms hash prevent a competing amendment from silently replacing a newer agreement. The order amendment nonce permits either party to withdraw pending changes without cancelling the existing work or redefining Core cancellation. Proposing a newer Core intent is not equivalent to invalidating every older order amendment.
Explicit acceptance and atomic funding
Requiring the initiator to accept as well as propose distinguishes an offer from a final agreement. Funding from current state rather than a signed absolute supplement prevents double-counting chained amendments. A 100 to 180 to 220 sequence needs supplements of 80 and 40. An external budget remains authoritative at execution: it may be reduced or revoked after both parties accept.
Failed attempts and submitted work
A consumed execution attempt gives the coordination a definite outcome even when application fails. Requiring a new intent and fresh acceptances makes a later retry explicit. The tradeoff is that any caller may consume a Ready attempt during a temporary funding failure. This profile does not claim to solve execution scheduling or griefing.
Freezing amendments at submission protects the agreement attached to delivered work. Milestone changes or continuation after partial delivery require a different profile that explicitly preserves accrued rights. Discovery, tender awards, work quality, acceptance, disputes and payout remain separate application responsibilities.
Backwards Compatibility
This profile does not modify ERC-8001's typed data, canonical domain, Core status values or required interface. It constrains the opaque coordination payload and adds order-application requirements. A generic coordinator does not automatically conform merely because it accepts this payload. Consumers MUST distinguish Executed from CoordinationExecuted.success and the authoritative order application record. Existing tenders with immutable rewards cannot be repriced merely by advertising or signing this profile's terms.
Test Cases
The deterministic vector includes original terms, complete amendment data, ABI bytes, Core intent and acceptances, the illustrative domain, expected hashes and signatures. All integers are decimal strings in JSON; JSON serialization is not the hashed message. The signatures use public test keys and MUST NOT be used for production assets.
| Case | Expected result |
|---|---|
| Current total 100; complete agreed total 180 | Supplement 80; revision and amendment nonce each increase once; new terms hash becomes authoritative. |
| Current total 180 after an applied amendment; complete agreed total 220 | Supplement 40, not 120. |
| Two amendments share one base revision | At most one applies; applying the other cannot change funds or order state. |
| Either party invalidates before application | Pending amendments using the old order nonce cannot apply; the underlying agreement stays intact. |
| Funding fails after bilateral acceptance | Application writes, transfers and application logs roll back; the coordination records Executed, success=false. |
| Capacity restored after that failed attempt | The old coordination stays terminal; a fresh intent needs fresh acceptances from both parties. |
| Nonempty unsigned execution data | Outer transaction reverts without consuming the coordination. |
| Complete replacement data is not canonical ABI, or its terms hash differs | Reject the payload; do not apply an amendment. |
| Current time equals the current order deadline or amendment validity limit | Application fails; equality is expired. |
| Work already submitted against the current revision | Amendment fails; the submission's agreement is not rewritten. |
| Price decreases or deadline shortens | Application fails even if both parties accepted. |
Security Considerations
Signatures MUST bind the chain, verifying contract, canonical payload and actual counterparties. Full terms commitments MUST be checked against supplied data. Empty or ignored acceptance constraints MUST NOT be treated as enforceable policy. An order ID, descriptor hash, tender version or external budget identifier is not interchangeable with the signed order revision and terms hash.
Current base state, eligibility, deadlines and funding policy MUST be checked in the application call. A preflight does not reserve funds, and a budget grant does not supply order consent. Implementations MUST prevent callbacks from applying an amendment twice or bypassing the isolated application entry point. Arbitrary token behavior can defeat balance assumptions; exact balance checks are not a general guarantee for malicious tokens.
Signature validation at proposal/acceptance time does not guarantee a mutable contract wallet would approve later. This profile provides explicit order invalidation for withdrawal while eligible. Permissionless execution and consumed-on-failure attempts introduce the scheduling/griefing tradeoff described above. Gas exhaustion can also revert an entire transaction; no success or failed-attempt record is established if the outer transaction itself reverts.
Document hashes do not prove availability, understanding or service quality. Signers SHOULD inspect exact terms and their changes. This specification provides no default payment, adjudication, review timeout or refund rule for submitted work; a deployment must specify those application policies independently. Cross-chain atomicity and off-chain database recovery are not established by this profile.
Copyright
Copyright and related rights waived via CC0.
