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
|
@@ -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
|
+
|