dequanto 0.2.46 → 0.2.48
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/docs/ai/INDEX.md +41 -0
- package/docs/ai/examples/contract-read.spec.ts +44 -0
- package/docs/ai/examples/contract-write.spec.ts +16 -0
- package/docs/ai/examples/deploy-contract.spec.ts +32 -0
- package/docs/ai/examples/erc4337-userop.spec.ts +37 -0
- package/docs/ai/examples/explorer-abi.spec.ts +18 -0
- package/docs/ai/examples/generate-client.spec.ts +22 -0
- package/docs/ai/examples/index-events.spec.ts +27 -0
- package/docs/ai/examples/rpc-read.spec.ts +15 -0
- package/docs/ai/examples/safe-batch.spec.ts +55 -0
- package/docs/ai/examples/send-transaction.spec.ts +22 -0
- package/docs/ai/examples/storage-read.spec.ts +27 -0
- package/docs/ai/examples/token-transfer.spec.ts +22 -0
- package/docs/ai/references/contracts.md +111 -0
- package/docs/ai/references/deployments.md +98 -0
- package/docs/ai/references/events-indexing.md +97 -0
- package/docs/ai/references/explorer.md +77 -0
- package/docs/ai/references/generation.md +182 -0
- package/docs/ai/references/migration-from-ethers-viem.md +43 -0
- package/docs/ai/references/rpc-clients.md +115 -0
- package/docs/ai/references/safe-erc4337.md +134 -0
- package/docs/ai/references/storage.md +93 -0
- package/docs/ai/references/tokens-accounts.md +99 -0
- package/docs/ai/references/transactions.md +146 -0
- package/docs/ai/skill/dequanto/SKILL.md +59 -0
- package/lib/cjs/abi/$abiCoder.js +14 -0
- package/lib/cjs/abi/$abiCoder.js.map +1 -1
- package/lib/cjs/clients/ClientPool.js +14 -0
- package/lib/cjs/clients/ClientPool.js.map +1 -1
- package/lib/cjs/clients/Web3Client.js +14 -4
- package/lib/cjs/clients/Web3Client.js.map +1 -1
- package/lib/cjs/clients/Web3ClientFactory.js.map +1 -1
- package/lib/cjs/clients/model/ClientStatus.js +1 -0
- package/lib/cjs/clients/model/ClientStatus.js.map +1 -1
- package/lib/cjs/clients/utils/ClientErrorUtil.js +9 -0
- package/lib/cjs/clients/utils/ClientErrorUtil.js.map +1 -1
- package/lib/cjs/config/ConfigDefaults.js +0 -3
- package/lib/cjs/config/ConfigDefaults.js.map +1 -1
- package/lib/cjs/contracts/ContractCreationResolver.js +1 -0
- package/lib/cjs/contracts/ContractCreationResolver.js.map +1 -1
- package/lib/cjs/rpc/RpcBase.js +4 -1
- package/lib/cjs/rpc/RpcBase.js.map +1 -1
- package/lib/cjs/solidity/utils/$str.js +1 -1
- package/lib/cjs/solidity/utils/$str.js.map +1 -1
- package/lib/cjs/utils/$abiParser.js +85 -1
- package/lib/cjs/utils/$abiParser.js.map +1 -1
- package/lib/cjs/utils/$base.js +1 -1
- package/lib/cjs/utils/$base.js.map +1 -1
- package/lib/cjs/utils/$crypto.js.map +1 -1
- package/lib/cjs/utils/$hex.js +15 -3
- package/lib/cjs/utils/$hex.js.map +1 -1
- package/lib/esm/abi/$abiCoder.js.map +1 -1
- package/lib/esm/abi/$abiCoder.mjs +14 -0
- package/lib/esm/clients/ClientPool.js.map +1 -1
- package/lib/esm/clients/ClientPool.mjs +14 -0
- package/lib/esm/clients/Web3Client.js.map +1 -1
- package/lib/esm/clients/Web3Client.mjs +14 -4
- package/lib/esm/clients/Web3ClientFactory.js.map +1 -1
- package/lib/esm/clients/model/ClientStatus.js.map +1 -1
- package/lib/esm/clients/model/ClientStatus.mjs +1 -0
- package/lib/esm/clients/utils/ClientErrorUtil.js.map +1 -1
- package/lib/esm/clients/utils/ClientErrorUtil.mjs +9 -0
- package/lib/esm/config/ConfigDefaults.js.map +1 -1
- package/lib/esm/config/ConfigDefaults.mjs +0 -3
- package/lib/esm/contracts/ContractCreationResolver.js.map +1 -1
- package/lib/esm/contracts/ContractCreationResolver.mjs +1 -0
- package/lib/esm/rpc/RpcBase.js.map +1 -1
- package/lib/esm/rpc/RpcBase.mjs +4 -1
- package/lib/esm/solidity/utils/$str.js.map +1 -1
- package/lib/esm/solidity/utils/$str.mjs +1 -1
- package/lib/esm/utils/$abiParser.js.map +1 -1
- package/lib/esm/utils/$abiParser.mjs +85 -1
- package/lib/esm/utils/$base.js.map +1 -1
- package/lib/esm/utils/$base.mjs +1 -1
- package/lib/esm/utils/$crypto.js.map +1 -1
- package/lib/esm/utils/$hex.js.map +1 -1
- package/lib/esm/utils/$hex.mjs +15 -3
- package/lib/types/abi/$abiCoder.d.ts +11 -9
- package/lib/types/clients/ClientPool.d.ts +2 -0
- package/lib/types/clients/Web3Client.d.ts +4 -1
- package/lib/types/clients/Web3ClientFactory.d.ts +3 -2
- package/lib/types/clients/model/ClientStatus.d.ts +1 -0
- package/lib/types/clients/utils/ClientErrorUtil.d.ts +4 -0
- package/lib/types/contracts/ContractBase.d.ts +1 -1
- package/lib/types/contracts/wrappers/FnRequestWrapper.d.ts +1 -1
- package/lib/types/models/TAccount.d.ts +1 -1
- package/lib/types/rpc/RpcBase.d.ts +1 -0
- package/lib/types/utils/$abiParser.d.ts +6 -0
- package/lib/types/utils/$crypto.d.ts +3 -0
- package/lib/types/utils/$hex.d.ts +2 -0
- package/package.json +1 -1
- package/src/abi/$abiCoder.ts +31 -10
- package/src/clients/ClientPool.ts +17 -1
- package/src/clients/Web3Client.ts +20 -7
- package/src/clients/Web3ClientFactory.ts +10 -5
- package/src/clients/model/ClientStatus.ts +1 -0
- package/src/clients/utils/ClientErrorUtil.ts +8 -0
- package/src/config/ConfigDefaults.ts +0 -3
- package/src/contracts/ContractCreationResolver.ts +1 -0
- package/src/contracts/wrappers/FnRequestWrapper.ts +1 -1
- package/src/models/TAccount.ts +1 -1
- package/src/rpc/RpcBase.ts +5 -1
- package/src/solidity/utils/$str.ts +1 -1
- package/src/utils/$abiParser.ts +93 -1
- package/src/utils/$base.ts +1 -1
- package/src/utils/$crypto.ts +1 -0
- package/src/utils/$hex.ts +12 -3
|
@@ -6,16 +6,19 @@ import { Config } from '@dequanto/config/Config';
|
|
|
6
6
|
import { EvmWeb3Client } from './EvmWeb3Client';
|
|
7
7
|
import { $require } from '@dequanto/utils/$require';
|
|
8
8
|
import { $config } from '@dequanto/utils/$config';
|
|
9
|
+
import type { HardhatWeb3Client } from '@dequanto/hardhat/HardhatWeb3Client';
|
|
9
10
|
|
|
10
11
|
export namespace Web3ClientFactory {
|
|
11
12
|
|
|
12
|
-
export function get
|
|
13
|
+
export function get <
|
|
14
|
+
TClient extends EvmWeb3Client | HardhatWeb3Client = EvmWeb3Client
|
|
15
|
+
> (platform: TPlatform | number, opts?: IWeb3EndpointOptions): TClient {
|
|
13
16
|
if (typeof platform === 'string' && (platform === 'hardhat' || platform.startsWith('hh:'))) {
|
|
14
17
|
let client = di.resolve(HardhatProvider).client('localhost', opts);
|
|
15
18
|
if (platform.startsWith('hh:')) {
|
|
16
19
|
client.configureFork(platform.slice(3));
|
|
17
20
|
}
|
|
18
|
-
return client;
|
|
21
|
+
return client as TClient;
|
|
19
22
|
}
|
|
20
23
|
|
|
21
24
|
let options = $config.getWeb3Options(platform);
|
|
@@ -23,12 +26,14 @@ export namespace Web3ClientFactory {
|
|
|
23
26
|
return new EvmWeb3Client({
|
|
24
27
|
...options,
|
|
25
28
|
...(opts ?? {})
|
|
26
|
-
});
|
|
29
|
+
}) as TClient;
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
/** Same as the sync variant, but ensures the config is fetched */
|
|
30
|
-
export async function getAsync
|
|
33
|
+
export async function getAsync <
|
|
34
|
+
TClient extends EvmWeb3Client | HardhatWeb3Client = EvmWeb3Client
|
|
35
|
+
> (platform: TPlatform | string | number, opts?: IWeb3EndpointOptions): Promise<TClient> {
|
|
31
36
|
let cfg = await Config.get();
|
|
32
|
-
return get(platform, opts);
|
|
37
|
+
return get<TClient>(platform, opts);
|
|
33
38
|
}
|
|
34
39
|
}
|
|
@@ -14,6 +14,14 @@ export namespace ClientErrorUtil {
|
|
|
14
14
|
}
|
|
15
15
|
return false;
|
|
16
16
|
}
|
|
17
|
+
export function isNodeConfigurationError (error: Error & { code?, reason? }) {
|
|
18
|
+
let str = error.message ?? error.stack;
|
|
19
|
+
let noHistory = /history unavailable/i.test(str);
|
|
20
|
+
if (noHistory) {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
17
25
|
export function isAlreadyKnown (error: Error & { code?, reason? }) {
|
|
18
26
|
return /already known/i.test(error.message);
|
|
19
27
|
}
|
|
@@ -72,6 +72,7 @@ class BlockchainExplorerDateResolver {
|
|
|
72
72
|
throw error;
|
|
73
73
|
}
|
|
74
74
|
let tx = await this.client.getTransaction(info.txHash);
|
|
75
|
+
$require.notNull(tx, `Tx not found: ${info.txHash} in ${this.client.network} (${this.client.options?.endpoints?.[0]?.url})`);
|
|
75
76
|
let block = await this.client.getBlock(tx.blockNumber);
|
|
76
77
|
return {
|
|
77
78
|
tx: tx.hash,
|
|
@@ -9,7 +9,7 @@ export namespace FnRequestWrapper {
|
|
|
9
9
|
|
|
10
10
|
type TRequests<T extends ContractBase> = {
|
|
11
11
|
[K in keyof T]: T[K] extends (...any) => Promise<any>
|
|
12
|
-
? (...params: Parameters<T[K]>) => ContractReaderUtils.IContractReadParams<Awaited<ReturnType<T[K]
|
|
12
|
+
? (...params: Parameters<T[K]>) => Promise<ContractReaderUtils.IContractReadParams<Awaited<ReturnType<T[K]>>>>
|
|
13
13
|
: never
|
|
14
14
|
}
|
|
15
15
|
|
package/src/models/TAccount.ts
CHANGED
|
@@ -65,7 +65,7 @@ export interface TimelockAccount extends IAccount {
|
|
|
65
65
|
// Erc4337 account must include platform information
|
|
66
66
|
platform: TPlatform
|
|
67
67
|
|
|
68
|
-
operator:
|
|
68
|
+
operator: IAccount
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
export type TAccount = string | IAccount | EoAccount | SafeAccount | Erc4337Account;
|
package/src/rpc/RpcBase.ts
CHANGED
|
@@ -122,7 +122,7 @@ export abstract class RpcBase {
|
|
|
122
122
|
};
|
|
123
123
|
}
|
|
124
124
|
private _unwrapBody (resp: any): any {
|
|
125
|
-
return resp
|
|
125
|
+
return RpcBase.unwrapBody(resp);
|
|
126
126
|
}
|
|
127
127
|
private _deserialize (method: string, result: any) {
|
|
128
128
|
let { methods, schemas } = this.returnSchemas;
|
|
@@ -141,6 +141,10 @@ export abstract class RpcBase {
|
|
|
141
141
|
|
|
142
142
|
|
|
143
143
|
protected abstract returnSchemas
|
|
144
|
+
|
|
145
|
+
static unwrapBody (resp: any) {
|
|
146
|
+
return resp.result;
|
|
147
|
+
}
|
|
144
148
|
}
|
|
145
149
|
|
|
146
150
|
|
package/src/utils/$abiParser.ts
CHANGED
|
@@ -86,6 +86,69 @@ export namespace $abiParser {
|
|
|
86
86
|
};
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Parses Solidity struct declarations into a tuple ABI component.
|
|
92
|
+
* Supports multiple declarations so later structs can reference earlier ones,
|
|
93
|
+
* and returns the ABI component for the last struct in the input.
|
|
94
|
+
*/
|
|
95
|
+
export function parseStruct (struct: string): TAbiItem {
|
|
96
|
+
let structs = Parse.structs(struct);
|
|
97
|
+
$require.gt(structs.length, 0, `No structs found in ${struct}`);
|
|
98
|
+
|
|
99
|
+
let byName = new Map(structs.map(x => [ x.name, x ]));
|
|
100
|
+
let cache = new Map<string, TAbiInput>();
|
|
101
|
+
|
|
102
|
+
function toTuple (name: string): TAbiInput {
|
|
103
|
+
let cached = cache.get(name);
|
|
104
|
+
if (cached != null) {
|
|
105
|
+
return cached;
|
|
106
|
+
}
|
|
107
|
+
let def = byName.get(name);
|
|
108
|
+
$require.notNull(def, `Struct ${name} is not found`);
|
|
109
|
+
|
|
110
|
+
let tuple: TAbiInput = {
|
|
111
|
+
name: '',
|
|
112
|
+
type: 'tuple',
|
|
113
|
+
internalType: `struct ${name}`,
|
|
114
|
+
components: []
|
|
115
|
+
};
|
|
116
|
+
cache.set(name, tuple);
|
|
117
|
+
tuple.components = Parse.splitByDelimiter(def.body, ';')
|
|
118
|
+
.map(field => $abiParser.parseArguments(field)[0])
|
|
119
|
+
.map(resolveStructs);
|
|
120
|
+
|
|
121
|
+
return tuple;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function resolveStructs (param: TAbiInput): TAbiInput {
|
|
125
|
+
let { type, array } = Parse.extractArray(param.type);
|
|
126
|
+
if (byName.has(type) === false) {
|
|
127
|
+
if (param.components != null) {
|
|
128
|
+
return {
|
|
129
|
+
...param,
|
|
130
|
+
components: param.components.map(resolveStructs)
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
return param;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
let tuple = toTuple(type);
|
|
137
|
+
return {
|
|
138
|
+
name: param.name,
|
|
139
|
+
type: `tuple${array}`,
|
|
140
|
+
internalType: `struct ${type}${array}`,
|
|
141
|
+
components: tuple.components
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
let last = structs[structs.length - 1];
|
|
146
|
+
return {
|
|
147
|
+
...toTuple(last.name),
|
|
148
|
+
name: last.name
|
|
149
|
+
} as any as TAbiItem;
|
|
150
|
+
}
|
|
151
|
+
|
|
89
152
|
// uint256
|
|
90
153
|
// address[]
|
|
91
154
|
// (uint256, uint256)
|
|
@@ -247,6 +310,35 @@ namespace Parse {
|
|
|
247
310
|
|
|
248
311
|
const CLOSE_CHARS = {
|
|
249
312
|
'[': ']',
|
|
250
|
-
'(': ')'
|
|
313
|
+
'(': ')',
|
|
314
|
+
'{': '}'
|
|
251
315
|
};
|
|
316
|
+
|
|
317
|
+
export function structs (source: string) {
|
|
318
|
+
let rgx = /\bstruct\s+(?<name>[\w_$]+)\s*\{/g;
|
|
319
|
+
let arr: { name: string, body: string }[] = [];
|
|
320
|
+
let match: RegExpExecArray;
|
|
321
|
+
while ((match = rgx.exec(source)) != null) {
|
|
322
|
+
let openI = source.indexOf('{', match.index);
|
|
323
|
+
let closeI = goToClosing(source, openI, '{');
|
|
324
|
+
arr.push({
|
|
325
|
+
name: match.groups.name,
|
|
326
|
+
body: source.substring(openI + 1, closeI).trim()
|
|
327
|
+
});
|
|
328
|
+
rgx.lastIndex = closeI + 1;
|
|
329
|
+
}
|
|
330
|
+
return arr;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
export function extractArray (type: string) {
|
|
334
|
+
let array = '';
|
|
335
|
+
while (true) {
|
|
336
|
+
let match = /^(?<type>.+?)(?<array>\[[^\]]*\])$/.exec(type);
|
|
337
|
+
if (match == null) {
|
|
338
|
+
return { type, array };
|
|
339
|
+
}
|
|
340
|
+
type = match.groups.type;
|
|
341
|
+
array = `${match.groups.array}${array}`;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
252
344
|
}
|
package/src/utils/$base.ts
CHANGED
package/src/utils/$crypto.ts
CHANGED
|
@@ -8,6 +8,7 @@ interface ICrypto {
|
|
|
8
8
|
randomUUID(): `${string}-${string}-${string}-${string}-${string}`;
|
|
9
9
|
createECDH(curve: string)
|
|
10
10
|
|
|
11
|
+
sha256 (mix: string | TEth.Hex | Uint8Array, opts?: { encoding: 'hex' }): Promise<TEth.Hex>;
|
|
11
12
|
sha256 (mix: string | TEth.Hex | Uint8Array): Promise<Uint8Array>;
|
|
12
13
|
|
|
13
14
|
encrypt(buffer: string | TEth.Hex | Uint8Array, opts: IEncryptionParams & { encoding?: undefined | 'binary' }): Promise<Uint8Array>
|
package/src/utils/$hex.ts
CHANGED
|
@@ -24,10 +24,19 @@ export namespace $hex {
|
|
|
24
24
|
* Trims '00' bytes from start or end, e.g. 0x68656c6c6f000000 => 0x68656c6c6f
|
|
25
25
|
*/
|
|
26
26
|
export function trimBytes(hex: TEth.Hex): TEth.Hex {
|
|
27
|
-
|
|
27
|
+
return trimBytesEnd(trimBytesStart(hex));
|
|
28
|
+
}
|
|
29
|
+
export function trimBytesStart(hex: TEth.Hex): TEth.Hex {
|
|
30
|
+
if (hex.startsWith('0x00') === false) {
|
|
28
31
|
return hex;
|
|
29
32
|
}
|
|
30
|
-
return hex.replace(/^0x(0{2})+/, '0x')
|
|
33
|
+
return hex.replace(/^0x(0{2})+/, '0x') as TEth.Hex;
|
|
34
|
+
}
|
|
35
|
+
export function trimBytesEnd(hex: TEth.Hex): TEth.Hex {
|
|
36
|
+
if (hex.endsWith('00') === false) {
|
|
37
|
+
return hex;
|
|
38
|
+
}
|
|
39
|
+
return hex.replace(/(0{2})+$/, '') as TEth.Hex;
|
|
31
40
|
}
|
|
32
41
|
export function trimLeadingZerosFromNumber(hex: string) {
|
|
33
42
|
hex = hex.replace(/^0x0*/, '');
|
|
@@ -114,7 +123,6 @@ export namespace $hex {
|
|
|
114
123
|
return hex;
|
|
115
124
|
}
|
|
116
125
|
|
|
117
|
-
|
|
118
126
|
/**
|
|
119
127
|
* Adds `0x` to the start if not present
|
|
120
128
|
*/
|
|
@@ -131,6 +139,7 @@ export namespace $hex {
|
|
|
131
139
|
if (typeof mix ==='boolean') {
|
|
132
140
|
return mix ? '0x1' : '0x0';
|
|
133
141
|
}
|
|
142
|
+
$require.match(/^(0x)?[\da-f]*$/i, mix, 'NotValidHex');
|
|
134
143
|
if (mix.startsWith('0x')) {
|
|
135
144
|
return mix as TEth.Hex;
|
|
136
145
|
}
|