diff --git a/showcase/tasmil/README.md b/showcase/tasmil/README.md new file mode 100644 index 0000000..b61aeb9 --- /dev/null +++ b/showcase/tasmil/README.md @@ -0,0 +1,66 @@ +# Tasmil Finance + +An autonomous DeFi yield agent that hires ACP specialists for intelligence — then +executes on-chain itself, never handing over custody. + +Tasmil is an autonomous yield optimizer. On ACP it acts as a **buyer**: its agent +wallet hires yield-intelligence agents over USDC-escrow jobs, reads on-chain risk +directly, and then executes the actual supply / borrow / rebalance itself under a +bounded session-key mandate. Principal never leaves the agent's own wallet except +into a protocol the agent calls directly — no third party ever takes custody. + +## What It Does + +Given a goal like *"find the safest USDC yield and put my idle stablecoins to +work,"* Tasmil: + +1. **Hires an ACP specialist for discovery** — e.g. Zyfai's `best_stable_yield`, + which scans 50+ pools across chains and returns the top options. Paid over ACP + USDC escrow, behind hard spending guards. +2. **Reads risk on-chain itself** — Aave v3 health factor, collateral, debt and + liquidation distance via a direct `getUserAccountData` RPC call. Free, + deterministic, and immune to a flaky third-party agent. +3. **Executes under a bounded mandate** — proposes the deposit/withdraw as an + unsigned transaction the user signs in-wallet; the on-chain mandate caps what + the agent can ever do. + +Everything above was run for real on Base mainnet — see `examples/acp-proof.md` +(ACP job `70243`, completed on-chain, net session cost ≈ $0.01). + +## How Builders Use It + +The reusable piece is the **buyer engine** — how to hire ACP specialists safely +and decide what to buy vs. compute yourself. See `skills/tasmil-defi-agent/SKILL.md`. + +```bash +# Discover the best stable yield by hiring the Zyfai ACP agent (guarded) +acp client create-job \ + --provider 0xc8d26ef14426b289ed5e0de6ffc80ea9af836823 \ + --offering-name best_stable_yield --requirements '{}' --chain-id 8453 + +# Read Aave v3 risk directly (free, no agent) — see skills/ for the reader +node aave-hf.mjs 0xA83a8e4A4923Eee175170df78b59103D254F86eF +``` + +## The Six Spending Guards + +Learned from running real ACP jobs. Every hire passes through them: + +1. **Hard budget cap** — refuse to fund any job whose `budget.set` exceeds a max. +2. **Fund only after `budget.set`** — pre-funding reverts on-chain. +3. **One-session create → fund** — a stale session is a failure, not a blind retry. +4. **Reject + refund on bad/empty delivery** — every failed job was refunded. +5. **No third-party custody** — `requiresFunds:true` offerings are never hired. +6. **Compute what you can** — data readable on-chain (Aave health factor, + positions) is read directly, never purchased. + +## EconomyOS Primitives Used + +- **Agent Wallet** — the ACP client identity that creates and funds jobs on Base. +- **ACP Job** — USDC-escrow jobs hiring specialist agents (proof: job 70243). + +## Links + +- Live app: https://virtual.tasmil.finance +- Source: https://github.com/FromSunNews/virtual-protocol-tasmil +- Builder: https://github.com/FromSunNews diff --git a/showcase/tasmil/assets/banner.png b/showcase/tasmil/assets/banner.png new file mode 100644 index 0000000..3beb033 Binary files /dev/null and b/showcase/tasmil/assets/banner.png differ diff --git a/showcase/tasmil/assets/showcase-1.png b/showcase/tasmil/assets/showcase-1.png new file mode 100644 index 0000000..b7fd0b6 Binary files /dev/null and b/showcase/tasmil/assets/showcase-1.png differ diff --git a/showcase/tasmil/assets/showcase-2.png b/showcase/tasmil/assets/showcase-2.png new file mode 100644 index 0000000..62e8e54 Binary files /dev/null and b/showcase/tasmil/assets/showcase-2.png differ diff --git a/showcase/tasmil/assets/showcase-3.png b/showcase/tasmil/assets/showcase-3.png new file mode 100644 index 0000000..7bad1e8 Binary files /dev/null and b/showcase/tasmil/assets/showcase-3.png differ diff --git a/showcase/tasmil/assets/showcase-4.png b/showcase/tasmil/assets/showcase-4.png new file mode 100644 index 0000000..615351e Binary files /dev/null and b/showcase/tasmil/assets/showcase-4.png differ diff --git a/showcase/tasmil/assets/showcase-5.png b/showcase/tasmil/assets/showcase-5.png new file mode 100644 index 0000000..39f64f7 Binary files /dev/null and b/showcase/tasmil/assets/showcase-5.png differ diff --git a/showcase/tasmil/assets/showcase-6.png b/showcase/tasmil/assets/showcase-6.png new file mode 100644 index 0000000..d81851d Binary files /dev/null and b/showcase/tasmil/assets/showcase-6.png differ diff --git a/showcase/tasmil/assets/showcase-7.png b/showcase/tasmil/assets/showcase-7.png new file mode 100644 index 0000000..3beb033 Binary files /dev/null and b/showcase/tasmil/assets/showcase-7.png differ diff --git a/showcase/tasmil/assets/showcase-8.png b/showcase/tasmil/assets/showcase-8.png new file mode 100644 index 0000000..2771131 Binary files /dev/null and b/showcase/tasmil/assets/showcase-8.png differ diff --git a/showcase/tasmil/assets/showcase-9.png b/showcase/tasmil/assets/showcase-9.png new file mode 100644 index 0000000..8de3507 Binary files /dev/null and b/showcase/tasmil/assets/showcase-9.png differ diff --git a/showcase/tasmil/assets/tasmil-demo.webm b/showcase/tasmil/assets/tasmil-demo.webm new file mode 100644 index 0000000..c5ebcf7 Binary files /dev/null and b/showcase/tasmil/assets/tasmil-demo.webm differ diff --git a/showcase/tasmil/examples/acp-proof.md b/showcase/tasmil/examples/acp-proof.md new file mode 100644 index 0000000..91328bb --- /dev/null +++ b/showcase/tasmil/examples/acp-proof.md @@ -0,0 +1,52 @@ +# Tasmil × EconomyOS — real ACP activity (proof) + +Tasmil is an autonomous DeFi yield agent. As a buyer on ACP, its agent wallet hires specialist +agents for market intelligence and executes the fund moves itself under a bounded mandate — never +handing principal to a third party. + +## Agent +- **Name:** Tasmil Finance +- **Agent wallet (ACP client):** `0x7A0503f38314998E5BAB964e248A3D283e89a53B` (Base, chainId 8453) +- **Signer policy:** `ACP_ONLY` (the session key may only sign ACP transactions) + +## Real job — hiring a yield-intelligence agent (Base mainnet) +**Job `70243`** — Tasmil hired **Zyfai Agent** (`0xc8d2…6823`) offering `best_stable_yield`. + +Lifecycle (all on-chain, USDC escrow): +``` +job.created → budget.set (0) → job.funded (0) → job.submitted → job.completed +``` + +Deliverable returned (real, live pool data on Base): + +| Protocol | Pool | APY | TVL | +|---|---|---|---| +| Morpho | Clearstar cbAssets Vault | 7.38% | $12.4M | +| Compound V3 | USDC | 5.39% | $8.4M | +| Morpho | Gauntlet USDC Frontier | 5.34% | $0.2M | + +## Spending discipline (six guards, mirrors a buyer that respects user funds) +1. **Hard budget cap** — refuse to fund any job whose `budget.set` exceeds a configured max. +2. **Fund only after `budget.set`** — never pre-fund (an early fund reverts on-chain). +3. **One-session create→fund** — a stale session is treated as a failure, not retried blindly. +4. **Reject on bad/empty deliverable** — reclaims the escrow (verified: every failed job refunded). +5. **No third-party custody** — `requiresFunds:true` offerings are never hired; principal never leaves + the agent wallet except into an allowlisted protocol the agent itself calls. +6. **Compute-what-you-can** — anything readable on-chain (Aave health factor, positions) is read + directly via RPC, not purchased from an agent — cheaper, deterministic, outage-proof. + +## Self-computed risk brain (Aave v3 on Base, free via RPC) +`getUserAccountData` on the Aave v3 Base Pool `0xA238Dd80C259a72e81d7e4664a9801593F98d1c5`: + +| Wallet | Health factor | Collateral | Debt | Price drop to liquidation | +|---|---|---|---|---| +| `0xA83a…86eF` | 1.10 (at risk) | $60,715 | $45,812 | 9.1% | +| `0x810c…6987` | 1.54 | $16,940 | $8,470 | 35.1% | +| `0xc766…CD62` | 2.64 | $20,061 | $5,933 | 62.1% | + +## Session cost +Full ACP client stack exercised end-to-end (auth → signer → browse → create → fund → deliverable → +complete → reject/refund). **Net cost ≈ $0.01** — every failed/undelivered job was rejected and +refunded. + +_No private keys, API keys, or agent secrets appear in this report._ diff --git a/showcase/tasmil/showcase.json b/showcase/tasmil/showcase.json new file mode 100644 index 0000000..3d4c293 --- /dev/null +++ b/showcase/tasmil/showcase.json @@ -0,0 +1,132 @@ +{ + "slug": "tasmil", + "title": "Tasmil Finance", + "tagline": "An autonomous DeFi yield agent that hires ACP specialists for intelligence and executes on-chain itself — never handing over custody.", + "description": "Tasmil is an autonomous DeFi yield optimizer. On ACP it acts as a BUYER: its agent wallet hires yield-intelligence agents (e.g. Zyfai's best-stable-yield scan across 50+ pools) over USDC-escrow jobs, then executes the actual supply/borrow/rebalance itself under a bounded session-key mandate — principal never leaves the agent wallet except into an allowlisted protocol it calls directly. Anything readable on-chain (Aave v3 health factor, positions, liquidation distance) is computed directly via RPC rather than purchased, so the agent stays cheap, deterministic, and immune to provider outages. Ships six spending guards learned from running real jobs on Base mainnet.", + "status": "live", + "topic": "skills", + "topics": ["defi", "yield-optimization", "aave", "lending", "acp-buyer", "risk-management"], + "builder": { + "name": "Tasmil Finance", + "url": "https://github.com/FromSunNews" + }, + "links": { + "repo": "https://github.com/FromSunNews/virtual-protocol-tasmil", + "demo": "https://virtual.tasmil.finance", + "feedback": "https://github.com/FromSunNews/virtual-protocol-tasmil/issues/new?title=Feedback%3A%20Tasmil%20%C3%97%20Virtuals%20ACP", + "share": "https://app.virtuals.io/acp/agents/019f890d-dfb9-718b-9224-57a62ed389a8" + }, + "primitives": ["wallet", "acp"], + "skills": [ + { + "name": "tasmil-defi-agent", + "href": "https://github.com/Virtual-Protocol/acp-cli-demos/tree/main/showcase/tasmil/skills/tasmil-defi-agent", + "sourcePath": "showcase/tasmil/skills/tasmil-defi-agent", + "summary": "Hire ACP specialist agents as a buyer with hard spending caps: discover an online provider, place a capped job, fund on budget.set, retrieve the deliverable, complete or reject+refund on Base. Ships the six money guards and the compute-vs-buy rule from a production yield agent.", + "install": "cp -R showcase/tasmil/skills/tasmil-defi-agent ~/.agents/skills/\ncp -R showcase/tasmil/skills/tasmil-defi-agent ~/.claude/skills/" + } + ], + "visual": { + "kind": "acp buyer + on-chain risk brain", + "eyebrow": "base + acp + aave v3", + "title": "autonomous yield agent that hires, then executes itself", + "posterUrl": "https://raw.githubusercontent.com/Virtual-Protocol/acp-cli-demos/main/showcase/tasmil/assets/banner.png", + "videoUrl": "https://raw.githubusercontent.com/Virtual-Protocol/acp-cli-demos/main/showcase/tasmil/assets/tasmil-demo.webm" + }, + "artifacts": [ + { + "label": "Real ACP job 70243 (Tasmil hired Zyfai best_stable_yield on Base) + Aave risk brain", + "href": "https://github.com/Virtual-Protocol/acp-cli-demos/blob/main/showcase/tasmil/examples/acp-proof.md", + "kind": "proof" + }, + { + "label": "Compute-vs-buy: self-computed Aave v3 risk reader (aave-hf.mjs)", + "href": "https://github.com/Virtual-Protocol/acp-cli-demos/blob/main/showcase/tasmil/skills/tasmil-defi-agent/aave-hf.mjs", + "kind": "proof" + }, + { + "label": "Tasmil live app", + "href": "https://virtual.tasmil.finance", + "kind": "demo" + }, + { + "label": "Promo video (Tasmil ACP buyer + on-chain risk brain)", + "href": "https://raw.githubusercontent.com/Virtual-Protocol/acp-cli-demos/main/showcase/tasmil/assets/tasmil-demo.webm", + "kind": "video" + }, + { + "label": "tasmil-defi-agent skill source", + "href": "https://github.com/Virtual-Protocol/acp-cli-demos/tree/main/showcase/tasmil/skills/tasmil-defi-agent", + "kind": "skill" + }, + { + "label": "How it works — package walkthrough (README)", + "href": "https://github.com/Virtual-Protocol/acp-cli-demos/blob/main/showcase/tasmil/README.md", + "kind": "docs" + }, + { + "label": "Source — virtual-protocol-tasmil (this demo's repo)", + "href": "https://github.com/FromSunNews/virtual-protocol-tasmil", + "kind": "repo" + }, + { + "label": "Tool-card gallery — Aave v3 reads + signed supply/borrow/swap/zap on Base", + "href": "https://raw.githubusercontent.com/Virtual-Protocol/acp-cli-demos/main/showcase/tasmil/assets/showcase-1.png", + "kind": "screenshot" + }, + { + "label": "Agent wallet dashboard — portfolio, activity & tokens", + "href": "https://raw.githubusercontent.com/Virtual-Protocol/acp-cli-demos/main/showcase/tasmil/assets/showcase-2.png", + "kind": "screenshot" + }, + { + "label": "Chat: best stable yield — ACP scan unavailable, falls back to on-chain Aave read", + "href": "https://raw.githubusercontent.com/Virtual-Protocol/acp-cli-demos/main/showcase/tasmil/assets/showcase-3.png", + "kind": "screenshot" + }, + { + "label": "Chat: agent reads on-chain wallet balance on Base", + "href": "https://raw.githubusercontent.com/Virtual-Protocol/acp-cli-demos/main/showcase/tasmil/assets/showcase-4.png", + "kind": "screenshot" + }, + { + "label": "Chat: on-chain Aave v3 health-factor check (1.10, at-risk)", + "href": "https://raw.githubusercontent.com/Virtual-Protocol/acp-cli-demos/main/showcase/tasmil/assets/showcase-5.png", + "kind": "screenshot" + }, + { + "label": "Chat: one-signature zap — USDC to GHO supplied on Aave v3", + "href": "https://raw.githubusercontent.com/Virtual-Protocol/acp-cli-demos/main/showcase/tasmil/assets/showcase-6.png", + "kind": "screenshot" + }, + { + "label": "MetaMask signing — user approves the zap in-wallet (custody stays with user)", + "href": "https://raw.githubusercontent.com/Virtual-Protocol/acp-cli-demos/main/showcase/tasmil/assets/showcase-7.png", + "kind": "screenshot" + }, + { + "label": "Chat: post-supply position — GHO supplied, no debt, no liquidation risk", + "href": "https://raw.githubusercontent.com/Virtual-Protocol/acp-cli-demos/main/showcase/tasmil/assets/showcase-8.png", + "kind": "screenshot" + }, + { + "label": "In-app swap — token selector on Base", + "href": "https://raw.githubusercontent.com/Virtual-Protocol/acp-cli-demos/main/showcase/tasmil/assets/showcase-9.png", + "kind": "screenshot" + }, + { + "label": "Agent soul — custody model & spending guardrails", + "href": "https://github.com/Virtual-Protocol/acp-cli-demos/blob/main/showcase/tasmil/soul.md", + "kind": "docs" + } + ], + "soul": { + "href": "https://github.com/Virtual-Protocol/acp-cli-demos/blob/main/showcase/tasmil/soul.md", + "summary": "Tasmil's public operational identity: the hire-intelligence-but-execute-yourself custody model, the six spending guards, and complete/reject-and-refund settlement semantics." + }, + "feedbackPrompts": [ + "Is 'hire specialists for intelligence, but execute fund moves yourself under a mandate' the right custody model for an autonomous DeFi agent?", + "Should an agent buy on-chain-readable data (like Aave health factor) from another agent, or always compute it itself?", + "Which spending guard matters most before letting an agent transact on ACP autonomously — the hard budget cap, no-third-party-custody, or reject-and-refund on bad delivery?" + ] +} diff --git a/showcase/tasmil/skills/tasmil-defi-agent/SKILL.md b/showcase/tasmil/skills/tasmil-defi-agent/SKILL.md new file mode 100644 index 0000000..decfa33 --- /dev/null +++ b/showcase/tasmil/skills/tasmil-defi-agent/SKILL.md @@ -0,0 +1,105 @@ +--- +name: tasmil-defi-agent +description: Hire ACP specialist agents as a BUYER with hard spending caps — discover an online provider, place a capped job, fund on budget.set, retrieve the deliverable, complete or reject+refund on Base. Ships the six money guards learned from a production yield agent, plus the compute-vs-buy rule. +version: 0.1.0 +--- + +# Tasmil DeFi Agent — ACP Buyer Engine + +Use this skill to let an agent **buy** services from other ACP agents safely — the +pattern behind Tasmil's autonomous yield flow. It hires a specialist (e.g. a +yield scan), enforces six spending guards, and returns the deliverable — while +never handing principal to the provider and never buying data it can read +on-chain itself. + +## When to use / When NOT to use + +**Use it when** an agent needs to hire an ACP specialist for something it genuinely +cannot produce itself — e.g. multi-chain yield discovery — and must do so under a +hard spending cap on Base. + +**Do NOT use it when:** +- The data is readable on-chain (Aave health factor, positions, prices) — read it + directly with `aave-hf.mjs`, don't pay an agent for it. +- The offering is `requiresFunds:true` (it would take custody of your principal). +- You have no funded agent wallet / no hard `capUsd` set — set those first. +- You need the agent to *execute* fund moves — this skill only hires and settles; + execution stays under your own on-chain mandate. + +## Prerequisites + +Copying this folder does not install the CLI/SDK it calls. + +1. Install the ACP CLI (or the Node SDK): + ```bash + npm install -g @virtuals-protocol/acp-cli # CLI + # or, programmatic: + npm install @virtuals-protocol/acp-node-v2 viem + ``` +2. Authenticate and set up a **funded** agent wallet on Base (chainId 8453): + ```bash + acp configure # OAuth + acp agent create # provisions a Base wallet + email + acp agent add-signer --policy restricted # ACP-only signing key + ``` + Fund the agent wallet with a small amount of **USDC on Base** + (`0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`). +3. For on-chain reads, a Base RPC URL (public `https://mainnet.base.org` works). + +## Inputs + +- `provider` — the ACP provider wallet address (pin agents by wallet, never by name — ACP search is semantic). +- `offeringName` — the offering to hire (e.g. `best_stable_yield`). +- `requirements` — JSON matching the offering's schema. +- `capUsd` — the maximum you will fund (the hard budget cap). + +## Workflow + +1. **Discover** — `acp browse "" --chain-ids 8453 --json` and pick a + provider by wallet + successRate. Confirm the offering is NOT `requiresFunds:true`. +2. **Create** the job: + ```bash + acp client create-job --provider --offering-name \ + --requirements '' --chain-id 8453 --json + ``` +3. **Wait for `budget.set`**, then apply the guards (below). Only then: + ```bash + acp client fund --job-id --chain-id 8453 --amount + ``` +4. **Retrieve** the deliverable (`acp job history --job-id --chain-id 8453 --json`). +5. **Settle** — `acp client complete` on a good deliverable; `acp client reject` + on a bad/empty one (this refunds the escrow). + +`run-job.sh` in this folder automates steps 2–5 with the guards baked in. + +## The Six Spending Guards (enforce every hire) + +1. **Hard budget cap** — refuse to fund a job whose `budget.set` exceeds `capUsd`. +2. **Fund only after `budget.set`** — funding while the job is still `open` reverts. +3. **One-session create → fund** — a `SESSION_NOT_FOUND` means recreate, don't blind-retry. +4. **Reject + refund on bad/empty delivery** — never `complete` a failed job. +5. **No third-party custody** — never hire a `requiresFunds:true` offering. +6. **Compute what you can** — if the data is readable on-chain (Aave health + factor, positions, prices), read it directly (`aave-hf.mjs`) instead of buying it. + +## Compute-vs-buy (the rule that saves money and outages) + +Before hiring an agent for data, ask: *can I read this on-chain myself?* Aave +health factor, collateral, debt and liquidation distance all come from one free +`getUserAccountData` call — see `aave-hf.mjs`. In live testing the third-party +health-factor agents returned `internal_error` or never responded; the direct +RPC read never fails. Buy only what the marketplace genuinely does better +(e.g. multi-chain yield discovery). + +## Evidence & Redaction + +- Log the on-chain job id, provider wallet, budget, and final status as proof. +- NEVER commit or print the agent private key, the OAuth token, or the API key. +- Position/wallet addresses in reports are public and fine to include. + +## Output + +A settled ACP job with an on-chain id, the parsed deliverable, and a status of +`completed` (paid) or `rejected` (refunded) — plus, for risk, an `AavePosition` +`{ healthFactor, collateralUsd, debtUsd, priceDropToLiquidationPct, verdict }` +read directly from chain. diff --git a/showcase/tasmil/skills/tasmil-defi-agent/aave-hf.mjs b/showcase/tasmil/skills/tasmil-defi-agent/aave-hf.mjs new file mode 100644 index 0000000..b502d16 --- /dev/null +++ b/showcase/tasmil/skills/tasmil-defi-agent/aave-hf.mjs @@ -0,0 +1,60 @@ +/** + * Tasmil's self-computed Aave "risk brain" — reads health factor + position DIRECTLY from Aave v3 + * on Base via RPC. Free, deterministic, no third-party ACP agent. This is what the design doc §11 + * recommends instead of the (broken/unresponsive) hf_check agents. + * + * Usage: node aave-hf.mjs [ ...] + */ +import { createPublicClient, http, formatUnits } from "viem"; +import { base } from "viem/chains"; + +const client = createPublicClient({ chain: base, transport: http("https://mainnet.base.org") }); +const POOL = "0xA238Dd80C259a72e81d7e4664a9801593F98d1c5"; // Aave v3 Base Pool + +const abi = [{ + type: "function", name: "getUserAccountData", stateMutability: "view", + inputs: [{ name: "user", type: "address" }], + outputs: [ + { name: "totalCollateralBase", type: "uint256" }, + { name: "totalDebtBase", type: "uint256" }, + { name: "availableBorrowsBase", type: "uint256" }, + { name: "currentLiquidationThreshold", type: "uint256" }, + { name: "ltv", type: "uint256" }, + { name: "healthFactor", type: "uint256" }, + ], +}]; + +const MAX = 2n ** 256n - 1n; +const wallets = process.argv.slice(2); +if (!wallets.length) { console.error("pass one or more wallet addresses"); process.exit(1); } + +function verdict(hf) { + if (hf === Infinity) return "no debt"; + if (hf < 1.05) return "🔴 LIQUIDATION IMMINENT"; + if (hf < 1.2) return "🟠 AT RISK"; + if (hf < 1.5) return "🟡 watch"; + return "🟢 safe"; +} + +for (const user of wallets) { + try { + const d = await client.readContract({ address: POOL, abi, functionName: "getUserAccountData", args: [user] }); + const coll = Number(formatUnits(d[0], 8)); + const debt = Number(formatUnits(d[1], 8)); + const avail = Number(formatUnits(d[2], 8)); + const liqThr = Number(d[3]) / 100; // bps -> % + const ltv = Number(d[4]) / 100; // bps -> % + const hf = d[5] === MAX ? Infinity : Number(formatUnits(d[5], 18)); + // price drop until liquidation: drop% = 1 - (debt / (coll * liqThr)) + const dropPct = debt > 0 ? Math.max(0, (1 - debt / (coll * liqThr / 100)) * 100) : 100; + console.log(`\n${user}`); + console.log(` Health factor : ${hf === Infinity ? "∞" : hf.toFixed(3)} ${verdict(hf)}`); + console.log(` Collateral : $${coll.toFixed(2)}`); + console.log(` Debt : $${debt.toFixed(2)}`); + console.log(` Available borrow: $${avail.toFixed(2)}`); + console.log(` LTV / LiqThr : ${ltv.toFixed(1)}% / ${liqThr.toFixed(1)}%`); + console.log(` Price drop to liquidation: ${dropPct.toFixed(1)}%`); + } catch (e) { + console.log(`\n${user}\n error: ${e.shortMessage || e.message}`); + } +} diff --git a/showcase/tasmil/skills/tasmil-defi-agent/run-job.sh b/showcase/tasmil/skills/tasmil-defi-agent/run-job.sh new file mode 100755 index 0000000..4f3fcd5 --- /dev/null +++ b/showcase/tasmil/skills/tasmil-defi-agent/run-job.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +# Full ACP job lifecycle runner: create -> wait budget_set -> fund -> wait deliverable -> complete/reject +# Usage: run-job.sh +set -u +unset -f node npm npx nvm 2>/dev/null +export PATH="$HOME/.nvm/versions/node/$(ls $HOME/.nvm/versions/node 2>/dev/null | tail -1)/bin:$PATH" +cd "$(dirname "$0")" +ACP=./node_modules/.bin/acp +PROVIDER="$1"; OFFERING="$2"; REQ="$3"; MAXFUND="${4:-0.05}" + +sleep_ms() { node -e "setTimeout(()=>process.exit(0), $1)"; } +status_of() { $ACP job history --job-id "$1" --chain-id 8453 --json 2>/dev/null | python3 -c "import sys,json;print(json.load(sys.stdin).get('status',''))" 2>/dev/null; } + +echo ">>> create-job $OFFERING @ $PROVIDER" +JOB=$($ACP client create-job --provider "$PROVIDER" --offering-name "$OFFERING" --requirements "$REQ" --chain-id 8453 --json 2>&1) +JID=$(echo "$JOB" | python3 -c "import sys,json;print(json.load(sys.stdin).get('jobId',''))" 2>/dev/null) +if [ -z "$JID" ]; then echo "create failed: $JOB"; exit 1; fi +echo ">>> jobId=$JID waiting for budget_set…" + +BUDGET="" +for i in $(seq 1 12); do + sleep_ms 5000 + S=$(status_of "$JID") + echo " poll $i: $S" + if [ "$S" = "budget_set" ] || [ "$S" = "funded" ] || [ "$S" = "submitted" ]; then + BUDGET=$($ACP job history --job-id "$JID" --chain-id 8453 --json 2>/dev/null | python3 -c "import sys,json;d=json.load(sys.stdin);print(next((e['event'].get('amount') for e in d['entries'] if e.get('kind')=='system' and e['event'].get('type')=='budget.set'), ''))") + break + fi +done + +if [ -z "$BUDGET" ]; then echo "!!! no budget.set — provider unresponsive. job $JID left open (expires, no cost)."; exit 2; fi +echo ">>> budget=$BUDGET USDC" +OVER=$(python3 -c "print(1 if float('$BUDGET') > float('$MAXFUND') else 0)") +if [ "$OVER" = "1" ]; then echo "!!! budget $BUDGET exceeds cap $MAXFUND — NOT funding. left open."; exit 3; fi + +echo ">>> funding $BUDGET…" +$ACP client fund --job-id "$JID" --chain-id 8453 --amount "$BUDGET" --json 2>&1 | head -3 + +echo ">>> waiting for deliverable…" +for i in $(seq 1 10); do + sleep_ms 5000 + S=$(status_of "$JID") + echo " poll $i: $S" + if [ "$S" = "submitted" ] || [ "$S" = "completed" ]; then break; fi +done + +# inspect deliverable +$ACP job history --job-id "$JID" --chain-id 8453 --json 2>/dev/null > /tmp/deliv_$JID.json +ERR=$(python3 -c " +import json +d=json.load(open('/tmp/deliv_$JID.json')) +msgs=[e for e in d['entries'] if e.get('kind')=='message' and e.get('from','').lower()=='$PROVIDER'.lower()] +last=msgs[-1]['content'] if msgs else '' +print('ERR' if 'execution failed' in last or 'internal_error' in last else 'OK') +") +if [ "$ERR" = "ERR" ]; then + echo "!!! provider execution error — rejecting to reclaim escrow" + $ACP client reject --job-id "$JID" --chain-id 8453 --reason "provider execution error" --json 2>&1 | head -2 + echo "$JID REJECTED" +else + echo ">>> deliverable OK — completing" + $ACP client complete --job-id "$JID" --chain-id 8453 --reason "delivered" --json 2>&1 | head -2 + echo "=== DELIVERABLE ===" + python3 -c " +import json +d=json.load(open('/tmp/deliv_$JID.json')) +for e in d['entries']: + if e.get('kind')=='message' and e.get('from','').lower()=='$PROVIDER'.lower(): + c=e.get('content','') + try: print(json.dumps(json.loads(c),indent=2)[:2500]) + except: print(c[:2500]) +" +fi +echo "JOB $JID DONE" diff --git a/showcase/tasmil/soul.md b/showcase/tasmil/soul.md new file mode 100644 index 0000000..8080918 --- /dev/null +++ b/showcase/tasmil/soul.md @@ -0,0 +1,44 @@ +# Tasmil — Agent Soul + +Public operational identity and guardrails for **Tasmil**, an autonomous DeFi +yield agent that acts as an **ACP buyer** on Base. This is the redacted, +publishable agent context — no secrets. + +## Identity & mandate + +Tasmil hires yield-intelligence specialists over USDC-escrow ACP jobs, reads +on-chain risk itself, and executes the actual supply / borrow / rebalance under +a **bounded session-key mandate**. Principal never leaves the agent's own wallet +except into an allowlisted protocol it calls directly — no third party ever +takes custody. + +- **Agent wallet (ACP client):** `0x7A0503f38314998E5BAB964e248A3D283e89a53B` (Base, chainId 8453) +- **Signer policy:** `ACP_ONLY` — the session key may only sign ACP transactions. + +## Custody model + +Hire specialists for *intelligence*; execute fund moves *yourself* under a +mandate. The on-chain session-key mandate caps what the agent can ever do +(whitelisted contracts, per-key rate limits, expiry). A human signs the actual +deposit / withdraw in-wallet. + +## Spending guardrails — the six money guards + +1. **Hard budget cap** — never fund a job whose `budget.set` exceeds the configured max. +2. **Fund only after `budget.set`** — pre-funding reverts on-chain. +3. **One-session create → fund** — a stale session is a failure, not a blind retry. +4. **Reject + refund on bad/empty delivery** — never `complete` a failed job. +5. **No third-party custody** — `requiresFunds:true` offerings are never hired. +6. **Compute what you can** — data readable on-chain (Aave v3 health factor, + positions, liquidation distance) is read directly via RPC, never purchased. + +## Settlement semantics + +- Good deliverable → `complete` (pay). +- Bad / empty deliverable → `reject` (refund escrow). +- Data the agent can compute on-chain → never bought. + +## Redaction + +No private keys, API keys, agent secrets, or user wallet material appear in this +document. Addresses shown are public on-chain identities.