Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: CI

on:
push:
branches: [master, main]
pull_request:

jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Install
run: bun install --frozen-lockfile
- name: Typecheck + build
run: bun run build
- name: Test
run: bun test
233 changes: 159 additions & 74 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
<div align="center">

# 🛡️ plugin-tereno
<img src="images/logo.png" alt="Tereno" width="150" />

### Your agent's onchain instinct — verdicts before it signs, income while it sleeps
# plugin-tereno

[![npm version](https://img.shields.io/npm/v/plugin-tereno?style=flat-square&color=00ff66)](https://www.npmjs.com/package/plugin-tereno)
[![ElizaOS](https://img.shields.io/badge/ElizaOS-%E2%89%A51.0-blueviolet?style=flat-square)](https://elizaos.ai)
[![Base](https://img.shields.io/badge/Base-mainnet-0052FF?style=flat-square)](https://base.org)
[![x402](https://img.shields.io/badge/payments-x402%20%2F%20USDC-2775CA?style=flat-square)](https://www.x402.org)
[![Discord](https://img.shields.io/badge/community-Discord-5865F2?style=flat-square)](https://discord.gg/YsgGSRBxn)
### 🛡️ A pre-signature security layer for ElizaOS agents on Base

**No API key. No signup. No subscription.**
Your agent's wallet *is* the account — it pays per answer in USDC over x402,
and earns its own safety budget by contributing verified work back to the network.
**Before your agent signs, it checks.** One paid call flags unlimited approvals,
suspicious contracts, unexpected balance changes and abnormal gas — and returns
a single, standardized verdict your agent can branch on.

<br/>

[![npm version](https://img.shields.io/npm/v/plugin-tereno?style=for-the-badge&color=0052FF&logo=npm)](https://www.npmjs.com/package/plugin-tereno)
[![ElizaOS](https://img.shields.io/badge/ElizaOS-%E2%89%A51.0-8B5CF6?style=for-the-badge)](https://elizaos.ai)
[![Base](https://img.shields.io/badge/Base-0052FF?style=for-the-badge&logo=coinbase&logoColor=white)](https://base.org)
[![x402](https://img.shields.io/badge/x402%20%C2%B7%20USDC-2775CA?style=for-the-badge)](https://www.x402.org)

[![CI](https://img.shields.io/github/actions/workflow/status/RobMartello/plugin-tereno/ci.yml?style=flat-square&label=CI)](https://github.com/RobMartello/plugin-tereno/actions)
[![license](https://img.shields.io/npm/l/plugin-tereno?style=flat-square&color=green)](./LICENSE)
[![fail-closed](https://img.shields.io/badge/default-fail--closed-critical?style=flat-square)](#fail-open-vs-fail-closed)

```bash
bun add plugin-tereno
Expand All @@ -24,115 +31,193 @@ bun add plugin-tereno

## ⚡ Why this exists

Every autonomous agent on Base faces the same two problems:
Autonomous agents sign transactions with no instinct for danger. One malicious
approval, one drainer contract, one rug-after-audit, and the wallet is gone.

`plugin-tereno` gives an ElizaOS agent a **pre-signature check**: before it signs
a Base transaction, it buys a bounded verdict from [Tereno](https://www.tereno.xyz)
that simulates the call and flags the ways it could lose funds. **Failed calls are
never charged** — x402 settles only after a successful response.

- **No API key, no signup.** The agent's wallet *is* the identity; it pays a few
cents per check in USDC over x402.
- **Budget-capped.** Per-call and rolling-daily USDC limits — a chatty agent can't
drain its wallet.
- **Fail-closed by default.** If the check can't complete, a financial action is
told to **abort**, not to sign blind.

## 🚦 The core check

```
TERENO_CHECK_TRANSACTION
{"from":"0x…","to":"0x…","data":"0x…","value":"0"}
│
▼
decision · riskLevel · reason · exposure · cost · recommendedAction
```

Every guard action returns the **same standardized verdict**:

1. **It signs blind.** One malicious approval and the wallet is gone.
2. **It recomputes what thousands of other agents already computed.** Same
token lookups, same contract checks, same RPC work — paid N times.
```ts
interface TerenoVerdict {
decision: "allow" | "review" | "block";
riskLevel: "none" | "low" | "medium" | "high";
reason: string; // human-readable summary + reason codes
exposure: { // what the tx would change
balanceDeltas?: unknown;
allowanceChanges?: unknown;
unlimitedApproval: boolean;
};
cost: { paidUsd: number; capUsd: number; dailySpentUsd: number };
recommendedAction: "sign" | "review" | "abort";
receiptUrl: string | null;
raw: unknown; // full Tereno payload, unchanged
}
```

[Tereno](https://www.tereno.xyz) is a coordination layer that fixes both:
bounded pre-sign verdicts for cents, served from a **shared cache that gets
cheaper the more agents use it** — and pays the agent who seeded each answer.
Your agent branches on one field: `recommendedAction`.

## 🔍 Spend loop — answers before actions
## 🔍 What it checks

| Action | Price | The question it answers |
|---|---:|---|
| 🚦 `TERENO_CHECK_TRANSACTION` | $0.005 | **Is this safe to sign?** Simulation, gas, balance/allowance deltas, drainer & unlimited-approval flags |
| 🛡️ `TERENO_CHECK_CONTRACT` | $0.001–3 | Is this contract safe to interact with? (code, proxy, pause) |
| 🕵️ `TERENO_CONTRACT_CHANGED` | $0.001 | Did it change since last look? The rug-pull-after-audit detector |
| 🕵️ `TERENO_CONTRACT_CHANGED` | $0.001 | Did it change since last look? (rug-pull-after-audit detector) |
| 🪙 `TERENO_TOKEN_INFO` | $0.001 | What token is this, really? (name, symbol, decimals, supply) |
| 🧬 `TERENO_CONTRACT_INTERFACE` | $0.001 | ERC-20? NFT? Proxy? One bounded probe |
| ⛽ `TERENO_CHAIN_SNAPSHOT` | $0.001 | Latest Base block + gas, zero parameters |
| 🧾 `TERENO_PREVIEW` | free | What the checks cover, cost and current config |
| 📖 `TERENO_CATALOG` | free | Live catalog and prices |

Every verdict ships with reason codes, evidence, block freshness and
**explicit limitations**. Failed calls are never charged — x402 settles only
after a successful response.

## 🌱 Earn loop — the agent funds itself

The network publishes its **unmet demand as open bounties**. Your agent can
claim them:

| Action | Cost | What happens |
|---|---:|---|
| 📋 `TERENO_BOUNTIES` | free | See what the network will pay for next |
| 🌱 `TERENO_SEED` | free–$0.001 | Compute a contract fingerprint locally (free RPC work), publish it signed, pass the on-chain recomputation audit → **claim the seeder slot** |
| 📈 `TERENO_STANDING` | free | Audited track record: publications, reuses, credits |
| ✍️ `TERENO_REPORT_OUTCOME` | free | Honest signed feedback → review credit |

**Seeders earn 20% of every settled cross-wallet reuse** of their work, as
credits that discount the guard calls. Buy protection → contribute work →
protection pays for itself. That's the flywheel.
## 🚀 Quickstart (free, no wallet needed)

> **The honest fine print** (we lead with it on purpose): rewards are
> non-transferable credits, capped per artifact. This funds your agent's
> safety — it is not yield farming. Reputation is computed by the network
> from recomputation audits and settled economics, never from claims.
Dry-run mode wires the whole flow with **no payment**, so you can integrate first
and spend later:

## 🚀 Quick start
```bash
# .env
TERENO_DRY_RUN=true # no x402 payment; validates + shapes the verdict
TERENO_NETWORK=eip155:8453 # Base mainnet
```

```ts
import terenoPlugin from "plugin-tereno";

// register like any ElizaOS plugin
agent(character, [terenoPlugin]);
import { terenoPlugin } from "plugin-tereno";
// add terenoPlugin to your ElizaOS character's plugins, then ask the agent:
// is it safe to sign {"from":"0x…","to":"0x…","data":"0x…"}?
// → returns a TerenoVerdict with recommendedAction, no USDC spent.
```

```env
# the wallet that pays — needs USDC on Base (falls back to EVM_PRIVATE_KEY)
TERENO_PRIVATE_KEY=0x...
A complete runnable agent lives in [`examples/eliza-base-agent`](./examples/eliza-base-agent).

# hard budget guards (defaults shown)
TERENO_MAX_PRICE_USD=0.005
TERENO_DAILY_BUDGET_USD=0.05
### Going live

# recommended for public-facing agents: strangers can't spend your USDC
TERENO_PRIVATE_ONLY=true
```bash
TERENO_DRY_RUN=false
TERENO_PRIVATE_KEY=0x… # a dedicated hot wallet with a little USDC on Base
TERENO_MAX_PRICE_USD=0.005 # per-call cap
TERENO_DAILY_BUDGET_USD=0.05 # rolling daily cap
TERENO_FAIL_MODE=closed # financial checks abort if the guard can't answer
```

> **Networks.** The hosted Tereno API (`www.tereno.xyz`) serves **Base mainnet**.
> To try it on **Base Sepolia**, point `TERENO_API_URL` at a Tereno instance
> configured with `X402_NETWORK=eip155:84532` (self-host) and set
> `TERENO_NETWORK=eip155:84532`. Dry-run works on any network with no wallet.

Then just talk to your agent:

> **you:** is it safe to sign this? `{"from":"0x…","to":"0x…","data":"0x095ea7b3…"}`
> **agent:** ⚠️ review — UNLIMITED_ALLOWANCE. The spender gets max approval. Paid $0.005 · receipt attached.
>
> **you:** what is the network asking for?
> **agent:** 3 open bounties. Seeding the top one costs me only RPC work and earns $0.0002/reuse.
>
> **you:** seed it
> **agent:** 🌱 Fingerprint published, audit passed. I'm the seeder now.
> **agent:** ⛔ BLOCK · risk high · → abort — UNLIMITED_ALLOWANCE: the spender gets max approval. Paid $0.005 · receipt attached.

## ⚙️ All configuration
## ⚙️ Configuration

| Env | Default | Purpose |
|---|---|---|
| `TERENO_PRIVATE_KEY` | — | Paying wallet (or `EVM_PRIVATE_KEY`) |
| `TERENO_MAX_PRICE_USD` | `0.005` | Per-call cap |
| `TERENO_DAILY_BUDGET_USD` | `0.05` | Rolling daily cap |
| `TERENO_PRIVATE_ONLY` | `false` | Refuse paid actions from public Discord/Telegram/Twitter |
| `TERENO_NETWORK` | `eip155:8453` | Base mainnet · `eip155:84532` for Sepolia |
| `TERENO_API_URL` | `https://www.tereno.xyz` | API origin |
| `TERENO_RPC_URL` | `https://mainnet.base.org` | RPC for local fingerprint work |
| `TERENO_PRIVATE_KEY` | — | Wallet that pays x402 (USDC on Base). Falls back to `EVM_PRIVATE_KEY`. |
| `TERENO_MAX_PRICE_USD` | `0.005` | Per-call USDC cap. |
| `TERENO_DAILY_BUDGET_USD` | `0.05` | Rolling daily USDC budget. |
| `TERENO_FAIL_MODE` | `closed` | `closed` → financial checks abort on failure; `open` → degrade to review. |
| `TERENO_DRY_RUN` | `false` | `true` → no payment, simulated verdict. |
| `TERENO_PRIVATE_ONLY` | `false` | `true` → refuse paid actions from public Discord/Telegram/Twitter. |
| `TERENO_NETWORK` | `eip155:8453` | `eip155:8453` (mainnet) or `eip155:84532` (Sepolia). |
| `TERENO_API_URL` | `https://www.tereno.xyz` | API origin. |
| `TERENO_RPC_URL` | `https://mainnet.base.org` | RPC for local fingerprint work. |
| `TERENO_TELEMETRY` | `on` | `off` → send no anonymous usage telemetry. |

### Fail-open vs fail-closed

- **`closed` (default, for financial actions):** if the guard errors, times out, or
the daily budget is spent, `TERENO_CHECK_TRANSACTION` returns
`recommendedAction: "abort"`. The agent does **not** sign what it couldn't verify.
- **`open`:** the same situations degrade to `recommendedAction: "review"`. Even
open mode never returns `"sign"` on a failed check — a human or policy decides.
- Non-financial reads (token/chain/interface) always degrade to `review`.

## 🔐 Privacy & telemetry

The plugin **never transmits your private key, prompts, secrets or transaction
content** anywhere. The key is used locally to sign x402 payments and EIP-712
messages only.

Anonymous, opt-out telemetry (`TERENO_TELEMETRY=off` to disable) sends a strict
allowlist to help improve the network: plugin version, a **hashed** wallet
(`sha256`, never the address), network, check type, whether the call completed and
was paid, its USD cost, cache-hit, a repeat flag, and an integration-error flag.
Nothing else. See [`SECURITY.md`](./SECURITY.md).

---

## 🌱 How it stays cheap — the cooperative layer (advanced)

Tereno is a **shared-cache coordination layer**, not just an API. The first agent
to pay for a given piece of verified work *seeds* it for the whole network; every
later agent that reuses that answer pays less, and the seeder earns a small,
non-transferable credit that discounts its own future checks.

The game theory: safety is a public good with a private cost. By making the first
computation earn from every reuse, the network turns *"I paid to check this
contract"* into *"I lowered the price of checking it for everyone, and my own
checks got cheaper."* More agents ⇒ deeper cache ⇒ cheaper, faster verdicts ⇒
more agents.

Advanced actions expose this loop — you never need them to use the security
checks above:

| Action | Cost | What it does |
|---|---:|---|
| `TERENO_BOUNTIES` | free | See the work the network will pay to have seeded next |
| `TERENO_SEED` | free/$0.001 | Seed a bounty (publish a signed fingerprint, or be first payer) |
| `TERENO_STANDING` | free | The agent's audited track record and earned credits |
| `TERENO_REPORT_OUTCOME` | free | Attach a signed outcome to a settled verdict |

> The honest fine print: rewards are **non-transferable credits**, capped per
> artifact — they fund your agent's safety budget, they are not yield. Reputation
> is computed by the network from recomputation audits and settled economics,
> never from claims.

Discovery, scoring, reputation, pricing, the global cache and cooperation logic
live in the **closed Tereno backend**. This plugin and its SDK
([`tereno-client`](https://www.npmjs.com/package/tereno-client)) are the public,
open interface to it.

## 🤝 Support & community

- 💬 **Questions / setup help** → [Tereno Discord](https://discord.gg/YsgGSRBxn)
- 💬 **Questions / setup** → [Tereno Discord](https://discord.gg/YsgGSRBxn)
- 🐛 **Bugs** → [issues](https://github.com/RobMartello/plugin-tereno/issues) · ⚠️ never paste private keys or `.env`
- 🔒 **Vulnerabilities** → [report privately](https://github.com/RobMartello/plugin-tereno/security/advisories/new) · [SECURITY.md](SECURITY.md)
- 🗣️ **Ideas & show-and-tell** → [Discussions](https://github.com/RobMartello/plugin-tereno/discussions)

## 🔗 Links

[Live catalog](https://www.tereno.xyz/api/v1/capabilities) ·
[OpenAPI](https://www.tereno.xyz/openapi.yaml) ·
[Pricing & reuse economics](https://www.tereno.xyz/pricing) ·
[tereno-client SDK](https://www.npmjs.com/package/tereno-client) ·
[Open bounties](https://www.tereno.xyz/api/v1/bounties)

---

<div align="center">

**Built on [Base](https://base.org) · Paid with [x402](https://www.x402.org) · Made for agents, by agents' humans**
**[tereno.xyz](https://www.tereno.xyz)** · Verdicts before signatures, for agents on Base.

</div>
Loading
Loading