Examples
Practical flows for using Cortex as a merchant, agent operator, or application developer. Reads can use the hosted Base Sepolia API; writes go through your wallet, RPC, and the deployed contracts.
Base Sepolia Setup
export API_URL=https://api.cortex.wallyweb.com
export RPC_URL=https://sepolia.base.org
export COMMERCE_REGISTRY_ADDRESS=0xf0bf44b28567f0b3d2370dc7af8a63335746d8d4
export AGENT_REGISTRY_ADDRESS=0x24ca7dc7747b0166e73a2d6d99ce677476f046f3
export POLICY_MODULE_ADDRESS=0xb2686c5cc3ab7ce45acfe0091698d9b6a16c2d0c
export INTENT_BOOK_ADDRESS=0x16f7e7c4856bad4dcbE61400630087Dab75B229E| Contract | Address |
|---|---|
| CommerceRegistry | 0xf0bf44b28567f0b3d2370dc7af8a63335746d8d4 |
| AgentRegistry | 0x24ca7dc7747b0166e73a2d6d99ce677476f046f3 |
| PolicyModule | 0xb2686c5cc3ab7ce45acfe0091698d9b6a16c2d0c |
| IntentBook | 0x16f7e7c4856bad4dcbE61400630087Dab75B229E |
Add Yourself as a Merchant
Publish merchant metadata offchain, hash it, then anchor the merchant record onchain.
{
"name": "Example Data Merchant",
"website": "https://merchant.example",
"support": "support@merchant.example",
"payout_chain": "base-sepolia",
"refund_policy": "Refunds available when fulfillment does not match accepted quote terms."
}export MERCHANT_KEY=0x...
export PAYOUT_ADDRESS=0x...
export MERCHANT_METADATA_URI=ipfs://merchant-metadata
export MERCHANT_METADATA_HASH=0x...
cast send "$COMMERCE_REGISTRY_ADDRESS" \
"registerMerchant(address,string,bytes32)" \
"$PAYOUT_ADDRESS" \
"$MERCHANT_METADATA_URI" \
"$MERCHANT_METADATA_HASH" \
--rpc-url "$RPC_URL" \
--private-key "$MERCHANT_KEY"
curl "$API_URL/merchants?owner=0x..."Register a Service
A service is a merchant-owned capability with a metadata URI/hash and capability hash.
export MERCHANT_ID=1
export SERVICE_ID=enrich-company-v1
export SERVICE_METADATA_URI=ipfs://service-metadata
export SERVICE_METADATA_HASH=0x...
export CAPABILITY_HASH=0x...
cast send "$COMMERCE_REGISTRY_ADDRESS" \
"registerService(uint256,string,string,bytes32,bytes32)" \
"$MERCHANT_ID" \
"$SERVICE_ID" \
"$SERVICE_METADATA_URI" \
"$SERVICE_METADATA_HASH" \
"$CAPABILITY_HASH" \
--rpc-url "$RPC_URL" \
--private-key "$MERCHANT_KEY"
curl "$API_URL/services?merchant_id=$MERCHANT_ID&active=true"Register an Agent
export AGENT_KEY=0x...
export AGENT_METADATA_URI=ipfs://agent-metadata
export AGENT_PUBKEY=0xaabb
export AGENT_CAPABILITIES_HASH=0x0000000000000000000000000000000000000000000000000000000000000001
cast send "$AGENT_REGISTRY_ADDRESS" \
"registerAgent(string,bytes,bytes32)" \
"$AGENT_METADATA_URI" \
"$AGENT_PUBKEY" \
"$AGENT_CAPABILITIES_HASH" \
--rpc-url "$RPC_URL" \
--private-key "$AGENT_KEY"
curl "$API_URL/agents/1"Create a Policy Smart Account
In the current repo, PolicyAccount is deployed with an agent signer and the shared policy module. A production app should wrap this in its account factory, bundler, and wallet UX.
const policyAccountHash = await walletClient.deployContract({
abi: PolicyAccountABI,
bytecode: policyAccountBytecode,
args: [agentOwnerAddress, POLICY_MODULE_ADDRESS],
});
const receipt = await publicClient.waitForTransactionReceipt({ hash: policyAccountHash });
const policyAccount = receipt.contractAddress;
await walletClient.writeContract({
address: policyAccount,
abi: PolicyAccountABI,
functionName: "setSpendLimit",
args: [USDC_ADDRESS, 100_000_000n],
});
await walletClient.writeContract({
address: policyAccount,
abi: PolicyAccountABI,
functionName: "setTargetAllowed",
args: [merchantOrRouterAddress, true],
});Allow Facilitator or x402 Payments
export MERCHANT_OWNER=0x...
export TOKEN=0x...
export FACILITATOR=0x...
export MAX_PER_PAYMENT=1000000
export MAX_PER_DAY=10000000
cast send "$POLICY_MODULE_ADDRESS" \
"setSignedPaymentPolicy(address,address,address,uint256,uint256,bool)" \
"$MERCHANT_OWNER" \
"$TOKEN" \
"$FACILITATOR" \
"$MAX_PER_PAYMENT" \
"$MAX_PER_DAY" \
true \
--rpc-url "$RPC_URL" \
--private-key "$AGENT_KEY"Commit a Quote
Quotes bind payment rail, amount, expiry, nonce, resource hash, terms hash, optional x402 payload hash, and zero-fee protocol instrumentation.
const quote = {
merchantId: 1n,
serviceNumericId: 1n,
agent: agentAddress,
token: USDC_ADDRESS,
facilitator: facilitatorAddress,
amount: 1_000_000n,
paymentRail: 3, // 0=transfer, 1=swap, 2=facilitator, 3=x402
expiresAt: BigInt(Math.floor(Date.now() / 1000) + 3600),
paymentNonce: 1n,
resourceHash,
termsHash,
x402PayloadHash,
};
const quoteHash = await publicClient.readContract({
address: COMMERCE_REGISTRY_ADDRESS,
abi: CommerceRegistryABI,
functionName: "computeQuoteHash",
args: [
quote.merchantId,
quote.serviceNumericId,
quote.agent,
quote.token,
quote.facilitator,
quote.amount,
quote.paymentRail,
quote.expiresAt,
quote.paymentNonce,
quote.resourceHash,
quote.termsHash,
quote.x402PayloadHash,
],
});
await walletClient.writeContract({
address: COMMERCE_REGISTRY_ADDRESS,
abi: CommerceRegistryABI,
functionName: "commitQuote",
args: [quote],
});Record a Receipt and Fulfillment
await facilitatorWallet.writeContract({
address: COMMERCE_REGISTRY_ADDRESS,
abi: CommerceRegistryABI,
functionName: "recordReceipt",
args: [quoteHash, resultHash],
});
await merchantWallet.writeContract({
address: COMMERCE_REGISTRY_ADDRESS,
abi: CommerceRegistryABI,
functionName: "recordFulfillment",
args: [receiptId, fulfillmentHash],
});curl "$API_URL/receipts?agent=0x..."
curl "$API_URL/merchants/1/reputation"Submit an Agent Intent with the SDK
import { AgentChainClient } from "@cortex/sdk";
const client = new AgentChainClient({
apiUrl: "https://api.cortex.wallyweb.com",
publicClient,
walletClient,
intentBookAddress: INTENT_BOOK_ADDRESS,
chain: { id: 84532 },
});
const result = await client.createIntent({
intent: {
inputToken: USDC_ADDRESS,
outputToken: OUTPUT_TOKEN,
nonce: BigInt(Date.now()),
constraints: {
amountInMax: 1_000_000n,
amountOutMin: 990_000n,
deadline: BigInt(Math.floor(Date.now() / 1000) + 1800),
slippageBps: 100,
},
},
metadata: {
metadata_uri: "ipfs://intent-metadata",
execution_target: routerAddress,
execution_data: "0x...",
},
preflight: {
account: policyAccountAddress,
target: routerAddress,
value: "0",
data: "0x...",
},
});
const bids = await client.listBids(result.intentId, "open");Agent Runtime Checklist
- Fetch merchant and service state from the API.
- Verify service metadata hashes against fetched metadata documents.
- Check trust signals, disputes, and merchant reputation.
- Confirm quote hash matches local payment/resource/terms payloads.
- For x402, verify
x402PayloadHashagainst the facilitator payment requirement. - Run policy preflight for target calls or signed payment policy.
- Submit payment or intent.
- Wait for receipt and fulfillment indexing.
- Record a dispute or trust signal if fulfillment is invalid.
Run the Full Demo
make e2e
# Testnet demo with funded wallets
cp ops/.env.testnet ops/.env.deployed
cd ops/demo
npm run build
node dist/run.js