@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
package/README.md
CHANGED
|
@@ -4,12 +4,37 @@ WZRD Liquid Attention Protocol plugin for autonomous Solana agents. Provides 5 a
|
|
|
4
4
|
|
|
5
5
|
Works standalone, with [Solana Agent Kit](https://github.com/sendAI/solana-agent-kit), or as a base for ElizaOS action wrappers.
|
|
6
6
|
|
|
7
|
+
## 30-Second Test
|
|
8
|
+
|
|
9
|
+
No Solana Agent Kit dependency is required for the first smoke test. The package is ESM-first, so use `type: "module"` and `import`.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
mkdir wzrd-agent && cd wzrd-agent
|
|
13
|
+
printf '{\"name\":\"wzrd-agent\",\"type\":\"module\",\"private\":true}\n' > package.json
|
|
14
|
+
npm install @wzrd_sol/solana-agent-plugin @solana/web3.js
|
|
15
|
+
curl -O https://raw.githubusercontent.com/twzrd-sol/wzrd-final/main/agents/solana-agent-kit-plugin/examples/hello-wzrd.mjs
|
|
16
|
+
solana-keygen new -o /tmp/agent.json --no-bip39-passphrase
|
|
17
|
+
WZRD_KEYPAIR_PATH=/tmp/agent.json node hello-wzrd.mjs
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
What you should see:
|
|
21
|
+
- top markets
|
|
22
|
+
- successful Ed25519 agent auth
|
|
23
|
+
- portfolio or signup-bonus path
|
|
24
|
+
- claimable CCM state
|
|
25
|
+
|
|
7
26
|
## Install
|
|
8
27
|
|
|
9
28
|
```bash
|
|
10
29
|
npm install @wzrd_sol/solana-agent-plugin
|
|
11
30
|
```
|
|
12
31
|
|
|
32
|
+
Install with Solana Agent Kit only when you are ready to execute through its action system:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm install @wzrd_sol/solana-agent-plugin solana-agent-kit
|
|
36
|
+
```
|
|
37
|
+
|
|
13
38
|
## Quick Start
|
|
14
39
|
|
|
15
40
|
```typescript
|
|
@@ -30,6 +55,18 @@ const claims = await client.getClaims();
|
|
|
30
55
|
const result = await client.claimRelay(); // gasless CCM claim
|
|
31
56
|
```
|
|
32
57
|
|
|
58
|
+
## Solana Agent Kit
|
|
59
|
+
|
|
60
|
+
The package works standalone or as a Solana Agent Kit plugin.
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { SolanaAgentKit } from 'solana-agent-kit';
|
|
64
|
+
import { WZRD_PLUGIN } from '@wzrd_sol/solana-agent-plugin';
|
|
65
|
+
|
|
66
|
+
const agent = new SolanaAgentKit(/* wallet + rpc + model config */);
|
|
67
|
+
agent.use(WZRD_PLUGIN);
|
|
68
|
+
```
|
|
69
|
+
|
|
33
70
|
## Actions
|
|
34
71
|
|
|
35
72
|
The plugin exports 5 actions that follow the Solana Agent Kit action interface:
|
|
@@ -38,7 +75,7 @@ The plugin exports 5 actions that follow the Solana Agent Kit action interface:
|
|
|
38
75
|
|--------|------|-------------|
|
|
39
76
|
| `LEADERBOARD_ACTION` | No | Fetch ranked attention markets |
|
|
40
77
|
| `VELOCITY_ACTION` | No | Classify signal strength (BREAKOUT / MOMENTUM / EMERGING / STABLE / COOLING / WEAK) |
|
|
41
|
-
| `PORTFOLIO_ACTION` | Yes | View positions
|
|
78
|
+
| `PORTFOLIO_ACTION` | Yes | View portfolio positions |
|
|
42
79
|
| `DEPOSIT_ACTION` | Yes | Deposit USDC into a market, receive vLOFI |
|
|
43
80
|
| `CLAIM_ACTION` | Yes | Claim CCM via server-paid gasless relay |
|
|
44
81
|
|
|
@@ -65,6 +102,11 @@ Creates a client instance. The keypair is used for Ed25519 agent authentication.
|
|
|
65
102
|
|
|
66
103
|
Auth is handled automatically: the client requests a challenge nonce, signs it with the keypair, and caches the bearer token (24h TTL, auto-refreshes).
|
|
67
104
|
|
|
105
|
+
For an end-to-end smoke test, use [`examples/hello-wzrd.mjs`](./examples/hello-wzrd.mjs). It works with just:
|
|
106
|
+
- `@wzrd_sol/solana-agent-plugin`
|
|
107
|
+
- `@solana/web3.js`
|
|
108
|
+
- `WZRD_KEYPAIR_PATH=/path/to/keypair.json`
|
|
109
|
+
|
|
68
110
|
## License
|
|
69
111
|
|
|
70
112
|
MIT
|
package/dist/actions/claim.d.ts
CHANGED
|
@@ -6,33 +6,14 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Flow: check claimable amount → relay claim → receive CCM.
|
|
8
8
|
*/
|
|
9
|
-
import
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
validate: () => Promise<boolean>;
|
|
21
|
-
handler: (client: WzrdClient, params: {
|
|
22
|
-
execute?: boolean;
|
|
23
|
-
}) => Promise<{
|
|
24
|
-
success: boolean;
|
|
25
|
-
text: string;
|
|
26
|
-
data: import("../client.js").WzrdClaim;
|
|
27
|
-
} | {
|
|
28
|
-
success: boolean;
|
|
29
|
-
text: string;
|
|
30
|
-
data: {
|
|
31
|
-
claimable_before: number;
|
|
32
|
-
explorer: string;
|
|
33
|
-
root_seq: number;
|
|
34
|
-
cumulative_total: number;
|
|
35
|
-
tx_sig: string;
|
|
36
|
-
};
|
|
37
|
-
}>;
|
|
38
|
-
};
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import type { Action, SolanaAgentKit } from 'solana-agent-kit';
|
|
11
|
+
export declare const claimSchema: z.ZodObject<{
|
|
12
|
+
execute: z.ZodOptional<z.ZodBoolean>;
|
|
13
|
+
}, "strip", z.ZodTypeAny, {
|
|
14
|
+
execute?: boolean | undefined;
|
|
15
|
+
}, {
|
|
16
|
+
execute?: boolean | undefined;
|
|
17
|
+
}>;
|
|
18
|
+
export declare function claimHandler(agent: SolanaAgentKit, input: z.infer<typeof claimSchema>): Promise<Record<string, unknown>>;
|
|
19
|
+
export declare const CLAIM_ACTION: Action;
|
package/dist/actions/claim.js
CHANGED
|
@@ -6,6 +6,55 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Flow: check claimable amount → relay claim → receive CCM.
|
|
8
8
|
*/
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import { formatCcm, getClaimsData, getClientForAgent } from '../runtime.js';
|
|
11
|
+
export const claimSchema = z.object({
|
|
12
|
+
execute: z.boolean().optional(),
|
|
13
|
+
});
|
|
14
|
+
export async function claimHandler(agent, input) {
|
|
15
|
+
const claims = await getClaimsData(agent);
|
|
16
|
+
const claimable = claims.cumulative_total - claims.claimed_total;
|
|
17
|
+
if (claimable <= 0) {
|
|
18
|
+
return {
|
|
19
|
+
success: true,
|
|
20
|
+
text: `No CCM to claim. Cumulative: ${claims.cumulative_total}, ` +
|
|
21
|
+
`already claimed: ${claims.claimed_total}. ` +
|
|
22
|
+
`Deposit into markets and wait for the next scoring cycle.`,
|
|
23
|
+
data: claims,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
if (input.execute === false) {
|
|
27
|
+
return {
|
|
28
|
+
success: true,
|
|
29
|
+
text: `${formatCcm(claimable)} CCM claimable ` +
|
|
30
|
+
`(${formatCcm(claims.cumulative_total)} cumulative, ` +
|
|
31
|
+
`${formatCcm(claims.claimed_total)} claimed). ` +
|
|
32
|
+
`Root seq: ${claims.root_seq}. Call with execute=true to claim.`,
|
|
33
|
+
data: claims,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const result = await getClientForAgent(agent).claimRelay();
|
|
37
|
+
if (result.status === 'already_claimed') {
|
|
38
|
+
return {
|
|
39
|
+
success: true,
|
|
40
|
+
text: `Already claimed through root ${result.root_seq}. ` +
|
|
41
|
+
`Claimed total: ${formatCcm(result.claimed_total ?? claims.claimed_total)} CCM.`,
|
|
42
|
+
data: result,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
success: true,
|
|
47
|
+
text: `Claimed CCM via gasless relay. ` +
|
|
48
|
+
`Cumulative total: ${formatCcm(result.cumulative_total)}. ` +
|
|
49
|
+
`Root seq: ${result.root_seq}. ` +
|
|
50
|
+
`Tx: ${result.tx_sig?.slice(0, 16)}...`,
|
|
51
|
+
data: {
|
|
52
|
+
...result,
|
|
53
|
+
claimable_before: claimable,
|
|
54
|
+
explorer: result.tx_sig ? `https://solscan.io/tx/${result.tx_sig}` : null,
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
9
58
|
export const CLAIM_ACTION = {
|
|
10
59
|
name: 'wzrd_claim',
|
|
11
60
|
similes: ['wzrd_harvest', 'claim_ccm', 'redeem_rewards', 'collect_yield'],
|
|
@@ -17,68 +66,16 @@ export const CLAIM_ACTION = {
|
|
|
17
66
|
examples: [
|
|
18
67
|
[
|
|
19
68
|
{
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
content: {
|
|
26
|
-
text: 'Claimed 100,000 CCM via gasless relay. ' +
|
|
27
|
-
'Cumulative total: 250,000 CCM. Tx: 2VKz...J39c',
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
],
|
|
31
|
-
[
|
|
32
|
-
{
|
|
33
|
-
user: 'user',
|
|
34
|
-
content: { text: 'How much CCM can I claim?' },
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
user: 'assistant',
|
|
38
|
-
content: {
|
|
39
|
-
text: 'You have 100,000 CCM claimable (250,000 cumulative, 150,000 already claimed). ' +
|
|
40
|
-
'Shall I claim it now?',
|
|
69
|
+
input: { execute: false },
|
|
70
|
+
output: {
|
|
71
|
+
success: true,
|
|
72
|
+
claimable: 100000,
|
|
73
|
+
cumulative_total: 250000,
|
|
41
74
|
},
|
|
75
|
+
explanation: 'Check how much CCM is available before triggering a relay claim.',
|
|
42
76
|
},
|
|
43
77
|
],
|
|
44
78
|
],
|
|
45
|
-
|
|
46
|
-
handler: async (
|
|
47
|
-
// 1. Check claimable amount
|
|
48
|
-
const claims = await client.getClaims();
|
|
49
|
-
const claimable = claims.cumulative_total - claims.claimed_total;
|
|
50
|
-
if (claimable <= 0) {
|
|
51
|
-
return {
|
|
52
|
-
success: true,
|
|
53
|
-
text: `No CCM to claim. Cumulative: ${claims.cumulative_total}, ` +
|
|
54
|
-
`already claimed: ${claims.claimed_total}. ` +
|
|
55
|
-
`Deposit into markets and wait for the next scoring cycle.`,
|
|
56
|
-
data: claims,
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
// 2. If just checking (not executing), report the amount
|
|
60
|
-
if (params.execute === false) {
|
|
61
|
-
return {
|
|
62
|
-
success: true,
|
|
63
|
-
text: `${claimable} CCM claimable ` +
|
|
64
|
-
`(${claims.cumulative_total} cumulative, ${claims.claimed_total} claimed). ` +
|
|
65
|
-
`Root seq: ${claims.root_seq}. Call with execute=true to claim.`,
|
|
66
|
-
data: claims,
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
// 3. Execute gasless relay claim
|
|
70
|
-
const result = await client.claimRelay();
|
|
71
|
-
return {
|
|
72
|
-
success: true,
|
|
73
|
-
text: `Claimed CCM via gasless relay. ` +
|
|
74
|
-
`Cumulative total: ${result.cumulative_total}. ` +
|
|
75
|
-
`Root seq: ${result.root_seq}. ` +
|
|
76
|
-
`Tx: ${result.tx_sig.slice(0, 16)}...`,
|
|
77
|
-
data: {
|
|
78
|
-
...result,
|
|
79
|
-
claimable_before: claimable,
|
|
80
|
-
explorer: `https://solscan.io/tx/${result.tx_sig}`,
|
|
81
|
-
},
|
|
82
|
-
};
|
|
83
|
-
},
|
|
79
|
+
schema: claimSchema,
|
|
80
|
+
handler: async (agent, input) => claimHandler(agent, claimSchema.parse(input)),
|
|
84
81
|
};
|
|
@@ -7,51 +7,20 @@
|
|
|
7
7
|
* The agent picks a market_id (from leaderboard), specifies USDC amount,
|
|
8
8
|
* and the handler builds + signs + sends the deposit transaction.
|
|
9
9
|
*/
|
|
10
|
-
import {
|
|
11
|
-
import type {
|
|
12
|
-
export
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
import type { Action, SolanaAgentKit } from 'solana-agent-kit';
|
|
12
|
+
export declare const depositSchema: z.ZodObject<{
|
|
13
|
+
market_id: z.ZodNumber;
|
|
14
|
+
amount_usdc: z.ZodNumber;
|
|
15
|
+
priority_fee: z.ZodOptional<z.ZodNumber>;
|
|
16
|
+
}, "strip", z.ZodTypeAny, {
|
|
13
17
|
market_id: number;
|
|
14
18
|
amount_usdc: number;
|
|
15
|
-
priority_fee?: number;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
content: {
|
|
24
|
-
text: string;
|
|
25
|
-
};
|
|
26
|
-
}[][];
|
|
27
|
-
validate: (_client: WzrdClient, params: DepositParams) => Promise<boolean>;
|
|
28
|
-
handler: (_client: WzrdClient, params: DepositParams, connection: Connection, wallet: Keypair) => Promise<{
|
|
29
|
-
success: boolean;
|
|
30
|
-
text: string;
|
|
31
|
-
data?: undefined;
|
|
32
|
-
} | {
|
|
33
|
-
success: boolean;
|
|
34
|
-
text: string;
|
|
35
|
-
data: {
|
|
36
|
-
logs: string[] | undefined;
|
|
37
|
-
signature?: undefined;
|
|
38
|
-
market_id?: undefined;
|
|
39
|
-
amount_usdc?: undefined;
|
|
40
|
-
cu_used?: undefined;
|
|
41
|
-
elapsed_ms?: undefined;
|
|
42
|
-
explorer?: undefined;
|
|
43
|
-
};
|
|
44
|
-
} | {
|
|
45
|
-
success: boolean;
|
|
46
|
-
text: string;
|
|
47
|
-
data: {
|
|
48
|
-
signature: string;
|
|
49
|
-
market_id: number;
|
|
50
|
-
amount_usdc: number;
|
|
51
|
-
cu_used: number | undefined;
|
|
52
|
-
elapsed_ms: number;
|
|
53
|
-
explorer: string;
|
|
54
|
-
logs?: undefined;
|
|
55
|
-
};
|
|
56
|
-
}>;
|
|
57
|
-
};
|
|
19
|
+
priority_fee?: number | undefined;
|
|
20
|
+
}, {
|
|
21
|
+
market_id: number;
|
|
22
|
+
amount_usdc: number;
|
|
23
|
+
priority_fee?: number | undefined;
|
|
24
|
+
}>;
|
|
25
|
+
export declare function depositHandler(agent: SolanaAgentKit, input: z.infer<typeof depositSchema>): Promise<Record<string, unknown>>;
|
|
26
|
+
export declare const DEPOSIT_ACTION: Action;
|
package/dist/actions/deposit.js
CHANGED
|
@@ -8,9 +8,147 @@
|
|
|
8
8
|
* and the handler builds + signs + sends the deposit transaction.
|
|
9
9
|
*/
|
|
10
10
|
import { ComputeBudgetProgram, TransactionMessage, VersionedTransaction, } from '@solana/web3.js';
|
|
11
|
-
import {
|
|
11
|
+
import { z } from 'zod';
|
|
12
|
+
import { formatUsdc, getWalletPublicKey } from '../runtime.js';
|
|
12
13
|
const USDC_MINT = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v';
|
|
13
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
|
+
}
|
|
14
152
|
export const DEPOSIT_ACTION = {
|
|
15
153
|
name: 'wzrd_deposit',
|
|
16
154
|
similes: ['wzrd_invest', 'deposit_usdc', 'buy_attention', 'enter_market'],
|
|
@@ -23,112 +161,17 @@ export const DEPOSIT_ACTION = {
|
|
|
23
161
|
examples: [
|
|
24
162
|
[
|
|
25
163
|
{
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
text: 'Deposited 0.01 USDC into Market #10 (Qwen 2.5 72B). ' +
|
|
33
|
-
'Received 10,000 vLOFI. Tx: X7FG...Cziv (772ms, 50687 CU)',
|
|
34
|
-
},
|
|
35
|
-
},
|
|
36
|
-
],
|
|
37
|
-
[
|
|
38
|
-
{
|
|
39
|
-
user: 'user',
|
|
40
|
-
content: { text: 'Invest in the highest velocity market' },
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
user: 'assistant',
|
|
44
|
-
content: {
|
|
45
|
-
text: 'Looking up leaderboard... Top market is #16 (Qwen 3.5 35B) ' +
|
|
46
|
-
'with 804K velocity. Depositing 0.01 USDC...',
|
|
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...',
|
|
47
170
|
},
|
|
171
|
+
explanation: 'Deposit 0.01 USDC into a known vaulted market and mint vLOFI.',
|
|
48
172
|
},
|
|
49
173
|
],
|
|
50
174
|
],
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
return false;
|
|
54
|
-
if (!params.amount_usdc || params.amount_usdc <= 0)
|
|
55
|
-
return false;
|
|
56
|
-
if (params.amount_usdc > 100)
|
|
57
|
-
return false; // safety cap
|
|
58
|
-
return true;
|
|
59
|
-
},
|
|
60
|
-
handler: async (_client, params, connection, wallet) => {
|
|
61
|
-
const { market_id, amount_usdc, priority_fee = 50_000 } = params;
|
|
62
|
-
const amountNative = BigInt(Math.round(amount_usdc * 1_000_000));
|
|
63
|
-
const t0 = Date.now();
|
|
64
|
-
// 1. Idempotency — check existing position
|
|
65
|
-
const existing = await fetchOnChainPosition(connection, wallet.publicKey, market_id);
|
|
66
|
-
if (existing && existing.depositedAmount > 0n && !existing.settled) {
|
|
67
|
-
return {
|
|
68
|
-
success: false,
|
|
69
|
-
text: `Position already exists in market ${market_id} ` +
|
|
70
|
-
`(${existing.depositedAmount} deposited). Cannot double-deposit.`,
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
// 2. Balance checks
|
|
74
|
-
const { PublicKey } = await import('@solana/web3.js');
|
|
75
|
-
const usdcMint = new PublicKey(USDC_MINT);
|
|
76
|
-
const usdcAta = getAta(wallet.publicKey, usdcMint, TOKEN_PROGRAM_ID);
|
|
77
|
-
const usdcBalance = await fetchTokenBalance(connection, usdcAta);
|
|
78
|
-
if (usdcBalance < amountNative) {
|
|
79
|
-
return {
|
|
80
|
-
success: false,
|
|
81
|
-
text: `Insufficient USDC: have ${Number(usdcBalance) / 1e6}, need ${amount_usdc}`,
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
const solBalance = await connection.getBalance(wallet.publicKey);
|
|
85
|
-
if (solBalance < 10_000) {
|
|
86
|
-
return {
|
|
87
|
-
success: false,
|
|
88
|
-
text: `Insufficient SOL for tx fees: ${solBalance} lamports`,
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
// 3. Build deposit instructions
|
|
92
|
-
const ixs = await createDepositMarketIx(connection, wallet.publicKey, market_id, amountNative);
|
|
93
|
-
ixs.unshift(ComputeBudgetProgram.setComputeUnitLimit({ units: 300_000 }), ComputeBudgetProgram.setComputeUnitPrice({ microLamports: priority_fee }));
|
|
94
|
-
// 4. Simulate
|
|
95
|
-
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
|
|
96
|
-
const message = new TransactionMessage({
|
|
97
|
-
payerKey: wallet.publicKey,
|
|
98
|
-
recentBlockhash: blockhash,
|
|
99
|
-
instructions: ixs,
|
|
100
|
-
}).compileToV0Message();
|
|
101
|
-
const tx = new VersionedTransaction(message);
|
|
102
|
-
tx.sign([wallet]);
|
|
103
|
-
const sim = await connection.simulateTransaction(tx);
|
|
104
|
-
if (sim.value.err) {
|
|
105
|
-
return {
|
|
106
|
-
success: false,
|
|
107
|
-
text: `Simulation failed: ${JSON.stringify(sim.value.err)}`,
|
|
108
|
-
data: { logs: sim.value.logs?.slice(-5) },
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
// 5. Send + confirm
|
|
112
|
-
const signature = await connection.sendTransaction(tx, {
|
|
113
|
-
skipPreflight: true,
|
|
114
|
-
maxRetries: 3,
|
|
115
|
-
});
|
|
116
|
-
const confirmed = connection.confirmTransaction({ signature, blockhash, lastValidBlockHeight }, 'confirmed');
|
|
117
|
-
const timeout = new Promise((_, reject) => setTimeout(() => reject(new Error(`Timeout after ${CONFIRM_TIMEOUT_MS}ms`)), CONFIRM_TIMEOUT_MS));
|
|
118
|
-
await Promise.race([confirmed, timeout]);
|
|
119
|
-
const elapsed = Date.now() - t0;
|
|
120
|
-
return {
|
|
121
|
-
success: true,
|
|
122
|
-
text: `Deposited ${amount_usdc} USDC into Market #${market_id}. ` +
|
|
123
|
-
`Tx: ${signature.slice(0, 16)}... (${elapsed}ms, ${sim.value.unitsConsumed} CU)`,
|
|
124
|
-
data: {
|
|
125
|
-
signature,
|
|
126
|
-
market_id,
|
|
127
|
-
amount_usdc,
|
|
128
|
-
cu_used: sim.value.unitsConsumed,
|
|
129
|
-
elapsed_ms: elapsed,
|
|
130
|
-
explorer: `https://solscan.io/tx/${signature}`,
|
|
131
|
-
},
|
|
132
|
-
};
|
|
133
|
-
},
|
|
175
|
+
schema: depositSchema,
|
|
176
|
+
handler: async (agent, input) => depositHandler(agent, depositSchema.parse(input)),
|
|
134
177
|
};
|
package/dist/actions/index.d.ts
CHANGED
|
@@ -4,24 +4,17 @@
|
|
|
4
4
|
* Fetch the WZRD attention market leaderboard — ranked by velocity EMA.
|
|
5
5
|
* No auth required. Permissionless read.
|
|
6
6
|
*/
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
platform?: string;
|
|
22
|
-
}) => Promise<{
|
|
23
|
-
success: boolean;
|
|
24
|
-
text: string;
|
|
25
|
-
data: import("../client.js").WzrdLeaderboard;
|
|
26
|
-
}>;
|
|
27
|
-
};
|
|
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;
|