@wzrd_sol/solana-agent-plugin 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,177 +0,0 @@
1
- /**
2
- * Action: wzrd_deposit
3
- *
4
- * Deposit USDC into a WZRD attention market → mint vLOFI tokens.
5
- * Requires: Keypair with USDC balance + SOL for tx fees.
6
- *
7
- * The agent picks a market_id (from leaderboard), specifies USDC amount,
8
- * and the handler builds + signs + sends the deposit transaction.
9
- */
10
- import { ComputeBudgetProgram, TransactionMessage, VersionedTransaction, } from '@solana/web3.js';
11
- import { z } from 'zod';
12
- import { formatUsdc, getWalletPublicKey } from '../runtime.js';
13
- const USDC_MINT = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v';
14
- const CONFIRM_TIMEOUT_MS = 60_000;
15
- export const depositSchema = z.object({
16
- market_id: z.number().int().min(1),
17
- amount_usdc: z.number().positive().max(100),
18
- priority_fee: z.number().int().positive().optional(),
19
- });
20
- export async function depositHandler(agent, input) {
21
- const { market_id, amount_usdc, priority_fee = 50_000 } = input;
22
- const connection = agent.connection;
23
- const payer = getWalletPublicKey(agent);
24
- const amountNative = BigInt(Math.round(amount_usdc * 1_000_000));
25
- const t0 = Date.now();
26
- const sdk = await loadSdk();
27
- const { createDepositMarketIx, fetchMarketVault, fetchOnChainPosition, fetchTokenBalance, getAta, TOKEN_PROGRAM_ID, } = sdk;
28
- const vault = await fetchMarketVault(connection, market_id);
29
- if (!vault) {
30
- return {
31
- success: false,
32
- text: `Market ${market_id} is listed but does not have an on-chain vault yet. ` +
33
- 'Pick a market with an initialized vault before depositing.',
34
- data: { market_id, reason: 'missing_vault' },
35
- };
36
- }
37
- const existing = await fetchOnChainPosition(connection, payer, market_id);
38
- if (existing && existing.depositedAmount > 0n && !existing.settled) {
39
- return {
40
- success: false,
41
- text: `Position already exists in market ${market_id} ` +
42
- `(${formatUsdc(existing.depositedAmount)} USDC deposited). Cannot double-deposit.`,
43
- data: { market_id, deposited_amount: existing.depositedAmount.toString() },
44
- };
45
- }
46
- const usdcAta = getAta(payer, vault.depositMint, TOKEN_PROGRAM_ID);
47
- const usdcBalance = await fetchTokenBalance(connection, usdcAta);
48
- if (usdcBalance < amountNative) {
49
- return {
50
- success: false,
51
- text: `Insufficient USDC: have ${formatUsdc(usdcBalance)}, need ${amount_usdc.toFixed(4)}`,
52
- data: {
53
- market_id,
54
- required_native: amountNative.toString(),
55
- balance_native: usdcBalance.toString(),
56
- },
57
- };
58
- }
59
- const solBalance = await connection.getBalance(payer);
60
- if (solBalance < 10_000) {
61
- return {
62
- success: false,
63
- text: `Insufficient SOL for tx fees: ${solBalance} lamports`,
64
- data: { market_id, sol_balance_lamports: solBalance },
65
- };
66
- }
67
- let ixs;
68
- try {
69
- ixs = await createDepositMarketIx(connection, payer, market_id, amountNative);
70
- }
71
- catch (error) {
72
- const message = error instanceof Error ? error.message : String(error);
73
- if (message.includes('MarketVault not found')) {
74
- return {
75
- success: false,
76
- text: `Market ${market_id} does not have a live vault yet. ` +
77
- 'Choose a depositable market and retry.',
78
- data: { market_id, reason: 'missing_vault' },
79
- };
80
- }
81
- throw error;
82
- }
83
- ixs.unshift(ComputeBudgetProgram.setComputeUnitLimit({ units: 300_000 }), ComputeBudgetProgram.setComputeUnitPrice({ microLamports: priority_fee }));
84
- const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
85
- const message = new TransactionMessage({
86
- payerKey: payer,
87
- recentBlockhash: blockhash,
88
- instructions: ixs,
89
- }).compileToV0Message();
90
- const tx = new VersionedTransaction(message);
91
- const signedTx = await agent.wallet.signTransaction(tx);
92
- const sim = await connection.simulateTransaction(signedTx);
93
- if (sim.value.err) {
94
- return {
95
- success: false,
96
- text: `Simulation failed: ${JSON.stringify(sim.value.err)}`,
97
- data: { market_id, logs: sim.value.logs?.slice(-5) ?? [] },
98
- };
99
- }
100
- const { signature } = await agent.wallet.signAndSendTransaction(tx, {
101
- skipPreflight: true,
102
- maxRetries: 3,
103
- });
104
- const confirmed = connection.confirmTransaction({ signature, blockhash, lastValidBlockHeight }, 'confirmed');
105
- const timeout = new Promise((_, reject) => setTimeout(() => reject(new Error(`Timeout after ${CONFIRM_TIMEOUT_MS}ms`)), CONFIRM_TIMEOUT_MS));
106
- try {
107
- await Promise.race([confirmed, timeout]);
108
- }
109
- catch (error) {
110
- return {
111
- success: true,
112
- text: `Deposit transaction sent for Market #${market_id}, but confirmation timed out. ` +
113
- `Tx: ${signature}`,
114
- data: {
115
- signature,
116
- market_id,
117
- amount_usdc,
118
- timed_out: true,
119
- explorer: `https://solscan.io/tx/${signature}`,
120
- },
121
- };
122
- }
123
- const elapsed = Date.now() - t0;
124
- return {
125
- success: true,
126
- text: `Deposited ${amount_usdc.toFixed(4)} USDC into Market #${market_id}. ` +
127
- `Tx: ${signature.slice(0, 16)}... (${elapsed}ms, ${sim.value.unitsConsumed} CU)`,
128
- data: {
129
- signature,
130
- market_id,
131
- amount_usdc,
132
- cu_used: sim.value.unitsConsumed,
133
- elapsed_ms: elapsed,
134
- explorer: `https://solscan.io/tx/${signature}`,
135
- },
136
- };
137
- }
138
- async function loadSdk() {
139
- try {
140
- return await import('@wzrd_sol/sdk');
141
- }
142
- catch (error) {
143
- const fallbackUrl = new URL('../../../../sdk/dist/index.js', import.meta.url);
144
- try {
145
- return (await import(fallbackUrl.href));
146
- }
147
- catch {
148
- throw error;
149
- }
150
- }
151
- }
152
- export const DEPOSIT_ACTION = {
153
- name: 'wzrd_deposit',
154
- similes: ['wzrd_invest', 'deposit_usdc', 'buy_attention', 'enter_market'],
155
- description: 'Deposit USDC into a WZRD attention market to mint vLOFI tokens. ' +
156
- 'vLOFI represents your position in the market. As the underlying AI model ' +
157
- 'gains attention (downloads, stars), your multiplier increases and you earn ' +
158
- 'more CCM on each merkle root publication. ' +
159
- 'Requires: market_id (from leaderboard) and amount_usdc (e.g., 0.01). ' +
160
- 'The deposit is atomic — USDC is transferred and vLOFI is minted in one transaction.',
161
- examples: [
162
- [
163
- {
164
- input: { market_id: 10, amount_usdc: 0.01 },
165
- output: {
166
- success: true,
167
- market_id: 10,
168
- amount_usdc: 0.01,
169
- signature: 'X7FG...',
170
- },
171
- explanation: 'Deposit 0.01 USDC into a known vaulted market and mint vLOFI.',
172
- },
173
- ],
174
- ],
175
- schema: depositSchema,
176
- handler: async (agent, input) => depositHandler(agent, depositSchema.parse(input)),
177
- };
@@ -1,20 +0,0 @@
1
- /**
2
- * Action: wzrd_leaderboard
3
- *
4
- * Fetch the WZRD attention market leaderboard — ranked by velocity EMA.
5
- * No auth required. Permissionless read.
6
- */
7
- import { z } from 'zod';
8
- import type { Action, SolanaAgentKit } from 'solana-agent-kit';
9
- export declare const leaderboardSchema: z.ZodObject<{
10
- limit: z.ZodOptional<z.ZodNumber>;
11
- platform: z.ZodOptional<z.ZodString>;
12
- }, "strip", z.ZodTypeAny, {
13
- limit?: number | undefined;
14
- platform?: string | undefined;
15
- }, {
16
- limit?: number | undefined;
17
- platform?: string | undefined;
18
- }>;
19
- export declare function leaderboardHandler(agent: SolanaAgentKit, input: z.infer<typeof leaderboardSchema>): Promise<Record<string, unknown>>;
20
- export declare const LEADERBOARD_ACTION: Action;
@@ -1,47 +0,0 @@
1
- /**
2
- * Action: wzrd_leaderboard
3
- *
4
- * Fetch the WZRD attention market leaderboard — ranked by velocity EMA.
5
- * No auth required. Permissionless read.
6
- */
7
- import { z } from 'zod';
8
- import { formatVelocity, getLeaderboardData } from '../runtime.js';
9
- export const leaderboardSchema = z.object({
10
- limit: z.number().int().min(1).max(50).optional(),
11
- platform: z.string().min(1).optional(),
12
- });
13
- export async function leaderboardHandler(agent, input) {
14
- const data = await getLeaderboardData(agent, input);
15
- const lines = data.markets.map((m, i) => `${i + 1}. ${m.metric} — ${formatVelocity(m.velocity_ema)} velocity ` +
16
- `(${m.platform}) | ${m.multiplier_bps / 10000}x multiplier | ` +
17
- `${m.position_count} positions | market_id=${m.market_id}`);
18
- return {
19
- success: true,
20
- text: `WZRD Leaderboard (${data.markets.length} markets, ` +
21
- `root_seq=${data.root.root_seq}):\n${lines.join('\n')}`,
22
- data,
23
- };
24
- }
25
- export const LEADERBOARD_ACTION = {
26
- name: 'wzrd_leaderboard',
27
- similes: ['wzrd_markets', 'wzrd_trending', 'attention_markets', 'top_models'],
28
- description: 'Fetch the WZRD attention market leaderboard. Shows AI models and open-source ' +
29
- 'projects ranked by real-time velocity (download/star momentum). Returns market IDs, ' +
30
- 'velocity EMA, multiplier, TVL, and platform (huggingface/github). ' +
31
- 'Use this to find the highest-attention markets before depositing.',
32
- examples: [
33
- [
34
- {
35
- input: { limit: 3 },
36
- output: {
37
- success: true,
38
- root_seq: 1549,
39
- markets: ['#16 Qwen 3.5 35B', '#14 Qwen 3.5 9B', '#10 Qwen 2.5 72B'],
40
- },
41
- explanation: 'Fetch the top three WZRD markets without requiring auth.',
42
- },
43
- ],
44
- ],
45
- schema: leaderboardSchema,
46
- handler: async (agent, input) => leaderboardHandler(agent, leaderboardSchema.parse(input)),
47
- };
@@ -1,11 +0,0 @@
1
- /**
2
- * Action: wzrd_portfolio
3
- *
4
- * Fetch the agent's WZRD portfolio — positions, USDC deposited, vLOFI held, CCM earned.
5
- * Requires auth (Ed25519 agent session).
6
- */
7
- import { z } from 'zod';
8
- import type { Action, SolanaAgentKit } from 'solana-agent-kit';
9
- export declare const portfolioSchema: z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>;
10
- export declare function portfolioHandler(agent: SolanaAgentKit, _input: z.infer<typeof portfolioSchema>): Promise<Record<string, unknown>>;
11
- export declare const PORTFOLIO_ACTION: Action;
@@ -1,48 +0,0 @@
1
- /**
2
- * Action: wzrd_portfolio
3
- *
4
- * Fetch the agent's WZRD portfolio — positions, USDC deposited, vLOFI held, CCM earned.
5
- * Requires auth (Ed25519 agent session).
6
- */
7
- import { z } from 'zod';
8
- import { formatCcm, formatUsdc, getPortfolioData } from '../runtime.js';
9
- export const portfolioSchema = z.object({});
10
- export async function portfolioHandler(agent, _input) {
11
- const portfolio = await getPortfolioData(agent);
12
- const open = portfolio.positions.filter((p) => !p.is_settled);
13
- const lines = open.map((p) => `• Market #${p.market_id} (${p.metric}): ` +
14
- `${formatUsdc(p.usdc_deposited)} USDC, ` +
15
- `${(p.multiplier_bps / 10_000).toFixed(1)}x multiplier` +
16
- (p.is_settled ? ' [settled]' : ''));
17
- return {
18
- success: true,
19
- text: `Your WZRD portfolio (${open.length} open positions):\n` +
20
- `${lines.length ? lines.join('\n') : '(no positions)'}\n` +
21
- `Total: ${formatUsdc(portfolio.total_deposited_usdc)} USDC deposited, ` +
22
- `${formatCcm(portfolio.total_ccm_earned)} CCM earned`,
23
- data: portfolio,
24
- };
25
- }
26
- export const PORTFOLIO_ACTION = {
27
- name: 'wzrd_portfolio',
28
- similes: ['wzrd_positions', 'wzrd_balance', 'wzrd_holdings', 'my_positions'],
29
- description: 'Fetch your WZRD portfolio — all open positions across attention markets. ' +
30
- 'Shows USDC deposited, vLOFI minted, multiplier, and settlement status per market. ' +
31
- 'Use this to check your exposure before depositing more or claiming CCM.',
32
- examples: [
33
- [
34
- {
35
- input: {},
36
- output: {
37
- success: true,
38
- open_positions: 2,
39
- total_deposited_usdc: 20000,
40
- total_ccm_earned: 0,
41
- },
42
- explanation: 'Fetch the authenticated agent portfolio and summarize open exposure.',
43
- },
44
- ],
45
- ],
46
- schema: portfolioSchema,
47
- handler: async (agent, input) => portfolioHandler(agent, portfolioSchema.parse(input)),
48
- };
@@ -1,37 +0,0 @@
1
- /**
2
- * Action: wzrd_velocity
3
- *
4
- * Analyze attention velocity across markets — classify signal strength.
5
- * No auth required. Pure analytics over leaderboard data.
6
- *
7
- * Signal tiers:
8
- * BREAKOUT — top 10% velocity (p90+)
9
- * MOMENTUM — p70-90
10
- * EMERGING — new market (<300 snapshots) with above-median velocity
11
- * STABLE — p40-70
12
- * COOLING — p20-40
13
- * WEAK — below p20
14
- */
15
- import { z } from 'zod';
16
- import type { Action, SolanaAgentKit } from 'solana-agent-kit';
17
- import { type SignalTier } from '../runtime.js';
18
- export interface MarketSignal {
19
- market_id: number;
20
- metric: string;
21
- platform: string;
22
- velocity_ema: number;
23
- signal: SignalTier;
24
- percentile: number;
25
- }
26
- export declare const velocitySchema: z.ZodObject<{
27
- platform: z.ZodOptional<z.ZodString>;
28
- min_signal: z.ZodOptional<z.ZodEnum<["BREAKOUT", "MOMENTUM", "EMERGING", "STABLE", "COOLING", "WEAK"]>>;
29
- }, "strip", z.ZodTypeAny, {
30
- platform?: string | undefined;
31
- min_signal?: "BREAKOUT" | "MOMENTUM" | "EMERGING" | "STABLE" | "COOLING" | "WEAK" | undefined;
32
- }, {
33
- platform?: string | undefined;
34
- min_signal?: "BREAKOUT" | "MOMENTUM" | "EMERGING" | "STABLE" | "COOLING" | "WEAK" | undefined;
35
- }>;
36
- export declare function velocityHandler(agent: SolanaAgentKit, input: z.infer<typeof velocitySchema>): Promise<Record<string, unknown>>;
37
- export declare const VELOCITY_ACTION: Action;
@@ -1,110 +0,0 @@
1
- /**
2
- * Action: wzrd_velocity
3
- *
4
- * Analyze attention velocity across markets — classify signal strength.
5
- * No auth required. Pure analytics over leaderboard data.
6
- *
7
- * Signal tiers:
8
- * BREAKOUT — top 10% velocity (p90+)
9
- * MOMENTUM — p70-90
10
- * EMERGING — new market (<300 snapshots) with above-median velocity
11
- * STABLE — p40-70
12
- * COOLING — p20-40
13
- * WEAK — below p20
14
- */
15
- import { z } from 'zod';
16
- import { formatVelocity, getLeaderboardData } from '../runtime.js';
17
- export const velocitySchema = z.object({
18
- platform: z.string().min(1).optional(),
19
- min_signal: z
20
- .enum(['BREAKOUT', 'MOMENTUM', 'EMERGING', 'STABLE', 'COOLING', 'WEAK'])
21
- .optional(),
22
- });
23
- export async function velocityHandler(agent, input) {
24
- const data = await getLeaderboardData(agent, { limit: 50, platform: input.platform });
25
- const markets = data.markets;
26
- if (markets.length === 0) {
27
- return { success: true, text: 'No markets found.', data: { signals: [] } };
28
- }
29
- const sorted = [...markets].sort((a, b) => a.velocity_ema - b.velocity_ema);
30
- const signals = markets.map((m) => {
31
- const rank = sorted.findIndex((s) => s.market_id === m.market_id);
32
- const percentile = ((rank + 1) / sorted.length) * 100;
33
- const signal = classify(m, percentile);
34
- return {
35
- market_id: m.market_id,
36
- metric: m.metric,
37
- platform: m.platform,
38
- velocity_ema: m.velocity_ema,
39
- signal,
40
- percentile: Math.round(percentile),
41
- };
42
- });
43
- const tierOrder = ['BREAKOUT', 'MOMENTUM', 'EMERGING', 'STABLE', 'COOLING', 'WEAK'];
44
- const minIdx = input.min_signal
45
- ? tierOrder.indexOf(input.min_signal)
46
- : tierOrder.length;
47
- const filtered = minIdx < tierOrder.length
48
- ? signals.filter((s) => tierOrder.indexOf(s.signal) <= minIdx)
49
- : signals;
50
- const grouped = new Map();
51
- for (const s of filtered) {
52
- const arr = grouped.get(s.signal) ?? [];
53
- arr.push(s);
54
- grouped.set(s.signal, arr);
55
- }
56
- const lines = [];
57
- for (const tier of tierOrder) {
58
- const group = grouped.get(tier);
59
- if (!group?.length)
60
- continue;
61
- lines.push(`${tier}:`);
62
- for (const s of group) {
63
- lines.push(` • ${s.metric} (${formatVelocity(s.velocity_ema)} velocity, p${s.percentile}) [${s.platform}]`);
64
- }
65
- }
66
- const medianIdx = Math.floor(sorted.length / 2);
67
- const medianVelocity = sorted[medianIdx]?.velocity_ema ?? 0;
68
- return {
69
- success: true,
70
- text: `Velocity analysis (${markets.length} markets, ` +
71
- `median ${formatVelocity(medianVelocity)}):\n${lines.join('\n')}`,
72
- data: { signals: filtered, median_velocity: medianVelocity },
73
- };
74
- }
75
- export const VELOCITY_ACTION = {
76
- name: 'wzrd_velocity',
77
- similes: ['wzrd_signal', 'attention_signal', 'market_analysis', 'velocity_check'],
78
- description: 'Analyze attention velocity across WZRD markets. Classifies each market into ' +
79
- 'signal tiers: BREAKOUT (top 10%), MOMENTUM (70-90th percentile), EMERGING ' +
80
- '(new + above median), STABLE, COOLING, WEAK. ' +
81
- 'Use this to find the best deposit opportunities — BREAKOUT and MOMENTUM ' +
82
- 'markets have the strongest attention momentum.',
83
- examples: [
84
- [
85
- {
86
- input: { min_signal: 'MOMENTUM' },
87
- output: {
88
- success: true,
89
- signals: ['BREAKOUT: Qwen 3.5 35B', 'MOMENTUM: Qwen 2.5 72B'],
90
- },
91
- explanation: 'Classify the current leaderboard into signal tiers for deposit decisions.',
92
- },
93
- ],
94
- ],
95
- schema: velocitySchema,
96
- handler: async (agent, input) => velocityHandler(agent, velocitySchema.parse(input)),
97
- };
98
- function classify(m, percentile) {
99
- if (percentile >= 90)
100
- return 'BREAKOUT';
101
- if (percentile >= 70)
102
- return 'MOMENTUM';
103
- if (m.snapshot_count < 300 && percentile >= 50)
104
- return 'EMERGING';
105
- if (percentile >= 40)
106
- return 'STABLE';
107
- if (percentile >= 20)
108
- return 'COOLING';
109
- return 'WEAK';
110
- }
@@ -1,79 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * WZRD "Hello World" — prove an agent can interact in 30 seconds.
4
- *
5
- * What this does:
6
- * 1. Read the leaderboard (no auth, 2 seconds)
7
- * 2. Authenticate with Ed25519 (no browser, 1 second)
8
- * 3. Check portfolio (what do I hold?)
9
- * 4. Check claimable CCM (any rewards ready?)
10
- *
11
- * Usage:
12
- * SOLANA_RPC_URL=https://... WZRD_KEYPAIR_PATH=~/.config/solana/id.json node hello-wzrd.mjs
13
- *
14
- * Or generate a fresh keypair:
15
- * solana-keygen new -o /tmp/agent.json --no-bip39-passphrase
16
- * SOLANA_RPC_URL=https://... WZRD_KEYPAIR_PATH=/tmp/agent.json node hello-wzrd.mjs
17
- */
18
-
19
- import { readFileSync } from 'node:fs';
20
- import { Keypair } from '@solana/web3.js';
21
- import { WzrdClient } from '@wzrd_sol/solana-agent-plugin';
22
-
23
- const KEYPAIR_PATH = process.env.WZRD_KEYPAIR_PATH;
24
- if (!KEYPAIR_PATH) {
25
- console.log('Usage: WZRD_KEYPAIR_PATH=/path/to/keypair.json node hello-wzrd.mjs');
26
- console.log('Generate one: solana-keygen new -o /tmp/agent.json --no-bip39-passphrase');
27
- process.exit(1);
28
- }
29
-
30
- const raw = readFileSync(KEYPAIR_PATH, 'utf8');
31
- const wallet = Keypair.fromSecretKey(Uint8Array.from(JSON.parse(raw)));
32
- const client = new WzrdClient(wallet);
33
-
34
- console.log(`\n=== WZRD Hello World ===`);
35
- console.log(`Agent: ${wallet.publicKey.toBase58()}\n`);
36
-
37
- // 1. Leaderboard (public, no auth)
38
- console.log('→ Fetching leaderboard...');
39
- const board = await client.getLeaderboard(5);
40
- console.log(` ${board.markets.length} markets, root_seq=${board.root.root_seq}`);
41
- for (const m of board.markets) {
42
- const vel = m.velocity_ema >= 1000 ? `${(m.velocity_ema/1000).toFixed(0)}K` : m.velocity_ema.toFixed(0);
43
- console.log(` #${m.market_id} ${m.metric} — ${vel} velocity (${m.platform})`);
44
- }
45
-
46
- // 2. Portfolio (auth required — triggers challenge/verify automatically)
47
- console.log('\n→ Authenticating + fetching portfolio...');
48
- try {
49
- const portfolio = await client.getPortfolio();
50
- const open = portfolio.positions.filter(p => !p.is_settled);
51
- console.log(` ${open.length} open positions, ${(portfolio.total_deposited_usdc / 1e6).toFixed(4)} USDC total`);
52
- for (const p of open) {
53
- console.log(` • Market #${p.market_id}: ${(p.usdc_deposited / 1e6).toFixed(4)} USDC, ${(p.multiplier_bps / 10000).toFixed(1)}x`);
54
- }
55
- } catch (e) {
56
- console.log(` No portfolio yet (${e instanceof Error ? e.message : e})`);
57
- console.log(' → First-time agent? You got auto-funded 0.003 SOL + 1000 CCM signup bonus!');
58
- }
59
-
60
- // 3. Claims check
61
- console.log('\n→ Checking claimable CCM...');
62
- try {
63
- const claims = await client.getClaims();
64
- const claimable = claims.cumulative_total - claims.claimed_total;
65
- console.log(` Cumulative: ${claims.cumulative_total}, Claimed: ${claims.claimed_total}`);
66
- console.log(` Claimable now: ${claimable > 0 ? claimable : 'none'}`);
67
- if (claimable > 0) {
68
- console.log(' → Run with --claim to harvest via gasless relay');
69
- }
70
- } catch (e) {
71
- console.log(` No claims data yet (${e instanceof Error ? e.message : e})`);
72
- }
73
-
74
- console.log('\n=== Done ===');
75
- console.log('Next steps:');
76
- console.log(' 1. Fund your wallet with USDC (even 0.01 is enough)');
77
- console.log(' 2. Use wzrd_deposit to enter a market');
78
- console.log(' 3. Wait ~10 min for scoring cycle');
79
- console.log(' 4. Use wzrd_claim to harvest CCM (gasless — no SOL needed)');
@@ -1,101 +0,0 @@
1
- /**
2
- * Action: wzrd_claim
3
- *
4
- * Claim accrued CCM tokens via the gasless relay.
5
- * Server pays tx fees — agent doesn't need SOL to claim.
6
- *
7
- * Flow: check claimable amount → relay claim → receive CCM.
8
- */
9
-
10
- import { z } from 'zod';
11
- import type { Action, SolanaAgentKit } from 'solana-agent-kit';
12
-
13
- import { formatCcm, getClaimsData, getClientForAgent } from '../runtime.js';
14
-
15
- export const claimSchema = z.object({
16
- execute: z.boolean().optional(),
17
- });
18
-
19
- export async function claimHandler(
20
- agent: SolanaAgentKit,
21
- input: z.infer<typeof claimSchema>,
22
- ): Promise<Record<string, unknown>> {
23
- const claims = await getClaimsData(agent);
24
- const claimable = claims.cumulative_total - claims.claimed_total;
25
-
26
- if (claimable <= 0) {
27
- return {
28
- success: true,
29
- text:
30
- `No CCM to claim. Cumulative: ${claims.cumulative_total}, ` +
31
- `already claimed: ${claims.claimed_total}. ` +
32
- `Deposit into markets and wait for the next scoring cycle.`,
33
- data: claims,
34
- };
35
- }
36
-
37
- if (input.execute === false) {
38
- return {
39
- success: true,
40
- text:
41
- `${formatCcm(claimable)} CCM claimable ` +
42
- `(${formatCcm(claims.cumulative_total)} cumulative, ` +
43
- `${formatCcm(claims.claimed_total)} claimed). ` +
44
- `Root seq: ${claims.root_seq}. Call with execute=true to claim.`,
45
- data: claims,
46
- };
47
- }
48
-
49
- const result = await getClientForAgent(agent).claimRelay();
50
-
51
- if (result.status === 'already_claimed') {
52
- return {
53
- success: true,
54
- text:
55
- `Already claimed through root ${result.root_seq}. ` +
56
- `Claimed total: ${formatCcm(result.claimed_total ?? claims.claimed_total)} CCM.`,
57
- data: result,
58
- };
59
- }
60
-
61
- return {
62
- success: true,
63
- text:
64
- `Claimed CCM via gasless relay. ` +
65
- `Cumulative total: ${formatCcm(result.cumulative_total)}. ` +
66
- `Root seq: ${result.root_seq}. ` +
67
- `Tx: ${result.tx_sig?.slice(0, 16)}...`,
68
- data: {
69
- ...result,
70
- claimable_before: claimable,
71
- explorer: result.tx_sig ? `https://solscan.io/tx/${result.tx_sig}` : null,
72
- },
73
- };
74
- }
75
-
76
- export const CLAIM_ACTION: Action = {
77
- name: 'wzrd_claim',
78
- similes: ['wzrd_harvest', 'claim_ccm', 'redeem_rewards', 'collect_yield'],
79
- description:
80
- 'Claim accrued CCM tokens from your WZRD positions. Uses the gasless relay — ' +
81
- 'the server pays transaction fees, so you don\'t need SOL to claim. ' +
82
- 'CCM accrues based on your velocity multiplier and is distributed via ' +
83
- 'merkle proofs published on-chain every ~10 minutes. ' +
84
- 'Call this periodically to harvest your earned CCM.',
85
-
86
- examples: [
87
- [
88
- {
89
- input: { execute: false },
90
- output: {
91
- success: true,
92
- claimable: 100000,
93
- cumulative_total: 250000,
94
- },
95
- explanation: 'Check how much CCM is available before triggering a relay claim.',
96
- },
97
- ],
98
- ],
99
- schema: claimSchema,
100
- handler: async (agent, input) => claimHandler(agent, claimSchema.parse(input)),
101
- };