> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agentchain.cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# EVM Guard Quickstart

> Submit a transaction through the AgentChain policy engine and get a cryptographically signed receipt in under 60 seconds.

## Overview

AgentChain SDK v2 introduces the **EVM guard flow** — a pre-transaction policy check that returns a signed receipt before any value moves on-chain.

```mermaid theme={null}
flowchart TD
    A["SDK\nguardTransaction()"] --> B["POST /api/v1/evm/guard\n[Gateway]"]
    B --> C["Policy evaluation\n(GuardEngineService)"]
    C -->|allow| D["EIP-712 signed receipt\n(decision = allow)"]
    C -->|deny| E["Signed receipt\n(decision = deny)"]
    C -->|above threshold| F["Signed receipt\n(decision = approval_required)"]
    D --> G["wallet.sendTransaction\n[Chain]"]
    G --> H["POST /api/v1/receipts/:id/execution\nreportExecution()"]
    H --> I["state = executed"]
    I --> J["ReceiptAnchorJob\n(batch cron)"]
    J --> K["ReceiptAnchor.sol\nstate = anchored"]

    style A fill:#0a0a0b,stroke:#d7b94d,stroke-width:2px,color:#fafafa
    style B fill:#0a0a0b,stroke:#5ba3b5,stroke-width:2px,color:#fafafa
    style C fill:#0a0a0b,stroke:#818cf8,stroke-width:2px,color:#fafafa
    style D fill:#0a0a0b,stroke:#10B981,stroke-width:2px,color:#fafafa
    style E fill:#0a0a0b,stroke:#fbbf24,stroke-width:2px,color:#fafafa
    style F fill:#0a0a0b,stroke:#d7b94d,stroke-width:2px,color:#fafafa
    style G fill:#0a0a0b,stroke:#818cf8,stroke-width:2px,color:#fafafa
    style H fill:#0a0a0b,stroke:#5ba3b5,stroke-width:2px,color:#fafafa
    style I fill:#0a0a0b,stroke:#10B981,stroke-width:2px,color:#fafafa
    style J fill:#0a0a0b,stroke:#818cf8,stroke-width:2px,color:#fafafa
    style K fill:#0a0a0b,stroke:#10B981,stroke-width:2px,color:#fafafa
```

## Install

```bash theme={null}
npm install @humbleaf/agentchain-sdk viem
```

## Create a client

```typescript theme={null}
import { AgentChain } from '@humbleaf/agentchain-sdk';

const ac = new AgentChain({
  apiKey: process.env.AGENTCHAIN_API_KEY,
});
```

## Create a policy

Before guarding any transaction, create a policy for your chain and contract:

```typescript theme={null}
await ac.policies.create({
  policyId: 'pol_uniswap_safe',
  chainId: 84532, // Base Sepolia
  label: 'Safe Uniswap swaps',
  rules: {
    allowedTargets: ['0x2626664c2603336E57B271c5C0b26F421741e481'],
    allowedSelectors: ['0x414bf389'], // exactInputSingle
    maxValueWei: '1000000000000000000',   // 1 ETH max
    maxSlippageBps: 100,                  // 1%
    dailyCapWei: '5000000000000000000',   // 5 ETH / day
    approvalThresholdWei: '500000000000000000', // > 0.5 ETH → approval
  },
});
```

## Guard and execute

```typescript theme={null}
import { createWalletClient, http, encodeFunctionData } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { baseSepolia } from 'viem/chains';
import {
  AgentChainEvmPolicyDenied,
  AgentChainEvmApprovalRequired,
  AgentChainExpiredDecision,
} from '@humbleaf/agentchain-sdk';

const wallet = createWalletClient({
  account: privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`),
  chain: baseSepolia,
  transport: http(),
});

try {
  const { receipt, transactionHash } = await ac.evm.guardAndExecute(wallet, {
    chainId: 84532,
    from: wallet.account.address,
    to: '0x2626664c2603336E57B271c5C0b26F421741e481',
    data: encodeFunctionData({ abi, functionName: 'exactInputSingle', args: [params] }),
    value: '0',
    policyId: 'pol_uniswap_safe',
  });

  console.log('✓ Transaction sent:', transactionHash);
  console.log('  Receipt:', receipt.receiptId, '| state:', receipt.state);
} catch (err) {
  if (err instanceof AgentChainEvmPolicyDenied) {
    console.error('✗ Denied:', err.reasonCodes);
  } else if (err instanceof AgentChainEvmApprovalRequired) {
    console.log('⏳ Needs approval. approvalId:', err.approvalId);
  } else if (err instanceof AgentChainExpiredDecision) {
    console.warn('⟳ Decision expired — retry guardAndExecute');
  } else {
    throw err;
  }
}
```

## Guard only (no execution)

If you want the policy decision without executing, use `guardTransaction`:

```typescript theme={null}
const receipt = await ac.evm.guardTransaction({
  chainId: 84532,
  from: '0x...',
  to: '0x...',
  data: '0x...',
  value: '0',
  policyId: 'pol_uniswap_safe',
});

console.log(receipt.decision); // 'allow' | 'deny' | 'approval_required'
console.log(receipt.reasonCodes); // e.g. ['VALUE_EXCEEDED']
```

<Info>
  **`decisionExpiresAt`** — The gateway sets this to `issuedAt + 300s`. If execution takes more than 5 minutes, call `guardTransaction` again for a fresh receipt. `guardAndExecute` throws `AgentChainExpiredDecision` automatically if the window has closed.
</Info>

## Verify a receipt locally

No network call required:

```typescript theme={null}
const valid = ac.receipts.verify(
  receipt.receiptHash,
  receipt.signature,
  receipt.signerAddress,
);
console.log('signature valid:', valid);
```

## Verify on-chain (SignerAnchor)

For trustless verification — confirm the signer is authorized at the contract level:

```typescript theme={null}
const ac = new AgentChain({
  apiKey: process.env.AGENTCHAIN_API_KEY,
  signerAnchorAddress: '0x36cbAE566545e8df3ad15C171a7840266526E28F', // Base Sepolia
  signerAnchorChainId: 84532,
  signerAnchorRpcUrl: 'https://sepolia.base.org',
});

const result = await ac.receipts.verifyWithAnchor(receipt);

if (result.valid && result.onChainVerified) {
  // Fully trustless: ECDSA passed + signer confirmed authorized on SignerAnchor
  console.log('Receipt is fully verified on-chain');
} else if (result.valid && !result.onChainVerified) {
  // ECDSA passed but on-chain check skipped or degraded
  console.log('ECDSA valid; on-chain check skipped:', result.reasons);
  // reasons: 'signer_anchor_unavailable' | 'signer_anchor_rpc_error'
} else {
  // Receipt is invalid
  console.log('Receipt invalid, reasons:', result.reasons);
  // reasons: 'signature_mismatch' | 'signer_revoked'
}
```

## Next steps

* [Policy model](/agentchain/policy-model) — configure rules, thresholds, and caps
* [Receipts](/agentchain/receipts) — receipt lifecycle, states, and verification
* [Deployments](/agentchain/deployments) — live anchor contract addresses
* [API reference](/api-reference) — REST endpoints

***

## Security notes for pilots

### Simulation fail-closed behavior

When `simulate: true` is set in the guard request and the RPC circuit breaker is **OPEN**
(too many consecutive simulation failures), the guard returns **`503 SIMULATION_DEGRADED`**.
All subsequent guard requests with `simulate: true` will fail until the circuit recovers.

Pilots should decide their fallback strategy upfront:

| Strategy                           | Behavior                                  | Risk                             |
| ---------------------------------- | ----------------------------------------- | -------------------------------- |
| Keep `simulate: true`, halt on 503 | Agent stops during outage                 | Zero false-allows during outage  |
| Fall back to `simulate: false`     | Agent continues without revert protection | Transactions may revert on-chain |

The circuit auto-recovers after 60 seconds of no failures (HALF\_OPEN → CLOSED).

### 4-byte selector collision limitation

`allowedSelectors` matches on the **first 4 bytes** of calldata. Two different Solidity functions
can share the same 4-byte selector (keccak256 collision). This is extremely unlikely in practice
but is a documented limitation.

**Mitigation**: Combine `allowedTargets` + `allowedSelectors` — both must match. The probability
of a meaningful collision on a *specific target contract* is negligible for standard EVM deployments.
