logiqical 0.4.0 → 0.5.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 +113 -25
- package/dist/admin.mjs +2946 -0
- package/dist/vault.mjs +271 -0
- package/package.json +7 -4
- package/skills/logiqical/CLAUDE.md +180 -0
- package/skills/logiqical/CODEX.md +48 -0
package/dist/vault.mjs
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
#!/usr/bin/env node
|
|
3
|
+
|
|
4
|
+
// src/cli/vault.ts
|
|
5
|
+
import { createServer } from "http";
|
|
6
|
+
import { Wallet, JsonRpcProvider, ethers } from "ethers";
|
|
7
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
8
|
+
import { join } from "path";
|
|
9
|
+
import { homedir } from "os";
|
|
10
|
+
var CONFIG_DIR = join(homedir(), ".logiqical");
|
|
11
|
+
var KEYS_DIR = join(CONFIG_DIR, "keys");
|
|
12
|
+
var VAULT_STATE_FILE = join(CONFIG_DIR, "vault-state.json");
|
|
13
|
+
var DEFAULT_PORT = 7842;
|
|
14
|
+
function loadConfig() {
|
|
15
|
+
const configFile = join(CONFIG_DIR, "config.json");
|
|
16
|
+
if (existsSync(configFile)) return JSON.parse(readFileSync(configFile, "utf-8"));
|
|
17
|
+
return {};
|
|
18
|
+
}
|
|
19
|
+
function loadVaultState() {
|
|
20
|
+
if (existsSync(VAULT_STATE_FILE)) {
|
|
21
|
+
return JSON.parse(readFileSync(VAULT_STATE_FILE, "utf-8"));
|
|
22
|
+
}
|
|
23
|
+
const config = loadConfig();
|
|
24
|
+
return {
|
|
25
|
+
spentThisHour: "0",
|
|
26
|
+
spentToday: "0",
|
|
27
|
+
hourStart: Date.now(),
|
|
28
|
+
dayStart: Date.now(),
|
|
29
|
+
policy: config.policy || {}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function saveVaultState(state) {
|
|
33
|
+
if (!existsSync(CONFIG_DIR)) mkdirSync(CONFIG_DIR, { recursive: true });
|
|
34
|
+
writeFileSync(VAULT_STATE_FILE, JSON.stringify(state, null, 2));
|
|
35
|
+
}
|
|
36
|
+
function resetBudgetPeriods(state) {
|
|
37
|
+
const now = Date.now();
|
|
38
|
+
if (now - state.hourStart > 36e5) {
|
|
39
|
+
state.spentThisHour = "0";
|
|
40
|
+
state.hourStart = now;
|
|
41
|
+
}
|
|
42
|
+
if (now - state.dayStart > 864e5) {
|
|
43
|
+
state.spentToday = "0";
|
|
44
|
+
state.dayStart = now;
|
|
45
|
+
}
|
|
46
|
+
return state;
|
|
47
|
+
}
|
|
48
|
+
function checkPolicy(policy, tx, state) {
|
|
49
|
+
const valueWei = BigInt(tx.value || "0");
|
|
50
|
+
const valueEth = parseFloat(ethers.formatEther(valueWei));
|
|
51
|
+
if (policy.maxPerTx) {
|
|
52
|
+
const max = parseFloat(policy.maxPerTx);
|
|
53
|
+
if (valueEth > max) return `Transaction value ${valueEth} exceeds max per tx (${max})`;
|
|
54
|
+
}
|
|
55
|
+
if (policy.maxPerHour) {
|
|
56
|
+
const max = parseFloat(policy.maxPerHour);
|
|
57
|
+
const spent = parseFloat(state.spentThisHour);
|
|
58
|
+
if (spent + valueEth > max) return `Would exceed hourly budget (${spent + valueEth} > ${max})`;
|
|
59
|
+
}
|
|
60
|
+
if (policy.maxPerDay) {
|
|
61
|
+
const max = parseFloat(policy.maxPerDay);
|
|
62
|
+
const spent = parseFloat(state.spentToday);
|
|
63
|
+
if (spent + valueEth > max) return `Would exceed daily budget (${spent + valueEth} > ${max})`;
|
|
64
|
+
}
|
|
65
|
+
if (policy.allowedContracts && policy.allowedContracts.length > 0) {
|
|
66
|
+
const allowed = policy.allowedContracts.map((a) => a.toLowerCase());
|
|
67
|
+
if (!allowed.includes(tx.to.toLowerCase())) {
|
|
68
|
+
return `Contract ${tx.to} not in allowlist`;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (policy.blockedContracts && policy.blockedContracts.length > 0) {
|
|
72
|
+
const blocked = policy.blockedContracts.map((b) => b.toLowerCase());
|
|
73
|
+
if (blocked.includes(tx.to.toLowerCase())) {
|
|
74
|
+
return `Contract ${tx.to} is blocked`;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
function createVaultServer(wallet, provider, state) {
|
|
80
|
+
async function readBody(req) {
|
|
81
|
+
return new Promise((resolve, reject) => {
|
|
82
|
+
let data = "";
|
|
83
|
+
req.on("data", (chunk) => {
|
|
84
|
+
data += chunk.toString();
|
|
85
|
+
});
|
|
86
|
+
req.on("end", () => {
|
|
87
|
+
try {
|
|
88
|
+
resolve(JSON.parse(data));
|
|
89
|
+
} catch {
|
|
90
|
+
reject(new Error("Invalid JSON"));
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
function json(res, statusCode, body) {
|
|
96
|
+
res.writeHead(statusCode, { "Content-Type": "application/json" });
|
|
97
|
+
res.end(JSON.stringify(body));
|
|
98
|
+
}
|
|
99
|
+
return async (req, res) => {
|
|
100
|
+
const remoteAddr = req.socket.remoteAddress;
|
|
101
|
+
if (remoteAddr !== "127.0.0.1" && remoteAddr !== "::1" && remoteAddr !== "::ffff:127.0.0.1") {
|
|
102
|
+
return json(res, 403, { error: "Vault only accepts localhost connections" });
|
|
103
|
+
}
|
|
104
|
+
const url = req.url || "/";
|
|
105
|
+
const method = req.method || "GET";
|
|
106
|
+
try {
|
|
107
|
+
if (url === "/health" && method === "GET") {
|
|
108
|
+
return json(res, 200, { status: "ok", address: wallet.address });
|
|
109
|
+
}
|
|
110
|
+
if (url === "/address" && method === "GET") {
|
|
111
|
+
return json(res, 200, { address: wallet.address });
|
|
112
|
+
}
|
|
113
|
+
if (url === "/policy" && method === "GET") {
|
|
114
|
+
return json(res, 200, { policy: state.policy });
|
|
115
|
+
}
|
|
116
|
+
if (url === "/policy" && method === "POST") {
|
|
117
|
+
const body = await readBody(req);
|
|
118
|
+
state.policy = { ...state.policy, ...body };
|
|
119
|
+
saveVaultState(state);
|
|
120
|
+
return json(res, 200, { policy: state.policy });
|
|
121
|
+
}
|
|
122
|
+
if (url === "/budget" && method === "GET") {
|
|
123
|
+
state = resetBudgetPeriods(state);
|
|
124
|
+
return json(res, 200, {
|
|
125
|
+
spentThisHour: state.spentThisHour,
|
|
126
|
+
spentToday: state.spentToday,
|
|
127
|
+
hourlyLimit: state.policy.maxPerHour || null,
|
|
128
|
+
dailyLimit: state.policy.maxPerDay || null,
|
|
129
|
+
hourlyRemaining: state.policy.maxPerHour ? String(Math.max(0, parseFloat(state.policy.maxPerHour) - parseFloat(state.spentThisHour))) : null,
|
|
130
|
+
dailyRemaining: state.policy.maxPerDay ? String(Math.max(0, parseFloat(state.policy.maxPerDay) - parseFloat(state.spentToday))) : null
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
if (url === "/sign" && method === "POST") {
|
|
134
|
+
const body = await readBody(req);
|
|
135
|
+
const { to, data, value, chainId, gasLimit } = body;
|
|
136
|
+
if (!to) return json(res, 400, { error: "Missing 'to' field" });
|
|
137
|
+
state = resetBudgetPeriods(state);
|
|
138
|
+
const policyError = checkPolicy(state.policy, { to, value: value || "0" }, state);
|
|
139
|
+
if (policyError) {
|
|
140
|
+
return json(res, 403, { error: policyError, code: "POLICY_VIOLATION" });
|
|
141
|
+
}
|
|
142
|
+
if (state.policy.simulateBeforeSend) {
|
|
143
|
+
try {
|
|
144
|
+
await provider.call({
|
|
145
|
+
to,
|
|
146
|
+
data,
|
|
147
|
+
value: value ? BigInt(value) : void 0,
|
|
148
|
+
from: wallet.address
|
|
149
|
+
});
|
|
150
|
+
} catch (e) {
|
|
151
|
+
return json(res, 400, {
|
|
152
|
+
error: `Simulation failed: ${e.reason || e.message || "would revert"}`,
|
|
153
|
+
code: "SIMULATION_FAILED"
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (state.policy.dryRun) {
|
|
158
|
+
return json(res, 200, {
|
|
159
|
+
signedTx: null,
|
|
160
|
+
dryRun: true,
|
|
161
|
+
message: "Dry run \u2014 transaction not signed"
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
const tx = { to, data: data || "0x", value: value || "0" };
|
|
165
|
+
if (gasLimit) tx.gasLimit = gasLimit;
|
|
166
|
+
if (chainId) tx.chainId = chainId;
|
|
167
|
+
const signedTx = await wallet.signTransaction(tx);
|
|
168
|
+
const valueWei = BigInt(value || "0");
|
|
169
|
+
if (valueWei > 0n) {
|
|
170
|
+
const valueEth = parseFloat(ethers.formatEther(valueWei));
|
|
171
|
+
state.spentThisHour = String(parseFloat(state.spentThisHour) + valueEth);
|
|
172
|
+
state.spentToday = String(parseFloat(state.spentToday) + valueEth);
|
|
173
|
+
saveVaultState(state);
|
|
174
|
+
}
|
|
175
|
+
return json(res, 200, { signedTx });
|
|
176
|
+
}
|
|
177
|
+
if (url === "/sign-message" && method === "POST") {
|
|
178
|
+
const body = await readBody(req);
|
|
179
|
+
if (!body.message) return json(res, 400, { error: "Missing 'message' field" });
|
|
180
|
+
const signature = await wallet.signMessage(body.message);
|
|
181
|
+
return json(res, 200, { signature });
|
|
182
|
+
}
|
|
183
|
+
if (url === "/sign-typed-data" && method === "POST") {
|
|
184
|
+
const body = await readBody(req);
|
|
185
|
+
const { domain, types, value } = body;
|
|
186
|
+
if (!domain || !types || !value) {
|
|
187
|
+
return json(res, 400, { error: "Missing domain, types, or value" });
|
|
188
|
+
}
|
|
189
|
+
const signature = await wallet.signTypedData(domain, types, value);
|
|
190
|
+
return json(res, 200, { signature });
|
|
191
|
+
}
|
|
192
|
+
if (url === "/broadcast" && method === "POST") {
|
|
193
|
+
const body = await readBody(req);
|
|
194
|
+
if (!body.signedTx) return json(res, 400, { error: "Missing 'signedTx' field" });
|
|
195
|
+
const txResponse = await provider.broadcastTransaction(body.signedTx);
|
|
196
|
+
return json(res, 200, {
|
|
197
|
+
hash: txResponse.hash,
|
|
198
|
+
nonce: txResponse.nonce
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
return json(res, 404, { error: `Unknown endpoint: ${method} ${url}` });
|
|
202
|
+
} catch (e) {
|
|
203
|
+
return json(res, 500, { error: e.message });
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
async function main() {
|
|
208
|
+
const args = process.argv.slice(2).filter((a) => a !== "vault");
|
|
209
|
+
const portArg = args.indexOf("--port");
|
|
210
|
+
const port = portArg >= 0 ? parseInt(args[portArg + 1]) : parseInt(process.env.LOGIQICAL_VAULT_PORT || String(DEFAULT_PORT));
|
|
211
|
+
console.log("");
|
|
212
|
+
console.log(" \x1B[1mLogiqical Vault Daemon\x1B[0m");
|
|
213
|
+
console.log(" \x1B[2mSigns transactions, enforces policies. Keys never leave this process.\x1B[0m");
|
|
214
|
+
console.log("");
|
|
215
|
+
const keystorePath = join(KEYS_DIR, "agent.json");
|
|
216
|
+
if (!existsSync(keystorePath)) {
|
|
217
|
+
console.error(" No wallet found. Run: logiqical setup");
|
|
218
|
+
process.exit(1);
|
|
219
|
+
}
|
|
220
|
+
const config = loadConfig();
|
|
221
|
+
const password = config.password || "logiqical-agent";
|
|
222
|
+
console.log(" Loading keystore...");
|
|
223
|
+
const keystoreData = JSON.parse(readFileSync(keystorePath, "utf-8"));
|
|
224
|
+
const decrypted = await Wallet.fromEncryptedJson(keystoreData.encryptedJson, password);
|
|
225
|
+
const rpcUrl = config.rpcUrl || "https://api.avax.network/ext/bc/C/rpc";
|
|
226
|
+
const provider = new JsonRpcProvider(rpcUrl, 43114);
|
|
227
|
+
const wallet = new Wallet(decrypted.privateKey, provider);
|
|
228
|
+
let state = loadVaultState();
|
|
229
|
+
state = resetBudgetPeriods(state);
|
|
230
|
+
console.log(` Address: \x1B[32m${wallet.address}\x1B[0m`);
|
|
231
|
+
console.log(` Network: Avalanche C-Chain`);
|
|
232
|
+
console.log(` Port: ${port}`);
|
|
233
|
+
if (state.policy.maxPerTx || state.policy.maxPerDay) {
|
|
234
|
+
console.log(` Policy: max/tx: ${state.policy.maxPerTx || "none"}, max/day: ${state.policy.maxPerDay || "none"}, simulate: ${state.policy.simulateBeforeSend ?? false}`);
|
|
235
|
+
} else {
|
|
236
|
+
console.log(" Policy: \x1B[33mnone set \u2014 all transactions will be signed\x1B[0m");
|
|
237
|
+
}
|
|
238
|
+
const server = createServer(createVaultServer(wallet, provider, state));
|
|
239
|
+
server.listen(port, "127.0.0.1", () => {
|
|
240
|
+
console.log("");
|
|
241
|
+
console.log(` \x1B[32mVault running on http://127.0.0.1:${port}\x1B[0m`);
|
|
242
|
+
console.log("");
|
|
243
|
+
console.log(" Endpoints:");
|
|
244
|
+
console.log(" GET /health \u2014 health check");
|
|
245
|
+
console.log(" GET /address \u2014 wallet address");
|
|
246
|
+
console.log(" GET /policy \u2014 current policy");
|
|
247
|
+
console.log(" POST /policy \u2014 update policy");
|
|
248
|
+
console.log(" GET /budget \u2014 spending budget status");
|
|
249
|
+
console.log(" POST /sign \u2014 sign a transaction (policy-enforced)");
|
|
250
|
+
console.log(" POST /sign-message \u2014 sign an arbitrary message");
|
|
251
|
+
console.log(" POST /sign-typed-data \u2014 sign EIP-712 typed data");
|
|
252
|
+
console.log(" POST /broadcast \u2014 broadcast signed tx");
|
|
253
|
+
console.log("");
|
|
254
|
+
console.log(" \x1B[2mPress Ctrl+C to stop\x1B[0m");
|
|
255
|
+
});
|
|
256
|
+
process.on("SIGINT", () => {
|
|
257
|
+
console.log("\n Shutting down vault...");
|
|
258
|
+
saveVaultState(state);
|
|
259
|
+
server.close();
|
|
260
|
+
process.exit(0);
|
|
261
|
+
});
|
|
262
|
+
process.on("SIGTERM", () => {
|
|
263
|
+
saveVaultState(state);
|
|
264
|
+
server.close();
|
|
265
|
+
process.exit(0);
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
main().catch((e) => {
|
|
269
|
+
console.error("Error:", e.message);
|
|
270
|
+
process.exit(1);
|
|
271
|
+
});
|
package/package.json
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "logiqical",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Agent wallet SDK for Avalanche + Arena —
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "Agent wallet SDK for Avalanche + Arena — 91 MCP tools, admin CLI, vault daemon, skill packs. No backend needed.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"bin": {
|
|
9
|
-
"logiqical
|
|
9
|
+
"logiqical": "dist/admin.mjs",
|
|
10
|
+
"logiqical-mcp": "dist/cli.mjs",
|
|
11
|
+
"logiqical-vault": "dist/vault.mjs"
|
|
10
12
|
},
|
|
11
13
|
"exports": {
|
|
12
14
|
".": {
|
|
@@ -16,7 +18,8 @@
|
|
|
16
18
|
}
|
|
17
19
|
},
|
|
18
20
|
"files": [
|
|
19
|
-
"dist"
|
|
21
|
+
"dist",
|
|
22
|
+
"skills"
|
|
20
23
|
],
|
|
21
24
|
"scripts": {
|
|
22
25
|
"build": "tsup",
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# Logiqical Agent SDK
|
|
2
|
+
|
|
3
|
+
You have access to the Logiqical SDK — a non-custodial agent wallet for Avalanche and Arena with 91 MCP tools across 15 modules.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
The agent wallet is already booted. Use MCP tools directly. No imports needed.
|
|
8
|
+
|
|
9
|
+
## Core Concepts
|
|
10
|
+
|
|
11
|
+
- **Every on-chain action goes through MCP tools** — you call tools, they sign and broadcast
|
|
12
|
+
- **Spending policies are enforced automatically** — per-tx limits, hourly/daily budgets, simulation
|
|
13
|
+
- **Arena API key is required** for social, perps, and tickets tools (set via `ARENA_API_KEY` env var)
|
|
14
|
+
|
|
15
|
+
## Available Tools (91 total)
|
|
16
|
+
|
|
17
|
+
### Wallet (4 tools)
|
|
18
|
+
- `get_address` — your agent wallet address
|
|
19
|
+
- `get_balance` — AVAX balance
|
|
20
|
+
- `send_avax` — send AVAX to any address
|
|
21
|
+
- `sign_message` — sign arbitrary messages
|
|
22
|
+
|
|
23
|
+
### ARENA Token (6 tools)
|
|
24
|
+
- `get_balances` — AVAX + ARENA balances
|
|
25
|
+
- `swap_quote_buy` — quote AVAX to ARENA
|
|
26
|
+
- `swap_quote_sell` — quote ARENA to AVAX
|
|
27
|
+
- `swap_buy_arena` — buy ARENA with AVAX
|
|
28
|
+
- `swap_sell_arena` — sell ARENA for AVAX
|
|
29
|
+
|
|
30
|
+
### Staking (4 tools)
|
|
31
|
+
- `stake_info` — staked amount + pending rewards
|
|
32
|
+
- `stake_arena` — stake ARENA tokens
|
|
33
|
+
- `unstake_arena` — unstake + claim rewards
|
|
34
|
+
- `buy_and_stake` — buy ARENA + stake in one tx
|
|
35
|
+
|
|
36
|
+
### DEX — Any Token Swap (6 tools)
|
|
37
|
+
- `dex_tokens` — list known tokens
|
|
38
|
+
- `dex_token_info` — look up any ERC-20 by address
|
|
39
|
+
- `dex_balance` — check any token balance
|
|
40
|
+
- `dex_quote` — quote any token pair
|
|
41
|
+
- `dex_swap` — swap any tokens on Avalanche
|
|
42
|
+
|
|
43
|
+
### Launchpad (6 tools)
|
|
44
|
+
- `launchpad_overview` — platform stats
|
|
45
|
+
- `launchpad_recent` — recently launched tokens
|
|
46
|
+
- `launchpad_token` — full token info by ID
|
|
47
|
+
- `launchpad_quote` — bonding curve price quote
|
|
48
|
+
- `launchpad_buy` — buy a launchpad token
|
|
49
|
+
- `launchpad_sell` — sell a launchpad token
|
|
50
|
+
|
|
51
|
+
### Tickets (8 tools)
|
|
52
|
+
- `tickets_buy_price` / `tickets_sell_price` — price quotes
|
|
53
|
+
- `tickets_balance` — ticket balance
|
|
54
|
+
- `tickets_supply` — total supply
|
|
55
|
+
- `tickets_fees` — fee structure
|
|
56
|
+
- `tickets_buy` / `tickets_sell` — buy/sell tickets
|
|
57
|
+
|
|
58
|
+
### Bridge — Cross-Chain (8 tools)
|
|
59
|
+
- `bridge_info` — supported chains + USDC addresses
|
|
60
|
+
- `bridge_chains` — all supported chains
|
|
61
|
+
- `bridge_tokens` — tokens on specified chains
|
|
62
|
+
- `bridge_quote` — bridge quote with transaction
|
|
63
|
+
- `bridge_routes` — multiple route options
|
|
64
|
+
- `bridge_status` — check transfer status
|
|
65
|
+
|
|
66
|
+
### Perps — Perpetual Futures (12 tools)
|
|
67
|
+
- `perps_register` — register for Hyperliquid perps
|
|
68
|
+
- `perps_registration_status` — check registration
|
|
69
|
+
- `perps_wallet_address` — get Hyperliquid wallet
|
|
70
|
+
- `perps_trading_pairs` — all 250+ pairs
|
|
71
|
+
- `perps_update_leverage` — set leverage (1-50x)
|
|
72
|
+
- `perps_place_order` — place orders
|
|
73
|
+
- `perps_cancel_orders` — cancel orders
|
|
74
|
+
- `perps_close_position` — close a position
|
|
75
|
+
- `perps_orders` — view open orders
|
|
76
|
+
- `perps_positions` — positions + margin summary
|
|
77
|
+
- `perps_deposit_info` — Hyperliquid deposit addresses
|
|
78
|
+
- `perps_arbitrum_usdc_balance` — USDC balance on Arbitrum
|
|
79
|
+
- `perps_deposit_usdc` — build USDC deposit tx
|
|
80
|
+
|
|
81
|
+
### Signals Intelligence (6 tools)
|
|
82
|
+
- `signals_market` — price, funding, OI, volume
|
|
83
|
+
- `signals_technical` — SMA, RSI, trend, support/resistance
|
|
84
|
+
- `signals_whales` — whale positions from orderbook
|
|
85
|
+
- `signals_funding` — funding rate extremes
|
|
86
|
+
- `signals_summary` — full signal digest + verdict
|
|
87
|
+
- `signals_scan` — scan all markets for opportunities
|
|
88
|
+
|
|
89
|
+
### Social (14 tools)
|
|
90
|
+
- `social_search_users` — search Arena users
|
|
91
|
+
- `social_user_by_handle` — get user by handle
|
|
92
|
+
- `social_me` — your Arena profile
|
|
93
|
+
- `social_top_users` — top users
|
|
94
|
+
- `social_follow` / `social_unfollow` — follow/unfollow
|
|
95
|
+
- `social_update_profile` — update profile
|
|
96
|
+
- `social_conversations` — list chats
|
|
97
|
+
- `social_send_message` — send a message
|
|
98
|
+
- `social_messages` — read messages
|
|
99
|
+
- `social_create_thread` — create a post
|
|
100
|
+
- `social_like_thread` — like a thread
|
|
101
|
+
- `social_post_trade` — auto-post a trade update
|
|
102
|
+
|
|
103
|
+
### Agent Registration (1 tool)
|
|
104
|
+
- `agent_register` — register a new AI agent on Arena (returns API key)
|
|
105
|
+
|
|
106
|
+
### Copy Trading (3 tools)
|
|
107
|
+
- `copy_get_positions` — get target wallet positions
|
|
108
|
+
- `copy_calculate_orders` — calculate mirror orders
|
|
109
|
+
- `copy_execute` — one-shot copy trade
|
|
110
|
+
|
|
111
|
+
### Market Data (6 tools)
|
|
112
|
+
- `market_price` — prices, 24h change, market cap
|
|
113
|
+
- `market_trending` — trending coins
|
|
114
|
+
- `market_top` — top by market cap
|
|
115
|
+
- `market_search` — search coins
|
|
116
|
+
- `market_avax_price` / `market_arena_price` — quick price checks
|
|
117
|
+
|
|
118
|
+
### DeFi (8 tools)
|
|
119
|
+
- `defi_savax_info` — sAVAX exchange rate + balances
|
|
120
|
+
- `defi_savax_quote` — quote AVAX to sAVAX
|
|
121
|
+
- `defi_savax_stake` — stake AVAX to sAVAX
|
|
122
|
+
- `defi_savax_unstake` — unstake sAVAX
|
|
123
|
+
- `defi_vault_info` — ERC-4626 vault info
|
|
124
|
+
- `defi_vault_quote` — vault deposit quote
|
|
125
|
+
- `defi_vault_deposit` — deposit into vault
|
|
126
|
+
- `defi_vault_withdraw` — withdraw from vault
|
|
127
|
+
|
|
128
|
+
### Policy (3 tools)
|
|
129
|
+
- `policy_get` — current spending policy
|
|
130
|
+
- `policy_set` — replace policy
|
|
131
|
+
- `policy_budget` — budget status (spent today, remaining)
|
|
132
|
+
|
|
133
|
+
### Contract Call (1 tool)
|
|
134
|
+
- `call_contract` — call any smart contract method
|
|
135
|
+
|
|
136
|
+
## Patterns
|
|
137
|
+
|
|
138
|
+
### Before trading, always check balances first
|
|
139
|
+
```
|
|
140
|
+
1. get_balance (check AVAX)
|
|
141
|
+
2. get_balances (check ARENA)
|
|
142
|
+
3. Then swap/trade
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Before perps, check registration
|
|
146
|
+
```
|
|
147
|
+
1. perps_registration_status
|
|
148
|
+
2. If not registered: perps_register
|
|
149
|
+
3. Then trade
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### For copy trading
|
|
153
|
+
```
|
|
154
|
+
1. copy_get_positions (see what the target holds)
|
|
155
|
+
2. copy_calculate_orders (see what you'd need to do)
|
|
156
|
+
3. copy_execute (or execute manually with perps_place_order)
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### For cross-chain operations
|
|
160
|
+
```
|
|
161
|
+
1. bridge_info (get chain IDs and token addresses)
|
|
162
|
+
2. bridge_quote (get quote + tx)
|
|
163
|
+
3. Execute the bridge tx
|
|
164
|
+
4. bridge_status (poll until complete)
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Always check policy before large trades
|
|
168
|
+
```
|
|
169
|
+
1. policy_budget (check remaining budget)
|
|
170
|
+
2. If over limit, inform the user
|
|
171
|
+
3. policy_set to adjust if user approves
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Important Notes
|
|
175
|
+
|
|
176
|
+
- All on-chain transactions are real and irreversible. Always confirm with the user before executing trades.
|
|
177
|
+
- The agent wallet's private key is stored in an encrypted keystore at `~/.logiqical/keys/agent.json`.
|
|
178
|
+
- Spending policies are your guardrails. Never disable simulation without the user's explicit consent.
|
|
179
|
+
- Arena API rate limits: 10 posts/hour, 120 orders/hour, 100 reads/minute.
|
|
180
|
+
- For perps, Arena holds the signing keys. Orders go through Arena's API, not direct on-chain.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Logiqical Agent SDK — Codex Instructions
|
|
2
|
+
|
|
3
|
+
You are an AI agent with a non-custodial wallet on Avalanche. You have 91 tools across 15 modules for DeFi, trading, social, and more.
|
|
4
|
+
|
|
5
|
+
## Your Capabilities
|
|
6
|
+
|
|
7
|
+
You can:
|
|
8
|
+
- **Trade**: Swap any token on Avalanche, buy/sell ARENA, trade launchpad tokens
|
|
9
|
+
- **Perps**: Trade 250+ perpetual futures on Hyperliquid (up to 50x leverage)
|
|
10
|
+
- **Copy Trade**: Mirror any Hyperliquid wallet's positions
|
|
11
|
+
- **Stake**: Stake ARENA for rewards, liquid stake AVAX to sAVAX
|
|
12
|
+
- **Bridge**: Move tokens across 20+ EVM chains
|
|
13
|
+
- **Social**: Post to Arena feed, chat, follow users, auto-post trade updates
|
|
14
|
+
- **Analyze**: Market signals, whale tracking, funding rates, technical analysis
|
|
15
|
+
- **DeFi**: Deposit into ERC-4626 vaults, liquid staking
|
|
16
|
+
|
|
17
|
+
## How to Trade
|
|
18
|
+
|
|
19
|
+
Always follow this flow:
|
|
20
|
+
1. Check your balance first (`get_balance`, `get_balances`, `dex_balance`)
|
|
21
|
+
2. Get a quote (`dex_quote`, `swap_quote_buy`, `launchpad_quote`)
|
|
22
|
+
3. Confirm with the user
|
|
23
|
+
4. Execute (`dex_swap`, `swap_buy_arena`, `launchpad_buy`)
|
|
24
|
+
|
|
25
|
+
## How to Analyze Markets
|
|
26
|
+
|
|
27
|
+
1. Quick check: `market_avax_price`, `market_arena_price`, `market_price`
|
|
28
|
+
2. Deep analysis: `signals_summary` for full market + technical + whale data
|
|
29
|
+
3. Scan opportunities: `signals_scan` to find the best setups across all markets
|
|
30
|
+
4. Funding plays: `signals_funding` to find extreme funding rates
|
|
31
|
+
|
|
32
|
+
## How to Copy Trade
|
|
33
|
+
|
|
34
|
+
1. `copy_get_positions` — see what the target wallet holds
|
|
35
|
+
2. `copy_calculate_orders` — calculate what you need to match them
|
|
36
|
+
3. `copy_execute` — execute all mirror orders in one shot
|
|
37
|
+
|
|
38
|
+
## Spending Policies
|
|
39
|
+
|
|
40
|
+
Your wallet has spending limits. Check with `policy_budget` before large trades.
|
|
41
|
+
If a trade is rejected by policy, tell the user and suggest adjusting with `policy_set`.
|
|
42
|
+
|
|
43
|
+
## Safety Rules
|
|
44
|
+
|
|
45
|
+
- Always confirm trades with the user before executing
|
|
46
|
+
- Check balances before every trade
|
|
47
|
+
- Never disable spending policies without explicit user consent
|
|
48
|
+
- All transactions are real and irreversible on the blockchain
|