# Vurto AI API Guide

This document is the machine-operator guide for AI agents (Clawbot/OpenClaw style) to execute Vurto actions directly via API.

## 1. Base URLs

- Production: `https://ana.vurto.cc/api/v1`
- OpenAPI Spec: `https://ana.vurto.cc/api/v1/openapi.json`

Health check:

```bash
curl -sS https://ana.vurto.cc/api/v1/health
```

Public call template (no API key required):

```bash
curl -sS https://ana.vurto.cc/api/v1/donator-status \
  -H 'content-type: application/json' \
  --data '{"walletAddress":"0x1111111111111111111111111111111111111111","chainId":137}'
```

## 2. Agent Contract (Clawbot/OpenClaw Friendly)

For each command, the agent should always keep this contract:

1. Validate intent + required params.
2. Resolve donor status (`/donator-status`) before quote/build.
3. Quote first if command requires swap math (`/quote/*`).
4. Build tx payload (`/build/*`) and inspect `to`, `data`, `value`, `feeBps`, `feeAmount`.
5. Sign and send onchain.
6. Report status to tracking endpoint (`/transactions/:id/*`) when `transactionId` exists.
7. Return final result with tx hash, chain, token amounts, and effective fee.

## 3. Common Rules

- All token amounts are integer strings in raw units (wei-like, token decimals).
- Token object shape:

```json
{
  "address": "0x...",
  "decimals": 6,
  "symbol": "USDC"
}
```

- Minimum shared fields in most calls:
  - `chainId`
  - `walletAddress`
  - `userAddress` (required for quote/build swap routes)
- Pool routes require `poolAddress`.
- Default interest mode for borrow/repay: variable (`2`).
- Public routes (no credential): `GET /health` and docs/root guide.
- Sensitive routes are also public on `ana.vurto.cc` and `ana.vurto.cc`:
  - `POST /donator-status`
  - `POST /quote/*`
  - `POST /build/*`
- Anti-flood rate limits are layered by IP + credential + wallet + route + method.
- On limit hit, API returns `429` with headers:
  - `retry-after`
  - `x-ratelimit-limit`
  - `x-ratelimit-remaining`
  - `x-ratelimit-reset`
  - `x-ratelimit-scope`
- Extra telemetry header: `x-ratelimit-source` (`edge`, `edge_local`, or `local`).
- Agent behavior on `429`: wait `retry-after` seconds and retry with backoff; avoid parallel bursts.
- OpenAPI contract guard is active on sensitive routes: unknown/missing fields are rejected.
- Kill-switch can temporarily disable specific routes and returns `503 api_route_disabled`.

## 3.1 APY History (Self-Collected + DeFi Llama)

Vurto independently collects supply and borrow APY rates every 12 hours (00:00 and 12:00 UTC). This self-collected data is combined with DeFi Llama where available, and over time will provide full 365-day coverage without external dependencies.

Endpoints:

- `GET /apy/history?chainId=<id>` — current rates (supply + borrow) from DeFi Llama bulk
- `GET /apy/history/rolling?chainId=<id>&days=365` — rolling averages from self-collected + DeFi Llama charts

Recommended query for agents:

```bash
curl -sS "https://ana.vurto.cc/api/v1/apy/history/rolling?chainId=42161&days=365"
```

How to read the response:

- `source`: data source mode — `vurto_collected`, `defillama+vurto_collected`, or `defillama+rolling_chart`
- `coverageDays`: max coverage across supply and borrow for that token
- `supplyCoverageDays`: days of supply APY history available
- `borrowCoverageDays`: days of borrow APY history available (from self-collection)
- `supply.avg30d|avg90d|avg180d|avg365d` — supply APY rolling averages
- `borrow.avg30d|avg90d|avg180d|avg365d` — borrow APY rolling averages
- `collection.collectedDays`: number of unique daily snapshots Vurto has recorded
- `collection.notice`: human-readable status of the collection progress

Important rules for agents:

- Consider `30d/90d/180d/365d` values valid only when `coverageDays >= window` (or the specific `supplyCoverageDays`/`borrowCoverageDays`).
- If coverage is insufficient, treat that window as unavailable (`N/A`) instead of extrapolating.
- Prefer token lookup by underlying address; use `symbol:<SYMBOL>` alias only as fallback.
- Rolling endpoint is capped at `days=365`.
- Use `collection.collectedDays` to know how mature the borrow average data is.

Background collection:

- APY snapshots (both supply and borrow current rates) are persisted in Vurto KV every 12 hours.
- Borrow averages grow daily as more snapshots accumulate — goal is full 365-day independence within one year.

## Support Error Reporting for AI Agents

- Purpose: allow agents to report runtime issues and retrieve aggregated incident context for debugging loops.
- Write endpoint (public intake): `POST /support/tickets`
- Read endpoints (private): `GET /support/tickets`, `GET /support/tickets/:id`, `GET /support/analysis`
- Privacy rule: support reads require valid credential; unauthenticated reads return `401 support_read_auth_required`.

Recommended agent flow:

1. On execution failure, call `POST /support/tickets` with `message`, optional `contactEmail`, and optional `screenshotDataUrl`.
2. For triage sessions, call `GET /support/analysis` (with credential) to cluster recurring signatures.
3. If needed, fetch detailed incidents via `GET /support/tickets` and `GET /support/tickets/:id`.

## 4. Fee and Donor Policy

- Base fee: `2.5 bps` = `0.025%`.
- If wallet is verified donor: fee = `0`.
- Verify donor:

```bash
curl -sS https://ana.vurto.cc/api/v1/donator-status \
  -H 'content-type: application/json' \
  --data '{
    "walletAddress":"0x1111111111111111111111111111111111111111",
    "chainId":137
  }'
```

Expected key fields:

- `donator.isDonator`
- `donator.discountPercent`
- `donator.validUntil`
- `donatorPolicy.minimumDonationUsd`
- `donatorPolicy.walletAddressByChain`

### Important: How to Donate Correctly

To register donor status onchain, donation must use contract method `donate` (or `donateFor`).

- Correct: call `donate(token, amount)` on donation registry contract for that network.
- Not enough: direct ERC20 transfer to the contract (this does not update donor state in registry logic).

Donation ABI methods:

- `donate(address token, uint256 amount)`
- `donateFor(address beneficiary, address token, uint256 amount)`
- `isDonorNow(address account)`

Network note:

- Registry contract can differ by chain. Use `GET /dapp-vurto/config` and read:
  - `donationPolicy.walletAddressByChain`
  - `donationPolicy.acceptedTokensByNetwork`

### Donor Tier Matrix (Current Policy)

Current configured tiers in backend policy:

| Tier | Minimum donation (USD) | Donor validity |
|---|---:|---:|
| 1 | 0.99 | 30 days |
| 2 | 1.95 | 60 days |
| 3 | 5.00 | 180 days |
| 4 | 10.00 | 365 days |

Important behavior:

- Base platform fee is `0.025%` (2.5 bps).
- Verified donor gets `100%` discount on platform fee (effective fee `0`).
- A qualifying donation sets/extends donor validity (`donator.validUntil`) according to its tier.
- Higher qualifying donation tiers can increase validity window.
- Confirm active state from API fields: `donator.isDonator`, `donator.validUntil`, `donator.activeTierMinUsd`, `donator.activeTierValidityDays`.

After onchain donation confirmation, refresh donor state:

```bash
curl -sS https://ana.vurto.cc/api/v1/donator-status \
  -H 'content-type: application/json' \
  --data '{
    "walletAddress":"0x1111111111111111111111111111111111111111",
    "chainId":137,
    "force":true
  }'
```

## 5. Command Index

**Same-chain operations** (single transaction on one chain):

1. `supply_collateral` — deposit token as collateral
2. `supply_collateral_zap_in` — swap token A → supply token B as collateral
3. `borrow` — borrow token against collateral
4. `withdraw_supplied` — withdraw collateral
5. `withdraw_supplied_zap_out` — withdraw collateral → swap to another token
6. `switch_supplied` — swap supplied collateral to a different token
7. `repay_borrowed` — repay debt with the same token
8. `switch_borrowed` — swap debt to a different token (repay-with-swap)
9. `dual_swap` — switch both collateral AND debt in one transaction

**Crosschain operations** (non-atomic, multi-step across two chains via bridge):

10. `crosschain_supply` — withdraw from chain A → bridge → supply on chain B
11. `crosschain_repay` — borrow on chain A → bridge → repay debt on chain B
12. `position_migration` — alternate crosschain supply + crosschain repay cycles to move an entire position from chain A to chain B

---

## 6. Commands and Examples

### 6.1 Supply de collateral (`supply_collateral`)

Endpoint:

- `POST /build/supply`

Example:

```bash
curl -sS https://ana.vurto.cc/api/v1/build/supply \
  -H 'content-type: application/json' \
  --data '{
    "chainId":137,
    "walletAddress":"0x1111111111111111111111111111111111111111",
    "poolAddress":"0x794a61358d6845594f94dc1db02a252b5b4814ad",
    "token":{"address":"0x3c499c542cef5e3811e1192ce70d8cc03d5c3359","decimals":6,"symbol":"USDC"},
    "amount":"1000000"
  }'
```

### 6.2 Supply com zap in (`supply_collateral_zap_in`)

Flow:

1. `POST /quote/collateral`
2. `POST /build/collateral/paraswap` (swap)
3. `POST /build/supply` (deposit target token)

Quote:

```bash
curl -sS https://ana.vurto.cc/api/v1/quote/collateral \
  -H 'content-type: application/json' \
  --data '{
    "chainId":137,
    "walletAddress":"0x1111111111111111111111111111111111111111",
    "userAddress":"0x1111111111111111111111111111111111111111",
    "fromToken":{"address":"0x3c499c542cef5e3811e1192ce70d8cc03d5c3359","decimals":6,"symbol":"USDC"},
    "toToken":{"address":"0xc2132d05d31c914a87c6611c10748aeb04b58e8f","decimals":6,"symbol":"USDT"},
    "srcAmount":"1000000"
  }'
```

Build swap (use `priceRoute` from quote):

```bash
curl -sS https://ana.vurto.cc/api/v1/build/collateral/paraswap \
  -H 'content-type: application/json' \
  --data '{
    "chainId":137,
    "walletAddress":"0x1111111111111111111111111111111111111111",
    "userAddress":"0x1111111111111111111111111111111111111111",
    "fromToken":{"address":"0x3c499c542cef5e3811e1192ce70d8cc03d5c3359","decimals":6,"symbol":"USDC"},
    "toToken":{"address":"0xc2132d05d31c914a87c6611c10748aeb04b58e8f","decimals":6,"symbol":"USDT"},
    "srcAmount":"1000000",
    "slippageBps":3,
    "priceRoute": {"...":"from quote"}
  }'
```

Then build supply with target token amount (`destAmount` or conservative min output):

```bash
curl -sS https://ana.vurto.cc/api/v1/build/supply \
  -H 'content-type: application/json' \
  --data '{
    "chainId":137,
    "walletAddress":"0x1111111111111111111111111111111111111111",
    "poolAddress":"0x794a61358d6845594f94dc1db02a252b5b4814ad",
    "token":{"address":"0xc2132d05d31c914a87c6611c10748aeb04b58e8f","decimals":6,"symbol":"USDT"},
    "amount":"995000"
  }'
```

### 6.3 Borrow (`borrow`)

Endpoint:

- `POST /build/borrow`

```bash
curl -sS https://ana.vurto.cc/api/v1/build/borrow \
  -H 'content-type: application/json' \
  --data '{
    "chainId":137,
    "walletAddress":"0x1111111111111111111111111111111111111111",
    "poolAddress":"0x794a61358d6845594f94dc1db02a252b5b4814ad",
    "token":{"address":"0x3c499c542cef5e3811e1192ce70d8cc03d5c3359","decimals":6,"symbol":"USDC"},
    "amount":"1000000",
    "interestRateMode":2
  }'
```

### 6.4 Withdrawn de supplied (`withdraw_supplied`)

Endpoint:

- `POST /build/withdraw`

```bash
curl -sS https://ana.vurto.cc/api/v1/build/withdraw \
  -H 'content-type: application/json' \
  --data '{
    "chainId":137,
    "walletAddress":"0x1111111111111111111111111111111111111111",
    "poolAddress":"0x794a61358d6845594f94dc1db02a252b5b4814ad",
    "token":{"address":"0x3c499c542cef5e3811e1192ce70d8cc03d5c3359","decimals":6,"symbol":"USDC"},
    "amount":"1000000",
    "recipient":"0x1111111111111111111111111111111111111111"
  }'
```

For full balance where supported:

- add `"useMaxAmount": true`

### 6.5 Withdrawn de supplied com zap out (`withdraw_supplied_zap_out`)

Flow:

1. `POST /build/withdraw`
2. `POST /quote/collateral`
3. `POST /build/collateral/paraswap`

Withdraw build:

```bash
curl -sS https://ana.vurto.cc/api/v1/build/withdraw \
  -H 'content-type: application/json' \
  --data '{
    "chainId":137,
    "walletAddress":"0x1111111111111111111111111111111111111111",
    "poolAddress":"0x794a61358d6845594f94dc1db02a252b5b4814ad",
    "token":{"address":"0x3c499c542cef5e3811e1192ce70d8cc03d5c3359","decimals":6,"symbol":"USDC"},
    "amount":"1000000",
    "recipient":"0x1111111111111111111111111111111111111111"
  }'
```

Then quote/build collateral swap from withdrawn token to desired token.

### 6.6 Switch de supplied (`switch_supplied`)

Flow:

1. `POST /quote/collateral`
2. `POST /build/collateral/paraswap`

```bash
curl -sS https://ana.vurto.cc/api/v1/quote/collateral \
  -H 'content-type: application/json' \
  --data '{
    "chainId":137,
    "walletAddress":"0x1111111111111111111111111111111111111111",
    "userAddress":"0x1111111111111111111111111111111111111111",
    "fromToken":{"address":"0x3c499c542cef5e3811e1192ce70d8cc03d5c3359","decimals":6,"symbol":"USDC"},
    "toToken":{"address":"0xc2132d05d31c914a87c6611c10748aeb04b58e8f","decimals":6,"symbol":"USDT"},
    "srcAmount":"1000000"
  }'
```

### 6.7 Repay de borrowed (`repay_borrowed`)

Endpoint:

- `POST /build/repay`

```bash
curl -sS https://ana.vurto.cc/api/v1/build/repay \
  -H 'content-type: application/json' \
  --data '{
    "chainId":137,
    "walletAddress":"0x1111111111111111111111111111111111111111",
    "poolAddress":"0x794a61358d6845594f94dc1db02a252b5b4814ad",
    "token":{"address":"0x3c499c542cef5e3811e1192ce70d8cc03d5c3359","decimals":6,"symbol":"USDC"},
    "amount":"1000000",
    "interestRateMode":2
  }'
```

### 6.8 Switch de borrowed (`switch_borrowed`)

Flow:

1. `POST /quote/debt`
2. `POST /build/debt/paraswap`

```bash
curl -sS https://ana.vurto.cc/api/v1/quote/debt \
  -H 'content-type: application/json' \
  --data '{
    "chainId":137,
    "walletAddress":"0x1111111111111111111111111111111111111111",
    "userAddress":"0x1111111111111111111111111111111111111111",
    "fromToken":{"address":"0x3c499c542cef5e3811e1192ce70d8cc03d5c3359","decimals":6,"symbol":"USDC"},
    "toToken":{"address":"0xc2132d05d31c914a87c6611c10748aeb04b58e8f","decimals":6,"symbol":"USDT"},
    "destAmount":"1000000"
  }'
```

### 6.9 Dual swap (`dual_swap`)

Preferred flow:

1. `POST /quote/dual`
2. `POST /build/dual/aave-adapter`
3. Fallback: `POST /build/dual/executor` if adapter route is unavailable on chain.

Dual quote:

```bash
curl -sS https://ana.vurto.cc/api/v1/quote/dual \
  -H 'content-type: application/json' \
  --data '{
    "chainId":137,
    "walletAddress":"0x1111111111111111111111111111111111111111",
    "userAddress":"0x1111111111111111111111111111111111111111",
    "collateral":{
      "fromToken":{"address":"0x3c499c542cef5e3811e1192ce70d8cc03d5c3359","decimals":6,"symbol":"USDC"},
      "toToken":{"address":"0xc2132d05d31c914a87c6611c10748aeb04b58e8f","decimals":6,"symbol":"USDT"},
      "srcAmount":"1000000"
    },
    "debt":{
      "fromToken":{"address":"0x3c499c542cef5e3811e1192ce70d8cc03d5c3359","decimals":6,"symbol":"USDC"},
      "toToken":{"address":"0xc2132d05d31c914a87c6611c10748aeb04b58e8f","decimals":6,"symbol":"USDT"},
      "destAmount":"1000000"
    }
  }'
```

Dual build payload accepts backward-compatible quote-driven shape with `priceRoute` for both legs.

### 6.9.1 Compound quote+build endpoints (recommended)

For agents that do not need to inspect the quote before building, three compound endpoints run quote and build server-side in one round-trip. This avoids the ParaSwap `priceRoute` TTL race between two separate calls.

Endpoints:

- `POST /quote-and-build/collateral` — replaces `/quote/collateral` + `/build/collateral/paraswap`
- `POST /quote-and-build/debt` — replaces `/quote/debt` + `/build/debt/paraswap`
- `POST /quote-and-build/dual` — replaces `/quote/dual` + `/build/dual/aave-adapter` (with executor fallback)

Request bodies match the existing `/quote/*` request shapes.

Response shape: the existing `build_*` response (`to`, `data`, `value`, `transactionId`, `approval`, `steps`, `feeBps`, `feeAmount`, `_meta`) **plus** a new top-level `quote` object:

```json
{
  "to": "0x...",
  "data": "0x...",
  "value": "0",
  "transactionId": "f07544a0-12f9-4dc8-9d6f-b92280c38828",
  "feeBps": 2.5,
  "feeAmount": "2500",
  "quote": {
    "srcAmount": "1000000",
    "destAmount": "999300",
    "gasEstimate": "210000",
    "route": { "...": "opaque" },
    "priceImpactBps": 1.2,
    "recommendedSlippageBps": 30
  }
}
```

For `/quote-and-build/dual`, `quote` carries per-leg sub-objects: `quote.collateral` and `quote.debt`, each with the same shape as the single-leg `quote` above.

Example:

```bash
curl -sS https://ana.vurto.cc/api/v1/quote-and-build/collateral \
  -H 'content-type: application/json' \
  --data '{
    "chainId":137,
    "walletAddress":"0x1111111111111111111111111111111111111111",
    "userAddress":"0x1111111111111111111111111111111111111111",
    "fromToken":{"address":"0x3c499c542cef5e3811e1192ce70d8cc03d5c3359","decimals":6,"symbol":"USDC"},
    "toToken":{"address":"0xc2132d05d31c914a87c6611c10748aeb04b58e8f","decimals":6,"symbol":"USDT"},
    "srcAmount":"1000000",
    "slippageBps":30
  }'
```

### 6.9.2 `user_notice` for local-signer flows

When an agent delegates signing to the local signer (via the MCP `prepare_signing` tool), the response includes a `cli.user_notice` string. The agent **must relay this notice verbatim to the user before printing the local signer URL**. It explains that the URL is local, why the browser may show "unknown application" warnings, and that the signer enforces wallet/chain match before submitting. Do not paraphrase or omit it.

### 6.10 Crosschain Supply (`crosschain_supply`) — Non-Atomic

> **Do not confuse with same-chain operations.** `build_supply`, `build_borrow`, `build_withdraw`, and `build_repay` operate on a single chain. Crosschain Supply and Crosschain Repay are **multi-chain** operations that move funds between two different chains via a bridge.

**Crosschain Supply** withdraws collateral from the source chain, bridges it, and supplies it on the destination chain. Use `intent: "supply"` with `sourceFunding.mode: "withdraw"` (or `"withdraw_and_zap_out"` if the token is not bridge-compatible).

This is the fundamental building block for moving collateral from one chain to another.

Flow overview:

1. `POST /quote/longshot` — get crosschain route quote (auto-selects bridge provider: Across or USDT0)
2. `POST /build/longshot` — build multi-step execution with quoteId
3. Execute **source step**: sign and send the borrow/withdraw tx on source chain
4. Report: `POST /longshot/executions/:id/event` with `event: source_submitted` + `txHash`
5. Wait for source confirmation and report: `event: source_confirmed`
6. Execute **bridge step**: sign approve + deposit txs on source chain (if zap-out needed, also sign swap txs first; if non-donor, execute fee transfer before deposit)
7. Poll: `GET /longshot/executions/:id/bridge-check` until `bridged: true`
8. Execute **destination step**: sign and send supply tx on destination chain
9. Report: `event: destination_submitted` + `txHash`, then `event: destination_confirmed`

**Important rules for agents:**

- This is a **non-atomic** operation — each step is a separate onchain transaction.
- The execution may need **zap-out** (source token → bridge stable) and/or **zap-in** (bridge stable → destination token) if the tokens are not the same stablecoin family.
- The `projectedSourceHealthFactor` must be >= ~1.08 or the quote will be rejected.
- Quote expires in ~5 minutes from creation.
- If any step fails, use `POST /longshot/executions/:id/recover` with the appropriate action (`retry_source`, `retry_bridge`, `retry_destination`, or `mark_abandoned`).
- Bridge fee: non-donors pay 2.5 bps bridge fee transfer before the deposit. Donors pay 0.

Quote:

```bash
curl -sS https://ana.vurto.cc/api/v1/quote/longshot \
  -H 'content-type: application/json' \
  --data '{
    "walletAddress": "0x1111111111111111111111111111111111111111",
    "intent": "supply",
    "sourceChainId": 42161,
    "destinationChainId": 137,
    "sourceFunding": {
      "mode": "borrow",
      "token": {"address": "0xaf88d065e77c8cc2239327c5edb3a432268e5831", "decimals": 6, "symbol": "USDC"},
      "amount": "1000000",
      "poolAddress": "0x794a61358d6845594f94dc1db02a252b5b4814ad",
      "projectedSourceHealthFactor": 1.5,
      "interestRateMode": 2
    },
    "destinationAction": {
      "token": {"address": "0x3c499c542cef5e3811e1192ce70d8cc03d5c3359", "decimals": 6, "symbol": "USDC"},
      "amount": "990000",
      "poolAddress": "0x794a61358d6845594f94dc1db02a252b5b4814ad"
    },
    "slippageBps": 30
  }'
```

Build from quote:

```bash
curl -sS https://ana.vurto.cc/api/v1/build/longshot \
  -H 'content-type: application/json' \
  --data '{
    "quoteId": "lq_...",
    "walletAddress": "0x1111111111111111111111111111111111111111"
  }'
```

Response contains `executionId`, `steps` array (source, bridge, destination), `statusUrl`, and `recoverUrl`.

Report source tx submitted:

```bash
curl -sS https://ana.vurto.cc/api/v1/longshot/executions/lex_.../event \
  -H 'content-type: application/json' \
  --data '{
    "walletAddress": "0x1111111111111111111111111111111111111111",
    "event": "source_submitted",
    "txHash": "0xabc..."
  }'
```

Check bridge arrival:

```bash
curl -sS "https://ana.vurto.cc/api/v1/longshot/executions/lex_.../bridge-check?walletAddress=0x1111111111111111111111111111111111111111"
```

Poll until `bridged: true`, then execute destination tx and report `destination_submitted` → `destination_confirmed`.

Get execution status:

```bash
curl -sS "https://ana.vurto.cc/api/v1/longshot/executions/lex_.../status?walletAddress=0x1111111111111111111111111111111111111111"
```

Recover from failure:

```bash
curl -sS https://ana.vurto.cc/api/v1/longshot/executions/lex_.../recover \
  -H 'content-type: application/json' \
  --data '{
    "walletAddress": "0x1111111111111111111111111111111111111111",
    "action": "retry_source"
  }'
```

### 6.11 Crosschain Repay (`crosschain_repay`) — Non-Atomic

**Crosschain Repay** borrows on the source chain, bridges the funds, and repays debt on the destination chain. Use `intent: "repay"` with `sourceFunding.mode: "borrow"`.

This is the complement of Crosschain Supply — it allows paying down debt on one chain using borrowing capacity from another.

Same execution flow as Crosschain Supply (quote → build → source step → bridge → destination step).

Quote example:

```bash
curl -sS https://ana.vurto.cc/api/v1/quote/longshot \
  -H 'content-type: application/json' \
  --data '{
    "walletAddress": "0x1111111111111111111111111111111111111111",
    "intent": "repay",
    "sourceChainId": 42161,
    "destinationChainId": 137,
    "sourceFunding": {
      "mode": "withdraw",
      "token": {"address": "0xaf88d065e77c8cc2239327c5edb3a432268e5831", "decimals": 6, "symbol": "USDC"},
      "amount": "2000000",
      "poolAddress": "0x794a61358d6845594f94dc1db02a252b5b4814ad",
      "projectedSourceHealthFactor": 2.0,
      "interestRateMode": 2
    },
    "destinationAction": {
      "token": {"address": "0x3c499c542cef5e3811e1192ce70d8cc03d5c3359", "decimals": 6, "symbol": "USDC"},
      "amount": "1950000",
      "poolAddress": "0x794a61358d6845594f94dc1db02a252b5b4814ad",
      "interestRateMode": 2
    },
    "slippageBps": 30
  }'
```

### 6.12 Position Migration — Moving an Entire Position Between Chains

When a user has both collateral and debt on chain A and wants to move everything to chain B, use alternating **Crosschain Supply** and **Crosschain Repay** cycles:

1. **Crosschain Supply** — withdraw a safe portion of collateral from A → bridge → supply on B.
2. **Crosschain Repay** — borrow on B (now possible thanks to step 1 collateral) → bridge → repay debt on A. This restores chain A's health factor.
3. **Repeat** steps 1–2, each cycle moving more collateral and reducing more debt.
4. **Final step is always a Crosschain Supply** — once all debt on A is repaid, withdraw the remaining collateral from A and supply it on B.

**Key rules:**
- Call `GET /position` on both chains between cycles to recalculate safe withdrawal/borrow amounts and health factors.
- The `projectedSourceHealthFactor` must stay >= ~1.08 at every step.
- The number of cycles depends on the position's loan-to-value ratio — higher leverage requires more, smaller cycles.
- Each Crosschain Supply or Crosschain Repay is a full multi-step execution (source tx → bridge → destination tx) that must complete before starting the next.

### Crosschain Execution States

| State | Meaning |
|---|---|
| `awaiting_source_signature` | Waiting for agent to sign source tx |
| `source_submitted` | Source tx sent, awaiting confirmation |
| `source_confirmed` | Source tx confirmed onchain |
| `source_failed` | Source tx reverted — recoverable via `retry_source` |
| `bridge_pending` | Bridge deposit in progress |
| `bridge_confirmed` | Funds arrived on destination chain |
| `bridge_failed` | Bridge issue — recoverable via `retry_bridge` |
| `awaiting_destination_signature` | Waiting for agent to sign destination tx |
| `destination_submitted` | Destination tx sent |
| `destination_confirmed` | Destination tx confirmed — operation complete |
| `destination_failed` | Destination tx failed — recoverable via `retry_destination` |
| `completed` | Full crosschain operation finished |
| `abandoned` | User abandoned the execution |

### Crosschain Error Classes

- `422 longshot_source_hf_guardrail` — projected source health factor too low
- `422 longshot_destination_guardrail` — destination reserve frozen or disabled
- `422 longshot_no_route` — no bridge route available for chain pair
- `422 longshot_provider_override_unavailable` — forced provider not available
- `410 longshot_quote_expired` — quote TTL exceeded (re-quote needed)
- `403 longshot_wallet_mismatch` — build/event wallet differs from quote wallet
- `503 longshot_disabled` — crosschain feature disabled by runtime config

## 7. Transaction Tracking Hooks (Optional but Recommended)

If build response includes `transactionId`, track state. `transactionId` is a UUID v4 string (e.g. `f07544a0-12f9-4dc8-9d6f-b92280c38828`) — pass it verbatim in the URL. Legacy integer IDs are still accepted as input for backward compatibility, but new build responses always return strings.

- Sent hash:

```bash
curl -sS https://ana.vurto.cc/api/v1/transactions/f07544a0-12f9-4dc8-9d6f-b92280c38828/send-hash \
  -H 'content-type: application/json' \
  --data '{"txHash":"0xabc..."}'
```

- Confirmed:

```bash
curl -sS https://ana.vurto.cc/api/v1/transactions/f07544a0-12f9-4dc8-9d6f-b92280c38828/confirm \
  -H 'content-type: application/json' \
  --data '{"gasUsed":"210000","actualPaid":"1000000"}'
```

- Rejected:

```bash
curl -sS https://ana.vurto.cc/api/v1/transactions/f07544a0-12f9-4dc8-9d6f-b92280c38828/reject \
  -H 'content-type: application/json' \
  --data '{"reason":"user_rejected"}'
```

- Failed:

```bash
curl -sS https://ana.vurto.cc/api/v1/transactions/f07544a0-12f9-4dc8-9d6f-b92280c38828/fail \
  -H 'content-type: application/json' \
  --data '{"reason":"execution_failed"}'
```

History:

- `GET /transactions/user/:walletAddress?limit=50`

## 7.1 MCP Tool `prepare_signing` (Hardware Wallet Flow)

For agents speaking MCP to the Vurto AnA server (`https://ana.vurto.cc/mcp`): when the user holds a hardware wallet (Ledger/Trezor) or asks to sign via a browser wallet, the agent cannot inject a private key. Use the MCP tool `prepare_signing` to obtain a CLI invocation that drives a local browser signer.

This tool does NOT call any backend endpoint. It synthesizes the CLI invocation inline from its arguments plus the worker's pinned CLI version (`VURTO_SIGN_CLI_VERSION` env var).

Tool name: `prepare_signing`

Request (MCP `tools/call` arguments):

```json
{
  "transactionId": 12345,
  "txData": {
    "to": "0x794a61358D6845594F94dc1DB02A252b5b4814aD",
    "data": "0x617ba037...",
    "chainId": 42161,
    "value": "0x0"
  },
  "walletAddress": "0x12426b77FC96a5250f9A2d27dA3B26e826af5Dc0",
  "humanSummary": "Supply 100 USDC on Arbitrum to AAVE V3"
}
```

Required fields: `transactionId` (number, from a prior `build_*`), `txData.to`, `txData.data`, `txData.chainId`, `walletAddress`. Optional: `txData.value` (defaults to `"0x0"`), `humanSummary` (recommended — shown to the user on the signer page).

Response (single content item, `type: text`, with a JSON string body):

```json
{
  "stdin_payload": "<base64-encoded-json>",
  "methods": {
    "browser": { "recommended": true, "command": "npx @vurto/sign-tx@<version>", "args": ["--timeout", "300"] },
    "key": { "command": "npx @vurto/sign-tx@<version>", "args": ["--mode", "key"] },
    "fast": {
      "url": "https://ana.vurto.cc/cli/sign-tx-<version>.cjs",
      "sha256": "<hex>",
      "shell": "f=\"$(mktemp)\" && curl -fsSL <url> -o \"$f\" && echo \"<sha256>  $f\" | sha256sum -c - >/dev/null && node \"$f\" --timeout 300; rc=$?; rm -f \"$f\"; exit $rc"
    }
  },
  "cli": {
    "package": "@vurto/sign-tx",
    "version": "<version>",
    "command": "npx @vurto/sign-tx@<version>",
    "args": ["--timeout", "300"],
    "stdin_payload": "<base64-encoded-json>",
    "parse_stdout_as_json": true,
    "expected_keys": ["txHash", "from"],
    "exit_codes": { "0": "signed", "1": "rejected", "2": "timeout", "3": "error" }
  }
}
```

Pick one `methods` entry (the `cli` block is a flat back-compat mirror of `browser`):

- `browser` (default): `npx @vurto/sign-tx@<version>` over npm — portable (sh/Windows), version-pinned, cosign-verifiable.
- `key`: same npm CLI with `--mode key` for headless signing (the key is typed into the user's terminal, never the chat).
- `fast` (when present): the **same signer fetched from this MCP's own origin** (`/cli/sign-tx-<version>.cjs`) instead of npm — no dependency install, faster cold start. Run `fast.shell` via `sh -c`; it downloads to a temp file, verifies `fast.sha256`, runs it, and cleans up (POSIX sh). Trust is HTTPS to the same origin serving this API. Prefer it for latency; use `browser` for npm's independent integrity check or on Windows.

`stdin_payload` is the base64 encoding of `{ txData, summary: { humanDescription }, walletAddress, transactionId }`. Whichever method you pick, pipe this string verbatim into the process's stdin — the CLI base64-decodes it internally. Do NOT decode it before piping.

CLI stdout on success (one line of JSON):

```json
{ "txHash": "0x...", "from": "0x...", "chainId": 42161, "signedAt": "2026-05-27T15:42:00Z" }
```

After receiving the hash, the agent posts it to the existing tracking endpoint:

```bash
curl -sS https://ana.vurto.cc/api/v1/transactions/12345/send-hash \
  -H 'content-type: application/json' \
  --data '{"txHash":"0x..."}'
```

Version pinning is mandatory: always invoke the exact version returned by the tool, never `@latest`. See `SECURITY.md` for supply-chain verification steps.

Validation errors returned by the tool (as `isError: true`): missing or non-numeric `transactionId`, malformed `walletAddress`, malformed `txData.to` / `txData.data`, or non-integer `txData.chainId`.

## 8. Minimum Pre-Trade Checklist for Agent

Before any build:

1. `POST /position` to get user exposure and available assets.
2. `POST /donator-status` to resolve fee profile.
3. `GET /dapp-vurto/config` to read donation policy, supported dual chains, and runtime limits.
4. For swap flows, always run quote right before build.
5. Reject execution if route impact is too high or payload is missing required addresses.

## 9. Common Error Classes

- `400 invalid_payload` or `invalid_amount`: malformed input.
- `400 unsupported_chain`: dual mode not configured on selected chain.
- `403 cors_origin_not_allowed`: origin not allowed by backend policy.
- `403 target_not_allowed` / `aggregator_not_allowed` / `spender_not_allowed`: dual allowlist enforcement.
- `422 quote_impact_too_high`: risk guardrail triggered.
- `429 rate_limited`: request throttle.

## 10. Response Fields Agents Should Persist

For every successful build, store at least:

- `to`
- `data`
- `value`
- `transactionId` (UUID v4 string; legacy integer form still accepted as input to `/transactions/:id/*`)
- `feeBps`
- `feeAmount`
- `_meta` (contains backend mode and donation policy context)

## 11. Vurto Swap — Token Swaps (MCP-only, proxied)

Ana's MCP server (`https://ana.vurto.cc/mcp`) also exposes `swap_*` tools for general EVM token
swaps (Velora, KyberSwap, 1inch, OpenOcean, CoW Protocol across 9 chains). These have **no REST
equivalent on `ana.vurto.cc/api/v1`** — they are a thin passthrough to the independent, separately
audited Vurto Swap backend at `https://swap.vurto.cc`, not a reimplementation. Use them exactly
like any other Ana tool; the proxy is transparent.

| Tool | Purpose | Needs credential? |
|------|---------|-------------------|
| `swap_quote` | Compare ranked routes for a swap | No |
| `swap_build` | Quote + build a signable plan | **Yes** |
| `swap_double_quote` | Quote two legs at once (split source / converge destination) | No |
| `swap_double_build` | Build both legs of a `swap_double_quote` | **Yes** |
| `swap_prepare_signing` | Local CLI signer invocation for one `swap_build` step | No |
| `swap_report_execution` | Report a sent tx / signed CoW order | **Yes** |
| `swap_status` | Re-check a swap execution's real on-chain/orderbook status | **Yes** |

**Credential**: `swap_build`, `swap_double_build`, `swap_report_execution`, and `swap_status` all
require the caller's own vurto-swap machine credential, sent as the `Authorization: Bearer <token>`
header on the MCP connection to `ana.vurto.cc/mcp` (Ana relays it through unchanged). Obtain one
**once**, using the same wallet already used for AAVE operations, via the challenge/verify/credential
flow documented at `https://swap.vurto.cc/agent-api.md` — Ana does not mint or store this credential
itself. `swap_quote`, `swap_double_quote`, and `swap_prepare_signing` need no credential.

**CLI**: for a non-MCP / scripted flow, the same backend is also reachable via `@vurto/swap`, a
standalone CLI (`quote`/`swap`/`sign`/`status`/`refund`). See `https://swap.vurto.cc` for install
and usage — it is not part of the `vurto-a` package and is not wrapped by Ana.

**Full reference**: tool schemas, provider/chain support, receiver semantics, and error classes for
the swap domain are documented at `https://swap.vurto.cc/agent-api.md` — this section only covers
what differs when calling through Ana instead of `swap.vurto.cc/mcp` directly (nothing does, besides
the URL and the `swap_` tool-name prefix used to avoid colliding with Ana's own AAVE `prepare_signing`).
