Skip to content

LeventLabs/SentinelVault

Repository files navigation

SentinelVault — Agents That Earn The Right To Trade

SentinelVault Cover

🟢 Live Demo: sentinel-vault-ai.vercel.app 🎥 Video Demo: youtu.be/G0hb350hL7k

AI reputation is usually cosmetic. SentinelVault turns it into a transparent, code-enforced economic constraint.

The more trust the agent earns, the more capital it is allowed to deploy. Bad agents can't trade.


Core Idea

Agent starts with minimal seed reputation to bootstrap activity. Trust must be earned through successful trades — every decision is logged with reasoning.

After each trade decision, the agent generates an artifact that captures its reasoning, confidence score, and risk context. If PINATA_JWT is configured, the artifact is pinned to IPFS; otherwise it is saved locally. Either way, the artifact is linked to the executed transaction, creating an auditable trail of agent decisions.


Deployed Contracts (Sepolia)

Contract Address
SentinelVault v2 0x3CEb1CEFa9baaA1b6C62508560a689AeF40F4B48
UniswapV3Adapter 0x5f3E3c7c6ab9dB110185cd05d94D2674644C31C6
ReputationRegistry 0x5e6915AB82aeA458078734435DFE46b0fC4964B9
Policy 0x1d1380eB6CEbAC6FAEFab5C124F5DA20683e4493
OracleVerifier 0x5634150a2A71aE6516b0c92e0f4943B8109821AD
TrustGate 0x508e14620690203AD6Cb8ab65D77F87e049CadD1
Agent 0x79a4Ca003893a3E80bbdBb57f59b9745018106f6
ERC-8004 Identity BaseScan (minted via Synthesis platform registration, not implemented in this repo)

How It Works

Smart Contracts

1. ReputationRegistry.sol

  • getReputation(agent) → uint256
  • reportOutcome(agent, stakeAmount, success, intentHash, reason, confidence) → updates score
  • Asymmetric stake/burn model:
    • Success → reputation += stake * 1.5
    • Failure → reputation -= stake * 2.0
    • Agent must maintain >57% win rate just to hold position
    • Trust is hard to earn, easy to lose
  • ReputationUpdated event with agent, delta, newScore, intentHash

2. Policy.sol

  • getMaxPosition(agent) → uint256 (based on reputation)
  • checkIntent(agent, amount, reputationStake) → (bool allowed, string reason)
  • Formula: maxPosition = base + rep * multiplier (capped by globalMax)
    • Config: base = 100, multiplier = 5, globalMax = 1000
    • rep 0 → 100 | rep 10 → 150 | rep 50 → 350 | rep 100 → 600 | rep 200 → 1000 (cap)
  • Daily limit enforcement per agent
  • Human Guardian: contract owner can pauseAgent() / resumeAgent() — AI is autonomous but human stays in control.

3. SentinelVault v2 — Intent-Verified Execution Engine

  • Not a generic forwarder. Identity-aware, intent-verified, adapter-based, balance-checked execution engine.
  • Agent signs EIP-712 TradeIntent → vault verifies signature on-chain → policy enforced → typed adapter executes swap → balance delta verified → oracle records atomically
  • executeIntent(intent, signature, adapter, adapterData) — the production-grade path:
    • EIP-712 signature verification (agent identity bound to execution)
    • Nonce tracking (replay protection)
    • Deadline enforcement (freshness)
    • Token allowlist (only approved tokenIn/tokenOut)
    • Adapter allowlist (no arbitrary calldata — each DEX gets a typed adapter)
    • Max value per trade limit
    • Policy enforcement (reputation constrains capital)
    • Balance delta verification (don't trust adapter return values)
    • Oracle recording (atomic, tied to execution)
  • Vault IS the execution identity: quote, custody, and routing all bound to vault address
  • Owner can pause(), withdraw(), manage adapters/tokens/limits — guardian retains control

4. OracleVerifier.sol

  • Chainlink ETH/USD price feed for objective trade verification
  • recordTrade() locks entry price from Chainlink (called by vault after successful swap)
  • verifyOutcome() reads exit price after minWait (configurable; 4h in production, 60s for validation) and calls ReputationRegistry

5. TrustGate.sol

  • Any protocol can set a minimum reputation threshold and gate access to agents that haven't earned enough trust
  • Deployed example of how ReputationRegistry enables permissionless trust queries

Reputation-Backed Trade Guarantee

Agent stakes reputation on every trade — confidence becomes economic commitment:

Agent confidence: 0.85 → stakes 15 rep
Agent confidence: 0.35 → stakes 3 rep

Success → reputation += stakeAmount * 1.5
Failure → reputation -= stakeAmount * 2.0

Contract enforces: require(reputation >= stakeAmount) — agent can't stake what it hasn't earned.

Multi-Agent Trust Layer

ReputationRegistry is a public contract — any agent or protocol can query trust before interacting:

uint256 rep = registry.getReputation(counterpartyAgent);
require(rep >= minimumTrust, "Agent not trusted enough");

No centralized registry. No API keys. Reputation lives on-chain and is verifiable by anyone, permissionlessly.

Oracle-Verified Outcomes

Trade outcomes are verified by Chainlink ETH/USD price feed:

  1. Agent executes swap, then calls OracleVerifier.recordTrade() → entry price locked from Chainlink
  2. After minWait elapses (configurable per deployment), an authorized verifier calls OracleVerifier.verifyOutcome(agent) → exit price read from Chainlink
  3. OracleVerifier compares prices and calls ReputationRegistry.reportOutcome()

Entry and exit prices come from the oracle. Verification can be called by the agent or by a separate authorized verifier process.

Agent Loop

AI reasoning (Claude Opus) → decides LONG / SHORT / SKIP
    ↓
EIP-712 TradeIntent signed off-chain
    ↓
SentinelVault.executeIntent()                    ← TRUST BOUNDARY
    ├── 1. EIP-712 signature verified ON-CHAIN (agent identity bound)
    ├── 2. Nonce checked (replay protection)
    ├── 3. Deadline checked (freshness)
    ├── 4. Token allowlist checked
    ├── 5. Adapter allowlist checked (no arbitrary calldata)
    ├── 6. Max value per trade checked
    ├── 7. Policy.sol enforced (reputation constrains capital)
    ├── 8. UniswapV3Adapter executes swap (vault→adapter→SwapRouter02)
    ├── 9. Balance delta verified (don't trust adapter)
    └── 10. OracleVerifier.recordTrade() — atomic, tied to execution
    ↓ (after minWait elapses)
OracleVerifier.verifyOutcome(agent) → Chainlink exit price → reputation update
    ↓
Artifact → IPFS (decision trail)

Architecture: The vault is the execution identity — quote, custody, and routing are all bound to the vault address. Instead of forwarding arbitrary calldata, the vault calls typed swap adapters that know each DEX's semantics. The UniswapV3Adapter routes through SwapRouter02 (which supports contract callers, unlike the Trading API executor). This eliminates the identity mismatch that breaks generic forwarding patterns.

Risk Router Integration

  • Agent produces EIP-712 TradeIntent (agent, market, side, amount, reputationStake, nonce, timestamp)
  • EIP-712 intents are signed off-chain and verified on-chain by the vault before execution
  • For the hackathon demo, Risk Router responses are simulated when RISK_ROUTER_URL is unset
  • On acceptance → vault executes swap via UniswapV3Adapter → txHash on Sepolia

Uniswap Integration

Trade execution via two paths:

  • Vault path (production): SentinelVault → UniswapV3Adapter → SwapRouter02. Adapter knows router semantics, builds correct calls, pins recipient to vault. Contract callers fully supported.
  • Quote API: Uniswap Trading API (https://trade-api.gateway.uniswap.org/v1/) used for price quotes and gas estimates.
  • LONG swaps USDC → ETH, SHORT swaps ETH → USDC
  • Swap amounts are derived from the agent's reputation-scaled maxPosition (0.0003–0.003 ETH range on testnet).

Artifacts & Auditability

  • JSON artifact per decision pinned to IPFS via Pinata
  • On-chain data is limited to events (TradeExecuted, ReputationUpdated) and oracle price records
  • Full reasoning, confidence scores, and trade context live in IPFS artifacts
  • If PINATA_JWT is not set, IPFS pinning is silently skipped (artifacts still saved locally)
{
  "volatility": 0.82,
  "trend": "weak",
  "drawdown": 0.14,
  "confidence": 0.31,
  "mode": "VAULT",
  "stakeAmount": 3,
  "reason": "High volatility and weak trend detected. Reducing exposure and preserving capital.",
  "txHash": "0x...",
  "ipfsCid": "Qm...",
  "timestamp": 1234567890
}

Theme Alignment

Theme How SentinelVault addresses it
Agents that pay Reputation enforces spending limits — vault verifies EIP-712 intent on-chain, enforces policy, executes via typed adapter, verifies balance delta, records on oracle atomically. Full reasoning in IPFS artifacts.
Agents that trust On-chain reputation score = verifiable trust without centralized registry. ERC-8004 identity via Synthesis platform.
Agents that cooperate EIP-712 intents (off-chain signed) + IPFS artifacts = auditable decision trail
Agents that keep secrets Weak fit: minimizes on-chain footprint, but does not implement private payments, ZK auth, or encrypted coordination.

Tech Stack

  • Solidity + Hardhat (contracts)
  • Node.js / TypeScript (agent runtime)
  • Claude (reasoning engine)
  • Kiro CLI (development orchestration)
  • Sepolia testnet
  • Uniswap Trading API (quotes and gas estimates; execution via adapter → SwapRouter02)
  • Chainlink price feeds (oracle verification)
  • EIP-712 typed data signing (off-chain signing, on-chain verification before execution)
  • IPFS / Pinata (artifact storage)

Project Structure

sentinel-vault/
├── contracts/
│   ├── ReputationRegistry.sol
│   ├── Policy.sol
│   ├── OracleVerifier.sol    # Chainlink-verified outcomes
│   ├── TrustGate.sol         # multi-agent trust gate
│   ├── SentinelVault.sol     # intent-verified execution engine (trust boundary)
│   ├── interfaces/
│   │   └── ISwapAdapter.sol  # typed adapter interface
│   ├── adapters/
│   │   └── UniswapV3Adapter.sol  # Uniswap V3 SwapRouter02 adapter
│   └── mocks/
│       ├── MockSwapAdapter.sol   # vault test mock
│       └── MockSwapRouter.sol    # adapter test mock
├── agent/
│   ├── index.ts          # main loop (vault v2 executeIntent path)
│   ├── confidence.ts     # multi-timeframe → confidence score
│   ├── market.ts         # Binance multi-timeframe data
│   ├── intent.ts         # EIP-712 TradeIntent builder
│   ├── reasoning.ts      # Claude reasoning engine
│   ├── riskRouter.ts     # Risk Router adapter (simulated for demo)
│   ├── ipfs.ts           # Pinata IPFS pinning
│   └── uniswap.ts        # Uniswap Trading API
├── test/
│   ├── sentinelVault.test.ts      # 46 vault v2 tests
│   └── uniswapV3Adapter.test.ts   # 7 adapter tests
├── scripts/
│   ├── deploy-all.ts         # unified deploy
│   ├── deploy-vault-v2.ts    # vault v2 + adapter
│   ├── validate-sepolia.ts   # full Sepolia validation suite
│   └── lifecycle-proof.ts    # trade → oracle → verify → reputation delta
├── VALIDATION.md         # on-chain evidence with tx hashes
├── validation-report.json
├── lifecycle-proof.json
├── sample-artifacts/     # real agent decision artifacts
├── hardhat.config.ts
├── .env.example
└── README.md

Live Agent Evidence

The agent runs on a VPS (pm2 managed), executing real Uniswap swaps on Sepolia at every 4-hour UTC candle close.

Runtime Validation (Sepolia)

Full end-to-end validation against real Uniswap V3 on Sepolia — see VALIDATION.md for complete evidence.

Test Result TX Hash
SHORT (ETH→USDC) ✅ 0.0005 ETH → 2.75 USDC 0xf7f5e959...
LONG (USDC→ETH) ✅ 0.5 USDC → 0.00009 ETH 0xc9939be3...
verifyOutcome ✅ rep 32→22 (delta -10) 0x4384674f...
DeadlinePassed ✅ Correctly reverted
NonceUsed ✅ Correctly reverted
TokenNotAllowed ✅ Correctly reverted
AdapterNotAllowed ✅ Correctly reverted
ExceedsMaxValue ✅ Correctly reverted

53 local tests passing (46 vault + 7 adapter). 14 trades executed on-chain.

Sample Transactions

Tick Decision Tx Hash IPFS Artifact
Mar 16 20:00 UTC LONG (150 USDC, stake 3 rep) 0xdbda32... QmVT9AQ...
Mar 17 00:00 UTC SKIP (conflicting signals) QmQ92wn...
Mar 17 04:00 UTC SKIP (overbought RSI 71.57) QmbQeom...
Mar 17 08:00 UTC SKIP (overbought RSI 72.22) QmNtJZ7...

Oracle verification in action: After the Mar 16 20:00 LONG trade, the Chainlink oracle verified the outcome at Mar 17 04:00 — ETH price dropped, reputation went from 40 → 34 (stake 3 × 2.0 = 6 burned).

Sample artifacts are in sample-artifacts/ for inspection.


Deployment & Run

npm install
npx hardhat compile
npx hardhat test          # 53 tests (46 vault + 7 adapter)

# deploy vault v2 + adapter
npx hardhat run scripts/deploy-vault-v2.ts --network sepolia

# run Sepolia validation suite
npx ts-node scripts/validate-sepolia.ts

# run full lifecycle proof (trade → oracle → verify → reputation delta)
npx ts-node scripts/lifecycle-proof.ts

# run agent (dry mode)
DRY_RUN=true npx ts-node agent/index.ts

# run agent (live testnet)
npx ts-node agent/index.ts

Note: The agent only runs in vault mode. VAULT_ADDRESS is required so all live executions pass through the policy-enforced trust boundary.


Known Limitations

  • Risk Router is simulated for the hackathon demo (no live endpoint)
  • verifyOutcome(agent) depends on an authorized caller process; not yet fully automated on-chain
  • ERC-8004 identity was minted via Synthesis platform registration, not implemented in this repo
  • Trade sizing on testnet is proportionally scaled (0.0003–0.003 ETH) — not representative of production amounts
  • minAmountOut is derived from an off-chain quote (Uniswap Trading API); the trust assumption is that the quote source is honest at signing time
  • Approval-reset patterns and adversarial ERC-20 edge cases are not yet hardened for production

EIP-712 TradeIntent

Signed off-chain by the agent, verified on-chain by the vault before execution:

{
  "domain": {
    "name": "SentinelVault",
    "version": "2",
    "chainId": 11155111,
    "verifyingContract": "0x3CEb1CEFa9baaA1b6C62508560a689AeF40F4B48"
  },
  "types": {
    "TradeIntent": [
      { "name": "agent", "type": "address" },
      { "name": "tokenIn", "type": "address" },
      { "name": "tokenOut", "type": "address" },
      { "name": "amountIn", "type": "uint256" },
      { "name": "minAmountOut", "type": "uint256" },
      { "name": "policyAmount", "type": "uint256" },
      { "name": "deadline", "type": "uint256" },
      { "name": "nonce", "type": "uint256" },
      { "name": "isLong", "type": "bool" },
      { "name": "confidence", "type": "uint256" },
      { "name": "reputationStake", "type": "uint256" }
    ]
  }
}

License

MIT

About

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors