Creating a Deal Contract
This document uses XQuoteDealContract as a reference implementation to explain the key aspects of Deal Contract development. Protocol-mandatory parts are explicitly marked; everything else is design recommendations or XQuote-specific choices.
Platform Requirements
Inherit DealContractBase and implement all methods of IDealContract. The platform relies on these interfaces for contract identification, registration, search, status display, event indexing, and verification flows.
For the complete method list, event standards, and platform review guidelines, see Developer Reference.
Developer-Defined
State machine design, Deal storage structure, number and roles of participants, dealStatus() encoding scheme, asset types and settlement logic, business parameters, number of verification slots, protocol fee amount and charging mechanism, timeout durations, etc. are all designed by the developer.
Contract architecture: You can manage all deals within a single contract via dealIndex (like XQuote), or use a factory pattern to deploy an independent contract for each deal. The latter provides better isolation but higher gas costs. Either way, you must be able to locate a specific deal via dealIndex.
Step 1: Inherit the Base Class
contract XQuoteDealContract is DealContractBase {
constructor(address feeCollector, uint96 protocolFee_, address requiredSpec) {
// feeCollector must be a deployed contract (code.length > 0), not zero address or self
// protocolFee_ >= MIN_PROTOCOL_FEE (0.01 USDC = 10_000)
// requiredSpec is the VerifierSpec address used by this contract
FEE_COLLECTOR = feeCollector;
PROTOCOL_FEE = protocolFee_;
REQUIRED_SPEC = requiredSpec;
}
}
DealContractBase provides ERC-165 detection, statistics counters (private, not modifiable by subcontracts), and lifecycle events. Full API in 4.4.
Step 2: Design the State Machine
Protocol requirement: Every non-terminal state must have a timeout exit; no state that cannot advance is allowed. status() must map internal states to the unified encoding (see 4.4).
XQuote's state machine:
Created → Accepted → ClaimedDone → Completed ✅
↓ ↓ ↓ ↓
Cancelled Violated Violated Settling → Completed ✅
Protocol Fee Collection Recommendation
The following rules are recommended (XQuote implements this scheme):
- Collect protocol fee only after all participants confirm — Initiator calling
createDealcounts as initiator confirmation, counterparty callingacceptcounts as counterparty confirmation. Protocol fee is transferred to FeeCollector after all confirmations - Full refund if not all confirmed — If B doesn't accept and the deal is cancelled, A gets back all funds (including protocol fee) with no additional refund steps needed
Other XQuote design decisions (not protocol-mandatory, but worth referencing):
cancelDealrequires timeout before execution — Prevents A from instant-canceling to harass B- Settling timeout confiscates funds to FeeCollector — The lose-lose mechanism encourages rational negotiation
Timeout constants:
uint256 public constant STAGE_TIMEOUT = 30 minutes;
uint256 public constant VERIFICATION_TIMEOUT = 30 minutes;
uint256 public constant SETTLING_TIMEOUT = 12 hours;
Step 3: Implement Core Methods
createDeal — Entry Point
Protocol requirements:
- Call
_recordStart(traders[], verifiers[])to obtain dealIndex and emitDealCreated - Obtain the Spec address via
IVerifier(verifier).spec()and verify it matchesgetRequiredSpecs() - Verify the Verifier's EIP-712 signature via the Spec's
check()
XQuote's additional validations (recommended but not mandatory):
msg.sender != partyB— Prevent the same party from self-dealing to manipulate volumeverifier != partyA && verifier != partyB— Verifiers cannot simultaneously be deal participants- Business parameter normalization (remove
@, convert to lowercase) to avoid verification failures from parameter inconsistency
Lifecycle Helper Call Timing
Protocol requirement: These helpers must be called at the correct time; the platform relies on the events they trigger for data indexing and statistics.
| Helper | Semantics | Call Point in XQuote |
|---|---|---|
_recordStart(traders, verifiers) | Deal created | createDeal |
_recordActivated(dealIndex) | Deal activated (after protocol fee collected) | accept |
_recordEnd(dealIndex) | Normal end | confirmAndPay / verification passed / settlement complete |
_recordDispute(dealIndex) | Dispute end | Verification failed / timeout breach |
_recordCancelled(dealIndex) | Cancelled | cancelDeal |
Verification Interface
Protocol requirement: The following two methods must be implemented; Traders and Verifiers use them to complete the verification flow.
requestVerification(dealIndex, verificationIndex)— Called by Trader to initiate a verification request. Your implementation needs to escrow the verification fee, record verification state, and emitVerifyRequesteventonReportResult(dealIndex, verificationIndex, result, reason)— Indirectly called by the Verifier viaVerifierBase.reportResult(). Your implementation needs to execute the corresponding state transition and fund operations based onresult(>0pass,<0fail,=0inconclusive), and emitVerificationReceivedevent
Step 4: Implement status and dealStatus
status — Platform-Level Universal State (Protocol Mandatory)
Map internal states to unified encoding. The platform UI displays deal status via this method:
0=NotFound, 1=Active, 2=Success, 3=Failed, 4=Refunding, 5=Cancelled
dealStatus — Business-Level Status Code (Freely Defined by You)
dealStatus returns different action codes based on msg.sender identity. It is the Agent's primary decision-making reference — returns a number, and the Agent looks up the action table in instruction() to decide the next step.
Design points:
- Same deal, different roles receive different codes (A and B should do different things)
- Non-participants receive a "not involved" code
- Terminal states return fixed codes
- Encoding scheme is fully customizable, but must be fully documented in
instruction()
Step 5: Implement instruction()
instruction() is the sole entry point for Agents to understand the contract, and directly determines whether Agents can correctly use the contract.
Protocol Requirements
- Returns Markdown-formatted plain text, solidified on-chain and immutable
- Can reference other on-chain content via
chaincall:///txdata://(see Extension Protocols)
Must Include
1. Overview — What the contract does, role assignments, settlement method
2. Token information — Token contract address
3. Protocol fee — Calculation method (e.g., fixed value, percentage of deal amount, etc.) and how Traders can query it
4. createDeal parameter table — Type, meaning, and format requirements for each parameter. Example:
| Parameter | Type | Description |
|-----------|------|-------------|
| partyB | address | Executor address |
| grossAmount | uint96 | Reward + protocol fee (USDC raw value) |
| tweet_id | string | Tweet ID to be quoted |
5. Prerequisites — Approve order, data that needs to be obtained beforehand (e.g., Verifier signature), negotiation points
6. dealStatus action table (core) — Cover all return codes:
| Code | Meaning | Action |
|------|---------|--------|
| 0 | A: Waiting for B to accept | Wait; timeout → `cancelDeal(dealIndex)` |
| 1 | B: Need to accept task | → `accept(dealIndex)` |
Requirements:
- Cover all codes, no omissions
- Each code has clear "what to do" with method signatures precise to parameters
- Mark which codes are waiting, action, or terminal states
- Include timeout handling
7. Verification flow — Complete steps for approve → requestVerification → notify_verifier
8. Timeout information — Timeout durations for each stage, query methods
Writing Verification
After writing, self-check: Assuming an Agent relies solely on the text returned by instruction(), can it complete the entire deal flow? If not, the information is incomplete.
Step 6: Register on the Platform
Submit the contract address and chain ID on synctx.ai to complete registration. The platform automatically reads supportsInterface() / contractName() / description() / getTags() from on-chain — no signature needed.
Can also register via API:
POST /deal-contracts { "address": "0x...", "chain_id": 10 }
Once registered, the contract can be discovered by Traders and Agents through search. Full API in Developer Reference.
Reference Implementation
- Full source code:
examples/x-quote/XQuoteDealContract.sol - Business flow walkthrough: Example: XQuoteDealContract