AereAgentWallet2of2 holds the agent's tokens and accepts only the agent's signature followed by the policy service's, over the same digest. In the new cosign mode the wallet service signs only its half, after every check it already made, and the agent adds its half only after it recomputes the payment itself (payer, recipient, amount, the nonce of its own ledger entry, validity, digest, declared policy signer). verifica-plati.mjs requires the wallet's code on chain to be exactly the compiled contract with the two signers; recompileaza-contract.mjs recompiles the published artifact byte for byte with solc 0.8.23. Tests: co-signing 16/16, payment verifier 14/14, negative control 30/30, wallet 25/25. On the public testnet 28001 on 2026-09-29: 13/13 with the 2-of-2 wallet (the agent alone and the policy signer alone refused by the facilitator and by the token asked on chain) and 9/9 with the wallet key. Evidence in dovezi-28001/. Nothing here has been run on the Aere Network mainnet.
38 lines
2.1 KiB
JavaScript
38 lines
2.1 KiB
JavaScript
// Portofelul-contract 2-din-2 al agentului (AereAgentWallet2of2.sol), vazut din afara (2026-09-29): artefactul compilat si codul de
|
|
// rulare ASTEPTAT pentru o pereche de semnatari. Un contract care doar RASPUNDE agentSigner()/policySigner() ar putea minti; octetii de
|
|
// pe lant nu pot: codul de rulare e cel compilat din sursa publicata, cu cele doua adrese scrise in locul imutabilelor, si nimic altceva.
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import crypto from 'node:crypto';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const AICI = path.dirname(fileURLToPath(import.meta.url));
|
|
export const ARTEFACT = path.join(AICI, 'AereAgentWallet2of2.json');
|
|
|
|
export function incarcaArtefact(f = ARTEFACT) {
|
|
const a = JSON.parse(fs.readFileSync(f, 'utf8'));
|
|
if (a.kind !== 'aere-agent-wallet-2of2-artifact' || !a.deployedBytecode || !a.immutables || !a.immutables.agentSigner || !a.immutables.policySigner)
|
|
throw new Error('not an AereAgentWallet2of2 artifact');
|
|
return a;
|
|
}
|
|
|
|
/** sha256 al sursei contractului, citit din intrarea compilatorului (ce s-a compilat), nu dintr-un camp declarat */
|
|
export function amprentaSursei(a) {
|
|
const s = a.standardJsonInput && a.standardJsonInput.sources && a.standardJsonInput.sources[a.sourcePath];
|
|
return s ? crypto.createHash('sha256').update(s.content, 'utf8').digest('hex') : null;
|
|
}
|
|
|
|
/** codul de rulare pe care il are pe lant un AereAgentWallet2of2(agentSigner, policySigner), in hex cu litere mici */
|
|
export function codulAsteptat(a, { agentSigner, policySigner }) {
|
|
const cod = Buffer.from(a.deployedBytecode.replace(/^0x/, ''), 'hex');
|
|
const pune = (poz, adresa) => {
|
|
const h = String(adresa).toLowerCase().replace(/^0x/, '');
|
|
if (!/^[0-9a-f]{40}$/.test(h)) throw new Error(`not an address: ${adresa}`);
|
|
const cuvant = Buffer.from(h.padStart(64, '0'), 'hex');
|
|
for (const p of poz) { if (p.length !== 32) throw new Error('immutable of unexpected length'); cuvant.copy(cod, p.start); }
|
|
};
|
|
pune(a.immutables.agentSigner, agentSigner);
|
|
pune(a.immutables.policySigner, policySigner);
|
|
return '0x' + cod.toString('hex');
|
|
}
|