Skip to content
Open
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
217 changes: 164 additions & 53 deletions showcase/pip-conversational-trader/skills/pip-trade-agent/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,95 +1,206 @@
---
name: pip-trade-agent
description: Hand a trade to PipTrade Agent in plain english, read the live quote, respect the token safety gate, and confirm a self-custody settlement that is private by default. Buyer-side, approval-gated, keeps the user in custody.
version: 1.0.0
description: Quote and execute a token trade through PipTrade Agent in plain english, across every listed chain, with a token safety gate and self-custody signing that is private by default. Use when a buyer agent needs a live cross-chain quote, a honeypot check before trading, or a settlement that does not link the user wallet to the destination. Public read endpoints need no auth; anything that moves value is signed by the user.
license: MIT
compatibility: Requires network access to https://piptradedex.xyz. Read endpoints and dry quotes are public. Executing a trade requires the user signed in at /app with their own wallet.
metadata:
version: "1.1.0"
builder: PipTradeDex
---

# Pip Trade Agent

Use this skill when a buyer agent wants to execute a token trade for a user through PipTrade Agent instead of building routing, quoting, and token safety from scratch. The skill is buyer-side, approval-gated, and custody-preserving. It never signs for the user and never invents an intent the user did not state.
Hand a trade to PipTrade Agent instead of building routing, quoting, and token safety yourself. Buyer-side, approval-gated, custody-preserving. It never signs for the user and never invents an intent the user did not state.

## When To Use

- A user asked, in words, to buy, sell, swap, or send a token.
- The buyer agent wants a live quote with price impact, minimum received, and route before committing.
- The trade should be gated by a token safety read (GO, CAUTION, or BLOCK).
- You want a live quote with amount out, minimum received, and settlement time before committing.
- You want a token safety read (GO, CAUTION, BLOCK) before trading an unknown token.
- The user must keep their keys and sign in their own wallet.
- Settlement should be private by default, breaking the on-chain link between the wallet and the destination.
- The settlement should not publicly link the user wallet to the destination.

## When NOT To Use

- Do not use it to sign or move funds without the user in the loop.
- Do not use it to invent a token, a side, or an amount the user did not state.
- Do not use it to send funds to an address the user did not give.
- Do not use it to skip the token safety read on a token about to be traded.
- Do not use it to claim privacy stronger than unlinkability by construction, which is not a zero knowledge proof.
- To sign or move funds without the user in the loop.
- To invent a token, a side, or an amount the user did not state.
- To send funds to an address the user did not give.
- To skip the safety read on a token about to be traded.
- To claim privacy stronger than unlinkability by construction, which is not a zero knowledge proof.

## Inputs
## Quick Reference

Base URL `https://piptradedex.xyz`.

- One trade intent in plain english, for example buy 10 usd of PIP, or swap 2 usdc on base to sol and send it over.
- The chain context if the user named one, otherwise let Pip infer from the token.
- A per-trade spend cap and an allowlist of tokens the agent may act on.
- The user approval state for anything that signs.
| Endpoint | Method | Auth | Returns |
| --- | --- | --- | --- |
| `/api/tokens` | GET | none | tradeable registry: `assetId`, `symbol`, `blockchain`, `decimals`, `price` |
| `/api/prices` | GET | none | live prices by symbol |
| `/api/markets` | GET | none | market list with 24h change and volume |
| `/api/pip/stats` | GET | none | $PIP token stats |
| `/api/rh/tokens` | GET | none | the listed Robinhood Chain universe |
| `/api/rh/sellcheck` | GET | none | can this token be sold, the honeypot gate |
| `/api/quote` | POST | none for a dry quote | live cross-chain quote |
| `/api/app2/safety` | POST | signed-in user | full GoPlus rating, verdict and checks |
| `/api/holdings`, `/api/wallets` | GET | signed-in user | balances for that wallet |
| `/api/rh/quote`, `/api/rh/swap`, `/api/rh/withdraw` | POST | signed-in user | Robinhood Chain trade and private send |

## Outputs
A GET against a POST-only route returns the landing page HTML with status 200, not a 405. Always POST where the table says POST, and parse the body rather than trusting the status.

- A parsed intent, side, token, and amount, echoed back for confirmation.
- A live quote, price impact, minimum received, route, and estimated time.
- A token safety verdict, GO, CAUTION, or BLOCK.
- A settled transaction reference on success, delivered to the user own wallet.
## Getting A Quote

## Approval Gates
`POST /api/quote` is the unified intent quote. One instruction moves value across every listed chain and token. A cross-chain move such as `swap 2 usdc on base to sol and send it over` is a single intent, not a bridge plus a swap.

The user, or the operator acting for the user, must approve:
**A dry quote needs no session.** Any agent can price a route before involving the user. Only execution requires the user signed in.

1. the parsed intent before any quote is treated as final,
2. any token that returns CAUTION,
3. any trade above the per-trade spend cap,
4. the signature itself, which always happens in the user own wallet.
Request:

| Field | Required | Notes |
| --- | --- | --- |
| `originAsset` | yes | `assetId` from `/api/tokens` |
| `destinationAsset` | yes | `assetId` from `/api/tokens` |
| `amount` | yes | **base units, not human units** (see below) |
| `recipient` | no | address on the DESTINATION chain. Omitted on a dry quote, a chain-correct placeholder is used |
| `refundTo` | no | address on the ORIGIN chain |
| `private` | no | settlement is already private whenever the private rail is available |
| `dry` | no | defaults `true`. `dry:false` requests a real deposit address and requires a session |

### 🚨 Amount is in base units

Multiply by the token `decimals` from `/api/tokens`. This is the single most common integration error, and it fails as an unhelpful `busy` rather than a clear message.

- 5 USDC on Base, `decimals: 6`, send `"5000000"`.
- 1 ETH, `decimals: 18`, send `"1000000000000000000"`.
- Sending `"5"` for USDC quotes 0.000005 USDC and the route fails.

### Worked example

```bash
curl -s -X POST https://piptradedex.xyz/api/quote \
-H 'content-type: application/json' \
-d '{
"originAsset": "nep141:base-0x833589fcd6edb6e08f4c7c32d4f71b54bda02913.omft.near",
"destinationAsset": "nep141:base.omft.near",
"amount": "5000000"
}'
```

Response:

```json
{
"ok": true,
"private": true,
"amountInFormatted": "5.0",
"amountOutFormatted": "0.002602097377635916",
"amountInUsd": "4.998260000000",
"amountOutUsd": "4.980986842218",
"minAmountOut": "2576076403859556",
"timeEstimate": 37,
"depositAddress": null,
"depositMemo": null
}
```

`minAmountOut` is in base units of the destination token. `timeEstimate` is seconds. `depositAddress` is null on a dry quote and populated only on a real, signed-in execution.

### Errors

Every failure returns HTTP 200 with `ok:false` unless noted. Read `error`, never the status alone.

| `error` | Meaning | What to do |
| --- | --- | --- |
| `missing_fields` (400) | an `originAsset`, `destinationAsset` or `amount` is absent | fix the request |
| `amount_range` | outside the route minimum or maximum | read the `min` object, which carries `amount`, `usd`, `sym` and `chain`, then re-quote |
| `no_liquidity` | no route at that size right now | try a smaller size or a different pair |
| `unsupported` | that pair is not routable | pick another pair from `/api/tokens` |
| `busy` | unclassified router failure, often a wrong `amount` unit | check base units first, then retry |
| `private_activating` | the private rail is warming up | retry shortly |
| `not_logged_in` (401) | the endpoint needs the user session | hand back to the user at `/app` |

If any approval is missing, stop and hand control back to the user. A BLOCK verdict is a hard stop, never trade through it.
## The Safety Gate

## Workflow
The gate has two levels. Use the public one before you quote, and the full one when the user is signed in.

1. Read the user words and map them to a single intent, side, token, amount, and destination if a send. If anything is unclear, ask one short question, never guess.
2. Confirm the token is on the agent allowlist and the amount is within the per-trade cap.
3. Request a quote and a token safety read. Show price impact, minimum received, route, estimated time, and the GO CAUTION BLOCK verdict.
**Public, no auth.** `GET /api/rh/sellcheck?address=<0x...>&chain=base|robinhood` answers the question that matters most on an unknown token: can it be sold again.

🚨 **Always send `chain`.** It defaults to a Robinhood Chain sell simulation, so a healthy Base token comes back `sellable:null, reason:"unverifiable"` and you would gate a good trade on a false CAUTION. The same response also carries a wrong `decimals` in that state, so take decimals from `/api/tokens`, never from this endpoint.

```bash
curl -s "https://piptradedex.xyz/api/rh/sellcheck?address=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913&chain=base"
# {"ok":true,"address":"0x833589...","chain":"base","sellable":true,"venue":"routed"}
```

| Field | Meaning |
| --- | --- |
| `sellable: true` | a sell simulated successfully, treat as GO on this check alone |
| `sellable: false` | the sell failed, treat as BLOCK, this is the honeypot signal |
| `sellable: null` with `reason` | unverifiable, for example `unverifiable` on a non-token address, treat as CAUTION and get user approval |
| `venue` | where it would route, for example `bonding` for $PIP on the Virtuals curve |

A malformed address returns `400 {"ok":false,"error":"bad_address"}`. Never map that to BLOCK; it is your bug, not the token's.

**Full scan, session required.** `POST /api/app2/safety` with `{"chain":"base","address":"0x..."}` returns a GoPlus-backed rating with per-check detail (honeypot, tax, ownership). Returns `401 not_logged_in` without a session and is rate limited to 30 calls a minute. Use `{"rh":true,"sym":"PIP"}` for a Robinhood Chain token and `{"native":true,"sym":"ETH","chain":"base"}` for a native asset, which is always safe by construction.

Map both into one verdict: BLOCK on `sellable:false` or a failing scan, CAUTION on `null`/unverifiable, GO only when a check actually passed. Absence of evidence is CAUTION, never GO.

## Executing A Trade

The agent shapes the intent. The user signs. Nothing here signs on the agent behalf.

1. Map the user words to one intent: side, token, amount, and destination if a send. If anything is unclear, ask one short question, never guess.
2. Confirm the token is on your allowlist and the amount is within your per-trade cap.
3. Quote it, and read the token safety verdict.
4. On BLOCK, stop. On CAUTION, get explicit user approval. On GO, proceed.
5. Present the full quote to the user and let the user sign in their own wallet. The agent never signs.
6. On success, return the settled transaction reference. Settlement is private by default, so the destination is not directly linked to the source.
5. Present the full quote and let the user sign in their own wallet at `/app`.
6. On success, return the settled transaction reference.

### Approval gates

The user, or the operator acting for the user, must approve:

## Interface
1. the parsed intent before any quote is treated as final,
2. any token that returns CAUTION,
3. any trade above the per-trade spend cap,
4. the signature itself, which always happens in the user own wallet.

PipTrade Agent runs at https://piptradedex.xyz/app for chat and https://piptradedex.xyz/rh for the terminal. On the terminal the same intent maps to a market, limit, TWAP, or stop order, run by a keeper, on any listed Robinhood Chain token, with the same safety gate and self-custody signing. $PIP is a Virtuals token traded through the Virtuals bonding curve.
If any approval is missing, stop and hand control back. A BLOCK verdict is a hard stop, never trade through it.

## Endpoints
## Surfaces

Read only, public, callable by any agent today at https://piptradedex.xyz:
- `/app` is the chat surface. Plain english intents, a GO CAUTION BLOCK safety read before any trade, deposit from another chain by intent, price alerts, and a referral link.
- `/rh` is the Robinhood Chain terminal on the same wallet. Market trades on any listed token, with the same safety gate and self-custody signing. Limit, TWAP and stop orders are being rebuilt and are not available today, so do not promise them to a user.

- GET /api/prices, live token prices.
- GET /api/markets, market list with 24h change and volume.
- GET /api/tokens, the tradeable token registry with decimals and logos.
- GET /api/pip/stats, $PIP token stats.
$PIP is a Virtuals token traded through the Virtuals bonding curve.

At /app, intent based, signed in with the user own wallet. The agent shapes the intent, the user signs, and nothing here signs on the agent behalf:
There is no anonymous trade endpoint. Reads and dry quotes are open to any agent; anything that moves value requires the user signed in with their own keys, which is the point.

- POST /api/quote, the unified intent quote and swap. One instruction moves value across every listed chain and token, private by default, so the on-chain link between the wallet and the destination is broken. A cross-chain move like swap 2 usdc on base to sol and send it over is a single intent.
- GET /api/wallets and GET /api/holdings, balances for the signed-in wallet.
- The /app chat drives the rest on the same signed-in wallet, a GO CAUTION BLOCK token safety read before any trade, deposit from another chain by intent, price alerts in plain english, and a referral link.
## Runnable Example

At /rh, the Robinhood Chain terminal on the same wallet:
[`pip-quote.mjs`](https://piptradedex.xyz/agent/pip-quote.mjs) does the whole read-only flow in one file: resolve two `assetId`s from `/api/tokens`, convert a human amount to base units using the real `decimals`, run the public sell check, then quote. No auth, no signing, nothing moves.

- GET /api/rh/tokens, the listed token universe.
- POST /api/rh/quote and POST /api/rh/swap, a market trade on any listed token with a safety badge.
- Market, limit, TWAP, and stop orders, run by a keeper.
- POST /api/rh/withdraw, a private send.
```bash
curl -sO https://piptradedex.xyz/agent/pip-quote.mjs
node pip-quote.mjs 5 USDC base ETH base
```

There is no anonymous trade endpoint. Trading always requires the user signed in with their own keys, which is the point. An agent uses the public reads freely and shapes the signed-in intents through the user at /app.
Read it before writing your own client. It encodes the exact base-units conversion and the error branching this API requires, both of which are easy to get wrong.

## Safety Invariants

- The user keeps their keys. The agent and the service never hold them.
- Every trade shows a full quote before it signs.
- Every token is safety checked, and a high risk token is gated.
- Privacy is unlinkability by construction, stated plainly, never oversold.
- Privacy is unlinkability by construction, stated plainly, never oversold. It breaks the public link between the source wallet and the destination. It is not a zero knowledge proof.

## Common Mistakes

| Mistake | Symptom | Fix |
| --- | --- | --- |
| Human amount instead of base units | `busy` on a valid pair | multiply by `decimals` from `/api/tokens` |
| GET on a POST route | HTML body, status 200 | POST, and parse the body |
| Trusting the HTTP status | a failed quote read as success | branch on `ok` and `error` |
| Hardcoding an `assetId` | breaks when a listing changes | resolve from `/api/tokens` every run |
| Omitting `chain` on the sell check | false CAUTION on a healthy token, wrong `decimals` | always pass `chain`, take decimals from `/api/tokens` |
| Promising limit, TWAP or stop orders | user hits a coming-soon screen | market orders today, the rest are being rebuilt |
| Calling privacy zero knowledge | overclaim a reviewer will catch | say unlinkability by construction |
Loading