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>
53 lines
2.3 KiB
TypeScript
53 lines
2.3 KiB
TypeScript
/**
|
|
* 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: '0xe2f6f511', // PAYOUT_TOKEN()
|
|
ORACLE: '0x38013f02', // ORACLE()
|
|
FOUNDATION: '0x65df2e51', // FOUNDATION()
|
|
configs: '0xfce89878', // configs(address)
|
|
states: '0x02a22337', // states(address)
|
|
periodRemaining: '0x0a41950f', // periodRemaining(address)
|
|
payoutLiquidity: '0x875d90e6', // 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));
|
|
}
|
|
}
|