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.