0.16.13: repair ~130 client selectors that did not match the deployed contracts (D-512)
Ten clients (RaaS, Sink, Agent and x402 settlement, state channels, compliance,
lending, the compliant pool) carried hand-written function selectors that matched
neither the compiled ABI nor the signature written next to them, so every call
through them reverted. Every selector is now the keccak of a signature in the
compiled ABI. Functions the contracts never had are replaced by the real ones:
AereSanctionsRegistry (latestEpoch, isSanctioned with epoch, isSanctionedLatest,
currentRoot via snapshotStatus), ChainalysisOracleWrapper (upstreamOracle),
AereTravelRuleHashRegistry (status by commitment id), AereInsuranceFund (two-step
proposeMarket + registerMarket). AereRaaSFactoryClient.registerRollup targets the
canonical AereRaaSFactoryV2 (11 parameters, optional defenseGrace).
Proof: the gate aerenew/scripts/deschise/sdk-selectori-corecti.cjs reads 330 of
330 selectors correct and fails on a planted one; src/test/selectors-live.ts reads
18 values from the deployed contracts through the shipped clients, and the old
rollupCount selector still reverts (its negative control).
Also: state-window-live records that both public endpoints now refuse state
outside the 512-block window ("World state unavailable") instead of returning a
false 0x0, and proves the guard against an endpoint that still lies; npm test
runs the offline suite through scripts/run-tests.mjs (61/61), live proofs stay
separate. README network facts brought to 2026-10-15.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
0e4339632b
commit
6f13c671f1
61
README.md
61
README.md
@ -5,8 +5,18 @@ live AERE L1 (chain ID 2800): the DeFi, agentic-settlement, compliance,
|
|||||||
account-abstraction and post-quantum contract surface, the seedless hybrid PQC
|
account-abstraction and post-quantum contract surface, the seedless hybrid PQC
|
||||||
wallet, and AERE's native NIST post-quantum precompiles.
|
wallet, and AERE's native NIST post-quantum precompiles.
|
||||||
|
|
||||||
**SDK version:** 0.16.12
|
**SDK version:** 0.16.13
|
||||||
**Last updated:** 2026-08-19 (consensus and network facts; the rest is as of 2026-07-16)
|
**Last updated:** 2026-10-15 (network facts, state window, client selectors; the rest is as of 2026-07-16)
|
||||||
|
|
||||||
|
**0.16.13, 2026-10-15: client selectors repaired.** Until this release about 130 hand-written function selectors in ten
|
||||||
|
clients (RaaS, Sink, Agent and x402 settlement, state channels, compliance, lending, the compliant pool) did not match
|
||||||
|
the deployed contracts, so calls through them reverted. Every selector is now the keccak of a signature in the compiled
|
||||||
|
ABI, checked by a gate on each change, and `src/test/selectors-live.ts` reads the deployed contracts through the shipped
|
||||||
|
clients. API changes: `AereSanctionsRegistryClient` gains `latestEpoch()`, `isSanctioned(epoch, ...)` and
|
||||||
|
`isSanctionedLatest(...)`, and `currentRoot(epoch?)` now reads the root of an epoch; `ChainalysisOracleWrapperClient`
|
||||||
|
gains `upstreamOracle()`; `AereTravelRuleHashRegistryClient.status` takes a commitment id; `AereInsuranceFundClient`
|
||||||
|
registers a market in two steps, `proposeMarket` then `registerMarket`; `AereRaaSFactoryClient.registerRollup` targets
|
||||||
|
the canonical `AereRaaSFactoryV2` and accepts an optional `defenseGrace`.
|
||||||
**Network state at this release:** 35+ typed contract clients over a canonical
|
**Network state at this release:** 35+ typed contract clients over a canonical
|
||||||
address book of 130+ live contracts on chain 2800.
|
address book of 130+ live contracts on chain 2800.
|
||||||
|
|
||||||
@ -18,10 +28,10 @@ address book of 130+ live contracts on chain 2800.
|
|||||||
|---|---|
|
|---|---|
|
||||||
| Chain name | AERE Network |
|
| Chain name | AERE Network |
|
||||||
| Chain ID | 2800 (`0xAF0`) |
|
| Chain ID | 2800 (`0xAF0`) |
|
||||||
| Consensus | Hyperledger Besu QBFT, classical secp256k1 ECDSA |
|
| Consensus | QBFT; per-block finality on classical secp256k1 ECDSA commit seals, with post-quantum validator seals on consensus messages and a post-quantum certificate under every 32nd block's hash (details on aere.network) |
|
||||||
| Validators | 7, Byzantine-fault tolerance f=2, commit quorum 5 of 7 |
|
| Validators | 10 since 2026-09-11, Byzantine-fault tolerance f=3, commit quorum 7 of 10 |
|
||||||
| Operator / client diversity | Single operator (Foundation), single client (Besu) today |
|
| Operator / client diversity | Single operator (the Foundation); two client implementations, Besu-derived and Nethermind-derived (one validator, since 2026-09-11) |
|
||||||
| Block period | 0.5 s (500 ms) target, sub-second deterministic finality |
|
| Block period | 0.5 s target; measured 0.62 s (median of five 20,000-block windows, 2026-10-15); deterministic finality |
|
||||||
| Native token | AERE (18 decimals) |
|
| Native token | AERE (18 decimals) |
|
||||||
| Max supply | 2,800,000,000 AERE (capped at genesis-v2, 2026-05-07) |
|
| Max supply | 2,800,000,000 AERE (capped at genesis-v2, 2026-05-07) |
|
||||||
| EVM ruleset | Pectra + Fusaka opcode and precompile set (Besu), plus five AERE post-quantum precompiles; not full parity with Ethereum mainnet (the beacon-chain system contracts, e.g. EIP-4788 beacon roots, have no code on chain 2800) |
|
| EVM ruleset | Pectra + Fusaka opcode and precompile set (Besu), plus five AERE post-quantum precompiles; not full parity with Ethereum mainnet (the beacon-chain system contracts, e.g. EIP-4788 beacon roots, have no code on chain 2800) |
|
||||||
@ -245,28 +255,31 @@ Options:
|
|||||||
$ aere chain
|
$ aere chain
|
||||||
AERE chain — https://rpc.aere.network
|
AERE chain — https://rpc.aere.network
|
||||||
Chain ID 2800 (0xaf0)
|
Chain ID 2800 (0xaf0)
|
||||||
Block height 9520927
|
Block height 22945693
|
||||||
Base fee 1.0 gwei
|
Base fee 1.0 gwei (1000000000 wei)
|
||||||
Gas price 1.0 gwei
|
Gas price 1.0 gwei (1000000000 wei)
|
||||||
Validators 7
|
Validators 10
|
||||||
Peers 7
|
- 0x38fb1510d4d11624564a74e6ebfd752e666849c3
|
||||||
|
...
|
||||||
```
|
```
|
||||||
|
(Output of 2026-10-15. Since block 20,836,228 the validator list holds post-quantum validator ids, not ECDSA addresses.)
|
||||||
|
|
||||||
## State window on the public RPC (read before pinning a historical block)
|
## State window on the public RPC (read before pinning a historical block)
|
||||||
|
|
||||||
Both public endpoints are **pruning full nodes**, not archive nodes.
|
Both public endpoints are **pruning full nodes**, not archive nodes.
|
||||||
|
|
||||||
- Blocks, transactions, receipts, logs and `qbft_getValidatorsByBlockNumber` go back to **block 0**.
|
- Blocks, transactions, receipts, logs and `qbft_getValidatorsByBlockNumber` go back to **block 0**.
|
||||||
- **World state is kept for only about the most recent 512 blocks**, roughly 4 minutes 25 seconds
|
- **World state is kept for only about the most recent 512 blocks**, roughly 5 minutes 17 seconds
|
||||||
at the measured 517 ms block interval. That bounds `eth_getBalance`, `eth_getCode`,
|
at the 0.62 s block interval measured on 2026-10-15. That bounds `eth_getBalance`, `eth_getCode`,
|
||||||
`eth_getStorageAt`, `eth_call`, `eth_getProof` and `eth_getTransactionCount`.
|
`eth_getStorageAt`, `eth_call`, `eth_getProof` and `eth_getTransactionCount`.
|
||||||
|
|
||||||
Outside the window most methods say so: `eth_getBalance` / `eth_getCode` / `eth_getStorageAt`
|
Outside the window both public endpoints now say so for every state method: measured on 2026-10-15,
|
||||||
return `null`, and `eth_getProof` returns `-32000 World state unavailable`.
|
`eth_getTransactionCount`, `eth_getBalance` and `eth_getProof` all return `-32000 World state unavailable`.
|
||||||
**`eth_getTransactionCount` does not.** It returns `0x0`, which is well formed and
|
Until October 2026 they did not: `eth_getBalance` / `eth_getCode` / `eth_getStorageAt` returned `null`, and
|
||||||
indistinguishable from an account that has never transacted. Reproduce it yourself: block
|
**`eth_getTransactionCount` returned `0x0`**, well formed and indistinguishable from an account that has
|
||||||
8,236,382 contains a transaction from `0xbeb33d20dfbbd49ec7ac1f617667f1f02dfd6465` with nonce
|
never transacted (block 8,236,382 holds a transaction from `0xbeb33d20dfbbd49ec7ac1f617667f1f02dfd6465` with
|
||||||
123,063, and the endpoint still answers `0x0` for that address at that block.
|
nonce 123,063, and the endpoint answered `0x0` for that address at that block). Other endpoints and other
|
||||||
|
node versions may still answer that way, which is why the reader below keeps its guards.
|
||||||
|
|
||||||
`StateWindowReader` returns a value or throws. It never returns a placeholder.
|
`StateWindowReader` returns a value or throws. It never returns a placeholder.
|
||||||
|
|
||||||
@ -301,11 +314,11 @@ pinning a historical block; and never test a nonce for zero at a historical bloc
|
|||||||
pass that signer into the SDK, or use the seedless PQC wallet above.
|
pass that signer into the SDK, or use the seedless PQC wallet above.
|
||||||
- **Fiat rails are out of scope.** AERE is the on-chain settlement layer; fiat
|
- **Fiat rails are out of scope.** AERE is the on-chain settlement layer; fiat
|
||||||
IBANs / cards / SEPA come from a BaaS partner (Striga, Baanx, Kulipa, etc.).
|
IBANs / cards / SEPA come from a BaaS partner (Striga, Baanx, Kulipa, etc.).
|
||||||
- **Decentralization.** 7 QBFT validators give f=2 (the chain keeps producing
|
- **Decentralization.** 10 QBFT validators give f=3 (the chain keeps producing
|
||||||
blocks while up to 2 validators are down), commit quorum 5 of 7. All 7 are
|
blocks while up to 3 validators are down), commit quorum 7 of 10. All 10 are
|
||||||
operated by the Foundation on a single client (Besu), so this is
|
operated by the Foundation; nine run the Besu-derived client and one, since
|
||||||
fault-tolerance, not yet operator or client diversity. Broader validator
|
2026-09-11, the Nethermind-derived client. That is fault tolerance and a second
|
||||||
operators and a second client are roadmap.
|
code base, not yet operator diversity: independent validator operators are roadmap.
|
||||||
- **Foundation key, not a multisig.** `0x0243A4f47D44b40b65D33f20329dE20D00c6f3C3`
|
- **Foundation key, not a multisig.** `0x0243A4f47D44b40b65D33f20329dE20D00c6f3C3`
|
||||||
is a single-key EOA (zero bytecode on-chain), described here as a
|
is a single-key EOA (zero bytecode on-chain), described here as a
|
||||||
Foundation-controlled account. A real Safe-style threshold multisig is roadmap,
|
Foundation-controlled account. A real Safe-style threshold multisig is roadmap,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@aere/sdk",
|
"name": "@aere/sdk",
|
||||||
"version": "0.16.12",
|
"version": "0.16.13",
|
||||||
"description": "Official AERE Network SDK: typed ethers v6 clients for AERE L1 (chain ID 2800). 35+ typed clients over a 130+ contract address book, covering core DeFi, agentic x402 settlement, compliance, ERC-4337 account abstraction, t-of-n post-quantum custody, the 5 live NIST PQC precompiles (Falcon-512/1024, ML-DSA-44, SLH-DSA-128s, SHAKE256), and a seedless hybrid PQC wallet.",
|
"description": "Official AERE Network SDK: typed ethers v6 clients for AERE L1 (chain ID 2800). 35+ typed clients over a 130+ contract address book, covering core DeFi, agentic x402 settlement, compliance, ERC-4337 account abstraction, t-of-n post-quantum custody, the 5 live NIST PQC precompiles (Falcon-512/1024, ML-DSA-44, SLH-DSA-128s, SHAKE256), and a seedless hybrid PQC wallet.",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
@ -24,7 +24,7 @@
|
|||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"test": "node --test dist/test/*.js",
|
"test": "node scripts/run-tests.mjs",
|
||||||
"test:live": "node dist/test/state-window-live.js"
|
"test:live": "node dist/test/state-window-live.js"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
|||||||
14
scripts/run-tests.mjs
Normal file
14
scripts/run-tests.mjs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// Runs the offline test suite: every dist/test/*.js except the *-live.js proofs, which need the network
|
||||||
|
// (run those explicitly, e.g. `npm run test:live`). Portable: no shell globbing, works the same under cmd and sh.
|
||||||
|
import { readdirSync } from 'node:fs';
|
||||||
|
import { spawnSync } from 'node:child_process';
|
||||||
|
|
||||||
|
const files = readdirSync('dist/test')
|
||||||
|
.filter((f) => f.endsWith('.js') && !/-live(\.test)?\.js$/.test(f))
|
||||||
|
.map((f) => `dist/test/${f}`);
|
||||||
|
if (files.length === 0) {
|
||||||
|
console.error('no compiled tests in dist/test; run `npm run build` first');
|
||||||
|
process.exit(2);
|
||||||
|
}
|
||||||
|
const r = spawnSync(process.execPath, ['--test', ...files], { stdio: 'inherit' });
|
||||||
|
process.exit(r.status ?? 1);
|
||||||
@ -8,14 +8,14 @@ export interface Eip1193Provider {
|
|||||||
|
|
||||||
// 4-byte selectors (precomputed; never call eth_sign just to derive them).
|
// 4-byte selectors (precomputed; never call eth_sign just to derive them).
|
||||||
const SEL = {
|
const SEL = {
|
||||||
registerAgent: '0xa30b3acc', // registerAgent(address,bytes32,bytes32,uint128,uint128,uint128,string)
|
registerAgent: '0x8d471e06', // registerAgent(address,bytes32,bytes32,uint128,uint128,uint128,string)
|
||||||
setSigner: '0x6c19e783', // setSigner(uint256,address)
|
setSigner: '0x85267907', // setSigner(uint256,address)
|
||||||
setRateLimits: '0x44dec0e2', // setRateLimits(uint256,uint128,uint128,uint128)
|
setRateLimits: '0x70c4e4df', // setRateLimits(uint256,uint128,uint128,uint128)
|
||||||
setPaused: '0x8456db15', // setPaused(uint256,bool)
|
setPaused: '0xdaff97b5', // setPaused(uint256,bool)
|
||||||
topUp: '0xc35a8e8b', // topUp(uint256,address,uint256)
|
topUp: '0x16645824', // topUp(uint256,address,uint256)
|
||||||
withdraw: '0x069a89ec', // withdraw(uint256,address,uint256,address)
|
withdraw: '0x5f0f48bd', // withdraw(uint256,address,uint256,address)
|
||||||
signerOf: '0x9f9eb5b1', // signerOf(uint256) view returns (address)
|
signerOf: '0x5161fdf5', // signerOf(uint256) view returns (address)
|
||||||
balances: '0xa7263000', // balances(uint256,address) view returns (uint256)
|
balances: '0x1f320331', // balances(uint256,address) view returns (uint256)
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
function pad32Hex(hex: string): string {
|
function pad32Hex(hex: string): string {
|
||||||
@ -175,7 +175,7 @@ export function buildAuthTypedData(opts: {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const SEL_SETTLE = '0x0c0a40c3'; // settle(uint256,address,address,uint256,bytes32,uint256,uint256,bytes)
|
const SEL_SETTLE = '0xdf3beb47'; // settle(uint256,address,address,uint256,bytes32,uint256,uint256,bytes)
|
||||||
|
|
||||||
export class AERE402SettlementClient {
|
export class AERE402SettlementClient {
|
||||||
constructor(public readonly provider: Eip1193Provider, public readonly facilitator: string) {}
|
constructor(public readonly provider: Eip1193Provider, public readonly facilitator: string) {}
|
||||||
|
|||||||
@ -135,10 +135,10 @@ export class AereAIReputationClient {
|
|||||||
const INFER_SEL = {
|
const INFER_SEL = {
|
||||||
modelEpochCount: '0xf407005b',
|
modelEpochCount: '0xf407005b',
|
||||||
modelOf: '0x1548a0e9',
|
modelOf: '0x1548a0e9',
|
||||||
epochOf: '0xc1a5ae12',
|
epochOf: '0x033ee480', // epochOf(address,bytes32,uint64)
|
||||||
registerModel: '0x703722ac',
|
registerModel: '0x703722ac',
|
||||||
commitEpoch: '0x7f11fb10',
|
commitEpoch: '0x7f11fb10',
|
||||||
verifyInference: '0xa2a98a64',
|
verifyInference: '0x46a121a5', // verifyInference(address,bytes32,uint64,bytes32,bytes32,uint64,bytes32,bytes32[])
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export class AereInferNetClient {
|
export class AereInferNetClient {
|
||||||
|
|||||||
@ -51,15 +51,15 @@ function encDynBytes(hex: string): { offset: bigint; encoded: string } {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const SEL = {
|
const SEL = {
|
||||||
CHALLENGE_WINDOW: '0xe9333e75',
|
CHALLENGE_WINDOW: '0xd62aad29', // CHALLENGE_WINDOW()
|
||||||
channels: '0xb29a8140', // channels(bytes32)
|
channels: '0x7a7ebd7b', // channels(bytes32)
|
||||||
open: '0x73c0d3a9', // open(address,address,address,uint256,uint256)
|
open: '0xf9bff880', // open(address,address,address,uint256,uint256)
|
||||||
cooperativeClose: '0xa9fbe4b6', // cooperativeClose(ChannelState,bytes,bytes)
|
cooperativeClose: '0xeb8edd09', // cooperativeClose((bytes32,uint256,uint256,uint256,uint256,uint256,bytes32,uint256),bytes,bytes)
|
||||||
startChallenge: '0xd1e26000', // startChallenge(ChannelState,bytes,bytes)
|
startChallenge: '0x1b6a88c1', // startChallenge((bytes32,uint256,uint256,uint256,uint256,uint256,bytes32,uint256),bytes,bytes)
|
||||||
overrideChallenge: '0x44b04beb', // overrideChallenge(ChannelState,bytes,bytes)
|
overrideChallenge: '0x70c84312', // overrideChallenge((bytes32,uint256,uint256,uint256,uint256,uint256,bytes32,uint256),bytes,bytes)
|
||||||
finalize: '0x6e3e98bf', // finalize(bytes32)
|
finalize: '0x92584d80', // finalize(bytes32)
|
||||||
settleHtlc: '0xa84f3c0e', // settleHtlc(bytes32,bytes)
|
settleHtlc: '0x9be71c4d', // settleHtlc(bytes32,bytes)
|
||||||
withdraw: '0x51cff8d9', // withdraw(bytes32)
|
withdraw: '0x8e19899e', // withdraw(bytes32)
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export class AereStateChannelsClient {
|
export class AereStateChannelsClient {
|
||||||
|
|||||||
@ -125,23 +125,23 @@ const POOL_SEL = {
|
|||||||
publishAssociationRoot: '0x9f92a5b1',
|
publishAssociationRoot: '0x9f92a5b1',
|
||||||
withdraw: '0xb7433691',
|
withdraw: '0xb7433691',
|
||||||
// R5/R6 additions
|
// R5/R6 additions
|
||||||
proposeAssociationRoot: '0x73fc3b6a', // proposeAssociationRoot(bytes32)
|
proposeAssociationRoot: '0xcca5d27b', // proposeAssociationRoot(bytes32)
|
||||||
challengeAssociationRoot: '0x45cb9085', // challengeAssociationRoot(bytes32,string) — bond required
|
challengeAssociationRoot: '0x45cb9085', // challengeAssociationRoot(bytes32,string) — bond required
|
||||||
dismissAssociationRootChallenge: '0x793819b9',
|
dismissAssociationRootChallenge: '0x793819b9',
|
||||||
associationRootProposedAt: '0x68c46b72',
|
associationRootProposedAt: '0xaff8a8bd', // associationRootProposedAt(bytes32)
|
||||||
associationRootChallenged: '0x8a76c7c8',
|
associationRootChallenged: '0x7cb2674e', // associationRootChallenged(bytes32)
|
||||||
associationRootDismissCount: '0x6c7560c8',
|
associationRootDismissCount: '0x5b2aa748', // associationRootDismissCount(bytes32)
|
||||||
associationRootChallenger: '0xbb84a4c8',
|
associationRootChallenger: '0x957d8c14', // associationRootChallenger(bytes32)
|
||||||
CHALLENGE_BOND: '0x9790ce71',
|
CHALLENGE_BOND: '0x9790ce71',
|
||||||
MAX_DISMISSALS_PER_ROOT: '0x9c9eea4f',
|
MAX_DISMISSALS_PER_ROOT: '0xde2ccfa5', // MAX_DISMISSALS_PER_ROOT()
|
||||||
CHALLENGE_BOND_BURN: '0x9f3098ff',
|
CHALLENGE_BOND_BURN: '0xf10dca34', // CHALLENGE_BOND_BURN()
|
||||||
BOND_TOKEN: '0x10ee36c5',
|
BOND_TOKEN: '0xf21b52e5', // BOND_TOKEN()
|
||||||
isKnownRoot: '0x2b7ac3f3',
|
isKnownRoot: '0x6d9833e3', // isKnownRoot(bytes32)
|
||||||
getLastRoot: '0x4cf088d9',
|
getLastRoot: '0xba70f757', // getLastRoot()
|
||||||
ROOT_HISTORY_SIZE: '0xb0d3e9b4',
|
ROOT_HISTORY_SIZE: '0xcd87a3b4', // ROOT_HISTORY_SIZE()
|
||||||
TREE_DEPTH: '0x7d9f6c6f',
|
TREE_DEPTH: '0xf1650536', // TREE_DEPTH()
|
||||||
nextLeafIndex: '0x3b15aabf',
|
nextLeafIndex: '0x0be4f422', // nextLeafIndex()
|
||||||
ASSOCIATION_ROOT_CHALLENGE_WINDOW: '0x37dd9e6c',
|
ASSOCIATION_ROOT_CHALLENGE_WINDOW: '0x03cf6363', // ASSOCIATION_ROOT_CHALLENGE_WINDOW()
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export class AereCompliancePoolClient {
|
export class AereCompliancePoolClient {
|
||||||
|
|||||||
@ -35,27 +35,56 @@ function encodeDynamicBytes(hex: string): { offset: string; body: string } {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ===================== AereSanctionsRegistry ====================== */
|
/* ===================== AereSanctionsRegistry ====================== */
|
||||||
|
/* 2026-10-15 (D-512): this client called currentRoot() and an isSanctioned(address,uint16,bytes32[]) that the deployed
|
||||||
|
* contract does not have. The registry keeps one Merkle root per epoch: read latestEpoch(), the root and state of an epoch
|
||||||
|
* through snapshotStatus(uint256), and check an address with a Merkle proof against a given or the latest attested epoch. */
|
||||||
|
|
||||||
const SANCT_SEL = {
|
const SANCT_SEL = {
|
||||||
currentRoot: '0x6f29ed46', // currentRoot()
|
latestEpoch: '0x9cb118bf', // latestEpoch()
|
||||||
isSanctioned: '0x7ad8e02b', // isSanctioned(address,uint16,bytes32[])
|
snapshotStatus: '0x3d1146fa', // snapshotStatus(uint256)
|
||||||
commitRoot: '0x9b30b9ae', // commitRoot(bytes32,uint16,string) — placeholder
|
isSanctioned: '0x7acc3cf1', // isSanctioned(uint256,address,uint16,bytes32[])
|
||||||
|
isSanctionedLatest: '0xf6035837', // isSanctionedLatest(address,uint16,bytes32[])
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
/** list ids as defined by the contract (LIST_OFAC_SDN = 1, ...). */
|
||||||
|
export const SANCTIONS_LIST = { OFAC_SDN: 1, OFAC_SSI: 2, EU_CONSOLIDATED: 3, UK_HMT: 4, UN_CONSOLIDATED: 5 } as const;
|
||||||
|
|
||||||
|
const encProof = (proof: string[]) => encUint(BigInt(proof.length)) + proof.map(encBytes32).join('');
|
||||||
|
|
||||||
export class AereSanctionsRegistryClient {
|
export class AereSanctionsRegistryClient {
|
||||||
constructor(public readonly provider: RpcProvider, public readonly address: string) {}
|
constructor(public readonly provider: RpcProvider, public readonly address: string) {}
|
||||||
|
|
||||||
async currentRoot(): Promise<string> {
|
async latestEpoch(): Promise<bigint> {
|
||||||
return await ethCall(this.provider, this.address, SANCT_SEL.currentRoot);
|
return BigInt(await ethCall(this.provider, this.address, SANCT_SEL.latestEpoch));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Root committed for `epoch` (default: the latest epoch). The registry holds one snapshot per epoch. */
|
||||||
|
async currentRoot(epoch?: bigint): Promise<string> {
|
||||||
|
const e = epoch ?? await this.latestEpoch();
|
||||||
|
const res = await ethCall(this.provider, this.address, SANCT_SEL.snapshotStatus + encUint(e));
|
||||||
|
return '0x' + res.replace(/^0x/, '').slice(0, 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** True iff the proof shows `addr` on `listId` in snapshot `epoch` AND that snapshot is attested. */
|
||||||
|
async isSanctioned(epoch: bigint, addr: string, listId: number, proof: string[]): Promise<boolean> {
|
||||||
|
const data = SANCT_SEL.isSanctioned + encUint(epoch) + encAddr(addr) + pad32(listId.toString(16)) + encUint(4n * 32n) + encProof(proof);
|
||||||
|
return BigInt(await ethCall(this.provider, this.address, data)) === 1n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Same check against the latest attested epoch; returns the verdict and that epoch (0 if none is attested). */
|
||||||
|
async isSanctionedLatest(addr: string, listId: number, proof: string[]): Promise<{ sanctioned: boolean; attestedEpoch: bigint }> {
|
||||||
|
const data = SANCT_SEL.isSanctionedLatest + encAddr(addr) + pad32(listId.toString(16)) + encUint(3n * 32n) + encProof(proof);
|
||||||
|
const res = (await ethCall(this.provider, this.address, data)).replace(/^0x/, '');
|
||||||
|
return { sanctioned: BigInt('0x' + res.slice(0, 64)) === 1n, attestedEpoch: BigInt('0x' + res.slice(64, 128)) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===================== ChainalysisOracleWrapper =================== */
|
/* ===================== ChainalysisOracleWrapper =================== */
|
||||||
|
|
||||||
const CHAIN_SEL = {
|
const CHAIN_SEL = {
|
||||||
isSanctioned: '0xdf592f7d', // isSanctioned(address)
|
isSanctioned: '0xdf592f7d', // isSanctioned(address)
|
||||||
upstream: '0x6c0360eb', // upstream()
|
upstreamOracle: '0xff132a15', // upstreamOracle()
|
||||||
locked: '0xcf30901', // locked()
|
locked: '0xcf309012', // locked()
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export class ChainalysisOracleWrapperClient {
|
export class ChainalysisOracleWrapperClient {
|
||||||
@ -70,32 +99,44 @@ export class ChainalysisOracleWrapperClient {
|
|||||||
return true; // fails closed
|
return true; // fails closed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** The upstream oracle the wrapper forwards to; the zero address means none is configured and every call fails closed. */
|
||||||
|
async upstreamOracle(): Promise<string> {
|
||||||
|
return '0x' + (await ethCall(this.provider, this.address, CHAIN_SEL.upstreamOracle)).slice(-40);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===================== AereTravelRuleHashRegistry ================= */
|
/* ===================== AereTravelRuleHashRegistry ================= */
|
||||||
|
/* 2026-10-15 (D-512): this client read committedHashes(bytes32) and status(bytes32), which the contract does not have.
|
||||||
|
* Commitments are numbered: read one by id through commitments(uint256). */
|
||||||
|
|
||||||
const TRR_SEL = {
|
const TRR_SEL = {
|
||||||
committedHashes: '0x6c5e6e95', // committedHashes(bytes32)
|
commitments: '0x49ce8997', // commitments(uint256)
|
||||||
status: '0x200d2ed2', // status(bytes32)
|
nextCommitmentId: '0x5ac48e6d', // nextCommitmentId()
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export class AereTravelRuleHashRegistryClient {
|
export class AereTravelRuleHashRegistryClient {
|
||||||
constructor(public readonly provider: RpcProvider, public readonly address: string) {}
|
constructor(public readonly provider: RpcProvider, public readonly address: string) {}
|
||||||
|
|
||||||
/** State enum: 0=Unknown, 1=Committed, 2=Acknowledged, 3=Disputed. */
|
async nextCommitmentId(): Promise<bigint> {
|
||||||
async status(hash: string): Promise<number> {
|
return BigInt(await ethCall(this.provider, this.address, TRR_SEL.nextCommitmentId));
|
||||||
const res = await ethCall(this.provider, this.address, TRR_SEL.status + encBytes32(hash));
|
}
|
||||||
return Number(BigInt(res));
|
|
||||||
|
/** State of commitment `id`: 0=Committed, 1=Acknowledged, 2=Disputed (the contract's State enum). */
|
||||||
|
async status(id: bigint): Promise<number> {
|
||||||
|
const res = (await ethCall(this.provider, this.address, TRR_SEL.commitments + encUint(id))).replace(/^0x/, '');
|
||||||
|
// words: payloadHash, originatorVasp, beneficiaryVasp, threshold, committedAt, statusUpdatedAt, state, offset(disputeReason)
|
||||||
|
return Number(BigInt('0x' + res.slice(6 * 64, 7 * 64)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===================== AereForensicEventRegistry ================== */
|
/* ===================== AereForensicEventRegistry ================== */
|
||||||
|
|
||||||
const FORENSIC_SEL = {
|
const FORENSIC_SEL = {
|
||||||
subjectAlertCount: '0x7c1d3d0a', // subjectAlertCount(address)
|
subjectAlertCount: '0x3fa664d6', // subjectAlertCount(address)
|
||||||
recentConfirmedAlertCount: '0x44e3a39d', // recentConfirmedAlertCount(address,uint8,uint256)
|
recentConfirmedAlertCount: '0xd9f77c99', // recentConfirmedAlertCount(address,uint8,uint256)
|
||||||
nextBotId: '0xf4cae09e', // nextBotId()
|
nextBotId: '0x6fc0c79d', // nextBotId()
|
||||||
nextAlertId: '0xa0d49d3a', // nextAlertId()
|
nextAlertId: '0x260be2a2', // nextAlertId()
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export class AereForensicEventRegistryClient {
|
export class AereForensicEventRegistryClient {
|
||||||
@ -116,9 +157,9 @@ export class AereForensicEventRegistryClient {
|
|||||||
/* ===================== AereZKScreen =============================== */
|
/* ===================== AereZKScreen =============================== */
|
||||||
|
|
||||||
const ZK_SEL = {
|
const ZK_SEL = {
|
||||||
isCleared: '0xb6a5d7de', // isCleared(address,bytes32,uint256)
|
isCleared: '0x011f0451', // isCleared(address,bytes32,uint256)
|
||||||
clearedAt: '0xc5f4dec0', // clearedAt(address,bytes32)
|
clearedAt: '0xedddc71f', // clearedAt(address,bytes32)
|
||||||
submitProof: '0x77a91da7', // submitProof(bytes32,bytes,bytes)
|
submitProof: '0xeb90e2cb', // submitProof(bytes32,bytes,bytes)
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export class AereZKScreenClient {
|
export class AereZKScreenClient {
|
||||||
@ -163,10 +204,10 @@ export class AereZKScreenClient {
|
|||||||
* proof of inference see AereZKMLVerifier. */
|
* proof of inference see AereZKMLVerifier. */
|
||||||
|
|
||||||
const AI_SEL = {
|
const AI_SEL = {
|
||||||
models: '0x88e98b22', // models(bytes32)
|
models: '0xe236f46b', // models(bytes32)
|
||||||
attestationCount: '0x8b2c3a99', // attestationCount(bytes32)
|
attestationCount: '0xd65ddd52', // attestationCount(bytes32)
|
||||||
registerModel: '0xa9b5a9eb', // registerModel(bytes32,address,string)
|
registerModel: '0x31c0953b', // registerModel(bytes32,address,string)
|
||||||
anchor: '0x5b9babe0', // anchor(bytes32,bytes32,bytes32,bytes32,uint256,uint256,bytes)
|
anchor: '0x10912ffc', // anchor(bytes32,bytes32,bytes32,bytes32,uint256,uint256,bytes)
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export class AereAIProofClient {
|
export class AereAIProofClient {
|
||||||
|
|||||||
@ -21,15 +21,16 @@ async function ethSend(p: RpcProvider, from: string, to: string, data: string):
|
|||||||
}
|
}
|
||||||
|
|
||||||
const SEL = {
|
const SEL = {
|
||||||
FOUNDATION: '0x4d09f93e', // FOUNDATION()
|
FOUNDATION: '0x65df2e51', // FOUNDATION()
|
||||||
COOLDOWN_SECONDS: '0xb47d5cf5', // COOLDOWN_SECONDS()
|
COOLDOWN_SECONDS: '0x72b49d63', // COOLDOWN_SECONDS()
|
||||||
markets: '0x2c43cab8', // markets(address)
|
markets: '0x8e8f294b', // markets(address)
|
||||||
balances: '0x27e235e3', // balances(address)
|
balances: '0x27e235e3', // balances(address)
|
||||||
coverageRemaining: '0x1d29df0e', // coverageRemaining(address)
|
coverageRemaining: '0xb8046933', // coverageRemaining(address)
|
||||||
cooldownReady: '0x3a09a73e', // cooldownReady(address)
|
cooldownReady: '0xd881ceec', // cooldownReady(address)
|
||||||
registerMarket: '0xc6da18d4', // registerMarket(address,uint256)
|
proposeMarket: '0xe993ea12', // proposeMarket(address,uint256)
|
||||||
donate: '0xf14fcbc8', // donate(address,uint256)
|
registerMarket: '0xa79b9ec9', // registerMarket(address)
|
||||||
coverBadDebt: '0xa90c1e1c', // coverBadDebt(address,address,uint256)
|
donate: '0xe69d849d', // donate(address,uint256)
|
||||||
|
coverBadDebt: '0x71c8886f', // coverBadDebt(address,address,uint256)
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export class AereInsuranceFundClient {
|
export class AereInsuranceFundClient {
|
||||||
@ -59,9 +60,18 @@ export class AereInsuranceFundClient {
|
|||||||
return ethSend(this.provider, from, this.address, SEL.donate + encAddr(token) + encUint(amount));
|
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> {
|
* Foundation-only, step 1 of 2: propose a market with a lifetime coverage cap. The contract enforces
|
||||||
return ethSend(this.provider, from, this.address, SEL.registerMarket + encAddr(market) + encUint(lifetimeCap));
|
* REGISTRATION_DELAY before step 2. (2026-10-15: this client used to send a one-step
|
||||||
|
* registerMarket(address,uint256) that the contract does not have.)
|
||||||
|
*/
|
||||||
|
async proposeMarket(from: string, market: string, lifetimeCap: bigint): Promise<string> {
|
||||||
|
return ethSend(this.provider, from, this.address, SEL.proposeMarket + encAddr(market) + encUint(lifetimeCap));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Foundation-only, step 2 of 2: register a proposed market once REGISTRATION_DELAY has passed. */
|
||||||
|
async registerMarket(from: string, market: string): Promise<string> {
|
||||||
|
return ethSend(this.provider, from, this.address, SEL.registerMarket + encAddr(market));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Foundation-only: pay down `amount` of `borrower`'s debt on `market`. */
|
/** Foundation-only: pay down `amount` of `borrower`'s debt on `market`. */
|
||||||
|
|||||||
@ -21,47 +21,47 @@ export interface LendingMarketConfig {
|
|||||||
|
|
||||||
const SEL = {
|
const SEL = {
|
||||||
// immutable views
|
// immutable views
|
||||||
COLLATERAL: '0xfb4cd02f', // COLLATERAL()
|
COLLATERAL: '0x24bbab8b', // COLLATERAL()
|
||||||
DEBT_TOKEN: '0xea5b5ddf', // DEBT_TOKEN()
|
DEBT_TOKEN: '0x854db43c', // DEBT_TOKEN()
|
||||||
SINK: '0xf4f3b200', // SINK()
|
SINK: '0xae9fc205', // SINK()
|
||||||
ORACLE: '0x7dc0d1d0', // ORACLE()
|
ORACLE: '0x38013f02', // ORACLE()
|
||||||
LTV_BPS: '0xcbc4cdc7', // LTV_BPS()
|
LTV_BPS: '0xfae3706f', // LTV_BPS()
|
||||||
LIQ_THRESHOLD_BPS: '0xc0c5294d', // LIQ_THRESHOLD_BPS()
|
LIQ_THRESHOLD_BPS: '0xe3cd32d6', // LIQ_THRESHOLD_BPS()
|
||||||
LIQ_BONUS_BPS: '0x3a86d9b3', // LIQ_BONUS_BPS()
|
LIQ_BONUS_BPS: '0xe3513531', // LIQ_BONUS_BPS()
|
||||||
BORROW_FEE_BPS: '0x47bf8b54', // BORROW_FEE_BPS()
|
BORROW_FEE_BPS: '0x185691da', // BORROW_FEE_BPS()
|
||||||
MARKET_DEBT_CAP: '0xcca5e09e', // MARKET_DEBT_CAP()
|
MARKET_DEBT_CAP: '0xfaac9ee3', // MARKET_DEBT_CAP()
|
||||||
COLLATERAL_DECIMALS: '0x99e9f4ad', // COLLATERAL_DECIMALS()
|
COLLATERAL_DECIMALS: '0x4ddde78d', // COLLATERAL_DECIMALS()
|
||||||
DEBT_DECIMALS: '0x4d9e7826', // DEBT_DECIMALS()
|
DEBT_DECIMALS: '0xbad8a798', // DEBT_DECIMALS()
|
||||||
|
|
||||||
// state views
|
// state views
|
||||||
collateralOf: '0x8aef7ddf', // collateralOf(address)
|
collateralOf: '0x1aefb107', // collateralOf(address)
|
||||||
debtOf: '0xcc4d2f49', // debtOf(address)
|
debtOf: '0xd283e75f', // debtOf(address)
|
||||||
supplierScaled: '0x9d7d6f0d', // supplierScaled(address)
|
supplierScaled: '0x68fdada6', // supplierScaled(address)
|
||||||
supplierBalance: '0x9d9f3ff6', // supplierBalance(address)
|
supplierBalance: '0x1de233e8', // supplierBalance(address)
|
||||||
debtBalance: '0x33ed81e4', // debtBalance(address)
|
debtBalance: '0x11005b07', // debtBalance(address)
|
||||||
borrowIndex: '0xaa5af0fd', // borrowIndex()
|
borrowIndex: '0xaa5af0fd', // borrowIndex()
|
||||||
supplyIndex: '0xb02f7d5e', // supplyIndex()
|
supplyIndex: '0x98f1bc12', // supplyIndex()
|
||||||
totalBorrowsScaled: '0xc0c44d6b', // totalBorrowsScaled()
|
totalBorrowsScaled: '0x03647a88', // totalBorrowsScaled()
|
||||||
totalSuppliedScaled: '0x7b0b3da7', // totalSuppliedScaled()
|
totalSuppliedScaled: '0x2785ce6d', // totalSuppliedScaled()
|
||||||
totalBorrowsCurrent: '0xc26c9116', // totalBorrowsCurrent()
|
totalBorrowsCurrent: '0x73acee98', // totalBorrowsCurrent()
|
||||||
totalSuppliedCurrent: '0x57e3c7fc', // totalSuppliedCurrent()
|
totalSuppliedCurrent: '0x9a1509b4', // totalSuppliedCurrent()
|
||||||
pendingSinkFee: '0x99c50fcb', // pendingSinkFee()
|
pendingSinkFee: '0x20a0e28c', // pendingSinkFee()
|
||||||
borrowRatePerSecond: '0x9e6dadce', // borrowRatePerSecond()
|
borrowRatePerSecond: '0x52609750', // borrowRatePerSecond()
|
||||||
borrowPaused: '0x42b6e3bf', // borrowPaused()
|
borrowPaused: '0xbcb4bbea', // borrowPaused()
|
||||||
depositPaused: '0x6a5db0fa', // depositPaused()
|
depositPaused: '0x02befd24', // depositPaused()
|
||||||
healthFactor: '0xe8b9c2dd', // healthFactor(address)
|
healthFactor: '0x6ad9f9df', // healthFactor(address)
|
||||||
|
|
||||||
// write
|
// write
|
||||||
accrueInterest: '0x59601e8a', // accrueInterest()
|
accrueInterest: '0xa6afed95', // accrueInterest()
|
||||||
flushSinkFee: '0x71a5ba73', // flushSinkFee()
|
flushSinkFee: '0x599fb8ac', // flushSinkFee()
|
||||||
supply: '0xf2b9fdb8', // supply(uint256)
|
supply: '0x35403023', // supply(uint256)
|
||||||
redeem: '0xdb006a75', // redeem(uint256)
|
redeem: '0xdb006a75', // redeem(uint256)
|
||||||
depositCollateral: '0x80aebec5', // depositCollateral(uint256)
|
depositCollateral: '0xbad4a01f', // depositCollateral(uint256)
|
||||||
withdrawCollateral: '0xeb0aaa4b', // withdrawCollateral(uint256)
|
withdrawCollateral: '0x6112fe2e', // withdrawCollateral(uint256)
|
||||||
borrow: '0xc5ebeaec', // borrow(uint256)
|
borrow: '0xc5ebeaec', // borrow(uint256)
|
||||||
repay: '0x0e752702', // repay(uint256)
|
repay: '0x371fd8e6', // repay(uint256)
|
||||||
repayOnBehalfOf: '0x8f1a3bf0', // repayOnBehalfOf(address,uint256)
|
repayOnBehalfOf: '0xede66a45', // repayOnBehalfOf(address,uint256)
|
||||||
liquidate: '0xf5e3c462', // liquidate(address,uint256)
|
liquidate: '0xbcbaf487', // liquidate(address,uint256)
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
/* ----------------------------- helpers ---------------------------------- */
|
/* ----------------------------- helpers ---------------------------------- */
|
||||||
|
|||||||
@ -19,13 +19,13 @@ async function ethSend(p: RpcProvider, from: string, to: string, data: string):
|
|||||||
}
|
}
|
||||||
|
|
||||||
const SEL = {
|
const SEL = {
|
||||||
PAYOUT_TOKEN: '0x935ca8e6', // PAYOUT_TOKEN()
|
PAYOUT_TOKEN: '0xe2f6f511', // PAYOUT_TOKEN()
|
||||||
ORACLE: '0x7dc0d1d0', // ORACLE()
|
ORACLE: '0x38013f02', // ORACLE()
|
||||||
FOUNDATION: '0x4d09f93e', // FOUNDATION()
|
FOUNDATION: '0x65df2e51', // FOUNDATION()
|
||||||
configs: '0x1d12be96', // configs(address)
|
configs: '0xfce89878', // configs(address)
|
||||||
states: '0xb95da3ec', // states(address)
|
states: '0x02a22337', // states(address)
|
||||||
periodRemaining: '0x3aff0d34', // periodRemaining(address)
|
periodRemaining: '0x0a41950f', // periodRemaining(address)
|
||||||
payoutLiquidity: '0x8b8a55be', // payoutLiquidity()
|
payoutLiquidity: '0x875d90e6', // payoutLiquidity()
|
||||||
redeem: '0x1e9a6950', // redeem(address,uint256)
|
redeem: '0x1e9a6950', // redeem(address,uint256)
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
|||||||
@ -27,19 +27,19 @@ async function ethSend(p: RpcProvider, from: string, to: string, data: string, v
|
|||||||
|
|
||||||
const FAC_SEL = {
|
const FAC_SEL = {
|
||||||
// immutable views
|
// immutable views
|
||||||
BOND_TOKEN: '0x18b13f55', // BOND_TOKEN()
|
BOND_TOKEN: '0xf21b52e5', // BOND_TOKEN()
|
||||||
SINK: '0xf4f3b200', // SINK()
|
SINK: '0xae9fc205', // SINK()
|
||||||
REGISTRATION_BOND: '0x4b094c4b', // REGISTRATION_BOND()
|
REGISTRATION_BOND: '0xc89d37de', // REGISTRATION_BOND()
|
||||||
MIN_SINK_BPS: '0x9dabd040', // MIN_SINK_BPS()
|
MIN_SINK_BPS: '0x354ec275', // MIN_SINK_BPS()
|
||||||
DEFAULT_CHALLENGE_WINDOW: '0x8e8a6f3a', // DEFAULT_CHALLENGE_WINDOW()
|
DEFAULT_CHALLENGE_WINDOW: '0xda493740', // DEFAULT_CHALLENGE_WINDOW()
|
||||||
FOUNDATION: '0x4d09f93e', // FOUNDATION()
|
FOUNDATION: '0x65df2e51', // FOUNDATION()
|
||||||
// state views
|
// state views
|
||||||
rollups: '0xdcecb8e3', // rollups(bytes32)
|
rollups: '0x59a181dc', // rollups(bytes32)
|
||||||
rollupCount: '0xff19a3a4', // rollupCount()
|
rollupCount: '0xf4e92675', // rollupCount()
|
||||||
// writes
|
// writes
|
||||||
registerRollup: '0xbb4ab86c', // registerRollup(bytes32,address,address,address,uint16,uint16,uint16,uint256,uint64,string)
|
registerRollup: '0x3878aaf1', // registerRollup(bytes32,address,address,address,uint16,uint16,uint16,uint256,uint64,uint64,string) (AereRaaSFactoryV2)
|
||||||
updateMetadata: '0xa1ae9b0e', // updateMetadata(bytes32,string)
|
updateMetadata: '0xa375765e', // updateMetadata(bytes32,string)
|
||||||
exitRollup: '0x73db2bba', // exitRollup(bytes32,address,uint64,bytes)
|
exitRollup: '0x72fbb1bb', // exitRollup(bytes32,address,uint64,bytes)
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export class AereRaaSFactoryClient {
|
export class AereRaaSFactoryClient {
|
||||||
@ -73,7 +73,8 @@ export class AereRaaSFactoryClient {
|
|||||||
rollupBps: number;
|
rollupBps: number;
|
||||||
sequencerBps: number;
|
sequencerBps: number;
|
||||||
minChallengeBond: bigint;
|
minChallengeBond: bigint;
|
||||||
challengeWindow: number;
|
challengeWindow: number; // seconds; 0 = the factory's DEFAULT_CHALLENGE_WINDOW
|
||||||
|
defenseGrace?: number; // seconds; 0 or omitted = the factory's DEFAULT_DEFENSE_GRACE (AereRaaSFactoryV2)
|
||||||
metadataUri: string;
|
metadataUri: string;
|
||||||
}
|
}
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
@ -88,7 +89,8 @@ export class AereRaaSFactoryClient {
|
|||||||
encUint(BigInt(opts.sequencerBps)) +
|
encUint(BigInt(opts.sequencerBps)) +
|
||||||
encUint(opts.minChallengeBond) +
|
encUint(opts.minChallengeBond) +
|
||||||
encUint(BigInt(opts.challengeWindow)) +
|
encUint(BigInt(opts.challengeWindow)) +
|
||||||
encUint(0x140n); // 10 head slots * 32 = 320 = 0x140
|
encUint(BigInt(opts.defenseGrace ?? 0)) +
|
||||||
|
encUint(0x160n); // 11 head slots * 32 = 352 = 0x160
|
||||||
const padded = Buffer.alloc(Math.ceil(meta.length / 32) * 32);
|
const padded = Buffer.alloc(Math.ceil(meta.length / 32) * 32);
|
||||||
meta.copy(padded);
|
meta.copy(padded);
|
||||||
const dyn = encUint(BigInt(meta.length)) + padded.toString('hex');
|
const dyn = encUint(BigInt(meta.length)) + padded.toString('hex');
|
||||||
@ -100,28 +102,28 @@ export class AereRaaSFactoryClient {
|
|||||||
/* ============================ Settlement ============================= */
|
/* ============================ Settlement ============================= */
|
||||||
|
|
||||||
const SET_SEL = {
|
const SET_SEL = {
|
||||||
ROLLUP_ID: '0x7b0a4eb1', // ROLLUP_ID()
|
ROLLUP_ID: '0xb5ed5559', // ROLLUP_ID()
|
||||||
SINK: '0xf4f3b200', // SINK()
|
SINK: '0xae9fc205', // SINK()
|
||||||
DEBT_TOKEN: '0xea5b5ddf', // DEBT_TOKEN()
|
DEBT_TOKEN: '0x854db43c', // DEBT_TOKEN()
|
||||||
CHALLENGE_WINDOW: '0x7a6a4abe', // CHALLENGE_WINDOW()
|
CHALLENGE_WINDOW: '0xd62aad29', // CHALLENGE_WINDOW()
|
||||||
SINK_BPS: '0xb3f54bdd', // SINK_BPS()
|
SINK_BPS: '0x10dbc17d', // SINK_BPS()
|
||||||
ROLLUP_BPS: '0xc70aa727', // ROLLUP_BPS()
|
ROLLUP_BPS: '0x7c103fdc', // ROLLUP_BPS()
|
||||||
SEQUENCER_BPS: '0xe35d8b85', // SEQUENCER_BPS()
|
SEQUENCER_BPS: '0x9d09bcd5', // SEQUENCER_BPS()
|
||||||
rollupOwner: '0x0e8d63c0', // rollupOwner()
|
rollupOwner: '0x7c3a72a0', // rollupOwner()
|
||||||
sequencer: '0x42d1de27', // sequencer()
|
sequencer: '0x5c1bba38', // sequencer()
|
||||||
latestEpoch: '0x6f6db00f', // latestEpoch()
|
latestEpoch: '0x9cb118bf', // latestEpoch()
|
||||||
latestFinalisedEpoch:'0x3aac4670', // latestFinalisedEpoch()
|
latestFinalisedEpoch:'0x24b5e709', // latestFinalisedEpoch()
|
||||||
isFinalised: '0x3a8a4a3e', // isFinalised(uint256)
|
isFinalised: '0xc7a9b0ed', // isFinalised(uint256)
|
||||||
totalRevenueSettled: '0xf3b6db95', // totalRevenueSettled()
|
totalRevenueSettled: '0x335d152b', // totalRevenueSettled()
|
||||||
|
|
||||||
proposeStateRoot: '0x9e706b08', // proposeStateRoot(uint256,bytes32,bytes32)
|
proposeStateRoot: '0xe871f194', // proposeStateRoot(uint256,bytes32,bytes32)
|
||||||
advanceFinalisation: '0xb78f2ebd', // advanceFinalisation()
|
advanceFinalisation: '0x51f09e3b', // advanceFinalisation()
|
||||||
challenge: '0x8da548fa', // challenge(uint256,uint256,bytes32)
|
challenge: '0xe0f7c5ae', // challenge(uint256,uint256,bytes32)
|
||||||
resolveChallenge: '0x437f2ba0', // resolveChallenge(uint256,bool)
|
resolveChallenge: '0x94a754e0', // resolveChallenge(uint256,bool)
|
||||||
resolveChallengeExpired: '0xb1cc5a3d', // resolveChallengeExpired(uint256)
|
resolveChallengeExpired: '0x5454e09a', // resolveChallengeExpired(uint256)
|
||||||
settleRevenue: '0xc7c1aa8c', // settleRevenue(uint256)
|
settleRevenue: '0xe3c22c42', // settleRevenue(uint256)
|
||||||
setSequencer: '0xa6f9dae1', // setSequencer(address)
|
setSequencer: '0x2547fa3e', // setSequencer(address)
|
||||||
transferOwner: '0xc6dad082', // transferOwner(address)
|
transferOwner: '0x4fb2e45d', // transferOwner(address)
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export class AereRollupSettlementClient {
|
export class AereRollupSettlementClient {
|
||||||
|
|||||||
@ -33,20 +33,20 @@ export interface AereSinkConfig {
|
|||||||
// 4-byte function selectors. Computed once at module load and held constant.
|
// 4-byte function selectors. Computed once at module load and held constant.
|
||||||
// (Verified via cast sig-of <name>().)
|
// (Verified via cast sig-of <name>().)
|
||||||
const SEL = {
|
const SEL = {
|
||||||
AERE: '0x1cc59c1b', // AERE()
|
AERE: '0xe3b11fda', // AERE()
|
||||||
BURN_VAULT: '0x4e7eee76', // BURN_VAULT()
|
BURN_VAULT: '0x25bad93c', // BURN_VAULT()
|
||||||
SAERE_VAULT: '0xc46aedd7', // SAERE_VAULT()
|
SAERE_VAULT: '0x4f0a5e94', // SAERE_VAULT()
|
||||||
DEX_ROUTER: '0x3b1664c1', // DEX_ROUTER()
|
DEX_ROUTER: '0x7af11ac0', // DEX_ROUTER()
|
||||||
BURN_BPS: '0x9748d6c0', // BURN_BPS()
|
BURN_BPS: '0xa37a9fc0', // BURN_BPS()
|
||||||
BUYBACK_BPS: '0xb56fcecf', // BUYBACK_BPS()
|
BUYBACK_BPS: '0x1a17db67', // BUYBACK_BPS()
|
||||||
STAKER_YIELD_BPS: '0xc77b3402', // STAKER_YIELD_BPS()
|
STAKER_YIELD_BPS: '0x7a03922d', // STAKER_YIELD_BPS()
|
||||||
MAX_SLIPPAGE_BPS: '0xfb6fb1f9', // MAX_SLIPPAGE_BPS()
|
MAX_SLIPPAGE_BPS: '0xe229cd76', // MAX_SLIPPAGE_BPS()
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
// flush(address,uint256) — for write
|
// flush(address,uint256) — for write
|
||||||
const FLUSH_SELECTOR = '0x6cd5c39b';
|
const FLUSH_SELECTOR = '0x96fd1c42';
|
||||||
// sweepDust(address) — for write
|
// sweepDust(address) — for write
|
||||||
const SWEEP_DUST_SELECTOR = '0xeb1a0a96';
|
const SWEEP_DUST_SELECTOR = '0xac7ad478';
|
||||||
|
|
||||||
/* ----------------------------- helper functions ---------------------------- */
|
/* ----------------------------- helper functions ---------------------------- */
|
||||||
|
|
||||||
|
|||||||
93
src/test/selectors-live.ts
Normal file
93
src/test/selectors-live.ts
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
/**
|
||||||
|
* selectors-live.ts — prove the repaired SDK clients against the REAL contracts on chain 2800 (D-512).
|
||||||
|
*
|
||||||
|
* On 2026-10-15 a site page showed "0 rollups" because the SDK's RaaS client called rollupCount() with a selector that
|
||||||
|
* no contract has; the call reverted and the caller printed a zero. The same day ~130 selectors across ten clients were
|
||||||
|
* found wrong, none of them even matching the signature written next to it. The offline gate
|
||||||
|
* (aerenew/scripts/deschise/sdk-selectori-corecti.cjs) now checks every selector against keccak and the compiled ABI;
|
||||||
|
* this file checks the other half: that the clients, as shipped, get an ANSWER from the deployed contracts.
|
||||||
|
*
|
||||||
|
* Every read below must return without a revert. Values are printed, not asserted, except where the chain fixes them
|
||||||
|
* (RaaS bond, sink floor, list of sanctions epochs). Negative control: the same RaaS read with the pre-repair selector
|
||||||
|
* must revert, otherwise this file could not tell a broken client from a working one.
|
||||||
|
*
|
||||||
|
* node dist/test/selectors-live.js [rpc] (network; not part of `npm test`)
|
||||||
|
* Read-only. No keys, no transactions.
|
||||||
|
*/
|
||||||
|
import { AereRaaSFactoryClient } from '../raas/index.js';
|
||||||
|
import { AereSinkClient } from '../sink/AereSinkClient.js';
|
||||||
|
import { LendingMarketClient, AereInsuranceFundClient } from '../lending/index.js';
|
||||||
|
import { AereSanctionsRegistryClient, ChainalysisOracleWrapperClient, AereTravelRuleHashRegistryClient, AereForensicEventRegistryClient } from '../compliance/index.js';
|
||||||
|
import { AereCompliancePoolClient } from '../compliance/NewComplianceClients.js';
|
||||||
|
|
||||||
|
const RPC = process.argv[2] ?? 'https://rpc.aere.network';
|
||||||
|
const provider = {
|
||||||
|
async request({ method, params }: { method: string; params: unknown[] }): Promise<unknown> {
|
||||||
|
const r = await fetch(RPC, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params }) });
|
||||||
|
const j = (await r.json()) as { result?: unknown; error?: { message: string } };
|
||||||
|
if (j.error) throw new Error(j.error.message);
|
||||||
|
return j.result;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let failures = 0;
|
||||||
|
async function check(label: string, f: () => Promise<unknown>, expect?: (v: unknown) => boolean): Promise<void> {
|
||||||
|
try {
|
||||||
|
const v = await f();
|
||||||
|
const shown = typeof v === 'bigint' ? v.toString() : JSON.stringify(v, (_k, x) => (typeof x === 'bigint' ? x.toString() : x));
|
||||||
|
if (expect && !expect(v)) { failures++; console.log(` FAIL ${label}: unexpected ${shown}`); }
|
||||||
|
else console.log(` PASS ${label}: ${shown}`);
|
||||||
|
} catch (e) {
|
||||||
|
failures++;
|
||||||
|
console.log(` FAIL ${label}: ${(e as Error).message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main(): Promise<void> {
|
||||||
|
console.log(`selector live proof against ${RPC}\n`);
|
||||||
|
const raas = new AereRaaSFactoryClient(provider, '0xB7F8c754AC3155197d76f01857172bBd5a5F39Ab');
|
||||||
|
await check('RaaS V2 rollupCount()', () => raas.rollupCount());
|
||||||
|
await check('RaaS V2 REGISTRATION_BOND() = 1000 AERE', () => raas.getRegistrationBond(), (v) => v === 1000n * 10n ** 18n);
|
||||||
|
await check('RaaS V2 MIN_SINK_BPS() = 1000', () => raas.getMinSinkBps(), (v) => v === 1000);
|
||||||
|
await check('RaaS V2 SINK()', () => raas.getSink(), (v) => typeof v === 'string' && /^0x[0-9a-f]{40}$/i.test(v));
|
||||||
|
|
||||||
|
// negative control: the pre-repair rollupCount selector must revert, or this file proves nothing
|
||||||
|
await provider.request({ method: 'eth_call', params: [{ to: '0xB7F8c754AC3155197d76f01857172bBd5a5F39Ab', data: '0xff19a3a4' }, 'latest'] }).then(
|
||||||
|
() => { failures++; console.log(' FAIL negative control: the old selector 0xff19a3a4 answered; this proof cannot tell broken from working'); },
|
||||||
|
() => console.log(' PASS negative control: the old selector 0xff19a3a4 reverts, as it did on the site'),
|
||||||
|
);
|
||||||
|
|
||||||
|
const sink = new AereSinkClient({ provider: provider as never, address: '0x69581B86A48161b067Ff4E01544780625B231676' });
|
||||||
|
await check('AereSink readConfig()', () => sink.readConfig());
|
||||||
|
|
||||||
|
const market = new LendingMarketClient({ provider: provider as never, address: '0x2C2d39dB711C0A33De04Dc74b1E22f4760FD4bb0' });
|
||||||
|
await check('AereLendingMarket getLtvBps()', () => market.getLtvBps());
|
||||||
|
await check('AereLendingMarket totalSuppliedCurrent()', () => market.totalSuppliedCurrent());
|
||||||
|
await check('AereLendingMarket borrowPaused()', () => market.borrowPaused());
|
||||||
|
|
||||||
|
const fund = new AereInsuranceFundClient(provider as never, '0x5Ab95C549c2A2b07913Df7edD4a16fd108B7CAAC');
|
||||||
|
await check('AereInsuranceFund FOUNDATION()', () => fund.getFoundation());
|
||||||
|
|
||||||
|
const sanctions = new AereSanctionsRegistryClient(provider, '0xb7d235718D99560F6EA4Fc5eAea2F8a306A3Cacf');
|
||||||
|
await check('AereSanctionsRegistry latestEpoch()', () => sanctions.latestEpoch(), (v) => typeof v === 'bigint' && v > 0n);
|
||||||
|
await check('AereSanctionsRegistry currentRoot()', () => sanctions.currentRoot(), (v) => typeof v === 'string' && /^0x[0-9a-f]{64}$/i.test(v));
|
||||||
|
|
||||||
|
const chainalysis = new ChainalysisOracleWrapperClient(provider, '0x1B7Be82C80f368f75Cb3807B1bc05E86A498f85c');
|
||||||
|
await check('ChainalysisOracleWrapper upstreamOracle()', () => chainalysis.upstreamOracle());
|
||||||
|
|
||||||
|
const travel = new AereTravelRuleHashRegistryClient(provider, '0xcF0E2e010E6e4506672019b1e570874AEeBC4c84');
|
||||||
|
await check('AereTravelRuleHashRegistry nextCommitmentId()', () => travel.nextCommitmentId());
|
||||||
|
|
||||||
|
const forensic = new AereForensicEventRegistryClient(provider, '0x4a7526A068e5DDE9788f6571E4A99095b14C6fff');
|
||||||
|
await check('AereForensicEventRegistry subjectAlertCount()', () => forensic.subjectAlertCount('0x0000000000000000000000000000000000000001'));
|
||||||
|
|
||||||
|
const pool = new AereCompliancePoolClient(provider as never, '0xB144c923572E5Ac1B6B961C4ccfec36917173465');
|
||||||
|
await check('AereCompliancePoolV2 depositCount()', () => pool.depositCount());
|
||||||
|
await check('AereCompliancePoolV2 nextLeafIndex()', () => pool.nextLeafIndex());
|
||||||
|
await check('AereCompliancePoolV2 getLastRoot()', () => pool.getLastRoot());
|
||||||
|
|
||||||
|
console.log(`\n${failures === 0 ? 'RESULT: PASS' : `RESULT: FAIL, ${failures} check(s)`}`);
|
||||||
|
process.exit(failures === 0 ? 0 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((e) => { console.error('live proof aborted:', e); process.exit(2); });
|
||||||
@ -6,8 +6,8 @@
|
|||||||
* still behaves the way the author measured. This file closes that gap by
|
* still behaves the way the author measured. This file closes that gap by
|
||||||
* pointing the guard at production and asserting on what comes back.
|
* pointing the guard at production and asserting on what comes back.
|
||||||
*
|
*
|
||||||
* It is deliberately NOT part of `npm test`: it needs the network, and a test
|
* It is deliberately NOT part of `npm test` (the test script skips *-live.js): it needs the network, and a
|
||||||
* suite that fails when the internet is down teaches people to ignore red.
|
* test suite that fails when the internet is down teaches people to ignore red.
|
||||||
*
|
*
|
||||||
* node dist/test/state-window-live.js # rpc.aere.network
|
* node dist/test/state-window-live.js # rpc.aere.network
|
||||||
* node dist/test/state-window-live.js https://rpc2.aere.network
|
* node dist/test/state-window-live.js https://rpc2.aere.network
|
||||||
@ -18,7 +18,7 @@
|
|||||||
* Structure, in this order, because a guard that has never been shown to fail
|
* Structure, in this order, because a guard that has never been shown to fail
|
||||||
* cannot be trusted:
|
* cannot be trusted:
|
||||||
*
|
*
|
||||||
* STEP 1 PLANTED FAILURE. The raw call really does return a false zero.
|
* STEP 1 THE ENDPOINT. What the raw call returns today (a false zero until 2026-10, a refusal since).
|
||||||
* STEP 2 NEGATIVE CONTROL. With the guards disabled, the reader hands that
|
* STEP 2 NEGATIVE CONTROL. With the guards disabled, the reader hands that
|
||||||
* false zero straight to the caller.
|
* false zero straight to the caller.
|
||||||
* STEP 3 THE GUARD. With the guards on, the reader refuses.
|
* STEP 3 THE GUARD. With the guards on, the reader refuses.
|
||||||
@ -74,35 +74,38 @@ async function main(): Promise<void> {
|
|||||||
console.log('');
|
console.log('');
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
console.log('STEP 1 PLANTED FAILURE: the raw call must still lie');
|
console.log('STEP 1 WHAT THE ENDPOINT DOES TODAY outside the state window');
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
const rawNonce = await send('eth_getTransactionCount', [SIGNER, tag]);
|
// Until 2026-10 this endpoint returned a false "0x0" here. Measured on 2026-10-15 it refuses with
|
||||||
if (rawNonce === '0x0') {
|
// "-32000 World state unavailable", which is honest. Either answer is recorded; a non-zero number would be a new hazard.
|
||||||
ok('eth_getTransactionCount returns a false zero',
|
let endpointLies = false;
|
||||||
`result "0x0" at block ${deepBlock}, where the block body proves ${trueNonce}`);
|
await send('eth_getTransactionCount', [SIGNER, tag]).then(
|
||||||
} else {
|
(raw) => {
|
||||||
bad('eth_getTransactionCount returns a false zero',
|
if (raw === '0x0') { endpointLies = true; ok('the endpoint still returns a false zero (hazard real)', `"0x0" at block ${deepBlock}, the body proves ${trueNonce}`); }
|
||||||
`expected "0x0", got ${JSON.stringify(rawNonce)}. If this endpoint now answers honestly, ` +
|
else bad('eth_getTransactionCount answers outside the window', `got ${JSON.stringify(raw)}; neither a refusal nor the known false zero`);
|
||||||
`the published documentation must be updated, not this assertion.`);
|
},
|
||||||
}
|
(e: Error) => ok('the endpoint refuses honestly outside the window', `error ${e.message}`),
|
||||||
|
|
||||||
const rawBalance = await send('eth_getBalance', [SIGNER, tag]);
|
|
||||||
if (rawBalance === null) {
|
|
||||||
ok('eth_getBalance is honest at the same block', 'result null, which is a refusal and not a value');
|
|
||||||
} else {
|
|
||||||
bad('eth_getBalance is honest at the same block', `expected null, got ${JSON.stringify(rawBalance)}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
await send('eth_getProof', [SIGNER, [], tag]).then(
|
|
||||||
() => bad('eth_getProof is honest at the same block', 'it answered; the state window may have changed'),
|
|
||||||
(e: Error) => ok('eth_getProof is honest at the same block', `error ${e.message}`),
|
|
||||||
);
|
);
|
||||||
console.log('');
|
console.log('');
|
||||||
|
|
||||||
|
// A lying endpoint, reproducing exactly the behaviour measured until 2026-10: state calls outside the window answer
|
||||||
|
// "0x0" (nonce) or null (balance) instead of an error. The guard must hold against THAT, whatever this endpoint does now.
|
||||||
|
const lying = async (method: string, params: unknown[]): Promise<unknown> => {
|
||||||
|
try { return await send(method, params); } catch (e) {
|
||||||
|
if (/World state unavailable/.test(String(e))) {
|
||||||
|
if (method === 'eth_getTransactionCount') return '0x0';
|
||||||
|
if (method === 'eth_getBalance' || method === 'eth_getCode' || method === 'eth_getStorageAt') return null;
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (!endpointLies) console.log(' the steps below run against a wrapper that reproduces the false zero, since this endpoint no longer produces it');
|
||||||
|
if (!endpointLies) console.log('');
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
console.log('STEP 2 NEGATIVE CONTROL: with the guards off, the lie gets through');
|
console.log('STEP 2 NEGATIVE CONTROL: with the guards off, the lie gets through');
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
const unguarded = new StateWindowReader(send, {
|
const unguarded = new StateWindowReader(endpointLies ? send : lying, {
|
||||||
windowBlocks: 100_000_000, safetyMarginBlocks: 0, corroborateNonce: false,
|
windowBlocks: 100_000_000, safetyMarginBlocks: 0, corroborateNonce: false,
|
||||||
});
|
});
|
||||||
const leaked = await unguarded.getTransactionCount(SIGNER, deepBlock);
|
const leaked = await unguarded.getTransactionCount(SIGNER, deepBlock);
|
||||||
@ -116,7 +119,7 @@ async function main(): Promise<void> {
|
|||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
console.log('STEP 3 THE GUARD: it refuses instead of guessing');
|
console.log('STEP 3 THE GUARD: it refuses instead of guessing');
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
const reader = new StateWindowReader(send);
|
const reader = new StateWindowReader(endpointLies ? send : lying);
|
||||||
|
|
||||||
await reader.getTransactionCount(SIGNER, deepBlock).then(
|
await reader.getTransactionCount(SIGNER, deepBlock).then(
|
||||||
(v) => bad('pre-flight refuses the deep nonce', `expected a throw, got ${v}`),
|
(v) => bad('pre-flight refuses the deep nonce', `expected a throw, got ${v}`),
|
||||||
@ -127,7 +130,7 @@ async function main(): Promise<void> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Corroboration is the guard that survives a caller who races past pre-flight.
|
// Corroboration is the guard that survives a caller who races past pre-flight.
|
||||||
const racedPast = new StateWindowReader(send, { windowBlocks: 100_000_000, safetyMarginBlocks: 0 });
|
const racedPast = new StateWindowReader(endpointLies ? send : lying, { windowBlocks: 100_000_000, safetyMarginBlocks: 0 });
|
||||||
await racedPast.getTransactionCount(SIGNER, deepBlock).then(
|
await racedPast.getTransactionCount(SIGNER, deepBlock).then(
|
||||||
(v) => bad('corroboration catches what pre-flight missed', `expected a throw, got ${v}`),
|
(v) => bad('corroboration catches what pre-flight missed', `expected a throw, got ${v}`),
|
||||||
(e: unknown) =>
|
(e: unknown) =>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user