plugin-a2a-swap 0.1.1

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 ADDED
@@ -0,0 +1,109 @@
1
+ # @liqdlad/plugin-a2a-swap
2
+
3
+ ElizaOS plugin for **A2A-Swap** — the constant-product AMM built for autonomous AI agents on Solana.
4
+
5
+ ## Overview
6
+
7
+ A2A-Swap is a lightweight, agent-native decentralized exchange on Solana. Unlike traditional DEXes designed for human UIs, every instruction was designed for programmatic agent workflows:
8
+
9
+ - **No tick ranges** — constant-product x·y=k, simple to reason about
10
+ - **No LP token mints** — LP shares tracked on-chain in a `Position` account
11
+ - **Dual-approval mode** — `approve_and_execute` requires both agent + approver signatures, enabling multi-agent authorization workflows
12
+ - **Auto-compound** — fees can be automatically reinvested into LP shares
13
+
14
+ Program ID: `8XJfG4mHqRZjByAd7HxHdEALfB8jVtJVQsdhGEmysTFq` (mainnet-beta)
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @liqdlad/plugin-a2a-swap
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ```typescript
25
+ import { createAgent } from '@elizaos/core';
26
+ import { a2aSwapPlugin } from '@liqdlad/plugin-a2a-swap';
27
+
28
+ const agent = createAgent({
29
+ plugins: [a2aSwapPlugin],
30
+ // ...
31
+ });
32
+ ```
33
+
34
+ ## Environment Variables
35
+
36
+ | Variable | Required | Description |
37
+ |---|---|---|
38
+ | `AGENT_PRIVATE_KEY` | ✅ | Agent wallet secret key as JSON byte array, e.g. `[1,2,3,...]` |
39
+ | `SOLANA_RPC_URL` | optional | Solana RPC endpoint (default: `https://api.mainnet-beta.solana.com`) |
40
+
41
+ ## Actions
42
+
43
+ ### `A2A_SIMULATE_SWAP`
44
+
45
+ Simulate a swap and get fee breakdown without spending funds.
46
+
47
+ **Options:** `mintIn`, `mintOut`, `amountIn` (atomic units)
48
+
49
+ **Returns:** pool address, direction, protocol fee (0.020%), LP fee, estimated output, effective rate, price impact
50
+
51
+ **Trigger phrases:** `simulate swap`, `estimate swap`, `quote swap`, `swap preview`
52
+
53
+ ---
54
+
55
+ ### `A2A_SWAP`
56
+
57
+ Execute an atomic token swap. Fully autonomous — no human approval needed.
58
+
59
+ **Options:** `mintIn`, `mintOut`, `amountIn`, optional `maxSlippageBps` (default: 50)
60
+
61
+ **Trigger phrases:** `swap tokens`, `trade tokens`, `buy token`, `sell token`
62
+
63
+ ---
64
+
65
+ ### `A2A_PROVIDE_LIQUIDITY`
66
+
67
+ Deposit tokens into a pool and receive LP shares.
68
+
69
+ **Options:** `mintA`, `mintB`, `amountA`, optional `amountB`, optional `autoCompound` (`"true"`/`"false"`)
70
+
71
+ **Trigger phrases:** `provide liquidity`, `add liquidity`, `become LP`
72
+
73
+ ---
74
+
75
+ ### `A2A_POOL_INFO`
76
+
77
+ Fetch pool reserves, spot price, LP supply, and fee rate.
78
+
79
+ **Options:** `mintA`, `mintB`
80
+
81
+ **Trigger phrases:** `pool info`, `pool stats`, `pool price`, `check pool`
82
+
83
+ ---
84
+
85
+ ### `A2A_MY_FEES`
86
+
87
+ Show accrued trading fees across all LP positions for the agent wallet.
88
+
89
+ **Trigger phrases:** `my fees`, `check fees`, `claimable fees`, `earned fees`
90
+
91
+ ---
92
+
93
+ ## Live Pools (Mainnet)
94
+
95
+ | Pool | Address |
96
+ |---|---|
97
+ | SOL/USDC (30 bps) | `BtBL5wpMbmabFimeUmLtjZAAeh4xWWf76NSpefMXb4TC` |
98
+
99
+ Pools are permissionless — any agent can create a new pair.
100
+
101
+ ## Links
102
+
103
+ - **Program:** [Solscan](https://solscan.io/account/8XJfG4mHqRZjByAd7HxHdEALfB8jVtJVQsdhGEmysTFq)
104
+ - **TypeScript SDK:** [@liqdlad/a2a-swap-sdk](https://www.npmjs.com/package/@liqdlad/a2a-swap-sdk)
105
+ - **GitHub:** [liqdlad-rgb/a2a-swap](https://github.com/liqdlad-rgb/a2a-swap)
106
+
107
+ ## License
108
+
109
+ MIT
@@ -0,0 +1,22 @@
1
+ import { Plugin, Action } from '@elizaos/core';
2
+
3
+ /**
4
+ * @liqdlad/plugin-a2a-swap
5
+ *
6
+ * ElizaOS plugin for A2A-Swap — the constant-product AMM designed for AI agents.
7
+ * Gives any ElizaOS agent native on-chain swap, liquidity, and fee-query
8
+ * capabilities on Solana without any human approval flow.
9
+ *
10
+ * Required environment variables:
11
+ * AGENT_PRIVATE_KEY – agent wallet secret key as a JSON byte array
12
+ * SOLANA_RPC_URL – RPC endpoint (defaults to mainnet-beta)
13
+ */
14
+
15
+ declare const simulateSwapAction: Action;
16
+ declare const swapTokensAction: Action;
17
+ declare const provideLiquidityAction: Action;
18
+ declare const poolInfoAction: Action;
19
+ declare const myFeesAction: Action;
20
+ declare const a2aSwapPlugin: Plugin;
21
+
22
+ export { a2aSwapPlugin, a2aSwapPlugin as default, myFeesAction, poolInfoAction, provideLiquidityAction, simulateSwapAction, swapTokensAction };
@@ -0,0 +1,22 @@
1
+ import { Plugin, Action } from '@elizaos/core';
2
+
3
+ /**
4
+ * @liqdlad/plugin-a2a-swap
5
+ *
6
+ * ElizaOS plugin for A2A-Swap — the constant-product AMM designed for AI agents.
7
+ * Gives any ElizaOS agent native on-chain swap, liquidity, and fee-query
8
+ * capabilities on Solana without any human approval flow.
9
+ *
10
+ * Required environment variables:
11
+ * AGENT_PRIVATE_KEY – agent wallet secret key as a JSON byte array
12
+ * SOLANA_RPC_URL – RPC endpoint (defaults to mainnet-beta)
13
+ */
14
+
15
+ declare const simulateSwapAction: Action;
16
+ declare const swapTokensAction: Action;
17
+ declare const provideLiquidityAction: Action;
18
+ declare const poolInfoAction: Action;
19
+ declare const myFeesAction: Action;
20
+ declare const a2aSwapPlugin: Plugin;
21
+
22
+ export { a2aSwapPlugin, a2aSwapPlugin as default, myFeesAction, poolInfoAction, provideLiquidityAction, simulateSwapAction, swapTokensAction };
package/dist/index.js ADDED
@@ -0,0 +1,348 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ a2aSwapPlugin: () => a2aSwapPlugin,
24
+ default: () => index_default,
25
+ myFeesAction: () => myFeesAction,
26
+ poolInfoAction: () => poolInfoAction,
27
+ provideLiquidityAction: () => provideLiquidityAction,
28
+ simulateSwapAction: () => simulateSwapAction,
29
+ swapTokensAction: () => swapTokensAction
30
+ });
31
+ module.exports = __toCommonJS(index_exports);
32
+ var import_web3 = require("@solana/web3.js");
33
+ var import_a2a_swap_sdk = require("@liqdlad/a2a-swap-sdk");
34
+ var DEFAULT_RPC = "https://api.mainnet-beta.solana.com";
35
+ function loadKeypair() {
36
+ const raw = process.env.AGENT_PRIVATE_KEY;
37
+ if (!raw) throw new Error("AGENT_PRIVATE_KEY is not set");
38
+ const bytes = JSON.parse(raw);
39
+ return import_web3.Keypair.fromSecretKey(Uint8Array.from(bytes));
40
+ }
41
+ function buildClient() {
42
+ return new import_a2a_swap_sdk.A2ASwapClient({
43
+ rpcUrl: process.env.SOLANA_RPC_URL ?? DEFAULT_RPC
44
+ });
45
+ }
46
+ function parseMint(addr) {
47
+ try {
48
+ return new import_web3.PublicKey(addr.trim());
49
+ } catch {
50
+ throw new Error(`Invalid mint address: "${addr}"`);
51
+ }
52
+ }
53
+ function opt(options, key) {
54
+ return options?.[key];
55
+ }
56
+ var simulateSwapAction = {
57
+ name: "A2A_SIMULATE_SWAP",
58
+ description: "Simulate a token swap on A2A-Swap and return the fee breakdown without spending any funds. Returns: pool address, direction, protocol fee, LP fee, estimated output, effective rate, price impact.",
59
+ similes: [
60
+ "simulate swap",
61
+ "estimate swap",
62
+ "quote swap",
63
+ "how much will I get",
64
+ "swap preview",
65
+ "check swap price",
66
+ "get swap quote"
67
+ ],
68
+ examples: [
69
+ [
70
+ {
71
+ name: "user",
72
+ content: { text: "Simulate swapping 1 SOL for USDC on A2A-Swap" }
73
+ },
74
+ {
75
+ name: "agent",
76
+ content: {
77
+ text: "Simulating swap: 1 SOL \u2192 USDC \u2026",
78
+ action: "A2A_SIMULATE_SWAP"
79
+ }
80
+ }
81
+ ],
82
+ [
83
+ {
84
+ name: "user",
85
+ content: { text: "Quote me 500000000 lamports for USDC" }
86
+ },
87
+ {
88
+ name: "agent",
89
+ content: {
90
+ text: "Getting swap quote from A2A-Swap \u2026",
91
+ action: "A2A_SIMULATE_SWAP"
92
+ }
93
+ }
94
+ ]
95
+ ],
96
+ validate: async (_runtime, _message, _state) => true,
97
+ handler: async (_runtime, _message, _state, options, callback) => {
98
+ try {
99
+ const client = buildClient();
100
+ const params = {
101
+ mintIn: parseMint(opt(options, "mintIn") ?? ""),
102
+ mintOut: parseMint(opt(options, "mintOut") ?? ""),
103
+ amountIn: BigInt(opt(options, "amountIn") ?? "0")
104
+ };
105
+ const sim = await client.simulate(params);
106
+ const text = `Swap simulation result:
107
+ Pool: ${sim.pool.toBase58()}
108
+ Direction: ${sim.aToB ? "A \u2192 B" : "B \u2192 A"}
109
+ Amount in: ${sim.amountIn}
110
+ Protocol fee: ${sim.protocolFee} (0.020%)
111
+ LP fee: ${sim.lpFee} (${sim.feeRateBps} bps)
112
+ Estimated out: ${sim.estimatedOut}
113
+ Effective rate: ${sim.effectiveRate.toFixed(6)}
114
+ Price impact: ${sim.priceImpactPct.toFixed(3)}%`;
115
+ await callback?.({ text, data: sim });
116
+ } catch (err) {
117
+ await callback?.({ text: `Simulation failed: ${err.message}` });
118
+ }
119
+ }
120
+ };
121
+ var swapTokensAction = {
122
+ name: "A2A_SWAP",
123
+ description: "Execute an atomic token swap on A2A-Swap. Fully autonomous \u2014 no human approval required by default. Accepts: mintIn, mintOut, amountIn (atomic units), optional maxSlippageBps.",
124
+ similes: [
125
+ "swap tokens",
126
+ "trade tokens",
127
+ "exchange tokens",
128
+ "buy token",
129
+ "sell token",
130
+ "convert token",
131
+ "execute swap",
132
+ "do a swap"
133
+ ],
134
+ examples: [
135
+ [
136
+ {
137
+ name: "user",
138
+ content: { text: "Swap 0.5 SOL for USDC on A2A-Swap" }
139
+ },
140
+ {
141
+ name: "agent",
142
+ content: {
143
+ text: "Executing swap: 0.5 SOL \u2192 USDC \u2026",
144
+ action: "A2A_SWAP"
145
+ }
146
+ }
147
+ ]
148
+ ],
149
+ validate: async (_runtime, _message, _state) => true,
150
+ handler: async (_runtime, _message, _state, options, callback) => {
151
+ try {
152
+ const client = buildClient();
153
+ const keypair = loadKeypair();
154
+ const params = {
155
+ mintIn: parseMint(opt(options, "mintIn") ?? ""),
156
+ mintOut: parseMint(opt(options, "mintOut") ?? ""),
157
+ amountIn: BigInt(opt(options, "amountIn") ?? "0"),
158
+ maxSlippageBps: opt(options, "maxSlippageBps") ? parseInt(opt(options, "maxSlippageBps"), 10) : 50
159
+ };
160
+ const sim = await client.simulate({
161
+ mintIn: params.mintIn,
162
+ mintOut: params.mintOut,
163
+ amountIn: params.amountIn
164
+ });
165
+ await callback?.({
166
+ text: `Swap preview \u2014 estimated out: ${sim.estimatedOut} (impact: ${sim.priceImpactPct.toFixed(3)}%). Executing \u2026`
167
+ });
168
+ const result = await client.convert(keypair, params);
169
+ await callback?.({
170
+ text: `Swap complete!
171
+ Signature: ${result.signature}
172
+ Amount in: ${result.amountIn}
173
+ Estimated out: ${result.estimatedOut}
174
+ Direction: ${result.aToB ? "A \u2192 B" : "B \u2192 A"}`,
175
+ data: result
176
+ });
177
+ } catch (err) {
178
+ await callback?.({ text: `Swap failed: ${err.message}` });
179
+ }
180
+ }
181
+ };
182
+ var provideLiquidityAction = {
183
+ name: "A2A_PROVIDE_LIQUIDITY",
184
+ description: "Deposit tokens into an A2A-Swap pool and receive LP shares. Enable autoCompound to reinvest accrued fees automatically. Accepts: mintA, mintB, amountA, optional amountB, optional autoCompound.",
185
+ similes: [
186
+ "provide liquidity",
187
+ "add liquidity",
188
+ "deposit liquidity",
189
+ "become LP",
190
+ "add to pool",
191
+ "supply liquidity"
192
+ ],
193
+ examples: [
194
+ [
195
+ {
196
+ name: "user",
197
+ content: { text: "Add liquidity to the SOL/USDC pool on A2A-Swap" }
198
+ },
199
+ {
200
+ name: "agent",
201
+ content: {
202
+ text: "Providing liquidity to SOL/USDC pool \u2026",
203
+ action: "A2A_PROVIDE_LIQUIDITY"
204
+ }
205
+ }
206
+ ]
207
+ ],
208
+ validate: async (_runtime, _message, _state) => true,
209
+ handler: async (_runtime, _message, _state, options, callback) => {
210
+ try {
211
+ const client = buildClient();
212
+ const keypair = loadKeypair();
213
+ const amountBStr = opt(options, "amountB");
214
+ const params = {
215
+ mintA: parseMint(opt(options, "mintA") ?? ""),
216
+ mintB: parseMint(opt(options, "mintB") ?? ""),
217
+ amountA: BigInt(opt(options, "amountA") ?? "0"),
218
+ amountB: amountBStr ? BigInt(amountBStr) : void 0,
219
+ autoCompound: opt(options, "autoCompound") === "true",
220
+ compoundThreshold: 0n,
221
+ minLp: 0n
222
+ };
223
+ const result = await client.provideLiquidity(keypair, params);
224
+ await callback?.({
225
+ text: `Liquidity provided!
226
+ Signature: ${result.signature}
227
+ Position: ${result.position.toBase58()}
228
+ Deposited: ${result.amountA} tokenA, ${result.amountB} tokenB`,
229
+ data: result
230
+ });
231
+ } catch (err) {
232
+ await callback?.({ text: `Liquidity provision failed: ${err.message}` });
233
+ }
234
+ }
235
+ };
236
+ var poolInfoAction = {
237
+ name: "A2A_POOL_INFO",
238
+ description: "Fetch A2A-Swap pool reserves, spot price, LP supply, and fee rate. Accepts: mintA, mintB (the two token mint addresses).",
239
+ similes: [
240
+ "pool info",
241
+ "pool stats",
242
+ "pool state",
243
+ "pool price",
244
+ "liquidity info",
245
+ "check pool",
246
+ "what is the price",
247
+ "how much liquidity"
248
+ ],
249
+ examples: [
250
+ [
251
+ {
252
+ name: "user",
253
+ content: { text: "What is the SOL/USDC pool price on A2A-Swap?" }
254
+ },
255
+ {
256
+ name: "agent",
257
+ content: { text: "Fetching pool info \u2026", action: "A2A_POOL_INFO" }
258
+ }
259
+ ]
260
+ ],
261
+ validate: async (_runtime, _message, _state) => true,
262
+ handler: async (_runtime, _message, _state, options, callback) => {
263
+ try {
264
+ const client = buildClient();
265
+ const info = await client.poolInfo(
266
+ parseMint(opt(options, "mintA") ?? ""),
267
+ parseMint(opt(options, "mintB") ?? "")
268
+ );
269
+ await callback?.({
270
+ text: `Pool info:
271
+ Pool: ${info.pool.toBase58()}
272
+ Reserve A: ${info.reserveA}
273
+ Reserve B: ${info.reserveB}
274
+ LP supply: ${info.lpSupply}
275
+ Fee rate: ${info.feeRateBps} bps
276
+ Spot price: ${info.spotPrice.toFixed(6)}`,
277
+ data: info
278
+ });
279
+ } catch (err) {
280
+ await callback?.({ text: `Pool info failed: ${err.message}` });
281
+ }
282
+ }
283
+ };
284
+ var myFeesAction = {
285
+ name: "A2A_MY_FEES",
286
+ description: "Show accrued trading fees across all A2A-Swap LP positions for the agent wallet.",
287
+ similes: [
288
+ "my fees",
289
+ "check fees",
290
+ "claimable fees",
291
+ "LP fees",
292
+ "earned fees",
293
+ "how much fees",
294
+ "fee summary"
295
+ ],
296
+ examples: [
297
+ [
298
+ { name: "user", content: { text: "How much fees have I earned on A2A-Swap?" } },
299
+ { name: "agent", content: { text: "Fetching fee summary \u2026", action: "A2A_MY_FEES" } }
300
+ ]
301
+ ],
302
+ validate: async (_runtime, _message, _state) => true,
303
+ handler: async (_runtime, _message, _state, _options, callback) => {
304
+ try {
305
+ const client = buildClient();
306
+ const keypair = loadKeypair();
307
+ const fees = await client.myFees(keypair.publicKey);
308
+ if (fees.positions.length === 0) {
309
+ await callback?.({ text: "No LP positions found for this agent." });
310
+ return;
311
+ }
312
+ const lines = fees.positions.map(
313
+ (p, i) => ` [${i + 1}] ${p.address.toBase58().slice(0, 8)}\u2026 LP: ${p.lpShares} fees A: ${p.totalFeesA} fees B: ${p.totalFeesB}`
314
+ );
315
+ await callback?.({
316
+ text: `Fee summary (${fees.positions.length} position${fees.positions.length > 1 ? "s" : ""}):
317
+ ` + lines.join("\n") + `
318
+ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
319
+ Total fees A: ${fees.totalFeesA}
320
+ Total fees B: ${fees.totalFeesB}`,
321
+ data: fees
322
+ });
323
+ } catch (err) {
324
+ await callback?.({ text: `Fee check failed: ${err.message}` });
325
+ }
326
+ }
327
+ };
328
+ var a2aSwapPlugin = {
329
+ name: "plugin-a2a-swap",
330
+ description: "A2A-Swap AMM \u2014 autonomous token swaps and liquidity management on Solana. Backed by a constant-product x*y=k AMM with no tick ranges, no LP token mints, and a dual-approval mode for multi-agent workflows.",
331
+ actions: [
332
+ simulateSwapAction,
333
+ swapTokensAction,
334
+ provideLiquidityAction,
335
+ poolInfoAction,
336
+ myFeesAction
337
+ ]
338
+ };
339
+ var index_default = a2aSwapPlugin;
340
+ // Annotate the CommonJS export names for ESM import in node:
341
+ 0 && (module.exports = {
342
+ a2aSwapPlugin,
343
+ myFeesAction,
344
+ poolInfoAction,
345
+ provideLiquidityAction,
346
+ simulateSwapAction,
347
+ swapTokensAction
348
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,320 @@
1
+ // src/index.ts
2
+ import { Keypair, PublicKey } from "@solana/web3.js";
3
+ import {
4
+ A2ASwapClient
5
+ } from "@liqdlad/a2a-swap-sdk";
6
+ var DEFAULT_RPC = "https://api.mainnet-beta.solana.com";
7
+ function loadKeypair() {
8
+ const raw = process.env.AGENT_PRIVATE_KEY;
9
+ if (!raw) throw new Error("AGENT_PRIVATE_KEY is not set");
10
+ const bytes = JSON.parse(raw);
11
+ return Keypair.fromSecretKey(Uint8Array.from(bytes));
12
+ }
13
+ function buildClient() {
14
+ return new A2ASwapClient({
15
+ rpcUrl: process.env.SOLANA_RPC_URL ?? DEFAULT_RPC
16
+ });
17
+ }
18
+ function parseMint(addr) {
19
+ try {
20
+ return new PublicKey(addr.trim());
21
+ } catch {
22
+ throw new Error(`Invalid mint address: "${addr}"`);
23
+ }
24
+ }
25
+ function opt(options, key) {
26
+ return options?.[key];
27
+ }
28
+ var simulateSwapAction = {
29
+ name: "A2A_SIMULATE_SWAP",
30
+ description: "Simulate a token swap on A2A-Swap and return the fee breakdown without spending any funds. Returns: pool address, direction, protocol fee, LP fee, estimated output, effective rate, price impact.",
31
+ similes: [
32
+ "simulate swap",
33
+ "estimate swap",
34
+ "quote swap",
35
+ "how much will I get",
36
+ "swap preview",
37
+ "check swap price",
38
+ "get swap quote"
39
+ ],
40
+ examples: [
41
+ [
42
+ {
43
+ name: "user",
44
+ content: { text: "Simulate swapping 1 SOL for USDC on A2A-Swap" }
45
+ },
46
+ {
47
+ name: "agent",
48
+ content: {
49
+ text: "Simulating swap: 1 SOL \u2192 USDC \u2026",
50
+ action: "A2A_SIMULATE_SWAP"
51
+ }
52
+ }
53
+ ],
54
+ [
55
+ {
56
+ name: "user",
57
+ content: { text: "Quote me 500000000 lamports for USDC" }
58
+ },
59
+ {
60
+ name: "agent",
61
+ content: {
62
+ text: "Getting swap quote from A2A-Swap \u2026",
63
+ action: "A2A_SIMULATE_SWAP"
64
+ }
65
+ }
66
+ ]
67
+ ],
68
+ validate: async (_runtime, _message, _state) => true,
69
+ handler: async (_runtime, _message, _state, options, callback) => {
70
+ try {
71
+ const client = buildClient();
72
+ const params = {
73
+ mintIn: parseMint(opt(options, "mintIn") ?? ""),
74
+ mintOut: parseMint(opt(options, "mintOut") ?? ""),
75
+ amountIn: BigInt(opt(options, "amountIn") ?? "0")
76
+ };
77
+ const sim = await client.simulate(params);
78
+ const text = `Swap simulation result:
79
+ Pool: ${sim.pool.toBase58()}
80
+ Direction: ${sim.aToB ? "A \u2192 B" : "B \u2192 A"}
81
+ Amount in: ${sim.amountIn}
82
+ Protocol fee: ${sim.protocolFee} (0.020%)
83
+ LP fee: ${sim.lpFee} (${sim.feeRateBps} bps)
84
+ Estimated out: ${sim.estimatedOut}
85
+ Effective rate: ${sim.effectiveRate.toFixed(6)}
86
+ Price impact: ${sim.priceImpactPct.toFixed(3)}%`;
87
+ await callback?.({ text, data: sim });
88
+ } catch (err) {
89
+ await callback?.({ text: `Simulation failed: ${err.message}` });
90
+ }
91
+ }
92
+ };
93
+ var swapTokensAction = {
94
+ name: "A2A_SWAP",
95
+ description: "Execute an atomic token swap on A2A-Swap. Fully autonomous \u2014 no human approval required by default. Accepts: mintIn, mintOut, amountIn (atomic units), optional maxSlippageBps.",
96
+ similes: [
97
+ "swap tokens",
98
+ "trade tokens",
99
+ "exchange tokens",
100
+ "buy token",
101
+ "sell token",
102
+ "convert token",
103
+ "execute swap",
104
+ "do a swap"
105
+ ],
106
+ examples: [
107
+ [
108
+ {
109
+ name: "user",
110
+ content: { text: "Swap 0.5 SOL for USDC on A2A-Swap" }
111
+ },
112
+ {
113
+ name: "agent",
114
+ content: {
115
+ text: "Executing swap: 0.5 SOL \u2192 USDC \u2026",
116
+ action: "A2A_SWAP"
117
+ }
118
+ }
119
+ ]
120
+ ],
121
+ validate: async (_runtime, _message, _state) => true,
122
+ handler: async (_runtime, _message, _state, options, callback) => {
123
+ try {
124
+ const client = buildClient();
125
+ const keypair = loadKeypair();
126
+ const params = {
127
+ mintIn: parseMint(opt(options, "mintIn") ?? ""),
128
+ mintOut: parseMint(opt(options, "mintOut") ?? ""),
129
+ amountIn: BigInt(opt(options, "amountIn") ?? "0"),
130
+ maxSlippageBps: opt(options, "maxSlippageBps") ? parseInt(opt(options, "maxSlippageBps"), 10) : 50
131
+ };
132
+ const sim = await client.simulate({
133
+ mintIn: params.mintIn,
134
+ mintOut: params.mintOut,
135
+ amountIn: params.amountIn
136
+ });
137
+ await callback?.({
138
+ text: `Swap preview \u2014 estimated out: ${sim.estimatedOut} (impact: ${sim.priceImpactPct.toFixed(3)}%). Executing \u2026`
139
+ });
140
+ const result = await client.convert(keypair, params);
141
+ await callback?.({
142
+ text: `Swap complete!
143
+ Signature: ${result.signature}
144
+ Amount in: ${result.amountIn}
145
+ Estimated out: ${result.estimatedOut}
146
+ Direction: ${result.aToB ? "A \u2192 B" : "B \u2192 A"}`,
147
+ data: result
148
+ });
149
+ } catch (err) {
150
+ await callback?.({ text: `Swap failed: ${err.message}` });
151
+ }
152
+ }
153
+ };
154
+ var provideLiquidityAction = {
155
+ name: "A2A_PROVIDE_LIQUIDITY",
156
+ description: "Deposit tokens into an A2A-Swap pool and receive LP shares. Enable autoCompound to reinvest accrued fees automatically. Accepts: mintA, mintB, amountA, optional amountB, optional autoCompound.",
157
+ similes: [
158
+ "provide liquidity",
159
+ "add liquidity",
160
+ "deposit liquidity",
161
+ "become LP",
162
+ "add to pool",
163
+ "supply liquidity"
164
+ ],
165
+ examples: [
166
+ [
167
+ {
168
+ name: "user",
169
+ content: { text: "Add liquidity to the SOL/USDC pool on A2A-Swap" }
170
+ },
171
+ {
172
+ name: "agent",
173
+ content: {
174
+ text: "Providing liquidity to SOL/USDC pool \u2026",
175
+ action: "A2A_PROVIDE_LIQUIDITY"
176
+ }
177
+ }
178
+ ]
179
+ ],
180
+ validate: async (_runtime, _message, _state) => true,
181
+ handler: async (_runtime, _message, _state, options, callback) => {
182
+ try {
183
+ const client = buildClient();
184
+ const keypair = loadKeypair();
185
+ const amountBStr = opt(options, "amountB");
186
+ const params = {
187
+ mintA: parseMint(opt(options, "mintA") ?? ""),
188
+ mintB: parseMint(opt(options, "mintB") ?? ""),
189
+ amountA: BigInt(opt(options, "amountA") ?? "0"),
190
+ amountB: amountBStr ? BigInt(amountBStr) : void 0,
191
+ autoCompound: opt(options, "autoCompound") === "true",
192
+ compoundThreshold: 0n,
193
+ minLp: 0n
194
+ };
195
+ const result = await client.provideLiquidity(keypair, params);
196
+ await callback?.({
197
+ text: `Liquidity provided!
198
+ Signature: ${result.signature}
199
+ Position: ${result.position.toBase58()}
200
+ Deposited: ${result.amountA} tokenA, ${result.amountB} tokenB`,
201
+ data: result
202
+ });
203
+ } catch (err) {
204
+ await callback?.({ text: `Liquidity provision failed: ${err.message}` });
205
+ }
206
+ }
207
+ };
208
+ var poolInfoAction = {
209
+ name: "A2A_POOL_INFO",
210
+ description: "Fetch A2A-Swap pool reserves, spot price, LP supply, and fee rate. Accepts: mintA, mintB (the two token mint addresses).",
211
+ similes: [
212
+ "pool info",
213
+ "pool stats",
214
+ "pool state",
215
+ "pool price",
216
+ "liquidity info",
217
+ "check pool",
218
+ "what is the price",
219
+ "how much liquidity"
220
+ ],
221
+ examples: [
222
+ [
223
+ {
224
+ name: "user",
225
+ content: { text: "What is the SOL/USDC pool price on A2A-Swap?" }
226
+ },
227
+ {
228
+ name: "agent",
229
+ content: { text: "Fetching pool info \u2026", action: "A2A_POOL_INFO" }
230
+ }
231
+ ]
232
+ ],
233
+ validate: async (_runtime, _message, _state) => true,
234
+ handler: async (_runtime, _message, _state, options, callback) => {
235
+ try {
236
+ const client = buildClient();
237
+ const info = await client.poolInfo(
238
+ parseMint(opt(options, "mintA") ?? ""),
239
+ parseMint(opt(options, "mintB") ?? "")
240
+ );
241
+ await callback?.({
242
+ text: `Pool info:
243
+ Pool: ${info.pool.toBase58()}
244
+ Reserve A: ${info.reserveA}
245
+ Reserve B: ${info.reserveB}
246
+ LP supply: ${info.lpSupply}
247
+ Fee rate: ${info.feeRateBps} bps
248
+ Spot price: ${info.spotPrice.toFixed(6)}`,
249
+ data: info
250
+ });
251
+ } catch (err) {
252
+ await callback?.({ text: `Pool info failed: ${err.message}` });
253
+ }
254
+ }
255
+ };
256
+ var myFeesAction = {
257
+ name: "A2A_MY_FEES",
258
+ description: "Show accrued trading fees across all A2A-Swap LP positions for the agent wallet.",
259
+ similes: [
260
+ "my fees",
261
+ "check fees",
262
+ "claimable fees",
263
+ "LP fees",
264
+ "earned fees",
265
+ "how much fees",
266
+ "fee summary"
267
+ ],
268
+ examples: [
269
+ [
270
+ { name: "user", content: { text: "How much fees have I earned on A2A-Swap?" } },
271
+ { name: "agent", content: { text: "Fetching fee summary \u2026", action: "A2A_MY_FEES" } }
272
+ ]
273
+ ],
274
+ validate: async (_runtime, _message, _state) => true,
275
+ handler: async (_runtime, _message, _state, _options, callback) => {
276
+ try {
277
+ const client = buildClient();
278
+ const keypair = loadKeypair();
279
+ const fees = await client.myFees(keypair.publicKey);
280
+ if (fees.positions.length === 0) {
281
+ await callback?.({ text: "No LP positions found for this agent." });
282
+ return;
283
+ }
284
+ const lines = fees.positions.map(
285
+ (p, i) => ` [${i + 1}] ${p.address.toBase58().slice(0, 8)}\u2026 LP: ${p.lpShares} fees A: ${p.totalFeesA} fees B: ${p.totalFeesB}`
286
+ );
287
+ await callback?.({
288
+ text: `Fee summary (${fees.positions.length} position${fees.positions.length > 1 ? "s" : ""}):
289
+ ` + lines.join("\n") + `
290
+ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
291
+ Total fees A: ${fees.totalFeesA}
292
+ Total fees B: ${fees.totalFeesB}`,
293
+ data: fees
294
+ });
295
+ } catch (err) {
296
+ await callback?.({ text: `Fee check failed: ${err.message}` });
297
+ }
298
+ }
299
+ };
300
+ var a2aSwapPlugin = {
301
+ name: "plugin-a2a-swap",
302
+ description: "A2A-Swap AMM \u2014 autonomous token swaps and liquidity management on Solana. Backed by a constant-product x*y=k AMM with no tick ranges, no LP token mints, and a dual-approval mode for multi-agent workflows.",
303
+ actions: [
304
+ simulateSwapAction,
305
+ swapTokensAction,
306
+ provideLiquidityAction,
307
+ poolInfoAction,
308
+ myFeesAction
309
+ ]
310
+ };
311
+ var index_default = a2aSwapPlugin;
312
+ export {
313
+ a2aSwapPlugin,
314
+ index_default as default,
315
+ myFeesAction,
316
+ poolInfoAction,
317
+ provideLiquidityAction,
318
+ simulateSwapAction,
319
+ swapTokensAction
320
+ };
Binary file
Binary file
package/package.json ADDED
@@ -0,0 +1,87 @@
1
+ {
2
+ "name": "plugin-a2a-swap",
3
+ "version": "0.1.1",
4
+ "description": "A2A-Swap plugin for ElizaOS — autonomous token swaps and liquidity management on Solana via a constant-product AMM built for AI agents",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "module": "dist/index.esm.js",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.esm.js",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "images",
18
+ "README.md"
19
+ ],
20
+ "scripts": {
21
+ "build": "tsup src/index.ts --format cjs,esm --dts --clean",
22
+ "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
23
+ "typecheck": "tsc --noEmit"
24
+ },
25
+ "keywords": [
26
+ "elizaos",
27
+ "eliza",
28
+ "plugin",
29
+ "solana",
30
+ "amm",
31
+ "defi",
32
+ "swap",
33
+ "liquidity",
34
+ "agent",
35
+ "autonomous",
36
+ "ai"
37
+ ],
38
+ "author": "A2A-Swap Contributors",
39
+ "license": "MIT",
40
+ "homepage": "https://github.com/liqdlad-rgb/a2a-swap#readme",
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "https://github.com/liqdlad-rgb/a2a-swap.git",
44
+ "directory": "plugin-a2a-swap"
45
+ },
46
+ "bugs": {
47
+ "url": "https://github.com/liqdlad-rgb/a2a-swap/issues"
48
+ },
49
+ "peerDependencies": {
50
+ "@elizaos/core": ">=1.0.0"
51
+ },
52
+ "dependencies": {
53
+ "@liqdlad/a2a-swap-sdk": "^0.1.0",
54
+ "@solana/web3.js": "^1.95.4"
55
+ },
56
+ "devDependencies": {
57
+ "@elizaos/core": "^1.0.0",
58
+ "tsup": "^8.0.0",
59
+ "typescript": "^5.3.0",
60
+ "@types/node": "^20.0.0"
61
+ },
62
+ "publishConfig": {
63
+ "access": "public"
64
+ },
65
+ "engines": {
66
+ "node": ">=18"
67
+ },
68
+ "agentConfig": {
69
+ "pluginType": "elizaos:plugin:1.0.0",
70
+ "pluginParameters": {
71
+ "SOLANA_RPC_URL": {
72
+ "type": "string",
73
+ "description": "Solana RPC endpoint URL (e.g. https://api.mainnet-beta.solana.com)",
74
+ "required": false
75
+ },
76
+ "AGENT_PRIVATE_KEY": {
77
+ "type": "string",
78
+ "description": "Agent wallet secret key as a JSON byte array (e.g. [1,2,3,...])",
79
+ "required": true,
80
+ "secret": true
81
+ }
82
+ }
83
+ },
84
+ "packageType": "plugin",
85
+ "platform": "node",
86
+ "npmPackage": "@liqdlad/plugin-a2a-swap"
87
+ }