Documentation navigation
Docs/Protocol/Overview

Protocol overview

Credo is a proof-triggered delivery-versus-payment settlement layer. Official USDC remains final on Ethereum, the ERC-1155 remains on Creditcoin, and only cryptographic evidence crosses chains.

Payment rail

Official USDC on Sepolia. No wrapper, pool, or bridge custody.

Settlement rail

ERC-1155 escrow and deterministic release on Creditcoin CC3.

Trust boundary: The worker discovers transactions. Attestcoin proves receipts. The contract independently decides.

Quickstart

A Credo integration has two wallet roles. The seller creates and escrows the RWA on Creditcoin; the bound buyer pays official USDC on Sepolia. The recommended API-assisted path validates parameters and indexes the sale, while both users still sign their own wallet transactions.

  1. 1Authenticate the seller wallet using the nonce and verify endpoints.
  2. 2Approve SettleRWA to transfer the seller’s ERC-1155 asset.
  3. 3Prepare the sale, then submit the returned createSale call from the seller wallet.
  4. 4Index the confirmed Creditcoin transaction with its saleId.
  5. 5Authenticate the buyer wallet, show the exact payment instruction, and register the confirmed Sepolia transaction hash.
  6. 6Poll the settlement resource until the sale settles or the proof reaches a retryable or permanent error.
// 1. Prepare a sale as the authenticated seller
const prepared = await fetch("/api/v1/sales/prepare", {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({
    buyer: "0xBuyer...",
    assetContract: "0xYourERC1155...",
    tokenId: "1",
    assetAmount: "1",
    paymentNetwork: "sepolia",
    paymentRecipient: "0xSeller...",
    // Decimal USDC with exactly 6 fraction digits; the response returns raw units.
    paymentAmount: "25.000000"
  })
}).then(r => r.json());

// 2. Preserve this exact argument order for the contract call.
const args = [
  prepared.params.buyer,
  prepared.params.assetContract,
  BigInt(prepared.params.tokenId),
  BigInt(prepared.params.assetAmount),
  BigInt(prepared.params.paymentChainKey),
  BigInt(prepared.params.paymentChainId),
  prepared.params.paymentToken,
  prepared.params.paymentRecipient,
  BigInt(prepared.params.paymentAmount),
  BigInt(prepared.params.sourceStartBlock),
  BigInt(prepared.params.sourceEndBlock)
];
// Send createSale(args) to prepared.contract from the seller on CC3.

// 3. After SaleCreated, register the confirmed transaction
await fetch("/api/v1/sales/index", {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({ saleId, creationTxHash })
});

Before you integrate

Asset

An ERC-1155 on Creditcoin CC3 that is already on the operator-managed allowlist, plus seller balance and approval for SettleRWA.

Wallets

Distinct seller and buyer EVM addresses. The payment recipient must be the authenticated seller.

Payment

Official Sepolia USDC 0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238. API amounts are decimal USDC; contract amounts are 6-decimal raw units.

Networks

Creditcoin CC3 (102031) for the RWA and Sepolia (11155111) for payment.

Active deployment

The following v3 testnet deployment is the canonical integration target. Bytecode and configuration were verified through CC3 RPC; Blockscout source publication is still pending, so this is not a production-value deployment.

SettleRWA0x643e070304b7ae9Eed815A7976AA83217206b64aDeployment tx
PaymentVerifierUSC0x89df0af9C61D9636d1f67748D863f9AfC741EcfFDeployment tx
TestRWA0xEe1e1D277d011157dAC95F59189E9d5877668284Deployment tx
CC3 · 102031Sepolia · 11155111Attestcoin · key 1

Integration path

Use the API-assisted path below for validation, authentication, and worker tracking. A direct-contract integration may call the same ABI, but must calculate every raw value and source block itself and still index the resulting sale before using Credo's payment API.

  1. 01Verify the deployment manifest and explorer transactions.
  2. 02Ask the deployment operator to add the ERC-1155 through configureAsset; there is no public self-service endpoint today.
  3. 03Approve SettleRWA as the ERC-1155 operator.
  4. 04Call createSale with the Buyer and exact payment tuple.
  5. 05Index SaleCreated. Settlement continues automatically after payment.

Sale lifecycle

OPEN
  ↓ exact official USDC Transfer
PAYMENT FOUND
  ↓ receipt + continuity proof
VALIDATING
  ↓ exact on-chain verification
SETTLED

Registering a payment returns 202 Accepted. This means proof processing has started, not that settlement has completed. Poll GET /api/v1/sales/:saleId/settlement. The sale status is OPEN, SETTLED, or RECLAIMED. Payment/proof processing may report RETRYABLE_ERROR or PERMANENT_REJECTION; those are not sale statuses.

API reference

All request bodies are strict JSON. Protected endpoints use the HTTP-only session cookie created by wallet authentication.

POST/api/v1/auth/nonceCreate a five-minute wallet signing challenge.
POST/api/v1/auth/verifyVerify the signature and create a 15-minute session.
POST/api/v1/sales/prepareValidate inputs and return the Creditcoin createSale call.
POST/api/v1/sales/indexIndex a confirmed SaleCreated transaction.
GET/api/v1/sales/:saleIdRead sale, asset, payment, window, and current status.
GET/api/v1/sales/:saleId/payment-instructionGet the exact USDC transfer parameters.
POST/api/v1/sales/:saleId/paymentAs the authenticated bound buyer, register the confirmed Sepolia transaction.
GET/api/v1/sales/:saleId/settlementRead sale, payment, proof, query ID, and Creditcoin settlement status.
// Authenticate the buyer wallet through /auth/nonce and /auth/verify.
// The resulting HTTP-only cookie must be sent with this request.

// Buyer: fetch the exact payment tuple
const instruction = await fetch(
  `/api/v1/sales/${saleId}/payment-instruction`
).then(r => r.json());

// Transfer instruction.amountRaw to instruction.recipient using
// instruction.token on instruction.chainId, then register its hash.
await fetch(`/api/v1/sales/${saleId}/payment`, {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({ sourceTxHash })
});

const state = await fetch(
  `/api/v1/sales/${saleId}/settlement`
).then(r => r.json());

Parameter reference

The prepare endpoint builds a default payment window of 7,200 blocks from the next Sepolia block. JSON integer values remain decimal strings; convert them to BigInt only when encoding the Creditcoin transaction. Attestcoin chain key 1 identifies the proof source, while EVM chain ID 11155111 identifies Sepolia. They are different fields and are not interchangeable.

buyeraddressNon-zero address; must be different from the authenticated seller.
assetContractaddressERC-1155 approved by the operator-managed allowlist.
tokenIduint256Unsigned decimal string; seller must own the requested token.
assetAmountuint256Positive unsigned decimal string within the seller balance.
paymentChainKeyuint641 for the Sepolia Attestcoin proof source.
paymentChainIduint6411155111 for Sepolia; must match the configured chain key.
paymentTokenaddressOfficial Sepolia USDC: 0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238.
paymentRecipientaddressMust equal the authenticated seller wallet.
paymentAmountuint256Exact 6-decimal raw USDC amount; positive and tuple-unique while open.
sourceStartBlockuint64First accepted Sepolia payment block, inclusive.
sourceEndBlockuint64Last accepted block, inclusive; after start and at most 50,000 blocks away.

Contract ABI

Use the ABI to encode contract calls, decode events, and read sale state. Most frontend integrations only need the public sale functions and events below; the complete compiler-generated ABIs are available for tooling and contract verification.

import { parseAbi } from "viem";

export const settleRwaAbi = parseAbi([
  "function createSale(address buyer,address assetContract,uint256 tokenId,uint256 assetAmount,uint64 paymentChainKey,uint64 paymentChainId,address paymentToken,address paymentRecipient,uint256 paymentAmount,uint64 sourceStartBlock,uint64 sourceEndBlock) returns (bytes32 saleId)",
  "function getSale(bytes32 saleId) view returns ((address seller,address buyer,address assetContract,uint256 tokenId,uint256 assetAmount,uint64 paymentChainKey,uint64 paymentChainId,address paymentToken,address paymentRecipient,uint256 paymentAmount,uint64 sourceStartBlock,uint64 sourceEndBlock,uint64 reclaimAfter,uint8 status))",
  "function reclaim(bytes32 saleId)",
  "event SaleCreated(bytes32 indexed saleId,address indexed seller,address indexed buyer,bytes32 paymentTuple)",
  "event AssetEscrowed(bytes32 indexed saleId,address indexed asset,uint256 tokenId,uint256 amount)",
  "event SaleSettled(bytes32 indexed saleId,address indexed buyer,address indexed seller,bytes32 queryId,uint64 sourceBlock)",
  "event AssetReclaimed(bytes32 indexed saleId,address indexed seller,address indexed asset,uint256 tokenId,uint256 amount)"
]);

Protocol limits

Maximum source window50,000 blocks
Reclaim safety grace24 hours + source window
Estimated source block time12 seconds
Observed v3 latency489 seconds
Stale worker recovery60 seconds

Security model

Settlement binds the source chain key, block window, official token emitter, designated Buyer, recipient, exact raw amount, successful receipt status, and a globally unused query ID.

An open sale reserves its exact payment tuple so the same intended payment cannot back two active sales. The worker has no settlement authority: anyone may submit evidence, but only a proof accepted by the native verifier can release escrow. The operator can allowlist assets and pause new sales, but cannot force an existing sale to settle or redirect its asset.

Non-atomic settlement: A Sepolia payment is irreversible before Creditcoin release completes. The reclaim deadline covers the source payment window plus a 24-hour grace so the seller cannot reclaim during the expected proof period.

Errors & recovery

Error responses use { error: { code, message, requestId } }. Log the request ID for support and branch on the stable code, not the human-readable message.

400INVALID_SCHEMAFix the request shape or decimal-string fields.
401NOT_AUTHENTICATED / SESSION_EXPIREDRepeat wallet authentication.
403*_WALLET_MISMATCHConnect the seller or buyer bound to the sale.
404SALE_NOT_FOUNDCheck the saleId or wait until indexing completes.
410SALE_NOT_OPEN / SALE_NOT_PAYABLEStop payment; the sale is terminal.
422INVALID_SALE_TRANSACTIONVerify chain, contract, receipt success, and SaleCreated event.
503*_NOT_CONFIGUREDThe deployment is unavailable; retry only after operator recovery.

Explicit non-goals

  • No asset bridge or wrapped USDC.
  • No settlement authority granted to the worker; contracts trust verified proof only.
  • No immediate Seller cancellation.
  • No claim of a simultaneous two-chain atomic swap.
  • No production-value guarantee for this testnet deployment.