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.
Files changed (107) hide show
  1. package/docs/ai/INDEX.md +41 -0
  2. package/docs/ai/examples/contract-read.spec.ts +44 -0
  3. package/docs/ai/examples/contract-write.spec.ts +16 -0
  4. package/docs/ai/examples/deploy-contract.spec.ts +32 -0
  5. package/docs/ai/examples/erc4337-userop.spec.ts +37 -0
  6. package/docs/ai/examples/explorer-abi.spec.ts +18 -0
  7. package/docs/ai/examples/generate-client.spec.ts +22 -0
  8. package/docs/ai/examples/index-events.spec.ts +27 -0
  9. package/docs/ai/examples/rpc-read.spec.ts +15 -0
  10. package/docs/ai/examples/safe-batch.spec.ts +55 -0
  11. package/docs/ai/examples/send-transaction.spec.ts +22 -0
  12. package/docs/ai/examples/storage-read.spec.ts +27 -0
  13. package/docs/ai/examples/token-transfer.spec.ts +22 -0
  14. package/docs/ai/references/contracts.md +111 -0
  15. package/docs/ai/references/deployments.md +98 -0
  16. package/docs/ai/references/events-indexing.md +97 -0
  17. package/docs/ai/references/explorer.md +77 -0
  18. package/docs/ai/references/generation.md +182 -0
  19. package/docs/ai/references/migration-from-ethers-viem.md +43 -0
  20. package/docs/ai/references/rpc-clients.md +115 -0
  21. package/docs/ai/references/safe-erc4337.md +134 -0
  22. package/docs/ai/references/storage.md +93 -0
  23. package/docs/ai/references/tokens-accounts.md +99 -0
  24. package/docs/ai/references/transactions.md +146 -0
  25. package/docs/ai/skill/dequanto/SKILL.md +59 -0
  26. package/lib/cjs/abi/$abiCoder.js +14 -0
  27. package/lib/cjs/abi/$abiCoder.js.map +1 -1
  28. package/lib/cjs/clients/ClientPool.js +14 -0
  29. package/lib/cjs/clients/ClientPool.js.map +1 -1
  30. package/lib/cjs/clients/Web3Client.js +14 -4
  31. package/lib/cjs/clients/Web3Client.js.map +1 -1
  32. package/lib/cjs/clients/Web3ClientFactory.js.map +1 -1
  33. package/lib/cjs/clients/model/ClientStatus.js +1 -0
  34. package/lib/cjs/clients/model/ClientStatus.js.map +1 -1
  35. package/lib/cjs/clients/utils/ClientErrorUtil.js +9 -0
  36. package/lib/cjs/clients/utils/ClientErrorUtil.js.map +1 -1
  37. package/lib/cjs/config/ConfigDefaults.js +0 -3
  38. package/lib/cjs/config/ConfigDefaults.js.map +1 -1
  39. package/lib/cjs/contracts/ContractCreationResolver.js +1 -0
  40. package/lib/cjs/contracts/ContractCreationResolver.js.map +1 -1
  41. package/lib/cjs/rpc/RpcBase.js +4 -1
  42. package/lib/cjs/rpc/RpcBase.js.map +1 -1
  43. package/lib/cjs/solidity/utils/$str.js +1 -1
  44. package/lib/cjs/solidity/utils/$str.js.map +1 -1
  45. package/lib/cjs/utils/$abiParser.js +85 -1
  46. package/lib/cjs/utils/$abiParser.js.map +1 -1
  47. package/lib/cjs/utils/$base.js +1 -1
  48. package/lib/cjs/utils/$base.js.map +1 -1
  49. package/lib/cjs/utils/$crypto.js.map +1 -1
  50. package/lib/cjs/utils/$hex.js +15 -3
  51. package/lib/cjs/utils/$hex.js.map +1 -1
  52. package/lib/esm/abi/$abiCoder.js.map +1 -1
  53. package/lib/esm/abi/$abiCoder.mjs +14 -0
  54. package/lib/esm/clients/ClientPool.js.map +1 -1
  55. package/lib/esm/clients/ClientPool.mjs +14 -0
  56. package/lib/esm/clients/Web3Client.js.map +1 -1
  57. package/lib/esm/clients/Web3Client.mjs +14 -4
  58. package/lib/esm/clients/Web3ClientFactory.js.map +1 -1
  59. package/lib/esm/clients/model/ClientStatus.js.map +1 -1
  60. package/lib/esm/clients/model/ClientStatus.mjs +1 -0
  61. package/lib/esm/clients/utils/ClientErrorUtil.js.map +1 -1
  62. package/lib/esm/clients/utils/ClientErrorUtil.mjs +9 -0
  63. package/lib/esm/config/ConfigDefaults.js.map +1 -1
  64. package/lib/esm/config/ConfigDefaults.mjs +0 -3
  65. package/lib/esm/contracts/ContractCreationResolver.js.map +1 -1
  66. package/lib/esm/contracts/ContractCreationResolver.mjs +1 -0
  67. package/lib/esm/rpc/RpcBase.js.map +1 -1
  68. package/lib/esm/rpc/RpcBase.mjs +4 -1
  69. package/lib/esm/solidity/utils/$str.js.map +1 -1
  70. package/lib/esm/solidity/utils/$str.mjs +1 -1
  71. package/lib/esm/utils/$abiParser.js.map +1 -1
  72. package/lib/esm/utils/$abiParser.mjs +85 -1
  73. package/lib/esm/utils/$base.js.map +1 -1
  74. package/lib/esm/utils/$base.mjs +1 -1
  75. package/lib/esm/utils/$crypto.js.map +1 -1
  76. package/lib/esm/utils/$hex.js.map +1 -1
  77. package/lib/esm/utils/$hex.mjs +15 -3
  78. package/lib/types/abi/$abiCoder.d.ts +11 -9
  79. package/lib/types/clients/ClientPool.d.ts +2 -0
  80. package/lib/types/clients/Web3Client.d.ts +4 -1
  81. package/lib/types/clients/Web3ClientFactory.d.ts +3 -2
  82. package/lib/types/clients/model/ClientStatus.d.ts +1 -0
  83. package/lib/types/clients/utils/ClientErrorUtil.d.ts +4 -0
  84. package/lib/types/contracts/ContractBase.d.ts +1 -1
  85. package/lib/types/contracts/wrappers/FnRequestWrapper.d.ts +1 -1
  86. package/lib/types/models/TAccount.d.ts +1 -1
  87. package/lib/types/rpc/RpcBase.d.ts +1 -0
  88. package/lib/types/utils/$abiParser.d.ts +6 -0
  89. package/lib/types/utils/$crypto.d.ts +3 -0
  90. package/lib/types/utils/$hex.d.ts +2 -0
  91. package/package.json +1 -1
  92. package/src/abi/$abiCoder.ts +31 -10
  93. package/src/clients/ClientPool.ts +17 -1
  94. package/src/clients/Web3Client.ts +20 -7
  95. package/src/clients/Web3ClientFactory.ts +10 -5
  96. package/src/clients/model/ClientStatus.ts +1 -0
  97. package/src/clients/utils/ClientErrorUtil.ts +8 -0
  98. package/src/config/ConfigDefaults.ts +0 -3
  99. package/src/contracts/ContractCreationResolver.ts +1 -0
  100. package/src/contracts/wrappers/FnRequestWrapper.ts +1 -1
  101. package/src/models/TAccount.ts +1 -1
  102. package/src/rpc/RpcBase.ts +5 -1
  103. package/src/solidity/utils/$str.ts +1 -1
  104. package/src/utils/$abiParser.ts +93 -1
  105. package/src/utils/$base.ts +1 -1
  106. package/src/utils/$crypto.ts +1 -0
  107. package/src/utils/$hex.ts +12 -3
@@ -0,0 +1,97 @@
1
+ # Events And Indexing
2
+
3
+ Use generated contract log helpers for simple event reads. Use `EventsIndexer` for resumable, cached, file-backed historical indexing.
4
+
5
+ Key source files:
6
+
7
+ - `src/contracts/ContractBase.ts`
8
+ - `src/contracts/ContractReader.ts`
9
+ - `src/contracts/ContractStream.ts`
10
+ - `src/indexer/EventsIndexer.ts`
11
+ - `src/indexer/storage/FsEventsIndexerStore.ts`
12
+ - `src/indexer/storage/FsEventsMetaStore.ts`
13
+
14
+ Useful tests:
15
+
16
+ - `test/indexer/EventsIndexer.spec.ts`
17
+ - `test/subscriptions.spec.ts`
18
+ - `test/receipt.spec.ts`
19
+
20
+ ## Direct Past Logs
21
+
22
+ ```ts
23
+ const logs = await contract.getPastLogs('Transfer', {
24
+ fromBlock,
25
+ toBlock,
26
+ params: {
27
+ from: owner
28
+ }
29
+ });
30
+ ```
31
+
32
+ Use `'*'` for all events, or an event-name array for multiple events.
33
+
34
+ ## EventsIndexer
35
+
36
+ ```ts
37
+ import { EventsIndexer } from '@dequanto/indexer/EventsIndexer';
38
+
39
+ const indexer = new EventsIndexer(contract, {
40
+ name: 'TokenTransfers',
41
+ fs: {
42
+ directory: './data/logs/',
43
+ blockTimeAvg: 12
44
+ }
45
+ });
46
+
47
+ const { logs, infos } = await indexer.getPastLogs('Transfer', {
48
+ fromBlock,
49
+ toBlock,
50
+ params: { from: owner }
51
+ });
52
+ ```
53
+
54
+ `infos.fetched` counts newly fetched events. `infos.cached` counts events loaded from the store.
55
+
56
+ ## Multiple Addresses
57
+
58
+ Use `addresses` when the same ABI is deployed to multiple addresses:
59
+
60
+ ```ts
61
+ const indexer = new EventsIndexer(contract, {
62
+ addresses: [contract.address, secondAddress],
63
+ name: 'FactoryChildren'
64
+ });
65
+ ```
66
+
67
+ ## Streaming
68
+
69
+ Use `getPastLogsStream` for large ranges:
70
+
71
+ ```ts
72
+ for await (const chunk of indexer.getPastLogsStream('Transfer', {
73
+ fromBlock,
74
+ blockRangeLimits: { blocks: 1_000 }
75
+ })) {
76
+ for (const log of chunk.logs) {
77
+ console.log(log.params);
78
+ }
79
+ }
80
+ ```
81
+
82
+ ## Cache Invalidation
83
+
84
+ Use `removeCached({ fromBlock })` to delete cached logs and metadata from a given block onward.
85
+
86
+ ## Live Events
87
+
88
+ Generated contracts expose:
89
+
90
+ ```ts
91
+ contract.$onLog('Transfer', log => {
92
+ console.log(log);
93
+ });
94
+ ```
95
+
96
+ For raw client subscriptions, use `client.subscribe(...)`.
97
+
@@ -0,0 +1,77 @@
1
+ # Blockchain Explorer
2
+
3
+ Use dequanto explorer APIs instead of hand-written Etherscan-compatible HTTP calls.
4
+
5
+ Key source files:
6
+
7
+ - `src/explorer/BlockchainExplorerFactory.ts`
8
+ - `src/explorer/BlockchainExplorer.ts`
9
+ - `src/explorer/IBlockchainExplorer.ts`
10
+ - `src/contracts/ContractAbiProvider.ts`
11
+ - `src/explorer/ContractVerifier.ts`
12
+
13
+ Useful tests:
14
+
15
+ - `test/BlockchainExplorer.spec.ts`
16
+ - `test/safe/safe.spec.ts`
17
+ - `test/erc4337/erc4337.spec.ts`
18
+
19
+ ## Create Explorer
20
+
21
+ ```ts
22
+ import { BlockchainExplorerFactory } from '@dequanto/explorer/BlockchainExplorerFactory';
23
+
24
+ const explorer = BlockchainExplorerFactory.get('eth');
25
+ ```
26
+
27
+ `getAsync(platform)` ensures config is loaded first.
28
+
29
+ ## ABI And Source
30
+
31
+ ```ts
32
+ const { abi, implementation } = await explorer.getContractAbi(address);
33
+ const source = await explorer.getContractSource(implementation);
34
+ const creation = await explorer.getContractCreation(address);
35
+ ```
36
+
37
+ `getContractAbi` follows common proxy patterns:
38
+
39
+ - OpenZeppelin implementation slot
40
+ - Zeppelinos implementation slot
41
+ - `implementation()`
42
+ - `getTarget()`
43
+ - similar-bytecode explorer hints
44
+
45
+ ## Transactions And Transfers
46
+
47
+ ```ts
48
+ const txs = await explorer.getTransactionsAll(address);
49
+ const internal = await explorer.getInternalTransactionsAll(address);
50
+ const transfers = await explorer.getErc20TransfersAll(address);
51
+ ```
52
+
53
+ ERC20 transfer values are normalized to `bigint`; `blockNumber` and `tokenDecimal` are numbers; `timeStamp` is a `Date`.
54
+
55
+ ## Local ABI Registry
56
+
57
+ For local decoding without remote explorer data:
58
+
59
+ ```ts
60
+ explorer.registerAbi([{
61
+ name: 'Demo',
62
+ address,
63
+ abi
64
+ }]);
65
+ ```
66
+
67
+ This pattern is used by Safe and ERC-4337 decoding tests.
68
+
69
+ ## Verification
70
+
71
+ Use `Deployments` for normal verification orchestration. It delegates to `ContractVerifier` and explorer `submitContractVerification(...)` / `checkContractVerificationSubmission(...)`.
72
+
73
+ ## Avoid
74
+
75
+ - Do not call explorer URLs directly if `BlockchainExplorer` exposes the operation.
76
+ - Do not manually resolve proxy implementations without checking `getContractAbi(address)` first.
77
+
@@ -0,0 +1,182 @@
1
+ # Contract Generation
2
+
3
+ TypeScript class generation is a core dequanto workflow. Prefer generated contract classes over raw ABI calls: generated classes let application code call contracts as ordinary TypeScript classes, with no direct web3-specific ABI encoding, decoding, or JSON-RPC plumbing.
4
+
5
+ Before generating a contract, check whether dequanto already ships a prebuilt class. The package includes OpenZeppelin contract classes under `dequanto/prebuilt/**` / `@dequanto/prebuilt/openzeppelin/**`. Class names match the OpenZeppelin contract names, for example `ERC20`, `ERC721`, `Ownable`, or `TimelockController`.
6
+
7
+ For standard OpenZeppelin contracts, do not generate a new class. Import the prebuilt class and pass the target contract address plus a chain client loaded by platform/chain abbreviation:
8
+
9
+ ```ts
10
+ import { Web3ClientFactory } from '@dequanto/clients/Web3ClientFactory';
11
+ import { ERC20 } from '@dequanto/prebuilt/openzeppelin/ERC20';
12
+
13
+ const platform = 'eth';
14
+ const address = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48';
15
+ const client = await Web3ClientFactory.getAsync(platform);
16
+ const token = new ERC20(address, client);
17
+
18
+ const symbol = await token.symbol();
19
+ const decimals = await token.decimals();
20
+ ```
21
+
22
+ Use the high-level generation tools when no prebuilt class exists:
23
+
24
+ - For deployed and explorer-verified contracts, use the `0xweb` CLI.
25
+ - For Hardhat projects, use the `@0xweb/hardhat` plugin so local Solidity contracts generate TypeScript classes whenever Hardhat compiles.
26
+ - Use the low-level `Generator` API only when the task needs custom generation inside TypeScript code.
27
+
28
+ Key source files:
29
+
30
+ - `src/gen/Generator.ts`
31
+ - `src/gen/GeneratorFromAbi.ts`
32
+ - `src/gen/GeneratorStorageReader.ts`
33
+ - `src/contracts/ContractClassFactory.ts`
34
+ - `src/hardhat/HardhatProvider.ts`
35
+
36
+ Useful tests:
37
+
38
+ - `test/generate/gen.spec.ts`
39
+ - `test/generate/class.spec.ts`
40
+ - `test/generate/base.spec.ts`
41
+ - `test/generate/slotreader.spec.ts`
42
+ - `test/hardhat/deployments/deployments.spec.ts`
43
+
44
+ ## Install Deployed Verified Contracts
45
+
46
+ Use `0xweb install` for any deployed contract that is verified on Etherscan-compatible explorers:
47
+
48
+ ```bash
49
+ npm i 0xweb -g
50
+ 0xweb install <address> --chain <chainAbbr> --name <contractClassName>
51
+ ```
52
+
53
+ Example:
54
+
55
+ ```bash
56
+ 0xweb install 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 --chain eth --name USDC
57
+ ```
58
+
59
+ The generated class can then be imported and used like a normal TypeScript class:
60
+
61
+ ```ts
62
+ import { Web3ClientFactory } from '@dequanto/clients/Web3ClientFactory';
63
+ import { USDC } from './0xc/eth/USDC/USDC';
64
+
65
+ const client = await Web3ClientFactory.getAsync('eth');
66
+ const usdc = new USDC(undefined, client);
67
+
68
+ const symbol = await usdc.symbol();
69
+ const decimals = await usdc.decimals();
70
+ ```
71
+
72
+ ## Hardhat Projects
73
+
74
+ Use `@0xweb/hardhat` in Hardhat projects. The plugin hooks into the Hardhat compile flow and generates TypeScript classes for local `*.sol` contracts whenever the project is compiled.
75
+
76
+ ```bash
77
+ npm i @0xweb/hardhat --save-dev
78
+ ```
79
+
80
+ Load the plugin from the Hardhat config:
81
+
82
+ ```ts
83
+ import '@0xweb/hardhat';
84
+ ```
85
+
86
+ Then compile normally:
87
+
88
+ ```bash
89
+ npx hardhat compile
90
+ ```
91
+
92
+ Use the generated classes in tests, scripts, and app code instead of raw ABI objects.
93
+
94
+ ## Low-Level Generator API
95
+
96
+ Use `Generator` directly only for custom generation tasks, test fixtures, non-Hardhat toolchains, or agent code that must generate classes from explicit ABI arrays, ABI JSON, compiled artifacts, Solidity files, or explorer-verified source by address.
97
+
98
+ ### Generate From Compiled Artifact
99
+
100
+ ```ts
101
+ import { Generator } from '@dequanto/gen/Generator';
102
+
103
+ const gen = new Generator({
104
+ name: 'AnyERC20',
105
+ platform: 'hardhat',
106
+ source: {
107
+ path: './artifacts/contracts/AnyERC20.sol/AnyERC20.json'
108
+ },
109
+ output: './0xc/hardhat/'
110
+ });
111
+
112
+ const info = await gen.generate();
113
+ ```
114
+
115
+ ### Generate From Solidity
116
+
117
+ ```ts
118
+ const info = await Generator.generateFromSol('./contracts/MyToken.sol');
119
+ ```
120
+
121
+ Or:
122
+
123
+ ```ts
124
+ const gen = new Generator({
125
+ name: 'IERC4626',
126
+ platform: 'hardhat',
127
+ source: {
128
+ path: '@openzeppelin/contracts/interfaces/IERC4626.sol'
129
+ },
130
+ output: './0xc/hardhat/'
131
+ });
132
+
133
+ await gen.generate();
134
+ ```
135
+
136
+ ### Generate From Explorer Address
137
+
138
+ ```ts
139
+ const gen = new Generator({
140
+ name: 'DaiToken',
141
+ platform: 'eth',
142
+ source: {
143
+ abi: '0x6b175474e89094c44da98b954eedeac495271d0f'
144
+ },
145
+ output: './0xc/eth/'
146
+ });
147
+
148
+ await gen.generate();
149
+ ```
150
+
151
+ When `source.abi` is an address, the generator asks the platform explorer for ABI/source and follows common proxy implementations. Prefer `0xweb install` for normal installed-contract workflows.
152
+
153
+ ## Storage Reader Generation
154
+
155
+ When a contract is generated from verified on-chain source, such as with `0xweb install` or a generator address source, the generated contract class also includes a storage reader. Consumers can use it to load private storage variables by Solidity variable name, when the verified source exposes the storage layout.
156
+
157
+ Use `GeneratorStorageReader` when the task needs generated storage accessors without generating the full contract class.
158
+
159
+ ```ts
160
+ import { GeneratorStorageReader } from '@dequanto/gen/GeneratorStorageReader';
161
+
162
+ const gen = new GeneratorStorageReader();
163
+ const result = await gen.generate({
164
+ address,
165
+ name: 'WETH',
166
+ contractName: 'MaticWETH',
167
+ network: 'poly',
168
+ client,
169
+ sources
170
+ });
171
+ ```
172
+
173
+ ## Generated Metadata
174
+
175
+ Generated classes can include `$meta`:
176
+
177
+ - `artifact`
178
+ - `class`
179
+ - `source`
180
+ - `name`
181
+
182
+ Agents should inspect generated files before assuming method names, constructor helpers, event helper names, or storage reader fields.
@@ -0,0 +1,43 @@
1
+ # Migration From Ethers And Viem Habits
2
+
3
+ Agents often know ethers and viem better than dequanto. Use this file to translate those habits into dequanto patterns.
4
+
5
+ | Goal | ethers / viem habit | Dequanto pattern |
6
+ | --- | --- | --- |
7
+ | Create RPC client | `new JsonRpcProvider(url)`, `createPublicClient(...)` | `await Web3ClientFactory.getAsync(platform)` or `new EvmWeb3Client({ platform, chainId, endpoints })` |
8
+ | Read block number | `provider.getBlockNumber()`, `client.getBlockNumber()` | `client.getBlockNumber()` |
9
+ | Read native balance | `provider.getBalance(address)` | `client.getBalance(address)` |
10
+ | Read contract | `new Contract(address, abi, provider).balanceOf(owner)` | generated contract class, for example `new ERC20(address, client).balanceOf(owner)` |
11
+ | Write contract | `contract.connect(signer).transfer(...)`, `walletClient.writeContract(...)` | generated write method returning `TxWriter` |
12
+ | Wait for tx | `tx.wait()` | `await writer.wait()` or `await contract.$receipt().method(...)` |
13
+ | Build calldata | `iface.encodeFunctionData(...)`, `encodeFunctionData(...)` | generated `contract.$data().method(...)` or `$abiUtils.serializeMethodCallData(...)` |
14
+ | Raw eth_call | `provider.call(tx)` | `contract.$call().method(...)` or `client.call(tx)` |
15
+ | Raw ABI read | `readContract(...)` | `client.readContract(...)` or `ContractReader.readAsync(...)` |
16
+ | Logs | `provider.getLogs(...)`, `client.getLogs(...)` | `client.getPastLogs(...)`, generated `getPastLogs(...)`, or `EventsIndexer` |
17
+ | Explorer ABI | hand-written Etherscan HTTP | `BlockchainExplorerFactory.get(platform).getContractAbi(address)` |
18
+ | Contract generation | TypeChain, viem codegen | `Generator` / 0xweb-generated dequanto contract classes |
19
+ | Storage | raw `eth_getStorageAt` plus manual decode | `SlotsParser` + `SlotsStorage` |
20
+ | Bigint formatting | `parseUnits`, `formatUnits` | `bigint` js type is supported natively, additionally `$bigint` helpers and token decimals through dequanto token services |
21
+ | Safe tx | Safe SDK | `SafeAccount`, `GnosisSafeHandler`, `SafeTx`, Safe transports |
22
+ | ERC-4337 | external bundler/account SDK | `Erc4337Service`, `Erc4337TxWriter`, `Erc4337Account` |
23
+
24
+ ## Strong Defaults
25
+
26
+ - Use generated contract classes first.
27
+ - Use `Web3ClientFactory` for platform clients.
28
+ - Use `TxWriter` for transaction lifecycle.
29
+ - Use `EventsIndexer` when events must be cached and resumed.
30
+ - Use `SlotsParser` and `SlotsStorage` for storage decoding.
31
+
32
+ ## Anti-Patterns
33
+
34
+ Do not introduce:
35
+
36
+ ```ts
37
+ import { ethers } from 'ethers';
38
+ import { createPublicClient } from 'viem';
39
+ import Web3 from 'web3';
40
+ ```
41
+
42
+ unless the user explicitly asks for those libraries or the local repo already uses them for that exact integration.
43
+
@@ -0,0 +1,115 @@
1
+ # RPC Clients
2
+
3
+ Use dequanto RPC clients for node access. Prefer `await Web3ClientFactory.getAsync(platform, opts?)` so configuration is loaded before RPC, explorer, and chain services are used.
4
+
5
+ Key source files:
6
+
7
+ - `src/clients/Web3ClientFactory.ts`
8
+ - `src/clients/Web3Client.ts`
9
+ - `src/clients/EvmWeb3Client.ts`
10
+ - `src/clients/ClientPool.ts`
11
+ - `src/rpc/Rpc.ts`
12
+ - `src/rpc/RpcBase.ts`
13
+
14
+ Useful tests:
15
+
16
+ - `test/Web3Client.spec.ts`
17
+ - `test/client/block.spec.ts`
18
+ - `test/node/block.spec.ts`
19
+ - `test/subscriptions.spec.ts`
20
+
21
+ ## Client Creation
22
+
23
+ ```ts
24
+ import { Web3ClientFactory } from '@dequanto/clients/Web3ClientFactory';
25
+
26
+ const client = await Web3ClientFactory.getAsync('eth');
27
+ ```
28
+
29
+ For Hardhat:
30
+
31
+ ```ts
32
+ const client = await Web3ClientFactory.getAsync('hardhat');
33
+ ```
34
+
35
+ For a fork-like platform string:
36
+
37
+ ```ts
38
+ const client = await Web3ClientFactory.getAsync('hh:eth');
39
+ ```
40
+
41
+ For direct endpoints:
42
+
43
+ ```ts
44
+ import { EvmWeb3Client } from '@dequanto/clients/EvmWeb3Client';
45
+
46
+ const client = new EvmWeb3Client({
47
+ platform: 'eth',
48
+ chainId: 1,
49
+ endpoints: [{ url: process.env.RPC_URL_ETH }]
50
+ });
51
+ ```
52
+
53
+ ## Common Reads
54
+
55
+ ```ts
56
+ const blockNumber = await client.getBlockNumber();
57
+ const block = await client.getBlock('latest');
58
+ const balance = await client.getBalance(address);
59
+ const tx = await client.getTransaction(hash);
60
+ const receipt = await client.getTransactionReceipt(hash);
61
+ const code = await client.getCode(contractAddress);
62
+ const chainId = await client.getChainId();
63
+ ```
64
+
65
+ Storage:
66
+
67
+ ```ts
68
+ const slot0 = await client.getStorageAt(contractAddress, 0);
69
+ const slots = await client.getStorageAtBatched(contractAddress, [0, 1, 2]);
70
+ ```
71
+
72
+ Raw contract call:
73
+
74
+ ```ts
75
+ const result = await client.readContract({
76
+ address: tokenAddress,
77
+ abi,
78
+ method: 'balanceOf',
79
+ params: [owner]
80
+ });
81
+ ```
82
+
83
+ ## Logs
84
+
85
+ Use `getPastLogs(filter, options?)` for raw log queries. It handles block-range pagination and node range limits.
86
+
87
+ ```ts
88
+ const logs = await client.getPastLogs({
89
+ address: tokenAddress,
90
+ fromBlock,
91
+ toBlock,
92
+ topics: [transferTopic]
93
+ });
94
+ ```
95
+
96
+ For large ranges, use `streamed: true` and `onProgress`.
97
+
98
+ ## Subscriptions
99
+
100
+ Use `subscribe(...)` for websocket subscriptions:
101
+
102
+ ```ts
103
+ const sub = await client.subscribe('newHeads', (error, block) => {
104
+ if (error) throw error;
105
+ console.log(block.number);
106
+ });
107
+ ```
108
+
109
+ For contract events, generated contracts expose `$onLog(event, cb?)`.
110
+
111
+ ## Avoid
112
+
113
+ - Do not use raw `fetch`/HTTP for Ethereum JSON-RPC when `Web3Client` or `client.getRpc()` can do it.
114
+ - Do not call `getWeb3()` on `Web3Client`; the base class throws and points to the compatibility layer.
115
+
@@ -0,0 +1,134 @@
1
+ # Safe And ERC-4337
2
+
3
+ Use dequanto account-agent flows for Gnosis Safe and ERC-4337 instead of wiring external SDK calls directly.
4
+
5
+ Key source files:
6
+
7
+ - `src/safe/GnosisSafeHandler.ts`
8
+ - `src/safe/GnosisSafeFactory.ts`
9
+ - `src/safe/GnosisSafeService.ts`
10
+ - `src/safe/SafeTx.ts`
11
+ - `src/safe/transport/InMemoryServiceTransport.ts`
12
+ - `src/safe/transport/FileServiceTransport.ts`
13
+ - `src/safe/transport/SafeServiceTransport.ts`
14
+ - `src/erc4337/Erc4337Service.ts`
15
+ - `src/erc4337/Erc4337TxWriter.ts`
16
+ - `src/txs/agents/SafeAgent.ts`
17
+ - `src/txs/agents/Erc4337Agent.ts`
18
+ - `src/txs/agents/BatchAgent.ts`
19
+
20
+ Useful tests:
21
+
22
+ - `test/safe/safe.spec.ts`
23
+ - `test/erc4337/erc4337.spec.ts`
24
+
25
+ ## Safe Account Transaction
26
+
27
+ Use a `SafeAccount` with generated contract write methods:
28
+
29
+ ```ts
30
+ const safeAccount = {
31
+ type: 'safe',
32
+ address: safeAddress,
33
+ operator: owner1,
34
+ owners: [owner1, owner2]
35
+ } as const;
36
+
37
+ const tx = await token.transfer(safeAccount, receiver, amount);
38
+ await tx.wait();
39
+ ```
40
+
41
+ Pass a Safe transport through writer config when needed:
42
+
43
+ ```ts
44
+ const tx = await token
45
+ .$config(null, {
46
+ safeTransport: new InMemoryServiceTransport(client, owner1)
47
+ })
48
+ .transfer(safeAccount, receiver, amount);
49
+ ```
50
+
51
+ ## Manual Safe Flow
52
+
53
+ ```ts
54
+ import { GnosisSafeHandler } from '@dequanto/safe/GnosisSafeHandler';
55
+ import { ContractWriter } from '@dequanto/contracts/ContractWriter';
56
+
57
+ const writer = new ContractWriter(target.address, client);
58
+ const txWriter = await writer.writeAsync(safeAccount, 'airdrop()', [], {
59
+ builderConfig: {
60
+ send: 'manual',
61
+ gasEstimation: false
62
+ }
63
+ });
64
+
65
+ const safe = new GnosisSafeHandler({
66
+ safeAddress,
67
+ owners: [owner1],
68
+ client,
69
+ transport
70
+ });
71
+
72
+ const { safeTxHash } = await safe.createTransaction(txWriter, 0n);
73
+ await safe.confirmTx(safeTxHash, owner2);
74
+ const submitTx = await safe.submitTransaction(safeTxHash);
75
+ await submitTx.wait();
76
+ ```
77
+
78
+ ## Safe Batch
79
+
80
+ Use `SafeTx.executeBatch(...)` with generated `$data()` calls when manually composing a Safe batch:
81
+
82
+ ```ts
83
+ const safeTx = new SafeTx(safeAccount, client, {
84
+ safeTransport,
85
+ contracts
86
+ });
87
+
88
+ const tx = await safeTx.executeBatch(
89
+ await token.$data().approve(safeAccount, spender, amount),
90
+ await token.$data().transfer(safeAccount, receiver, amount)
91
+ );
92
+
93
+ await tx.wait();
94
+ ```
95
+
96
+ For scripts, prefer `BatchAgent` when the code should call generated write methods normally and review or submit the collected transactions at the end. If the submitting account is a Safe, `batch.execute()` converts the collected single transactions into one Safe batch/multicall transaction. If the submitting account is a Timelock, `batch.execute()` converts them into one Timelock batch/scheduleBatch flow.
97
+
98
+ See `../../references/transactions.md` for the full `BatchAgent` script pattern.
99
+
100
+ ## Safe Decoding
101
+
102
+ Use `GnosisSafeService.decodeSafeTx(data, { decodeContractCall: true })`. Register ABIs on the explorer when decoding local or unknown contracts.
103
+
104
+ ## ERC-4337
105
+
106
+ Use `Erc4337TxWriter` for the higher-level flow:
107
+
108
+ ```ts
109
+ const erc4337 = new Erc4337TxWriter(client, explorer, {
110
+ addresses: {
111
+ entryPoint,
112
+ accountFactory
113
+ }
114
+ });
115
+
116
+ const account = await erc4337.getAccount(owner);
117
+ const txData = await token.$data().transfer(account, receiver, amount);
118
+
119
+ const { writer } = await erc4337.submitUserOpViaEntryPointWithOwner({
120
+ tx: txData,
121
+ owner,
122
+ submitter
123
+ });
124
+
125
+ await writer.wait();
126
+ ```
127
+
128
+ Use `Erc4337Service` for low-level operation creation, signing, decoding, and `handleOps` submission.
129
+
130
+ ## Avoid
131
+
132
+ - Do not manually assemble Safe `execTransaction` signatures unless the task is explicitly low-level.
133
+ - Do not bypass dequanto `TxWriter` account agents for Safe or ERC-4337 when generated contract writes can use account types.
134
+