dequanto 0.2.48 → 0.2.50

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.
Files changed (142) hide show
  1. package/contracts/oz/Proxy.sol +1 -0
  2. package/docs/ai/INDEX.md +4 -3
  3. package/docs/ai/examples/config.spec.ts +113 -0
  4. package/docs/ai/examples/contract-read.spec.ts +81 -13
  5. package/docs/ai/examples/contract-write.spec.ts +61 -9
  6. package/docs/ai/examples/deploy-contract.spec.ts +53 -16
  7. package/docs/ai/examples/erc4337-userop.spec.ts +7 -5
  8. package/docs/ai/examples/explorer-abi.spec.ts +9 -6
  9. package/docs/ai/examples/{generate-client.spec.ts → generate-contract-class.spec.ts} +6 -3
  10. package/docs/ai/examples/index-events.spec.ts +8 -6
  11. package/docs/ai/examples/rpc-read.spec.ts +32 -5
  12. package/docs/ai/examples/safe-batch.spec.ts +5 -4
  13. package/docs/ai/examples/send-transaction.spec.ts +23 -11
  14. package/docs/ai/examples/storage-read.spec.ts +15 -7
  15. package/docs/ai/examples/token-transfer.spec.ts +22 -15
  16. package/docs/ai/references/generation.md +30 -7
  17. package/docs/ai/skill/dequanto/SKILL.md +5 -1
  18. package/lib/cjs/abi/$abi.js +60 -0
  19. package/lib/cjs/abi/$abi.js.map +1 -0
  20. package/lib/cjs/abi/$abiCoder.js +1 -0
  21. package/lib/cjs/abi/$abiCoder.js.map +1 -1
  22. package/lib/cjs/abi/abi-coder.js +1 -1
  23. package/lib/cjs/abi/abi-coder.js.map +1 -1
  24. package/lib/cjs/blocks/BlockDateResolver.js.map +1 -1
  25. package/lib/cjs/clients/Web3Client.js +43 -2
  26. package/lib/cjs/clients/Web3Client.js.map +1 -1
  27. package/lib/cjs/clients/Web3ClientFactory.js +26 -4
  28. package/lib/cjs/clients/Web3ClientFactory.js.map +1 -1
  29. package/lib/cjs/clients/debug/ClientDebugMethods.js +4 -0
  30. package/lib/cjs/clients/debug/ClientDebugMethods.js.map +1 -1
  31. package/lib/cjs/clients/utils/$web3Abi.js +1 -1
  32. package/lib/cjs/clients/utils/$web3Abi.js.map +1 -1
  33. package/lib/cjs/config/Config.js +28 -6
  34. package/lib/cjs/config/Config.js.map +1 -1
  35. package/lib/cjs/config/ConfigDefaults.js +6 -2
  36. package/lib/cjs/config/ConfigDefaults.js.map +1 -1
  37. package/lib/cjs/config/ConfigProvider.js +5 -0
  38. package/lib/cjs/config/ConfigProvider.js.map +1 -1
  39. package/lib/cjs/config/DefaultFactory.js +27 -0
  40. package/lib/cjs/config/DefaultFactory.js.map +1 -0
  41. package/lib/cjs/contracts/ContractBase.js +6 -2
  42. package/lib/cjs/contracts/ContractBase.js.map +1 -1
  43. package/lib/cjs/contracts/ContractReader.js +1 -35
  44. package/lib/cjs/contracts/ContractReader.js.map +1 -1
  45. package/lib/cjs/explorer/BlockchainExplorerFactory.js.map +1 -1
  46. package/lib/cjs/rpc/RpcContract.js +4 -32
  47. package/lib/cjs/rpc/RpcContract.js.map +1 -1
  48. package/lib/cjs/utils/$account.js +5 -0
  49. package/lib/cjs/utils/$account.js.map +1 -1
  50. package/lib/cjs/utils/$config.js +4 -5
  51. package/lib/cjs/utils/$config.js.map +1 -1
  52. package/lib/cjs/utils/$erc20.js +47 -0
  53. package/lib/cjs/utils/$erc20.js.map +1 -0
  54. package/lib/cjs/utils/$hex.js +1 -0
  55. package/lib/cjs/utils/$hex.js.map +1 -1
  56. package/lib/cjs/utils/$require.js +6 -2
  57. package/lib/cjs/utils/$require.js.map +1 -1
  58. package/lib/esm/abi/$abi.js.map +1 -0
  59. package/lib/esm/abi/$abi.mjs +57 -0
  60. package/lib/esm/abi/$abiCoder.js.map +1 -1
  61. package/lib/esm/abi/$abiCoder.mjs +1 -0
  62. package/lib/esm/abi/abi-coder.js.map +1 -1
  63. package/lib/esm/abi/abi-coder.mjs +1 -1
  64. package/lib/esm/blocks/BlockDateResolver.js.map +1 -1
  65. package/lib/esm/clients/Web3Client.js.map +1 -1
  66. package/lib/esm/clients/Web3Client.mjs +43 -2
  67. package/lib/esm/clients/Web3ClientFactory.js.map +1 -1
  68. package/lib/esm/clients/Web3ClientFactory.mjs +26 -4
  69. package/lib/esm/clients/debug/ClientDebugMethods.js.map +1 -1
  70. package/lib/esm/clients/debug/ClientDebugMethods.mjs +4 -0
  71. package/lib/esm/clients/utils/$web3Abi.js.map +1 -1
  72. package/lib/esm/clients/utils/$web3Abi.mjs +1 -1
  73. package/lib/esm/config/Config.js.map +1 -1
  74. package/lib/esm/config/Config.mjs +28 -6
  75. package/lib/esm/config/ConfigDefaults.js.map +1 -1
  76. package/lib/esm/config/ConfigDefaults.mjs +6 -2
  77. package/lib/esm/config/ConfigProvider.js.map +1 -1
  78. package/lib/esm/config/ConfigProvider.mjs +5 -0
  79. package/lib/esm/config/DefaultFactory.js.map +1 -0
  80. package/lib/esm/config/DefaultFactory.mjs +23 -0
  81. package/lib/esm/contracts/ContractBase.js.map +1 -1
  82. package/lib/esm/contracts/ContractBase.mjs +6 -2
  83. package/lib/esm/contracts/ContractReader.js.map +1 -1
  84. package/lib/esm/contracts/ContractReader.mjs +1 -35
  85. package/lib/esm/explorer/BlockchainExplorerFactory.js.map +1 -1
  86. package/lib/esm/rpc/RpcContract.js.map +1 -1
  87. package/lib/esm/rpc/RpcContract.mjs +4 -32
  88. package/lib/esm/utils/$account.js.map +1 -1
  89. package/lib/esm/utils/$account.mjs +5 -0
  90. package/lib/esm/utils/$config.js.map +1 -1
  91. package/lib/esm/utils/$config.mjs +4 -5
  92. package/lib/esm/utils/$erc20.js.map +1 -0
  93. package/lib/esm/utils/$erc20.mjs +41 -0
  94. package/lib/esm/utils/$hex.js.map +1 -1
  95. package/lib/esm/utils/$hex.mjs +1 -0
  96. package/lib/esm/utils/$require.js.map +1 -1
  97. package/lib/esm/utils/$require.mjs +6 -2
  98. package/lib/types/abi/$abi.d.ts +17 -0
  99. package/lib/types/abi/$abiCoder.d.ts +2 -1
  100. package/lib/types/blocks/BlockDateResolver.d.ts +1 -1
  101. package/lib/types/clients/Web3Client.d.ts +1 -1
  102. package/lib/types/clients/Web3ClientFactory.d.ts +10 -2
  103. package/lib/types/clients/debug/ClientDebugMethods.d.ts +1 -1
  104. package/lib/types/config/AConfigBase.d.ts +3 -0
  105. package/lib/types/config/Config.d.ts +2 -1
  106. package/lib/types/config/DefaultFactory.d.ts +2 -0
  107. package/lib/types/config/interface/IConfigData.d.ts +14 -2
  108. package/lib/types/contracts/ContractReader.d.ts +1 -1
  109. package/lib/types/explorer/IBlockchainExplorer.d.ts +6 -0
  110. package/lib/types/models/TPlatform.d.ts +1 -1
  111. package/lib/types/utils/$account.d.ts +1 -0
  112. package/lib/types/utils/$erc20.d.ts +5 -0
  113. package/lib/types/utils/$hex.d.ts +1 -0
  114. package/lib/types/utils/$require.d.ts +6 -6
  115. package/package.json +1 -1
  116. package/src/abi/$abi.ts +69 -0
  117. package/src/abi/$abiCoder.ts +1 -1
  118. package/src/abi/abi-coder.ts +1 -3
  119. package/src/blocks/BlockDateResolver.ts +1 -1
  120. package/src/clients/Web3Client.ts +48 -3
  121. package/src/clients/Web3ClientFactory.ts +33 -5
  122. package/src/clients/debug/ClientDebugMethods.ts +5 -1
  123. package/src/clients/utils/$web3Abi.ts +2 -2
  124. package/src/config/AConfigBase.ts +4 -0
  125. package/src/config/Config.ts +30 -8
  126. package/src/config/ConfigDefaults.ts +6 -2
  127. package/src/config/ConfigProvider.ts +5 -1
  128. package/src/config/DefaultFactory.ts +26 -0
  129. package/src/config/interface/IConfigData.ts +15 -2
  130. package/src/contracts/ContractBase.ts +6 -2
  131. package/src/contracts/ContractReader.ts +3 -40
  132. package/src/explorer/BlockchainExplorerFactory.ts +0 -1
  133. package/src/explorer/IBlockchainExplorer.ts +4 -0
  134. package/src/models/TPlatform.ts +1 -0
  135. package/src/rpc/RpcContract.ts +5 -33
  136. package/src/utils/$account.ts +5 -0
  137. package/src/utils/$config.ts +4 -6
  138. package/src/utils/$erc20.ts +53 -0
  139. package/src/utils/$hex.ts +3 -1
  140. package/src/utils/$require.ts +8 -4
  141. package/tsconfig.json +1 -2
  142. package/tsconfig.umd.json +1 -2
@@ -7,6 +7,7 @@ import { EvmWeb3Client } from './EvmWeb3Client';
7
7
  import { $require } from '@dequanto/utils/$require';
8
8
  import { $config } from '@dequanto/utils/$config';
9
9
  import type { HardhatWeb3Client } from '@dequanto/hardhat/HardhatWeb3Client';
10
+ import { IConfigData } from '@dequanto/config/interface/IConfigData';
10
11
 
11
12
  export namespace Web3ClientFactory {
12
13
 
@@ -14,9 +15,23 @@ export namespace Web3ClientFactory {
14
15
  TClient extends EvmWeb3Client | HardhatWeb3Client = EvmWeb3Client
15
16
  > (platform: TPlatform | number, opts?: IWeb3EndpointOptions): TClient {
16
17
  if (typeof platform === 'string' && (platform === 'hardhat' || platform.startsWith('hh:'))) {
17
- let client = di.resolve(HardhatProvider).client('localhost', opts);
18
- if (platform.startsWith('hh:')) {
19
- client.configureFork(platform.slice(3));
18
+ // hardhat - local hardhat network
19
+ // hh:eth - local hardhat network (which runs as a fork)
20
+ // hh:memory - in-memory hardhat network
21
+ // hh:memory:eth - getAsync only: in-memory forked hardhat network
22
+ if (platform.startsWith('hh:memory:')) {
23
+ throw new Error(`use getAsync to resolve forked "${platform}" client`);
24
+ }
25
+
26
+ let network = platform.startsWith('hh:')
27
+ ? platform.slice(3)
28
+ : null;
29
+ let hh = network === 'memory'
30
+ ? 'hardhat' as const
31
+ : 'localhost' as const;
32
+ let client = di.resolve(HardhatProvider).client(hh, opts);
33
+ if (network != null && network !== 'memory') {
34
+ client.configureFork(network);
20
35
  }
21
36
  return client as TClient;
22
37
  }
@@ -29,11 +44,24 @@ export namespace Web3ClientFactory {
29
44
  }) as TClient;
30
45
  }
31
46
 
47
+ type HHInMemoryForkData = {
48
+ block?: number
49
+ url?: string
50
+ }
32
51
  /** Same as the sync variant, but ensures the config is fetched */
33
52
  export async function getAsync <
34
53
  TClient extends EvmWeb3Client | HardhatWeb3Client = EvmWeb3Client
35
- > (platform: TPlatform | string | number, opts?: IWeb3EndpointOptions): Promise<TClient> {
36
- let cfg = await Config.get();
54
+ > (platform: TPlatform | string | number, opts?: IWeb3EndpointOptions & HHInMemoryForkData & { config?: Partial<IConfigData>}): Promise<TClient> {
55
+ let cfg = await Config.get(opts?.config);
56
+ if (typeof platform === 'string' && platform.startsWith('hh:memory:')) {
57
+ let network = platform.replace('hh:memory:', '');
58
+ let client = await di.resolve(HardhatProvider).forked({
59
+ platform: network,
60
+ block: opts?.block,
61
+ url: opts?.url,
62
+ });
63
+ return client as TClient;
64
+ }
37
65
  return get<TClient>(platform, opts);
38
66
  }
39
67
  }
@@ -7,6 +7,7 @@ import { $hex } from '@dequanto/utils/$hex';
7
7
  import { TEth } from '@dequanto/models/TEth';
8
8
  import { $array } from '@dequanto/utils/$array';
9
9
  import { $date } from '@dequanto/utils/$date';
10
+ import { $number } from '@dequanto/utils/$number';
10
11
 
11
12
 
12
13
  export class ClientDebugMethods {
@@ -53,10 +54,13 @@ export class ClientDebugMethods {
53
54
  return this.call('mine', ...args);
54
55
  }
55
56
 
56
- setBalance (address: TAddress, amount: bigint | string) {
57
+ setBalance (address: TAddress, amount: bigint | number | string) {
57
58
  if (typeof amount === 'bigint') {
58
59
  amount = $bigint.toHex(amount);
59
60
  }
61
+ if (typeof amount === 'number') {
62
+ amount = $number.toHex(amount);
63
+ }
60
64
  return this.call('setBalance', address, amount);
61
65
  }
62
66
 
@@ -8,13 +8,13 @@ export namespace $web3Abi {
8
8
  let arr: TAbiItem[];
9
9
  if (typeof abi === 'string') {
10
10
  arr = [ $abiParser.parseMethod(abi) ];
11
- } else if (Array.isArray(abi)) {
11
+ } else if (Array.isArray(abi)) {
12
12
  arr = abi;
13
13
  } else {
14
14
  arr = [ abi ];
15
15
  }
16
16
 
17
- let first = abi[0];
17
+ let first = arr[0];
18
18
  if (first.outputs == null || first.outputs.length === 0) {
19
19
  // Normalize outputs to read at least bytes if nothing is set
20
20
  first.outputs = [
@@ -5,6 +5,10 @@ import { TEth } from '@dequanto/models/TEth'
5
5
 
6
6
  type TConfigParamsBase = {
7
7
  config?: Partial<IConfigData>
8
+ // alias for config.web3.platform.endpoints
9
+ rpc?: {
10
+ [platform: string]: string | string[] | IConfigData['web3']['']['endpoints']
11
+ }
8
12
  }
9
13
 
10
14
  export type TConfigParamsNode = TConfigParamsBase & {
@@ -12,6 +12,27 @@ export class Config {
12
12
  static async fetch (parameters?: TConfigParamsNode | TConfigParamsBrowser): Promise<Appcfg<IConfigData> & IConfigData> {
13
13
  singleton ??= new class_Dfr();
14
14
 
15
+ if (parameters?.rpc) {
16
+ parameters.config ??= {};
17
+ parameters.config.web3 ??= {};
18
+ for (let platform in parameters.rpc) {
19
+ parameters.config.web3[platform] ??= {} as any;
20
+ parameters.config.web3[platform].endpoints = [];
21
+ let val = parameters.rpc[platform];
22
+ if (typeof val === 'string') {
23
+ parameters.config.web3[platform].endpoints.push({
24
+ url: val
25
+ });
26
+ continue;
27
+ }
28
+ if (Array.isArray(val) && typeof val[0] === 'string') {
29
+ parameters.config.web3[platform].endpoints.push(...val.map(url => ({url})));
30
+ continue;
31
+ }
32
+ parameters.config.web3[platform].endpoints = val as any;
33
+ }
34
+ }
35
+
15
36
  let cfg = await provider.fetch(parameters);
16
37
 
17
38
  obj_extend(config, cfg);
@@ -28,21 +49,22 @@ export class Config {
28
49
  }
29
50
 
30
51
  /** Will return a config that was previously loaded by fetch with any parameters or will trigger fetch with default parameters */
31
- static async get (): Promise<Appcfg<IConfigData> & IConfigData> {
32
- if (singleton != null) {
52
+ static async get (config?: Partial<IConfigData>): Promise<Appcfg<IConfigData> & IConfigData> {
53
+ if (singleton != null && config == null) {
33
54
  return singleton;
34
55
  }
35
- return Config.fetch();
56
+ return Config.fetch({ config });
36
57
  }
37
58
 
38
- // static async getExplorerConfig (platform: TPlatform | number): Promise<TExplorer> {
39
- // let config = await Config.get();
40
-
41
- // }
42
-
43
59
  static async extend (json) {
44
60
  await provider.extend(json);
45
61
  }
62
+
63
+ static clean (): Config {
64
+ memd.fn.clearMemoized(Config.fetch);
65
+ singleton = null;
66
+ return Config;
67
+ }
46
68
  }
47
69
 
48
70
  export const config = { } as IConfigData;
@@ -1,5 +1,6 @@
1
1
  import { IConfigData } from './interface/IConfigData';
2
- export const ConfigDefaults = <IConfigData> {
2
+ import { DefaultFactory } from './DefaultFactory';
3
+ export const ConfigDefaults = DefaultFactory({
3
4
  "accounts": null,
4
5
  "settings": {
5
6
  "generate": {
@@ -116,6 +117,9 @@ export const ConfigDefaults = <IConfigData> {
116
117
  "chainId": 1,
117
118
  "chainToken": "ETH",
118
119
  "endpoints": [
120
+ {
121
+ "url": "https://ethereum-rpc.publicnode.com"
122
+ },
119
123
  {
120
124
  "url": "https://eth.drpc.org",
121
125
  "rateLimit": "2000/5m"
@@ -504,4 +508,4 @@ export const ConfigDefaults = <IConfigData> {
504
508
  "base": "0x00000000000D6FFc74A8feb35aF5827bf57f6786",
505
509
  "linea": "0x00000000000D6FFc74A8feb35aF5827bf57f6786"
506
510
  }
507
- };
511
+ });
@@ -33,7 +33,6 @@ export class ConfigProvider implements IConfigProvider {
33
33
  ;
34
34
 
35
35
  let cfg = await AppConfig.fetch<IConfigData>(sources);
36
-
37
36
  if (this.config != null) {
38
37
  this.config.$extend(cfg.toJSON());
39
38
  } else {
@@ -102,6 +101,11 @@ export class ConfigProvider implements IConfigProvider {
102
101
  parameters?.dotenv ? {
103
102
  dotenv: true
104
103
  } : null,
104
+ parameters?.config ? {
105
+ sync: true,
106
+ extendArrays: false,
107
+ config: parameters.config
108
+ } : null,
105
109
  ];
106
110
  }
107
111
 
@@ -0,0 +1,26 @@
1
+ import { IConfigData } from './interface/IConfigData';
2
+
3
+ export function DefaultFactory (config: IConfigData): IConfigData {
4
+
5
+ if (typeof process !== 'undefined' && process.env != null) {
6
+ for (let key in process.env) {
7
+ if (key.startsWith('RPC_') === false) {
8
+ continue;
9
+ }
10
+ const platform = key.replace('RPC_', '').toLowerCase();
11
+ if (platform in config.web3 === false) {
12
+ continue;
13
+ }
14
+
15
+ const url = process.env[key];
16
+ if (/^(http|ws)/.test(url) === false) {
17
+ continue;
18
+ }
19
+ config.web3[platform].endpoints = [
20
+ { url: url }
21
+ ];
22
+ }
23
+ }
24
+
25
+ return config;
26
+ }
@@ -4,6 +4,7 @@ import { TAddress } from '@dequanto/models/TAddress';
4
4
  import { TPlatform } from '@dequanto/models/TPlatform';
5
5
  import { IRpcConfig } from '@dequanto/clients/ClientPool';
6
6
  import { TChain } from '@dequanto/models/TChain';
7
+ import { TEth } from '@dequanto/models/TEth';
7
8
 
8
9
 
9
10
  export interface IConfigData {
@@ -28,10 +29,10 @@ export interface IConfigData {
28
29
 
29
30
  blockchainExplorer: {
30
31
  [platform in TPlatform]: {
31
- key: string;
32
+ key?: string;
32
33
  host?: string;
33
34
  api?: string
34
- wwww?: string
35
+ www?: string
35
36
  };
36
37
  };
37
38
 
@@ -77,4 +78,16 @@ export interface IConfigData {
77
78
  [platform in TPlatform]: TAddress
78
79
  };
79
80
 
81
+ ns: {
82
+ [service: string]: {
83
+ [platform: string]: {
84
+ registry: TEth.Address
85
+ resolver?: TEth.Address
86
+ }
87
+ }
88
+ }
89
+
90
+ oracles: {
91
+ [service: string]: any
92
+ }
80
93
  }
@@ -299,14 +299,18 @@ export abstract class ContractBase {
299
299
 
300
300
  protected $read(abi: string | TAbiItem, ...params) {
301
301
  if (this.builderConfig?.send === 'manual') {
302
+ let abiJson = typeof abi === 'string'
303
+ ? $abiParser.parseMethod(abi)
304
+ : abi;
302
305
  let req = <ContractReaderUtils.IContractReadParams>{
303
306
  address: this.address,
304
- abi,
307
+ abi: abiJson,
305
308
  params: params,
306
309
  blockNumber: this.blockNumber ?? this.blockDate,
307
310
  options: {
308
311
  from: this.builderConfig?.from
309
- }
312
+ },
313
+ method: abiJson.name
310
314
  };
311
315
  return req;
312
316
  }
@@ -302,9 +302,9 @@ export class ContractReader implements IContractReader {
302
302
  return filters as RpcTypes.Filter;
303
303
  }
304
304
 
305
- static async read (client: Web3Client, address: TAddress, methodAbi: string){
305
+ static async read <TResult = any> (client: Web3Client, address: TAddress, methodAbi: string){
306
306
  let reader = new ContractReader(client);
307
- return reader.readAsync(address, methodAbi);
307
+ return reader.readAsync<TResult>(address, methodAbi);
308
308
  }
309
309
  }
310
310
 
@@ -357,43 +357,6 @@ export namespace ContractReaderUtils {
357
357
  export async function readAsyncBatch(client: Web3Client, requests: (IContractReadParams | null)[], options?: {
358
358
  allowErrors?: boolean
359
359
  }) {
360
-
361
- let rpcRequests = await alot(requests).map(async request => {
362
- if (request == null) {
363
- return null;
364
- }
365
- let abi = request.abi;
366
- if (typeof abi === 'string') {
367
- abi = $abiParser.parseMethod(abi);
368
- }
369
- let blockNumber = request.blockNumber;
370
- if (blockNumber instanceof Date) {
371
- let resolver = di.resolve(BlockDateResolver, client);
372
- blockNumber = await resolver.getBlockNumberFor(blockNumber);
373
- }
374
- return {
375
- address: request.address,
376
- abi: [ abi ],
377
- method: abi.name,
378
- params: request.params,
379
- blockNumber: blockNumber,
380
- options: request.options
381
- } as TRpcContractCall;
382
- }).toArrayAsync();
383
-
384
- let mapped = [];
385
- let rpcRequestsNotEmpty = [];
386
- for (let i = 0; i < rpcRequests.length; i++) {
387
- if (rpcRequests[i] == null) {
388
- continue;
389
- }
390
- let idx = rpcRequestsNotEmpty.push(rpcRequests[i]) - 1;
391
- mapped[i] = idx;
392
- }
393
-
394
- let outputs = await client.readContractBatch(rpcRequestsNotEmpty, options);
395
- return rpcRequests.map((_, i) => {
396
- return outputs[mapped[i]] ?? null;
397
- });
360
+ return await client.readContractBatch(requests, options);
398
361
  }
399
362
  }
@@ -58,7 +58,6 @@ export namespace BlockchainExplorerFactory {
58
58
 
59
59
  /** @obsolete Create instance directly with the get/getAsync method */
60
60
  export function create (opts: IBlockchainExplorerFactoryParams): Constructor<IBlockchainExplorer> {
61
-
62
61
  return class extends BlockchainExplorer {
63
62
  constructor (config?: IBlockchainExplorerFactoryParams) {
64
63
  super(config ?? opts);
@@ -3,9 +3,13 @@ import { IAbiProvider } from './IAbiProvider';
3
3
  import { TEth } from '@dequanto/models/TEth';
4
4
  import { TAddress } from '@dequanto/models/TAddress';
5
5
  import { IVerifier } from './verifiers/IVerifier';
6
+ import { TExplorerDefinition } from '@dequanto/models/TExplorer';
6
7
 
7
8
 
8
9
  export interface IBlockchainExplorer extends IAbiProvider, IVerifier {
10
+ config?: {
11
+ api?: { url?: string; key?: string }
12
+ }
9
13
  inMemoryDb: IContractDetails[]
10
14
  getContractMeta(q: string): Promise<IContractDetails>;
11
15
  getContractCreation(address: TEth.Address): Promise<{ creator: TEth.Address, txHash: TEth.Hex }>;
@@ -14,5 +14,6 @@ export type TPlatform = 'eth'
14
14
  | 'hardhat'
15
15
  | 'optimism'
16
16
  | 'avalanche'
17
+ | 'hh:memory'
17
18
  | `hh:${string}`
18
19
  | string;
@@ -2,11 +2,12 @@ import di from 'a-di';
2
2
  import alot from 'alot';
3
3
  import { Rpc, RpcTypes } from './Rpc';
4
4
 
5
- import { TAbiItem, TAbiOutput } from '@dequanto/types/TAbi';
5
+ import { TAbiItem } from '@dequanto/types/TAbi';
6
6
  import { TAddress } from '@dequanto/models/TAddress';
7
7
  import { $require } from '@dequanto/utils/$require';
8
8
  import { $abiUtils } from '@dequanto/utils/$abiUtils';
9
9
  import { $abiCoder } from '@dequanto/abi/$abiCoder';
10
+ import { $abi } from '@dequanto/abi/$abi';
10
11
  import { RpcError } from './RpcError';
11
12
  import { $hex } from '@dequanto/utils/$hex';
12
13
  import { TEth } from '@dequanto/models/TEth';
@@ -54,7 +55,7 @@ export class RpcContract {
54
55
  if (methodAbi == null) {
55
56
  return hex;
56
57
  }
57
- return utils.deserializeOutput(hex, methodAbi.outputs);
58
+ return $abi.decodeReturn(methodAbi, hex);
58
59
  } catch (err) {
59
60
  if (err instanceof RpcError) {
60
61
  err.message = `RpcCall ${req.method} (${JSON.stringify(req.params)}) ${err.message}`;
@@ -82,7 +83,7 @@ export class RpcContract {
82
83
  let defaults = null;
83
84
  try {
84
85
  const defaultHex = $abiCoder.encode(returnABI, [null]);
85
- defaults = utils.deserializeOutput(defaultHex, returnABI);
86
+ defaults = $abi.decodeReturn(abi, defaultHex);
86
87
  } catch (error) {}
87
88
  return {
88
89
  defaults,
@@ -90,7 +91,7 @@ export class RpcContract {
90
91
  };
91
92
  }
92
93
  let hex = typeof resp === 'string' ? resp : resp.data;
93
- let result = utils.deserializeOutput(hex, returnABI);
94
+ let result = $abi.decodeReturn(abi, hex);
94
95
  return result;
95
96
  });
96
97
 
@@ -191,32 +192,3 @@ export class RpcContract {
191
192
  // }
192
193
  }
193
194
 
194
-
195
- namespace utils {
196
- export function deserializeOutput(hex: string, outputs: TAbiOutput[]) {
197
-
198
- let abi = outputs;
199
- let isDynamic: boolean = null;
200
- if (outputs.length > 1) {
201
- let isNamedTuple = outputs.every(x => x.name != null && x.name !== '');
202
- if (isNamedTuple) {
203
- // Return as an object
204
- abi = [ { type: 'tuple', components: outputs, name: null } ];
205
- isDynamic = false;
206
- }
207
- }
208
-
209
- try {
210
- let arr = $abiCoder.decode(abi as any, hex, {
211
- dynamic: isDynamic
212
- });
213
- let value = abi.length === 1 ? arr[0] : arr;
214
- return value;
215
- } catch (error) {
216
- if (outputs.length === 1 && abi.length === 1) {
217
- return $abiCoder.decodeSingle(abi[0], hex);
218
- }
219
- throw error;
220
- }
221
- }
222
- }
@@ -1,6 +1,7 @@
1
1
  import { EoAccount, Erc4337Account, SafeAccount, TAccount, TimelockAccount } from "@dequanto/models/TAccount";
2
2
  import { $address } from './$address';
3
3
  import { $require } from './$require';
4
+ import { $sig } from './$sig';
4
5
 
5
6
  export namespace $account {
6
7
 
@@ -64,4 +65,8 @@ export namespace $account {
64
65
  // Optimistic match by pattern "timelock/";
65
66
  return rgx.test(account.name);
66
67
  }
68
+
69
+ export function generate(name: string): EoAccount {
70
+ return $sig.$account.generate({ name });
71
+ }
67
72
  }
@@ -16,8 +16,8 @@ export namespace $config {
16
16
  let envOptions = null;
17
17
 
18
18
  export function get <T = any> (path: string, $default?: T): T {
19
- let value = (typeof $global.app !== 'undefined' ? $global.app.config?.$get?.(path) : null)
20
- ?? obj_getProperty(config, path)
19
+ let value = obj_getProperty(config, path)
20
+ ?? (typeof $global.app !== 'undefined' ? $global.app.config?.$get?.(path) : null)
21
21
  ?? obj_getProperty(envOptions, path);
22
22
 
23
23
  if (value == null && envOptions == null) {
@@ -79,11 +79,10 @@ export namespace $config {
79
79
  let explorer = $config.get<IConfigData['blockchainExplorer']>(`blockchainExplorer`);
80
80
  let chains = $config.get<IConfigData['chains']>('chains', []);
81
81
 
82
-
83
82
  let explorerConfig = explorer[platform];
84
83
  let chainConfig = chains.find(x => x.platform === platform || x.aliases?.includes(platform));
85
84
 
86
- $require.notNull(explorerConfig || chainConfig, `Unsupported platform ${platform} for web3 client`);
85
+ $require.notNull(explorerConfig || chainConfig, `Unsupported platform ${platform} for blockchain explorer`);
87
86
  return {
88
87
  platform,
89
88
  ...(chainConfig?.explorers?.[0] ?? {}),
@@ -92,11 +91,10 @@ export namespace $config {
92
91
  }
93
92
 
94
93
  export function set <T = any> (path: string, value: T) {
94
+ obj_setProperty(config, path, value);
95
95
  if (typeof $global.app?.config?.$set === 'function') {
96
96
  $global.app.config.$set(path, value);
97
- return;
98
97
  }
99
- obj_setProperty(config, path, value);
100
98
  }
101
99
 
102
100
  /**
@@ -0,0 +1,53 @@
1
+ import alot from 'alot';
2
+ import { $require } from './$require';
3
+ import { $hex } from './$hex';
4
+ import { $bigint } from './$bigint';
5
+ import { TEth } from '@dequanto/models/TEth';
6
+ import { Web3Client } from '@dequanto/clients/Web3Client';
7
+ import { ERC20 } from '@dequanto/prebuilt/openzeppelin/ERC20';
8
+
9
+ export namespace $erc20 {
10
+ export async function setBalanceAny(client: Web3Client, token: TEth.Address, account: TEth.Address, amount: bigint | number) {
11
+ $require.eq(client.platform, 'hardhat', `Set Balance available only on Hardhat/Forked network`);
12
+ const erc20 = new ERC20(token, client);
13
+ const rpc = await client.getRpc();
14
+
15
+ const req = await (erc20.$data() as any).balanceOf(account);
16
+ const balanceTrace = await rpc.request({
17
+ method: 'debug_traceCall',
18
+ params: [
19
+ req,
20
+ 'latest',
21
+ {
22
+ disableMemory: true,
23
+ disableStack: true,
24
+ disableStorage: false,
25
+ }
26
+ ]
27
+ }) as {
28
+ returnValue: TEth.Hex
29
+ failed: boolean
30
+ structLogs: {
31
+ "op": "RETURN",
32
+ "pc": 1698,
33
+ "storage": Record<string, TEth.Hex>
34
+ }[]
35
+ };
36
+
37
+ $require.True(balanceTrace.failed === false, `erc20 balance retrieval failed for ${await erc20.symbol()}`);
38
+ let returnOp = alot(balanceTrace.structLogs.reverse()).find(x => x.op === 'RETURN');
39
+ $require.notNull(returnOp, `RETURN opcode not found`);
40
+ $require.notNull(returnOp.storage, `Storage not found`);
41
+
42
+ let returnValue = $hex.raw(balanceTrace.returnValue);
43
+ let slots = alot.fromObject(returnOp.storage).filter(x => x.value === returnValue).toArray();
44
+ $require.gt(slots.length, 0, `Slot not found`);
45
+ let SLOT = $hex.ensure(slots[slots.length - 1].key);
46
+
47
+ let balance = typeof amount === 'number'
48
+ ? await $bigint.toWei(amount, await erc20.decimals())
49
+ : amount;
50
+
51
+ await client.debug.setStorageAt(erc20.address, SLOT, $bigint.toHex(balance));
52
+ }
53
+ }
package/src/utils/$hex.ts CHANGED
@@ -3,7 +3,9 @@ import { $buffer } from './$buffer';
3
3
  import { $require } from './$require';
4
4
  export namespace $hex {
5
5
 
6
- export const ZERO = '0x'
6
+ export const ZERO = '0x';
7
+
8
+ export const ZERO_Bytes32 = '0x0000000000000000000000000000000000000000000000000000000000000000';
7
9
 
8
10
  /**
9
11
  * Adds '00' bytes to the hex string
@@ -61,17 +61,17 @@ export namespace $require {
61
61
  }
62
62
  return val;
63
63
  }
64
- export function notNull<T> (val: T, message: string, ...logs): NonNullable<T> {
64
+ export function notNull<T> (val: T, message?: string, ...logs): NonNullable<T> {
65
65
  if (val == null) {
66
66
  logs?.forEach(log => console.error(log));
67
- throw new Error(`Value is undefined. ${message}`);
67
+ throw new Error(`Value is undefined. ${message ?? ''}`);
68
68
  }
69
69
  return val;
70
70
  }
71
- export function Null<T> (val: T, message: string, ...logs): T {
71
+ export function Null<T> (val: T, message?: string, ...logs): T {
72
72
  if (val != null) {
73
73
  logs?.forEach(log => console.error(log));
74
- throw new Error(`Value ${val} expects to be undefined. ${message}`);
74
+ throw new Error(`Value ${val} expects to be undefined. ${message ?? ''}`);
75
75
  }
76
76
  return val;
77
77
  }
@@ -200,6 +200,7 @@ export namespace $require {
200
200
  if (a <= b) {
201
201
  throw new Error(`Expected a(${a}) > b(${b}). ${message}`);
202
202
  }
203
+ return a;
203
204
  }
204
205
  export function gte<T = number | bigint> (a: T, b: T, message: string = '') {
205
206
  Numeric(a);
@@ -207,6 +208,7 @@ export namespace $require {
207
208
  if (a < b) {
208
209
  throw new Error(`Expected a(${a}) > b(${b}). ${message}`);
209
210
  }
211
+ return a;
210
212
  }
211
213
 
212
214
  /**
@@ -218,6 +220,7 @@ export namespace $require {
218
220
  if (a >= b) {
219
221
  throw new Error(`Expected a(${a}) > b(${b}). ${message}`);
220
222
  }
223
+ return a;
221
224
  }
222
225
  export function lte<T = number | bigint> (a: T, b: T, message: string = '') {
223
226
  Numeric(a);
@@ -225,5 +228,6 @@ export namespace $require {
225
228
  if (a > b) {
226
229
  throw new Error(`Expected a(${a}) > b(${b}). ${message}`);
227
230
  }
231
+ return a;
228
232
  }
229
233
  }
package/tsconfig.json CHANGED
@@ -6,8 +6,7 @@
6
6
  "baseUrl": "./",
7
7
  "paths": {
8
8
  "@dequanto/*": [ "src/*" ],
9
- "dequanto/*": [ "src/*" ],
10
- "@dequanto-contracts/*": [ "src/prebuilt/*" ]
9
+ "dequanto/*": [ "src/*" ]
11
10
  },
12
11
  "typeRoots": [
13
12
  "node_modules/@types",
package/tsconfig.umd.json CHANGED
@@ -6,8 +6,7 @@
6
6
  "compilerOptions": {
7
7
  "baseUrl": "./",
8
8
  "paths": {
9
- "@dequanto/*": [ "src/*" ],
10
- "@dequanto-contracts/*": [ "src/prebuilt/*" ]
9
+ "@dequanto/*": [ "src/*" ]
11
10
  },
12
11
  "lib": [ "ES2019", "dom" ],
13
12
  "typeRoots": [