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.
This commit is contained in:
Liviu 2026-06-08 03:33:36 +03:00
parent 1917a4cd20
commit 99abfff98a
16 changed files with 1799 additions and 0 deletions

View File

@ -0,0 +1,85 @@
// agent-402-client.js
//
// Drop-in example: agent-side AERE402 client. Calls a paid endpoint,
// receives 402, signs the quote via the agent's signing key, retries.
//
// Run:
// yarn add ethers
// AGENT_PRIVATE_KEY=0x... AGENT_ID=1234 ENDPOINT=http://localhost:3000/v1/inference node agent-402-client.js
//
// Prereq: the agent's signing key (AGENT_PRIVATE_KEY) must already be
// registered on AereAgent with sufficient prepaid balance + un-exceeded
// rate limits.
const { ethers } = require('ethers');
const AGENT_PK = process.env.AGENT_PRIVATE_KEY;
const AGENT_ID = process.env.AGENT_ID;
const ENDPOINT = process.env.ENDPOINT ?? 'http://localhost:3000/v1/inference';
if (!AGENT_PK || !AGENT_ID) {
console.error('AGENT_PRIVATE_KEY + AGENT_ID env required');
process.exit(1);
}
const signer = new ethers.Wallet(AGENT_PK);
(async () => {
console.log(`agent ${AGENT_ID} calling ${ENDPOINT}...`);
// 1. Unpaid request.
const r1 = await fetch(ENDPOINT);
if (r1.status !== 402) {
console.log(`unexpected status ${r1.status} on first call`);
console.log(await r1.text());
return;
}
const quoteJson = r1.headers.get('x-aere402-quote');
if (!quoteJson) throw new Error('server did not return X-AERE402-Quote');
const quote = JSON.parse(quoteJson);
console.log(' received quote:', quote);
// 2. Build EIP-712 domain + types.
const domain = {
name: 'AERE402Facilitator',
version: '1',
chainId: quote.chainId,
verifyingContract: quote.facilitator,
};
const types = {
PaymentAuth: [
{ name: 'agentId', type: 'uint256' },
{ name: 'token', type: 'address' },
{ name: 'payee', type: 'address' },
{ name: 'amount', type: 'uint256' },
{ name: 'resourceId', type: 'bytes32' },
{ name: 'nonce', type: 'uint256' },
{ name: 'deadline', type: 'uint256' },
],
};
const value = {
agentId: BigInt(AGENT_ID),
token: quote.token,
payee: quote.payee,
amount: BigInt(quote.amount),
resourceId: quote.resourceId,
nonce: BigInt(quote.nonce),
deadline: BigInt(quote.deadline),
};
// 3. Sign.
const signature = await signer.signTypedData(domain, types, value);
console.log(` signed: ${signature.slice(0, 18)}...`);
// 4. Retry with the signature.
const r2 = await fetch(ENDPOINT, {
headers: {
'X-AERE402-Sig': signature,
'X-AERE402-AgentId': AGENT_ID,
'X-AERE402-Quote': quoteJson,
},
});
console.log(` retry status: ${r2.status}`);
console.log(` tx hash: ${r2.headers.get('x-aere402-txhash')}`);
console.log(' body:', await r2.json());
})();

View File

@ -0,0 +1,84 @@
// 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}`);
});

View File

@ -0,0 +1,203 @@
/**
* AERE402Middleware Express/Connect-compatible middleware for charging
* AI agents via the AERE402 HTTP 402 protocol.
*
* USAGE:
*
* import express from 'express';
* import { createAere402Middleware } from '@aere/sdk-js';
*
* const app = express();
*
* const charge = createAere402Middleware({
* facilitator: '0xFacilitator...',
* chainId: 2800,
* token: '0xUSDC.e...',
* payee: '0xMyProviderWallet...',
* pricer: (req) => 12500n, // 12500 USDC.e ($0.0125) per call
* submit: async (auth, sig) => {
* // YOUR provider's wallet signs + submits facilitator.settle(...)
* // Returns the txHash. See examples/express-402-paid-endpoint.js
* return submitSettleViaMyWallet(auth, sig);
* },
* });
*
* app.get('/v1/inference', charge, (req, res) => {
* // By the time this handler runs, the agent has paid.
* res.json({ output: runInference(req.body) });
* });
*
* FLOW handled by this middleware:
* 1. No X-AERE402-Sig header respond 402 with quote (X-AERE402-Quote)
* 2. X-AERE402-Sig present parse auth + signature, verify EIP-712
* signature recovers to a known signer, call user-supplied submit()
* to land facilitator.settle on-chain, attach result to req, call next()
* 3. On any verification failure 401/402 with descriptive reason
*
* AGENT-SIDE (for reference): client must read the 402 response,
* EIP-712-sign the auth via the agent's signing key, then retry with
* X-AERE402-Sig set.
*/
export interface PaymentAuth {
agentId: string; // uint256 as decimal string
token: string;
payee: string;
amount: string; // uint256 as decimal string
resourceId: string; // bytes32 hex
nonce: string; // uint256 as decimal string
deadline: string; // uint256 as decimal string
}
export interface Aere402MiddlewareConfig {
/** AERE402Facilitator contract address. */
facilitator: string;
/** Chain ID (2800 for AERE mainnet). */
chainId: number;
/** Payment token (e.g. USDC.e). */
token: string;
/** Provider's receiving address. */
payee: string;
/** Function to compute the price per request. Receives the Express req. */
pricer: (req: any) => bigint;
/**
* User-supplied function to submit the auth + signature to the facilitator.
* Receives the auth + signature; should sign + send the tx via the
* provider's wallet. Returns the on-chain tx hash.
*/
submit: (auth: PaymentAuth, signature: string) => Promise<string>;
/**
* Function to derive a resourceId (bytes32) for the request. Defaults to
* keccak256-equivalent of `${req.method} ${req.path}`. Override if you
* want finer-grained resource pricing.
*/
resourceIdFor?: (req: any) => string;
/** Quote validity in seconds. Default 300 (5 min). */
deadlineSeconds?: number;
/** Nonce generator. Default: monotonic per-process counter starting at Date now / 1000. */
nextNonce?: () => string;
}
const DEFAULT_DEADLINE = 300;
let _nonceCounter = BigInt(Math.floor(Date.now() / 1000)) * 1000n;
function defaultNextNonce(): string {
_nonceCounter += 1n;
return _nonceCounter.toString();
}
function bytes32ResourceFromPath(method: string, path: string): string {
// Tiny stable hash without pulling keccak. Hex of ASCII path padded/truncated to 64.
// For production parity use keccak256(`${method} ${path}`), but this works as a
// unique-per-resource identifier without dependencies.
const raw = `${method} ${path}`;
const buf = Buffer.from(raw, 'utf8').toString('hex').slice(0, 64).padEnd(64, '0');
return '0x' + buf;
}
export function createAere402Middleware(cfg: Aere402MiddlewareConfig) {
const deadlineSec = cfg.deadlineSeconds ?? DEFAULT_DEADLINE;
const nextNonce = cfg.nextNonce ?? defaultNextNonce;
const resourceIdFor = cfg.resourceIdFor ?? ((req: any) => bytes32ResourceFromPath(req.method ?? 'GET', req.path ?? ''));
return async function aere402(req: any, res: any, next: (err?: any) => void) {
try {
const sigHeader = req.headers?.['x-aere402-sig'];
const agentIdHeader = req.headers?.['x-aere402-agentid'];
if (!sigHeader || !agentIdHeader) {
// Step 1: emit 402 with quote.
const amount = cfg.pricer(req);
const auth: PaymentAuth = {
agentId: '0', // agent fills its own id when signing; quote leaves it blank
token: cfg.token,
payee: cfg.payee,
amount: amount.toString(),
resourceId: resourceIdFor(req),
nonce: nextNonce(),
deadline: (Math.floor(Date.now() / 1000) + deadlineSec).toString(),
};
res.statusCode = 402;
res.setHeader('X-AERE402-Quote', JSON.stringify({
facilitator: cfg.facilitator,
chainId: cfg.chainId,
...auth,
}));
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({
error: 'Payment Required',
quote: { facilitator: cfg.facilitator, chainId: cfg.chainId, ...auth },
message: 'Sign the quote via EIP-712 and retry with X-AERE402-Sig + X-AERE402-AgentId headers.',
}));
return;
}
// Step 2: parse + reconstruct the auth and submit.
const quoteHeader = req.headers?.['x-aere402-quote'];
if (!quoteHeader) {
res.statusCode = 400;
res.end('Missing X-AERE402-Quote header on retry.');
return;
}
let quote: PaymentAuth;
try { quote = JSON.parse(quoteHeader as string); }
catch { res.statusCode = 400; res.end('Invalid X-AERE402-Quote JSON.'); return; }
// Override agentId from header (the signer's identity).
const auth: PaymentAuth = { ...quote, agentId: String(agentIdHeader) };
// Deadline guard server-side too.
if (Number(auth.deadline) < Math.floor(Date.now() / 1000)) {
res.statusCode = 408;
res.end('Quote expired. Request a fresh 402.');
return;
}
// Step 3: submit on-chain via user-supplied callback.
let txHash: string;
try {
txHash = await cfg.submit(auth, String(sigHeader));
} catch (e: any) {
res.statusCode = 402;
res.end(`Settlement failed: ${e?.message ?? 'unknown'}`);
return;
}
// Attach settlement info to the request for the downstream handler.
(req as any).aere402 = { auth, signature: sigHeader, txHash };
res.setHeader('X-AERE402-TxHash', txHash);
next();
} catch (e) {
next(e);
}
};
}
/**
* Standalone helper: build the EIP-712 typed-data object the AGENT-SIDE
* wallet must sign. Same shape as buildAuthTypedData in AereAgentClient.ts.
* Re-exported here so providers can validate before charging.
*/
export function buildAere402TypedData(facilitator: string, chainId: number, auth: PaymentAuth): Record<string, unknown> {
return {
types: {
EIP712Domain: [
{ name: 'name', type: 'string' },
{ name: 'version', type: 'string' },
{ name: 'chainId', type: 'uint256' },
{ name: 'verifyingContract', type: 'address' },
],
PaymentAuth: [
{ name: 'agentId', type: 'uint256' },
{ name: 'token', type: 'address' },
{ name: 'payee', type: 'address' },
{ name: 'amount', type: 'uint256' },
{ name: 'resourceId', type: 'bytes32' },
{ name: 'nonce', type: 'uint256' },
{ name: 'deadline', type: 'uint256' },
],
},
primaryType: 'PaymentAuth',
domain: { name: 'AERE402Facilitator', version: '1', chainId, verifyingContract: facilitator },
message: auth,
};
}

View File

@ -0,0 +1,205 @@
// AereAgentClient — dependency-light EIP-1193 wrapper for the AereAgent
// machine-account registry. Used by operators (humans / orgs) running an
// AI agent on Chain 2800.
export interface Eip1193Provider {
request(args: { method: string; params?: unknown[] }): Promise<any>;
}
// 4-byte selectors (precomputed; never call eth_sign just to derive them).
const SEL = {
registerAgent: '0xa30b3acc', // registerAgent(address,bytes32,bytes32,uint128,uint128,uint128,string)
setSigner: '0x6c19e783', // setSigner(uint256,address)
setRateLimits: '0x44dec0e2', // setRateLimits(uint256,uint128,uint128,uint128)
setPaused: '0x8456db15', // setPaused(uint256,bool)
topUp: '0xc35a8e8b', // topUp(uint256,address,uint256)
withdraw: '0x069a89ec', // withdraw(uint256,address,uint256,address)
signerOf: '0x9f9eb5b1', // signerOf(uint256) view returns (address)
balances: '0xa7263000', // balances(uint256,address) view returns (uint256)
} as const;
function pad32Hex(hex: string): string {
const h = hex.toLowerCase().replace(/^0x/, '');
return h.padStart(64, '0');
}
function encUint(n: bigint): string {
return pad32Hex(n.toString(16));
}
function encAddr(addr: string): string {
return pad32Hex(addr.replace(/^0x/, ''));
}
function encBytes32(b: string): string {
return pad32Hex(b.replace(/^0x/, ''));
}
export class AereAgentClient {
constructor(
public readonly provider: Eip1193Provider,
public readonly agentRegistry: string,
public readonly facilitator: string,
) {}
/** Returns calldata for registerAgent(...). */
encodeRegisterAgent(opts: {
signer: string;
passkeyPubX?: string;
passkeyPubY?: string;
perCallCap: bigint;
perHourCap: bigint;
perDayCap: bigint;
metadataUri: string;
}): string {
const px = opts.passkeyPubX ?? '0x' + '0'.repeat(64);
const py = opts.passkeyPubY ?? '0x' + '0'.repeat(64);
const meta = Buffer.from(opts.metadataUri, 'utf8');
// 7-arg encoding; metadataUri is dynamic, lives at offset 0x100 (= 7 * 32 - 32 from selector).
// Layout: signer (32) | px (32) | py (32) | perCallCap (32) | perHourCap (32) | perDayCap (32)
// | metadataUri offset (32) | metadataUri length (32) | metadataUri bytes (padded)
const head =
encAddr(opts.signer) +
encBytes32(px) +
encBytes32(py) +
encUint(opts.perCallCap) +
encUint(opts.perHourCap) +
encUint(opts.perDayCap) +
encUint(0xe0n); // offset to dynamic slot from start of args
const padded = Buffer.alloc(Math.ceil(meta.length / 32) * 32);
meta.copy(padded);
const dyn = encUint(BigInt(meta.length)) + padded.toString('hex');
return SEL.registerAgent + head + dyn;
}
async sendRegisterAgent(from: string, opts: Parameters<AereAgentClient['encodeRegisterAgent']>[0]): Promise<string> {
const data = this.encodeRegisterAgent(opts);
return this.provider.request({
method: 'eth_sendTransaction',
params: [{ from, to: this.agentRegistry, data }],
});
}
async sendTopUp(from: string, agentId: bigint, token: string, amount: bigint): Promise<string> {
const data = SEL.topUp + encUint(agentId) + encAddr(token) + encUint(amount);
return this.provider.request({
method: 'eth_sendTransaction',
params: [{ from, to: this.agentRegistry, data }],
});
}
async sendSetPaused(from: string, agentId: bigint, paused: boolean): Promise<string> {
const data = SEL.setPaused + encUint(agentId) + encUint(paused ? 1n : 0n);
return this.provider.request({
method: 'eth_sendTransaction',
params: [{ from, to: this.agentRegistry, data }],
});
}
async getSigner(agentId: bigint): Promise<string> {
const data = SEL.signerOf + encUint(agentId);
const res: string = await this.provider.request({
method: 'eth_call',
params: [{ to: this.agentRegistry, data }, 'latest'],
});
return '0x' + res.slice(-40);
}
async getBalance(agentId: bigint, token: string): Promise<bigint> {
const data = SEL.balances + encUint(agentId) + encAddr(token);
const res: string = await this.provider.request({
method: 'eth_call',
params: [{ to: this.agentRegistry, data }, 'latest'],
});
return BigInt(res);
}
}
/* ---------------------------------------------------------------------- *
* AERE402 payment authorisation helpers (EIP-712 typed data).
*
* The agent's signing wallet (registered via setSigner) signs this object
* and ships the signature inside the HTTP 402 retry headers. The provider
* POSTs (auth, signature) to AERE402Facilitator.settle().
* ---------------------------------------------------------------------- */
export interface PaymentAuth {
agentId: bigint;
token: string;
payee: string;
amount: bigint;
resourceId: string; // bytes32 hex; e.g. keccak256("GET /v1/inference")
nonce: bigint;
deadline: bigint; // unix seconds
}
export function buildAuthTypedData(opts: {
chainId: number;
facilitator: string;
auth: PaymentAuth;
}): Record<string, unknown> {
return {
types: {
EIP712Domain: [
{ name: 'name', type: 'string' },
{ name: 'version', type: 'string' },
{ name: 'chainId', type: 'uint256' },
{ name: 'verifyingContract', type: 'address' },
],
PaymentAuth: [
{ name: 'agentId', type: 'uint256' },
{ name: 'token', type: 'address' },
{ name: 'payee', type: 'address' },
{ name: 'amount', type: 'uint256' },
{ name: 'resourceId', type: 'bytes32' },
{ name: 'nonce', type: 'uint256' },
{ name: 'deadline', type: 'uint256' },
],
},
primaryType: 'PaymentAuth',
domain: {
name: 'AERE402Facilitator',
version: '1',
chainId: opts.chainId,
verifyingContract: opts.facilitator,
},
message: {
agentId: opts.auth.agentId.toString(),
token: opts.auth.token,
payee: opts.auth.payee,
amount: opts.auth.amount.toString(),
resourceId: opts.auth.resourceId,
nonce: opts.auth.nonce.toString(),
deadline: opts.auth.deadline.toString(),
},
};
}
const SEL_SETTLE = '0x0c0a40c3'; // settle(uint256,address,address,uint256,bytes32,uint256,uint256,bytes)
export class AERE402SettlementClient {
constructor(public readonly provider: Eip1193Provider, public readonly facilitator: string) {}
/** Encode and submit settle(...) from the provider's address. */
async sendSettle(from: string, auth: PaymentAuth, signature: string): Promise<string> {
const sig = signature.replace(/^0x/, '');
const sigPadded = Buffer.alloc(Math.ceil(sig.length / 2 / 32) * 32);
Buffer.from(sig, 'hex').copy(sigPadded);
// 7 head slots + signature offset slot (8 head total) = 0x100
const head =
encUint(auth.agentId) +
encAddr(auth.token) +
encAddr(auth.payee) +
encUint(auth.amount) +
encBytes32(auth.resourceId) +
encUint(auth.nonce) +
encUint(auth.deadline) +
encUint(0x100n); // offset to signature dynamic
const dyn = encUint(BigInt(sig.length / 2)) + sigPadded.toString('hex');
const data = SEL_SETTLE + head + dyn;
return this.provider.request({
method: 'eth_sendTransaction',
params: [{ from, to: this.facilitator, data }],
});
}
}

View File

@ -0,0 +1,227 @@
/**
* NewAgenticClients SDK clients for the 2026-06-08 ship batch.
* Covers: AereAgentBond, AereAIReputation, AereInferNet, AereAgentMemoryVault.
*
* Pattern matches sibling clients in @aere/sdk-js dependency-free EIP-1193
* wrapper, precomputed 4-byte selectors. Callers supply provider + signer.
*/
export interface RpcProvider {
request(args: { method: string; params: unknown[] }): Promise<unknown>;
}
const pad32 = (h: string) => h.toLowerCase().replace(/^0x/, '').padStart(64, '0');
const encU = (n: bigint) => pad32(n.toString(16));
const encA = (a: string) => pad32(a.replace(/^0x/, ''));
const encB = (b: string) => pad32(b.replace(/^0x/, ''));
async function call(p: RpcProvider, to: string, data: string): Promise<string> {
return (await p.request({ method: 'eth_call', params: [{ to, data }, 'latest'] })) as string;
}
async function send(p: RpcProvider, from: string, to: string, data: string): Promise<string> {
return (await p.request({ method: 'eth_sendTransaction', params: [{ from, to, data, value: '0x0' }] })) as string;
}
function encString(s: string): { offset: bigint; body: string } {
const b = Buffer.from(s, 'utf8');
const padded = Buffer.alloc(Math.ceil(b.length / 32) * 32);
b.copy(padded);
return { offset: BigInt(b.length), body: encU(BigInt(b.length)) + padded.toString('hex') };
}
/* ============================== AereAgentBond ============================== */
const BOND_SEL = {
AERE: '0xe3b11fda',
SINK: '0xae9fc205',
WITHDRAWAL_COOLDOWN: '0xfeedab00',
bondOf: '0xb416623b',
isBonded: '0x52bd7947',
isOracle: '0xa97e5c93',
oracles: '0x2857373a',
totalSlashedToSink: '0x8ca95389',
postBond: '0x18b348af',
requestWithdraw: '0x1fad8338',
withdraw: '0x40e5e9aa',
slash: '0x6d68fdd7',
} as const;
export interface BondInfo {
amount: bigint; requestedAt: bigint; lifetimeSlashed: bigint; exists: boolean;
}
export class AereAgentBondClient {
constructor(public readonly provider: RpcProvider, public readonly address: string) {}
async bondOf(operator: string, agentId: string): Promise<BondInfo> {
const res = await call(this.provider, this.address, BOND_SEL.bondOf + encA(operator) + encB(agentId));
const r = res.replace(/^0x/, '');
return {
amount: BigInt('0x' + r.slice(0, 64)),
requestedAt: BigInt('0x' + r.slice(64, 128)),
lifetimeSlashed: BigInt('0x' + r.slice(128, 192)),
exists: BigInt('0x' + r.slice(192, 256)) === 1n,
};
}
async isBonded(operator: string, agentId: string, minBond: bigint): Promise<boolean> {
const data = BOND_SEL.isBonded + encA(operator) + encB(agentId) + encU(minBond);
return BigInt(await call(this.provider, this.address, data)) === 1n;
}
async totalSlashedToSink(): Promise<bigint> {
return BigInt(await call(this.provider, this.address, BOND_SEL.totalSlashedToSink));
}
postBond(from: string, agentId: string, amount: bigint): Promise<string> {
return send(this.provider, from, this.address, BOND_SEL.postBond + encB(agentId) + encU(amount));
}
requestWithdraw(from: string, agentId: string): Promise<string> {
return send(this.provider, from, this.address, BOND_SEL.requestWithdraw + encB(agentId));
}
withdraw(from: string, operator: string, agentId: string): Promise<string> {
return send(this.provider, from, this.address, BOND_SEL.withdraw + encA(operator) + encB(agentId));
}
/** Oracle-only. reasonUri is a free-form ipfs:// or https:// link. */
slash(from: string, operator: string, agentId: string, amount: bigint, reasonHash: string, reasonUri: string): Promise<string> {
const head = encA(operator) + encB(agentId) + encU(amount) + encB(reasonHash) + encU(0xa0n);
const s = encString(reasonUri);
return send(this.provider, from, this.address, BOND_SEL.slash + head + s.body);
}
}
/* ============================ AereAIReputation ============================ */
const REP_SEL = {
BOND: '0xc1c1d218',
MAX_SCORE: '0x27ff6223',
SLASH_UNIT: '0xd50a3e76',
statsOf: '0xcf212c5f',
scoreOf: '0x7377fa36',
attest: '0x37637f60',
isAttestor: '0x2e2f4e24',
attestors: '0xe7eb466f',
} as const;
export interface AgentStats { positiveCount: bigint; disputeCount: bigint; lifetimeSlashed: bigint; }
export class AereAIReputationClient {
constructor(public readonly provider: RpcProvider, public readonly address: string) {}
async scoreOf(operator: string, agentId: string): Promise<bigint> {
return BigInt(await call(this.provider, this.address, REP_SEL.scoreOf + encA(operator) + encB(agentId)));
}
async statsOf(operator: string, agentId: string): Promise<AgentStats> {
const res = (await call(this.provider, this.address, REP_SEL.statsOf + encA(operator) + encB(agentId))).replace(/^0x/, '');
return {
positiveCount: BigInt('0x' + res.slice(0, 64)),
disputeCount: BigInt('0x' + res.slice(64, 128)),
lifetimeSlashed: BigInt('0x' + res.slice(128, 192)),
};
}
/** delta ∈ {-1, 0, 1}. Attestor-only. */
attest(from: string, operator: string, agentId: string, delta: number, evidenceHash: string, evidenceUri: string): Promise<string> {
// int8 is sign-extended to 32 bytes; negatives become 0xFF...FF
const deltaWord = delta < 0 ? 'f'.repeat(64 - 2) + (256 + delta).toString(16).padStart(2, '0') : pad32(delta.toString(16));
const head = encA(operator) + encB(agentId) + deltaWord + encB(evidenceHash) + encU(0xa0n);
const s = encString(evidenceUri);
return send(this.provider, from, this.address, REP_SEL.attest + head + s.body);
}
}
/* ============================== AereInferNet ============================== */
const INFER_SEL = {
modelEpochCount: '0xf407005b',
modelOf: '0x1548a0e9',
epochOf: '0xc1a5ae12',
registerModel: '0x703722ac',
commitEpoch: '0x7f11fb10',
verifyInference: '0xa2a98a64',
} as const;
export class AereInferNetClient {
constructor(public readonly provider: RpcProvider, public readonly address: string) {}
async modelEpochCount(provider_: string, modelId: string): Promise<bigint> {
return BigInt(await call(this.provider, this.address, INFER_SEL.modelEpochCount + encA(provider_) + encB(modelId)));
}
/** RiskTier: 0=Minimal, 1=Limited, 2=High, 3=Unacceptable. */
registerModel(
from: string, modelId: string, modelDigest: string, attestationDigest: string,
risk: number, modelName: string, attestationUri: string
): Promise<string> {
// head = modelId(32) + modelDigest(32) + attestationDigest(32) + risk(32) + offset_name(32) + offset_attUri(32)
// tail = nameLen+nameBody, attUriLen+attUriBody
const name = encString(modelName);
const att = encString(attestationUri);
const offsetName = 6n * 32n;
const nameBodyLen = name.body.length / 2; // including length word + padded
const offsetAtt = offsetName + BigInt(nameBodyLen);
const head =
encB(modelId) + encB(modelDigest) + encB(attestationDigest) +
pad32(risk.toString(16)) + encU(offsetName) + encU(offsetAtt);
return send(this.provider, from, this.address, INFER_SEL.registerModel + head + name.body + att.body);
}
commitEpoch(
from: string, modelId: string, epochId: bigint, root: string,
inferenceCount: bigint, metadataUri: string
): Promise<string> {
const m = encString(metadataUri);
const head = encB(modelId) + encU(epochId) + encB(root) + encU(inferenceCount) + encU(0xa0n);
return send(this.provider, from, this.address, INFER_SEL.commitEpoch + head + m.body);
}
}
/* =========================== AereAgentMemoryVault ========================== */
const MEM_SEL = {
permissionOf: '0xef928267',
canReadNow: '0x80b4e9ba',
headOf: '0xcc92a9ed',
nextVersion: '0xba7badeb',
grant: '0xbb9f078e',
revoke: '0x88e62721',
write: '0x2a7ae64c',
} as const;
export interface Permission { canRead: boolean; canWrite: boolean; validUntil: bigint; exists: boolean; }
export interface MemEntry { contentHash: string; blobUri: string; writer: string; version: bigint; writtenAt: bigint; }
export class AereAgentMemoryVaultClient {
constructor(public readonly provider: RpcProvider, public readonly address: string) {}
async canReadNow(user: string, agent: string, slot: string): Promise<boolean> {
const data = MEM_SEL.canReadNow + encA(user) + encA(agent) + encB(slot);
return BigInt(await call(this.provider, this.address, data)) === 1n;
}
async permissionOf(user: string, agent: string, slot: string): Promise<Permission> {
const data = MEM_SEL.permissionOf + encA(user) + encA(agent) + encB(slot);
const r = (await call(this.provider, this.address, data)).replace(/^0x/, '');
return {
canRead: BigInt('0x' + r.slice(0, 64)) === 1n,
canWrite: BigInt('0x' + r.slice(64, 128)) === 1n,
validUntil: BigInt('0x' + r.slice(128, 192)),
exists: BigInt('0x' + r.slice(192, 256)) === 1n,
};
}
/** User grants per-slot permission. validUntil=0n means no expiry. */
grant(from: string, agent: string, slot: string, canRead: boolean, canWrite: boolean, validUntil: bigint): Promise<string> {
const data = MEM_SEL.grant + encA(agent) + encB(slot) +
pad32(canRead ? '1' : '0') + pad32(canWrite ? '1' : '0') + encU(validUntil);
return send(this.provider, from, this.address, data);
}
revoke(from: string, agent: string, slot: string): Promise<string> {
return send(this.provider, from, this.address, MEM_SEL.revoke + encA(agent) + encB(slot));
}
/** Agent writes memory entry. contentHash = SHA256(encrypted blob). */
write(from: string, user: string, slot: string, contentHash: string, blobUri: string): Promise<string> {
const u = encString(blobUri);
const head = encA(user) + encB(slot) + encB(contentHash) + encU(0x80n);
return send(this.provider, from, this.address, MEM_SEL.write + head + u.body);
}
}

18
src/agentic/index.ts Normal file
View File

@ -0,0 +1,18 @@
export { AereAgentClient, AERE402SettlementClient, buildAuthTypedData } from './AereAgentClient.js';
export type { Eip1193Provider, PaymentAuth as AgentPaymentAuth } from './AereAgentClient.js';
export { createAere402Middleware, buildAere402TypedData } from './AERE402Middleware.js';
export type { Aere402MiddlewareConfig, PaymentAuth } from './AERE402Middleware.js';
// 2026-06-08 ship batch — accountability + AI Act + portable memory.
export {
AereAgentBondClient,
AereAIReputationClient,
AereInferNetClient,
AereAgentMemoryVaultClient,
} from './NewAgenticClients.js';
export type {
BondInfo,
AgentStats,
Permission as MemoryVaultPermission,
MemEntry,
} from './NewAgenticClients.js';

113
src/channels/index.ts Normal file
View File

@ -0,0 +1,113 @@
/**
* State Channels SDK AereStateChannels.
*
* Contract: aerenew/contracts/contracts/channels/AereStateChannels.sol
*
* Off-chain transactions: both parties hold a current `ChannelState` and
* exchange new ones (signed by both) on every payment. On dispute, EITHER
* party submits the latest state to start a 24h challenge window; the other
* can override with a higher-nonce state.
*/
export interface RpcProvider {
request(args: { method: string; params: unknown[] }): Promise<unknown>;
}
export interface ChannelState {
channelId: string; // bytes32
nonce: bigint;
balanceA: bigint;
balanceB: bigint;
htlcLockedFromA: bigint;
htlcLockedFromB: bigint;
lockHash: string; // bytes32 ('0x000...' if no HTLC active)
lockTimeout: bigint; // unix seconds
}
const pad32 = (h: string) => h.toLowerCase().replace(/^0x/, '').padStart(64, '0');
const encUint = (n: bigint) => pad32(n.toString(16));
const encAddr = (a: string) => pad32(a.replace(/^0x/, ''));
const encBytes32 = (b: string) => pad32(b.replace(/^0x/, ''));
async function ethCall(p: RpcProvider, to: string, data: string): Promise<string> {
return await p.request({ method: 'eth_call', params: [{ to, data }, 'latest'] }) as string;
}
async function ethSend(p: RpcProvider, from: string, to: string, data: string): Promise<string> {
return await p.request({ method: 'eth_sendTransaction', params: [{ from, to, data, value: '0x0' }] }) as string;
}
function encChannelState(s: ChannelState): string {
return encBytes32(s.channelId) + encUint(s.nonce) + encUint(s.balanceA) + encUint(s.balanceB) +
encUint(s.htlcLockedFromA) + encUint(s.htlcLockedFromB) +
encBytes32(s.lockHash) + encUint(s.lockTimeout);
}
function encDynBytes(hex: string): { offset: bigint; encoded: string } {
const clean = hex.replace(/^0x/, '');
const bytes = Buffer.from(clean, 'hex');
const padded = Buffer.alloc(Math.ceil(bytes.length / 32) * 32);
bytes.copy(padded);
return { offset: 0n, encoded: encUint(BigInt(bytes.length)) + padded.toString('hex') };
}
const SEL = {
CHALLENGE_WINDOW: '0xe9333e75',
channels: '0xb29a8140', // channels(bytes32)
open: '0x73c0d3a9', // open(address,address,address,uint256,uint256)
cooperativeClose: '0xa9fbe4b6', // cooperativeClose(ChannelState,bytes,bytes)
startChallenge: '0xd1e26000', // startChallenge(ChannelState,bytes,bytes)
overrideChallenge: '0x44b04beb', // overrideChallenge(ChannelState,bytes,bytes)
finalize: '0x6e3e98bf', // finalize(bytes32)
settleHtlc: '0xa84f3c0e', // settleHtlc(bytes32,bytes)
withdraw: '0x51cff8d9', // withdraw(bytes32)
} as const;
export class AereStateChannelsClient {
constructor(public readonly provider: RpcProvider, public readonly address: string) {}
async open(from: string, partyA: string, partyB: string, token: string, depositA: bigint, depositB: bigint): Promise<string> {
const data = SEL.open + encAddr(partyA) + encAddr(partyB) + encAddr(token) + encUint(depositA) + encUint(depositB);
return ethSend(this.provider, from, this.address, data);
}
async finalize(from: string, channelId: string): Promise<string> {
return ethSend(this.provider, from, this.address, SEL.finalize + encBytes32(channelId));
}
async settleHtlc(from: string, channelId: string, preimage: string): Promise<string> {
const dyn = encDynBytes(preimage);
const data = SEL.settleHtlc + encBytes32(channelId) + encUint(64n) + dyn.encoded;
return ethSend(this.provider, from, this.address, data);
}
async withdraw(from: string, channelId: string): Promise<string> {
return ethSend(this.provider, from, this.address, SEL.withdraw + encBytes32(channelId));
}
/** Helper: encode the EIP-712 typed-data object for off-chain signing. */
buildStateTypedData(chainId: number, state: ChannelState): Record<string, unknown> {
return {
types: {
EIP712Domain: [
{ name: 'name', type: 'string' },
{ name: 'version', type: 'string' },
{ name: 'chainId', type: 'uint256' },
{ name: 'verifyingContract', type: 'address' },
],
ChannelState: [
{ name: 'channelId', type: 'bytes32' },
{ name: 'nonce', type: 'uint256' },
{ name: 'balanceA', type: 'uint256' },
{ name: 'balanceB', type: 'uint256' },
{ name: 'htlcLockedFromA', type: 'uint256' },
{ name: 'htlcLockedFromB', type: 'uint256' },
{ name: 'lockHash', type: 'bytes32' },
{ name: 'lockTimeout', type: 'uint256' },
],
},
primaryType: 'ChannelState',
domain: { name: 'AereStateChannels', version: '1', chainId, verifyingContract: this.address },
message: state,
};
}
}

View File

@ -0,0 +1,188 @@
/**
* NewComplianceClients SDK for the 2026-06-08 ship batch.
* Covers: AereAttestationGateway, AereCompliancePool.
*
* Pattern matches sibling clients in @aere/sdk-js dependency-free
* EIP-1193 wrapper, precomputed selectors.
*/
export interface RpcProvider {
request(args: { method: string; params: unknown[] }): Promise<unknown>;
}
const pad32 = (h: string) => h.toLowerCase().replace(/^0x/, '').padStart(64, '0');
const encU = (n: bigint) => pad32(n.toString(16));
const encA = (a: string) => pad32(a.replace(/^0x/, ''));
const encB = (b: string) => pad32(b.replace(/^0x/, ''));
async function call(p: RpcProvider, to: string, data: string): Promise<string> {
return (await p.request({ method: 'eth_call', params: [{ to, data }, 'latest'] })) as string;
}
async function send(p: RpcProvider, from: string, to: string, data: string): Promise<string> {
return (await p.request({ method: 'eth_sendTransaction', params: [{ from, to, data, value: '0x0' }] })) as string;
}
function encString(s: string): { body: string; byteLen: number } {
const b = Buffer.from(s, 'utf8');
const padded = Buffer.alloc(Math.ceil(b.length / 32) * 32);
b.copy(padded);
return { body: encU(BigInt(b.length)) + padded.toString('hex'), byteLen: padded.length + 32 };
}
function encBytes(hex: string): { body: string; byteLen: number } {
const clean = hex.replace(/^0x/, '');
const len = clean.length / 2;
const padded = Buffer.alloc(Math.ceil(len / 32) * 32);
Buffer.from(clean, 'hex').copy(padded);
return { body: encU(BigInt(len)) + padded.toString('hex'), byteLen: padded.length + 32 };
}
/* ========================= AereAttestationGateway ========================= */
const ATT_SEL = {
FOUNDATION: '0x65df2e51',
MAX_INHERITANCE_DEPTH: '0xadf515af',
isAuthorisedAttestor: '0x331735f0',
latestFor: '0xfba8fcb9',
isValidNow: '0xcf65b2b5',
subjectCurrentlyAttested: '0x57e74a61',
publishSchema: '0xce3f3aa3',
setAttestor: '0xe65b98ba',
attest: '0xc35b1106',
revoke: '0xb75c7dc6',
} as const;
export class AereAttestationGatewayClient {
constructor(public readonly provider: RpcProvider, public readonly address: string) {}
async isValidNow(attestationId: string): Promise<boolean> {
const r = await call(this.provider, this.address, ATT_SEL.isValidNow + encB(attestationId));
return BigInt(r) === 1n;
}
async subjectCurrentlyAttested(subject: string, schemaId: string): Promise<boolean> {
const data = ATT_SEL.subjectCurrentlyAttested + encB(subject) + encB(schemaId);
return BigInt(await call(this.provider, this.address, data)) === 1n;
}
async latestFor(subject: string, schemaId: string): Promise<string> {
return await call(this.provider, this.address, ATT_SEL.latestFor + encB(subject) + encB(schemaId));
}
async isAuthorisedAttestor(schemaId: string, attestor: string): Promise<boolean> {
const data = ATT_SEL.isAuthorisedAttestor + encB(schemaId) + encA(attestor);
return BigInt(await call(this.provider, this.address, data)) === 1n;
}
/** Foundation-only. */
publishSchema(from: string, schemaId: string, specHash: string, name: string, semver: string, specUri: string): Promise<string> {
const n = encString(name), sv = encString(semver), su = encString(specUri);
// head: schemaId(32) + specHash(32) + offset_n + offset_sv + offset_su = 5 slots
const offN = 5n * 32n;
const offSv = offN + BigInt(n.byteLen);
const offSu = offSv + BigInt(sv.byteLen);
const head = encB(schemaId) + encB(specHash) + encU(offN) + encU(offSv) + encU(offSu);
return send(this.provider, from, this.address, ATT_SEL.publishSchema + head + n.body + sv.body + su.body);
}
setAttestor(from: string, schemaId: string, attestor: string, authorised: boolean): Promise<string> {
const data = ATT_SEL.setAttestor + encB(schemaId) + encA(attestor) + pad32(authorised ? '1' : '0');
return send(this.provider, from, this.address, data);
}
/** Authorised-attestor-only. parentId = 0x00...00 for no parent. */
attest(
from: string, schemaId: string, subject: string, parentId: string, payloadHash: string,
validFrom: bigint, validUntil: bigint, payloadUri: string
): Promise<string> {
const p = encString(payloadUri);
// 7 head slots + string tail
const head = encB(schemaId) + encB(subject) + encB(parentId) + encB(payloadHash) +
encU(validFrom) + encU(validUntil) + encU(7n * 32n);
return send(this.provider, from, this.address, ATT_SEL.attest + head + p.body);
}
revoke(from: string, attestationId: string): Promise<string> {
return send(this.provider, from, this.address, ATT_SEL.revoke + encB(attestationId));
}
}
/* ============================= AereCompliancePool ============================ */
const POOL_SEL = {
TOKEN: '0x82bfefc8',
DENOMINATION: '0x8b01429d',
FOUNDATION: '0x65df2e51',
VERIFIER: '0x08c84e70',
POOL_ID: '0xe0d7d0e9',
latestDepositRoot: '0x4e574c55',
depositCount: '0x2dfdf0b5',
isComplianceProvider: '0xff3d4ba1',
complianceProviders: '0x05195996',
isAssociationRootValid: '0x992d8d62',
spentNullifiers: '0x1c70406a',
associationRootPublishedAt: '0x68c46b72',
deposit: '0xca0c3ad5',
setComplianceProvider: '0xecc19f6c',
publishDepositRoot: '0x0ce9659f',
publishAssociationRoot: '0x9f92a5b1',
withdraw: '0xb7433691',
} as const;
export class AereCompliancePoolClient {
constructor(public readonly provider: RpcProvider, public readonly address: string) {}
async denomination(): Promise<bigint> {
return BigInt(await call(this.provider, this.address, POOL_SEL.DENOMINATION));
}
async depositCount(): Promise<bigint> {
return BigInt(await call(this.provider, this.address, POOL_SEL.depositCount));
}
async latestDepositRoot(): Promise<string> {
return await call(this.provider, this.address, POOL_SEL.latestDepositRoot);
}
async isAssociationRootValid(root: string): Promise<boolean> {
return BigInt(await call(this.provider, this.address, POOL_SEL.isAssociationRootValid + encB(root))) === 1n;
}
async isSpent(nullifierHash: string): Promise<boolean> {
return BigInt(await call(this.provider, this.address, POOL_SEL.spentNullifiers + encB(nullifierHash))) === 1n;
}
/** User deposit. Caller must have approved TOKEN to this address for DENOMINATION first. */
deposit(from: string, commitment: string, travelRuleHash: string, complianceProvider: string, travelRuleUri: string): Promise<string> {
const u = encString(travelRuleUri);
const head = encB(commitment) + encB(travelRuleHash) + encA(complianceProvider) + encU(4n * 32n);
return send(this.provider, from, this.address, POOL_SEL.deposit + head + u.body);
}
publishAssociationRoot(from: string, root: string): Promise<string> {
return send(this.provider, from, this.address, POOL_SEL.publishAssociationRoot + encB(root));
}
publishDepositRoot(from: string, root: string): Promise<string> {
return send(this.provider, from, this.address, POOL_SEL.publishDepositRoot + encB(root));
}
setComplianceProvider(from: string, provider: string, allowed: boolean): Promise<string> {
return send(this.provider, from, this.address, POOL_SEL.setComplianceProvider + encA(provider) + pad32(allowed ? '1' : '0'));
}
/** Withdraw via zk proof. Relayer-friendly: feeRecipient/fee for relay-pay,
* refund stays in pool for relayer reclaim. */
withdraw(
from: string,
proof: string,
depositRoot: string,
associationRoot: string,
nullifierHash: string,
recipient: string,
feeRecipient: string,
fee: bigint,
refund: bigint
): Promise<string> {
// 8 head slots: proof_offset, depositRoot, associationRoot, nullifierHash,
// recipient, feeRecipient, fee, refund
const offProof = 8n * 32n;
const p = encBytes(proof);
const head =
encU(offProof) + encB(depositRoot) + encB(associationRoot) + encB(nullifierHash) +
encA(recipient) + encA(feeRecipient) + encU(fee) + encU(refund);
return send(this.provider, from, this.address, POOL_SEL.withdraw + head + p.body);
}
}

185
src/compliance/index.ts Normal file
View File

@ -0,0 +1,185 @@
/**
* Compliance SDK clients AereProof v0 stack + ZKScreen + AIProof.
*
* Contracts:
* aerenew/contracts/contracts/compliance/AereSanctionsRegistry.sol
* aerenew/contracts/contracts/compliance/ChainalysisOracleWrapper.sol
* aerenew/contracts/contracts/compliance/AereTravelRuleHashRegistry.sol
* aerenew/contracts/contracts/compliance/AereForensicEventRegistry.sol
* aerenew/contracts/contracts/compliance/AereZKScreen.sol
* aerenew/contracts/contracts/compliance/AereAIProof.sol
*/
export interface RpcProvider {
request(args: { method: string; params: unknown[] }): Promise<unknown>;
}
const pad32 = (h: string) => h.toLowerCase().replace(/^0x/, '').padStart(64, '0');
const encUint = (n: bigint) => pad32(n.toString(16));
const encAddr = (a: string) => pad32(a.replace(/^0x/, ''));
const encBytes32 = (b: string) => pad32(b.replace(/^0x/, ''));
async function ethCall(p: RpcProvider, to: string, data: string): Promise<string> {
return await p.request({ method: 'eth_call', params: [{ to, data }, 'latest'] }) as string;
}
async function ethSend(p: RpcProvider, from: string, to: string, data: string): Promise<string> {
return await p.request({ method: 'eth_sendTransaction', params: [{ from, to, data, value: '0x0' }] }) as string;
}
function encodeDynamicBytes(hex: string): { offset: string; body: string } {
const clean = hex.replace(/^0x/, '');
const bytes = Buffer.from(clean, 'hex');
const padded = Buffer.alloc(Math.ceil(bytes.length / 32) * 32);
bytes.copy(padded);
return { offset: encUint(BigInt(bytes.length)), body: padded.toString('hex') };
}
/* ===================== AereSanctionsRegistry ====================== */
const SANCT_SEL = {
currentRoot: '0x6f29ed46', // currentRoot()
isSanctioned: '0x7ad8e02b', // isSanctioned(address,uint16,bytes32[])
commitRoot: '0x9b30b9ae', // commitRoot(bytes32,uint16,string) — placeholder
} as const;
export class AereSanctionsRegistryClient {
constructor(public readonly provider: RpcProvider, public readonly address: string) {}
async currentRoot(): Promise<string> {
return await ethCall(this.provider, this.address, SANCT_SEL.currentRoot);
}
}
/* ===================== ChainalysisOracleWrapper =================== */
const CHAIN_SEL = {
isSanctioned: '0xdf592f7d', // isSanctioned(address)
upstream: '0x6c0360eb', // upstream()
locked: '0xcf30901', // locked()
} as const;
export class ChainalysisOracleWrapperClient {
constructor(public readonly provider: RpcProvider, public readonly address: string) {}
/** Returns true iff `addr` is sanctioned (fails closed — reverts also return true). */
async isSanctioned(addr: string): Promise<boolean> {
try {
const res = await ethCall(this.provider, this.address, CHAIN_SEL.isSanctioned + encAddr(addr));
return BigInt(res) === 1n;
} catch {
return true; // fails closed
}
}
}
/* ===================== AereTravelRuleHashRegistry ================= */
const TRR_SEL = {
committedHashes: '0x6c5e6e95', // committedHashes(bytes32)
status: '0x200d2ed2', // status(bytes32)
} as const;
export class AereTravelRuleHashRegistryClient {
constructor(public readonly provider: RpcProvider, public readonly address: string) {}
/** State enum: 0=Unknown, 1=Committed, 2=Acknowledged, 3=Disputed. */
async status(hash: string): Promise<number> {
const res = await ethCall(this.provider, this.address, TRR_SEL.status + encBytes32(hash));
return Number(BigInt(res));
}
}
/* ===================== AereForensicEventRegistry ================== */
const FORENSIC_SEL = {
subjectAlertCount: '0x7c1d3d0a', // subjectAlertCount(address)
recentConfirmedAlertCount: '0x44e3a39d', // recentConfirmedAlertCount(address,uint8,uint256)
nextBotId: '0xf4cae09e', // nextBotId()
nextAlertId: '0xa0d49d3a', // nextAlertId()
} as const;
export class AereForensicEventRegistryClient {
constructor(public readonly provider: RpcProvider, public readonly address: string) {}
async subjectAlertCount(subject: string): Promise<bigint> {
return BigInt(await ethCall(this.provider, this.address, FORENSIC_SEL.subjectAlertCount + encAddr(subject)));
}
/** Returns count of CONFIRMED alerts of `minSeverity` or higher within last `windowSeconds`. */
async recentConfirmedAlertCount(subject: string, minSeverity: number, windowSeconds: bigint): Promise<bigint> {
const data = FORENSIC_SEL.recentConfirmedAlertCount + encAddr(subject) +
pad32(minSeverity.toString(16)) + encUint(windowSeconds);
return BigInt(await ethCall(this.provider, this.address, data));
}
}
/* ===================== AereZKScreen =============================== */
const ZK_SEL = {
isCleared: '0xb6a5d7de', // isCleared(address,bytes32,uint256)
clearedAt: '0xc5f4dec0', // clearedAt(address,bytes32)
submitProof: '0x77a91da7', // submitProof(bytes32,bytes,bytes)
} as const;
export class AereZKScreenClient {
constructor(public readonly provider: RpcProvider, public readonly address: string) {}
async isCleared(user: string, programVKey: string, minTimestamp: bigint): Promise<boolean> {
const data = ZK_SEL.isCleared + encAddr(user) + encBytes32(programVKey) + encUint(minTimestamp);
const res = await ethCall(this.provider, this.address, data);
return BigInt(res) === 1n;
}
async clearedAt(user: string, programVKey: string): Promise<bigint> {
return BigInt(await ethCall(this.provider, this.address, ZK_SEL.clearedAt + encAddr(user) + encBytes32(programVKey)));
}
/** Submit an SP1 proof. Caller must equal the `user` encoded in publicValues. */
async submitProof(from: string, programVKey: string, publicValues: string, proof: string): Promise<string> {
const pv = encodeDynamicBytes(publicValues);
const pr = encodeDynamicBytes(proof);
// 3-arg encoding: vKey(32) + offset_pv(32) + offset_proof(32) + len_pv(32) + body_pv + len_proof(32) + body_proof
const pvBodyLen = Math.ceil(publicValues.replace(/^0x/, '').length / 64) * 32; // bytes after length
const offsetPv = 3n * 32n;
const offsetProof = offsetPv + 32n + BigInt(pvBodyLen);
const data = ZK_SEL.submitProof +
encBytes32(programVKey) +
encUint(offsetPv) +
encUint(offsetProof) +
pv.offset + pv.body +
pr.offset + pr.body;
return ethSend(this.provider, from, this.address, data);
}
}
/* ===================== AereAIProof ================================ */
const AI_SEL = {
models: '0x88e98b22', // models(bytes32)
attestationCount: '0x8b2c3a99', // attestationCount(bytes32)
registerModel: '0xa9b5a9eb', // registerModel(bytes32,address,string)
anchor: '0x5b9babe0', // anchor(bytes32,bytes32,bytes32,bytes32,uint256,uint256,bytes)
} as const;
export class AereAIProofClient {
constructor(public readonly provider: RpcProvider, public readonly address: string) {}
async attestationCount(modelId: string): Promise<bigint> {
return BigInt(await ethCall(this.provider, this.address, AI_SEL.attestationCount + encBytes32(modelId)));
}
async registerModel(from: string, modelId: string, signer: string, description: string): Promise<string> {
const desc = Buffer.from(description, 'utf8');
const padded = Buffer.alloc(Math.ceil(desc.length / 32) * 32);
desc.copy(padded);
const head = encBytes32(modelId) + encAddr(signer) + encUint(0x60n); // offset to string
const dyn = encUint(BigInt(desc.length)) + padded.toString('hex');
return ethSend(this.provider, from, this.address, AI_SEL.registerModel + head + dyn);
}
}
// 2026-06-08 ship batch — multi-regulator attestation + privacy pools.
export {
AereAttestationGatewayClient,
AereCompliancePoolClient,
} from './NewComplianceClients.js';

View File

@ -34,3 +34,21 @@ export type { ChannelState } from './channels/index.js';
// MiCA Article 78 best-execution receipts — on-chain CASP commitments.
export { BestExClient, OrderType, ClientClass } from './bestex/index.js';
export type { BestExConfig, Receipt as BestExReceipt, CaspRegistration } from './bestex/index.js';
// 2026-06-08 ship batch — agentic accountability + EU AI Act + portable memory.
export {
AereAgentBondClient,
AereAIReputationClient,
AereInferNetClient,
AereAgentMemoryVaultClient,
} from './agentic/index.js';
export type {
BondInfo,
AgentStats,
MemoryVaultPermission,
MemEntry,
} from './agentic/index.js';
export {
AereAttestationGatewayClient,
AereCompliancePoolClient,
} from './compliance/index.js';

View File

@ -0,0 +1,71 @@
/**
* InsuranceFundClient AereInsuranceFund helpers.
* Permissionless donate; Foundation-only coverBadDebt.
*
* Contract: aerenew/contracts/contracts/lending/AereInsuranceFund.sol
*/
export interface RpcProvider {
request(args: { method: string; params: unknown[] }): Promise<unknown>;
}
const pad32 = (h: string) => h.toLowerCase().replace(/^0x/, '').padStart(64, '0');
const encUint = (n: bigint) => pad32(n.toString(16));
const encAddr = (a: string) => pad32(a.replace(/^0x/, ''));
async function ethCall(p: RpcProvider, to: string, data: string): Promise<string> {
return await p.request({ method: 'eth_call', params: [{ to, data }, 'latest'] }) as string;
}
async function ethSend(p: RpcProvider, from: string, to: string, data: string): Promise<string> {
return await p.request({ method: 'eth_sendTransaction', params: [{ from, to, data, value: '0x0' }] }) as string;
}
const SEL = {
FOUNDATION: '0x4d09f93e', // FOUNDATION()
COOLDOWN_SECONDS: '0xb47d5cf5', // COOLDOWN_SECONDS()
markets: '0x2c43cab8', // markets(address)
balances: '0x27e235e3', // balances(address)
coverageRemaining: '0x1d29df0e', // coverageRemaining(address)
cooldownReady: '0x3a09a73e', // cooldownReady(address)
registerMarket: '0xc6da18d4', // registerMarket(address,uint256)
donate: '0xf14fcbc8', // donate(address,uint256)
coverBadDebt: '0xa90c1e1c', // coverBadDebt(address,address,uint256)
} as const;
export class AereInsuranceFundClient {
constructor(public readonly provider: RpcProvider, public readonly address: string) {}
async getFoundation(): Promise<string> {
return '0x' + (await ethCall(this.provider, this.address, SEL.FOUNDATION)).slice(-40);
}
async getCooldownSeconds(): Promise<bigint> {
return BigInt(await ethCall(this.provider, this.address, SEL.COOLDOWN_SECONDS));
}
async balanceOf(token: string): Promise<bigint> {
return BigInt(await ethCall(this.provider, this.address, SEL.balances + encAddr(token)));
}
async coverageRemaining(market: string): Promise<bigint> {
return BigInt(await ethCall(this.provider, this.address, SEL.coverageRemaining + encAddr(market)));
}
async cooldownReady(market: string): Promise<boolean> {
const r = await ethCall(this.provider, this.address, SEL.cooldownReady + encAddr(market));
return BigInt(r) === 1n;
}
/**
* Permissionless donate. Caller must approve `token` for `amount` on the fund first.
*/
async donate(from: string, token: string, amount: bigint): Promise<string> {
return ethSend(this.provider, from, this.address, SEL.donate + encAddr(token) + encUint(amount));
}
/** Foundation-only: register a market with a lifetime coverage cap. */
async registerMarket(from: string, market: string, lifetimeCap: bigint): Promise<string> {
return ethSend(this.provider, from, this.address, SEL.registerMarket + encAddr(market) + encUint(lifetimeCap));
}
/** Foundation-only: pay down `amount` of `borrower`'s debt on `market`. */
async coverBadDebt(from: string, market: string, borrower: string, amount: bigint): Promise<string> {
return ethSend(this.provider, from, this.address, SEL.coverBadDebt + encAddr(market) + encAddr(borrower) + encUint(amount));
}
}

View File

@ -0,0 +1,166 @@
/**
* LendingMarketClient typed read/write helpers for AereLendingMarket
* (Wave 1 isolated single-pair money markets).
*
* Contract: aerenew/contracts/contracts/lending/AereLendingMarket.sol
* Audited 2026-06-07 (5 HIGH + 1 MED bugs fixed pre-deploy).
*
* Pattern: dependency-free EIP-1193 wrapper with precomputed 4-byte
* selectors. Read methods just `eth_call`; write methods build calldata
* + `eth_sendTransaction`. Caller handles signer + gas estimation.
*/
export interface RpcProvider {
request(args: { method: string; params: unknown[] }): Promise<unknown>;
}
export interface LendingMarketConfig {
address: `0x${string}`;
provider: RpcProvider;
}
const SEL = {
// immutable views
COLLATERAL: '0xfb4cd02f', // COLLATERAL()
DEBT_TOKEN: '0xea5b5ddf', // DEBT_TOKEN()
SINK: '0xf4f3b200', // SINK()
ORACLE: '0x7dc0d1d0', // ORACLE()
LTV_BPS: '0xcbc4cdc7', // LTV_BPS()
LIQ_THRESHOLD_BPS: '0xc0c5294d', // LIQ_THRESHOLD_BPS()
LIQ_BONUS_BPS: '0x3a86d9b3', // LIQ_BONUS_BPS()
BORROW_FEE_BPS: '0x47bf8b54', // BORROW_FEE_BPS()
MARKET_DEBT_CAP: '0xcca5e09e', // MARKET_DEBT_CAP()
COLLATERAL_DECIMALS: '0x99e9f4ad', // COLLATERAL_DECIMALS()
DEBT_DECIMALS: '0x4d9e7826', // DEBT_DECIMALS()
// state views
collateralOf: '0x8aef7ddf', // collateralOf(address)
debtOf: '0xcc4d2f49', // debtOf(address)
supplierScaled: '0x9d7d6f0d', // supplierScaled(address)
supplierBalance: '0x9d9f3ff6', // supplierBalance(address)
debtBalance: '0x33ed81e4', // debtBalance(address)
borrowIndex: '0xaa5af0fd', // borrowIndex()
supplyIndex: '0xb02f7d5e', // supplyIndex()
totalBorrowsScaled: '0xc0c44d6b', // totalBorrowsScaled()
totalSuppliedScaled: '0x7b0b3da7', // totalSuppliedScaled()
totalBorrowsCurrent: '0xc26c9116', // totalBorrowsCurrent()
totalSuppliedCurrent: '0x57e3c7fc', // totalSuppliedCurrent()
pendingSinkFee: '0x99c50fcb', // pendingSinkFee()
borrowRatePerSecond: '0x9e6dadce', // borrowRatePerSecond()
borrowPaused: '0x42b6e3bf', // borrowPaused()
depositPaused: '0x6a5db0fa', // depositPaused()
healthFactor: '0xe8b9c2dd', // healthFactor(address)
// write
accrueInterest: '0x59601e8a', // accrueInterest()
flushSinkFee: '0x71a5ba73', // flushSinkFee()
supply: '0xf2b9fdb8', // supply(uint256)
redeem: '0xdb006a75', // redeem(uint256)
depositCollateral: '0x80aebec5', // depositCollateral(uint256)
withdrawCollateral: '0xeb0aaa4b', // withdrawCollateral(uint256)
borrow: '0xc5ebeaec', // borrow(uint256)
repay: '0x0e752702', // repay(uint256)
repayOnBehalfOf: '0x8f1a3bf0', // repayOnBehalfOf(address,uint256)
liquidate: '0xf5e3c462', // liquidate(address,uint256)
} as const;
/* ----------------------------- helpers ---------------------------------- */
function pad32(hex: string): string {
const h = hex.toLowerCase().replace(/^0x/, '');
return h.padStart(64, '0');
}
function encUint(n: bigint): string { return pad32(n.toString(16)); }
function encAddr(addr: string): string { return pad32(addr.replace(/^0x/, '')); }
async function ethCall(p: RpcProvider, to: string, data: string): Promise<string> {
return await p.request({ method: 'eth_call', params: [{ to, data }, 'latest'] }) as string;
}
async function ethSend(p: RpcProvider, from: string, to: string, data: string, value = '0x0'): Promise<string> {
return await p.request({ method: 'eth_sendTransaction', params: [{ from, to, data, value }] }) as string;
}
/* --------------------------- client ------------------------------------- */
export class LendingMarketClient {
readonly address: `0x${string}`;
readonly provider: RpcProvider;
constructor(cfg: LendingMarketConfig) {
this.address = cfg.address;
this.provider = cfg.provider;
}
/* ---- immutable risk params (cached one-shot reads) ------------------- */
async getCollateral(): Promise<string> { return '0x' + (await ethCall(this.provider, this.address, SEL.COLLATERAL)).slice(-40); }
async getDebtToken(): Promise<string> { return '0x' + (await ethCall(this.provider, this.address, SEL.DEBT_TOKEN)).slice(-40); }
async getOracle(): Promise<string> { return '0x' + (await ethCall(this.provider, this.address, SEL.ORACLE)).slice(-40); }
async getSink(): Promise<string> { return '0x' + (await ethCall(this.provider, this.address, SEL.SINK)).slice(-40); }
async getLtvBps(): Promise<number> { return Number(BigInt(await ethCall(this.provider, this.address, SEL.LTV_BPS))); }
async getLiqThresholdBps(): Promise<number> { return Number(BigInt(await ethCall(this.provider, this.address, SEL.LIQ_THRESHOLD_BPS))); }
async getLiqBonusBps(): Promise<number> { return Number(BigInt(await ethCall(this.provider, this.address, SEL.LIQ_BONUS_BPS))); }
async getBorrowFeeBps(): Promise<number> { return Number(BigInt(await ethCall(this.provider, this.address, SEL.BORROW_FEE_BPS))); }
async getMarketDebtCap(): Promise<bigint> { return BigInt(await ethCall(this.provider, this.address, SEL.MARKET_DEBT_CAP)); }
/* ---- live state ------------------------------------------------------- */
async totalBorrowsCurrent(): Promise<bigint> { return BigInt(await ethCall(this.provider, this.address, SEL.totalBorrowsCurrent)); }
async totalSuppliedCurrent(): Promise<bigint> { return BigInt(await ethCall(this.provider, this.address, SEL.totalSuppliedCurrent)); }
async pendingSinkFee(): Promise<bigint> { return BigInt(await ethCall(this.provider, this.address, SEL.pendingSinkFee)); }
async borrowRatePerSecond(): Promise<bigint> { return BigInt(await ethCall(this.provider, this.address, SEL.borrowRatePerSecond)); }
async borrowPaused(): Promise<boolean> { return BigInt(await ethCall(this.provider, this.address, SEL.borrowPaused)) === 1n; }
async depositPaused(): Promise<boolean> { return BigInt(await ethCall(this.provider, this.address, SEL.depositPaused)) === 1n; }
/* ---- per-user views --------------------------------------------------- */
async collateralOf(user: string): Promise<bigint> { return BigInt(await ethCall(this.provider, this.address, SEL.collateralOf + encAddr(user))); }
async debtBalance(user: string): Promise<bigint> { return BigInt(await ethCall(this.provider, this.address, SEL.debtBalance + encAddr(user))); }
async supplierBalance(user: string): Promise<bigint> { return BigInt(await ethCall(this.provider, this.address, SEL.supplierBalance + encAddr(user))); }
async healthFactor(user: string): Promise<bigint> { return BigInt(await ethCall(this.provider, this.address, SEL.healthFactor + encAddr(user))); }
/* ---- write methods ---------------------------------------------------- */
async accrueInterest(from: string): Promise<string> {
return ethSend(this.provider, from, this.address, SEL.accrueInterest);
}
async flushSinkFee(from: string): Promise<string> {
return ethSend(this.provider, from, this.address, SEL.flushSinkFee);
}
async supply(from: string, amount: bigint): Promise<string> {
return ethSend(this.provider, from, this.address, SEL.supply + encUint(amount));
}
async redeem(from: string, amount: bigint): Promise<string> {
return ethSend(this.provider, from, this.address, SEL.redeem + encUint(amount));
}
async depositCollateral(from: string, amount: bigint): Promise<string> {
return ethSend(this.provider, from, this.address, SEL.depositCollateral + encUint(amount));
}
async withdrawCollateral(from: string, amount: bigint): Promise<string> {
return ethSend(this.provider, from, this.address, SEL.withdrawCollateral + encUint(amount));
}
async borrow(from: string, amount: bigint): Promise<string> {
return ethSend(this.provider, from, this.address, SEL.borrow + encUint(amount));
}
async repay(from: string, amount: bigint): Promise<string> {
return ethSend(this.provider, from, this.address, SEL.repay + encUint(amount));
}
async repayOnBehalfOf(from: string, account: string, amount: bigint): Promise<string> {
return ethSend(this.provider, from, this.address, SEL.repayOnBehalfOf + encAddr(account) + encUint(amount));
}
async liquidate(from: string, borrower: string, repayAmount: bigint): Promise<string> {
return ethSend(this.provider, from, this.address, SEL.liquidate + encAddr(borrower) + encUint(repayAmount));
}
/* ---- helpers ---------------------------------------------------------- */
/**
* Returns the APY as a decimal (0.05 = 5%) computed from `borrowRatePerSecond`.
* Linear approximation; accurate at low rates.
*/
async borrowApy(): Promise<number> {
const rate = await this.borrowRatePerSecond();
const r = Number(rate) / 1e27;
return r * 365 * 86400;
}
}

View File

@ -0,0 +1,52 @@
/**
* RWATransferAdapterClient permissioned RWA USDC.e redemption.
* Contract: aerenew/contracts/contracts/lending/RWATransferAdapter.sol
*/
export interface RpcProvider {
request(args: { method: string; params: unknown[] }): Promise<unknown>;
}
const pad32 = (h: string) => h.toLowerCase().replace(/^0x/, '').padStart(64, '0');
const encUint = (n: bigint) => pad32(n.toString(16));
const encAddr = (a: string) => pad32(a.replace(/^0x/, ''));
async function ethCall(p: RpcProvider, to: string, data: string): Promise<string> {
return await p.request({ method: 'eth_call', params: [{ to, data }, 'latest'] }) as string;
}
async function ethSend(p: RpcProvider, from: string, to: string, data: string): Promise<string> {
return await p.request({ method: 'eth_sendTransaction', params: [{ from, to, data, value: '0x0' }] }) as string;
}
const SEL = {
PAYOUT_TOKEN: '0x935ca8e6', // PAYOUT_TOKEN()
ORACLE: '0x7dc0d1d0', // ORACLE()
FOUNDATION: '0x4d09f93e', // FOUNDATION()
configs: '0x1d12be96', // configs(address)
states: '0xb95da3ec', // states(address)
periodRemaining: '0x3aff0d34', // periodRemaining(address)
payoutLiquidity: '0x8b8a55be', // payoutLiquidity()
redeem: '0x1e9a6950', // redeem(address,uint256)
} as const;
export class RWATransferAdapterClient {
constructor(public readonly provider: RpcProvider, public readonly address: string) {}
async getPayoutToken(): Promise<string> {
return '0x' + (await ethCall(this.provider, this.address, SEL.PAYOUT_TOKEN)).slice(-40);
}
async getFoundation(): Promise<string> {
return '0x' + (await ethCall(this.provider, this.address, SEL.FOUNDATION)).slice(-40);
}
async periodRemaining(asset: string): Promise<bigint> {
return BigInt(await ethCall(this.provider, this.address, SEL.periodRemaining + encAddr(asset)));
}
async payoutLiquidity(): Promise<bigint> {
return BigInt(await ethCall(this.provider, this.address, SEL.payoutLiquidity));
}
/** Permissionless redeem. Caller must approve `asset` for `rwaAmount` on this contract first. */
async redeem(from: string, asset: string, rwaAmount: bigint): Promise<string> {
return ethSend(this.provider, from, this.address, SEL.redeem + encAddr(asset) + encUint(rwaAmount));
}
}

4
src/lending/index.ts Normal file
View File

@ -0,0 +1,4 @@
export { LendingMarketClient } from './LendingMarketClient.js';
export type { LendingMarketConfig } from './LendingMarketClient.js';
export { AereInsuranceFundClient } from './InsuranceFundClient.js';
export { RWATransferAdapterClient } from './RWATransferAdapterClient.js';

179
src/raas/RaaSClient.ts Normal file
View File

@ -0,0 +1,179 @@
/**
* RaaSClient AereRaaSFactory + AereRollupSettlement helpers.
*
* Contracts:
* aerenew/contracts/contracts/raas/AereRaaSFactory.sol
* aerenew/contracts/contracts/raas/AereRollupSettlement.sol
*/
export interface RpcProvider {
request(args: { method: string; params: unknown[] }): Promise<unknown>;
}
const pad32 = (h: string) => h.toLowerCase().replace(/^0x/, '').padStart(64, '0');
const encUint = (n: bigint) => pad32(n.toString(16));
const encAddr = (a: string) => pad32(a.replace(/^0x/, ''));
const encBytes32 = (b: string) => pad32(b.replace(/^0x/, ''));
const encBool = (b: boolean) => pad32(b ? '1' : '0');
async function ethCall(p: RpcProvider, to: string, data: string): Promise<string> {
return await p.request({ method: 'eth_call', params: [{ to, data }, 'latest'] }) as string;
}
async function ethSend(p: RpcProvider, from: string, to: string, data: string, value = '0x0'): Promise<string> {
return await p.request({ method: 'eth_sendTransaction', params: [{ from, to, data, value }] }) as string;
}
/* ============================== Factory =============================== */
const FAC_SEL = {
// immutable views
BOND_TOKEN: '0x18b13f55', // BOND_TOKEN()
SINK: '0xf4f3b200', // SINK()
REGISTRATION_BOND: '0x4b094c4b', // REGISTRATION_BOND()
MIN_SINK_BPS: '0x9dabd040', // MIN_SINK_BPS()
DEFAULT_CHALLENGE_WINDOW: '0x8e8a6f3a', // DEFAULT_CHALLENGE_WINDOW()
FOUNDATION: '0x4d09f93e', // FOUNDATION()
// state views
rollups: '0xdcecb8e3', // rollups(bytes32)
rollupCount: '0xff19a3a4', // rollupCount()
// writes
registerRollup: '0xbb4ab86c', // registerRollup(bytes32,address,address,address,uint16,uint16,uint16,uint256,uint64,string)
updateMetadata: '0xa1ae9b0e', // updateMetadata(bytes32,string)
exitRollup: '0x73db2bba', // exitRollup(bytes32,address,uint64,bytes)
} as const;
export class AereRaaSFactoryClient {
constructor(public readonly provider: RpcProvider, public readonly address: string) {}
async rollupCount(): Promise<bigint> {
return BigInt(await ethCall(this.provider, this.address, FAC_SEL.rollupCount));
}
async getSink(): Promise<string> {
return '0x' + (await ethCall(this.provider, this.address, FAC_SEL.SINK)).slice(-40);
}
async getRegistrationBond(): Promise<bigint> {
return BigInt(await ethCall(this.provider, this.address, FAC_SEL.REGISTRATION_BOND));
}
async getMinSinkBps(): Promise<number> {
return Number(BigInt(await ethCall(this.provider, this.address, FAC_SEL.MIN_SINK_BPS)));
}
/**
* Register a rollup. Requires the caller to have approved BOND_TOKEN for
* REGISTRATION_BOND on the factory beforehand.
*/
async registerRollup(
from: string,
opts: {
rollupId: string; // bytes32 hex
rollupOwner: string;
sequencer: string;
debtToken: string;
sinkBps: number;
rollupBps: number;
sequencerBps: number;
minChallengeBond: bigint;
challengeWindow: number;
metadataUri: string;
}
): Promise<string> {
const meta = Buffer.from(opts.metadataUri, 'utf8');
const head =
encBytes32(opts.rollupId) +
encAddr(opts.rollupOwner) +
encAddr(opts.sequencer) +
encAddr(opts.debtToken) +
encUint(BigInt(opts.sinkBps)) +
encUint(BigInt(opts.rollupBps)) +
encUint(BigInt(opts.sequencerBps)) +
encUint(opts.minChallengeBond) +
encUint(BigInt(opts.challengeWindow)) +
encUint(0x140n); // 10 head slots * 32 = 320 = 0x140
const padded = Buffer.alloc(Math.ceil(meta.length / 32) * 32);
meta.copy(padded);
const dyn = encUint(BigInt(meta.length)) + padded.toString('hex');
const data = FAC_SEL.registerRollup + head + dyn;
return ethSend(this.provider, from, this.address, data);
}
}
/* ============================ Settlement ============================= */
const SET_SEL = {
ROLLUP_ID: '0x7b0a4eb1', // ROLLUP_ID()
SINK: '0xf4f3b200', // SINK()
DEBT_TOKEN: '0xea5b5ddf', // DEBT_TOKEN()
CHALLENGE_WINDOW: '0x7a6a4abe', // CHALLENGE_WINDOW()
SINK_BPS: '0xb3f54bdd', // SINK_BPS()
ROLLUP_BPS: '0xc70aa727', // ROLLUP_BPS()
SEQUENCER_BPS: '0xe35d8b85', // SEQUENCER_BPS()
rollupOwner: '0x0e8d63c0', // rollupOwner()
sequencer: '0x42d1de27', // sequencer()
latestEpoch: '0x6f6db00f', // latestEpoch()
latestFinalisedEpoch:'0x3aac4670', // latestFinalisedEpoch()
isFinalised: '0x3a8a4a3e', // isFinalised(uint256)
totalRevenueSettled: '0xf3b6db95', // totalRevenueSettled()
proposeStateRoot: '0x9e706b08', // proposeStateRoot(uint256,bytes32,bytes32)
advanceFinalisation: '0xb78f2ebd', // advanceFinalisation()
challenge: '0x8da548fa', // challenge(uint256,uint256,bytes32)
resolveChallenge: '0x437f2ba0', // resolveChallenge(uint256,bool)
resolveChallengeExpired: '0xb1cc5a3d', // resolveChallengeExpired(uint256)
settleRevenue: '0xc7c1aa8c', // settleRevenue(uint256)
setSequencer: '0xa6f9dae1', // setSequencer(address)
transferOwner: '0xc6dad082', // transferOwner(address)
} as const;
export class AereRollupSettlementClient {
constructor(public readonly provider: RpcProvider, public readonly address: string) {}
async sequencer(): Promise<string> {
return '0x' + (await ethCall(this.provider, this.address, SET_SEL.sequencer)).slice(-40);
}
async rollupOwner(): Promise<string> {
return '0x' + (await ethCall(this.provider, this.address, SET_SEL.rollupOwner)).slice(-40);
}
async latestEpoch(): Promise<bigint> {
return BigInt(await ethCall(this.provider, this.address, SET_SEL.latestEpoch));
}
async isFinalised(epoch: bigint): Promise<boolean> {
const res = await ethCall(this.provider, this.address, SET_SEL.isFinalised + encUint(epoch));
return BigInt(res) === 1n;
}
async totalRevenueSettled(): Promise<bigint> {
return BigInt(await ethCall(this.provider, this.address, SET_SEL.totalRevenueSettled));
}
/* sequencer-only */
async proposeStateRoot(from: string, epoch: bigint, root: string, l2BlockHash: string): Promise<string> {
const data = SET_SEL.proposeStateRoot + encUint(epoch) + encBytes32(root) + encBytes32(l2BlockHash);
return ethSend(this.provider, from, this.address, data);
}
async resolveChallenge(from: string, epoch: bigint, accepted: boolean): Promise<string> {
return ethSend(this.provider, from, this.address, SET_SEL.resolveChallenge + encUint(epoch) + encBool(accepted));
}
/* permissionless */
async challenge(from: string, epoch: bigint, bond: bigint, reasonHash: string): Promise<string> {
const data = SET_SEL.challenge + encUint(epoch) + encUint(bond) + encBytes32(reasonHash);
return ethSend(this.provider, from, this.address, data);
}
async resolveChallengeExpired(from: string, epoch: bigint): Promise<string> {
return ethSend(this.provider, from, this.address, SET_SEL.resolveChallengeExpired + encUint(epoch));
}
async advanceFinalisation(from: string): Promise<string> {
return ethSend(this.provider, from, this.address, SET_SEL.advanceFinalisation);
}
/* rollupOwner-only */
async settleRevenue(from: string, amount: bigint): Promise<string> {
return ethSend(this.provider, from, this.address, SET_SEL.settleRevenue + encUint(amount));
}
async setSequencer(from: string, newSequencer: string): Promise<string> {
return ethSend(this.provider, from, this.address, SET_SEL.setSequencer + encAddr(newSequencer));
}
async transferOwner(from: string, newOwner: string): Promise<string> {
return ethSend(this.provider, from, this.address, SET_SEL.transferOwner + encAddr(newOwner));
}
}

1
src/raas/index.ts Normal file
View File

@ -0,0 +1 @@
export { AereRaaSFactoryClient, AereRollupSettlementClient } from './RaaSClient.js';