@sm-lab/receipts 0.1.0

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/README.md ADDED
@@ -0,0 +1,179 @@
1
+ # @sm-lab/receipts
2
+
3
+ Versioned, typed snapshots of Lido SM contract ABIs and deploy addresses. Replaces ad-hoc `deploy.json`
4
+ files copied between repos and the `DEPLOY_JSON_PATH` env-var dance.
5
+
6
+ ```ts
7
+ import { addresses, csModuleAbi, manifest } from '@sm-lab/receipts';
8
+
9
+ addresses.hoodi.csm; // typed address string, autocompleted, compile-checked
10
+ addresses.mainnet.csm;
11
+ ```
12
+
13
+ ## What's inside
14
+
15
+ | Path | Contents |
16
+ | ---------------------------- | ----------------------------------------------------------------------------- |
17
+ | `src/abi/*.ts` | One `as const` TypeScript module per contract (`csModuleAbi`, `vEBOAbi`, …) |
18
+ | `src/index.ts` | Re-exports `addresses`, all ABI consts, and `manifest` |
19
+ | `data/<chain>/<module>.json` | Per-(chain, module) address book |
20
+ | `data/manifest.json` | Contracts `git-ref`(s) + per-ABI sha256 hashes + optional protocol provenance |
21
+ | `scripts/refresh.ts` | CLI that populates the above from a local contracts checkout |
22
+
23
+ Public surface:
24
+
25
+ ```ts
26
+ import { addresses, csModuleAbi, vEBOAbi, manifest } from '@sm-lab/receipts';
27
+ // ^^^^^^^^^ { hoodi: { csm, cm }, mainnet: { csm } }
28
+ ```
29
+
30
+ Available chains/modules: `hoodi.csm`, `hoodi.cm`, `mainnet.csm`.
31
+ `mainnet/cm` is intentionally absent — no curated mainnet deployment exists yet.
32
+
33
+ ## Address book shape
34
+
35
+ Each `data/<chain>/<module>.json` is an **allowlist-curated, strictly-typed** set of addresses.
36
+ Only proxy and gate contracts that SM recipes actually use are included. `DeployParams`, `*Impl`
37
+ addresses, and linked library entries present in the upstream deploy config are intentionally
38
+ dropped — committing them here would add noise without value and they change on every upgrade.
39
+
40
+ > **Warning:** if you copy addresses from the raw upstream deploy config and notice extra keys
41
+ > (`*Impl`, `DeployParams`, `libraries`, …), those are not in `@sm-lab/receipts` by design.
42
+
43
+ Each book may also contain an optional `protocol` block with 6 addresses sourced directly
44
+ from the on-chain `LidoLocator` contract (see [Protocol block](#protocol-block) below).
45
+
46
+ ## Protocol block
47
+
48
+ The `protocol` field in each address book holds addresses resolved by calling the canonical
49
+ getter methods on the deployed `LidoLocator` contract:
50
+
51
+ | Key | LidoLocator getter |
52
+ | ------------------------- | --------------------------- |
53
+ | `lido` | `lido()` |
54
+ | `withdrawalVault` | `withdrawalVault()` |
55
+ | `validatorsExitBusOracle` | `validatorsExitBusOracle()` |
56
+ | `stakingRouter` | `stakingRouter()` |
57
+ | `burner` | `burner()` |
58
+ | `withdrawalQueue` | `withdrawalQueue()` |
59
+
60
+ These are the addresses that `@sm-lab/recipes`'s `connect()` and the `@sm-lab/keys` tool
61
+ need at runtime. When a `protocol` block is present in the committed data, both consumers
62
+ prefer it over resolving the addresses at runtime; they fall back to their previous runtime
63
+ resolution when it is absent.
64
+
65
+ `manifest.protocolResolvedAt` records provenance for the last enrichment:
66
+
67
+ ```json
68
+ {
69
+ "protocolResolvedAt": {
70
+ "hoodi/csm": { "chainId": 560048, "block": 1234567 },
71
+ "mainnet/csm": { "chainId": 1, "block": 654321 }
72
+ }
73
+ }
74
+ ```
75
+
76
+ **The `protocol` blocks are not populated in the initial committed data** — they require a live
77
+ RPC. Run enrichment once an RPC is available (see [Enriching protocol addresses](#enriching-protocol-addresses)).
78
+
79
+ ## How ABIs and addresses are sourced
80
+
81
+ No Solidity toolchain runs here. The `refresh` script only reads Forge's existing build output
82
+ from a local checkout of `community-staking-module`:
83
+
84
+ - **ABIs** — read from `out/<Contract>.sol/<Contract>.json` (`.abi` field). Several contracts are
85
+ interface-mapped so the ABI matches the actual public surface:
86
+
87
+ | Upstream contract | Artifact read |
88
+ | ----------------- | ---------------- |
89
+ | `VEBO` | `IVEBO` |
90
+ | `StakingRouter` | `IStakingRouter` |
91
+ | `Lido` | `ILido` |
92
+ | `LidoLocator` | `ILidoLocator` |
93
+ | all others | same name |
94
+
95
+ - **Addresses** — read from `artifacts/<chain>[/curated]/deploy-<chain>.json`.
96
+
97
+ The extracted snapshots are committed here. Consumers get reproducible, offline reads with no
98
+ Forge dependency.
99
+
100
+ ## Enriching protocol addresses
101
+
102
+ To populate (or refresh) the `protocol` block in the committed address data, pass `--rpc` (or
103
+ set the matching env var) when running `refresh`:
104
+
105
+ ```bash
106
+ # hoodi csm — explicit flag
107
+ pnpm --filter @sm-lab/receipts refresh --chain hoodi --module csm --rpc <url>
108
+
109
+ # hoodi csm — via env var
110
+ HOODI_RPC_URL=<url> pnpm --filter @sm-lab/receipts refresh --chain hoodi --module csm
111
+
112
+ # mainnet csm — via generic fallback
113
+ ETH_RPC_URL=<url> pnpm --filter @sm-lab/receipts refresh --chain mainnet --module csm
114
+ ```
115
+
116
+ RPC URL resolution order: `--rpc` flag → `<CHAIN>_RPC_URL` (uppercased chain name) → `ETH_RPC_URL`.
117
+
118
+ **Without an RPC** the enrichment step is skipped entirely and any existing `protocol` block
119
+ already in `data/<chain>/<module>.json` is carried forward unchanged (no data loss). This
120
+ means you can run a plain ABI/address refresh without a live node and the protocol provenance
121
+ remains intact.
122
+
123
+ After enriching, commit the updated `data/` files together with the updated `manifest.json`
124
+ (`protocolResolvedAt` is written there).
125
+
126
+ ## Refreshing snapshots
127
+
128
+ Run per-target when a deployment or contract changes:
129
+
130
+ ```bash
131
+ pnpm --filter @sm-lab/receipts refresh -- \
132
+ --chain <hoodi|mainnet> \
133
+ --module <csm|cm> \
134
+ [--contracts <path-to-community-staking-module>] \
135
+ [--config <relative-path-inside-contracts-repo>] \
136
+ [--force]
137
+ ```
138
+
139
+ `--contracts` defaults to `../../../community-staking-module` — a sibling of the sm-lab repo root
140
+ (relative paths resolve from the package root, `fixtures/receipts/`). `--force` bypasses
141
+ the git-ref guard (see below).
142
+
143
+ `--config` overrides which JSON file inside the contracts repo to read addresses from. Use it to
144
+ point at the **latest** upgrade config per the contracts repo's `.env` `DEPLOY_CONFIG` value —
145
+ CSM has been upgraded twice (v2, v3); proxy addresses are stable across upgrades but `*Impl`
146
+ addresses change and new contracts are added. Current per-(chain, module) configs:
147
+
148
+ | chain | module | config path | version |
149
+ | ------- | ------ | ------------------------------------------- | ------- |
150
+ | hoodi | csm | `artifacts/hoodi/upgrade-v3-hoodi.json` | v3 |
151
+ | hoodi | cm | `artifacts/hoodi/curated/deploy-hoodi.json` | — |
152
+ | mainnet | csm | `artifacts/mainnet/deploy-mainnet.json` | v2 |
153
+
154
+ If `--config` is omitted, the default is `artifacts/<chain>/deploy-<chain>.json` (or
155
+ `artifacts/<chain>/curated/deploy-<chain>.json` for cm). Only override when the authoritative
156
+ config for that chain has moved to an upgrade file.
157
+
158
+ After refreshing, commit the updated `data/` and `src/abi/` files together.
159
+
160
+ ## Drift guard
161
+
162
+ The manifest records the `git-ref` from the contracts checkout at refresh time. On subsequent
163
+ runs, the guard refuses to write addresses from a _different_ deployment's `git-ref` against the
164
+ already-committed ABIs unless `--force` is passed. This prevents silently pairing addresses with
165
+ ABIs from a mismatched contracts version.
166
+
167
+ ## Sibling SDK note
168
+
169
+ `lido-csm-sdk` maintains its own ABI copy via its `/update-abis` script. After refreshing here,
170
+ check whether the SDK needs a matching update — it applies an `Accounting.deposit*` overload
171
+ filter that may need adjustment if the ABI changes.
172
+
173
+ ## Build
174
+
175
+ ```ts
176
+ // tsdown.config.ts
177
+ import { libConfig } from '@sm-lab/config/tsdown';
178
+ export default libConfig();
179
+ ```
package/data/.gitkeep ADDED
File without changes
@@ -0,0 +1,34 @@
1
+ {
2
+ "CuratedModule": "0x87EB69Ae51317405FD285efD2326a4a11f6173b9",
3
+ "Accounting": "0x7f7356D29aCd915F1934220956c3305808ceB235",
4
+ "FeeDistributor": "0x0ced6de191E2A15f7BBAf9E32307626C9f6BD0Cd",
5
+ "FeeOracle": "0x5D2F27000C80f6f7A03015Fd49dB7FEba3fBfa83",
6
+ "HashConsensus": "0x920883908A78c1554f682006a8aB32E62Be09F33",
7
+ "ParametersRegistry": "0xefb8e4091A75C4828826bf64595F392f87A07b37",
8
+ "ValidatorStrikes": "0x4c427Ec826F403339719C0FABfb3209e80939eA6",
9
+ "Verifier": "0x209190Ebc2Be80367a15d05e626784Eb94d6A880",
10
+ "Ejector": "0xfDbde2B3554B69C84e0f8d7daB68D390Ff0f4394",
11
+ "ExitPenalties": "0xad79e1d3B380cEb1a0e188fBAB91f85A446E9E54",
12
+ "MetaRegistry": "0x857289cCBFBc4C134Cc312022a104CD9b38d8AAE",
13
+ "CuratedGateFactory": "0x0e26d2cC3f0c2A17D2D784068cAAD34206B6804D",
14
+ "LidoLocator": "0xe2EF9536DAAAEBFf5b1c130957AB3E80056b06D8",
15
+ "CuratedGates": [
16
+ "0xF1862d120831eBE31f7202378Ff3Ae63A5658ae3",
17
+ "0x410A309dF81B782190188CDB3d215729cc6bC1f3",
18
+ "0xa5A604b172787e017b1b118F02fE54fC1D696519",
19
+ "0xE966874cDB6A4282ED75Cd10439e3799e5531a2D",
20
+ "0x5c063da03e3f21443716D75a2205EE16706e1153",
21
+ "0x1cD655Ac53CfE8269DE0DBfc0140B074623C4A6B",
22
+ "0x28518be9894C20135F280a9539617783b08a04c7"
23
+ ],
24
+ "ChainId": 560048,
25
+ "git-ref": "a6be775483e17d76718f8852428b5251a75c6429",
26
+ "protocol": {
27
+ "stakingRouter": "0xCc820558B39ee15C7C45B59390B503b83fb499A8",
28
+ "validatorsExitBusOracle": "0x8664d394C2B3278F26A1B44B967aEf99707eeAB2",
29
+ "lido": "0x3508A952176b3c15387C97BE809eaffB1982176a",
30
+ "withdrawalQueue": "0xfe56573178f1bcdf53F01A6E9977670dcBBD9186",
31
+ "burner": "0xb2c99cd38a2636a6281a849C8de938B3eF4A7C3D",
32
+ "withdrawalVault": "0x4473dCDDbf77679A643BdB654dbd86D67F8d32f2"
33
+ }
34
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "CSModule": "0x79CEf36D84743222f37765204Bec41E92a93E59d",
3
+ "Accounting": "0xA54b90BA34C5f326BC1485054080994e38FB4C60",
4
+ "FeeDistributor": "0xaCd9820b0A2229a82dc1A0770307ce5522FF3582",
5
+ "FeeOracle": "0xe7314f561B2e72f9543F1004e741bab6Fc51028B",
6
+ "HashConsensus": "0x54f74a10e4397dDeF85C4854d9dfcA129D72C637",
7
+ "ParametersRegistry": "0xA4aD5236963f9Fe4229864712269D8d79B65C5Ad",
8
+ "ValidatorStrikes": "0x8fBA385C3c334D251eE413e79d4D3890db98693c",
9
+ "Verifier": "0x1773b2Ff99A030F6000554Cb8A5Ec93145650cbA",
10
+ "Ejector": "0xCAe028378d69D54dc8bF809e6C44CF751F997b80",
11
+ "ExitPenalties": "0xD259b31083Be841E5C85b2D481Cfc17C14276800",
12
+ "GateSeal": "0x725166f143DdcD9EC1b96dfb70f16E3f44968A65",
13
+ "LidoLocator": "0xe2EF9536DAAAEBFf5b1c130957AB3E80056b06D8",
14
+ "VettedGate": "0x10a254E724fe2b7f305F76f3F116a3969c53845f",
15
+ "PermissionlessGate": "0xd7bD8D2A9888D1414c770B35ACF55890B15de26a",
16
+ "IdentifiedDVTClusterGate": "0x887F8512F9998045f4b5993e6eaa6BCfE5F02A94",
17
+ "ChainId": 560048,
18
+ "git-ref": "a6be775483e17d76718f8852428b5251a75c6429",
19
+ "protocol": {
20
+ "stakingRouter": "0xCc820558B39ee15C7C45B59390B503b83fb499A8",
21
+ "validatorsExitBusOracle": "0x8664d394C2B3278F26A1B44B967aEf99707eeAB2",
22
+ "lido": "0x3508A952176b3c15387C97BE809eaffB1982176a",
23
+ "withdrawalQueue": "0xfe56573178f1bcdf53F01A6E9977670dcBBD9186",
24
+ "burner": "0xb2c99cd38a2636a6281a849C8de938B3eF4A7C3D",
25
+ "withdrawalVault": "0x4473dCDDbf77679A643BdB654dbd86D67F8d32f2"
26
+ }
27
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "CSModule": "0xdA7dE2ECdDfccC6c3AF10108Db212ACBBf9EA83F",
3
+ "Accounting": "0x4d72BFF1BeaC69925F8Bd12526a39BAAb069e5Da",
4
+ "FeeDistributor": "0xD99CC66fEC647E68294C6477B40fC7E0F6F618D0",
5
+ "FeeOracle": "0x4D4074628678Bd302921c20573EEa1ed38DdF7FB",
6
+ "HashConsensus": "0x71093efF8D8599b5fA340D665Ad60fA7C80688e4",
7
+ "ParametersRegistry": "0x9D28ad303C90DF524BA960d7a2DAC56DcC31e428",
8
+ "ValidatorStrikes": "0xaa328816027F2D32B9F56d190BC9Fa4A5C07637f",
9
+ "Verifier": "0xdC5FE1782B6943f318E05230d688713a560063DC",
10
+ "Ejector": "0xc72b58aa02E0e98cF8A4a0E9Dce75e763800802C",
11
+ "ExitPenalties": "0x06cd61045f958A209a0f8D746e103eCc625f4193",
12
+ "GateSeal": "0xE1686C2E90eb41a48356c1cC7FaA17629af3ADB3",
13
+ "LidoLocator": "0xC1d0b3DE6792Bf6b4b37EccdcC24e45978Cfd2Eb",
14
+ "VettedGate": "0xB314D4A76C457c93150d308787939063F4Cc67E0",
15
+ "PermissionlessGate": "0xcF33a38111d0B1246A3F38a838fb41D626B454f0",
16
+ "ChainId": 1,
17
+ "git-ref": "cc8409a8ac21d7816d572658077dd6cf5f61507f",
18
+ "protocol": {
19
+ "stakingRouter": "0xFdDf38947aFB03C621C71b06C9C70bce73f12999",
20
+ "validatorsExitBusOracle": "0x0De4Ea0184c2ad0BacA7183356Aea5B8d5Bf5c6e",
21
+ "lido": "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84",
22
+ "withdrawalQueue": "0x889edC2eDab5f40e902b864aD4d7AdE8E412F9B1",
23
+ "burner": "0xE76c52750019b80B43E36DF30bf4060EB73F573a",
24
+ "withdrawalVault": "0xB9D7934878B5FB9610B3fE8A5e441e8fad7E293f"
25
+ }
26
+ }
@@ -0,0 +1,53 @@
1
+ {
2
+ "abiGitRef": "b8efc5695322f3b5064dec961888806633ad2419",
3
+ "abiHashes": {
4
+ "CSModule": "9cad8e9a5e8330e9ec0e4b045713a6bfa8b63eeebfe15cea5b5745a2c6c661a5",
5
+ "CuratedModule": "f5460a39f02e1221b515deb642ba36783758dfb5e59e703f407b034a735846b5",
6
+ "Accounting": "26039df3e117838bb86c035b106038cb746514e440007fc10683bada8b2117ce",
7
+ "FeeDistributor": "3631179853889acf2b35ecc727daa0289631442cbb1979f8a9e7eec3bd25eee1",
8
+ "FeeOracle": "bea2188e38e62f4f32efec379b2b4886b3a810dd2da726f629c8910dc157a401",
9
+ "HashConsensus": "c56bd6734d1de5c843d8af3eef132f2baf65157937d3fa640471407317403731",
10
+ "VettedGate": "fbd27dfaf50549ad081740998f54b199d694e642d97db285eaf9f3e6ac67ac5c",
11
+ "CuratedGate": "64cbffb05557fc80711fd310760f121c01f4a4920a49361c5c8c13f9cbcfc02f",
12
+ "PermissionlessGate": "3d2f6e54999af1bb8a14b284f10e7a89f67e4e0b41ed8a85c8991a71078eaff9",
13
+ "ParametersRegistry": "8c8e9ec98221320f46c4593bbbcf07fda252d8291894c43e5ee9f1bbc490000c",
14
+ "MetaRegistry": "8aa946bab44d8dfccf38a381c541628d8ab59d3831e5168d3f3534b0b2dbb6f1",
15
+ "Verifier": "b86b0ba3eda936e51026043652c33197d73a77b708dfc67b41e605e964bcdcee",
16
+ "VEBO": "7999bdb1db0520c141efdcc3be6e5e185ffefc74b928948feae9f209bec1b6df",
17
+ "StakingRouter": "5c167acfa7b7afbd18323bef94936c1e41b96d2a71a1562b08a8da6f6b2639d4",
18
+ "Lido": "5d0b9f1b8017e723505fdc8ade1516b2556891527c05bda13cccb4369b46e700",
19
+ "LidoLocator": "352bf71565e2f635d6a86e59ea1f5921c1f6bc7a04d76caadcbd475a51e3b9e3"
20
+ },
21
+ "snapshots": [
22
+ {
23
+ "chain": "hoodi",
24
+ "module": "cm",
25
+ "gitRef": "a6be775483e17d76718f8852428b5251a75c6429"
26
+ },
27
+ {
28
+ "chain": "hoodi",
29
+ "module": "csm",
30
+ "gitRef": "a6be775483e17d76718f8852428b5251a75c6429"
31
+ },
32
+ {
33
+ "chain": "mainnet",
34
+ "module": "csm",
35
+ "gitRef": "cc8409a8ac21d7816d572658077dd6cf5f61507f"
36
+ }
37
+ ],
38
+ "protocolResolvedAt": {
39
+ "hoodi/csm": {
40
+ "chainId": 560048,
41
+ "block": 3113497
42
+ },
43
+ "hoodi/cm": {
44
+ "chainId": 560048,
45
+ "block": 3113499
46
+ },
47
+ "mainnet/csm": {
48
+ "chainId": 1,
49
+ "block": 25423656
50
+ }
51
+ },
52
+ "generatedAt": "2026-06-29T13:35:19.356Z"
53
+ }