# Fortunissimo Agent Skill

**For autonomous agents, bots, and LLM tool-users.** This file teaches an agent everything it needs to list tokens, trade on bonding curves or the AMM, open perps, lend, launch new tokens, and stream real-time prices on Fortunissimo — using its own Solana wallet, from Node.js, with no browser.

- **Protocol:** Solana DEX + token launchpad (bonding curves → AMM graduation, spot AMM, perps, lending, YAGG yield vault).
- **Default network:** `solana-devnet` (live, real transactions, mock USDT).
- **Mainnet:** `solana-mainnet` (coming soon — use devnet until then; every example below works unchanged once mainnet is live, with just the RPC URL and USDT mint swapped).
- **API origin:** `https://api.fortunissimo.com`
- **WebSocket origin:** `wss://api.fortunissimo.com/ws`
- **TypeScript SDK:** `@fortunissimo/sdk` (source: `packages/sdk/` in the repo)
- **Machine-readable contract:** [`/openapi.json`](https://api.fortunissimo.com/openapi.json)
- **Capability manifest:** [`/.well-known/ai-agent.json`](https://fortunissimo.com/.well-known/ai-agent.json)

If you can read this file and you have a funded Solana keypair, you can be trading within a few minutes.

---

## 1. Prerequisites

You need:

1. A Solana `Keypair` (file format: `Uint8Array` of 64 bytes, serialized as JSON array — what `solana-keygen new -o keypair.json` produces).
2. An RPC URL — devnet default: `https://api.devnet.solana.com`.
3. The USDT mint address for the current network (see table below).
4. Node.js 20+ and `@fortunissimo/sdk`.

| Network | Status | RPC URL | USDT mint |
|---|---|---|---|
| `solana-devnet` | **live** | `https://api.devnet.solana.com` | `Fu6JfC7EkWmoh3dmG8UoX2F7UgEykE4cAHAu6XEs1q1r` (mock) |
| `solana-mainnet` | coming soon — use devnet | `https://api.mainnet-beta.solana.com` | `Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB` |

Fund a devnet wallet with `solana airdrop 2 <pubkey> --url devnet` and mock USDT via `POST /faucet` (or the faucet UI on the web app).

```bash
pnpm add @fortunissimo/sdk @solana/web3.js @coral-xyz/anchor
```

---

## 2. Authentication

Most Fortunissimo functionality does **not** need auth:

- All REST `GET` endpoints (tokens, trades, funding, pool, lending, perp, portfolio, analytics, yields, …) are public.
- Every on-chain action authorizes itself via the wallet signature on the Solana transaction — the backend never sees your key and never signs.

Auth (JWT) is only required for two referral endpoints: `POST /referral/generate`, `POST /referral/attribute`.

### Wallet sign-in handshake

1. `POST /auth/nonce` with `{ "wallet_address": "<base58 pubkey>" }` → `{ nonce, message }`.
2. Sign `message` (exactly `"Sign this to authenticate with Fortunissimo: <nonce>"`) with the wallet's ed25519 secret key. Base64-encode the 64-byte signature.
3. `POST /auth/verify` with `{ wallet_address, signature, nonce }` → `{ token, profile }`.
4. Send `Authorization: Bearer <token>` on subsequent authenticated requests.

### curl

```bash
WALLET=$(solana address)
NONCE=$(curl -s -X POST https://api.fortunissimo.com/auth/nonce \
  -H 'content-type: application/json' \
  -d "{\"wallet_address\":\"$WALLET\"}")
# extract nonce + message, sign message with your keypair, base64 the sig, then:
curl -X POST https://api.fortunissimo.com/auth/verify \
  -H 'content-type: application/json' \
  -d "{\"wallet_address\":\"$WALLET\",\"signature\":\"<b64>\",\"nonce\":\"<nonce>\"}"
```

### TypeScript

See [`packages/sdk/examples/auth.ts`](https://github.com/idris67/fortunissimo/blob/main/packages/sdk/examples/auth.ts) for a 30-line working implementation using `tweetnacl`.

---

## 3. Reading state (REST)

All responses are JSON. All endpoints are `GET` unless noted.

### Tokens

| Path | Purpose |
|---|---|
| `/tokens` | List all live tokens with price + volume |
| `/tokens/:address` | Full metadata + current market snapshot |
| `/tokens/:address/candles` | OHLCV candles (query `?resolution=1m&from=&to=`) |
| `/tokens/:address/trades` | Recent on-chain trades |
| `/tokens/:address/funding` | Funding-rate history |
| `/tokens/:address/pool` | Spot AMM pool reserves |
| `/tokens/:address/perp` | Perp market state |
| `/tokens/:address/perp/trades` | Perp trades |
| `/tokens/:address/perp/candles` | Perp price candles |
| `/tokens/:address/perp/adl-rank` | Auto-deleveraging priority queue |
| `/tokens/:address/perp/adl-events` | ADL events history |
| `/tokens/:address/lending` | Lending pool state |
| `/tokens/:address/oracle` | Oracle price + TWAP |
| `/tokens/:address/insurance` | Token-specific insurance fund balance |
| `/tokens/:address/risk` | Current risk tier + limits |

### Yields, vault, portfolio

| Path | Purpose |
|---|---|
| `/yields` / `/yields/:token_mint` / `/yields/history/:token_mint` | APR feed |
| `/yagg/state` | YAGG vault NAV, mode, TVL |
| `/yagg/depositors/:wallet` | Your YAGG deposit position |
| `/yagg/series` | Historical NAV series |
| `/portfolio/:wallet` | Aggregate wallet portfolio |
| `/user/:address/positions` | Open positions (perp + lending) |
| `/funding/all` | Funding across every perp market |

### Social / creator

| Path | Purpose |
|---|---|
| `/creator/:address` | Creator dashboard (royalty earnings, launched tokens) |
| `/users/:address/profile` | Public profile |
| `/users/:address/stats` / `/badges` / `/followers` / `/following` | User metadata |
| `/feed/global` | Global activity feed |
| `/feed/following` | Your following feed (auth) |
| `/chat/:token_mint/messages` | Per-token chatroom |
| `/notifications` | Your notifications (auth) |

### Aggregate analytics

| Path | Purpose |
|---|---|
| `/analytics/overview` | Top-line TVL, volume, users |
| `/analytics/top-tokens` | Trending tokens |
| `/analytics/leaderboard` | Trader leaderboard |
| `/analytics/protocol-fees` | Protocol fee accrual |
| `/health` / `/health/deep` | Liveness + DB check |
| `/metrics` | Prometheus metrics |

The full contract (request params, response schemas) is in [`/openapi.json`](https://api.fortunissimo.com/openapi.json) and `docs/agents.md`.

---

## 4. Taking actions (SDK)

Every on-chain action is a method on `FortunissimoClient` that **builds** a `Transaction`. You sign and send. The backend is not in the loop.

```ts
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
import { BN } from '@coral-xyz/anchor';
import { FortunissimoClient, NodeWallet } from '@fortunissimo/sdk';

const keypair = Keypair.fromSecretKey(/* your secret */);
const connection = new Connection('https://api.devnet.solana.com', 'confirmed');
const client = new FortunissimoClient(connection, new NodeWallet(keypair));
```

### Create a token

```ts
const tokenMintKp = Keypair.generate();
const tx = await client.createToken(
  'My Token', 'MYT',
  /* metadataUriHash */ new Uint8Array(32),
  usdtMint, treasury, tokenMintKp.publicKey,
);
tx.partialSign(tokenMintKp); // mint keypair signs too
await client.sendAndConfirm(tx);
```

### Buy on the bonding curve

```ts
const tx = await client.buyOnCurve(
  tokenMint, usdtMint,
  new BN(1_000_000),              // 1 USDT (6 decimals)
  protocolTreasuryUsdtAta,        // fee recipient
);
await client.sendAndConfirm(tx);
```

### Sell on the bonding curve

```ts
const tx = await client.sellOnCurve(tokenMint, usdtMint, new BN(tokenAmount), protocolTreasuryUsdtAta);
```

### Swap on the AMM (post-graduation)

```ts
const tx = await client.swap(
  tokenMint, usdtMint,
  /* inputAmount */ new BN(1_000_000),
  /* minOutput (slippage floor) */ new BN(minOut),
  /* isTokenToUsdt */ false,
  protocolTreasuryUsdtAta, creatorRoyaltyUsdtAta,
);
```

### Open / close a perp

```ts
// side: 0 = long, 1 = short
const open = await client.openPosition(tokenMint, usdtMint, 0, new BN(marginUsdt), new BN(sizeUsdt));
const close = await client.closePosition(tokenMint, usdtMint);
```

### Lending: supply, borrow, repay

```ts
import { SupplyTier } from '@fortunissimo/sdk';
const supply = await client.deposit(tokenMint, usdtMint, new BN(amt), SupplyTier.Insured);
const withdraw = await client.withdraw(tokenMint, usdtMint, new BN(shares));
// Lower-level borrow/repay: see packages/sdk/src/instructions/lending-pool.ts
```

### YAGG yield vault

```ts
const deposit = await client.yaggDeposit(usdtMint, new BN(amt));
const redeem = await client.yaggRedeem(usdtMint, new BN(shares), /* nonce */ new BN(Date.now()));
```

### Claim creator royalty (for token creators)

```ts
const tx = await client.claimRoyalty(tokenMint, usdtMint);
```

### AMM migration (only once a curve graduates)

```ts
const tx = await client.migrateToAmm(tokenMint, usdtMint, treasury);
```

The full set is in [`packages/sdk/src/client.ts`](https://github.com/idris67/fortunissimo/blob/main/packages/sdk/src/client.ts) — treat it as the source of truth. The SDK also re-exports the lower-level instruction builders (`packages/sdk/src/instructions/*`) if you need finer control.

---

## 5. Real-time (WebSocket)

- URL: `wss://api.fortunissimo.com/ws`
- Wire format: JSON messages, `{"action":"subscribe","channel":"<channel>","address":"<base58>"}` to subscribe, `"unsubscribe"` to drop.
- **Max 20 subscriptions** per connection.
- Message size cap: **4096 bytes**.
- Heartbeat: server sends `{"action":"ping"}` every 30s; respond with `{"action":"pong"}`. If silent for 60s, the server drops you.

Channels:

| Channel | Emits when |
|---|---|
| `prices` | curve/AMM price updates for a token |
| `trades` | spot trades |
| `funding` | funding rate updates |
| `perp_trades` | perp fills |
| `perp_funding` | perp funding settlements |

See [`packages/sdk/examples/watch-prices.ts`](https://github.com/idris67/fortunissimo/blob/main/packages/sdk/examples/watch-prices.ts) for a runnable consumer.

---

## 6. Errors, rate limits, safety

- **Rate limit (anonymous):** 10 requests/second sustained, 50 burst, per IP (token bucket). Back off on HTTP `429`.
- **Rate limit (authenticated):** 20 rps sustained, 100 burst, keyed by wallet when you send `Authorization: Bearer <jwt>`. Your wallet bucket is independent of the anonymous IP bucket, so sharing a machine with other callers doesn't eat into your quota.
- **Error shape:** `{ "error": { "code": "string", "message": "string" } }` with a sensible HTTP status.
- **On-chain errors:** surface as rejected `sendAndConfirm` promises with the program log in `.message`. Custom error codes are defined in each Anchor program's `errors.rs`.
- **Simulate before sending** any non-trivial transaction. You have two options:
  - Hit `POST /simulate` on the Fortunissimo backend with `{ "transaction": "<base64>", "replace_blockhash": false }` — returns `{ success, logs, units_consumed, err }` using the backend's configured RPC, so you don't need to manage your own.
  - Or go direct to the RPC: `connection.simulateTransaction(tx)` from `@solana/web3.js`.
  - Either way catches missing ATAs, insufficient balance, and program errors without paying fees.
- **Slippage:** always pass a conservative `minOutput` to `swap` and check curve depth before a big buy — small bonding curves move a lot on 10 USDT trades.
- **Pool depth:** read `/tokens/:address/pool` or `client.getSpotPool(tokenMint)` before submitting a large swap.
- Mainnet has **real funds**. Run every strategy on devnet first. Mainnet defaults to the same RPC/API, only the USDT mint changes.

---

## 7. End-to-end example: launch + buy

```ts
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
import { BN } from '@coral-xyz/anchor';
import { FortunissimoClient, NodeWallet } from '@fortunissimo/sdk';

const connection = new Connection('https://api.devnet.solana.com', 'confirmed');
const creator = Keypair.fromSecretKey(/* secret */);
const client = new FortunissimoClient(connection, new NodeWallet(creator));

const usdtMint = new PublicKey('Fu6JfC7EkWmoh3dmG8UoX2F7UgEykE4cAHAu6XEs1q1r');
const treasury = new PublicKey(process.env.TREASURY!);
const treasuryUsdt = new PublicKey(process.env.TREASURY_USDT!);

// 1) Launch a new token.
const tokenMintKp = Keypair.generate();
const launchTx = await client.createToken(
  'Delightful Raccoon', 'DRAC',
  new Uint8Array(32), usdtMint, treasury, tokenMintKp.publicKey,
);
launchTx.partialSign(tokenMintKp);
console.log('launch tx:', await client.sendAndConfirm(launchTx));

// 2) Buy 5 USDT worth on the fresh bonding curve.
const buyTx = await client.buyOnCurve(
  tokenMintKp.publicKey, usdtMint, new BN(5_000_000), treasuryUsdt,
);
console.log('buy tx:', await client.sendAndConfirm(buyTx));

// 3) Read the resulting state.
const curve = await client.getCurveState(tokenMintKp.publicKey);
console.log('reserves:', curve?.virtualUsdtReserve.toString(), '/', curve?.virtualTokenReserve.toString());
```

---

## 8. Where to go next

- `/openapi.json` — machine-readable REST contract (OpenAPI 3.1)
- `/.well-known/ai-agent.json` — short capability manifest for automated crawlers
- [`packages/sdk/README.md`](https://github.com/idris67/fortunissimo/blob/main/packages/sdk/README.md) — install + full quickstart
- [`docs/agents.md`](https://github.com/idris67/fortunissimo/blob/main/docs/agents.md) — deep reference (every endpoint, every SDK method, every WS channel, devnet↔mainnet delta)
- [`packages/sdk/src/client.ts`](https://github.com/idris67/fortunissimo/blob/main/packages/sdk/src/client.ts) — authoritative SDK surface
- GitHub: [`idris67/fortunissimo`](https://github.com/idris67/fortunissimo)
