@wzrd_sol/solana-agent-plugin 0.1.0 → 0.1.2
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.
- package/README.md +43 -1
- package/dist/actions/claim.d.ts +11 -30
- package/dist/actions/claim.js +57 -60
- package/dist/actions/deposit.d.ts +15 -46
- package/dist/actions/deposit.js +148 -105
- package/dist/actions/index.d.ts +1 -0
- package/dist/actions/leaderboard.d.ts +14 -21
- package/dist/actions/leaderboard.js +26 -42
- package/dist/actions/portfolio.d.ts +5 -18
- package/dist/actions/portfolio.js +28 -28
- package/dist/actions/velocity.d.ts +15 -33
- package/dist/actions/velocity.js +67 -75
- package/dist/client.d.ts +18 -5
- package/dist/client.js +25 -8
- package/dist/index.d.ts +18 -273
- package/dist/index.js +53 -12
- package/dist/runtime.d.ts +16 -0
- package/dist/runtime.js +33 -0
- package/examples/hello-wzrd.mjs +24 -9
- package/package.json +14 -5
- package/src/actions/claim.ts +74 -71
- package/src/actions/deposit.ts +189 -157
- package/src/actions/index.ts +1 -0
- package/src/actions/leaderboard.ts +40 -57
- package/src/actions/portfolio.ts +41 -39
- package/src/actions/velocity.ts +84 -91
- package/src/client.ts +42 -11
- package/src/index.ts +70 -12
- package/src/runtime.ts +60 -0
- package/type-smoke-Cvxu.ts +8 -0
|
@@ -4,6 +4,24 @@
|
|
|
4
4
|
* Fetch the WZRD attention market leaderboard — ranked by velocity EMA.
|
|
5
5
|
* No auth required. Permissionless read.
|
|
6
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
|
+
}
|
|
7
25
|
export const LEADERBOARD_ACTION = {
|
|
8
26
|
name: 'wzrd_leaderboard',
|
|
9
27
|
similes: ['wzrd_markets', 'wzrd_trending', 'attention_markets', 'top_models'],
|
|
@@ -14,50 +32,16 @@ export const LEADERBOARD_ACTION = {
|
|
|
14
32
|
examples: [
|
|
15
33
|
[
|
|
16
34
|
{
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
content: {
|
|
23
|
-
text: 'Here are the top WZRD markets by velocity:\n' +
|
|
24
|
-
'1. Qwen 3.5 35B — 804K velocity (HuggingFace)\n' +
|
|
25
|
-
'2. Qwen 3.5 9B — 769K velocity (HuggingFace)\n' +
|
|
26
|
-
'3. Ollama — 104K velocity (GitHub)',
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
],
|
|
30
|
-
[
|
|
31
|
-
{
|
|
32
|
-
user: 'user',
|
|
33
|
-
content: { text: 'What HuggingFace models are trending?' },
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
user: 'assistant',
|
|
37
|
-
content: {
|
|
38
|
-
text: 'Top HuggingFace models by attention velocity: ...',
|
|
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'],
|
|
39
40
|
},
|
|
41
|
+
explanation: 'Fetch the top three WZRD markets without requiring auth.',
|
|
40
42
|
},
|
|
41
43
|
],
|
|
42
44
|
],
|
|
43
|
-
|
|
44
|
-
handler: async (
|
|
45
|
-
const data = await client.getLeaderboard(params.limit ?? 10, params.platform);
|
|
46
|
-
const lines = data.markets.map((m, i) => `${i + 1}. ${m.metric} — ${formatVelocity(m.velocity_ema)} velocity ` +
|
|
47
|
-
`(${m.platform}) | ${m.multiplier_bps / 10000}x multiplier | ` +
|
|
48
|
-
`${m.position_count} positions | market_id=${m.market_id}`);
|
|
49
|
-
return {
|
|
50
|
-
success: true,
|
|
51
|
-
text: `WZRD Leaderboard (${data.markets.length} markets, ` +
|
|
52
|
-
`root_seq=${data.root.root_seq}):\n${lines.join('\n')}`,
|
|
53
|
-
data,
|
|
54
|
-
};
|
|
55
|
-
},
|
|
45
|
+
schema: leaderboardSchema,
|
|
46
|
+
handler: async (agent, input) => leaderboardHandler(agent, leaderboardSchema.parse(input)),
|
|
56
47
|
};
|
|
57
|
-
function formatVelocity(v) {
|
|
58
|
-
if (v >= 1_000_000)
|
|
59
|
-
return `${(v / 1_000_000).toFixed(1)}M`;
|
|
60
|
-
if (v >= 1_000)
|
|
61
|
-
return `${(v / 1_000).toFixed(0)}K`;
|
|
62
|
-
return v.toFixed(0);
|
|
63
|
-
}
|
|
@@ -4,21 +4,8 @@
|
|
|
4
4
|
* Fetch the agent's WZRD portfolio — positions, USDC deposited, vLOFI held, CCM earned.
|
|
5
5
|
* Requires auth (Ed25519 agent session).
|
|
6
6
|
*/
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
examples: {
|
|
13
|
-
user: string;
|
|
14
|
-
content: {
|
|
15
|
-
text: string;
|
|
16
|
-
};
|
|
17
|
-
}[][];
|
|
18
|
-
validate: () => Promise<boolean>;
|
|
19
|
-
handler: (client: WzrdClient) => Promise<{
|
|
20
|
-
success: boolean;
|
|
21
|
-
text: string;
|
|
22
|
-
data: import("../client.js").WzrdPortfolio;
|
|
23
|
-
}>;
|
|
24
|
-
};
|
|
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;
|
|
@@ -4,6 +4,25 @@
|
|
|
4
4
|
* Fetch the agent's WZRD portfolio — positions, USDC deposited, vLOFI held, CCM earned.
|
|
5
5
|
* Requires auth (Ed25519 agent session).
|
|
6
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
|
+
}
|
|
7
26
|
export const PORTFOLIO_ACTION = {
|
|
8
27
|
name: 'wzrd_portfolio',
|
|
9
28
|
similes: ['wzrd_positions', 'wzrd_balance', 'wzrd_holdings', 'my_positions'],
|
|
@@ -13,36 +32,17 @@ export const PORTFOLIO_ACTION = {
|
|
|
13
32
|
examples: [
|
|
14
33
|
[
|
|
15
34
|
{
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
text: 'Your WZRD portfolio:\n' +
|
|
23
|
-
'• Market #10 (Qwen 2.5 72B): 0.01 USDC, 5.0x multiplier\n' +
|
|
24
|
-
'• Market #8 (Ollama): 0.01 USDC, 5.0x multiplier\n' +
|
|
25
|
-
'Total: 0.02 USDC deposited, 0 CCM earned',
|
|
35
|
+
input: {},
|
|
36
|
+
output: {
|
|
37
|
+
success: true,
|
|
38
|
+
open_positions: 2,
|
|
39
|
+
total_deposited_usdc: 20000,
|
|
40
|
+
total_ccm_earned: 0,
|
|
26
41
|
},
|
|
42
|
+
explanation: 'Fetch the authenticated agent portfolio and summarize open exposure.',
|
|
27
43
|
},
|
|
28
44
|
],
|
|
29
45
|
],
|
|
30
|
-
|
|
31
|
-
handler: async (
|
|
32
|
-
const portfolio = await client.getPortfolio();
|
|
33
|
-
const open = portfolio.positions.filter((p) => !p.is_settled);
|
|
34
|
-
const lines = open.map((p) => `• Market #${p.market_id} (${p.metric}): ` +
|
|
35
|
-
`${(p.usdc_deposited / 1_000_000).toFixed(4)} USDC, ` +
|
|
36
|
-
`${(p.multiplier_bps / 10_000).toFixed(1)}x multiplier` +
|
|
37
|
-
(p.is_settled ? ' [settled]' : ''));
|
|
38
|
-
const totalUsdc = portfolio.total_deposited_usdc / 1_000_000;
|
|
39
|
-
const totalCcm = portfolio.total_ccm_earned / 1_000_000;
|
|
40
|
-
return {
|
|
41
|
-
success: true,
|
|
42
|
-
text: `Your WZRD portfolio (${open.length} open positions):\n` +
|
|
43
|
-
`${lines.length ? lines.join('\n') : '(no positions)'}\n` +
|
|
44
|
-
`Total: ${totalUsdc.toFixed(4)} USDC deposited, ${totalCcm.toFixed(4)} CCM earned`,
|
|
45
|
-
data: portfolio,
|
|
46
|
-
};
|
|
47
|
-
},
|
|
46
|
+
schema: portfolioSchema,
|
|
47
|
+
handler: async (agent, input) => portfolioHandler(agent, portfolioSchema.parse(input)),
|
|
48
48
|
};
|
|
@@ -12,8 +12,9 @@
|
|
|
12
12
|
* COOLING — p20-40
|
|
13
13
|
* WEAK — below p20
|
|
14
14
|
*/
|
|
15
|
-
import
|
|
16
|
-
type
|
|
15
|
+
import { z } from 'zod';
|
|
16
|
+
import type { Action, SolanaAgentKit } from 'solana-agent-kit';
|
|
17
|
+
import { type SignalTier } from '../runtime.js';
|
|
17
18
|
export interface MarketSignal {
|
|
18
19
|
market_id: number;
|
|
19
20
|
metric: string;
|
|
@@ -22,34 +23,15 @@ export interface MarketSignal {
|
|
|
22
23
|
signal: SignalTier;
|
|
23
24
|
percentile: number;
|
|
24
25
|
}
|
|
25
|
-
export declare const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
platform?: string;
|
|
38
|
-
min_signal?: SignalTier;
|
|
39
|
-
}) => Promise<{
|
|
40
|
-
success: boolean;
|
|
41
|
-
text: string;
|
|
42
|
-
data: {
|
|
43
|
-
signals: never[];
|
|
44
|
-
median_velocity?: undefined;
|
|
45
|
-
};
|
|
46
|
-
} | {
|
|
47
|
-
success: boolean;
|
|
48
|
-
text: string;
|
|
49
|
-
data: {
|
|
50
|
-
signals: MarketSignal[];
|
|
51
|
-
median_velocity: number;
|
|
52
|
-
};
|
|
53
|
-
}>;
|
|
54
|
-
};
|
|
55
|
-
export {};
|
|
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;
|
package/dist/actions/velocity.js
CHANGED
|
@@ -12,6 +12,66 @@
|
|
|
12
12
|
* COOLING — p20-40
|
|
13
13
|
* WEAK — below p20
|
|
14
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
|
+
}
|
|
15
75
|
export const VELOCITY_ACTION = {
|
|
16
76
|
name: 'wzrd_velocity',
|
|
17
77
|
similes: ['wzrd_signal', 'attention_signal', 'market_analysis', 'velocity_check'],
|
|
@@ -23,78 +83,17 @@ export const VELOCITY_ACTION = {
|
|
|
23
83
|
examples: [
|
|
24
84
|
[
|
|
25
85
|
{
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
user: 'assistant',
|
|
31
|
-
content: {
|
|
32
|
-
text: 'BREAKOUT signals:\n' +
|
|
33
|
-
'• Qwen 3.5 35B (804K velocity, p95)\n' +
|
|
34
|
-
'MOMENTUM signals:\n' +
|
|
35
|
-
'• Qwen 3.5 9B (769K velocity, p85)\n' +
|
|
36
|
-
'• Qwen 2.5 72B (378K velocity, p72)',
|
|
86
|
+
input: { min_signal: 'MOMENTUM' },
|
|
87
|
+
output: {
|
|
88
|
+
success: true,
|
|
89
|
+
signals: ['BREAKOUT: Qwen 3.5 35B', 'MOMENTUM: Qwen 2.5 72B'],
|
|
37
90
|
},
|
|
91
|
+
explanation: 'Classify the current leaderboard into signal tiers for deposit decisions.',
|
|
38
92
|
},
|
|
39
93
|
],
|
|
40
94
|
],
|
|
41
|
-
|
|
42
|
-
handler: async (
|
|
43
|
-
const data = await client.getLeaderboard(50, params.platform);
|
|
44
|
-
const markets = data.markets;
|
|
45
|
-
if (markets.length === 0) {
|
|
46
|
-
return { success: true, text: 'No markets found.', data: { signals: [] } };
|
|
47
|
-
}
|
|
48
|
-
// Sort by velocity for percentile calculation
|
|
49
|
-
const sorted = [...markets].sort((a, b) => a.velocity_ema - b.velocity_ema);
|
|
50
|
-
const signals = markets.map((m) => {
|
|
51
|
-
const rank = sorted.findIndex((s) => s.market_id === m.market_id);
|
|
52
|
-
const percentile = ((rank + 1) / sorted.length) * 100;
|
|
53
|
-
const signal = classify(m, percentile);
|
|
54
|
-
return {
|
|
55
|
-
market_id: m.market_id,
|
|
56
|
-
metric: m.metric,
|
|
57
|
-
platform: m.platform,
|
|
58
|
-
velocity_ema: m.velocity_ema,
|
|
59
|
-
signal,
|
|
60
|
-
percentile: Math.round(percentile),
|
|
61
|
-
};
|
|
62
|
-
});
|
|
63
|
-
// Filter by minimum signal if requested
|
|
64
|
-
const tierOrder = ['BREAKOUT', 'MOMENTUM', 'EMERGING', 'STABLE', 'COOLING', 'WEAK'];
|
|
65
|
-
const minIdx = params.min_signal
|
|
66
|
-
? tierOrder.indexOf(params.min_signal)
|
|
67
|
-
: tierOrder.length;
|
|
68
|
-
const filtered = minIdx < tierOrder.length
|
|
69
|
-
? signals.filter((s) => tierOrder.indexOf(s.signal) <= minIdx)
|
|
70
|
-
: signals;
|
|
71
|
-
// Group by signal tier
|
|
72
|
-
const grouped = new Map();
|
|
73
|
-
for (const s of filtered) {
|
|
74
|
-
const arr = grouped.get(s.signal) ?? [];
|
|
75
|
-
arr.push(s);
|
|
76
|
-
grouped.set(s.signal, arr);
|
|
77
|
-
}
|
|
78
|
-
const lines = [];
|
|
79
|
-
for (const tier of tierOrder) {
|
|
80
|
-
const group = grouped.get(tier);
|
|
81
|
-
if (!group?.length)
|
|
82
|
-
continue;
|
|
83
|
-
lines.push(`${tier}:`);
|
|
84
|
-
for (const s of group) {
|
|
85
|
-
lines.push(` • ${s.metric} (${formatVelocity(s.velocity_ema)} velocity, p${s.percentile}) [${s.platform}]`);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
// Median velocity
|
|
89
|
-
const medianIdx = Math.floor(sorted.length / 2);
|
|
90
|
-
const medianVelocity = sorted[medianIdx]?.velocity_ema ?? 0;
|
|
91
|
-
return {
|
|
92
|
-
success: true,
|
|
93
|
-
text: `Velocity analysis (${markets.length} markets, ` +
|
|
94
|
-
`median ${formatVelocity(medianVelocity)}):\n${lines.join('\n')}`,
|
|
95
|
-
data: { signals: filtered, median_velocity: medianVelocity },
|
|
96
|
-
};
|
|
97
|
-
},
|
|
95
|
+
schema: velocitySchema,
|
|
96
|
+
handler: async (agent, input) => velocityHandler(agent, velocitySchema.parse(input)),
|
|
98
97
|
};
|
|
99
98
|
function classify(m, percentile) {
|
|
100
99
|
if (percentile >= 90)
|
|
@@ -109,10 +108,3 @@ function classify(m, percentile) {
|
|
|
109
108
|
return 'COOLING';
|
|
110
109
|
return 'WEAK';
|
|
111
110
|
}
|
|
112
|
-
function formatVelocity(v) {
|
|
113
|
-
if (v >= 1_000_000)
|
|
114
|
-
return `${(v / 1_000_000).toFixed(1)}M`;
|
|
115
|
-
if (v >= 1_000)
|
|
116
|
-
return `${(v / 1_000).toFixed(0)}K`;
|
|
117
|
-
return v.toFixed(0);
|
|
118
|
-
}
|
package/dist/client.d.ts
CHANGED
|
@@ -2,9 +2,16 @@
|
|
|
2
2
|
* WZRD API client — handles agent auth (Ed25519 challenge/verify),
|
|
3
3
|
* token caching, and all REST calls.
|
|
4
4
|
*
|
|
5
|
-
* Standalone: no framework dependency. Works with
|
|
5
|
+
* Standalone: no framework dependency. Works with a Keypair or any wallet
|
|
6
|
+
* implementation that supports `publicKey` + `signMessage()`.
|
|
6
7
|
*/
|
|
7
|
-
import { Keypair } from '@solana/web3.js';
|
|
8
|
+
import { Keypair, type PublicKey } from '@solana/web3.js';
|
|
9
|
+
export declare const DEFAULT_API_URL = "https://api.twzrd.xyz";
|
|
10
|
+
export interface WzrdSigner {
|
|
11
|
+
publicKey: PublicKey;
|
|
12
|
+
signMessage?: (message: Uint8Array) => Promise<Uint8Array>;
|
|
13
|
+
secretKey?: Uint8Array;
|
|
14
|
+
}
|
|
8
15
|
export interface WzrdMarket {
|
|
9
16
|
market_id: number;
|
|
10
17
|
channel_id: string;
|
|
@@ -18,6 +25,7 @@ export interface WzrdMarket {
|
|
|
18
25
|
status: string;
|
|
19
26
|
snapshot_count: number;
|
|
20
27
|
last_scored_at: string;
|
|
28
|
+
depositable: boolean;
|
|
21
29
|
}
|
|
22
30
|
export interface WzrdLeaderboard {
|
|
23
31
|
markets: WzrdMarket[];
|
|
@@ -57,15 +65,20 @@ export interface WzrdClaim {
|
|
|
57
65
|
export interface WzrdRelayResult {
|
|
58
66
|
root_seq: number;
|
|
59
67
|
cumulative_total: number;
|
|
60
|
-
|
|
68
|
+
claimed_total?: number;
|
|
69
|
+
tx_sig?: string;
|
|
70
|
+
status?: 'already_claimed';
|
|
61
71
|
}
|
|
62
72
|
export declare class WzrdClient {
|
|
63
|
-
private readonly
|
|
73
|
+
private readonly signer;
|
|
64
74
|
private readonly apiUrl;
|
|
65
75
|
private token;
|
|
66
76
|
private tokenExpiresAt;
|
|
67
|
-
constructor(
|
|
77
|
+
constructor(signer: WzrdSigner | Keypair, apiUrl?: string);
|
|
68
78
|
get pubkey(): string;
|
|
79
|
+
private isWalletSigner;
|
|
80
|
+
private hasSecretKey;
|
|
81
|
+
private signAuthMessage;
|
|
69
82
|
private authenticate;
|
|
70
83
|
private getToken;
|
|
71
84
|
private authedFetch;
|
package/dist/client.js
CHANGED
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
* WZRD API client — handles agent auth (Ed25519 challenge/verify),
|
|
3
3
|
* token caching, and all REST calls.
|
|
4
4
|
*
|
|
5
|
-
* Standalone: no framework dependency. Works with
|
|
5
|
+
* Standalone: no framework dependency. Works with a Keypair or any wallet
|
|
6
|
+
* implementation that supports `publicKey` + `signMessage()`.
|
|
6
7
|
*/
|
|
7
|
-
|
|
8
|
+
import { Keypair } from '@solana/web3.js';
|
|
9
|
+
export const DEFAULT_API_URL = 'https://api.twzrd.xyz';
|
|
8
10
|
const TOKEN_REFRESH_MARGIN_MS = 5 * 60 * 1000;
|
|
9
11
|
// ── Base58 encoder (zero-dependency) ────────────────────
|
|
10
12
|
const B58 = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
|
@@ -34,16 +36,32 @@ function toBase58(bytes) {
|
|
|
34
36
|
}
|
|
35
37
|
// ── Client ──────────────────────────────────────────────
|
|
36
38
|
export class WzrdClient {
|
|
37
|
-
|
|
39
|
+
signer;
|
|
38
40
|
apiUrl;
|
|
39
41
|
token = null;
|
|
40
42
|
tokenExpiresAt = 0;
|
|
41
|
-
constructor(
|
|
42
|
-
this.
|
|
43
|
+
constructor(signer, apiUrl = DEFAULT_API_URL) {
|
|
44
|
+
this.signer = signer;
|
|
43
45
|
this.apiUrl = apiUrl;
|
|
44
46
|
}
|
|
45
47
|
get pubkey() {
|
|
46
|
-
return this.
|
|
48
|
+
return this.signer.publicKey.toBase58();
|
|
49
|
+
}
|
|
50
|
+
isWalletSigner(signer) {
|
|
51
|
+
return typeof signer.signMessage === 'function';
|
|
52
|
+
}
|
|
53
|
+
hasSecretKey(signer) {
|
|
54
|
+
return signer instanceof Keypair || signer.secretKey instanceof Uint8Array;
|
|
55
|
+
}
|
|
56
|
+
async signAuthMessage(message) {
|
|
57
|
+
if (this.isWalletSigner(this.signer)) {
|
|
58
|
+
return this.signer.signMessage(message);
|
|
59
|
+
}
|
|
60
|
+
if (this.hasSecretKey(this.signer)) {
|
|
61
|
+
const { default: nacl } = await import('tweetnacl');
|
|
62
|
+
return nacl.sign.detached(message, this.signer.secretKey);
|
|
63
|
+
}
|
|
64
|
+
throw new Error('WzrdClient requires a signer with signMessage() or an Ed25519 secretKey');
|
|
47
65
|
}
|
|
48
66
|
// ── Auth ────────────────────────────────────────────
|
|
49
67
|
async authenticate() {
|
|
@@ -54,8 +72,7 @@ export class WzrdClient {
|
|
|
54
72
|
const { nonce } = (await cr.json());
|
|
55
73
|
// 2. Sign with Ed25519
|
|
56
74
|
const message = `wzrd-agent-auth v1 | wallet:${this.pubkey} | nonce:${nonce}`;
|
|
57
|
-
const
|
|
58
|
-
const sig = nacl.sign.detached(new TextEncoder().encode(message), this.keypair.secretKey);
|
|
75
|
+
const sig = await this.signAuthMessage(new TextEncoder().encode(message));
|
|
59
76
|
// 3. Verify
|
|
60
77
|
const vr = await fetch(`${this.apiUrl}/v1/agent/verify`, {
|
|
61
78
|
method: 'POST',
|