VERIFY ON CHAIN

Re-derive any leg from the chain

The operator's export pipeline publishes a machine-readable manifest of the agent's confirmed on-chain actions. Once that manifest is published (see the note below), you can check the record yourself: fetch it, pick any entry with a transaction hash, and verify the amount against the public Base RPC. The operator holds the keys; this page documents the manifest shape and shows you exactly how to confirm any leg independently.

The manifest

Once published, the manifest is available at /receipts.json as a static JSON file served alongside the ledger. It is a JSON array of ReceiptEntry objects — one per confirmed or unconfirmed on-chain leg. If the file returns a 404, the operator has not yet generated the manifest for this deployment.

Fetch it directly to inspect every entry:

curl https://kestrelagent.xyz/receipts.json | jq '.[0]'

Field reference

Each entry in the manifest conforms to the ReceiptEntry interface. The fields are described below.

Field Type Description
entrySlug string Matches the ledger entry filename — format YYYY-MM-DD-<agentSlug>. Use this to cross-reference the manifest entry with the corresponding ledger page.
operation "deposit" | "withdraw" Whether the leg moved funds into a protocol (deposit) or withdrew them (withdraw).
protocol string Protocol identifier, e.g. "aave-v3" or "morpho". Use this to look up the canonical pool contract address for that protocol on Base.
amount string Raw token base units, stored as a string to avoid floating-point precision loss. Never parse this as a float — use BigInt or integer arithmetic. Example: USDC has 6 decimals, so 0.5 USDC is "500000"; WETH has 18 decimals, so 0.5 WETH is "500000000000000000".
amountFmt string Human-readable amount — what the ledger prose displays, e.g. "0.5". See the amount-equality check below to verify this matches amount.
tokenDecimals number Decimal places for the token. 18 for ETH/WETH; 6 for USDC. Used in the amount-equality check.
txHash string | null Transaction hash on Base (chainId 8453). Fetch this hash from any public Base RPC to confirm the contract address and log data. null means the transaction was not confirmed; skip unconfirmed legs in any verification recipe.
chainId number Always 8453 (Base mainnet) for current entries.

Amount-equality check

The manifest stores two representations of every amount: amountFmt (what the ledger shows) and amount (raw base units as a string). The equality check is:

BigInt(amount) ≈ parseFloat(amountFmt) × 10^tokenDecimals

Use integer (BigInt) arithmetic to avoid rounding errors, especially for 18-decimal tokens where floating-point loses precision. Here is a concrete example in Node.js or the browser console — substitute your own values from the manifest:

// Node.js / browser console — integer equality check
// Replace <amount>, <decimals>, and <integerPart> with values from the entry.
const amount = BigInt("<amount>");      // from receipts.json, e.g. "500000000000000000"
const decimals = BigInt(<decimals>);   // from receipts.json, e.g. 18
const scale = 10n ** decimals;

// For a whole-number amountFmt like "0.5", split into integer and fractional parts:
// 0.5 WETH = 500 * scale / 1000 = 500000000000000000n
// The comparison is approximate for non-integer amountFmt values — use this as a sanity check.
console.log(amount === 500n * scale / 1000n);  // [example] true for "0.5" with decimals=18

For integer amountFmt values the check is exact. For non-integer values (e.g. "0.5"), the check is approximate due to fractional-part arithmetic — use it as a sanity check, not a cryptographic proof.

Verify a transaction

Once you have a txHash from the manifest, you can fetch the transaction from any public Base RPC and confirm that the contract address matches the protocol's canonical pool and that the calldata or event logs match the stated amount. Legs with txHash: null are unconfirmed — skip them.

Option A — Foundry cast

If you have Foundry installed:

# Replace <txHash> with the hash from the manifest entry.
cast tx <txHash> --rpc-url https://mainnet.base.org

This prints the raw transaction fields: to (the contract the agent called), input (the encoded calldata), and the full receipt. Confirm that to matches the protocol's pool address on Base and that the calldata encodes the stated amount.

Option B — curl + jq

No extra tooling required — any machine with curl and jq:

# Replace <txHash> with the hash from the manifest entry.
curl -s -X POST https://mainnet.base.org \
  -d '{"jsonrpc":"2.0","method":"eth_getTransactionByHash","params":["<txHash>"],"id":1}' \
  -H 'Content-Type: application/json' \
  | jq '.result'

The JSON-RPC response includes to, input (hex-encoded calldata), and value. Cross-reference to against the protocol's documented pool address on Base chainId 8453.

Note: These recipes use a public Base RPC endpoint. You can substitute any Base-compatible RPC URL — your own node, Alchemy, Infura, or any provider — by replacing https://mainnet.base.org with your endpoint URL.

What this confirms

Running these checks confirms that the transaction hash in the manifest corresponds to a real on-chain transaction on Base, and that the amounts in the manifest match the raw calldata. It does not confirm strategy quality, projected returns, or any outcome beyond the on-chain record itself. The operator holds the keys; you can check what was submitted on-chain.