@awaken-finance/agent-kit 1.1.0 → 1.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.
- package/README.md +26 -2
- package/awaken_trade_skill.ts +11 -11
- package/lib/aelf-client.ts +12 -6
- package/mcp-config.example.json +15 -0
- package/openclaw.json +4 -4
- package/package.json +2 -1
- package/src/core/trade.ts +31 -50
- package/src/mcp/server.ts +14 -14
package/README.md
CHANGED
|
@@ -184,12 +184,14 @@ All commands output standardized JSON on success. Errors go to stderr with `[ERR
|
|
|
184
184
|
|
|
185
185
|
2. Update the path and environment variables:
|
|
186
186
|
|
|
187
|
+
**EOA mode** (direct private key signing):
|
|
188
|
+
|
|
187
189
|
```json
|
|
188
190
|
{
|
|
189
191
|
"mcpServers": {
|
|
190
192
|
"awaken-agent-kit": {
|
|
191
193
|
"command": "bun",
|
|
192
|
-
"args": ["run", "/ABSOLUTE/PATH/TO/
|
|
194
|
+
"args": ["run", "/ABSOLUTE/PATH/TO/src/mcp/server.ts"],
|
|
193
195
|
"env": {
|
|
194
196
|
"AELF_PRIVATE_KEY": "your_private_key_here",
|
|
195
197
|
"AWAKEN_NETWORK": "mainnet"
|
|
@@ -199,6 +201,25 @@ All commands output standardized JSON on success. Errors go to stderr with `[ERR
|
|
|
199
201
|
}
|
|
200
202
|
```
|
|
201
203
|
|
|
204
|
+
**CA mode** (Portkey Contract Account):
|
|
205
|
+
|
|
206
|
+
```json
|
|
207
|
+
{
|
|
208
|
+
"mcpServers": {
|
|
209
|
+
"awaken-agent-kit": {
|
|
210
|
+
"command": "bun",
|
|
211
|
+
"args": ["run", "/ABSOLUTE/PATH/TO/src/mcp/server.ts"],
|
|
212
|
+
"env": {
|
|
213
|
+
"PORTKEY_PRIVATE_KEY": "your_manager_private_key",
|
|
214
|
+
"PORTKEY_CA_HASH": "your_ca_hash",
|
|
215
|
+
"PORTKEY_CA_ADDRESS": "your_ca_address",
|
|
216
|
+
"AWAKEN_NETWORK": "mainnet"
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
202
223
|
3. Start the MCP server manually (for debugging):
|
|
203
224
|
|
|
204
225
|
```bash
|
|
@@ -279,7 +300,10 @@ bun run test:e2e
|
|
|
279
300
|
|
|
280
301
|
| Variable | Required | Default | Description |
|
|
281
302
|
|----------|----------|---------|-------------|
|
|
282
|
-
| `AELF_PRIVATE_KEY` | For trades | — | aelf wallet private key |
|
|
303
|
+
| `AELF_PRIVATE_KEY` | For trades (EOA) | — | aelf wallet private key |
|
|
304
|
+
| `PORTKEY_PRIVATE_KEY` | For trades (CA) | — | Portkey Manager private key |
|
|
305
|
+
| `PORTKEY_CA_HASH` | For trades (CA) | — | Portkey CA hash |
|
|
306
|
+
| `PORTKEY_CA_ADDRESS` | For trades (CA) | — | Portkey CA address |
|
|
283
307
|
| `AWAKEN_NETWORK` | No | `mainnet` | `mainnet` or `testnet` |
|
|
284
308
|
| `AWAKEN_RPC_URL` | No | Per network | Override RPC endpoint |
|
|
285
309
|
| `AWAKEN_API_BASE_URL` | No | Per network | Override API endpoint |
|
package/awaken_trade_skill.ts
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
// Awaken Trade Skill - CLI Adapter (thin shell)
|
|
4
4
|
// ============================================================
|
|
5
5
|
// Commands: swap, add-liquidity, remove-liquidity, approve
|
|
6
|
-
// Requires: AELF_PRIVATE_KEY env
|
|
6
|
+
// Requires: AELF_PRIVATE_KEY (EOA) or PORTKEY_PRIVATE_KEY + CA env vars
|
|
7
7
|
// Core logic lives in src/core/trade.ts
|
|
8
8
|
|
|
9
9
|
import { Command } from 'commander';
|
|
10
|
+
import { createSignerFromEnv } from '@portkey/aelf-signer';
|
|
10
11
|
import { getNetworkConfig, DEFAULT_SLIPPAGE } from './lib/config';
|
|
11
|
-
import { getWalletByPrivateKey } from './lib/aelf-client';
|
|
12
12
|
import { outputSuccess, outputError } from './cli-helpers';
|
|
13
13
|
import { executeSwap, addLiquidity, removeLiquidity, approveTokenSpending } from './src/core/trade';
|
|
14
14
|
|
|
@@ -16,7 +16,7 @@ const program = new Command();
|
|
|
16
16
|
|
|
17
17
|
program
|
|
18
18
|
.name('awaken-trade')
|
|
19
|
-
.description('Awaken DEX trading tool (requires AELF_PRIVATE_KEY)')
|
|
19
|
+
.description('Awaken DEX trading tool (requires AELF_PRIVATE_KEY or Portkey CA env vars)')
|
|
20
20
|
.version('1.0.0')
|
|
21
21
|
.option('--network <network>', 'Network: mainnet or testnet', process.env.AWAKEN_NETWORK || 'mainnet');
|
|
22
22
|
|
|
@@ -31,8 +31,8 @@ program
|
|
|
31
31
|
.action(async (opts) => {
|
|
32
32
|
try {
|
|
33
33
|
const config = getNetworkConfig(program.opts().network);
|
|
34
|
-
const
|
|
35
|
-
const result = await executeSwap(config,
|
|
34
|
+
const signer = createSignerFromEnv();
|
|
35
|
+
const result = await executeSwap(config, signer, {
|
|
36
36
|
symbolIn: opts.symbolIn,
|
|
37
37
|
symbolOut: opts.symbolOut,
|
|
38
38
|
amountIn: opts.amountIn,
|
|
@@ -57,8 +57,8 @@ program
|
|
|
57
57
|
.action(async (opts) => {
|
|
58
58
|
try {
|
|
59
59
|
const config = getNetworkConfig(program.opts().network);
|
|
60
|
-
const
|
|
61
|
-
const result = await addLiquidity(config,
|
|
60
|
+
const signer = createSignerFromEnv();
|
|
61
|
+
const result = await addLiquidity(config, signer, {
|
|
62
62
|
tokenA: opts.tokenA,
|
|
63
63
|
tokenB: opts.tokenB,
|
|
64
64
|
amountA: opts.amountA,
|
|
@@ -84,8 +84,8 @@ program
|
|
|
84
84
|
.action(async (opts) => {
|
|
85
85
|
try {
|
|
86
86
|
const config = getNetworkConfig(program.opts().network);
|
|
87
|
-
const
|
|
88
|
-
const result = await removeLiquidity(config,
|
|
87
|
+
const signer = createSignerFromEnv();
|
|
88
|
+
const result = await removeLiquidity(config, signer, {
|
|
89
89
|
tokenA: opts.tokenA,
|
|
90
90
|
tokenB: opts.tokenB,
|
|
91
91
|
lpAmount: opts.lpAmount,
|
|
@@ -108,8 +108,8 @@ program
|
|
|
108
108
|
.action(async (opts) => {
|
|
109
109
|
try {
|
|
110
110
|
const config = getNetworkConfig(program.opts().network);
|
|
111
|
-
const
|
|
112
|
-
const result = await approveTokenSpending(config,
|
|
111
|
+
const signer = createSignerFromEnv();
|
|
112
|
+
const result = await approveTokenSpending(config, signer, {
|
|
113
113
|
symbol: opts.symbol,
|
|
114
114
|
spender: opts.spender,
|
|
115
115
|
amount: opts.amount,
|
package/lib/aelf-client.ts
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
// Awaken OpenClaw Skills - aelf SDK Client
|
|
3
3
|
// ============================================================
|
|
4
4
|
// Wraps aelf-sdk for both view (read) and send (write) contract calls.
|
|
5
|
-
//
|
|
5
|
+
// Supports both EOA and CA wallets via @portkey/aelf-signer.
|
|
6
6
|
|
|
7
7
|
import AElf from 'aelf-sdk';
|
|
8
8
|
import BigNumber from 'bignumber.js';
|
|
9
|
+
import type { AelfSigner } from '@portkey/aelf-signer';
|
|
9
10
|
import type { NetworkConfig, TxResult } from './types';
|
|
10
11
|
|
|
11
12
|
// ---- Caches ----
|
|
@@ -141,21 +142,26 @@ export async function getTokenInfo(
|
|
|
141
142
|
|
|
142
143
|
// ---- Approve ----
|
|
143
144
|
|
|
145
|
+
/**
|
|
146
|
+
* Approve a contract to spend tokens.
|
|
147
|
+
* Accepts AelfSigner (EOA or CA) — signing is handled transparently.
|
|
148
|
+
*/
|
|
144
149
|
export async function approveToken(
|
|
145
150
|
config: NetworkConfig,
|
|
146
|
-
|
|
151
|
+
signer: AelfSigner,
|
|
147
152
|
symbol: string,
|
|
148
153
|
spender: string,
|
|
149
154
|
amount: string,
|
|
150
155
|
): Promise<TxResult> {
|
|
151
|
-
const result = await
|
|
156
|
+
const result = await signer.sendContractCall(config.rpcUrl, config.tokenContract, 'Approve', {
|
|
152
157
|
symbol,
|
|
153
158
|
spender,
|
|
154
159
|
amount,
|
|
155
160
|
});
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
161
|
+
return {
|
|
162
|
+
transactionId: result.transactionId,
|
|
163
|
+
status: (result.txResult.Status || 'mined').toLowerCase(),
|
|
164
|
+
};
|
|
159
165
|
}
|
|
160
166
|
|
|
161
167
|
// ---- Utility ----
|
package/mcp-config.example.json
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
"_cursor_project": ".cursor/mcp.json (in project root)",
|
|
6
6
|
"_cursor_global": "~/.cursor/mcp.json",
|
|
7
7
|
|
|
8
|
+
"_eoa_mode": "EOA mode — direct private key signing:",
|
|
8
9
|
"mcpServers": {
|
|
9
10
|
"awaken-agent-kit": {
|
|
10
11
|
"command": "bun",
|
|
@@ -14,5 +15,19 @@
|
|
|
14
15
|
"AWAKEN_NETWORK": "mainnet"
|
|
15
16
|
}
|
|
16
17
|
}
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
"_ca_mode": "CA mode — Portkey Contract Account via ManagerForwardCall:",
|
|
21
|
+
"_mcpServers_ca_example": {
|
|
22
|
+
"awaken-agent-kit": {
|
|
23
|
+
"command": "bun",
|
|
24
|
+
"args": ["run", "/ABSOLUTE/PATH/TO/awaken-agent-skills/src/mcp/server.ts"],
|
|
25
|
+
"env": {
|
|
26
|
+
"PORTKEY_PRIVATE_KEY": "your_manager_private_key",
|
|
27
|
+
"PORTKEY_CA_HASH": "your_ca_hash",
|
|
28
|
+
"PORTKEY_CA_ADDRESS": "your_ca_address",
|
|
29
|
+
"AWAKEN_NETWORK": "mainnet"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
17
32
|
}
|
|
18
33
|
}
|
package/openclaw.json
CHANGED
|
@@ -33,25 +33,25 @@
|
|
|
33
33
|
{
|
|
34
34
|
"name": "awaken-trade-swap",
|
|
35
35
|
"command": "bun run awaken_trade_skill.ts swap --symbol-in {{symbolIn}} --symbol-out {{symbolOut}} --amount-in {{amountIn}} --slippage {{slippage}}",
|
|
36
|
-
"description": "Execute a token swap on Awaken DEX.
|
|
36
|
+
"description": "Execute a token swap on Awaken DEX. Requires wallet env vars: AELF_PRIVATE_KEY (EOA) or PORTKEY_PRIVATE_KEY + PORTKEY_CA_HASH + PORTKEY_CA_ADDRESS (CA). This sends a real on-chain transaction. Parameters: --symbol-in (token to sell), --symbol-out (token to buy), --amount-in (human-readable amount to sell), --slippage (tolerance, default 0.005 = 0.5%). The tool auto-queries the best route, approves if needed, and executes the swap. Returns: transactionId, estimated amounts, explorer URL.",
|
|
37
37
|
"cwd": "."
|
|
38
38
|
},
|
|
39
39
|
{
|
|
40
40
|
"name": "awaken-trade-add-liquidity",
|
|
41
41
|
"command": "bun run awaken_trade_skill.ts add-liquidity --token-a {{tokenA}} --token-b {{tokenB}} --amount-a {{amountA}} --amount-b {{amountB}} --fee-rate {{feeRate}}",
|
|
42
|
-
"description": "Add liquidity to an Awaken DEX trading pair.
|
|
42
|
+
"description": "Add liquidity to an Awaken DEX trading pair. Requires wallet env vars (EOA or CA). Parameters: --token-a and --token-b (token symbols), --amount-a and --amount-b (human-readable amounts), --fee-rate (pool fee tier, default 0.3), --slippage (tolerance, default 0.005). Auto-approves both tokens before adding.",
|
|
43
43
|
"cwd": "."
|
|
44
44
|
},
|
|
45
45
|
{
|
|
46
46
|
"name": "awaken-trade-remove-liquidity",
|
|
47
47
|
"command": "bun run awaken_trade_skill.ts remove-liquidity --token-a {{tokenA}} --token-b {{tokenB}} --lp-amount {{lpAmount}} --fee-rate {{feeRate}}",
|
|
48
|
-
"description": "Remove liquidity from an Awaken DEX trading pair.
|
|
48
|
+
"description": "Remove liquidity from an Awaken DEX trading pair. Requires wallet env vars (EOA or CA). Parameters: --token-a and --token-b (token symbols), --lp-amount (LP token amount to burn), --fee-rate (pool fee tier, default 0.3). Returns the underlying tokens to your wallet.",
|
|
49
49
|
"cwd": "."
|
|
50
50
|
},
|
|
51
51
|
{
|
|
52
52
|
"name": "awaken-trade-approve",
|
|
53
53
|
"command": "bun run awaken_trade_skill.ts approve --symbol {{symbol}} --spender {{spender}} --amount {{amount}}",
|
|
54
|
-
"description": "Approve a contract to spend your tokens.
|
|
54
|
+
"description": "Approve a contract to spend your tokens. Requires wallet env vars (EOA or CA). Parameters: --symbol (token to approve), --spender (contract address), --amount (human-readable amount). Use this before swap/liquidity if you need manual control over approvals.",
|
|
55
55
|
"cwd": "."
|
|
56
56
|
},
|
|
57
57
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@awaken-finance/agent-kit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "AI Agent toolkit for Awaken DEX on aelf blockchain — swap tokens, manage liquidity, fetch K-line data. Supports MCP, CLI, and SDK usage.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -63,6 +63,7 @@
|
|
|
63
63
|
"dependencies": {
|
|
64
64
|
"@microsoft/signalr": "^8.0.0",
|
|
65
65
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
66
|
+
"@portkey/aelf-signer": "^1.0.0",
|
|
66
67
|
"aelf-sdk": "^3.4.8",
|
|
67
68
|
"axios": "^1.7.0",
|
|
68
69
|
"bignumber.js": "^9.1.2",
|
package/src/core/trade.ts
CHANGED
|
@@ -12,14 +12,12 @@ import {
|
|
|
12
12
|
CHANNEL_ID,
|
|
13
13
|
SWAP_LABS_FEE_RATE,
|
|
14
14
|
} from '../../lib/config';
|
|
15
|
+
import type { AelfSigner } from '@portkey/aelf-signer';
|
|
15
16
|
import {
|
|
16
|
-
getWalletByPrivateKey,
|
|
17
|
-
callSendMethod,
|
|
18
17
|
callViewMethod,
|
|
19
18
|
getTokenInfo,
|
|
20
19
|
getAllowance,
|
|
21
20
|
approveToken,
|
|
22
|
-
getTxResult,
|
|
23
21
|
timesDecimals,
|
|
24
22
|
divDecimals,
|
|
25
23
|
} from '../../lib/aelf-client';
|
|
@@ -33,24 +31,23 @@ import type {
|
|
|
33
31
|
LiquidityRemoveResult,
|
|
34
32
|
ApproveParams,
|
|
35
33
|
ApproveResult,
|
|
36
|
-
TxResult,
|
|
37
34
|
} from '../../lib/types';
|
|
38
35
|
|
|
39
36
|
// ---- Helper: ensure approval ----
|
|
40
37
|
|
|
41
38
|
async function ensureApproval(
|
|
42
39
|
config: NetworkConfig,
|
|
43
|
-
|
|
40
|
+
signer: AelfSigner,
|
|
44
41
|
symbol: string,
|
|
45
42
|
spender: string,
|
|
46
43
|
requiredAmount: string,
|
|
47
44
|
): Promise<void> {
|
|
48
|
-
const owner =
|
|
45
|
+
const owner = signer.address;
|
|
49
46
|
const currentAllowance = await getAllowance(config.rpcUrl, config.tokenContract, symbol, owner, spender);
|
|
50
47
|
|
|
51
48
|
if (new BigNumber(currentAllowance).lt(requiredAmount)) {
|
|
52
49
|
const approveAmount = new BigNumber(requiredAmount).times(10).toFixed(0);
|
|
53
|
-
await approveToken(config,
|
|
50
|
+
await approveToken(config, signer, symbol, spender, approveAmount);
|
|
54
51
|
}
|
|
55
52
|
}
|
|
56
53
|
|
|
@@ -58,10 +55,10 @@ async function ensureApproval(
|
|
|
58
55
|
|
|
59
56
|
export async function executeSwap(
|
|
60
57
|
config: NetworkConfig,
|
|
61
|
-
|
|
58
|
+
signer: AelfSigner,
|
|
62
59
|
params: SwapParams,
|
|
63
60
|
): Promise<SwapResult> {
|
|
64
|
-
const account =
|
|
61
|
+
const account = signer.address;
|
|
65
62
|
const slippage = params.slippage || DEFAULT_SLIPPAGE;
|
|
66
63
|
|
|
67
64
|
// 1. Get token info
|
|
@@ -109,28 +106,23 @@ export async function executeSwap(
|
|
|
109
106
|
const swapHookAddress = config.swapHookContract;
|
|
110
107
|
|
|
111
108
|
// 5. Approve input token to swap hook contract
|
|
112
|
-
await ensureApproval(config,
|
|
109
|
+
await ensureApproval(config, signer, params.symbolIn, swapHookAddress, rawAmountIn);
|
|
113
110
|
|
|
114
|
-
// 6. Execute swap via
|
|
115
|
-
const
|
|
111
|
+
// 6. Execute swap via signer (EOA: direct sign, CA: ManagerForwardCall)
|
|
112
|
+
const sendResult = await signer.sendContractCall(config.rpcUrl, swapHookAddress, 'SwapExactTokensForTokens', {
|
|
116
113
|
swapTokens,
|
|
117
114
|
labsFeeRate: SWAP_LABS_FEE_RATE,
|
|
118
115
|
});
|
|
119
116
|
|
|
120
|
-
const txId = result?.TransactionId || result?.transactionId;
|
|
121
|
-
if (!txId) throw new Error('Swap failed: no transactionId returned');
|
|
122
|
-
|
|
123
|
-
const txResult = await getTxResult(config.rpcUrl, txId);
|
|
124
|
-
|
|
125
117
|
return {
|
|
126
|
-
transactionId:
|
|
127
|
-
status: txResult.
|
|
118
|
+
transactionId: sendResult.transactionId,
|
|
119
|
+
status: (sendResult.txResult.Status || 'mined').toLowerCase(),
|
|
128
120
|
symbolIn: params.symbolIn,
|
|
129
121
|
symbolOut: params.symbolOut,
|
|
130
122
|
amountIn: params.amountIn,
|
|
131
123
|
estimatedAmountOut: divDecimals(rawAmountOut, tokenOutInfo.decimals).toFixed(),
|
|
132
124
|
minAmountOut: divDecimals(amountOutMin, tokenOutInfo.decimals).toFixed(),
|
|
133
|
-
explorerUrl: `${config.explorerUrl}/tx/${
|
|
125
|
+
explorerUrl: `${config.explorerUrl}/tx/${sendResult.transactionId}`,
|
|
134
126
|
};
|
|
135
127
|
}
|
|
136
128
|
|
|
@@ -138,10 +130,10 @@ export async function executeSwap(
|
|
|
138
130
|
|
|
139
131
|
export async function addLiquidity(
|
|
140
132
|
config: NetworkConfig,
|
|
141
|
-
|
|
133
|
+
signer: AelfSigner,
|
|
142
134
|
params: LiquidityAddParams,
|
|
143
135
|
): Promise<LiquidityAddResult> {
|
|
144
|
-
const account =
|
|
136
|
+
const account = signer.address;
|
|
145
137
|
const feeRate = params.feeRate || '0.3';
|
|
146
138
|
const slippage = params.slippage || DEFAULT_SLIPPAGE;
|
|
147
139
|
|
|
@@ -160,12 +152,12 @@ export async function addLiquidity(
|
|
|
160
152
|
|
|
161
153
|
// Approve both tokens
|
|
162
154
|
await Promise.all([
|
|
163
|
-
ensureApproval(config,
|
|
164
|
-
ensureApproval(config,
|
|
155
|
+
ensureApproval(config, signer, params.tokenA, routerAddress, rawAmountA),
|
|
156
|
+
ensureApproval(config, signer, params.tokenB, routerAddress, rawAmountB),
|
|
165
157
|
]);
|
|
166
158
|
|
|
167
|
-
// Execute addLiquidity
|
|
168
|
-
const
|
|
159
|
+
// Execute addLiquidity via signer
|
|
160
|
+
const sendResult = await signer.sendContractCall(config.rpcUrl, routerAddress, 'AddLiquidity', {
|
|
169
161
|
symbolA: params.tokenA,
|
|
170
162
|
symbolB: params.tokenB,
|
|
171
163
|
amountADesired: rawAmountA,
|
|
@@ -177,20 +169,15 @@ export async function addLiquidity(
|
|
|
177
169
|
channel: CHANNEL_ID,
|
|
178
170
|
});
|
|
179
171
|
|
|
180
|
-
const txId = result?.TransactionId || result?.transactionId;
|
|
181
|
-
if (!txId) throw new Error('Add liquidity failed: no transactionId');
|
|
182
|
-
|
|
183
|
-
const txResult = await getTxResult(config.rpcUrl, txId);
|
|
184
|
-
|
|
185
172
|
return {
|
|
186
|
-
transactionId:
|
|
187
|
-
status: txResult.
|
|
173
|
+
transactionId: sendResult.transactionId,
|
|
174
|
+
status: (sendResult.txResult.Status || 'mined').toLowerCase(),
|
|
188
175
|
tokenA: params.tokenA,
|
|
189
176
|
tokenB: params.tokenB,
|
|
190
177
|
amountA: params.amountA,
|
|
191
178
|
amountB: params.amountB,
|
|
192
179
|
feeRate,
|
|
193
|
-
explorerUrl: `${config.explorerUrl}/tx/${
|
|
180
|
+
explorerUrl: `${config.explorerUrl}/tx/${sendResult.transactionId}`,
|
|
194
181
|
};
|
|
195
182
|
}
|
|
196
183
|
|
|
@@ -198,10 +185,10 @@ export async function addLiquidity(
|
|
|
198
185
|
|
|
199
186
|
export async function removeLiquidity(
|
|
200
187
|
config: NetworkConfig,
|
|
201
|
-
|
|
188
|
+
signer: AelfSigner,
|
|
202
189
|
params: LiquidityRemoveParams,
|
|
203
190
|
): Promise<LiquidityRemoveResult> {
|
|
204
|
-
const account =
|
|
191
|
+
const account = signer.address;
|
|
205
192
|
const feeRate = params.feeRate || '0.3';
|
|
206
193
|
|
|
207
194
|
const LP_DECIMALS = 8;
|
|
@@ -221,16 +208,15 @@ export async function removeLiquidity(
|
|
|
221
208
|
spender: routerAddress,
|
|
222
209
|
});
|
|
223
210
|
if (new BigNumber(currentAllowance?.allowance ?? '0').lt(rawLiquidity)) {
|
|
224
|
-
|
|
211
|
+
await signer.sendContractCall(config.rpcUrl, factoryAddress, 'Approve', {
|
|
225
212
|
symbol: lpSymbol,
|
|
226
213
|
spender: routerAddress,
|
|
227
214
|
amount: new BigNumber(rawLiquidity).times(10).toFixed(0),
|
|
228
215
|
});
|
|
229
|
-
const approveTxId = approveResult?.TransactionId || approveResult?.transactionId;
|
|
230
|
-
if (approveTxId) await getTxResult(config.rpcUrl, approveTxId);
|
|
231
216
|
}
|
|
232
217
|
|
|
233
|
-
|
|
218
|
+
// Remove liquidity via signer
|
|
219
|
+
const sendResult = await signer.sendContractCall(config.rpcUrl, routerAddress, 'RemoveLiquidity', {
|
|
234
220
|
symbolA: params.tokenA,
|
|
235
221
|
symbolB: params.tokenB,
|
|
236
222
|
amountAMin: '1',
|
|
@@ -240,18 +226,13 @@ export async function removeLiquidity(
|
|
|
240
226
|
deadline: { seconds: getDeadline(), nanos: 0 },
|
|
241
227
|
});
|
|
242
228
|
|
|
243
|
-
const txId = result?.TransactionId || result?.transactionId;
|
|
244
|
-
if (!txId) throw new Error('Remove liquidity failed: no transactionId');
|
|
245
|
-
|
|
246
|
-
const txResult = await getTxResult(config.rpcUrl, txId);
|
|
247
|
-
|
|
248
229
|
return {
|
|
249
|
-
transactionId:
|
|
250
|
-
status: txResult.
|
|
230
|
+
transactionId: sendResult.transactionId,
|
|
231
|
+
status: (sendResult.txResult.Status || 'mined').toLowerCase(),
|
|
251
232
|
tokenA: params.tokenA,
|
|
252
233
|
tokenB: params.tokenB,
|
|
253
234
|
lpAmount: params.lpAmount,
|
|
254
|
-
explorerUrl: `${config.explorerUrl}/tx/${
|
|
235
|
+
explorerUrl: `${config.explorerUrl}/tx/${sendResult.transactionId}`,
|
|
255
236
|
};
|
|
256
237
|
}
|
|
257
238
|
|
|
@@ -259,13 +240,13 @@ export async function removeLiquidity(
|
|
|
259
240
|
|
|
260
241
|
export async function approveTokenSpending(
|
|
261
242
|
config: NetworkConfig,
|
|
262
|
-
|
|
243
|
+
signer: AelfSigner,
|
|
263
244
|
params: ApproveParams,
|
|
264
245
|
): Promise<ApproveResult> {
|
|
265
246
|
const tokenInfo = await getTokenInfo(config.rpcUrl, config.tokenContract, params.symbol);
|
|
266
247
|
const rawAmount = timesDecimals(params.amount, tokenInfo.decimals).toFixed(0);
|
|
267
248
|
|
|
268
|
-
const txResult = await approveToken(config,
|
|
249
|
+
const txResult = await approveToken(config, signer, params.symbol, params.spender, rawAmount);
|
|
269
250
|
|
|
270
251
|
return {
|
|
271
252
|
transactionId: txResult.transactionId,
|
package/src/mcp/server.ts
CHANGED
|
@@ -12,8 +12,8 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
|
12
12
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
13
13
|
import { z } from 'zod';
|
|
14
14
|
|
|
15
|
+
import { createSignerFromEnv } from '@portkey/aelf-signer';
|
|
15
16
|
import { getNetworkConfig } from '../../lib/config';
|
|
16
|
-
import { getWalletByPrivateKey } from '../../lib/aelf-client';
|
|
17
17
|
import { getQuote, getPair, getTokenBalance, getTokenAllowance, getLiquidityPositions } from '../core/query';
|
|
18
18
|
import { executeSwap, addLiquidity, removeLiquidity, approveTokenSpending } from '../core/trade';
|
|
19
19
|
import { fetchKline, getKlineIntervals } from '../core/kline';
|
|
@@ -151,14 +151,14 @@ server.registerTool(
|
|
|
151
151
|
);
|
|
152
152
|
|
|
153
153
|
// ============================================================
|
|
154
|
-
// Trade Tools (require AELF_PRIVATE_KEY env
|
|
154
|
+
// Trade Tools (require AELF_PRIVATE_KEY or PORTKEY_PRIVATE_KEY + CA env vars)
|
|
155
155
|
// ============================================================
|
|
156
156
|
|
|
157
157
|
server.registerTool(
|
|
158
158
|
'awaken_swap',
|
|
159
159
|
{
|
|
160
160
|
description:
|
|
161
|
-
'Execute a token swap on Awaken DEX.
|
|
161
|
+
'Execute a token swap on Awaken DEX. Requires wallet env vars (AELF_PRIVATE_KEY for EOA, or PORTKEY_PRIVATE_KEY + PORTKEY_CA_HASH + PORTKEY_CA_ADDRESS for CA). Sends a real on-chain transaction. Auto-queries the best route, approves if needed, and executes the swap. Returns transactionId, estimated amounts, explorer URL.',
|
|
162
162
|
inputSchema: {
|
|
163
163
|
symbolIn: z.string().describe('Token to sell (e.g. ELF)'),
|
|
164
164
|
symbolOut: z.string().describe('Token to buy (e.g. USDT)'),
|
|
@@ -170,8 +170,8 @@ server.registerTool(
|
|
|
170
170
|
async ({ symbolIn, symbolOut, amountIn, slippage, network }) => {
|
|
171
171
|
try {
|
|
172
172
|
const config = getNetworkConfig(network);
|
|
173
|
-
const
|
|
174
|
-
const result = await executeSwap(config,
|
|
173
|
+
const signer = createSignerFromEnv();
|
|
174
|
+
const result = await executeSwap(config, signer, { symbolIn, symbolOut, amountIn, slippage });
|
|
175
175
|
return ok(result);
|
|
176
176
|
} catch (err) {
|
|
177
177
|
return fail(err);
|
|
@@ -183,7 +183,7 @@ server.registerTool(
|
|
|
183
183
|
'awaken_add_liquidity',
|
|
184
184
|
{
|
|
185
185
|
description:
|
|
186
|
-
'Add liquidity to an Awaken DEX trading pair.
|
|
186
|
+
'Add liquidity to an Awaken DEX trading pair. Requires wallet env vars (EOA or CA). Auto-approves both tokens before adding.',
|
|
187
187
|
inputSchema: {
|
|
188
188
|
tokenA: z.string().describe('Token A symbol (e.g. ELF)'),
|
|
189
189
|
tokenB: z.string().describe('Token B symbol (e.g. USDT)'),
|
|
@@ -197,8 +197,8 @@ server.registerTool(
|
|
|
197
197
|
async ({ tokenA, tokenB, amountA, amountB, feeRate, slippage, network }) => {
|
|
198
198
|
try {
|
|
199
199
|
const config = getNetworkConfig(network);
|
|
200
|
-
const
|
|
201
|
-
const result = await addLiquidity(config,
|
|
200
|
+
const signer = createSignerFromEnv();
|
|
201
|
+
const result = await addLiquidity(config, signer, { tokenA, tokenB, amountA, amountB, feeRate, slippage });
|
|
202
202
|
return ok(result);
|
|
203
203
|
} catch (err) {
|
|
204
204
|
return fail(err);
|
|
@@ -210,7 +210,7 @@ server.registerTool(
|
|
|
210
210
|
'awaken_remove_liquidity',
|
|
211
211
|
{
|
|
212
212
|
description:
|
|
213
|
-
'Remove liquidity from an Awaken DEX trading pair.
|
|
213
|
+
'Remove liquidity from an Awaken DEX trading pair. Requires wallet env vars (EOA or CA). Returns the underlying tokens to your wallet.',
|
|
214
214
|
inputSchema: {
|
|
215
215
|
tokenA: z.string().describe('Token A symbol'),
|
|
216
216
|
tokenB: z.string().describe('Token B symbol'),
|
|
@@ -222,8 +222,8 @@ server.registerTool(
|
|
|
222
222
|
async ({ tokenA, tokenB, lpAmount, feeRate, network }) => {
|
|
223
223
|
try {
|
|
224
224
|
const config = getNetworkConfig(network);
|
|
225
|
-
const
|
|
226
|
-
const result = await removeLiquidity(config,
|
|
225
|
+
const signer = createSignerFromEnv();
|
|
226
|
+
const result = await removeLiquidity(config, signer, { tokenA, tokenB, lpAmount, feeRate });
|
|
227
227
|
return ok(result);
|
|
228
228
|
} catch (err) {
|
|
229
229
|
return fail(err);
|
|
@@ -235,7 +235,7 @@ server.registerTool(
|
|
|
235
235
|
'awaken_approve',
|
|
236
236
|
{
|
|
237
237
|
description:
|
|
238
|
-
'Approve a contract to spend your tokens.
|
|
238
|
+
'Approve a contract to spend your tokens. Requires wallet env vars (EOA or CA). Use this before swap/liquidity if you need manual control over approvals.',
|
|
239
239
|
inputSchema: {
|
|
240
240
|
symbol: z.string().describe('Token to approve (e.g. ELF)'),
|
|
241
241
|
spender: z.string().describe('Contract address to approve'),
|
|
@@ -246,8 +246,8 @@ server.registerTool(
|
|
|
246
246
|
async ({ symbol, spender, amount, network }) => {
|
|
247
247
|
try {
|
|
248
248
|
const config = getNetworkConfig(network);
|
|
249
|
-
const
|
|
250
|
-
const result = await approveTokenSpending(config,
|
|
249
|
+
const signer = createSignerFromEnv();
|
|
250
|
+
const result = await approveTokenSpending(config, signer, { symbol, spender, amount });
|
|
251
251
|
return ok(result);
|
|
252
252
|
} catch (err) {
|
|
253
253
|
return fail(err);
|