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.
228 lines
9.6 KiB
TypeScript
228 lines
9.6 KiB
TypeScript
/**
|
|
* 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);
|
|
}
|
|
}
|