/// /** Opt-in simulation test. Requires a fresh loopback Anvil BSC fork; never broadcasts. */ import assert from 'node:assert/strict'; import { ALTANA_KEYSTORE_CONTROLLER_BSC, ALTANA_ORCHESTRATOR_BSC, ALTANA_ORCHESTRATOR_VERSION_BSC, FUNDING_BOOTSTRAP_FEE_WEI, TOKENS_BSC, } from '@agripinaa/shared'; import { createPublicClient, encodeAbiParameters, encodeFunctionData, erc20Abi, hashTypedData, http, keccak256, maxUint256, parseAbi, parseAbiParameters, parseTransaction, toHex, type Hex, } from 'viem'; import { privateKeyToAccount } from 'viem/accounts'; import { bsc } from 'viem/chains'; import { fundingQuote } from '../src/funding-merchant'; import { parseFundingRecovery, prepareFundingRecovery } from '../src/recover-funding'; import { buildFundingBootstrapPlan, type FundingGasQuote } from '../../web/src/lib/funding-bootstrap'; const url = new URL(process.env.FUNDING_RECOVERY_RPC ?? 'http://127.0.0.1:18556'); assert.equal(url.protocol, 'http:'); assert.ok(['127.0.0.1', 'localhost', '[::1]'].includes(url.hostname), 'fork test must never use a public RPC'); const client = createPublicClient({ chain: bsc, transport: http(url.href, { timeout: 30_000, retryCount: 0 }) }); async function local(method: string, params: unknown[] = []) { const response = await fetch(url, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params }), signal: AbortSignal.timeout(30_000) }); const body = await response.json() as { result?: unknown; error?: unknown }; assert.equal(body.error, undefined, JSON.stringify(body.error)); return body.result; } assert.match(String(await local('web3_clientVersion')), /anvil/i); assert.equal(await client.getChainId(), 56); const snapshot = await local('evm_snapshot'); try { const user = privateKeyToAccount(`0x${'02'.repeat(32)}`); const payer = privateKeyToAccount(`0x${'03'.repeat(32)}`); const sender = privateKeyToAccount(`0x${'04'.repeat(32)}`); const delegation = '0xc0f16888f4198f53892c53af859f673e23f26fa3'; const zero = '0x0000000000000000000000000000000000000000'; const gross = 100n * 10n ** 18n; for (const account of [user, payer, sender]) { await local('anvil_setNonce', [account.address, '0x0']); await local('anvil_setCode', [account.address, '0x']); await local('anvil_setBalance', [account.address, account === user ? '0x0' : toHex(10n ** 18n)]); } // BEP20 USDT balance mapping slot 1. These fixtures exist only in the disposable fork. const slot = keccak256(encodeAbiParameters(parseAbiParameters('address,uint256'), [user.address, 1n])); await local('anvil_setStorageAt', [TOKENS_BSC.USDT!.address, slot, toHex(gross, { size: 32 })]); assert.equal(await client.readContract({ address: TOKENS_BSC.USDT!.address, abi: erc20Abi, functionName: 'balanceOf', args: [user.address] }), gross); const rawQuote = await fundingQuote(client, 'USDT'); const gasQuote = { ...rawQuote } as unknown as FundingGasQuote; for (const name of ['gasReserveInput', 'bootstrapFeeInput', 'totalGasInput', 'gasReserveWei', 'bootstrapFeeWei', 'registrationFeeWei'] as const) { gasQuote[name] = BigInt(rawQuote[name]); } const plan = await buildFundingBootstrapPlan({ account: user.address, agent: 'yield-b', input: 'USDT', grossInput: gross, nativeBalance: 0n, gasQuote, quoteClient: client, merchantUrl: 'http://localhost' }); const publicKey = `0x${user.publicKey.slice(4)}` as Hex; const calls = [...plan.calls, { to: TOKENS_BSC.USDT!.address, data: encodeFunctionData({ abi: erc20Abi, functionName: 'approve', args: ['0x6807dc923806fE8Fd134338EABCA509979a7e0cB', maxUint256] }), }, { to: ALTANA_KEYSTORE_CONTROLLER_BSC, value: gasQuote.registrationFeeWei, data: encodeFunctionData({ abi: parseAbi(['function initialRegisterKey(bytes32,address,bytes,bytes,uint40) payable']), functionName: 'initialRegisterKey', args: [keccak256(publicKey), zero, '0x', publicKey, 0] }), }].map((call) => ({ to: call.to, data: call.data ?? '0x', value: call.value ?? 0n })); const intent: ReturnType['intent'] = { eoa: user.address, executionData: encodeAbiParameters(parseAbiParameters('(address to,uint256 value,bytes data)[]'), [calls]), nonce: 0n, payer: payer.address, paymentToken: zero, paymentMaxAmount: FUNDING_BOOTSTRAP_FEE_WEI, combinedGas: 1_500_000n, encodedPreCalls: [], encodedFundTransfers: [], settler: zero, expiry: 0n, isMultichain: false, funder: zero, funderSignature: '0x', settlerContext: '0x', paymentAmount: FUNDING_BOOTSTRAP_FEE_WEI, paymentRecipient: zero, signature: '0x', paymentSignature: '0x', supportedAccountImplementation: '0x4b5d20cd8a3927b500540d9bccddc27385c9fa79', }; const digest = hashTypedData({ domain: { chainId: 56, name: 'Orchestrator', verifyingContract: ALTANA_ORCHESTRATOR_BSC, version: ALTANA_ORCHESTRATOR_VERSION_BSC }, primaryType: 'Intent', types: { Call: [{ name: 'to', type: 'address' }, { name: 'value', type: 'uint256' }, { name: 'data', type: 'bytes' }], Intent: [ ['multichain', 'bool'], ['eoa', 'address'], ['calls', 'Call[]'], ['nonce', 'uint256'], ['payer', 'address'], ['paymentToken', 'address'], ['paymentMaxAmount', 'uint256'], ['combinedGas', 'uint256'], ['encodedPreCalls', 'bytes[]'], ['encodedFundTransfers', 'bytes[]'], ['settler', 'address'], ['expiry', 'uint256'] ].map(([name, type]) => ({ name: name!, type: type! })), }, message: { ...intent, multichain: false, calls }, }); // Test-owned EOAs replace the real user's passkey and production payer. No production keys/signatures. const signedIntent = { ...intent, signature: await user.sign({ hash: digest }), paymentSignature: await payer.sign({ hash: digest }) }; const auth = async (account: typeof user) => { const authorization = await account.signAuthorization({ contractAddress: delegation, chainId: 56, nonce: 0 }); return { ...authorization, chainId: '0x38', nonce: '0x0', yParity: toHex(authorization.yParity!) }; }; // Anvil's EIP-1559 gas-price suggestion defaults to 1 gwei, unlike this BSC deployment. const executionClient = { ...client, getGasPrice: async () => 50_000_000n }; const options = { client: executionClient, sender: sender.address, recovery: { intent: signedIntent, gas: 2_000_000n, additionalAuthorization: await auth(payer) }, userAuthorization: await auth(user) }; await assert.rejects(prepareFundingRecovery({ ...options, client: { ...client, getGasPrice: async () => 1_000_000_000n } }), /fee ceiling/); const transaction = await prepareFundingRecovery(options); const raw = await sender.signTransaction(transaction); const parsed = parseTransaction(raw); assert.equal(parsed.type, 'eip7702'); assert.equal(parsed.authorizationList?.length, 2); assert.equal(parsed.chainId, 56); assert.equal(parsed.nonce, 0); assert.equal(await client.getTransactionCount({ address: sender.address }), 0, 'no transaction was broadcast'); await assert.rejects(prepareFundingRecovery({ ...options, recovery: { ...options.recovery, intent: { ...signedIntent, signature: signedIntent.paymentSignature } } }), /simulation rejected/); await assert.rejects(prepareFundingRecovery({ ...options, recovery: { ...options.recovery, intent: { ...signedIntent, paymentSignature: signedIntent.signature } } }), /simulation rejected/); await local('anvil_setCode', [payer.address, `0xef0100${delegation.slice(2)}`]); const existingPayer = await prepareFundingRecovery({ ...options, recovery: { ...options.recovery, additionalAuthorization: null } }); assert.equal(existingPayer.authorizationList.length, 1, 'an already delegated payer must not be reinitialized'); await local('anvil_setCode', [user.address, `0xef0100${delegation.slice(2)}`]); await assert.rejects(prepareFundingRecovery(options), /untouched/); console.log({ result: 'full type-4 funding simulation passed; invalid user/payer signatures rejected', calls: calls.length, gas: String(transaction.gas), maximumGasCostWei: String(transaction.gas * transaction.maxFeePerGas), broadcasts: 0 }); } finally { assert.equal(await local('evm_revert', [snapshot]), true); }