recon-crypto-mcp 0.1.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/LICENSE +21 -0
- package/README.md +153 -0
- package/dist/abis/aave-pool.d.ts +174 -0
- package/dist/abis/aave-pool.js +101 -0
- package/dist/abis/aave-pool.js.map +1 -0
- package/dist/abis/aave-ui-pool-data-provider.d.ts +232 -0
- package/dist/abis/aave-ui-pool-data-provider.js +107 -0
- package/dist/abis/aave-ui-pool-data-provider.js.map +1 -0
- package/dist/abis/access-control.d.ts +94 -0
- package/dist/abis/access-control.js +51 -0
- package/dist/abis/access-control.js.map +1 -0
- package/dist/abis/compound-comet.d.ts +120 -0
- package/dist/abis/compound-comet.js +84 -0
- package/dist/abis/compound-comet.js.map +1 -0
- package/dist/abis/eigenlayer-delegation-manager.d.ts +23 -0
- package/dist/abis/eigenlayer-delegation-manager.js +18 -0
- package/dist/abis/eigenlayer-delegation-manager.js.map +1 -0
- package/dist/abis/eigenlayer-strategy-manager.d.ts +53 -0
- package/dist/abis/eigenlayer-strategy-manager.js +47 -0
- package/dist/abis/eigenlayer-strategy-manager.js.map +1 -0
- package/dist/abis/erc20.d.ts +78 -0
- package/dist/abis/erc20.js +10 -0
- package/dist/abis/erc20.js.map +1 -0
- package/dist/abis/lido.d.ts +80 -0
- package/dist/abis/lido.js +60 -0
- package/dist/abis/lido.js.map +1 -0
- package/dist/abis/morpho-blue.d.ts +321 -0
- package/dist/abis/morpho-blue.js +193 -0
- package/dist/abis/morpho-blue.js.map +1 -0
- package/dist/abis/uniswap-pool.d.ts +70 -0
- package/dist/abis/uniswap-pool.js +53 -0
- package/dist/abis/uniswap-pool.js.map +1 -0
- package/dist/abis/uniswap-position-manager.d.ts +71 -0
- package/dist/abis/uniswap-position-manager.js +41 -0
- package/dist/abis/uniswap-position-manager.js.map +1 -0
- package/dist/config/cache.d.ts +12 -0
- package/dist/config/cache.js +12 -0
- package/dist/config/cache.js.map +1 -0
- package/dist/config/chains.d.ts +24 -0
- package/dist/config/chains.js +158 -0
- package/dist/config/chains.js.map +1 -0
- package/dist/config/contracts.d.ts +107 -0
- package/dist/config/contracts.js +123 -0
- package/dist/config/contracts.js.map +1 -0
- package/dist/config/user-config.d.ts +15 -0
- package/dist/config/user-config.js +93 -0
- package/dist/config/user-config.js.map +1 -0
- package/dist/data/apis/etherscan.d.ts +30 -0
- package/dist/data/apis/etherscan.js +109 -0
- package/dist/data/apis/etherscan.js.map +1 -0
- package/dist/data/cache.d.ts +18 -0
- package/dist/data/cache.js +47 -0
- package/dist/data/cache.js.map +1 -0
- package/dist/data/format.d.ts +6 -0
- package/dist/data/format.js +44 -0
- package/dist/data/format.js.map +1 -0
- package/dist/data/prices.d.ts +12 -0
- package/dist/data/prices.js +81 -0
- package/dist/data/prices.js.map +1 -0
- package/dist/data/rpc.d.ts +17 -0
- package/dist/data/rpc.js +68 -0
- package/dist/data/rpc.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +344 -0
- package/dist/index.js.map +1 -0
- package/dist/modules/balances/index.d.ts +20 -0
- package/dist/modules/balances/index.js +49 -0
- package/dist/modules/balances/index.js.map +1 -0
- package/dist/modules/balances/schemas.d.ts +32 -0
- package/dist/modules/balances/schemas.js +21 -0
- package/dist/modules/balances/schemas.js.map +1 -0
- package/dist/modules/bitcoin/index.d.ts +26 -0
- package/dist/modules/bitcoin/index.js +128 -0
- package/dist/modules/bitcoin/index.js.map +1 -0
- package/dist/modules/bitcoin/schemas.d.ts +49 -0
- package/dist/modules/bitcoin/schemas.js +51 -0
- package/dist/modules/bitcoin/schemas.js.map +1 -0
- package/dist/modules/bitcoin/send.d.ts +52 -0
- package/dist/modules/bitcoin/send.js +158 -0
- package/dist/modules/bitcoin/send.js.map +1 -0
- package/dist/modules/bitcoin/utxo.d.ts +99 -0
- package/dist/modules/bitcoin/utxo.js +116 -0
- package/dist/modules/bitcoin/utxo.js.map +1 -0
- package/dist/modules/compound/actions.d.ts +8 -0
- package/dist/modules/compound/actions.js +154 -0
- package/dist/modules/compound/actions.js.map +1 -0
- package/dist/modules/compound/index.d.ts +26 -0
- package/dist/modules/compound/index.js +141 -0
- package/dist/modules/compound/index.js.map +1 -0
- package/dist/modules/compound/schemas.d.ts +95 -0
- package/dist/modules/compound/schemas.js +37 -0
- package/dist/modules/compound/schemas.js.map +1 -0
- package/dist/modules/execution/index.d.ts +51 -0
- package/dist/modules/execution/index.js +271 -0
- package/dist/modules/execution/index.js.map +1 -0
- package/dist/modules/execution/schemas.d.ts +183 -0
- package/dist/modules/execution/schemas.js +88 -0
- package/dist/modules/execution/schemas.js.map +1 -0
- package/dist/modules/feedback/index.d.ts +28 -0
- package/dist/modules/feedback/index.js +161 -0
- package/dist/modules/feedback/index.js.map +1 -0
- package/dist/modules/feedback/rate-limit.d.ts +15 -0
- package/dist/modules/feedback/rate-limit.js +110 -0
- package/dist/modules/feedback/rate-limit.js.map +1 -0
- package/dist/modules/feedback/schemas.d.ts +41 -0
- package/dist/modules/feedback/schemas.js +40 -0
- package/dist/modules/feedback/schemas.js.map +1 -0
- package/dist/modules/morpho/actions.d.ts +8 -0
- package/dist/modules/morpho/actions.js +265 -0
- package/dist/modules/morpho/actions.js.map +1 -0
- package/dist/modules/morpho/index.d.ts +26 -0
- package/dist/modules/morpho/index.js +94 -0
- package/dist/modules/morpho/index.js.map +1 -0
- package/dist/modules/morpho/schemas.d.ts +130 -0
- package/dist/modules/morpho/schemas.js +34 -0
- package/dist/modules/morpho/schemas.js.map +1 -0
- package/dist/modules/portfolio/index.d.ts +3 -0
- package/dist/modules/portfolio/index.js +197 -0
- package/dist/modules/portfolio/index.js.map +1 -0
- package/dist/modules/portfolio/schemas.d.ts +20 -0
- package/dist/modules/portfolio/schemas.js +15 -0
- package/dist/modules/portfolio/schemas.js.map +1 -0
- package/dist/modules/positions/aave.d.ts +22 -0
- package/dist/modules/positions/aave.js +197 -0
- package/dist/modules/positions/aave.js.map +1 -0
- package/dist/modules/positions/actions.d.ts +18 -0
- package/dist/modules/positions/actions.js +205 -0
- package/dist/modules/positions/actions.js.map +1 -0
- package/dist/modules/positions/index.d.ts +37 -0
- package/dist/modules/positions/index.js +59 -0
- package/dist/modules/positions/index.js.map +1 -0
- package/dist/modules/positions/schemas.d.ts +55 -0
- package/dist/modules/positions/schemas.js +25 -0
- package/dist/modules/positions/schemas.js.map +1 -0
- package/dist/modules/positions/uniswap.d.ts +4 -0
- package/dist/modules/positions/uniswap.js +181 -0
- package/dist/modules/positions/uniswap.js.map +1 -0
- package/dist/modules/prices/index.d.ts +19 -0
- package/dist/modules/prices/index.js +22 -0
- package/dist/modules/prices/index.js.map +1 -0
- package/dist/modules/security/index.d.ts +26 -0
- package/dist/modules/security/index.js +13 -0
- package/dist/modules/security/index.js.map +1 -0
- package/dist/modules/security/permissions.d.ts +8 -0
- package/dist/modules/security/permissions.js +96 -0
- package/dist/modules/security/permissions.js.map +1 -0
- package/dist/modules/security/risk-score.d.ts +18 -0
- package/dist/modules/security/risk-score.js +116 -0
- package/dist/modules/security/risk-score.js.map +1 -0
- package/dist/modules/security/schemas.d.ts +31 -0
- package/dist/modules/security/schemas.js +16 -0
- package/dist/modules/security/schemas.js.map +1 -0
- package/dist/modules/security/verification.d.ts +4 -0
- package/dist/modules/security/verification.js +82 -0
- package/dist/modules/security/verification.js.map +1 -0
- package/dist/modules/shared/approval.d.ts +71 -0
- package/dist/modules/shared/approval.js +130 -0
- package/dist/modules/shared/approval.js.map +1 -0
- package/dist/modules/staking/actions.d.ts +22 -0
- package/dist/modules/staking/actions.js +100 -0
- package/dist/modules/staking/actions.js.map +1 -0
- package/dist/modules/staking/eigenlayer.d.ts +14 -0
- package/dist/modules/staking/eigenlayer.js +105 -0
- package/dist/modules/staking/eigenlayer.js.map +1 -0
- package/dist/modules/staking/index.d.ts +24 -0
- package/dist/modules/staking/index.js +59 -0
- package/dist/modules/staking/index.js.map +1 -0
- package/dist/modules/staking/lido.d.ts +14 -0
- package/dist/modules/staking/lido.js +113 -0
- package/dist/modules/staking/lido.js.map +1 -0
- package/dist/modules/staking/schemas.d.ts +34 -0
- package/dist/modules/staking/schemas.js +20 -0
- package/dist/modules/staking/schemas.js.map +1 -0
- package/dist/modules/swap/index.d.ts +47 -0
- package/dist/modules/swap/index.js +376 -0
- package/dist/modules/swap/index.js.map +1 -0
- package/dist/modules/swap/lifi.d.ts +17 -0
- package/dist/modules/swap/lifi.js +44 -0
- package/dist/modules/swap/lifi.js.map +1 -0
- package/dist/modules/swap/oneinch.d.ts +26 -0
- package/dist/modules/swap/oneinch.js +33 -0
- package/dist/modules/swap/oneinch.js.map +1 -0
- package/dist/modules/swap/schemas.d.ts +65 -0
- package/dist/modules/swap/schemas.js +46 -0
- package/dist/modules/swap/schemas.js.map +1 -0
- package/dist/setup.d.ts +2 -0
- package/dist/setup.js +257 -0
- package/dist/setup.js.map +1 -0
- package/dist/signing/pre-sign-check.d.ts +8 -0
- package/dist/signing/pre-sign-check.js +231 -0
- package/dist/signing/pre-sign-check.js.map +1 -0
- package/dist/signing/session.d.ts +28 -0
- package/dist/signing/session.js +26 -0
- package/dist/signing/session.js.map +1 -0
- package/dist/signing/tx-store.d.ts +29 -0
- package/dist/signing/tx-store.js +85 -0
- package/dist/signing/tx-store.js.map +1 -0
- package/dist/signing/walletconnect.d.ts +33 -0
- package/dist/signing/walletconnect.js +226 -0
- package/dist/signing/walletconnect.js.map +1 -0
- package/dist/types/index.d.ts +222 -0
- package/dist/types/index.js +18 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +134 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { SignClient } from "@walletconnect/sign-client";
|
|
2
|
+
import { getSdkError } from "@walletconnect/utils";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { CHAIN_IDS } from "../types/index.js";
|
|
5
|
+
import { readUserConfig, patchUserConfig, resolveWalletConnectProjectId, getConfigDir, } from "../config/user-config.js";
|
|
6
|
+
/**
|
|
7
|
+
* Default WalletConnect Cloud project ID. Users should provide their own via
|
|
8
|
+
* WALLETCONNECT_PROJECT_ID or `recon-crypto-mcp-setup` — the default is a placeholder
|
|
9
|
+
* that will 401 against production relay. We keep a constant here so the code
|
|
10
|
+
* compiles; `getProjectId()` will throw if a real ID is not set.
|
|
11
|
+
*/
|
|
12
|
+
const DEFAULT_PROJECT_ID = "";
|
|
13
|
+
/**
|
|
14
|
+
* EVM namespace requested when proposing a session. We deliberately omit
|
|
15
|
+
* `personal_sign` and `eth_signTypedData_v4` — no tool in this server produces
|
|
16
|
+
* either, so requesting them would be an over-broad capability grant. Blind
|
|
17
|
+
* typed-data signing is the canonical Permit2 / off-chain-order phishing
|
|
18
|
+
* surface; scoping the session away from it means a compromised process can't
|
|
19
|
+
* issue those requests against a live pairing without reconnecting (which the
|
|
20
|
+
* user would see prompted on their device).
|
|
21
|
+
*/
|
|
22
|
+
export const REQUIRED_NAMESPACES = {
|
|
23
|
+
eip155: {
|
|
24
|
+
methods: [
|
|
25
|
+
"eth_sendTransaction",
|
|
26
|
+
"eth_signTransaction",
|
|
27
|
+
"eth_chainId",
|
|
28
|
+
],
|
|
29
|
+
chains: Object.values(CHAIN_IDS).map((id) => `eip155:${id}`),
|
|
30
|
+
events: ["accountsChanged", "chainChanged"],
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
let client = null;
|
|
34
|
+
let currentSession = null;
|
|
35
|
+
/**
|
|
36
|
+
* Set when the last liveness check timed out (peer didn't respond within the
|
|
37
|
+
* window) rather than returning an explicit "session not found". We keep the
|
|
38
|
+
* local session record in that case — the peer may just be offline — but
|
|
39
|
+
* surface the ambiguity via `getSessionStatus()` so callers don't treat the
|
|
40
|
+
* session as confirmed-alive.
|
|
41
|
+
*/
|
|
42
|
+
let peerUnreachable = false;
|
|
43
|
+
export function isPeerUnreachable() {
|
|
44
|
+
return peerUnreachable;
|
|
45
|
+
}
|
|
46
|
+
function getProjectId() {
|
|
47
|
+
const id = resolveWalletConnectProjectId(readUserConfig()) || DEFAULT_PROJECT_ID;
|
|
48
|
+
if (!id) {
|
|
49
|
+
throw new Error("No WalletConnect project ID configured. Set WALLETCONNECT_PROJECT_ID in your env or re-run `recon-crypto-mcp-setup`. " +
|
|
50
|
+
"Create a free project at https://cloud.walletconnect.com.");
|
|
51
|
+
}
|
|
52
|
+
return id;
|
|
53
|
+
}
|
|
54
|
+
export async function getSignClient() {
|
|
55
|
+
if (client)
|
|
56
|
+
return client;
|
|
57
|
+
// Persist WC symkey/pairing/session state under ~/.recon-crypto-mcp so it survives process exit.
|
|
58
|
+
// Without this, the SignClient defaults to an unstorage path in cwd — which Claude Code
|
|
59
|
+
// kills on exit, leaving the saved session topic useless (no keys to decrypt the relay).
|
|
60
|
+
const storageDbPath = join(getConfigDir(), "walletconnect.db");
|
|
61
|
+
client = await SignClient.init({
|
|
62
|
+
projectId: getProjectId(),
|
|
63
|
+
metadata: {
|
|
64
|
+
name: "Recon Crypto MCP",
|
|
65
|
+
description: "MCP server that prepares DeFi transactions for Ledger Live signing.",
|
|
66
|
+
url: "https://github.com/szhygulin/recon-crypto-mcp",
|
|
67
|
+
icons: [],
|
|
68
|
+
},
|
|
69
|
+
storageOptions: { database: storageDbPath },
|
|
70
|
+
});
|
|
71
|
+
// Attempt to restore the most recent session. Prefer the explicit topic from user config,
|
|
72
|
+
// but fall back to the most recent active session if the topic is missing or stale (can
|
|
73
|
+
// happen if the user manually edited config or the session expired and was renewed).
|
|
74
|
+
const cfg = readUserConfig();
|
|
75
|
+
const topic = cfg?.walletConnect?.sessionTopic;
|
|
76
|
+
const all = client.session.getAll();
|
|
77
|
+
if (topic) {
|
|
78
|
+
const match = all.find((s) => s.topic === topic);
|
|
79
|
+
if (match)
|
|
80
|
+
currentSession = match;
|
|
81
|
+
}
|
|
82
|
+
if (!currentSession && all.length > 0) {
|
|
83
|
+
currentSession = all[all.length - 1];
|
|
84
|
+
patchUserConfig({
|
|
85
|
+
walletConnect: {
|
|
86
|
+
sessionTopic: currentSession.topic,
|
|
87
|
+
pairingTopic: currentSession.pairingTopic,
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
// Verify the restored session is still live on the relay. Three outcomes:
|
|
92
|
+
// - alive: peer ack'd, keep using it.
|
|
93
|
+
// - dead: peer rejected (session was ended on their side), drop it locally.
|
|
94
|
+
// - unknown: ping timed out — peer is offline or the relay is slow. Keep
|
|
95
|
+
// the record so a future launch (when peer is back online) can
|
|
96
|
+
// resume without re-pairing, but flag `peerUnreachable` so
|
|
97
|
+
// callers don't assume the session is usable.
|
|
98
|
+
if (currentSession) {
|
|
99
|
+
const liveness = await verifySessionAlive(client, currentSession.topic);
|
|
100
|
+
if (liveness === "dead") {
|
|
101
|
+
try {
|
|
102
|
+
await client.session.delete(currentSession.topic, getSdkError("USER_DISCONNECTED"));
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// Session record may already be gone; ignore.
|
|
106
|
+
}
|
|
107
|
+
currentSession = null;
|
|
108
|
+
peerUnreachable = false;
|
|
109
|
+
patchUserConfig({
|
|
110
|
+
walletConnect: { sessionTopic: undefined, pairingTopic: undefined },
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
peerUnreachable = liveness === "unknown";
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return client;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Ping the peer over the relay with a short timeout. WC's ping resolves when
|
|
121
|
+
* the peer acknowledges; it rejects promptly if the peer has no matching
|
|
122
|
+
* session (explicit "dead"); and it hangs if the peer is offline (we surface
|
|
123
|
+
* that as "unknown" via the timeout branch, so callers can distinguish it
|
|
124
|
+
* from a confirmed rejection).
|
|
125
|
+
*/
|
|
126
|
+
async function verifySessionAlive(c, topic) {
|
|
127
|
+
const PING_TIMEOUT_MS = 5_000;
|
|
128
|
+
let timedOut = false;
|
|
129
|
+
try {
|
|
130
|
+
await Promise.race([
|
|
131
|
+
c.ping({ topic }),
|
|
132
|
+
new Promise((_, reject) => setTimeout(() => {
|
|
133
|
+
timedOut = true;
|
|
134
|
+
reject(new Error("ping timeout"));
|
|
135
|
+
}, PING_TIMEOUT_MS)),
|
|
136
|
+
]);
|
|
137
|
+
return "alive";
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
return timedOut ? "unknown" : "dead";
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/** Create a new pairing + session proposal. The returned URI is what the user scans in Ledger Live. */
|
|
144
|
+
export async function initiatePairing() {
|
|
145
|
+
const c = await getSignClient();
|
|
146
|
+
const { uri, approval } = await c.connect({ requiredNamespaces: REQUIRED_NAMESPACES });
|
|
147
|
+
if (!uri)
|
|
148
|
+
throw new Error("WalletConnect did not return a pairing URI.");
|
|
149
|
+
return {
|
|
150
|
+
uri,
|
|
151
|
+
approval: (async () => {
|
|
152
|
+
const session = await approval();
|
|
153
|
+
currentSession = session;
|
|
154
|
+
patchUserConfig({
|
|
155
|
+
walletConnect: {
|
|
156
|
+
sessionTopic: session.topic,
|
|
157
|
+
pairingTopic: session.pairingTopic,
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
return session;
|
|
161
|
+
})(),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
export function getCurrentSession() {
|
|
165
|
+
return currentSession;
|
|
166
|
+
}
|
|
167
|
+
/** Return the list of EVM accounts exposed by the connected wallet (across all namespaces). */
|
|
168
|
+
export async function getConnectedAccounts() {
|
|
169
|
+
if (!currentSession)
|
|
170
|
+
await getSignClient(); // ensure restoration attempted
|
|
171
|
+
if (!currentSession)
|
|
172
|
+
return [];
|
|
173
|
+
const accounts = [];
|
|
174
|
+
const ns = currentSession.namespaces.eip155;
|
|
175
|
+
if (!ns)
|
|
176
|
+
return [];
|
|
177
|
+
for (const entry of ns.accounts) {
|
|
178
|
+
// format: "eip155:1:0xabc..."
|
|
179
|
+
const parts = entry.split(":");
|
|
180
|
+
if (parts.length === 3 && /^0x[a-fA-F0-9]{40}$/.test(parts[2])) {
|
|
181
|
+
accounts.push(parts[2]);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return accounts;
|
|
185
|
+
}
|
|
186
|
+
/** Send an `eth_sendTransaction` request. Ledger Live shows it, user signs on device, we get tx hash back. */
|
|
187
|
+
export async function requestSendTransaction(tx) {
|
|
188
|
+
const c = await getSignClient();
|
|
189
|
+
if (!currentSession) {
|
|
190
|
+
throw new Error("No active WalletConnect session. Pair Ledger Live first via `pair_ledger_live` or `recon-crypto-mcp-setup`.");
|
|
191
|
+
}
|
|
192
|
+
const chainId = CHAIN_IDS[tx.chain];
|
|
193
|
+
const from = tx.from ?? (await getConnectedAccounts())[0];
|
|
194
|
+
if (!from)
|
|
195
|
+
throw new Error("Cannot determine sender address from WalletConnect session.");
|
|
196
|
+
const request = {
|
|
197
|
+
topic: currentSession.topic,
|
|
198
|
+
chainId: `eip155:${chainId}`,
|
|
199
|
+
request: {
|
|
200
|
+
method: "eth_sendTransaction",
|
|
201
|
+
params: [
|
|
202
|
+
{
|
|
203
|
+
from,
|
|
204
|
+
to: tx.to,
|
|
205
|
+
data: tx.data,
|
|
206
|
+
value: tx.value === "0" ? "0x0" : `0x${BigInt(tx.value).toString(16)}`,
|
|
207
|
+
...(tx.gasEstimate ? { gas: `0x${BigInt(tx.gasEstimate).toString(16)}` } : {}),
|
|
208
|
+
},
|
|
209
|
+
],
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
const hash = (await c.request(request));
|
|
213
|
+
return hash;
|
|
214
|
+
}
|
|
215
|
+
export async function disconnect() {
|
|
216
|
+
const c = await getSignClient();
|
|
217
|
+
if (!currentSession)
|
|
218
|
+
return;
|
|
219
|
+
await c.disconnect({
|
|
220
|
+
topic: currentSession.topic,
|
|
221
|
+
reason: getSdkError("USER_DISCONNECTED"),
|
|
222
|
+
});
|
|
223
|
+
currentSession = null;
|
|
224
|
+
patchUserConfig({ walletConnect: { sessionTopic: undefined, pairingTopic: undefined } });
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=walletconnect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walletconnect.js","sourceRoot":"","sources":["../../src/signing/walletconnect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
export type SupportedChain = "ethereum" | "arbitrum" | "polygon";
|
|
2
|
+
export declare const SUPPORTED_CHAINS: readonly SupportedChain[];
|
|
3
|
+
export type RpcProvider = "infura" | "alchemy" | "custom";
|
|
4
|
+
/** Numeric chain IDs for the chains we support. */
|
|
5
|
+
export declare const CHAIN_IDS: Record<SupportedChain, number>;
|
|
6
|
+
export declare const CHAIN_ID_TO_NAME: Record<number, SupportedChain>;
|
|
7
|
+
/** A token balance with optional USD valuation. */
|
|
8
|
+
export interface TokenAmount {
|
|
9
|
+
token: `0x${string}`;
|
|
10
|
+
symbol: string;
|
|
11
|
+
decimals: number;
|
|
12
|
+
/** Raw integer amount as a decimal string (e.g. "1000000" for 1 USDC). */
|
|
13
|
+
amount: string;
|
|
14
|
+
/** Human-readable amount (e.g. "1.0" for 1 USDC). */
|
|
15
|
+
formatted: string;
|
|
16
|
+
valueUsd?: number;
|
|
17
|
+
priceUsd?: number;
|
|
18
|
+
/**
|
|
19
|
+
* True when we could not resolve a USD price for this token. `valueUsd` is
|
|
20
|
+
* `undefined` rather than 0, and portfolio totals will NOT include this
|
|
21
|
+
* balance — callers should flag it to the user instead of silently treating
|
|
22
|
+
* it as worthless.
|
|
23
|
+
*/
|
|
24
|
+
priceMissing?: boolean;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Per-subsystem status reported alongside a portfolio summary, so callers can
|
|
28
|
+
* distinguish "no Aave position" (covered:true, positions empty) from "Aave
|
|
29
|
+
* fetch failed" (covered:false, errored:true) from "not attempted" (covered:
|
|
30
|
+
* false, errored:false — e.g. Morpho Blue, which requires caller-supplied
|
|
31
|
+
* market ids and so has no on-chain enumeration path from a wallet).
|
|
32
|
+
*/
|
|
33
|
+
export interface CoverageStatus {
|
|
34
|
+
covered: boolean;
|
|
35
|
+
errored?: boolean;
|
|
36
|
+
/** Free-form message explaining why `covered` is false when it is. */
|
|
37
|
+
note?: string;
|
|
38
|
+
}
|
|
39
|
+
export interface PortfolioCoverage {
|
|
40
|
+
aave: CoverageStatus;
|
|
41
|
+
compound: CoverageStatus;
|
|
42
|
+
morpho: CoverageStatus;
|
|
43
|
+
uniswapV3: CoverageStatus;
|
|
44
|
+
staking: CoverageStatus;
|
|
45
|
+
/** Number of token balances whose USD valuation could not be resolved. */
|
|
46
|
+
unpricedAssets: number;
|
|
47
|
+
}
|
|
48
|
+
export interface LendingPosition {
|
|
49
|
+
protocol: "aave-v3";
|
|
50
|
+
chain: SupportedChain;
|
|
51
|
+
collateral: TokenAmount[];
|
|
52
|
+
debt: TokenAmount[];
|
|
53
|
+
totalCollateralUsd: number;
|
|
54
|
+
totalDebtUsd: number;
|
|
55
|
+
netValueUsd: number;
|
|
56
|
+
/** Aave health factor (>1 safe, <1 liquidatable). Infinity if no debt. */
|
|
57
|
+
healthFactor: number;
|
|
58
|
+
/** Weighted average liquidation threshold (bps, e.g. 8250 = 82.5%). */
|
|
59
|
+
liquidationThreshold: number;
|
|
60
|
+
/** Weighted average loan-to-value (bps). */
|
|
61
|
+
ltv: number;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* A Compound V3 (Comet) position, flattened enough to slot alongside Aave in a unified
|
|
65
|
+
* lending bucket. Kept as a thin projection of modules/compound/index.ts#CompoundPosition
|
|
66
|
+
* so the types module doesn't need to pull in compound internals.
|
|
67
|
+
*/
|
|
68
|
+
export interface CompoundLendingPosition {
|
|
69
|
+
protocol: "compound-v3";
|
|
70
|
+
chain: SupportedChain;
|
|
71
|
+
market: string;
|
|
72
|
+
marketAddress: `0x${string}`;
|
|
73
|
+
baseSupplied: TokenAmount | null;
|
|
74
|
+
baseBorrowed: TokenAmount | null;
|
|
75
|
+
collateral: TokenAmount[];
|
|
76
|
+
totalCollateralUsd: number;
|
|
77
|
+
totalDebtUsd: number;
|
|
78
|
+
totalSuppliedUsd: number;
|
|
79
|
+
netValueUsd: number;
|
|
80
|
+
}
|
|
81
|
+
/** Any lending/borrowing position reported by the portfolio aggregator. */
|
|
82
|
+
export type LendingPositionUnion = LendingPosition | CompoundLendingPosition;
|
|
83
|
+
export interface LPPosition {
|
|
84
|
+
protocol: "uniswap-v3";
|
|
85
|
+
chain: SupportedChain;
|
|
86
|
+
tokenId: string;
|
|
87
|
+
token0: TokenAmount;
|
|
88
|
+
token1: TokenAmount;
|
|
89
|
+
/** Fee tier in hundredths of a bip (500 = 0.05%, 3000 = 0.30%, 10000 = 1.0%). */
|
|
90
|
+
feeTier: number;
|
|
91
|
+
tickLower: number;
|
|
92
|
+
tickUpper: number;
|
|
93
|
+
currentTick: number;
|
|
94
|
+
inRange: boolean;
|
|
95
|
+
liquidity: string;
|
|
96
|
+
/**
|
|
97
|
+
* Fees that have been checkpointed into NonfungiblePositionManager.tokensOwed
|
|
98
|
+
* (e.g. by a prior collect/burn touch). Fees accrued since the last
|
|
99
|
+
* checkpoint are NOT included — to see the full collectable amount, the
|
|
100
|
+
* caller would need to simulate collect() against fork state. Treat this as
|
|
101
|
+
* a LOWER BOUND on what a collect would return.
|
|
102
|
+
*/
|
|
103
|
+
tokensOwedCached0: TokenAmount;
|
|
104
|
+
tokensOwedCached1: TokenAmount;
|
|
105
|
+
/**
|
|
106
|
+
* USD value derived from token amounts computed at the current tick. This
|
|
107
|
+
* is an approximation: withdrawing the position at a different price would
|
|
108
|
+
* yield different amounts. Flagged as `valueUsdIsApproximate: true` so
|
|
109
|
+
* callers don't display this as a precise number.
|
|
110
|
+
*/
|
|
111
|
+
totalValueUsd: number;
|
|
112
|
+
valueUsdIsApproximate: true;
|
|
113
|
+
}
|
|
114
|
+
export interface StakingPosition {
|
|
115
|
+
protocol: "lido" | "eigenlayer";
|
|
116
|
+
chain: SupportedChain;
|
|
117
|
+
stakedAmount: TokenAmount;
|
|
118
|
+
/** Current APR as a decimal (0.035 = 3.5%). */
|
|
119
|
+
apr?: number;
|
|
120
|
+
/** Optional delegation info (for EigenLayer). */
|
|
121
|
+
delegatedTo?: `0x${string}`;
|
|
122
|
+
/** Extra protocol-specific details (e.g. strategy address for EigenLayer). */
|
|
123
|
+
meta?: Record<string, string | number | boolean>;
|
|
124
|
+
}
|
|
125
|
+
export interface PrivilegedRole {
|
|
126
|
+
role: string;
|
|
127
|
+
holder: `0x${string}`;
|
|
128
|
+
isContract: boolean;
|
|
129
|
+
isMultisig: boolean;
|
|
130
|
+
hasTimelock: boolean;
|
|
131
|
+
timelockDelaySeconds?: number;
|
|
132
|
+
}
|
|
133
|
+
export interface SecurityReport {
|
|
134
|
+
address: `0x${string}`;
|
|
135
|
+
chain: SupportedChain;
|
|
136
|
+
isVerified: boolean;
|
|
137
|
+
isProxy: boolean;
|
|
138
|
+
implementation?: `0x${string}`;
|
|
139
|
+
admin?: `0x${string}`;
|
|
140
|
+
dangerousFunctions: string[];
|
|
141
|
+
privilegedRoles: PrivilegedRole[];
|
|
142
|
+
}
|
|
143
|
+
/** Per-wallet slice of a multi-wallet portfolio, or a stand-alone single-wallet summary. */
|
|
144
|
+
export interface PortfolioSummary {
|
|
145
|
+
wallet: `0x${string}`;
|
|
146
|
+
chains: SupportedChain[];
|
|
147
|
+
walletBalancesUsd: number;
|
|
148
|
+
lendingNetUsd: number;
|
|
149
|
+
lpUsd: number;
|
|
150
|
+
stakingUsd: number;
|
|
151
|
+
totalUsd: number;
|
|
152
|
+
perChain: Record<SupportedChain, number>;
|
|
153
|
+
breakdown: {
|
|
154
|
+
native: TokenAmount[];
|
|
155
|
+
erc20: TokenAmount[];
|
|
156
|
+
lending: LendingPositionUnion[];
|
|
157
|
+
lp: LPPosition[];
|
|
158
|
+
staking: StakingPosition[];
|
|
159
|
+
};
|
|
160
|
+
coverage: PortfolioCoverage;
|
|
161
|
+
}
|
|
162
|
+
/** Multi-wallet portfolio aggregation. */
|
|
163
|
+
export interface MultiWalletPortfolioSummary {
|
|
164
|
+
wallets: `0x${string}`[];
|
|
165
|
+
chains: SupportedChain[];
|
|
166
|
+
totalUsd: number;
|
|
167
|
+
walletBalancesUsd: number;
|
|
168
|
+
lendingNetUsd: number;
|
|
169
|
+
lpUsd: number;
|
|
170
|
+
stakingUsd: number;
|
|
171
|
+
perChain: Record<SupportedChain, number>;
|
|
172
|
+
perWallet: PortfolioSummary[];
|
|
173
|
+
coverage: PortfolioCoverage;
|
|
174
|
+
}
|
|
175
|
+
/** Unsigned transaction, ready to be sent to Ledger Live for signing. */
|
|
176
|
+
export interface UnsignedTx {
|
|
177
|
+
chain: SupportedChain;
|
|
178
|
+
to: `0x${string}`;
|
|
179
|
+
data: `0x${string}`;
|
|
180
|
+
/** Value in wei as a decimal string (so JSON-safe). */
|
|
181
|
+
value: string;
|
|
182
|
+
from?: `0x${string}`;
|
|
183
|
+
/** Human-readable description (e.g. "Supply 1.0 USDC to Aave V3 on Ethereum"). */
|
|
184
|
+
description: string;
|
|
185
|
+
/** Decoded function name + args for display. */
|
|
186
|
+
decoded?: {
|
|
187
|
+
functionName: string;
|
|
188
|
+
args: Record<string, string>;
|
|
189
|
+
};
|
|
190
|
+
/** Estimated gas as a decimal string. */
|
|
191
|
+
gasEstimate?: string;
|
|
192
|
+
/** Estimated gas cost in USD. */
|
|
193
|
+
gasCostUsd?: number;
|
|
194
|
+
/** If this tx is a prerequisite (e.g. ERC-20 approve), the follow-up tx is in `next`. */
|
|
195
|
+
next?: UnsignedTx;
|
|
196
|
+
/**
|
|
197
|
+
* Opaque handle issued by the tx-store when the prepared tx is returned to
|
|
198
|
+
* the caller. `send_transaction` accepts ONLY this handle — raw calldata is
|
|
199
|
+
* not acceptable, which binds the signed tx to the previewed one and closes
|
|
200
|
+
* the prompt-injection → arbitrary-signing path.
|
|
201
|
+
*/
|
|
202
|
+
handle?: string;
|
|
203
|
+
}
|
|
204
|
+
/** Shape of ~/.recon-crypto-mcp/config.json. */
|
|
205
|
+
export interface UserConfig {
|
|
206
|
+
rpc: {
|
|
207
|
+
provider: RpcProvider;
|
|
208
|
+
/** API key for infura/alchemy. Ignored when provider === "custom". */
|
|
209
|
+
apiKey?: string;
|
|
210
|
+
/** Only used when provider === "custom". */
|
|
211
|
+
customUrls?: Partial<Record<SupportedChain, string>>;
|
|
212
|
+
};
|
|
213
|
+
etherscanApiKey?: string;
|
|
214
|
+
/** Optional 1inch Developer Portal API key for intra-chain swap-quote comparison. */
|
|
215
|
+
oneInchApiKey?: string;
|
|
216
|
+
walletConnect?: {
|
|
217
|
+
projectId?: string;
|
|
218
|
+
/** Topic of the active WC session (so we can resume after restart). */
|
|
219
|
+
sessionTopic?: string;
|
|
220
|
+
pairingTopic?: string;
|
|
221
|
+
};
|
|
222
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Shared domain types used across all modules.
|
|
2
|
+
export const SUPPORTED_CHAINS = [
|
|
3
|
+
"ethereum",
|
|
4
|
+
"arbitrum",
|
|
5
|
+
"polygon",
|
|
6
|
+
];
|
|
7
|
+
/** Numeric chain IDs for the chains we support. */
|
|
8
|
+
export const CHAIN_IDS = {
|
|
9
|
+
ethereum: 1,
|
|
10
|
+
arbitrum: 42161,
|
|
11
|
+
polygon: 137,
|
|
12
|
+
};
|
|
13
|
+
export const CHAIN_ID_TO_NAME = {
|
|
14
|
+
1: "ethereum",
|
|
15
|
+
42161: "arbitrum",
|
|
16
|
+
137: "polygon",
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAI/C,MAAM,CAAC,MAAM,gBAAgB,GAA8B;IACzD,UAAU;IACV,UAAU;IACV,SAAS;CACD,CAAC;AAIX,mDAAmD;AACnD,MAAM,CAAC,MAAM,SAAS,GAAmC;IACvD,QAAQ,EAAE,CAAC;IACX,QAAQ,EAAE,KAAK;IACf,OAAO,EAAE,GAAG;CACb,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAmC;IAC9D,CAAC,EAAE,UAAU;IACb,KAAK,EAAE,UAAU;IACjB,GAAG,EAAE,SAAS;CACf,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "recon-crypto-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for AI agents (Claude Code, Claude Desktop, Cursor) to manage a self-custodial crypto portfolio through a Ledger hardware wallet. Reads on-chain wallet balances, ENS, token prices, and DeFi positions across Ethereum/Arbitrum/Polygon (Aave V3, Compound V3, Morpho Blue, Uniswap V3 LP, Lido stETH, EigenLayer), surfaces liquidation/health-factor alerts and protocol risk scores, then prepares unsigned EVM transactions (supply, borrow, repay, withdraw, stake, unstake, native/ERC-20 send, and LiFi-routed swaps and cross-chain bridges) that the user signs on their Ledger device via WalletConnect — private keys never leave the hardware wallet.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"recon-crypto-mcp": "dist/index.js",
|
|
9
|
+
"recon-crypto-mcp-setup": "dist/setup.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"README.md",
|
|
14
|
+
"LICENSE"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc",
|
|
18
|
+
"dev": "tsc --watch",
|
|
19
|
+
"start": "node dist/index.js",
|
|
20
|
+
"setup": "node dist/setup.js",
|
|
21
|
+
"test": "vitest run",
|
|
22
|
+
"test:watch": "vitest"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"mcp",
|
|
26
|
+
"mcp-server",
|
|
27
|
+
"model-context-protocol",
|
|
28
|
+
"anthropic",
|
|
29
|
+
"claude",
|
|
30
|
+
"claude-code",
|
|
31
|
+
"claude-desktop",
|
|
32
|
+
"cursor",
|
|
33
|
+
"ai-agent",
|
|
34
|
+
"ai-agents",
|
|
35
|
+
"agent-tools",
|
|
36
|
+
"llm-tools",
|
|
37
|
+
"ledger",
|
|
38
|
+
"ledger-live",
|
|
39
|
+
"ledger-nano",
|
|
40
|
+
"hardware-wallet",
|
|
41
|
+
"self-custody",
|
|
42
|
+
"non-custodial",
|
|
43
|
+
"walletconnect",
|
|
44
|
+
"walletconnect-v2",
|
|
45
|
+
"crypto",
|
|
46
|
+
"cryptocurrency",
|
|
47
|
+
"crypto-portfolio",
|
|
48
|
+
"portfolio-management",
|
|
49
|
+
"portfolio-tracker",
|
|
50
|
+
"wallet",
|
|
51
|
+
"wallet-management",
|
|
52
|
+
"web3",
|
|
53
|
+
"blockchain",
|
|
54
|
+
"defi",
|
|
55
|
+
"defi-portfolio",
|
|
56
|
+
"defi-agent",
|
|
57
|
+
"onchain",
|
|
58
|
+
"onchain-agent",
|
|
59
|
+
"transaction-signing",
|
|
60
|
+
"tx-signing",
|
|
61
|
+
"unsigned-transactions",
|
|
62
|
+
"ethereum",
|
|
63
|
+
"arbitrum",
|
|
64
|
+
"polygon",
|
|
65
|
+
"evm",
|
|
66
|
+
"erc20",
|
|
67
|
+
"erc-20",
|
|
68
|
+
"ens",
|
|
69
|
+
"aave",
|
|
70
|
+
"aave-v3",
|
|
71
|
+
"compound",
|
|
72
|
+
"compound-v3",
|
|
73
|
+
"morpho",
|
|
74
|
+
"morpho-blue",
|
|
75
|
+
"uniswap",
|
|
76
|
+
"uniswap-v3",
|
|
77
|
+
"lido",
|
|
78
|
+
"steth",
|
|
79
|
+
"eigenlayer",
|
|
80
|
+
"liquid-staking",
|
|
81
|
+
"restaking",
|
|
82
|
+
"lending",
|
|
83
|
+
"borrowing",
|
|
84
|
+
"liquidation",
|
|
85
|
+
"health-factor",
|
|
86
|
+
"yield",
|
|
87
|
+
"staking",
|
|
88
|
+
"staking-rewards",
|
|
89
|
+
"swap",
|
|
90
|
+
"dex-aggregator",
|
|
91
|
+
"bridge",
|
|
92
|
+
"cross-chain",
|
|
93
|
+
"lifi",
|
|
94
|
+
"li-fi",
|
|
95
|
+
"1inch",
|
|
96
|
+
"token-prices",
|
|
97
|
+
"defillama",
|
|
98
|
+
"etherscan",
|
|
99
|
+
"smart-contract-security",
|
|
100
|
+
"protocol-risk",
|
|
101
|
+
"risk-assessment",
|
|
102
|
+
"gnosis-safe",
|
|
103
|
+
"multisig",
|
|
104
|
+
"timelock"
|
|
105
|
+
],
|
|
106
|
+
"homepage": "https://github.com/szhygulin/recon-crypto-mcp#readme",
|
|
107
|
+
"repository": {
|
|
108
|
+
"type": "git",
|
|
109
|
+
"url": "git+https://github.com/szhygulin/recon-crypto-mcp.git"
|
|
110
|
+
},
|
|
111
|
+
"bugs": {
|
|
112
|
+
"url": "https://github.com/szhygulin/recon-crypto-mcp/issues"
|
|
113
|
+
},
|
|
114
|
+
"author": "Viacheslav Zhygulin",
|
|
115
|
+
"license": "MIT",
|
|
116
|
+
"dependencies": {
|
|
117
|
+
"@lifi/sdk": "^3.16.3",
|
|
118
|
+
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
119
|
+
"@walletconnect/sign-client": "^2.17.0",
|
|
120
|
+
"@walletconnect/utils": "^2.17.0",
|
|
121
|
+
"qrcode-terminal": "^0.12.0",
|
|
122
|
+
"viem": "^2.21.0",
|
|
123
|
+
"zod": "^3.23.8"
|
|
124
|
+
},
|
|
125
|
+
"devDependencies": {
|
|
126
|
+
"@types/node": "^22.0.0",
|
|
127
|
+
"@types/qrcode-terminal": "^0.12.2",
|
|
128
|
+
"typescript": "^5.6.0",
|
|
129
|
+
"vitest": "^2.1.0"
|
|
130
|
+
},
|
|
131
|
+
"engines": {
|
|
132
|
+
"node": ">=18.17.0"
|
|
133
|
+
}
|
|
134
|
+
}
|