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.
53 lines
4.8 KiB
JavaScript
53 lines
4.8 KiB
JavaScript
#!/usr/bin/env node
|
|
// recompileaza-contract.mjs: arata ca AereAgentWallet2of2.json spune adevarul despre sursa lui (2026-09-29). Da intrarea standard a
|
|
// compilatorului din artefact (sursele si setarile) unui solc 0.8.23 ales de cel care verifica, si cere ca codul de desfasurare si
|
|
// codul de rulare sa iasa OCTET CU OCTET cele din artefact; codul de pe lant il compara apoi verifica-plati.mjs. Controlul metodei e
|
|
// inauntru: aceeasi intrare cu un singur caracter schimbat intr-un comentariu al sursei TREBUIE sa dea alt cod (amprenta metadatelor),
|
|
// altfel comparatia nu poate deosebi nimic si iesirea e NEMASURAT.
|
|
// node recompileaza-contract.mjs --solc <cale catre solc 0.8.23 nativ> iesire 0 IDENTIC, 1 DIFERIT, 2 NEMASURAT
|
|
// (solc 0.8.23: github.com/ethereum/solidity/releases/tag/v0.8.23, sau npx solc@0.8.23 cu --solcjs)
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import { spawnSync } from 'node:child_process';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { incarcaArtefact } from './contract-2of2.mjs';
|
|
|
|
const a = process.argv.slice(2); const get = (f) => { const i = a.indexOf(f); return i >= 0 ? a[i + 1] : undefined; };
|
|
const solc = get('--solc'); const solcjs = a.includes('--solcjs');
|
|
if (!solc && !solcjs) { console.log('usage: node recompileaza-contract.mjs --solc <path to a native solc 0.8.23> | --solcjs (runs npx solc@0.8.23)'); process.exit(2); }
|
|
const art = incarcaArtefact();
|
|
const cheama = (args, intrare) => solcjs
|
|
? spawnSync(process.platform === 'win32' ? 'npx.cmd' : 'npx', ['--yes', 'solc@0.8.23', ...args], { input: intrare, encoding: 'utf8', maxBuffer: 1 << 28, shell: process.platform === 'win32', timeout: 600000 })
|
|
: spawnSync(solc, args, { input: intrare, encoding: 'utf8', maxBuffer: 1 << 28, timeout: 600000 });
|
|
const ver = cheama(['--version']);
|
|
const versiune = ((ver.stdout || '') + (ver.stderr || '')).match(/0\.8\.23\+commit\.[0-9a-f]+/);
|
|
if (!versiune) { console.log(`NEMASURAT: the compiler is not solc 0.8.23 (${String((ver.stdout || ver.stderr || (ver.error && ver.error.message) || '').trim()).slice(0, 100)})`); process.exit(2); }
|
|
const compileaza = (input) => {
|
|
const r = cheama(['--standard-json'], JSON.stringify(input));
|
|
let o = null; try { o = JSON.parse(r.stdout); } catch { return { eroare: `no JSON from the compiler (exit ${r.status})` }; }
|
|
const erori = (o.errors || []).filter((e) => e.severity === 'error');
|
|
if (erori.length) return { eroare: erori.map((e) => e.formattedMessage || e.message).join(' | ').slice(0, 200) };
|
|
const c = o.contracts && o.contracts[art.sourcePath] && o.contracts[art.sourcePath][art.contractName];
|
|
return c ? { bytecode: '0x' + c.evm.bytecode.object, deployedBytecode: '0x' + c.evm.deployedBytecode.object } : { eroare: 'the output has no such contract' };
|
|
};
|
|
const r = compileaza(art.standardJsonInput);
|
|
if (r.eroare) { console.log(`NEMASURAT: ${r.eroare}`); process.exit(2); }
|
|
// controlul metodei: un comentariu schimbat trebuie sa schimbe codul
|
|
const alt = JSON.parse(JSON.stringify(art.standardJsonInput));
|
|
alt.sources[art.sourcePath].content = alt.sources[art.sourcePath].content.replace('HONEST SCOPE', 'HONEST SCOPF');
|
|
const rc = compileaza(alt);
|
|
if (rc.eroare || alt.sources[art.sourcePath].content === art.standardJsonInput.sources[art.sourcePath].content || rc.deployedBytecode === r.deployedBytecode) {
|
|
console.log(`NEMASURAT: the method control failed (a changed comment did not change the code${rc.eroare ? ': ' + rc.eroare : ''})`); process.exit(2);
|
|
}
|
|
// copia de citit a sursei (contract/AereAgentWallet2of2.sol, in pachetul publicat) trebuie sa fie chiar sursa compilata
|
|
const citibil = path.join(path.dirname(fileURLToPath(import.meta.url)), 'contract', 'AereAgentWallet2of2.sol');
|
|
const copieBuna = !fs.existsSync(citibil) || fs.readFileSync(citibil, 'utf8').replace(/\r\n/g, '\n') === art.standardJsonInput.sources[art.sourcePath].content;
|
|
const bun = r.bytecode === art.bytecode && r.deployedBytecode === art.deployedBytecode && copieBuna;
|
|
console.log(` compiler: solc ${versiune[0]}${solcjs ? ' (solcjs)' : ''}`);
|
|
console.log(fs.existsSync(citibil) ? ` ${copieBuna ? 'OK ' : 'FAIL'} contract/AereAgentWallet2of2.sol is the compiled source` : ' -- no readable copy of the source next to this script (contract/AereAgentWallet2of2.sol)');
|
|
console.log(` ${r.bytecode === art.bytecode ? 'OK ' : 'FAIL'} creation code: ${(r.bytecode.length - 2) / 2} bytes`);
|
|
console.log(` ${r.deployedBytecode === art.deployedBytecode ? 'OK ' : 'FAIL'} runtime code: ${(r.deployedBytecode.length - 2) / 2} bytes`);
|
|
console.log(` OK method control: one changed character in a comment gives another runtime code`);
|
|
console.log(bun ? 'IDENTICAL: the artifact is the compilation of its source' : 'DIFFERENT: the artifact is not the compilation of its source, or the readable copy is not that source');
|
|
process.exitCode = bun ? 0 : 1;
|