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.
- package/contracts/oz/Proxy.sol +1 -0
- package/docs/ai/INDEX.md +4 -3
- package/docs/ai/examples/config.spec.ts +113 -0
- package/docs/ai/examples/contract-read.spec.ts +81 -13
- package/docs/ai/examples/contract-write.spec.ts +61 -9
- package/docs/ai/examples/deploy-contract.spec.ts +53 -16
- package/docs/ai/examples/erc4337-userop.spec.ts +7 -5
- package/docs/ai/examples/explorer-abi.spec.ts +9 -6
- package/docs/ai/examples/{generate-client.spec.ts → generate-contract-class.spec.ts} +6 -3
- package/docs/ai/examples/index-events.spec.ts +8 -6
- package/docs/ai/examples/rpc-read.spec.ts +32 -5
- package/docs/ai/examples/safe-batch.spec.ts +5 -4
- package/docs/ai/examples/send-transaction.spec.ts +23 -11
- package/docs/ai/examples/storage-read.spec.ts +15 -7
- package/docs/ai/examples/token-transfer.spec.ts +22 -15
- package/docs/ai/references/generation.md +30 -7
- package/docs/ai/skill/dequanto/SKILL.md +5 -1
- package/lib/cjs/abi/$abi.js +60 -0
- package/lib/cjs/abi/$abi.js.map +1 -0
- package/lib/cjs/abi/$abiCoder.js +1 -0
- package/lib/cjs/abi/$abiCoder.js.map +1 -1
- package/lib/cjs/abi/abi-coder.js +1 -1
- package/lib/cjs/abi/abi-coder.js.map +1 -1
- package/lib/cjs/blocks/BlockDateResolver.js.map +1 -1
- package/lib/cjs/clients/Web3Client.js +43 -2
- package/lib/cjs/clients/Web3Client.js.map +1 -1
- package/lib/cjs/clients/Web3ClientFactory.js +26 -4
- package/lib/cjs/clients/Web3ClientFactory.js.map +1 -1
- package/lib/cjs/clients/debug/ClientDebugMethods.js +4 -0
- package/lib/cjs/clients/debug/ClientDebugMethods.js.map +1 -1
- package/lib/cjs/clients/utils/$web3Abi.js +1 -1
- package/lib/cjs/clients/utils/$web3Abi.js.map +1 -1
- package/lib/cjs/config/Config.js +28 -6
- package/lib/cjs/config/Config.js.map +1 -1
- package/lib/cjs/config/ConfigDefaults.js +6 -2
- package/lib/cjs/config/ConfigDefaults.js.map +1 -1
- package/lib/cjs/config/ConfigProvider.js +5 -0
- package/lib/cjs/config/ConfigProvider.js.map +1 -1
- package/lib/cjs/config/DefaultFactory.js +27 -0
- package/lib/cjs/config/DefaultFactory.js.map +1 -0
- package/lib/cjs/contracts/ContractBase.js +6 -2
- package/lib/cjs/contracts/ContractBase.js.map +1 -1
- package/lib/cjs/contracts/ContractReader.js +1 -35
- package/lib/cjs/contracts/ContractReader.js.map +1 -1
- package/lib/cjs/explorer/BlockchainExplorerFactory.js.map +1 -1
- package/lib/cjs/rpc/RpcContract.js +4 -32
- package/lib/cjs/rpc/RpcContract.js.map +1 -1
- package/lib/cjs/utils/$account.js +5 -0
- package/lib/cjs/utils/$account.js.map +1 -1
- package/lib/cjs/utils/$config.js +4 -5
- package/lib/cjs/utils/$config.js.map +1 -1
- package/lib/cjs/utils/$erc20.js +47 -0
- package/lib/cjs/utils/$erc20.js.map +1 -0
- package/lib/cjs/utils/$hex.js +1 -0
- package/lib/cjs/utils/$hex.js.map +1 -1
- package/lib/cjs/utils/$require.js +6 -2
- package/lib/cjs/utils/$require.js.map +1 -1
- package/lib/esm/abi/$abi.js.map +1 -0
- package/lib/esm/abi/$abi.mjs +57 -0
- package/lib/esm/abi/$abiCoder.js.map +1 -1
- package/lib/esm/abi/$abiCoder.mjs +1 -0
- package/lib/esm/abi/abi-coder.js.map +1 -1
- package/lib/esm/abi/abi-coder.mjs +1 -1
- package/lib/esm/blocks/BlockDateResolver.js.map +1 -1
- package/lib/esm/clients/Web3Client.js.map +1 -1
- package/lib/esm/clients/Web3Client.mjs +43 -2
- package/lib/esm/clients/Web3ClientFactory.js.map +1 -1
- package/lib/esm/clients/Web3ClientFactory.mjs +26 -4
- package/lib/esm/clients/debug/ClientDebugMethods.js.map +1 -1
- package/lib/esm/clients/debug/ClientDebugMethods.mjs +4 -0
- package/lib/esm/clients/utils/$web3Abi.js.map +1 -1
- package/lib/esm/clients/utils/$web3Abi.mjs +1 -1
- package/lib/esm/config/Config.js.map +1 -1
- package/lib/esm/config/Config.mjs +28 -6
- package/lib/esm/config/ConfigDefaults.js.map +1 -1
- package/lib/esm/config/ConfigDefaults.mjs +6 -2
- package/lib/esm/config/ConfigProvider.js.map +1 -1
- package/lib/esm/config/ConfigProvider.mjs +5 -0
- package/lib/esm/config/DefaultFactory.js.map +1 -0
- package/lib/esm/config/DefaultFactory.mjs +23 -0
- package/lib/esm/contracts/ContractBase.js.map +1 -1
- package/lib/esm/contracts/ContractBase.mjs +6 -2
- package/lib/esm/contracts/ContractReader.js.map +1 -1
- package/lib/esm/contracts/ContractReader.mjs +1 -35
- package/lib/esm/explorer/BlockchainExplorerFactory.js.map +1 -1
- package/lib/esm/rpc/RpcContract.js.map +1 -1
- package/lib/esm/rpc/RpcContract.mjs +4 -32
- package/lib/esm/utils/$account.js.map +1 -1
- package/lib/esm/utils/$account.mjs +5 -0
- package/lib/esm/utils/$config.js.map +1 -1
- package/lib/esm/utils/$config.mjs +4 -5
- package/lib/esm/utils/$erc20.js.map +1 -0
- package/lib/esm/utils/$erc20.mjs +41 -0
- package/lib/esm/utils/$hex.js.map +1 -1
- package/lib/esm/utils/$hex.mjs +1 -0
- package/lib/esm/utils/$require.js.map +1 -1
- package/lib/esm/utils/$require.mjs +6 -2
- package/lib/types/abi/$abi.d.ts +17 -0
- package/lib/types/abi/$abiCoder.d.ts +2 -1
- package/lib/types/blocks/BlockDateResolver.d.ts +1 -1
- package/lib/types/clients/Web3Client.d.ts +1 -1
- package/lib/types/clients/Web3ClientFactory.d.ts +10 -2
- package/lib/types/clients/debug/ClientDebugMethods.d.ts +1 -1
- package/lib/types/config/AConfigBase.d.ts +3 -0
- package/lib/types/config/Config.d.ts +2 -1
- package/lib/types/config/DefaultFactory.d.ts +2 -0
- package/lib/types/config/interface/IConfigData.d.ts +14 -2
- package/lib/types/contracts/ContractReader.d.ts +1 -1
- package/lib/types/explorer/IBlockchainExplorer.d.ts +6 -0
- package/lib/types/models/TPlatform.d.ts +1 -1
- package/lib/types/utils/$account.d.ts +1 -0
- package/lib/types/utils/$erc20.d.ts +5 -0
- package/lib/types/utils/$hex.d.ts +1 -0
- package/lib/types/utils/$require.d.ts +6 -6
- package/package.json +1 -1
- package/src/abi/$abi.ts +69 -0
- package/src/abi/$abiCoder.ts +1 -1
- package/src/abi/abi-coder.ts +1 -3
- package/src/blocks/BlockDateResolver.ts +1 -1
- package/src/clients/Web3Client.ts +48 -3
- package/src/clients/Web3ClientFactory.ts +33 -5
- package/src/clients/debug/ClientDebugMethods.ts +5 -1
- package/src/clients/utils/$web3Abi.ts +2 -2
- package/src/config/AConfigBase.ts +4 -0
- package/src/config/Config.ts +30 -8
- package/src/config/ConfigDefaults.ts +6 -2
- package/src/config/ConfigProvider.ts +5 -1
- package/src/config/DefaultFactory.ts +26 -0
- package/src/config/interface/IConfigData.ts +15 -2
- package/src/contracts/ContractBase.ts +6 -2
- package/src/contracts/ContractReader.ts +3 -40
- package/src/explorer/BlockchainExplorerFactory.ts +0 -1
- package/src/explorer/IBlockchainExplorer.ts +4 -0
- package/src/models/TPlatform.ts +1 -0
- package/src/rpc/RpcContract.ts +5 -33
- package/src/utils/$account.ts +5 -0
- package/src/utils/$config.ts +4 -6
- package/src/utils/$erc20.ts +53 -0
- package/src/utils/$hex.ts +3 -1
- package/src/utils/$require.ts +8 -4
- package/tsconfig.json +1 -2
- 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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
|
11
|
+
} else if (Array.isArray(abi)) {
|
|
12
12
|
arr = abi;
|
|
13
13
|
} else {
|
|
14
14
|
arr = [ abi ];
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
let first =
|
|
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 & {
|
package/src/config/Config.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|
32
|
+
key?: string;
|
|
32
33
|
host?: string;
|
|
33
34
|
api?: string
|
|
34
|
-
|
|
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 }>;
|
package/src/models/TPlatform.ts
CHANGED
package/src/rpc/RpcContract.ts
CHANGED
|
@@ -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
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
-
}
|
package/src/utils/$account.ts
CHANGED
|
@@ -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
|
}
|
package/src/utils/$config.ts
CHANGED
|
@@ -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 = (
|
|
20
|
-
??
|
|
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
|
|
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
|
package/src/utils/$require.ts
CHANGED
|
@@ -61,17 +61,17 @@ export namespace $require {
|
|
|
61
61
|
}
|
|
62
62
|
return val;
|
|
63
63
|
}
|
|
64
|
-
export function notNull<T> (val: T, message
|
|
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
|
|
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