sdk-js/examples/express-402-paid-endpoint.js
Liviu 99abfff98a feat(sdk): SDK clients for the 2026-06-08 ship batch
Six new clients (dependency-free EIP-1193 wrappers, precomputed
4-byte selectors, ABI tuple/string encoders inline):

- AereAgentBondClient        — bondOf, isBonded, postBond, requestWithdraw,
                               withdraw, slash; oracle-only on slash
- AereAIReputationClient     — scoreOf, statsOf, attest (delta -1/0/+1)
- AereInferNetClient         — modelEpochCount, registerModel, commitEpoch;
                               EU AI Act Article 12 provider surface
- AereAgentMemoryVaultClient — grant, revoke, write, canReadNow,
                               permissionOf; user-owned namespace
- AereAttestationGatewayClient — publishSchema, setAttestor, attest,
                                 revoke, isValidNow, subjectCurrentlyAttested
- AereCompliancePoolClient   — deposit, withdraw, publishAssociationRoot,
                               setComplianceProvider; Privacy Pools surface

All exported from the package barrel. Zero TS errors.
2026-06-08 03:33:52 +03:00

85 lines
3.1 KiB
JavaScript

// express-402-paid-endpoint.js
//
// Drop-in example: a paid `/v1/inference` endpoint that charges $0.0125
// in USDC.e per call via AERE402 settlement on Chain 2800.
//
// Run:
// yarn add express @aere/sdk-js ethers
// FACILITATOR=0x... PAYEE=0x... PROVIDER_PRIVATE_KEY=0x... node express-402-paid-endpoint.js
//
// Then the agent-side does:
// 1. curl http://localhost:3000/v1/inference
// → 402 with X-AERE402-Quote JSON header
// 2. agent EIP-712-signs the quote using its registered signing key
// 3. curl -H "X-AERE402-Sig: 0x.." -H "X-AERE402-AgentId: 1234" \
// -H "X-AERE402-Quote: <original-quote-json>" \
// http://localhost:3000/v1/inference
// → 200 with the actual inference output, X-AERE402-TxHash header set
const express = require('express');
const { ethers } = require('ethers');
const { createAere402Middleware } = require('@aere/sdk-js');
const FACILITATOR = process.env.FACILITATOR;
const USDC_E = process.env.USDC_E ?? '0x0000000000000000000000000000000000000000';
const PAYEE = process.env.PAYEE;
const PROVIDER_PK = process.env.PROVIDER_PRIVATE_KEY;
const RPC_URL = process.env.RPC_URL ?? 'https://rpc.aere.network';
const CHAIN_ID = parseInt(process.env.CHAIN_ID ?? '2800', 10);
if (!FACILITATOR || !PAYEE || !PROVIDER_PK) {
console.error('FACILITATOR, PAYEE, and PROVIDER_PRIVATE_KEY env vars required');
process.exit(1);
}
const provider = new ethers.JsonRpcProvider(RPC_URL);
const providerWallet = new ethers.Wallet(PROVIDER_PK, provider);
// Real `settle()` ABI from AERE402Facilitator. Pulled minimal — just what we call.
const FAC_ABI = [
'function settle(uint256 agentId, address token, address payee, uint256 amount, bytes32 resourceId, uint256 nonce, uint256 deadline, bytes signature) external',
];
const facContract = new ethers.Contract(FACILITATOR, FAC_ABI, providerWallet);
const charge = createAere402Middleware({
facilitator: FACILITATOR,
chainId: CHAIN_ID,
token: USDC_E,
payee: PAYEE,
pricer: () => 12500n, // $0.0125 in USDC.e (6 decimals)
submit: async (auth, signature) => {
const tx = await facContract.settle(
BigInt(auth.agentId),
auth.token,
auth.payee,
BigInt(auth.amount),
auth.resourceId,
BigInt(auth.nonce),
BigInt(auth.deadline),
signature,
);
const rcpt = await tx.wait();
return rcpt.hash;
},
});
const app = express();
app.get('/v1/inference', charge, (req, res) => {
// The middleware paid us — we can read req.aere402 for receipt info.
const { txHash, auth } = req.aere402;
console.log(`paid call: agent=${auth.agentId} amount=${auth.amount} tx=${txHash}`);
res.json({
output: 'Pretend this is an LLM completion.',
aere402: { txHash, amountCharged: auth.amount, token: auth.token },
});
});
const PORT = parseInt(process.env.PORT ?? '3000', 10);
app.listen(PORT, () => {
console.log(`paid endpoint running at http://localhost:${PORT}/v1/inference`);
console.log(`facilitator: ${FACILITATOR}`);
console.log(`payee: ${PAYEE}`);
console.log(`provider wallet: ${providerWallet.address}`);
});