web3-tools-mcp 3.0.0 → 3.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/CHANGELOG.md +86 -2
- package/README.md +76 -52
- package/dist/chain-meta.d.ts.map +1 -1
- package/dist/chain-meta.js +19 -8
- package/dist/chain-meta.js.map +1 -1
- package/dist/clear-signing.d.ts.map +1 -1
- package/dist/clear-signing.js +17 -6
- package/dist/clear-signing.js.map +1 -1
- package/dist/http-server.d.ts.map +1 -1
- package/dist/http-server.js +9 -3
- package/dist/http-server.js.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/kv-storage.d.ts +2 -1
- package/dist/kv-storage.d.ts.map +1 -1
- package/dist/kv-storage.js +5 -2
- package/dist/kv-storage.js.map +1 -1
- package/dist/oauth.d.ts +18 -4
- package/dist/oauth.d.ts.map +1 -1
- package/dist/oauth.js +62 -26
- package/dist/oauth.js.map +1 -1
- package/dist/preview.d.ts.map +1 -1
- package/dist/preview.js +7 -5
- package/dist/preview.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +14 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/read/advanced.d.ts +9 -4
- package/dist/tools/read/advanced.d.ts.map +1 -1
- package/dist/tools/read/advanced.js +45 -33
- package/dist/tools/read/advanced.js.map +1 -1
- package/dist/tools/read/balance.d.ts.map +1 -1
- package/dist/tools/read/balance.js +17 -32
- package/dist/tools/read/balance.js.map +1 -1
- package/dist/tools/read/contract-info.d.ts +2 -0
- package/dist/tools/read/contract-info.d.ts.map +1 -1
- package/dist/tools/read/contract-info.js +53 -122
- package/dist/tools/read/contract-info.js.map +1 -1
- package/dist/tools/read/contract.d.ts.map +1 -1
- package/dist/tools/read/contract.js +2 -1
- package/dist/tools/read/contract.js.map +1 -1
- package/dist/tools/read/ens.d.ts +20 -40
- package/dist/tools/read/ens.d.ts.map +1 -1
- package/dist/tools/read/ens.js +25 -33
- package/dist/tools/read/ens.js.map +1 -1
- package/dist/tools/read/gas.d.ts.map +1 -1
- package/dist/tools/read/gas.js +13 -48
- package/dist/tools/read/gas.js.map +1 -1
- package/dist/tools/read/logs.d.ts +61 -0
- package/dist/tools/read/logs.d.ts.map +1 -1
- package/dist/tools/read/logs.js +96 -115
- package/dist/tools/read/logs.js.map +1 -1
- package/dist/tools/read/signatures.d.ts.map +1 -1
- package/dist/tools/read/signatures.js +4 -3
- package/dist/tools/read/signatures.js.map +1 -1
- package/dist/tools/read/signing.d.ts.map +1 -1
- package/dist/tools/read/signing.js +8 -2
- package/dist/tools/read/signing.js.map +1 -1
- package/dist/tools/sign/transactions.d.ts +4 -4
- package/dist/tools/sign/transactions.d.ts.map +1 -1
- package/dist/tools/sign/transactions.js +54 -9
- package/dist/tools/sign/transactions.js.map +1 -1
- package/dist/utils.d.ts +18 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +43 -1
- package/dist/utils.js.map +1 -1
- package/dist/wallet-client.d.ts +1 -0
- package/dist/wallet-client.d.ts.map +1 -1
- package/dist/wallet-client.js +16 -3
- package/dist/wallet-client.js.map +1 -1
- package/package.json +4 -7
- package/src/chain-meta.ts +16 -7
- package/src/clear-signing.ts +15 -9
- package/src/http-server.ts +8 -3
- package/src/index.ts +5 -1
- package/src/kv-storage.ts +6 -3
- package/src/oauth.ts +93 -34
- package/src/preview.ts +7 -5
- package/src/tools/index.ts +12 -1
- package/src/tools/read/advanced.ts +63 -34
- package/src/tools/read/balance.ts +18 -33
- package/src/tools/read/contract-info.ts +64 -144
- package/src/tools/read/contract.ts +2 -1
- package/src/tools/read/ens.ts +26 -33
- package/src/tools/read/gas.ts +13 -50
- package/src/tools/read/logs.ts +131 -143
- package/src/tools/read/signatures.ts +4 -4
- package/src/tools/read/signing.ts +8 -2
- package/src/tools/sign/transactions.ts +60 -9
- package/src/utils.ts +47 -1
- package/src/wallet-client.ts +17 -3
package/dist/tools/read/logs.js
CHANGED
|
@@ -2,7 +2,7 @@ import { HypersyncClient, LogField } from '@envio-dev/hypersync-client';
|
|
|
2
2
|
import { decodeEventLog, isAddress, keccak256, numberToHex, padHex, parseAbiItem, toBytes, toEventSignature } from 'viem';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { getClientManager, SUPPORTED_CHAINS } from '../../client.js';
|
|
5
|
-
import { convertEventArgsToTypes, createTool, formatResponse } from '../../utils.js';
|
|
5
|
+
import { convertEventArgsToTypes, createTool, formatResponse, rpcReason } from '../../utils.js';
|
|
6
6
|
/**
|
|
7
7
|
* A topic is always 32 bytes, so an address, a number or a short hex value has to be
|
|
8
8
|
* left-padded to fit. Passing one through unpadded is rejected outright by Hypersync.
|
|
@@ -19,7 +19,46 @@ function toTopic(value) {
|
|
|
19
19
|
}
|
|
20
20
|
throw new Error(`Cannot filter on indexed value ${JSON.stringify(value)} — expected an address, number or hex string`);
|
|
21
21
|
}
|
|
22
|
-
|
|
22
|
+
/** More than this is cut short, with the block to resume from. */
|
|
23
|
+
export const MAX_LOGS = 1000;
|
|
24
|
+
function serializeLog(log) {
|
|
25
|
+
return {
|
|
26
|
+
address: log.address,
|
|
27
|
+
blockHash: log.blockHash,
|
|
28
|
+
blockNumber: log.blockNumber?.toString(),
|
|
29
|
+
data: log.data,
|
|
30
|
+
logIndex: log.logIndex,
|
|
31
|
+
topics: log.topics,
|
|
32
|
+
transactionHash: log.transactionHash,
|
|
33
|
+
transactionIndex: log.transactionIndex,
|
|
34
|
+
decoded: { eventName: log.eventName, args: log.args }
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/** Resuming from `nextBlock` may repeat logs of that block already returned. */
|
|
38
|
+
export function capLogs(logs) {
|
|
39
|
+
if (logs.length <= MAX_LOGS)
|
|
40
|
+
return { logs: logs.map(serializeLog) };
|
|
41
|
+
return {
|
|
42
|
+
logs: logs.slice(0, MAX_LOGS).map(serializeLog),
|
|
43
|
+
truncated: true,
|
|
44
|
+
nextBlock: logs[MAX_LOGS]?.blockNumber?.toString()
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The same range eth_getLogs would scan — each end defaults to the latest block — in
|
|
49
|
+
* Hypersync's terms, where `toBlock` is exclusive.
|
|
50
|
+
*/
|
|
51
|
+
export function hypersyncRange(fromBlock, toBlock, latest) {
|
|
52
|
+
return {
|
|
53
|
+
fromBlock: fromBlock ? Number(BigInt(fromBlock)) : latest,
|
|
54
|
+
toBlock: (toBlock ? Number(BigInt(toBlock)) : latest) + 1
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/** One topic, or a list of alternatives for an OR filter. */
|
|
58
|
+
export function toTopics(value) {
|
|
59
|
+
return Array.isArray(value) ? value.map(toTopic) : toTopic(value);
|
|
60
|
+
}
|
|
61
|
+
async function getLogsWithHypersync(chainName, abiItem, hypersyncApiKey, address, fromBlock, toBlock, eventArgs) {
|
|
23
62
|
const hypersyncUrl = getClientManager().getHypersyncUrl(chainName);
|
|
24
63
|
if (!hypersyncUrl) {
|
|
25
64
|
throw new Error(`Hypersync not supported for chain: ${chainName}`);
|
|
@@ -28,20 +67,20 @@ async function getLogsWithHypersync(chainName, eventAbi, hypersyncApiKey, addres
|
|
|
28
67
|
url: hypersyncUrl,
|
|
29
68
|
bearerToken: hypersyncApiKey
|
|
30
69
|
});
|
|
31
|
-
const
|
|
32
|
-
const eventSignature = toEventSignature(abiItem);
|
|
33
|
-
const topic0 = keccak256(toBytes(eventSignature));
|
|
70
|
+
const topic0 = keccak256(toBytes(toEventSignature(abiItem)));
|
|
34
71
|
// Build topics array for filtering
|
|
35
72
|
const topics = [topic0];
|
|
36
73
|
// Add indexed parameter filtering if eventArgs provided
|
|
37
|
-
if (eventArgs
|
|
74
|
+
if (eventArgs) {
|
|
38
75
|
const indexedInputs = abiItem.inputs.filter((input) => input.indexed);
|
|
39
76
|
for (let i = 0; i < indexedInputs.length && i < 3; i++) {
|
|
40
77
|
const input = indexedInputs[i];
|
|
41
78
|
const argValue = input?.name ? eventArgs[input.name] : undefined;
|
|
42
|
-
topics.push(argValue === undefined ? null :
|
|
79
|
+
topics.push(argValue === undefined ? null : toTopics(argValue));
|
|
43
80
|
}
|
|
44
81
|
}
|
|
82
|
+
const latest = fromBlock && toBlock ? 0 : await client.getHeight();
|
|
83
|
+
const range = hypersyncRange(fromBlock, toBlock, latest);
|
|
45
84
|
const query = {
|
|
46
85
|
fieldSelection: {
|
|
47
86
|
log: [
|
|
@@ -58,8 +97,7 @@ async function getLogsWithHypersync(chainName, eventAbi, hypersyncApiKey, addres
|
|
|
58
97
|
LogField.LogIndex
|
|
59
98
|
]
|
|
60
99
|
},
|
|
61
|
-
|
|
62
|
-
toBlock: toBlock ? Number.parseInt(toBlock, 10) : undefined,
|
|
100
|
+
...range,
|
|
63
101
|
logs: [
|
|
64
102
|
{
|
|
65
103
|
address: address ? [address] : undefined,
|
|
@@ -69,9 +107,16 @@ async function getLogsWithHypersync(chainName, eventAbi, hypersyncApiKey, addres
|
|
|
69
107
|
}
|
|
70
108
|
]
|
|
71
109
|
};
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
110
|
+
// One response covers only part of a long range; `nextBlock` says where it stopped.
|
|
111
|
+
const logs = [];
|
|
112
|
+
for (let from = range.fromBlock; from < range.toBlock && logs.length <= MAX_LOGS;) {
|
|
113
|
+
const res = await client.get({ ...query, fromBlock: from });
|
|
114
|
+
logs.push(...res.data.logs);
|
|
115
|
+
if (res.nextBlock <= from)
|
|
116
|
+
break;
|
|
117
|
+
from = res.nextBlock;
|
|
118
|
+
}
|
|
119
|
+
return logs
|
|
75
120
|
.map((log) => {
|
|
76
121
|
const topics = log.topics.filter((topic) => Boolean(topic));
|
|
77
122
|
const data = (log.data ?? '0x');
|
|
@@ -80,7 +125,7 @@ async function getLogsWithHypersync(chainName, eventAbi, hypersyncApiKey, addres
|
|
|
80
125
|
return {
|
|
81
126
|
address: log.address,
|
|
82
127
|
blockHash: log.blockHash,
|
|
83
|
-
blockNumber: log.blockNumber ? BigInt(log.blockNumber) :
|
|
128
|
+
blockNumber: log.blockNumber !== undefined ? BigInt(log.blockNumber) : null,
|
|
84
129
|
data,
|
|
85
130
|
logIndex: log.logIndex,
|
|
86
131
|
topics,
|
|
@@ -96,133 +141,69 @@ async function getLogsWithHypersync(chainName, eventAbi, hypersyncApiKey, addres
|
|
|
96
141
|
}
|
|
97
142
|
})
|
|
98
143
|
.filter((log) => log !== null);
|
|
99
|
-
return decodedLogs;
|
|
100
144
|
}
|
|
101
145
|
export default {
|
|
102
|
-
get_logs: createTool('Query Contract Events',
|
|
146
|
+
get_logs: createTool('Query Contract Events', `Search and decode contract events with filtering. Uses viem with hypersync fallback. Specify address and block ranges for best performance. Returns at most ${MAX_LOGS} logs; past that, truncated is true and nextBlock says where to resume.`, z.object({
|
|
103
147
|
chain: z.enum(SUPPORTED_CHAINS).describe('The blockchain network to use'),
|
|
104
148
|
eventAbi: z
|
|
105
149
|
.string()
|
|
106
150
|
.describe('Event ABI definition (e.g., "event Transfer(address indexed from, address indexed to, uint256 value)")'),
|
|
107
151
|
address: z.string().optional().describe('Contract address (RECOMMENDED for performance)'),
|
|
108
|
-
fromBlock: z.string().optional().describe('Start block (defaults to latest
|
|
109
|
-
toBlock: z.string().optional().describe('End block (defaults to latest)'),
|
|
152
|
+
fromBlock: z.string().optional().describe('Start block (defaults to the latest block)'),
|
|
153
|
+
toBlock: z.string().optional().describe('End block, inclusive (defaults to the latest block)'),
|
|
110
154
|
eventArgs: z
|
|
111
155
|
.record(z.union([z.string(), z.number(), z.boolean(), z.array(z.union([z.string(), z.number(), z.boolean()]))]))
|
|
112
156
|
.optional()
|
|
113
|
-
.describe('Filter by indexed parameters: {"from": "0x123...", "to": "0x456..."}')
|
|
157
|
+
.describe('Filter by indexed parameters: {"from": "0x123...", "to": "0x456..."}. A list matches any of its values: {"to": ["0x1...", "0x2..."]}')
|
|
114
158
|
}), async (args) => {
|
|
115
159
|
const clientManager = getClientManager();
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
toBlock: toBlockNum
|
|
129
|
-
};
|
|
130
|
-
// Add address filter if provided
|
|
131
|
-
if (args.address && isAddress(args.address)) {
|
|
132
|
-
getLogsParams.address = args.address;
|
|
133
|
-
}
|
|
134
|
-
// Add event argument filters if provided
|
|
135
|
-
if (args.eventArgs && Object.keys(args.eventArgs).length > 0) {
|
|
136
|
-
// Convert event arguments to proper types based on ABI
|
|
137
|
-
const convertedEventArgs = convertEventArgsToTypes(args.eventArgs, abiItem.inputs);
|
|
138
|
-
getLogsParams.args = convertedEventArgs;
|
|
139
|
-
}
|
|
140
|
-
// Use client.getLogs with proper typing
|
|
141
|
-
const logs = await client.getLogs(getLogsParams);
|
|
142
|
-
// Convert logs to serializable format
|
|
143
|
-
const serializedLogs = logs.map((log) => {
|
|
144
|
-
const baseLogData = {
|
|
145
|
-
address: log.address,
|
|
146
|
-
blockHash: log.blockHash,
|
|
147
|
-
blockNumber: log.blockNumber?.toString(),
|
|
148
|
-
data: log.data,
|
|
149
|
-
logIndex: log.logIndex,
|
|
150
|
-
topics: log.topics,
|
|
151
|
-
transactionHash: log.transactionHash,
|
|
152
|
-
transactionIndex: log.transactionIndex
|
|
153
|
-
};
|
|
154
|
-
return {
|
|
155
|
-
...baseLogData,
|
|
156
|
-
decoded: {
|
|
157
|
-
eventName: log.eventName,
|
|
158
|
-
args: log.args
|
|
159
|
-
}
|
|
160
|
-
};
|
|
161
|
-
});
|
|
160
|
+
const chain = args.chain;
|
|
161
|
+
const abiItem = parseAbiItem(args.eventAbi);
|
|
162
|
+
if (args.address && !isAddress(args.address)) {
|
|
163
|
+
throw new Error(`Invalid contract address: ${args.address}`);
|
|
164
|
+
}
|
|
165
|
+
const eventArgs = args.eventArgs && Object.keys(args.eventArgs).length > 0
|
|
166
|
+
? convertEventArgsToTypes(args.eventArgs, abiItem.inputs)
|
|
167
|
+
: undefined;
|
|
168
|
+
const fromBlockNum = args.fromBlock ? BigInt(args.fromBlock) : undefined;
|
|
169
|
+
const toBlockNum = args.toBlock ? BigInt(args.toBlock) : undefined;
|
|
170
|
+
const respond = (logs, dataSource) => {
|
|
171
|
+
const capped = capLogs(logs);
|
|
162
172
|
return formatResponse({
|
|
163
|
-
|
|
173
|
+
...capped,
|
|
164
174
|
eventSignature: toEventSignature(abiItem),
|
|
165
175
|
chain: args.chain,
|
|
166
176
|
fromBlock: fromBlockNum?.toString() || 'latest',
|
|
167
177
|
toBlock: toBlockNum?.toString() || 'latest',
|
|
168
|
-
count: logs.length,
|
|
169
|
-
dataSource
|
|
178
|
+
count: capped.logs.length,
|
|
179
|
+
dataSource,
|
|
170
180
|
filters: {
|
|
171
181
|
address: args.address || null,
|
|
172
182
|
eventArgs: args.eventArgs || null
|
|
173
183
|
}
|
|
174
184
|
});
|
|
185
|
+
};
|
|
186
|
+
try {
|
|
187
|
+
const logs = await clientManager.getClient(chain).getLogs({
|
|
188
|
+
address: args.address,
|
|
189
|
+
event: abiItem,
|
|
190
|
+
args: eventArgs,
|
|
191
|
+
fromBlock: fromBlockNum,
|
|
192
|
+
toBlock: toBlockNum
|
|
193
|
+
});
|
|
194
|
+
return respond(logs, 'viem');
|
|
175
195
|
}
|
|
176
196
|
catch (viemError) {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
const toBlockNum = args.toBlock ? BigInt(args.toBlock) : undefined;
|
|
185
|
-
// Convert hypersync logs to the same format as viem logs
|
|
186
|
-
const serializedLogs = hypersyncLogs.map((log) => {
|
|
187
|
-
const baseLogData = {
|
|
188
|
-
address: log.address,
|
|
189
|
-
blockHash: log.blockHash,
|
|
190
|
-
blockNumber: log.blockNumber?.toString(),
|
|
191
|
-
data: log.data,
|
|
192
|
-
logIndex: log.logIndex,
|
|
193
|
-
topics: log.topics,
|
|
194
|
-
transactionHash: log.transactionHash,
|
|
195
|
-
transactionIndex: log.transactionIndex
|
|
196
|
-
};
|
|
197
|
-
return {
|
|
198
|
-
...baseLogData,
|
|
199
|
-
decoded: {
|
|
200
|
-
eventName: log.eventName,
|
|
201
|
-
args: log.args
|
|
202
|
-
}
|
|
203
|
-
};
|
|
204
|
-
});
|
|
205
|
-
return formatResponse({
|
|
206
|
-
logs: serializedLogs,
|
|
207
|
-
eventSignature: toEventSignature(abiItem),
|
|
208
|
-
chain: args.chain,
|
|
209
|
-
fromBlock: fromBlockNum?.toString() || 'latest',
|
|
210
|
-
toBlock: toBlockNum?.toString() || 'latest',
|
|
211
|
-
count: hypersyncLogs.length,
|
|
212
|
-
dataSource: 'hypersync',
|
|
213
|
-
filters: {
|
|
214
|
-
address: args.address || null,
|
|
215
|
-
eventArgs: args.eventArgs || null
|
|
216
|
-
}
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
catch (hypersyncError) {
|
|
220
|
-
throw new Error(`Both viem and hypersync failed. Viem error: ${viemError}. Hypersync error: ${hypersyncError}`);
|
|
221
|
-
}
|
|
197
|
+
if (!clientManager.getHypersyncUrl(chain)) {
|
|
198
|
+
throw new Error(`Failed to get logs with viem (hypersync not available for ${args.chain}): ${rpcReason(viemError)}`);
|
|
199
|
+
}
|
|
200
|
+
console.warn(`Viem getLogs failed for ${args.chain}, trying hypersync fallback: ${rpcReason(viemError)}`);
|
|
201
|
+
try {
|
|
202
|
+
const logs = await getLogsWithHypersync(chain, abiItem, clientManager.getConfig().hypersyncApiKey, args.address, args.fromBlock, args.toBlock, eventArgs);
|
|
203
|
+
return respond(logs, 'hypersync');
|
|
222
204
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
throw new Error(`Failed to get logs with viem (hypersync not available for ${args.chain}): ${viemError}`);
|
|
205
|
+
catch (hypersyncError) {
|
|
206
|
+
throw new Error(`Both viem and hypersync failed. Viem error: ${rpcReason(viemError)}. Hypersync error: ${rpcReason(hypersyncError)}`);
|
|
226
207
|
}
|
|
227
208
|
}
|
|
228
209
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logs.js","sourceRoot":"","sources":["../../../src/tools/read/logs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAY,QAAQ,EAAE,MAAM,6BAA6B,CAAA;AACjF,OAAO,EAGL,cAAc,EAEd,SAAS,EACT,SAAS,EACT,WAAW,EACX,MAAM,EACN,YAAY,EACZ,OAAO,EACP,gBAAgB,EACjB,MAAM,MAAM,CAAA;AACb,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAEpE,OAAO,EAAE,uBAAuB,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"logs.js","sourceRoot":"","sources":["../../../src/tools/read/logs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAY,QAAQ,EAAE,MAAM,6BAA6B,CAAA;AACjF,OAAO,EAGL,cAAc,EAEd,SAAS,EACT,SAAS,EACT,WAAW,EACX,MAAM,EACN,YAAY,EACZ,OAAO,EACP,gBAAgB,EACjB,MAAM,MAAM,CAAA;AACb,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAEpE,OAAO,EAAE,uBAAuB,EAAE,UAAU,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAE/F;;;GAGG;AACH,SAAS,OAAO,CAAC,KAAc;IAC7B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC3D,OAAO,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAA;IACjD,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAA;IACtD,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;QAC9E,OAAO,MAAM,CAAC,KAAK,CAAC,WAAW,EAAS,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAA;IACzD,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,kCAAkC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAA;AACxH,CAAC;AAED,kEAAkE;AAClE,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,CAAA;AAe5B,SAAS,YAAY,CAAC,GAAe;IACnC,OAAO;QACL,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,QAAQ,EAAE;QACxC,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,eAAe,EAAE,GAAG,CAAC,eAAe;QACpC,gBAAgB,EAAE,GAAG,CAAC,gBAAgB;QACtC,OAAO,EAAE,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE;KACtD,CAAA;AACH,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,OAAO,CAAC,IAAkB;IACxC,IAAI,IAAI,CAAC,MAAM,IAAI,QAAQ;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAA;IACpE,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC;QAC/C,SAAS,EAAE,IAAI;QACf,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE,WAAW,EAAE,QAAQ,EAAE;KACnD,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,SAA6B,EAAE,OAA2B,EAAE,MAAc;IACvG,OAAO;QACL,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM;QACzD,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;KAC1D,CAAA;AACH,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,QAAQ,CAAC,KAAc;IACrC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;AACnE,CAAC;AAED,KAAK,UAAU,oBAAoB,CACjC,SAAoB,EACpB,OAAiB,EACjB,eAAwB,EACxB,OAAgB,EAChB,SAAkB,EAClB,OAAgB,EAChB,SAAmC;IAEnC,MAAM,YAAY,GAAG,gBAAgB,EAAE,CAAC,eAAe,CAAC,SAAS,CAAC,CAAA;IAClE,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,sCAAsC,SAAS,EAAE,CAAC,CAAA;IACpE,CAAC;IAED,MAAM,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC;QACjC,GAAG,EAAE,YAAY;QACjB,WAAW,EAAE,eAAe;KAC7B,CAAC,CAAA;IAEF,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IAE5D,mCAAmC;IACnC,MAAM,MAAM,GAA2B,CAAC,MAAM,CAAC,CAAA;IAE/C,wDAAwD;IACxD,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QAErE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YACvD,MAAM,KAAK,GAAG,aAAa,CAAC,CAAC,CAAC,CAAA;YAC9B,MAAM,QAAQ,GAAG,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;YAEhE,MAAM,CAAC,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAA;QACjE,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,SAAS,EAAE,CAAA;IAClE,MAAM,KAAK,GAAG,cAAc,CAAC,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,CAAA;IAExD,MAAM,KAAK,GAAG;QACZ,cAAc,EAAE;YACd,GAAG,EAAE;gBACH,QAAQ,CAAC,OAAO;gBAChB,QAAQ,CAAC,MAAM;gBACf,QAAQ,CAAC,MAAM;gBACf,QAAQ,CAAC,MAAM;gBACf,QAAQ,CAAC,MAAM;gBACf,QAAQ,CAAC,IAAI;gBACb,QAAQ,CAAC,WAAW;gBACpB,QAAQ,CAAC,SAAS;gBAClB,QAAQ,CAAC,eAAe;gBACxB,QAAQ,CAAC,gBAAgB;gBACzB,QAAQ,CAAC,QAAQ;aAClB;SACF;QACD,GAAG,KAAK;QACR,IAAI,EAAE;YACJ;gBACE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS;gBACxC,kFAAkF;gBAClF,uEAAuE;gBACvE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;aAC1E;SACF;KACF,CAAA;IAED,oFAAoF;IACpF,MAAM,IAAI,GAAU,EAAE,CAAA;IACtB,KAAK,IAAI,IAAI,GAAG,KAAK,CAAC,SAAS,EAAE,IAAI,GAAG,KAAK,CAAC,OAAO,IAAI,IAAI,CAAC,MAAM,IAAI,QAAQ,GAAI,CAAC;QACnF,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC3D,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC3B,IAAI,GAAG,CAAC,SAAS,IAAI,IAAI;YAAE,MAAK;QAChC,IAAI,GAAG,GAAG,CAAC,SAAS,CAAA;IACtB,CAAC;IAED,OAAO,IAAI;SACR,GAAG,CAAC,CAAC,GAAQ,EAAqB,EAAE;QACnC,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAoB,CAAA;QAC/F,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAQ,CAAA;QAEtC,IAAI,CAAC;YACH,MAAM,EAAE,IAAI,EAAE,GAAG,cAAc,CAAC,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAA;YACjE,OAAO;gBACL,OAAO,EAAE,GAAG,CAAC,OAAkB;gBAC/B,SAAS,EAAE,GAAG,CAAC,SAAgB;gBAC/B,WAAW,EAAE,GAAG,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI;gBAC3E,IAAI;gBACJ,QAAQ,EAAE,GAAG,CAAC,QAAQ;gBACtB,MAAM;gBACN,eAAe,EAAE,GAAG,CAAC,eAAsB;gBAC3C,gBAAgB,EAAE,GAAG,CAAC,gBAAgB;gBACtC,SAAS,EAAE,OAAO,CAAC,IAAI;gBACvB,IAAI,EAAE,IAAI,IAAI,EAAE;aACjB,CAAA;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAA;YAC5C,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC,CAAC;SACD,MAAM,CAAC,CAAC,GAAG,EAAqB,EAAE,CAAC,GAAG,KAAK,IAAI,CAAC,CAAA;AACrD,CAAC;AAED,eAAe;IACb,QAAQ,EAAE,UAAU,CAClB,uBAAuB,EACvB,+JAA+J,QAAQ,yEAAyE,EAChP,CAAC,CAAC,MAAM,CAAC;QACP,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,QAAQ,CAAC,+BAA+B,CAAC;QACzE,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,QAAQ,CAAC,wGAAwG,CAAC;QACrH,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gDAAgD,CAAC;QACzF,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4CAA4C,CAAC;QACvF,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qDAAqD,CAAC;QAC9F,SAAS,EAAE,CAAC;aACT,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;aAC/G,QAAQ,EAAE;aACV,QAAQ,CACP,sIAAsI,CACvI;KACJ,CAAC,EACF,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,MAAM,aAAa,GAAG,gBAAgB,EAAE,CAAA;QACxC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAkB,CAAA;QACrC,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAa,CAAA;QAEvD,IAAI,IAAI,CAAC,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7C,MAAM,IAAI,KAAK,CAAC,6BAA6B,IAAI,CAAC,OAAO,EAAE,CAAC,CAAA;QAC9D,CAAC;QAED,MAAM,SAAS,GACb,IAAI,CAAC,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,GAAG,CAAC;YACtD,CAAC,CAAC,uBAAuB,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC;YACzD,CAAC,CAAC,SAAS,CAAA;QACf,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QACxE,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QAElE,MAAM,OAAO,GAAG,CAAC,IAAkB,EAAE,UAAgC,EAAE,EAAE;YACvE,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;YAC5B,OAAO,cAAc,CAAC;gBACpB,GAAG,MAAM;gBACT,cAAc,EAAE,gBAAgB,CAAC,OAAO,CAAC;gBACzC,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,QAAQ;gBAC/C,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,QAAQ;gBAC3C,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM;gBACzB,UAAU;gBACV,OAAO,EAAE;oBACP,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,IAAI;oBAC7B,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,IAAI;iBAClC;aACF,CAAC,CAAA;QACJ,CAAC,CAAA;QAED,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC;gBACxD,OAAO,EAAE,IAAI,CAAC,OAA8B;gBAC5C,KAAK,EAAE,OAAO;gBACd,IAAI,EAAE,SAAS;gBACf,SAAS,EAAE,YAAY;gBACvB,OAAO,EAAE,UAAU;aACpB,CAAC,CAAA;YACF,OAAO,OAAO,CAAC,IAAoB,EAAE,MAAM,CAAC,CAAA;QAC9C,CAAC;QAAC,OAAO,SAAS,EAAE,CAAC;YACnB,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC1C,MAAM,IAAI,KAAK,CAAC,6DAA6D,IAAI,CAAC,KAAK,MAAM,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC,CAAA;YACtH,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,2BAA2B,IAAI,CAAC,KAAK,gCAAgC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC,CAAA;YAEzG,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,oBAAoB,CACrC,KAAK,EACL,OAAO,EACP,aAAa,CAAC,SAAS,EAAE,CAAC,eAAe,EACzC,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,SAAS,EACd,IAAI,CAAC,OAAO,EACZ,SAAS,CACV,CAAA;gBACD,OAAO,OAAO,CAAC,IAAI,EAAE,WAAW,CAAC,CAAA;YACnC,CAAC;YAAC,OAAO,cAAc,EAAE,CAAC;gBACxB,MAAM,IAAI,KAAK,CACb,+CAA+C,SAAS,CAAC,SAAS,CAAC,sBAAsB,SAAS,CAAC,cAAc,CAAC,EAAE,CACrH,CAAA;YACH,CAAC;QACH,CAAC;IACH,CAAC,CACF;CACF,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signatures.d.ts","sourceRoot":"","sources":["../../../src/tools/read/signatures.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"signatures.d.ts","sourceRoot":"","sources":["../../../src/tools/read/signatures.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkBvB,wBAgHC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { encodeFunctionData, keccak256, parseAbiItem, toBytes, toEventSignature, toFunctionSignature } from 'viem';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { createTool, formatResponse } from '../../utils.js';
|
|
3
|
+
import { convertArgumentsToTypes, createTool, formatResponse } from '../../utils.js';
|
|
4
4
|
const FunctionAbiSchema = z.object({
|
|
5
5
|
functionAbi: z.string().describe('Function ABI definition (e.g., "function transfer(address to, uint256 amount)")')
|
|
6
6
|
});
|
|
@@ -57,7 +57,8 @@ export default {
|
|
|
57
57
|
}), async (args) => {
|
|
58
58
|
const results = args.items.map((item) => {
|
|
59
59
|
const abiItem = parseAbiItem(item.errorAbi);
|
|
60
|
-
|
|
60
|
+
// Formatted as a function, which an error's signature is; viem keeps an "error " prefix otherwise.
|
|
61
|
+
const signature = toFunctionSignature({ ...abiItem, type: 'function', outputs: [], stateMutability: 'nonpayable' });
|
|
61
62
|
const hash = keccak256(toBytes(signature));
|
|
62
63
|
const selector = hash.slice(0, 10);
|
|
63
64
|
return {
|
|
@@ -81,7 +82,7 @@ export default {
|
|
|
81
82
|
const data = encodeFunctionData({
|
|
82
83
|
abi: [abiItem],
|
|
83
84
|
functionName: abiItem.name,
|
|
84
|
-
args: args.args
|
|
85
|
+
args: convertArgumentsToTypes(args.args, abiItem.inputs)
|
|
85
86
|
});
|
|
86
87
|
return formatResponse({
|
|
87
88
|
data,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signatures.js","sourceRoot":"","sources":["../../../src/tools/read/signatures.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"signatures.js","sourceRoot":"","sources":["../../../src/tools/read/signatures.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signing.d.ts","sourceRoot":"","sources":["../../../src/tools/read/signing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAKvB;;;;;;GAMG;;;;;;;;;;;;;;;;;;AACH,
|
|
1
|
+
{"version":3,"file":"signing.d.ts","sourceRoot":"","sources":["../../../src/tools/read/signing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAKvB;;;;;;GAMG;;;;;;;;;;;;;;;;;;AACH,wBA+EC"}
|
|
@@ -42,12 +42,18 @@ export default {
|
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
44
|
if (request.state === 'failed') {
|
|
45
|
+
// Only an explicit rejection proves nothing was signed. A timeout or a dropped
|
|
46
|
+
// connection can land after the wallet signed and broadcast.
|
|
47
|
+
const rejected = request.stage === 'approval' && /rejected|denied/i.test(request.error ?? '');
|
|
45
48
|
return formatResponse({
|
|
46
49
|
success: false,
|
|
47
|
-
status: '
|
|
50
|
+
status: rejected ? 'rejected' : 'outcome_unknown',
|
|
48
51
|
what: request.summary,
|
|
49
52
|
error: request.error,
|
|
50
|
-
|
|
53
|
+
...(request.txHash && { transactionHash: request.txHash }),
|
|
54
|
+
message: rejected
|
|
55
|
+
? 'The wallet rejected it. Nothing was signed.'
|
|
56
|
+
: 'It did not complete here, but it may still have been signed or broadcast. Do not retry until the wallet or a block explorer shows it did not go through.'
|
|
51
57
|
});
|
|
52
58
|
}
|
|
53
59
|
// A transaction carries how it ended on the chain; a message signature is just the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signing.js","sourceRoot":"","sources":["../../../src/tools/read/signing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAA;AACjE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAE3C;;;;;;GAMG;AACH,eAAe;IACb,qBAAqB,EAAE,UAAU,CAC/B,uBAAuB,EACvB,6QAA6Q,EAC7Q,CAAC,CAAC,MAAM,CAAC;QACP,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,4EAA4E,CAAC;KAC7G,CAAC,EACF,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;QACvB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,qBAAqB,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;YAErE,MAAM,SAAS,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,GAAG,CAAA;YAE3E,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;gBAChC,kFAAkF;gBAClF,uEAAuE;gBACvE,IAAI,OAAO,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;oBAC/B,OAAO,cAAc,CAAC;wBACpB,OAAO,EAAE,IAAI;wBACb,MAAM,EAAE,QAAQ;wBAChB,SAAS,EAAE,OAAO,CAAC,EAAE;wBACrB,IAAI,EAAE,OAAO,CAAC,OAAO;wBACrB,eAAe,EAAE,OAAO,CAAC,MAAM;wBAC/B,UAAU,EAAE,SAAS;wBACrB,QAAQ,EAAE,0FAA0F;wBACpG,OAAO,EAAE,8CAA8C;qBACxD,CAAC,CAAA;gBACJ,CAAC;gBAED,OAAO,cAAc,CAAC;oBACpB,OAAO,EAAE,IAAI;oBACb,MAAM,EAAE,mBAAmB;oBAC3B,SAAS,EAAE,OAAO,CAAC,EAAE;oBACrB,IAAI,EAAE,OAAO,CAAC,OAAO;oBACrB,UAAU,EAAE,SAAS;oBACrB,QAAQ,EACN,gIAAgI;oBAClI,OAAO,EAAE,8BAA8B;iBACxC,CAAC,CAAA;YACJ,CAAC;YAED,IAAI,OAAO,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC/B,OAAO,cAAc,CAAC;oBACpB,OAAO,EAAE,KAAK;oBACd,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"signing.js","sourceRoot":"","sources":["../../../src/tools/read/signing.ts"],"names":[],"mappings":"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"}
|
|
@@ -43,17 +43,17 @@ declare const _default: {
|
|
|
43
43
|
tokenAddress: z.ZodString;
|
|
44
44
|
to: z.ZodString;
|
|
45
45
|
amount: z.ZodString;
|
|
46
|
-
decimals: z.
|
|
46
|
+
decimals: z.ZodOptional<z.ZodNumber>;
|
|
47
47
|
signWith: z.ZodEnum<["phone", "browser"]>;
|
|
48
48
|
account: z.ZodOptional<z.ZodString>;
|
|
49
49
|
}, "strip", z.ZodTypeAny, {
|
|
50
50
|
chain: "mainnet" | "arbitrum" | "avalanche" | "base" | "bnb" | "gnosis" | "sonic" | "optimism" | "polygon" | "zksync" | "linea" | "unichain" | "localhost";
|
|
51
51
|
to: string;
|
|
52
|
-
decimals: number;
|
|
53
52
|
tokenAddress: string;
|
|
54
53
|
amount: string;
|
|
55
54
|
signWith: "browser" | "phone";
|
|
56
55
|
account?: string | undefined;
|
|
56
|
+
decimals?: number | undefined;
|
|
57
57
|
}, {
|
|
58
58
|
chain: "mainnet" | "arbitrum" | "avalanche" | "base" | "bnb" | "gnosis" | "sonic" | "optimism" | "polygon" | "zksync" | "linea" | "unichain" | "localhost";
|
|
59
59
|
to: string;
|
|
@@ -66,11 +66,11 @@ declare const _default: {
|
|
|
66
66
|
handler: (args: {
|
|
67
67
|
chain: "mainnet" | "arbitrum" | "avalanche" | "base" | "bnb" | "gnosis" | "sonic" | "optimism" | "polygon" | "zksync" | "linea" | "unichain" | "localhost";
|
|
68
68
|
to: string;
|
|
69
|
-
decimals: number;
|
|
70
69
|
tokenAddress: string;
|
|
71
70
|
amount: string;
|
|
72
71
|
signWith: "browser" | "phone";
|
|
73
72
|
account?: string | undefined;
|
|
73
|
+
decimals?: number | undefined;
|
|
74
74
|
}, identity: string) => Promise<import("../../types.js").ToolResult>;
|
|
75
75
|
available: (() => boolean) | undefined;
|
|
76
76
|
};
|
|
@@ -81,7 +81,7 @@ declare const _default: {
|
|
|
81
81
|
chain: z.ZodEnum<["mainnet" | "arbitrum" | "avalanche" | "base" | "bnb" | "gnosis" | "sonic" | "optimism" | "polygon" | "zksync" | "linea" | "unichain" | "localhost", ...("mainnet" | "arbitrum" | "avalanche" | "base" | "bnb" | "gnosis" | "sonic" | "optimism" | "polygon" | "zksync" | "linea" | "unichain" | "localhost")[]]>;
|
|
82
82
|
contractAddress: z.ZodString;
|
|
83
83
|
functionAbi: z.ZodString;
|
|
84
|
-
args: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean]>, "many">>;
|
|
84
|
+
args: z.ZodOptional<z.ZodArray<z.ZodUnion<[z.ZodString, z.ZodEffects<z.ZodNumber, number, number>, z.ZodBoolean]>, "many">>;
|
|
85
85
|
value: z.ZodOptional<z.ZodString>;
|
|
86
86
|
signWith: z.ZodEnum<["phone", "browser"]>;
|
|
87
87
|
account: z.ZodOptional<z.ZodString>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transactions.d.ts","sourceRoot":"","sources":["../../../src/tools/sign/transactions.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"transactions.d.ts","sourceRoot":"","sources":["../../../src/tools/sign/transactions.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwPvB,wBAoOC"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { randomBytes } from 'node:crypto';
|
|
2
2
|
import { encodeFunctionData, isAddress, parseAbiItem, parseUnits, toHex } from 'viem';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
+
import { tokenMeta } from '../../chain-meta.js';
|
|
4
5
|
import { getClientManager, SUPPORTED_CHAINS } from '../../client.js';
|
|
5
6
|
import { log } from '../../log.js';
|
|
6
7
|
import { buildTxPreview } from '../../preview.js';
|
|
7
8
|
import { signingCall } from '../../signing-requests.js';
|
|
8
|
-
import { createTool, formatResponse } from '../../utils.js';
|
|
9
|
+
import { convertArgumentsToTypes, createTool, formatResponse } from '../../utils.js';
|
|
9
10
|
import { getWalletClient } from '../../wallet-client.js';
|
|
10
11
|
import { getPhoneSigner } from '../../walletconnect.js';
|
|
11
12
|
import { failure } from './errors.js';
|
|
@@ -55,6 +56,29 @@ async function requirePhoneSession(identity, account) {
|
|
|
55
56
|
const from = session.accounts.find((a) => a.toLowerCase() === wanted) ?? session.accounts[0];
|
|
56
57
|
return { phone, session, from };
|
|
57
58
|
}
|
|
59
|
+
/** The phone's wallet reaches chains through its own RPC, which cannot see this machine's node. */
|
|
60
|
+
function requireReachable(chain, signWith) {
|
|
61
|
+
if (chain === 'localhost' && signWith === 'phone') {
|
|
62
|
+
throw new Error('A phone wallet cannot sign on localhost: it has no route to this machine\'s node. Use signWith "browser".');
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The token's own decimals. A caller-supplied figure is only a cross-check: trusting a wrong
|
|
67
|
+
* one moves orders of magnitude more or less than was asked for.
|
|
68
|
+
*/
|
|
69
|
+
async function tokenDecimals(chain, token, claimed) {
|
|
70
|
+
const onChain = (await tokenMeta(chain, token).catch(() => undefined))?.decimals;
|
|
71
|
+
if (onChain === undefined) {
|
|
72
|
+
if (claimed === undefined) {
|
|
73
|
+
throw new Error(`Could not read decimals() from ${token} on ${chain}. Check it is an ERC20 token on this chain, or pass "decimals" explicitly.`);
|
|
74
|
+
}
|
|
75
|
+
return claimed;
|
|
76
|
+
}
|
|
77
|
+
if (claimed !== undefined && claimed !== onChain) {
|
|
78
|
+
throw new Error(`"decimals" was ${claimed}, but ${token} reports ${onChain} on ${chain}. Nothing was sent.`);
|
|
79
|
+
}
|
|
80
|
+
return onChain;
|
|
81
|
+
}
|
|
58
82
|
/** Long enough for a congested chain, short enough that a stuck one is reported rather than hung on. */
|
|
59
83
|
const RECEIPT_TIMEOUT = 180_000;
|
|
60
84
|
/**
|
|
@@ -98,6 +122,7 @@ async function signOnPhone(chain, tx, identity, account, progress) {
|
|
|
98
122
|
*/
|
|
99
123
|
async function requestSignature(chain, tx, signWith, identity, account, progress) {
|
|
100
124
|
log('info', 'Transaction', `${chain} → ${tx.to}, signing with ${signWith}`);
|
|
125
|
+
requireReachable(chain, signWith);
|
|
101
126
|
if (signWith === 'phone')
|
|
102
127
|
return signOnPhone(chain, tx, identity, account, progress);
|
|
103
128
|
const wallet = getWalletClient(identity);
|
|
@@ -162,6 +187,8 @@ function previewSummary(preview) {
|
|
|
162
187
|
return {
|
|
163
188
|
action: preview.decoded?.intent ?? preview.decoded?.functionName,
|
|
164
189
|
protocol: preview.decoded?.protocol ?? preview.toLabel,
|
|
190
|
+
// Labels come from the contracts themselves, so the address they belong to goes too.
|
|
191
|
+
to: preview.to,
|
|
165
192
|
details: preview.decoded?.fields.map((f) => `${f.name}: ${f.value}${f.warning ? ` (${f.warning})` : ''}`),
|
|
166
193
|
simulation: preview.simulation
|
|
167
194
|
};
|
|
@@ -202,16 +229,21 @@ export default {
|
|
|
202
229
|
tokenAddress: z.string().describe('ERC20 token contract address'),
|
|
203
230
|
to: z.string().describe('Recipient address'),
|
|
204
231
|
amount: z.string().describe('Amount in token units (e.g., "100" for 100 USDC)'),
|
|
205
|
-
decimals: z
|
|
232
|
+
decimals: z
|
|
233
|
+
.number()
|
|
234
|
+
.int()
|
|
235
|
+
.optional()
|
|
236
|
+
.describe('Token decimals. Read from the token when omitted; when given, must match what the token reports.'),
|
|
206
237
|
signWith: SignWithSchema,
|
|
207
238
|
account: AccountSchema
|
|
208
239
|
}), async (args, identity) => {
|
|
209
240
|
try {
|
|
210
241
|
const tokenAddress = requireAddress('token address', args.tokenAddress);
|
|
211
242
|
const to = requireAddress('recipient address', args.to);
|
|
243
|
+
const decimals = await tokenDecimals(args.chain, tokenAddress, args.decimals);
|
|
212
244
|
const data = encodeFunctionData({
|
|
213
245
|
abi: [parseAbiItem('function transfer(address to, uint256 amount)')],
|
|
214
|
-
args: [to, parseUnits(args.amount,
|
|
246
|
+
args: [to, parseUnits(args.amount, decimals)]
|
|
215
247
|
});
|
|
216
248
|
const outcome = await signingCall({ identity, signer: args.signWith, summary: `Send ${args.amount} of ${tokenAddress} on ${args.chain} to ${to}` }, (progress) => requestSignature(args.chain, { to: tokenAddress, data, value: '0x0' }, args.signWith, identity, args.account, progress));
|
|
217
249
|
if (!outcome.done)
|
|
@@ -238,9 +270,16 @@ export default {
|
|
|
238
270
|
contractAddress: z.string().describe('Contract address'),
|
|
239
271
|
functionAbi: z.string().describe('Function ABI definition (e.g., "function transfer(address to, uint256 amount)")'),
|
|
240
272
|
args: z
|
|
241
|
-
.array(z.union([
|
|
273
|
+
.array(z.union([
|
|
274
|
+
z.string(),
|
|
275
|
+
// JSON numbers past 2^53 arrive already rounded, so signing one would send a different value.
|
|
276
|
+
z.number().refine(Number.isSafeInteger, {
|
|
277
|
+
message: 'Numbers must be integers within ±2^53-1. Pass large or exact values as strings, e.g. "1000000000000000000".'
|
|
278
|
+
}),
|
|
279
|
+
z.boolean()
|
|
280
|
+
]))
|
|
242
281
|
.optional()
|
|
243
|
-
.describe('Function arguments in order matching the ABI signature'),
|
|
282
|
+
.describe('Function arguments in order matching the ABI signature. Pass uint/int values as strings.'),
|
|
244
283
|
value: z.string().optional().describe('Optional native value to send with transaction (in ETH units, e.g., "0.1")'),
|
|
245
284
|
signWith: SignWithSchema,
|
|
246
285
|
account: AccountSchema
|
|
@@ -251,7 +290,7 @@ export default {
|
|
|
251
290
|
const data = encodeFunctionData({
|
|
252
291
|
abi: [abiItem],
|
|
253
292
|
functionName: abiItem.name,
|
|
254
|
-
args: (args.args || [])
|
|
293
|
+
args: convertArgumentsToTypes(args.args || [], abiItem.inputs)
|
|
255
294
|
});
|
|
256
295
|
const value = args.value ? `0x${parseUnits(args.value, 18).toString(16)}` : '0x0';
|
|
257
296
|
const outcome = await signingCall({ identity, signer: args.signWith, summary: `${abiItem.name}() on ${contractAddress} (${args.chain})` }, (progress) => requestSignature(args.chain, { to: contractAddress, data, value }, args.signWith, identity, args.account, progress));
|
|
@@ -281,8 +320,12 @@ export default {
|
|
|
281
320
|
try {
|
|
282
321
|
const sign = async (progress) => {
|
|
283
322
|
if (args.signWith === 'phone') {
|
|
284
|
-
const { phone, from } = await requirePhoneSession(identity, args.account);
|
|
285
|
-
|
|
323
|
+
const { phone, session, from } = await requirePhoneSession(identity, args.account);
|
|
324
|
+
// personal_sign is chain-agnostic, but the request still has to name a chain the session holds.
|
|
325
|
+
const chain = SUPPORTED_CHAINS.find((c) => session.chains.includes(getClientManager().getChainId(c)));
|
|
326
|
+
if (!chain)
|
|
327
|
+
throw new Error(`The paired wallet approved no chain this server knows: ${session.chains.join(', ')}.`);
|
|
328
|
+
return phone.request(chain, 'personal_sign', [toHex(args.message), from], {
|
|
286
329
|
identity,
|
|
287
330
|
account: args.account,
|
|
288
331
|
onWaiting: progress.waiting
|
|
@@ -294,7 +337,9 @@ export default {
|
|
|
294
337
|
id: generateRequestId(),
|
|
295
338
|
type: 'sign_message',
|
|
296
339
|
chain: 'any',
|
|
297
|
-
|
|
340
|
+
// Hex on both signers: a wallet reads a raw "0x…" string as bytes, so the same text
|
|
341
|
+
// would otherwise sign differently depending on where it was approved.
|
|
342
|
+
data: { message: toHex(args.message) }
|
|
298
343
|
});
|
|
299
344
|
};
|
|
300
345
|
const outcome = await signingCall({ identity, signer: args.signWith, summary: `Sign the message "${args.message.slice(0, 60)}"` }, sign);
|