Inspecting evidence
Read receipts, events, and explorer data to understand what happened onchain.
Execution evidence has two parts: the transaction receipt tells you whether a submitted transaction committed, while events explain the state changes and successful execution that the transaction contained. A read-only DENY result has no transaction receipt unless a caller submits it and causes a revert.
Load the current stack
cd contracts
set -a
source .env
set +a
MANIFEST="$DEPLOYMENT_MANIFEST_PATH"
RPC="$XLAYER_TESTNET_RPC_URL"
EXPLORER="$XLAYER_TESTNET_EXPLORER_URL"
GRANTLINE="$(jq -r '.grantline.proxy' "$MANIFEST")"
VAULT="$VAULT_ADDRESS"
REGISTRY="$(jq -r '.modules.registry.proxy' "$MANIFEST")"
EXECUTOR="$(jq -r '.modules.executor.proxy' "$MANIFEST")"
MANAGER="$(jq -r '.modules.escalationManager.proxy' "$MANIFEST")"Use the manifest values for every lookup. Set VAULT to the actual Vault address from a VaultCreated event or your own records; the manifest does not track individual Vault addresses.
Scoped onchain reads
The fresh contract architecture exposes direct indexes for the records a controller or agent needs to inspect. These views return addresses, Mandate IDs, or escalation digests; hydrate each result with getVault, getMandate, or getEscalation when the full record is needed.
Read the Vaults currently controlled by an address through Grantline:
CONTROLLER=0x...
cast call "$GRANTLINE" \
"controllerVaultCount(address)(uint256)" \
"$CONTROLLER" \
--rpc-url "$RPC"
cast call "$GRANTLINE" \
"controllerVaultAt(address,uint256)(address)" \
"$CONTROLLER" \
0 \
--rpc-url "$RPC"Read Mandates through the registry by Vault, creator, or authorised agent:
cast call "$REGISTRY" "vaultMandateCount(address)(uint256)" "$VAULT" --rpc-url "$RPC"
cast call "$REGISTRY" "vaultMandateAt(address,uint256)(uint256)" "$VAULT" 0 --rpc-url "$RPC"
cast call "$REGISTRY" "creatorMandateCount(address)(uint256)" "$CONTROLLER" --rpc-url "$RPC"
cast call "$REGISTRY" "creatorMandateAt(address,uint256)(uint256)" "$CONTROLLER" 0 --rpc-url "$RPC"
cast call "$REGISTRY" "agentMandateCount(address)(uint256)" "$AGENT" --rpc-url "$RPC"
cast call "$REGISTRY" "agentMandateAt(address,uint256)(uint256)" "$AGENT" 0 --rpc-url "$RPC"For Escalations, use the manager's global, Vault, or agent index and then load each digest:
cast call "$MANAGER" "escalationCount()(uint256)" --rpc-url "$RPC"
cast call "$MANAGER" "escalationAt(uint256)(bytes32)" 0 --rpc-url "$RPC"
cast call "$MANAGER" "vaultEscalationCount(address)(uint256)" "$VAULT" --rpc-url "$RPC"
cast call "$MANAGER" "vaultEscalationAt(address,uint256)(bytes32)" "$VAULT" 0 --rpc-url "$RPC"
cast call "$MANAGER" "agentEscalationCount(address)(uint256)" "$AGENT" --rpc-url "$RPC"
cast call "$MANAGER" "agentEscalationAt(address,uint256)(bytes32)" "$AGENT" 0 --rpc-url "$RPC"
DIGEST=0x...
cast call "$MANAGER" "getEscalation(bytes32)" "$DIGEST" --rpc-url "$RPC"Escalation indexes retain records in their submitted history, including PENDING, APPROVED, DENIED, and EXECUTED statuses. The contract returns the stored order; an application can sort active records before finalized records for presentation. submittedBy remains part of each Escalation record, but it is not a separate index.
Successful execution
Given a transaction hash from a successful normal execution:
TX_HASH=0x...
cast receipt "$TX_HASH" --rpc-url "$RPC"
cast tx "$TX_HASH" --rpc-url "$RPC"Receipt status 1 means the complete transaction committed.
Read the ActionPlanExecuted event from the executor:
cast logs \
--rpc-url "$RPC" \
--address "$EXECUTOR" \
'ActionPlanExecuted(bytes32,uint256,address,address,uint256,uint256,uint256,uint256,uint256,uint256)' \
--from-block 0Fields: actionDigest, mandateId, agent, vault, nonce, nativeAmount, nativeUsdValue, actionCount, nativeBalanceAfter, nativeBalanceUsdValue.
Inspect the Vault's low-level call evidence:
cast logs \
--rpc-url "$RPC" \
--address "$VAULT" \
'ExecutionAttempted(address,address,uint256,bytes32,bool,bytes32)' \
--from-block 0ExecutionAttempted shows the authority, target, value, calldata hash, low-level success flag, and result hash for a Vault call. It does not by itself prove that the complete Action Plan succeeded; use the transaction status and executor event together.
Escalation lifecycle
For an escalated digest, query the manager state and its events:
DIGEST=0x...
cast call "$MANAGER" \
"statusOf(bytes32)(uint8)" \
"$DIGEST" \
--rpc-url "$RPC"
cast call "$MANAGER" \
"getEscalation(bytes32)" \
"$DIGEST" \
--rpc-url "$RPC"Status enum: 0 NONE, 1 PENDING, 2 APPROVED, 3 DENIED, 4 EXECUTED.
Read the escalation events:
cast logs \
--rpc-url "$RPC" \
--address "$MANAGER" \
'EscalationSubmitted(bytes32,uint256,address,address,uint256,uint256,uint256,uint256,uint64)' \
--from-block 0
cast logs --rpc-url "$RPC" --address "$MANAGER" \
'EscalationApproved(bytes32,uint256,address,uint64)' --from-block 0
cast logs --rpc-url "$RPC" --address "$MANAGER" \
'EscalationDenied(bytes32,uint256,address,uint64)' --from-block 0
cast logs --rpc-url "$RPC" --address "$MANAGER" \
'EscalationExecuted(bytes32,uint256,address,uint256,uint64)' --from-block 0The stored plan and signature are the evidence for what the controller approved. Query the manager events for approval, denial, and execution timestamps, then inspect the executor receipt for the final capital movement.
Revoked authority failure
A revoked Mandate or ancestor causes evaluation to return DENY with MANDATE_INACTIVE. If a caller submits that plan to the executor, the transaction reverts before the Vault call:
FAILED_TX=0x...
cast receipt "$FAILED_TX" --rpc-url "$RPC"Receipt status 0 and revert data show that the submitted attempt failed. Events emitted by that reverted transaction do not persist, so the absence of an executor event is expected. The persistent evidence is the earlier MandateRevoked event and the stored Mandate status.
Paused mandate
A paused Mandate causes evaluation to return DENY with MANDATE_PAUSED. Read the MandatePaused event:
cast logs \
--rpc-url "$RPC" \
--address "$REGISTRY" \
'MandatePaused(uint256,address,uint64)' \
--from-block 0Cancelled nonce
A cancelled nonce causes evaluation to return DENY with NONCE_USED. Read the NonceCancelled event:
cast logs \
--rpc-url "$RPC" \
--address "$GRANTLINE" \
'NonceCancelled(uint256,address,uint256,address,uint64)' \
--from-block 0Verify the nonce state:
cast call "$GRANTLINE" \
"getNonceState(uint256,uint256)(bool,bytes32)" \
"$MANDATE_ID" "$NONCE" \
--rpc-url "$RPC"The used field should be true for a cancelled nonce.
Reverted transaction
A reverted receipt proves that a submitted transaction failed, but it does not create a persistent event stream for the failed path. Events emitted inside a reverted transaction are rolled back.
Use cast tx to inspect the revert data:
cast tx "$FAILED_TX" --rpc-url "$RPC"Then check earlier committed events to understand the authority state that led to the failure.
What the evidence proves
- A successful
ActionPlanExecutedevent proves that the complete plan reached the executor's successful point in a committed transaction. - An
EscalationApprovedevent proves that the Vault controller approved the stored digest, not that it later executed successfully. - A
MandateRevokedevent proves that an administrator revoked the Mandate at the recorded time; descendant lineage becomes inactive when evaluated. - A
MandatePausedevent proves that an administrator paused the Mandate; execution is blocked until unpause. - A
NonceCancelledevent proves that a specific nonce was permanently invalidated. - A reverted receipt proves that a submitted transaction failed, but it does not create a persistent event stream for the failed path.
See Events for event fields and Transaction lifecycle for the relationship between decisions, calls, and receipts.
Last updated on