@invisi-labs/sdk 1.1.6 → 1.2.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.
Files changed (132) hide show
  1. package/README.md +5 -0
  2. package/dist/broadcaster-3KTB4JO2.cjs +21 -0
  3. package/dist/broadcaster-3KTB4JO2.cjs.map +1 -0
  4. package/dist/broadcaster-7ZKKSTZQ.js +21 -0
  5. package/dist/broadcaster-preparation-PJ263WBL.cjs +15 -0
  6. package/dist/broadcaster-preparation-PJ263WBL.cjs.map +1 -0
  7. package/dist/broadcaster-preparation-ZQAPZAUG.js +15 -0
  8. package/dist/broadcaster-preparation-ZQAPZAUG.js.map +1 -0
  9. package/dist/chunk-2URICDPW.cjs +167 -0
  10. package/dist/chunk-2URICDPW.cjs.map +1 -0
  11. package/dist/chunk-3D24ABYR.js +86 -0
  12. package/dist/chunk-3D24ABYR.js.map +1 -0
  13. package/dist/chunk-3KTQQZOW.cjs +71 -0
  14. package/dist/chunk-3KTQQZOW.cjs.map +1 -0
  15. package/dist/chunk-4H4FARQK.js +1582 -0
  16. package/dist/chunk-4H4FARQK.js.map +1 -0
  17. package/dist/chunk-4SDP53YQ.cjs +765 -0
  18. package/dist/chunk-4SDP53YQ.cjs.map +1 -0
  19. package/dist/{chunk-QC6TQR3R.js → chunk-4VI6LYGH.js} +35 -12
  20. package/dist/chunk-4VI6LYGH.js.map +1 -0
  21. package/dist/chunk-BBSRP4MH.cjs +287 -0
  22. package/dist/chunk-BBSRP4MH.cjs.map +1 -0
  23. package/dist/chunk-DGMVGFKM.js +41 -0
  24. package/dist/chunk-DGMVGFKM.js.map +1 -0
  25. package/dist/chunk-GUD3LAUO.js +765 -0
  26. package/dist/chunk-GUD3LAUO.js.map +1 -0
  27. package/dist/chunk-HCB7RQ3S.cjs +79 -0
  28. package/dist/chunk-HCB7RQ3S.cjs.map +1 -0
  29. package/dist/{broadcaster-preparation-QVL62KM6.js → chunk-HKGJXQVN.js} +73 -34
  30. package/dist/chunk-HKGJXQVN.js.map +1 -0
  31. package/dist/chunk-HLH5JZD4.js +287 -0
  32. package/dist/chunk-HLH5JZD4.js.map +1 -0
  33. package/dist/chunk-J6TZZVAM.cjs +230 -0
  34. package/dist/chunk-J6TZZVAM.cjs.map +1 -0
  35. package/dist/chunk-LOR6PYH5.cjs +397 -0
  36. package/dist/chunk-LOR6PYH5.cjs.map +1 -0
  37. package/dist/chunk-MA2QZEF5.cjs +399 -0
  38. package/dist/chunk-MA2QZEF5.cjs.map +1 -0
  39. package/dist/chunk-MI4IP4ZD.cjs +86 -0
  40. package/dist/chunk-MI4IP4ZD.cjs.map +1 -0
  41. package/dist/chunk-NKYHYIRP.cjs +1582 -0
  42. package/dist/chunk-NKYHYIRP.cjs.map +1 -0
  43. package/dist/chunk-OCZLJKIA.cjs +41 -0
  44. package/dist/chunk-OCZLJKIA.cjs.map +1 -0
  45. package/dist/chunk-R5YAOJKB.js +71 -0
  46. package/dist/chunk-R5YAOJKB.js.map +1 -0
  47. package/dist/chunk-RY4M2CIQ.js +399 -0
  48. package/dist/chunk-RY4M2CIQ.js.map +1 -0
  49. package/dist/chunk-THMD5QO2.js +79 -0
  50. package/dist/chunk-THMD5QO2.js.map +1 -0
  51. package/dist/chunk-ZD2652WH.js +230 -0
  52. package/dist/chunk-ZD2652WH.js.map +1 -0
  53. package/dist/credit.cjs +1 -0
  54. package/dist/credit.cjs.map +1 -0
  55. package/dist/credit.d.cts +12 -0
  56. package/dist/credit.d.ts +12 -0
  57. package/dist/credit.js +1 -0
  58. package/dist/credit.js.map +1 -0
  59. package/dist/ethers.cjs +11 -385
  60. package/dist/ethers.cjs.map +1 -1
  61. package/dist/ethers.d.cts +16 -6
  62. package/dist/ethers.d.ts +16 -6
  63. package/dist/ethers.js +1 -1
  64. package/dist/index-CLhGwLxZ.d.cts +42 -0
  65. package/dist/index-Crp-ZFiM.d.ts +42 -0
  66. package/dist/index.cjs +479 -7847
  67. package/dist/index.cjs.map +1 -1
  68. package/dist/index.d.cts +87 -710
  69. package/dist/index.d.ts +87 -710
  70. package/dist/index.js +407 -869
  71. package/dist/index.js.map +1 -1
  72. package/dist/note.cjs +11 -0
  73. package/dist/note.cjs.map +1 -0
  74. package/dist/note.d.cts +29 -0
  75. package/dist/note.d.ts +29 -0
  76. package/dist/note.js +11 -0
  77. package/dist/note.js.map +1 -0
  78. package/dist/operation-bridge-CoECSxfi.d.cts +472 -0
  79. package/dist/operation-bridge-CoECSxfi.d.ts +472 -0
  80. package/dist/preparation-HUBTVCZE.js +404 -0
  81. package/dist/preparation-HUBTVCZE.js.map +1 -0
  82. package/dist/preparation-QD3ZSYV5.cjs +404 -0
  83. package/dist/preparation-QD3ZSYV5.cjs.map +1 -0
  84. package/dist/provenance-preparation-43DN2WK7.cjs +16 -0
  85. package/dist/provenance-preparation-43DN2WK7.cjs.map +1 -0
  86. package/dist/provenance-preparation-HEZE4L5H.js +16 -0
  87. package/dist/provenance-preparation-HEZE4L5H.js.map +1 -0
  88. package/dist/provenance.cjs +59 -0
  89. package/dist/provenance.cjs.map +1 -0
  90. package/dist/provenance.d.cts +34 -0
  91. package/dist/provenance.d.ts +34 -0
  92. package/dist/provenance.js +59 -0
  93. package/dist/provenance.js.map +1 -0
  94. package/dist/receipt-logs-8Msm_HZS.d.ts +322 -0
  95. package/dist/receipt-logs-DWG4In8N.d.cts +322 -0
  96. package/dist/session-support.cjs +189 -0
  97. package/dist/session-support.cjs.map +1 -0
  98. package/dist/session-support.d.cts +284 -0
  99. package/dist/session-support.d.ts +284 -0
  100. package/dist/session-support.js +189 -0
  101. package/dist/session-support.js.map +1 -0
  102. package/package.json +25 -19
  103. package/dist/NoteOutput-DRkVnwlx.d.cts +0 -398
  104. package/dist/NoteOutput-DpDC6T2O.d.ts +0 -398
  105. package/dist/broadcaster-preparation-QVL62KM6.js.map +0 -1
  106. package/dist/chunk-4SD3MW6N.js +0 -4711
  107. package/dist/chunk-4SD3MW6N.js.map +0 -1
  108. package/dist/chunk-FL4TIGWW.js +0 -1781
  109. package/dist/chunk-FL4TIGWW.js.map +0 -1
  110. package/dist/chunk-QC6TQR3R.js.map +0 -1
  111. package/dist/indexeddb.cjs +0 -6878
  112. package/dist/indexeddb.cjs.map +0 -1
  113. package/dist/indexeddb.d.cts +0 -20
  114. package/dist/indexeddb.d.ts +0 -20
  115. package/dist/indexeddb.js +0 -71
  116. package/dist/indexeddb.js.map +0 -1
  117. package/dist/memory.cjs +0 -6886
  118. package/dist/memory.cjs.map +0 -1
  119. package/dist/memory.d.cts +0 -12
  120. package/dist/memory.d.ts +0 -12
  121. package/dist/memory.js +0 -11
  122. package/dist/sqlite.cjs +0 -6862
  123. package/dist/sqlite.cjs.map +0 -1
  124. package/dist/sqlite.d.cts +0 -28
  125. package/dist/sqlite.d.ts +0 -28
  126. package/dist/sqlite.js +0 -55
  127. package/dist/sqlite.js.map +0 -1
  128. package/dist/state-C4HZFotm.d.cts +0 -78
  129. package/dist/state-C4HZFotm.d.ts +0 -78
  130. package/dist/store-8aBhnbGr.d.ts +0 -42
  131. package/dist/store-YrbXb6CY.d.cts +0 -42
  132. /package/dist/{memory.js.map → broadcaster-7ZKKSTZQ.js.map} +0 -0
@@ -1,4711 +0,0 @@
1
- import {
2
- TransactionPreparation,
3
- authorizationRequest,
4
- configureRecipientInfrastructure,
5
- creditLeaf,
6
- creditReservationKey,
7
- encodeOperation,
8
- exportBroadcasterIntent,
9
- fundingTypedData,
10
- inputFacts,
11
- operationExpired,
12
- operationSources,
13
- prepareWithErrors,
14
- publicProof,
15
- requiresAuthorization,
16
- statement,
17
- verifyMembership,
18
- walletBalance,
19
- walletBalances,
20
- witnessFor
21
- } from "./chunk-FL4TIGWW.js";
22
- import {
23
- EthersChainReader
24
- } from "./chunk-QC6TQR3R.js";
25
-
26
- // src/data/gas-benchmarks.json
27
- var gas_benchmarks_default = [
28
- {
29
- formatVersion: 1,
30
- id: "protocol-044e2ee-bc51dde071f1-prague-credit-real",
31
- deployment: {
32
- chainId: "31337",
33
- protocolAddress: "0x8a276b1F407e1273EDFf65e2f6292ee18dA68DD9",
34
- runtimeCodeHash: "0xf311c797d0296b13c1ef3f230bf4aadd621e38572f0c09a3f631b8edd0402ab4",
35
- tokenAddress: "0x99bbA657f2BbC93c02D617f8bA121cB8Fc104Acf"
36
- },
37
- source: {
38
- protocolCommit: "044e2ee9aeb9ba0e3dbd0630247495189e0405d4",
39
- measuredAt: "2026-11-05T09:54:05.044Z",
40
- chain: "Anvil 31337",
41
- hardfork: "prague",
42
- token: "MockERC20",
43
- verifier: "real",
44
- fingerprints: {
45
- protocolSourceSha256: "bc51dde071f1ac4616b3264305aeb2b04b52e0d13772625feed53fb5e8dae51b",
46
- dirtyDiffSha256: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
47
- compiledArtifactsSha256: "4900a39e94aeb31f686915bf8618efabf573b93365444db46a0bff3544741221",
48
- creditManifestSha256: "c27ff83889c3082b4c918bd63e15437881f0a6f12ed7f130312e1140873679fb",
49
- userManifestSha256: "9ef9d34d4459c2843d022712093216142e3eacdd1467d2382a6a68ad36c33b8f",
50
- sdkSourceSha256: "0f2fe2deda57196d3736964c8e2caea6d4975d2c246cb6d11edbb6c4b5eeead6"
51
- },
52
- toolchain: {
53
- solidity: "0.8.38",
54
- barretenberg: "6.0.0",
55
- noir: "1.0.0-rc.6",
56
- evmVersion: "prague",
57
- optimizerRuns: 200,
58
- anvil: "anvil Version: 1.8.6"
59
- },
60
- blockGasLimit: "500000000",
61
- runtimeContracts: {
62
- transact_user_slots14_direct_Verifier: {
63
- address: "0x5FbDB2315678afecb367f032d93F642f64180aa3",
64
- runtimeCodeHash: "0x42d1932097f18874242d98855b2fc167471ba84dd122ab3744996dd64320f675"
65
- },
66
- "transact_user_slots14-adapter": {
67
- address: "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512",
68
- runtimeCodeHash: "0x876f0e43fc1d24475c0c63ee8c7907427d534b0c604f5985aacd28ee2c6d1b12"
69
- },
70
- transact_user_slots56_direct_Verifier: {
71
- address: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0",
72
- runtimeCodeHash: "0xefca4a7ee5382b0f2029571f6781f2ade7ac698906c32d3e49f10def631e7882"
73
- },
74
- "transact_user_slots56-adapter": {
75
- address: "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9",
76
- runtimeCodeHash: "0x945680c4278b61c07bf07fa7637908e9a38ccd414c9330bf23b3c41119ea0de6"
77
- },
78
- transact_user_slots112_direct_Verifier: {
79
- address: "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9",
80
- runtimeCodeHash: "0xfbf97cd940123ab3e81ce55283efb48b55ddaa95423fff4d0d648b248f4e196b"
81
- },
82
- "transact_user_slots112-adapter": {
83
- address: "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707",
84
- runtimeCodeHash: "0xac129aa749b7ece8c51ed68f4f0afcc82a1cbd7b2a01f5ff7ff7de1dcde21b1e"
85
- },
86
- transact_user_slots168_direct_Verifier: {
87
- address: "0x0165878A594ca255338adfa4d48449f69242Eb8F",
88
- runtimeCodeHash: "0x7ee9799d55001f74c8d88179dd0247b3de932516f975605ba248b52e7ba540c8"
89
- },
90
- "transact_user_slots168-adapter": {
91
- address: "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853",
92
- runtimeCodeHash: "0x24b5ea6f436b90b3821bd0ea4872fb205c996fd74f1546bc1086d98b7ec5d87d"
93
- },
94
- transact_aggregate_14_4_Verifier: {
95
- address: "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6",
96
- runtimeCodeHash: "0xae41039ded63fa7777c99a2552ba603a3a4d9703d464079dff787dab6893ef24"
97
- },
98
- "transact_aggregate_14_4-adapter": {
99
- address: "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318",
100
- runtimeCodeHash: "0xf4e86e9b2001f5972ce00f7fcd5a01deb9bfe5d676e437e74135ee7036469ca3"
101
- },
102
- transact_aggregate_14_8_Verifier: {
103
- address: "0x610178dA211FEF7D417bC0e6FeD39F05609AD788",
104
- runtimeCodeHash: "0x089f476f56fb1003586b18c0b5a75f9d24c76d4804d84ea202005371eae333de"
105
- },
106
- "transact_aggregate_14_8-adapter": {
107
- address: "0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e",
108
- runtimeCodeHash: "0xc40142342902da65f45bb995724b129389e3505c283d7209a6c29bf27521c363"
109
- },
110
- transact_aggregate_14_12_Verifier: {
111
- address: "0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0",
112
- runtimeCodeHash: "0xe0cba79e66fdb75dbc082ef0f938b07e4d38acce283b87869fe414083b3e08b0"
113
- },
114
- "transact_aggregate_14_12-adapter": {
115
- address: "0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82",
116
- runtimeCodeHash: "0x155bfc9367a6f3c96ac9b4d1dc1d0358a4046b584a9a1322a9582557ea691ff4"
117
- },
118
- create_credit_direct_Verifier: {
119
- address: "0x9A676e781A523b5d0C0e43731313A708CB607508",
120
- runtimeCodeHash: "0xbc88c374cc3c0c1e2cdf8663cee4c960f3a3ba4b210e2c520ca111e56461b23a"
121
- },
122
- "create_credit-adapter": {
123
- address: "0x0B306BF915C4d645ff596e518fAf3F9669b97016",
124
- runtimeCodeHash: "0xfd39446d56c189fbb35c0906e525433b6b9c63444c97b13990b7dd6f19bd38fc"
125
- },
126
- credit_draw_slots1_direct_Verifier: {
127
- address: "0x959922bE3CAee4b8Cd9a407cc3ac1C251C2007B1",
128
- runtimeCodeHash: "0x47be80e72c3a22ea044638f6004de8c3a0264d5a0d17189c01153cdabfd7bab6"
129
- },
130
- "credit_draw_slots1-adapter": {
131
- address: "0x9A9f2CCfdE556A7E9Ff0848998Aa4a0CFD8863AE",
132
- runtimeCodeHash: "0x73a2af387b45cecf383b90f4cebb54b263f621a5038da947944c54f1089ba288"
133
- },
134
- credit_draw_slots12_direct_Verifier: {
135
- address: "0x68B1D87F95878fE05B998F19b66F4baba5De1aed",
136
- runtimeCodeHash: "0x244d9ba22f5c736c2a5c42c466701e2a8ba7ae8108665133541026ea45d56e04"
137
- },
138
- "credit_draw_slots12-adapter": {
139
- address: "0x3Aa5ebB10DC797CAC828524e59A333d0A371443c",
140
- runtimeCodeHash: "0x63c200eae61218b865f3c8b418bf0887da7a70ebf41f55825e4750c36a1d1914"
141
- },
142
- credit_draw_slots50_direct_Verifier: {
143
- address: "0xc6e7DF5E7b4f2A278906862b61205850344D4e7d",
144
- runtimeCodeHash: "0x2ad5eb64bcfae34ef04111dd8f9c1ffc5fc8aa6c1ad3a65d8da78233f3390660"
145
- },
146
- "credit_draw_slots50-adapter": {
147
- address: "0x59b670e9fA9D0A427751Af201D676719a970857b",
148
- runtimeCodeHash: "0x1716df69f1eb1c1db485bc3ba4a4ed5a1009275c9058a9e96b28ab3431a6c006"
149
- },
150
- credit_draw_slots120_direct_Verifier: {
151
- address: "0x4ed7c70F96B99c776995fB64377f0d4aB3B0e1C1",
152
- runtimeCodeHash: "0x523b6d211618bbd33d708f8198b9f3daafc10e2fa7a6a857db5795ed748a24e4"
153
- },
154
- "credit_draw_slots120-adapter": {
155
- address: "0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44",
156
- runtimeCodeHash: "0x32d875eb4f4c27252fa958971b66e1fdff8c02adb007fea2bf31eee4b851a132"
157
- },
158
- credit_cancel_direct_Verifier: {
159
- address: "0xa85233C63b9Ee964Add6F2cffe00Fd84eb32338f",
160
- runtimeCodeHash: "0x4058133b7ecd31fe06749bfa3107ad0fbcdc9bf72d3b9cbf4dbd2b2f65be6d35"
161
- },
162
- "credit_cancel-adapter": {
163
- address: "0x4A679253410272dd5232B3Ff7cF5dbB88f295319",
164
- runtimeCodeHash: "0x0f570794fb4b7f15a791c59c760732d9f9408d1e3bea881ba7c5b76b36fb4e9b"
165
- },
166
- credit_top_up_direct_Verifier: {
167
- address: "0x7a2088a1bFc9d81c55368AE168C2C02570cB814F",
168
- runtimeCodeHash: "0x7ada3623c851a9cfba7863a75f4fa289d747040f1a822510eefecc53d70180cd"
169
- },
170
- "credit_top_up-adapter": {
171
- address: "0x09635F643e140090A9A8Dcd712eD6285858ceBef",
172
- runtimeCodeHash: "0x23bba4eca8306f4bc02ead10449775a359beeed2065ea8c84da4dc6b9e4dfc82"
173
- },
174
- PrivateTransferVerifierRegistry: {
175
- address: "0xc5a5C42992dECbae36851359345FE25997F5C42d",
176
- runtimeCodeHash: "0xbc74aacbc22d853cb50fe2041f20014e644fa8f83e06f51656b4667f1da164bc"
177
- },
178
- CrossTreeVerifierRegistry: {
179
- address: "0x67d269191c92Caf3cD7723F116c85e6E9bf55933",
180
- runtimeCodeHash: "0x818ce6a634a11cdd9913873d3a265254dda45b490431ad1636373237e2685ba1"
181
- },
182
- DualVerifierRouter: {
183
- address: "0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E",
184
- runtimeCodeHash: "0xb3bdc1aa5a6e4eac85e3651615c7942c5565f0593d79bacccb19b5aa587548ca"
185
- },
186
- AtomicBatchOutputLib: {
187
- address: "0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690",
188
- runtimeCodeHash: "0xef68c4a35a62fbbb4d0918f1612f0ffd9d250c9ceefd38e59e9c8ef042addb45"
189
- },
190
- FundingLib: {
191
- address: "0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB",
192
- runtimeCodeHash: "0x36f4e6d20cf7ca1b221dad34bc34ed7b8540c0e774c594652048822272e6bb52"
193
- },
194
- PrivateTransferLib: {
195
- address: "0x9E545E3C0baAB3E08CdfD552C960A1050f373042",
196
- runtimeCodeHash: "0x1e538d13c68b2a7a2f605466cd7c09c166b904476a6b5b372f8b9b45d9de9a62"
197
- },
198
- CrossTreeTransferLib: {
199
- address: "0xa82fF9aFd8f496c3d6ac40E2a0F282E47488CFc9",
200
- runtimeCodeHash: "0x9ec892d5a5d1c38e3218c7d38c74bd63034641cc458a195ec63c6a50f67ded25"
201
- },
202
- AggregateTransferLib: {
203
- address: "0x1613beB3B2C4f22Ee086B2b38C1476A3cE7f78E8",
204
- runtimeCodeHash: "0x2c01c84317448e4786e7a7b9c06f6f3b4990354f151ae6914cdb75d8b7ebe881"
205
- },
206
- CreateCreditLib: {
207
- address: "0x851356ae760d987E095750cCeb3bC6014560891C",
208
- runtimeCodeHash: "0x8b28e626c6a0f41179880773a48681362a05e0eee12193d1641ae5bb625fe960"
209
- },
210
- CreditLifecycleLib: {
211
- address: "0xf5059a5D33d5853360D16C683c16e67980206f36",
212
- runtimeCodeHash: "0xa177a7f1dfb69cf2d6eea899ef8170959587b8cb3c60559c3b2cecf62309bfc4"
213
- },
214
- ShieldLib: {
215
- address: "0x95401dc811bb5740090279Ba06cfA8fcF6113778",
216
- runtimeCodeHash: "0xfde7bbf1c02e17ab2d9fc9849fc282b29ac1db86378eec27f3a006d7484aa768"
217
- },
218
- InvisiFactory: {
219
- address: "0x998abeb3E57409262aE5b751f60747921B33613E",
220
- runtimeCodeHash: "0x9055356390e48564adeca0065b12698a5d09451960af97ad2f5c2e450cb9c84c"
221
- },
222
- InvisiAddressRegistry: {
223
- address: "0x70e0bA845a1A0F2DA3359C97E0285013525FFC49",
224
- runtimeCodeHash: "0x007da3f4e888366ba0eed52cd511c4a369359291387ad19ca37e89eb395fce30"
225
- },
226
- InvisiProtocol: {
227
- address: "0x8a276b1F407e1273EDFf65e2f6292ee18dA68DD9",
228
- runtimeCodeHash: "0xf311c797d0296b13c1ef3f230bf4aadd621e38572f0c09a3f631b8edd0402ab4"
229
- },
230
- MockERC20: {
231
- address: "0x99bbA657f2BbC93c02D617f8bA121cB8Fc104Acf",
232
- runtimeCodeHash: "0xf7f676b5c54f6e94f82f0de65a0117468a0d915e8a79d150e74f76bd6d7f708b"
233
- }
234
- },
235
- assumptions: [
236
- "normal CREATE/Factory deployment and fresh registry; EIP170/EIP3860 unchanged; no code/storage injection",
237
- "Solidity0.8.38 optimizer200 Prague; pinned BB6.0.0 real verifiers; every native proof independently verified",
238
- "one physical source tree and 123 existing leaves shared by every sample; top-up has two authenticated source groups; no rollover or screener",
239
- "funding/approvals/121 genuine Credit seeds/usage-seed draw/payout reset excluded from business gas",
240
- "each round restores identical token balances, exact caller allowance100, note cursor, nullifiers and baseline; spender payout starts zero; broadcasterFee0",
241
- "complete receipt.gasUsed is measured, including verifier/calldata/logging/output insertion; memo0",
242
- "Prague local block gas limit500000000; measured transactions may be unmineable under lower network transaction/block limits",
243
- "observed three-sample ranges are neither a confidence interval nor a recommended transaction gas limit"
244
- ]
245
- },
246
- measurements: [
247
- {
248
- id: "create-credit-caller-0x0",
249
- shape: {
250
- kind: "create-credit",
251
- target: "evm",
252
- capacity: 10,
253
- noteInputs: 0,
254
- noteOutputs: 0,
255
- sourceTrees: 0,
256
- creditInputs: 0,
257
- creditOutputs: 1,
258
- creditRemainders: 0,
259
- funding: "caller",
260
- permit: false,
261
- deliveryBytes: 1132
262
- },
263
- circuit: {
264
- circuitName: "create_credit",
265
- target: "evm",
266
- artifactSha256: "16a41fd585d5f925e4e93fd6a308e1ca8c90ea287778871cb0d214f0d0e223ce",
267
- vkSha256: "e8d3dc1f6922dbe1a0aa6016e65664be28d7005180ee943a4b237ac5518971bb"
268
- },
269
- samples: [
270
- {
271
- gasUsed: "1577203",
272
- transactionHash: "0xf0532b598b3e3716709ff7aab549f95775ac0587c2f7cd0203f1a07cc32b46fc",
273
- blockNumber: "172",
274
- blockHash: "0x61f3ac4cb127a29dc679067666d91e3c123fda2fe8a149e46992d0581de6dbc6",
275
- calldataBytes: 11844
276
- },
277
- {
278
- gasUsed: "1577191",
279
- transactionHash: "0xcd1718bea7c432458c18f4215c36fa95ad5da0242fad67f1daaa33344518ae05",
280
- blockNumber: "172",
281
- blockHash: "0x08215dac6d5558f7ec753df9f66b3a03c7071b7c85b650ba170f621895ea53be",
282
- calldataBytes: 11844
283
- },
284
- {
285
- gasUsed: "1577203",
286
- transactionHash: "0xfd07f0fb37c58e302100fb533f946d8fae09514e53181666efc346313c758224",
287
- blockNumber: "172",
288
- blockHash: "0x5b1ac84931e9343276e5241088041bac0d07f1d7eced2b335eeccfe1a266d05d",
289
- calldataBytes: 11844
290
- }
291
- ]
292
- },
293
- {
294
- id: "create-credit-1x1",
295
- shape: {
296
- kind: "create-credit",
297
- target: "evm",
298
- capacity: 10,
299
- noteInputs: 1,
300
- noteOutputs: 1,
301
- sourceTrees: 1,
302
- creditInputs: 0,
303
- creditOutputs: 1,
304
- creditRemainders: 0,
305
- funding: "none",
306
- permit: false,
307
- deliveryBytes: 1360
308
- },
309
- circuit: {
310
- circuitName: "create_credit",
311
- target: "evm",
312
- artifactSha256: "16a41fd585d5f925e4e93fd6a308e1ca8c90ea287778871cb0d214f0d0e223ce",
313
- vkSha256: "e8d3dc1f6922dbe1a0aa6016e65664be28d7005180ee943a4b237ac5518971bb"
314
- },
315
- samples: [
316
- {
317
- gasUsed: "1673934",
318
- transactionHash: "0x267c40c655eaf82407bd9dcf4413a0e3ee991a39e2bf9f28506eb761d8eaf8ea",
319
- blockNumber: "172",
320
- blockHash: "0x137299123d2f9e8bae9f56f5f6e66f6020d41cc6e2397071458fb28abdc1d6b5",
321
- calldataBytes: 12196
322
- },
323
- {
324
- gasUsed: "1673898",
325
- transactionHash: "0x967d376d819fb00d0d52fb28ca8b3c1fce10e7ac9ff0314772c8d367b51b2e52",
326
- blockNumber: "172",
327
- blockHash: "0x16992b27d6bec5d87d6f2488ea31ad232b48dc0fd2effb724e312ddf83dd84f8",
328
- calldataBytes: 12196
329
- },
330
- {
331
- gasUsed: "1673994",
332
- transactionHash: "0xd474a561f35e353f446d312aba4338011f6a1765e5019cd839498ade1b2c8ad4",
333
- blockNumber: "172",
334
- blockHash: "0xdd2ff761b339b033dd11b462585cf747fdf97f6c304a66ddd1344d2421b790ae",
335
- calldataBytes: 12196
336
- }
337
- ]
338
- },
339
- {
340
- id: "draw-credit-1-partial",
341
- shape: {
342
- kind: "draw-credit",
343
- target: "evm",
344
- capacity: 1,
345
- noteInputs: 0,
346
- noteOutputs: 0,
347
- sourceTrees: 1,
348
- creditInputs: 1,
349
- creditOutputs: 1,
350
- creditRemainders: 1,
351
- funding: "none",
352
- permit: false,
353
- deliveryBytes: 1132
354
- },
355
- circuit: {
356
- circuitName: "credit_draw_slots1",
357
- target: "evm",
358
- artifactSha256: "4542b227e0552b45c302f1dace21cadeba4962c96244e021472f1f7531cff8d1",
359
- vkSha256: "43c051a2bedf9454c12e70b10156361e414944823ba23e80662c16c7ced0a2ce"
360
- },
361
- samples: [
362
- {
363
- gasUsed: "1587992",
364
- transactionHash: "0x7eecfe45066881f2e3a39d4d016e5234793a3927056ec51e5772661a7b0b8bd2",
365
- blockNumber: "172",
366
- blockHash: "0x4c6dd7f24673ec5e8f2bc6303827e3329f3b73d37043a638ed1bd4655282fa6a",
367
- calldataBytes: 11588
368
- },
369
- {
370
- gasUsed: "1587992",
371
- transactionHash: "0xb196e4ce260287d68a8ef8e072605f2cfb97e299e1ed3d8654ff33560a29a34d",
372
- blockNumber: "172",
373
- blockHash: "0x600aeaf1ca61fe7e4eb39dd8b618f696ba4b6a18a867232af62296c1fc7a24c0",
374
- calldataBytes: 11588
375
- },
376
- {
377
- gasUsed: "1587848",
378
- transactionHash: "0x14de44b3d363a129e8404c1e068d54098ccaf409bc0aaa142a962de94bc21825",
379
- blockNumber: "172",
380
- blockHash: "0x5312304c773a695984e22ff3eb08c4ca6f022e6e6bc8d7706012846ce8ac4f7c",
381
- calldataBytes: 11588
382
- }
383
- ]
384
- },
385
- {
386
- id: "draw-credit-1-full",
387
- shape: {
388
- kind: "draw-credit",
389
- target: "evm",
390
- capacity: 1,
391
- noteInputs: 0,
392
- noteOutputs: 0,
393
- sourceTrees: 1,
394
- creditInputs: 1,
395
- creditOutputs: 0,
396
- creditRemainders: 0,
397
- funding: "none",
398
- permit: false,
399
- deliveryBytes: 0
400
- },
401
- circuit: {
402
- circuitName: "credit_draw_slots1",
403
- target: "evm",
404
- artifactSha256: "4542b227e0552b45c302f1dace21cadeba4962c96244e021472f1f7531cff8d1",
405
- vkSha256: "43c051a2bedf9454c12e70b10156361e414944823ba23e80662c16c7ced0a2ce"
406
- },
407
- samples: [
408
- {
409
- gasUsed: "1043043",
410
- transactionHash: "0xfc91b84385a2f69bc253f0f486aa171a4911edd3041647b3758b44c0102c7c2f",
411
- blockNumber: "172",
412
- blockHash: "0x96f83ea8e57ebf1b8572bfbcb6285b8a57c894be0e3134e0c2b24dc44262fb07",
413
- calldataBytes: 10372
414
- },
415
- {
416
- gasUsed: "1043043",
417
- transactionHash: "0xddf613a92d05c1b80cf9074a0484fdbf3a2bfd94555b0d9c266fdfbe2661ed59",
418
- blockNumber: "172",
419
- blockHash: "0x27b36ebdd105eeb91be849f002816030377ea2e892fb7e1462509aa7b8632e6f",
420
- calldataBytes: 10372
421
- },
422
- {
423
- gasUsed: "1043091",
424
- transactionHash: "0x6df6942fafe1ef79c963b912206bd57443c90f9c8398e5529baf39d438a15b78",
425
- blockNumber: "172",
426
- blockHash: "0x95af3836c6fe01edbc70bab01ba2e844d0e8fdf9e03884ea5a9d569fd585ee81",
427
- calldataBytes: 10372
428
- }
429
- ]
430
- },
431
- {
432
- id: "draw-credit-12-partial",
433
- shape: {
434
- kind: "draw-credit",
435
- target: "evm",
436
- capacity: 12,
437
- noteInputs: 0,
438
- noteOutputs: 0,
439
- sourceTrees: 1,
440
- creditInputs: 12,
441
- creditOutputs: 12,
442
- creditRemainders: 12,
443
- funding: "none",
444
- permit: false,
445
- deliveryBytes: 13584
446
- },
447
- circuit: {
448
- circuitName: "credit_draw_slots12",
449
- target: "evm",
450
- artifactSha256: "dd72b0867fc3be7cd90de263bd2d0892075cb18eb4f6dd671b13111710f10369",
451
- vkSha256: "5e31d771e6294993736078596d9c69f21fe7595eda50e3cce6d7406b65cf1443"
452
- },
453
- samples: [
454
- {
455
- gasUsed: "3099088",
456
- transactionHash: "0x8a760b052eb9354ef7fd539ab21105ddec51feb6b4b9c51a73a139ac4f9bc1fe",
457
- blockNumber: "172",
458
- blockHash: "0x5f29a09258dbebafa6fa286c0a1d286bb54694df2e8bd7e7f0e1c9db26b53401",
459
- calldataBytes: 30276
460
- },
461
- {
462
- gasUsed: "3099004",
463
- transactionHash: "0x4af726505fdf1cdcb053d45cce369ff2a17a023b497b438206f232577f52a721",
464
- blockNumber: "172",
465
- blockHash: "0x762f0616f93335375441b637c545c4691e7ba09fae40952a220ef00a67198a87",
466
- calldataBytes: 30276
467
- },
468
- {
469
- gasUsed: "3099136",
470
- transactionHash: "0xf27042c34b5e7c0e0bfc2e7c6c1e3dcd5b24c98b09c91ab73d156a2d0e474698",
471
- blockNumber: "172",
472
- blockHash: "0xa7bde9fc7b6fe8e9a9082f4ae597f73608ad9ced3d670506b29584b2c67ab496",
473
- calldataBytes: 30276
474
- }
475
- ]
476
- },
477
- {
478
- id: "draw-credit-12-full",
479
- shape: {
480
- kind: "draw-credit",
481
- target: "evm",
482
- capacity: 12,
483
- noteInputs: 0,
484
- noteOutputs: 0,
485
- sourceTrees: 1,
486
- creditInputs: 12,
487
- creditOutputs: 0,
488
- creditRemainders: 0,
489
- funding: "none",
490
- permit: false,
491
- deliveryBytes: 0
492
- },
493
- circuit: {
494
- circuitName: "credit_draw_slots12",
495
- target: "evm",
496
- artifactSha256: "dd72b0867fc3be7cd90de263bd2d0892075cb18eb4f6dd671b13111710f10369",
497
- vkSha256: "5e31d771e6294993736078596d9c69f21fe7595eda50e3cce6d7406b65cf1443"
498
- },
499
- samples: [
500
- {
501
- gasUsed: "1537560",
502
- transactionHash: "0x6c78554a23c04c179a16a9da6c401f0097c02833d8e1c4a3cdeb79107c028333",
503
- blockNumber: "172",
504
- blockHash: "0xf463ea49ed0328a93b53bc796ff2e0dd46201cd3fee06e6fff160dbb95fe0654",
505
- calldataBytes: 15684
506
- },
507
- {
508
- gasUsed: "1537620",
509
- transactionHash: "0x8097a25c8c2ebced9bfa1baf39e128741e486ed5f7e23aed33ff03b280ac5a7f",
510
- blockNumber: "172",
511
- blockHash: "0xb121edc36419facbb33f4ca69021bcd71ab6f412664591edf040ac6558b44507",
512
- calldataBytes: 15684
513
- },
514
- {
515
- gasUsed: "1537560",
516
- transactionHash: "0x0a8311777aa63d9239647a14da359672f126c7aa306148d6f44f19eff48dab29",
517
- blockNumber: "172",
518
- blockHash: "0x065a0f3dd444525a0bed28045e978e3ba74c820eda5ecc488d04e83f416ab4f0",
519
- calldataBytes: 15684
520
- }
521
- ]
522
- },
523
- {
524
- id: "draw-credit-50-partial",
525
- shape: {
526
- kind: "draw-credit",
527
- target: "evm",
528
- capacity: 50,
529
- noteInputs: 0,
530
- noteOutputs: 0,
531
- sourceTrees: 1,
532
- creditInputs: 50,
533
- creditOutputs: 50,
534
- creditRemainders: 50,
535
- funding: "none",
536
- permit: false,
537
- deliveryBytes: 56600
538
- },
539
- circuit: {
540
- circuitName: "credit_draw_slots50",
541
- target: "evm",
542
- artifactSha256: "09c7469866748b4c0c4bbf2b040844771948a170999f6dc7a38fe5c0ecda4054",
543
- vkSha256: "7b613225b6f32a077011d4196c356e836d22dcd116efe687fde53144fbd8db9f"
544
- },
545
- samples: [
546
- {
547
- gasUsed: "7998858",
548
- transactionHash: "0x35a5ff5940aa7939214f82471b8d73531c07b1fcaa543bf31b0f7c1c91db73e2",
549
- blockNumber: "172",
550
- blockHash: "0x74175711e91a10d93a426d0ef778f12a15793ff5f8f9d8b397057e7cb4e27975",
551
- calldataBytes: 94276
552
- },
553
- {
554
- gasUsed: "7998498",
555
- transactionHash: "0x5e7a948f90e0d37a068d2904d5c1233b0ad6ecda632ef6968f4ec81daa3e932b",
556
- blockNumber: "172",
557
- blockHash: "0x8b348e78bbce768f9b44d55c43017b08ae0720cf010b923d658e4150bc4bd41f",
558
- calldataBytes: 94276
559
- },
560
- {
561
- gasUsed: "7998498",
562
- transactionHash: "0xf3d92e00b47c5d1c888f98c038b1dbac1986888fabbb40690762b0e9eea6b923",
563
- blockNumber: "172",
564
- blockHash: "0x1ae727d66e31623abc741d7e5c62db4197c6238fc73a6c0984725b1dee43b9b0",
565
- calldataBytes: 94276
566
- }
567
- ]
568
- },
569
- {
570
- id: "draw-credit-50-full",
571
- shape: {
572
- kind: "draw-credit",
573
- target: "evm",
574
- capacity: 50,
575
- noteInputs: 0,
576
- noteOutputs: 0,
577
- sourceTrees: 1,
578
- creditInputs: 50,
579
- creditOutputs: 0,
580
- creditRemainders: 0,
581
- funding: "none",
582
- permit: false,
583
- deliveryBytes: 0
584
- },
585
- circuit: {
586
- circuitName: "credit_draw_slots50",
587
- target: "evm",
588
- artifactSha256: "09c7469866748b4c0c4bbf2b040844771948a170999f6dc7a38fe5c0ecda4054",
589
- vkSha256: "7b613225b6f32a077011d4196c356e836d22dcd116efe687fde53144fbd8db9f"
590
- },
591
- samples: [
592
- {
593
- gasUsed: "3220161",
594
- transactionHash: "0xadd94db9328f43891fc6cb9c788415319c95a98bcd8b98e2a245d3ba07c1f20a",
595
- blockNumber: "172",
596
- blockHash: "0x257deb859f7a2c14ef38cb32797b6d0278b25ce2c7cd75ccf81f0c00a1b97250",
597
- calldataBytes: 33476
598
- },
599
- {
600
- gasUsed: "3219933",
601
- transactionHash: "0xe631bbd7681d42974d3b1b25f6e0c7602d32196253f6cee4dc67b5e87929132f",
602
- blockNumber: "172",
603
- blockHash: "0xafee3915573a0316c9df0f1a56b7a4c4ff8652e74c3890f851ef351e7faedbf3",
604
- calldataBytes: 33476
605
- },
606
- {
607
- gasUsed: "3219897",
608
- transactionHash: "0xfb3807a266b2bfa971b87b3820b6eba6ab968f1028b1d77c9fbcb19177fb7319",
609
- blockNumber: "172",
610
- blockHash: "0xe6310300cca8b021fd969b27392eae58c21a9c15e071ff8836e42e6490265c0c",
611
- calldataBytes: 33476
612
- }
613
- ]
614
- },
615
- {
616
- id: "draw-credit-120-partial",
617
- shape: {
618
- kind: "draw-credit",
619
- target: "evm",
620
- capacity: 120,
621
- noteInputs: 0,
622
- noteOutputs: 0,
623
- sourceTrees: 1,
624
- creditInputs: 120,
625
- creditOutputs: 120,
626
- creditRemainders: 120,
627
- funding: "none",
628
- permit: false,
629
- deliveryBytes: 135840
630
- },
631
- circuit: {
632
- circuitName: "credit_draw_slots120",
633
- target: "evm",
634
- artifactSha256: "6ccd0366a669c50fd5da875c3eae194fe8aa4c36d35a5f9ebfd64636ea599b48",
635
- vkSha256: "d715848afc5c1ecdfcef5ed5026865abef5040a3bc232fd65330a5ffee8475fb"
636
- },
637
- samples: [
638
- {
639
- gasUsed: "17418369",
640
- transactionHash: "0xfab5aadd357ae6105c153dcc98aee2df80a5b46bd911dab0bd457c5440c0e9bb",
641
- blockNumber: "172",
642
- blockHash: "0xa277729db5ab154b10f2a0c6daa2540f66de7f81e05a289f2f057fef30e43275",
643
- calldataBytes: 211140
644
- },
645
- {
646
- gasUsed: "17418537",
647
- transactionHash: "0xa3d1311b426b88808cd9a5403ecd36c3aea806ac7e2089e6aa22eba7f82e80f6",
648
- blockNumber: "172",
649
- blockHash: "0x1abf2a9ae3d60f84947bce8449d3ee19e6542a14c6bb1dcde4d37c4df9ab6dfc",
650
- calldataBytes: 211140
651
- },
652
- {
653
- gasUsed: "17417949",
654
- transactionHash: "0x6c7e3735c0d30d2b1897bbacd1a85d8534b714564c87449d1c66fb7b96aebf19",
655
- blockNumber: "172",
656
- blockHash: "0x17bbc7923c075a1beaf345fbe768629d1c895a32835343640ecb5f7a48da18ab",
657
- calldataBytes: 211140
658
- }
659
- ]
660
- },
661
- {
662
- id: "draw-credit-120-full",
663
- shape: {
664
- kind: "draw-credit",
665
- target: "evm",
666
- capacity: 120,
667
- noteInputs: 0,
668
- noteOutputs: 0,
669
- sourceTrees: 1,
670
- creditInputs: 120,
671
- creditOutputs: 0,
672
- creditRemainders: 0,
673
- funding: "none",
674
- permit: false,
675
- deliveryBytes: 0
676
- },
677
- circuit: {
678
- circuitName: "credit_draw_slots120",
679
- target: "evm",
680
- artifactSha256: "6ccd0366a669c50fd5da875c3eae194fe8aa4c36d35a5f9ebfd64636ea599b48",
681
- vkSha256: "d715848afc5c1ecdfcef5ed5026865abef5040a3bc232fd65330a5ffee8475fb"
682
- },
683
- samples: [
684
- {
685
- gasUsed: "6297541",
686
- transactionHash: "0x0e8e80524d7c23a263ad9ed122bb61e5a1ab19285585ac402b7206d87abaf067",
687
- blockNumber: "172",
688
- blockHash: "0x7ee829303eaaffc7823238e99e83304ccfd3ba349c64fecdee00b882fe39f854",
689
- calldataBytes: 65220
690
- },
691
- {
692
- gasUsed: "6297661",
693
- transactionHash: "0x98f2be383f19b1b17f86c6d365abe86655163b7846c29e5614667ab0e2823bc8",
694
- blockNumber: "172",
695
- blockHash: "0x3738cef2d40552677299002974043a4355f37d1d76575ee52fc4fe6b6e0c33dd",
696
- calldataBytes: 65220
697
- },
698
- {
699
- gasUsed: "6297613",
700
- transactionHash: "0xb574546b0aacd7d6910e25a2a749aad7f009ed725618763c6229ee7a99fd811e",
701
- blockNumber: "172",
702
- blockHash: "0x26a15b914134d2f5d5597d632328d368888f3d3076b486231345bb20a4749230",
703
- calldataBytes: 65220
704
- }
705
- ]
706
- },
707
- {
708
- id: "top-up-credit-1x1-unchanged-limits",
709
- shape: {
710
- kind: "top-up-credit",
711
- target: "evm",
712
- capacity: 10,
713
- noteInputs: 1,
714
- noteOutputs: 1,
715
- sourceTrees: 2,
716
- creditInputs: 1,
717
- creditOutputs: 1,
718
- creditRemainders: 0,
719
- funding: "none",
720
- permit: false,
721
- deliveryBytes: 1360
722
- },
723
- circuit: {
724
- circuitName: "credit_top_up",
725
- target: "evm",
726
- artifactSha256: "3004eea1c26ec8e33f8fc9ee171a3b6af250682efb607f7003ae58f8327998ab",
727
- vkSha256: "b7f378a871a27649c3f7fd1af554c8f87d99bcf0780b21972e910212ed4e5a0d"
728
- },
729
- samples: [
730
- {
731
- gasUsed: "1714625",
732
- transactionHash: "0x5cebd593124a22bfeac5d22ea51735fedbf409f61e42abd1f398c1b907f4b192",
733
- blockNumber: "172",
734
- blockHash: "0x04b820b1ac7b4697cc16e2d29e5ba8b530906b6fa5e75da2b022b0a5851cf150",
735
- calldataBytes: 12356
736
- },
737
- {
738
- gasUsed: "1714697",
739
- transactionHash: "0xd4506ce267c635552b112ee7d304d45433c34d938baf95a46241b88c33f7e57e",
740
- blockNumber: "172",
741
- blockHash: "0xe7424e20b69104ccf5d407ceb8d72a8fbd3a73ea76fea15c59d8a6e9f0ff3909",
742
- calldataBytes: 12356
743
- },
744
- {
745
- gasUsed: "1714577",
746
- transactionHash: "0xcf1af44b92f6fa4a46962ece6cbd9216db16438b0ce3320c78f62a59d8753875",
747
- blockNumber: "172",
748
- blockHash: "0x8a4e50a429190ed3f3d33c8863682d989bdf553cb5e0d961ebd9283f19b1aeea",
749
- calldataBytes: 12356
750
- }
751
- ]
752
- },
753
- {
754
- id: "top-up-credit-1x1-changed-limits",
755
- shape: {
756
- kind: "top-up-credit",
757
- target: "evm",
758
- capacity: 10,
759
- noteInputs: 1,
760
- noteOutputs: 1,
761
- sourceTrees: 2,
762
- creditInputs: 1,
763
- creditOutputs: 1,
764
- creditRemainders: 0,
765
- funding: "none",
766
- permit: false,
767
- deliveryBytes: 1360
768
- },
769
- circuit: {
770
- circuitName: "credit_top_up",
771
- target: "evm",
772
- artifactSha256: "3004eea1c26ec8e33f8fc9ee171a3b6af250682efb607f7003ae58f8327998ab",
773
- vkSha256: "b7f378a871a27649c3f7fd1af554c8f87d99bcf0780b21972e910212ed4e5a0d"
774
- },
775
- samples: [
776
- {
777
- gasUsed: "1714697",
778
- transactionHash: "0xa35c6efd60b27de672329ca9b8f05bb076f8d4e2505ee94a95387e097f9a967b",
779
- blockNumber: "172",
780
- blockHash: "0x1dd5c7d5206498ad08edcbaa5ba2002560008a6caff12383a14e3733718f0814",
781
- calldataBytes: 12356
782
- },
783
- {
784
- gasUsed: "1714637",
785
- transactionHash: "0xf8d23c58fa9030fc891c27e45b9bd5905a8b0fe065b83803dbf0239441b64a72",
786
- blockNumber: "172",
787
- blockHash: "0xc30c6143900dad39d793dc13065fd9c8f1c2e4f77fd350f9a4b3c7eea930c840",
788
- calldataBytes: 12356
789
- },
790
- {
791
- gasUsed: "1714709",
792
- transactionHash: "0xed72962263a722fcc0d8cb4218579d161dba700c490258c8b0e35a86c574b49e",
793
- blockNumber: "172",
794
- blockHash: "0x227f3f3fc06e7263168584b1e23d0f722a3255ec818570e76fd36ee4423efcfd",
795
- calldataBytes: 12356
796
- }
797
- ]
798
- },
799
- {
800
- id: "cancel-credit-1",
801
- shape: {
802
- kind: "cancel-credit",
803
- target: "evm",
804
- capacity: 1,
805
- noteInputs: 0,
806
- noteOutputs: 0,
807
- sourceTrees: 1,
808
- creditInputs: 1,
809
- creditOutputs: 0,
810
- creditRemainders: 0,
811
- funding: "none",
812
- permit: false,
813
- deliveryBytes: 0
814
- },
815
- circuit: {
816
- circuitName: "credit_cancel",
817
- target: "evm",
818
- artifactSha256: "6485609280fe5a3d44ca9f1865b29b44253b3d2cd49770d000e7bb7a3db8e65d",
819
- vkSha256: "d74cf842d204cdf271c06a69482ddff11568e89630346b634d486205bec4bd9e"
820
- },
821
- samples: [
822
- {
823
- gasUsed: "988734",
824
- transactionHash: "0x6a029f228817b397197ad191ec2f4d8e17e004c5c93b58ffcf7ae0d83bb4661a",
825
- blockNumber: "172",
826
- blockHash: "0x2d0c2050a76696544b225b450634bf892e336157e5dbe41f1a821af8d0c2702e",
827
- calldataBytes: 9604
828
- },
829
- {
830
- gasUsed: "988734",
831
- transactionHash: "0xd9a72b12117c0a3f3905b567922ca326ae21be4447b5e85b4a7b4744be8c2046",
832
- blockNumber: "172",
833
- blockHash: "0x50f057b1b6c559b46df96c6eea7f22f40a11c39186e8869c819cdc343e56826b",
834
- calldataBytes: 9604
835
- },
836
- {
837
- gasUsed: "988698",
838
- transactionHash: "0x5d7aeb7e7089d3ab48d8e2bfe482d0c65caacb39779e3550118f49937f43f494",
839
- blockNumber: "172",
840
- blockHash: "0x58dd724ad5f1bca91a0b7bc69722f58890c02e0d205193ad2bb47960bced25d6",
841
- calldataBytes: 9604
842
- }
843
- ]
844
- }
845
- ]
846
- },
847
- {
848
- formatVersion: 1,
849
- id: "protocol-92ef274-osaka-real",
850
- deployment: {
851
- chainId: "31337",
852
- protocolAddress: "0x8870C63A18a9480C7de9B860b849fD293832856D",
853
- runtimeCodeHash: "0x604572c0da90ea139b774cd0d2962a2972fac46e0556c7cec6f6f9aac5deef14",
854
- tokenAddress: "0x4826533B4897376654Bb4d4AD88B7faFD0C98528"
855
- },
856
- source: {
857
- protocolCommit: "92ef274c6b36d783507699a33ee20e52192c83c7",
858
- measuredAt: "2026-10-27T08:42:15.991Z",
859
- chain: "Anvil 31337",
860
- hardfork: "osaka",
861
- token: "MockERC20",
862
- verifier: "real",
863
- assumptions: [
864
- "normal CREATE/Factory deployment; no code or storage injection",
865
- "Solidity 0.8.27 optimizer 200; real BB 5.2.1 verifiers",
866
- "one source tree; two existing leaves; no rollover or screener",
867
- "funding/approval setup excluded; complete transaction receipt gas included",
868
- "exact allowance for caller funding; configured benchmark payout balances",
869
- "observed local samples, not a confidence interval or gas limit"
870
- ]
871
- },
872
- measurements: [
873
- {
874
- id: "shield-1",
875
- shape: {
876
- kind: "shield",
877
- target: "evm",
878
- capacity: 0,
879
- noteInputs: 0,
880
- noteOutputs: 1,
881
- sourceTrees: 0,
882
- creditInputs: 0,
883
- creditOutputs: 0,
884
- creditRemainders: 0,
885
- funding: "caller",
886
- permit: false,
887
- deliveryBytes: 226
888
- },
889
- circuit: null,
890
- samples: [
891
- {
892
- gasUsed: "649286",
893
- transactionHash: "0xcc299d1780ada9a69b1d9f0f3d06a165db15fccbd2b7ff407834f02f5d563a18",
894
- blockNumber: "50",
895
- blockHash: "0xbcb868e781a20588d2fa099a4d7f87c1600044a2e5ec1e369e384d7a5f22f00a",
896
- calldataBytes: 1156
897
- },
898
- {
899
- gasUsed: "649322",
900
- transactionHash: "0x95139dff109725989f0769e3e6fb9bd3e7e1bf581fd475f14e822875eb90fda4",
901
- blockNumber: "50",
902
- blockHash: "0x7ace353fea4fc8c856c0fd45521d200b02619921977709ff4f910e0ff41c06fe",
903
- calldataBytes: 1156
904
- },
905
- {
906
- gasUsed: "649322",
907
- transactionHash: "0xef578bb38dc8ff8bfd47d2e76e3ab4273019ea9a385f5d2fd99add32ceaecb58",
908
- blockNumber: "50",
909
- blockHash: "0xded817f8ef89637e2443e3b626c0837f184ca134fe753be913d5570554c649a6",
910
- calldataBytes: 1156
911
- }
912
- ]
913
- },
914
- {
915
- id: "shield-2",
916
- shape: {
917
- kind: "shield",
918
- target: "evm",
919
- capacity: 0,
920
- noteInputs: 0,
921
- noteOutputs: 2,
922
- sourceTrees: 0,
923
- creditInputs: 0,
924
- creditOutputs: 0,
925
- creditRemainders: 0,
926
- funding: "caller",
927
- permit: false,
928
- deliveryBytes: 452
929
- },
930
- circuit: null,
931
- samples: [
932
- {
933
- gasUsed: "757063",
934
- transactionHash: "0x024e2dfbd6f50c368e2a4aa347e3029de668f4ebd36b80227aa003bb7ac21c74",
935
- blockNumber: "50",
936
- blockHash: "0x8ed63973c158d706ac54bb646626e4f0db5777b4bd56d179b94503af6c417c50",
937
- calldataBytes: 1668
938
- },
939
- {
940
- gasUsed: "757063",
941
- transactionHash: "0x898d852ab28f68adac4d30b160a3dbfee33fa7ca875f70df9eb7763b6b1cd1f0",
942
- blockNumber: "50",
943
- blockHash: "0x9bb6810de38193933a9f26fa03d3d9bad1ca0151ff5e04544c56520e09da3043",
944
- calldataBytes: 1668
945
- },
946
- {
947
- gasUsed: "757039",
948
- transactionHash: "0x8ff9720e3197aab2d741fbd8d0fa2969203ea8cd051d9649d1e5eb890bcc2be3",
949
- blockNumber: "50",
950
- blockHash: "0x8604c75eb6363aaae774276e638f5b749aae1f8f815eb99ab1183137eef5730e",
951
- calldataBytes: 1668
952
- }
953
- ]
954
- },
955
- {
956
- id: "shield-10",
957
- shape: {
958
- kind: "shield",
959
- target: "evm",
960
- capacity: 0,
961
- noteInputs: 0,
962
- noteOutputs: 10,
963
- sourceTrees: 0,
964
- creditInputs: 0,
965
- creditOutputs: 0,
966
- creditRemainders: 0,
967
- funding: "caller",
968
- permit: false,
969
- deliveryBytes: 2260
970
- },
971
- circuit: null,
972
- samples: [
973
- {
974
- gasUsed: "1692143",
975
- transactionHash: "0x6c13db8bd8a8599daf5034e56712abefbf406982fafe7647b6d22291ba4199ed",
976
- blockNumber: "50",
977
- blockHash: "0x1ab2ae514f408a79e0c40ca10cee74b2e23d7c8a5f24641b8eea3e1cf58ce700",
978
- calldataBytes: 5764
979
- },
980
- {
981
- gasUsed: "1692083",
982
- transactionHash: "0x5e476c9d3838b782a51332af9bf5c372d29fc411c2168a7af619c52bd5309c7b",
983
- blockNumber: "50",
984
- blockHash: "0x9c62bc72fc90f990c6711b48865ff922a1856ae05c4fef61dad5f4da7d948401",
985
- calldataBytes: 5764
986
- },
987
- {
988
- gasUsed: "1692203",
989
- transactionHash: "0x0092e2d9160fad95279cde586fc6c79c713244f55db8a2060a5abab9d98c176a",
990
- blockNumber: "50",
991
- blockHash: "0xac1bf780b4cc05b4dcc7ee5d741c049ba99ab4af9bdcd25104add730c2a14152",
992
- calldataBytes: 5764
993
- }
994
- ]
995
- },
996
- {
997
- id: "transfer-1x2",
998
- shape: {
999
- kind: "transfer",
1000
- target: "evm",
1001
- capacity: 14,
1002
- noteInputs: 1,
1003
- noteOutputs: 2,
1004
- sourceTrees: 1,
1005
- creditInputs: 0,
1006
- creditOutputs: 0,
1007
- creditRemainders: 0,
1008
- funding: "none",
1009
- permit: false,
1010
- deliveryBytes: 452
1011
- },
1012
- circuit: {
1013
- circuitName: "transact_user_slots14",
1014
- target: "evm",
1015
- artifactSha256: "2a6a20839e90b88b1ecd629f59a01821bad3ee11dbe04db1fd9cdce7a3de0e84",
1016
- vkSha256: "ffe0e1a4e690792ecb4eb1fc1acc9ff60f13d3b5af03cfc6ae6d6bf26e99bdea"
1017
- },
1018
- samples: [
1019
- {
1020
- gasUsed: "1617516",
1021
- transactionHash: "0xf49ea3d31cc1346472172e2dee84f9360f60a3fe948a3ef6e87f727af6d42f0d",
1022
- blockNumber: "49",
1023
- blockHash: "0xf59c57e63ec2f03abc36d28f273b0af5290184dc97197df740b23d79a851a887",
1024
- calldataBytes: 11012
1025
- },
1026
- {
1027
- gasUsed: "1617516",
1028
- transactionHash: "0xf8d11286f1f2a4db006ff6b06900c47d0fbf685984499e1e5d4aea49478ba8e5",
1029
- blockNumber: "49",
1030
- blockHash: "0xeb5a800190be3534c9e2675c97ac56d0e0be8adef55f60bd32d375776a7d150c",
1031
- calldataBytes: 11012
1032
- },
1033
- {
1034
- gasUsed: "1617504",
1035
- transactionHash: "0x8939fcea97079a3c5118b9e94325455e2ad1cdb47310ae499a277272654b3eb6",
1036
- blockNumber: "49",
1037
- blockHash: "0xecffefb593e2fec5d5827cfd39d0cc4d0efb67dbff6f8dbbd0d2db2439a80cf9",
1038
- calldataBytes: 11012
1039
- }
1040
- ]
1041
- },
1042
- {
1043
- id: "transfer-1x14",
1044
- shape: {
1045
- kind: "transfer",
1046
- target: "evm",
1047
- capacity: 56,
1048
- noteInputs: 1,
1049
- noteOutputs: 14,
1050
- sourceTrees: 1,
1051
- creditInputs: 0,
1052
- creditOutputs: 0,
1053
- creditRemainders: 0,
1054
- funding: "none",
1055
- permit: false,
1056
- deliveryBytes: 3164
1057
- },
1058
- circuit: {
1059
- circuitName: "transact_user_slots56",
1060
- target: "evm",
1061
- artifactSha256: "ba83ec2f177d16fa88ea04bc54f2e99920f1ac195cdb05b88b9b3bbc245fd953",
1062
- vkSha256: "6ad5d3aff0c72a632fb19895658af093a6a92478a9994985e838a71e61237720"
1063
- },
1064
- samples: [
1065
- {
1066
- gasUsed: "2489010",
1067
- transactionHash: "0x053557acea930a869d6469c91e9bc015d0893607a6ab18d2af684986f7074676",
1068
- blockNumber: "49",
1069
- blockHash: "0x734873097eb5e4cb66bfc2cdb61fac6753b53a4b9450fb22895281100af3aaf3",
1070
- calldataBytes: 17156
1071
- },
1072
- {
1073
- gasUsed: "2489106",
1074
- transactionHash: "0xb3990edb994011775e275bc1eb38c527b7206a2bfadf510e8aa53e260f3594b8",
1075
- blockNumber: "49",
1076
- blockHash: "0xf8cb019ebb0ecd0ec5d6634198292883c63fe93a7c65c34f9f3120c6cc54f1cf",
1077
- calldataBytes: 17156
1078
- },
1079
- {
1080
- gasUsed: "2489094",
1081
- transactionHash: "0xc97079019567ff8a79d285421351ee4bc48d14092a0e12ff634151719e991088",
1082
- blockNumber: "49",
1083
- blockHash: "0x5a6947839165c8961eeeb9190331415c40366a78b4a6a5771e7b8954dbb8b3c7",
1084
- calldataBytes: 17156
1085
- }
1086
- ]
1087
- },
1088
- {
1089
- id: "transfer-1x56",
1090
- shape: {
1091
- kind: "transfer",
1092
- target: "evm",
1093
- capacity: 112,
1094
- noteInputs: 1,
1095
- noteOutputs: 56,
1096
- sourceTrees: 1,
1097
- creditInputs: 0,
1098
- creditOutputs: 0,
1099
- creditRemainders: 0,
1100
- funding: "none",
1101
- permit: false,
1102
- deliveryBytes: 12656
1103
- },
1104
- circuit: {
1105
- circuitName: "transact_user_slots112",
1106
- target: "evm",
1107
- artifactSha256: "713b78469b6e97711122210f8497942120c1c9d66d3604bc184566c4eba59cc3",
1108
- vkSha256: "d6a46e297949c28b9a62fd9aef1f202870fdca97b8bfb15beefd27b9e9f3d86e"
1109
- },
1110
- samples: [
1111
- {
1112
- gasUsed: "5389227",
1113
- transactionHash: "0xb820d3c358724c1d64422017f232d074e4ff1ffaf1b1ce5ee719409427cf2208",
1114
- blockNumber: "49",
1115
- blockHash: "0x474bd1e52457801d1a596a9f23aeb6d365a17be028ee0c8cf8fd4758eaa1106b",
1116
- calldataBytes: 36356
1117
- },
1118
- {
1119
- gasUsed: "5389095",
1120
- transactionHash: "0x16514d8cf1136d7a7f40591859e2ea2d256af66520498e1fc81eb28837db600d",
1121
- blockNumber: "49",
1122
- blockHash: "0x42314a0d6eb9e765869e1b66b279444c78f919d2c28aed544d9fa7ac3bd2acb4",
1123
- calldataBytes: 36356
1124
- },
1125
- {
1126
- gasUsed: "5389203",
1127
- transactionHash: "0xee69d565a7eafb60ad7a47afe80a49d4fa40b50660669d9141e7dc6f4c3dbe0d",
1128
- blockNumber: "49",
1129
- blockHash: "0x0dcdada663ee04dd63e06fcdb79dacc5623201d29b687f63deede2b4762a994e",
1130
- calldataBytes: 36356
1131
- }
1132
- ]
1133
- },
1134
- {
1135
- id: "transfer-1x112",
1136
- shape: {
1137
- kind: "transfer",
1138
- target: "evm",
1139
- capacity: 168,
1140
- noteInputs: 1,
1141
- noteOutputs: 112,
1142
- sourceTrees: 1,
1143
- creditInputs: 0,
1144
- creditOutputs: 0,
1145
- creditRemainders: 0,
1146
- funding: "none",
1147
- permit: false,
1148
- deliveryBytes: 25312
1149
- },
1150
- circuit: {
1151
- circuitName: "transact_user_slots168",
1152
- target: "evm",
1153
- artifactSha256: "f7b3b1384e961367702f544299ca3521d8205fac31b7691c45ff84325d5a31c3",
1154
- vkSha256: "e00181533d7e35d2307570528f9e7f8f88e2909b6ae338d93373b608dea96881"
1155
- },
1156
- samples: [
1157
- {
1158
- gasUsed: "9139842",
1159
- transactionHash: "0x09951c4e00b868b6660429d187a482004646e4c84ef341d3b98352c249db6a06",
1160
- blockNumber: "49",
1161
- blockHash: "0xba9da3c08189335acff1eb33554f5f12475e4a6510324cf6ec9eadf340ce15d2",
1162
- calldataBytes: 61444
1163
- },
1164
- {
1165
- gasUsed: "9139650",
1166
- transactionHash: "0xb06f69d1c6e5406758918d5d296ab889bab4c3814f616cc581ad312cc7ebb2f3",
1167
- blockNumber: "49",
1168
- blockHash: "0x5516a76b4b366f2e539a67bb848b7d232c3e6f328d34ca5bd3dba43a14c316bf",
1169
- calldataBytes: 61444
1170
- },
1171
- {
1172
- gasUsed: "9139530",
1173
- transactionHash: "0x116c4875b7712b7cb51cdb0fcb6e66a95733dca272aa272bc0b1fd265edbe26c",
1174
- blockNumber: "49",
1175
- blockHash: "0xd36340fddd1eace21b73f785c6589bf73b07bef782f2e78a5e3d3d828b0b607c",
1176
- calldataBytes: 61444
1177
- }
1178
- ]
1179
- },
1180
- {
1181
- id: "withdraw-1x1",
1182
- shape: {
1183
- kind: "withdraw",
1184
- target: "evm",
1185
- capacity: 14,
1186
- noteInputs: 1,
1187
- noteOutputs: 1,
1188
- sourceTrees: 1,
1189
- creditInputs: 0,
1190
- creditOutputs: 0,
1191
- creditRemainders: 0,
1192
- funding: "none",
1193
- permit: false,
1194
- deliveryBytes: 226
1195
- },
1196
- circuit: {
1197
- circuitName: "transact_user_slots14",
1198
- target: "evm",
1199
- artifactSha256: "2a6a20839e90b88b1ecd629f59a01821bad3ee11dbe04db1fd9cdce7a3de0e84",
1200
- vkSha256: "ffe0e1a4e690792ecb4eb1fc1acc9ff60f13d3b5af03cfc6ae6d6bf26e99bdea"
1201
- },
1202
- samples: [
1203
- {
1204
- gasUsed: "1597571",
1205
- transactionHash: "0x326892d32146e0bc36b396fd3973151a629312df68ed25a4ffbb6a3da23ba274",
1206
- blockNumber: "49",
1207
- blockHash: "0x3e0f326cba3dd019b86431b4c22145758a7f10c121a696a81a094746b04495b5",
1208
- calldataBytes: 10564
1209
- },
1210
- {
1211
- gasUsed: "1597715",
1212
- transactionHash: "0x2e3a15157ac9c07e4717bbd4641481ce3bc0068d26157752815b6ec6b30acdd0",
1213
- blockNumber: "49",
1214
- blockHash: "0xab7fceac97d55e8702d1202b98d3a05c4b1e0f71e51b6d88d7e80e91cc338596",
1215
- calldataBytes: 10564
1216
- },
1217
- {
1218
- gasUsed: "1597595",
1219
- transactionHash: "0x5052e94a67520c43416cdcb60a1365a126560861173d0eef46bcbf0a566fe947",
1220
- blockNumber: "49",
1221
- blockHash: "0x9a64cf76b646b5a07b72fcc61266e87f17365fec891701c331982a93e5ba9b89",
1222
- calldataBytes: 10564
1223
- }
1224
- ]
1225
- },
1226
- {
1227
- id: "sweep-1x0",
1228
- shape: {
1229
- kind: "sweep",
1230
- target: "evm",
1231
- capacity: 14,
1232
- noteInputs: 1,
1233
- noteOutputs: 0,
1234
- sourceTrees: 1,
1235
- creditInputs: 0,
1236
- creditOutputs: 0,
1237
- creditRemainders: 0,
1238
- funding: "none",
1239
- permit: false,
1240
- deliveryBytes: 0
1241
- },
1242
- circuit: {
1243
- circuitName: "transact_user_slots14",
1244
- target: "evm",
1245
- artifactSha256: "2a6a20839e90b88b1ecd629f59a01821bad3ee11dbe04db1fd9cdce7a3de0e84",
1246
- vkSha256: "ffe0e1a4e690792ecb4eb1fc1acc9ff60f13d3b5af03cfc6ae6d6bf26e99bdea"
1247
- },
1248
- samples: [
1249
- {
1250
- gasUsed: "1069308",
1251
- transactionHash: "0xb1ab469d05ca5f49659f54a332cc172892dcce37e475342fbf52fa9cfb4d3927",
1252
- blockNumber: "49",
1253
- blockHash: "0xe5b04579149987198801f1ca19ab771d5262de2aaf9861a6c962d50d1c6baef0",
1254
- calldataBytes: 10116
1255
- },
1256
- {
1257
- gasUsed: "1069284",
1258
- transactionHash: "0xd6adee997f7e1e19e3918f913f6ee48d94df69c09ed74e333325023089e7f6df",
1259
- blockNumber: "49",
1260
- blockHash: "0xcb225566f8f1ea6ae8da30158b8f1aef03d50fa4ea352a00aa42b7f41a05d63c",
1261
- calldataBytes: 10116
1262
- },
1263
- {
1264
- gasUsed: "1069308",
1265
- transactionHash: "0xe06dd7f3a2718bc9a9412c2d6f505960ce225b2e5fe6c1c66bb5b0e8f427006f",
1266
- blockNumber: "49",
1267
- blockHash: "0x37a08c5918892e1c19df017c746ab0ede03c1bb195c3be593d70c1f9de91897e",
1268
- calldataBytes: 10116
1269
- }
1270
- ]
1271
- }
1272
- ]
1273
- },
1274
- {
1275
- formatVersion: 1,
1276
- id: "protocol-044e2ee-bc51dde071f1-prague-credit-real-accrued-fees",
1277
- deployment: {
1278
- chainId: "31337",
1279
- protocolAddress: "0x8a276b1F407e1273EDFf65e2f6292ee18dA68DD9",
1280
- runtimeCodeHash: "0xf311c797d0296b13c1ef3f230bf4aadd621e38572f0c09a3f631b8edd0402ab4",
1281
- tokenAddress: "0x99bbA657f2BbC93c02D617f8bA121cB8Fc104Acf"
1282
- },
1283
- source: {
1284
- protocolCommit: "044e2ee9aeb9ba0e3dbd0630247495189e0405d4",
1285
- measuredAt: "2026-11-05T10:18:51.134Z",
1286
- chain: "Anvil 31337",
1287
- hardfork: "prague",
1288
- token: "MockERC20",
1289
- verifier: "real",
1290
- fingerprints: {
1291
- protocolSourceSha256: "bc51dde071f1ac4616b3264305aeb2b04b52e0d13772625feed53fb5e8dae51b",
1292
- dirtyDiffSha256: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
1293
- compiledArtifactsSha256: "4900a39e94aeb31f686915bf8618efabf573b93365444db46a0bff3544741221",
1294
- creditManifestSha256: "c27ff83889c3082b4c918bd63e15437881f0a6f12ed7f130312e1140873679fb",
1295
- userManifestSha256: "9ef9d34d4459c2843d022712093216142e3eacdd1467d2382a6a68ad36c33b8f",
1296
- sdkSourceSha256: "11b42d88482ab2b0ce8adf02a8fef00a667fc73e4cb5c926cd76da6181c5ce15"
1297
- },
1298
- toolchain: {
1299
- solidity: "0.8.38",
1300
- barretenberg: "6.0.0",
1301
- noir: "1.0.0-rc.6",
1302
- evmVersion: "prague",
1303
- optimizerRuns: 200,
1304
- anvil: "anvil Version: 1.8.6"
1305
- },
1306
- blockGasLimit: "500000000",
1307
- runtimeContracts: {
1308
- transact_user_slots14_direct_Verifier: {
1309
- address: "0x5FbDB2315678afecb367f032d93F642f64180aa3",
1310
- runtimeCodeHash: "0x42d1932097f18874242d98855b2fc167471ba84dd122ab3744996dd64320f675"
1311
- },
1312
- "transact_user_slots14-adapter": {
1313
- address: "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512",
1314
- runtimeCodeHash: "0x876f0e43fc1d24475c0c63ee8c7907427d534b0c604f5985aacd28ee2c6d1b12"
1315
- },
1316
- transact_user_slots56_direct_Verifier: {
1317
- address: "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0",
1318
- runtimeCodeHash: "0xefca4a7ee5382b0f2029571f6781f2ade7ac698906c32d3e49f10def631e7882"
1319
- },
1320
- "transact_user_slots56-adapter": {
1321
- address: "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9",
1322
- runtimeCodeHash: "0x945680c4278b61c07bf07fa7637908e9a38ccd414c9330bf23b3c41119ea0de6"
1323
- },
1324
- transact_user_slots112_direct_Verifier: {
1325
- address: "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9",
1326
- runtimeCodeHash: "0xfbf97cd940123ab3e81ce55283efb48b55ddaa95423fff4d0d648b248f4e196b"
1327
- },
1328
- "transact_user_slots112-adapter": {
1329
- address: "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707",
1330
- runtimeCodeHash: "0xac129aa749b7ece8c51ed68f4f0afcc82a1cbd7b2a01f5ff7ff7de1dcde21b1e"
1331
- },
1332
- transact_user_slots168_direct_Verifier: {
1333
- address: "0x0165878A594ca255338adfa4d48449f69242Eb8F",
1334
- runtimeCodeHash: "0x7ee9799d55001f74c8d88179dd0247b3de932516f975605ba248b52e7ba540c8"
1335
- },
1336
- "transact_user_slots168-adapter": {
1337
- address: "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853",
1338
- runtimeCodeHash: "0x24b5ea6f436b90b3821bd0ea4872fb205c996fd74f1546bc1086d98b7ec5d87d"
1339
- },
1340
- transact_aggregate_14_4_Verifier: {
1341
- address: "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6",
1342
- runtimeCodeHash: "0xae41039ded63fa7777c99a2552ba603a3a4d9703d464079dff787dab6893ef24"
1343
- },
1344
- "transact_aggregate_14_4-adapter": {
1345
- address: "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318",
1346
- runtimeCodeHash: "0xf4e86e9b2001f5972ce00f7fcd5a01deb9bfe5d676e437e74135ee7036469ca3"
1347
- },
1348
- transact_aggregate_14_8_Verifier: {
1349
- address: "0x610178dA211FEF7D417bC0e6FeD39F05609AD788",
1350
- runtimeCodeHash: "0x089f476f56fb1003586b18c0b5a75f9d24c76d4804d84ea202005371eae333de"
1351
- },
1352
- "transact_aggregate_14_8-adapter": {
1353
- address: "0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e",
1354
- runtimeCodeHash: "0xc40142342902da65f45bb995724b129389e3505c283d7209a6c29bf27521c363"
1355
- },
1356
- transact_aggregate_14_12_Verifier: {
1357
- address: "0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0",
1358
- runtimeCodeHash: "0xe0cba79e66fdb75dbc082ef0f938b07e4d38acce283b87869fe414083b3e08b0"
1359
- },
1360
- "transact_aggregate_14_12-adapter": {
1361
- address: "0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82",
1362
- runtimeCodeHash: "0x155bfc9367a6f3c96ac9b4d1dc1d0358a4046b584a9a1322a9582557ea691ff4"
1363
- },
1364
- create_credit_direct_Verifier: {
1365
- address: "0x9A676e781A523b5d0C0e43731313A708CB607508",
1366
- runtimeCodeHash: "0xbc88c374cc3c0c1e2cdf8663cee4c960f3a3ba4b210e2c520ca111e56461b23a"
1367
- },
1368
- "create_credit-adapter": {
1369
- address: "0x0B306BF915C4d645ff596e518fAf3F9669b97016",
1370
- runtimeCodeHash: "0xfd39446d56c189fbb35c0906e525433b6b9c63444c97b13990b7dd6f19bd38fc"
1371
- },
1372
- credit_draw_slots1_direct_Verifier: {
1373
- address: "0x959922bE3CAee4b8Cd9a407cc3ac1C251C2007B1",
1374
- runtimeCodeHash: "0x47be80e72c3a22ea044638f6004de8c3a0264d5a0d17189c01153cdabfd7bab6"
1375
- },
1376
- "credit_draw_slots1-adapter": {
1377
- address: "0x9A9f2CCfdE556A7E9Ff0848998Aa4a0CFD8863AE",
1378
- runtimeCodeHash: "0x73a2af387b45cecf383b90f4cebb54b263f621a5038da947944c54f1089ba288"
1379
- },
1380
- credit_draw_slots12_direct_Verifier: {
1381
- address: "0x68B1D87F95878fE05B998F19b66F4baba5De1aed",
1382
- runtimeCodeHash: "0x244d9ba22f5c736c2a5c42c466701e2a8ba7ae8108665133541026ea45d56e04"
1383
- },
1384
- "credit_draw_slots12-adapter": {
1385
- address: "0x3Aa5ebB10DC797CAC828524e59A333d0A371443c",
1386
- runtimeCodeHash: "0x63c200eae61218b865f3c8b418bf0887da7a70ebf41f55825e4750c36a1d1914"
1387
- },
1388
- credit_draw_slots50_direct_Verifier: {
1389
- address: "0xc6e7DF5E7b4f2A278906862b61205850344D4e7d",
1390
- runtimeCodeHash: "0x2ad5eb64bcfae34ef04111dd8f9c1ffc5fc8aa6c1ad3a65d8da78233f3390660"
1391
- },
1392
- "credit_draw_slots50-adapter": {
1393
- address: "0x59b670e9fA9D0A427751Af201D676719a970857b",
1394
- runtimeCodeHash: "0x1716df69f1eb1c1db485bc3ba4a4ed5a1009275c9058a9e96b28ab3431a6c006"
1395
- },
1396
- credit_draw_slots120_direct_Verifier: {
1397
- address: "0x4ed7c70F96B99c776995fB64377f0d4aB3B0e1C1",
1398
- runtimeCodeHash: "0x523b6d211618bbd33d708f8198b9f3daafc10e2fa7a6a857db5795ed748a24e4"
1399
- },
1400
- "credit_draw_slots120-adapter": {
1401
- address: "0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44",
1402
- runtimeCodeHash: "0x32d875eb4f4c27252fa958971b66e1fdff8c02adb007fea2bf31eee4b851a132"
1403
- },
1404
- credit_cancel_direct_Verifier: {
1405
- address: "0xa85233C63b9Ee964Add6F2cffe00Fd84eb32338f",
1406
- runtimeCodeHash: "0x4058133b7ecd31fe06749bfa3107ad0fbcdc9bf72d3b9cbf4dbd2b2f65be6d35"
1407
- },
1408
- "credit_cancel-adapter": {
1409
- address: "0x4A679253410272dd5232B3Ff7cF5dbB88f295319",
1410
- runtimeCodeHash: "0x0f570794fb4b7f15a791c59c760732d9f9408d1e3bea881ba7c5b76b36fb4e9b"
1411
- },
1412
- credit_top_up_direct_Verifier: {
1413
- address: "0x7a2088a1bFc9d81c55368AE168C2C02570cB814F",
1414
- runtimeCodeHash: "0x7ada3623c851a9cfba7863a75f4fa289d747040f1a822510eefecc53d70180cd"
1415
- },
1416
- "credit_top_up-adapter": {
1417
- address: "0x09635F643e140090A9A8Dcd712eD6285858ceBef",
1418
- runtimeCodeHash: "0x23bba4eca8306f4bc02ead10449775a359beeed2065ea8c84da4dc6b9e4dfc82"
1419
- },
1420
- PrivateTransferVerifierRegistry: {
1421
- address: "0xc5a5C42992dECbae36851359345FE25997F5C42d",
1422
- runtimeCodeHash: "0xbc74aacbc22d853cb50fe2041f20014e644fa8f83e06f51656b4667f1da164bc"
1423
- },
1424
- CrossTreeVerifierRegistry: {
1425
- address: "0x67d269191c92Caf3cD7723F116c85e6E9bf55933",
1426
- runtimeCodeHash: "0x818ce6a634a11cdd9913873d3a265254dda45b490431ad1636373237e2685ba1"
1427
- },
1428
- DualVerifierRouter: {
1429
- address: "0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E",
1430
- runtimeCodeHash: "0xb3bdc1aa5a6e4eac85e3651615c7942c5565f0593d79bacccb19b5aa587548ca"
1431
- },
1432
- AtomicBatchOutputLib: {
1433
- address: "0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690",
1434
- runtimeCodeHash: "0xef68c4a35a62fbbb4d0918f1612f0ffd9d250c9ceefd38e59e9c8ef042addb45"
1435
- },
1436
- FundingLib: {
1437
- address: "0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB",
1438
- runtimeCodeHash: "0x36f4e6d20cf7ca1b221dad34bc34ed7b8540c0e774c594652048822272e6bb52"
1439
- },
1440
- PrivateTransferLib: {
1441
- address: "0x9E545E3C0baAB3E08CdfD552C960A1050f373042",
1442
- runtimeCodeHash: "0x1e538d13c68b2a7a2f605466cd7c09c166b904476a6b5b372f8b9b45d9de9a62"
1443
- },
1444
- CrossTreeTransferLib: {
1445
- address: "0xa82fF9aFd8f496c3d6ac40E2a0F282E47488CFc9",
1446
- runtimeCodeHash: "0x9ec892d5a5d1c38e3218c7d38c74bd63034641cc458a195ec63c6a50f67ded25"
1447
- },
1448
- AggregateTransferLib: {
1449
- address: "0x1613beB3B2C4f22Ee086B2b38C1476A3cE7f78E8",
1450
- runtimeCodeHash: "0x2c01c84317448e4786e7a7b9c06f6f3b4990354f151ae6914cdb75d8b7ebe881"
1451
- },
1452
- CreateCreditLib: {
1453
- address: "0x851356ae760d987E095750cCeb3bC6014560891C",
1454
- runtimeCodeHash: "0x8b28e626c6a0f41179880773a48681362a05e0eee12193d1641ae5bb625fe960"
1455
- },
1456
- CreditLifecycleLib: {
1457
- address: "0xf5059a5D33d5853360D16C683c16e67980206f36",
1458
- runtimeCodeHash: "0xa177a7f1dfb69cf2d6eea899ef8170959587b8cb3c60559c3b2cecf62309bfc4"
1459
- },
1460
- ShieldLib: {
1461
- address: "0x95401dc811bb5740090279Ba06cfA8fcF6113778",
1462
- runtimeCodeHash: "0xfde7bbf1c02e17ab2d9fc9849fc282b29ac1db86378eec27f3a006d7484aa768"
1463
- },
1464
- InvisiFactory: {
1465
- address: "0x998abeb3E57409262aE5b751f60747921B33613E",
1466
- runtimeCodeHash: "0x9055356390e48564adeca0065b12698a5d09451960af97ad2f5c2e450cb9c84c"
1467
- },
1468
- InvisiAddressRegistry: {
1469
- address: "0x70e0bA845a1A0F2DA3359C97E0285013525FFC49",
1470
- runtimeCodeHash: "0x007da3f4e888366ba0eed52cd511c4a369359291387ad19ca37e89eb395fce30"
1471
- },
1472
- InvisiProtocol: {
1473
- address: "0x8a276b1F407e1273EDFf65e2f6292ee18dA68DD9",
1474
- runtimeCodeHash: "0xf311c797d0296b13c1ef3f230bf4aadd621e38572f0c09a3f631b8edd0402ab4"
1475
- },
1476
- MockERC20: {
1477
- address: "0x99bbA657f2BbC93c02D617f8bA121cB8Fc104Acf",
1478
- runtimeCodeHash: "0xf7f676b5c54f6e94f82f0de65a0117468a0d915e8a79d150e74f76bd6d7f708b"
1479
- }
1480
- },
1481
- assumptions: [
1482
- "normal CREATE/Factory deployment and fresh registry; EIP170/EIP3860 unchanged; no code/storage injection",
1483
- "Solidity0.8.38 optimizer200 Prague; pinned BB6.0.0 real verifiers; every native proof independently verified",
1484
- "one physical source tree and 4 existing leaves shared by every sample; top-up has two authenticated source groups; no rollover or screener",
1485
- "funding/approvals/2 genuine Credit seeds/usage-seed draw/payout reset excluded from business gas",
1486
- "each round restores identical token balances, exact caller allowance105, note cursor, nullifiers and baseline; spender payout starts zero; broadcasterFee5",
1487
- "complete receipt.gasUsed is measured, including verifier/calldata/logging/output insertion; memo0",
1488
- "Prague local block gas limit500000000; measured transactions may be unmineable under lower network transaction/block limits",
1489
- "observed three-sample ranges are neither a confidence interval nor a recommended transaction gas limit"
1490
- ]
1491
- },
1492
- measurements: [
1493
- {
1494
- id: "create-credit-caller-0x0",
1495
- shape: {
1496
- kind: "create-credit",
1497
- target: "evm",
1498
- capacity: 10,
1499
- noteInputs: 0,
1500
- noteOutputs: 0,
1501
- sourceTrees: 0,
1502
- creditInputs: 0,
1503
- creditOutputs: 1,
1504
- creditRemainders: 0,
1505
- funding: "caller",
1506
- permit: false,
1507
- deliveryBytes: 1132
1508
- },
1509
- circuit: {
1510
- circuitName: "create_credit",
1511
- target: "evm",
1512
- artifactSha256: "16a41fd585d5f925e4e93fd6a308e1ca8c90ea287778871cb0d214f0d0e223ce",
1513
- vkSha256: "e8d3dc1f6922dbe1a0aa6016e65664be28d7005180ee943a4b237ac5518971bb"
1514
- },
1515
- samples: [
1516
- {
1517
- gasUsed: "1591717",
1518
- transactionHash: "0xd06c84a0fd796d0100870a9f1a17be8069677f0f304664d3670712740c8bdf62",
1519
- blockNumber: "53",
1520
- blockHash: "0x3d7c908964c165726e2ec0e921e61287864c7a5cb4677bd472f1d2d3b22c0d1b",
1521
- calldataBytes: 11844
1522
- },
1523
- {
1524
- gasUsed: "1591897",
1525
- transactionHash: "0x9eb1f64a8aeffff70213ef442d8553fff10676770768b1f4ad37508cf354c11c",
1526
- blockNumber: "53",
1527
- blockHash: "0xe52bf98f68f306ce13761e3e985c04572d43ac09b0790db5c5217144d68c044d",
1528
- calldataBytes: 11844
1529
- },
1530
- {
1531
- gasUsed: "1591957",
1532
- transactionHash: "0xb3ff21541b1acc1ced31459140c0016f2a5abc25a4723086e3012861d4a8f718",
1533
- blockNumber: "53",
1534
- blockHash: "0x681e28c2f26a020985e262c947b3732edaeeeff78f6d59d4957c188af53cfedc",
1535
- calldataBytes: 11844
1536
- }
1537
- ]
1538
- },
1539
- {
1540
- id: "create-credit-1x1",
1541
- shape: {
1542
- kind: "create-credit",
1543
- target: "evm",
1544
- capacity: 10,
1545
- noteInputs: 1,
1546
- noteOutputs: 1,
1547
- sourceTrees: 1,
1548
- creditInputs: 0,
1549
- creditOutputs: 1,
1550
- creditRemainders: 0,
1551
- funding: "none",
1552
- permit: false,
1553
- deliveryBytes: 1360
1554
- },
1555
- circuit: {
1556
- circuitName: "create_credit",
1557
- target: "evm",
1558
- artifactSha256: "16a41fd585d5f925e4e93fd6a308e1ca8c90ea287778871cb0d214f0d0e223ce",
1559
- vkSha256: "e8d3dc1f6922dbe1a0aa6016e65664be28d7005180ee943a4b237ac5518971bb"
1560
- },
1561
- samples: [
1562
- {
1563
- gasUsed: "1631989",
1564
- transactionHash: "0xf8acf0ee3e372c214ce5ef60d8e28b75ca3041a77d41d1e94acec78070572b5d",
1565
- blockNumber: "53",
1566
- blockHash: "0xd822acd15a4373e9c901579700c1f5e83810cf4a3760c99bd535196550f05676",
1567
- calldataBytes: 12196
1568
- },
1569
- {
1570
- gasUsed: "1632085",
1571
- transactionHash: "0x5315adad09961f10a32d18b8337513347327b85475a5fccf2b700262e34660f0",
1572
- blockNumber: "53",
1573
- blockHash: "0xd8a5f0b8fe42d735c3e0107291afae3973e14bb8fcbff48ea3a30f65172022e8",
1574
- calldataBytes: 12196
1575
- },
1576
- {
1577
- gasUsed: "1632013",
1578
- transactionHash: "0xbd92a3f189c9cdc991cb2843959d2d020ab3f1aeb48fdb0315147f204b9e4295",
1579
- blockNumber: "53",
1580
- blockHash: "0x77deffc18bfbc2cbc8e29c34b62b3be52984869cdcc73ccd245b03025d59797c",
1581
- calldataBytes: 12196
1582
- }
1583
- ]
1584
- },
1585
- {
1586
- id: "top-up-credit-1x1-unchanged-limits",
1587
- shape: {
1588
- kind: "top-up-credit",
1589
- target: "evm",
1590
- capacity: 10,
1591
- noteInputs: 1,
1592
- noteOutputs: 1,
1593
- sourceTrees: 2,
1594
- creditInputs: 1,
1595
- creditOutputs: 1,
1596
- creditRemainders: 0,
1597
- funding: "none",
1598
- permit: false,
1599
- deliveryBytes: 1360
1600
- },
1601
- circuit: {
1602
- circuitName: "credit_top_up",
1603
- target: "evm",
1604
- artifactSha256: "3004eea1c26ec8e33f8fc9ee171a3b6af250682efb607f7003ae58f8327998ab",
1605
- vkSha256: "b7f378a871a27649c3f7fd1af554c8f87d99bcf0780b21972e910212ed4e5a0d"
1606
- },
1607
- samples: [
1608
- {
1609
- gasUsed: "1672668",
1610
- transactionHash: "0x7a0ce3262fedebbd2b7c919f37fe0beb0b34d89a8a71223f13e9946c04131e21",
1611
- blockNumber: "53",
1612
- blockHash: "0x34c561de8fae1ca6230391e9dfe98187cf68bc30b51b4c7338083e4d5349dbff",
1613
- calldataBytes: 12356
1614
- },
1615
- {
1616
- gasUsed: "1672824",
1617
- transactionHash: "0xf27e9d4e588253646168e8db8bc187e5483dbb0ddc147728c29e06f2ab397349",
1618
- blockNumber: "53",
1619
- blockHash: "0xae2cd77d442ba1d55b436388eeded196dcd8735152c0c56dee8830f0ddd457c9",
1620
- calldataBytes: 12356
1621
- },
1622
- {
1623
- gasUsed: "1672824",
1624
- transactionHash: "0xd0633554a0a357d450e49fadecdfb61f39410a2b77969a445a00d7796c088f8a",
1625
- blockNumber: "53",
1626
- blockHash: "0x4851b2333dcb118bd2ca4c6e1332736d32d074e90096e6d144ea4d4262a01124",
1627
- calldataBytes: 12356
1628
- }
1629
- ]
1630
- },
1631
- {
1632
- id: "top-up-credit-1x1-changed-limits",
1633
- shape: {
1634
- kind: "top-up-credit",
1635
- target: "evm",
1636
- capacity: 10,
1637
- noteInputs: 1,
1638
- noteOutputs: 1,
1639
- sourceTrees: 2,
1640
- creditInputs: 1,
1641
- creditOutputs: 1,
1642
- creditRemainders: 0,
1643
- funding: "none",
1644
- permit: false,
1645
- deliveryBytes: 1360
1646
- },
1647
- circuit: {
1648
- circuitName: "credit_top_up",
1649
- target: "evm",
1650
- artifactSha256: "3004eea1c26ec8e33f8fc9ee171a3b6af250682efb607f7003ae58f8327998ab",
1651
- vkSha256: "b7f378a871a27649c3f7fd1af554c8f87d99bcf0780b21972e910212ed4e5a0d"
1652
- },
1653
- samples: [
1654
- {
1655
- gasUsed: "1672824",
1656
- transactionHash: "0x7dcd2f549ac253a1db6bf1956a0ae4f7116258cefa4d6468635694cc0cb310d6",
1657
- blockNumber: "53",
1658
- blockHash: "0x1b318287c6f265fae88233ea20e7a881723fd01f48ff86941323ad0e465f4757",
1659
- calldataBytes: 12356
1660
- },
1661
- {
1662
- gasUsed: "1672824",
1663
- transactionHash: "0x71b6d1de440b578539ca0045c74ee688dbd9ed1971cb19d12fc9256d46d3a6bd",
1664
- blockNumber: "53",
1665
- blockHash: "0x4a9cf7f534d3136b7042447671dd14663bfecce06bb1d432570871de0800995f",
1666
- calldataBytes: 12356
1667
- },
1668
- {
1669
- gasUsed: "1672812",
1670
- transactionHash: "0x781a4f563c1f9d17ec5228f49dd32942622e2090b7cefabf718e575ec1159697",
1671
- blockNumber: "53",
1672
- blockHash: "0xb7f060617081dd56a3a4fa723a2308ef008da493417dffe3d31b130dfb0f3e64",
1673
- calldataBytes: 12356
1674
- }
1675
- ]
1676
- },
1677
- {
1678
- id: "cancel-credit-1",
1679
- shape: {
1680
- kind: "cancel-credit",
1681
- target: "evm",
1682
- capacity: 1,
1683
- noteInputs: 0,
1684
- noteOutputs: 0,
1685
- sourceTrees: 1,
1686
- creditInputs: 1,
1687
- creditOutputs: 0,
1688
- creditRemainders: 0,
1689
- funding: "none",
1690
- permit: false,
1691
- deliveryBytes: 0
1692
- },
1693
- circuit: {
1694
- circuitName: "credit_cancel",
1695
- target: "evm",
1696
- artifactSha256: "6485609280fe5a3d44ca9f1865b29b44253b3d2cd49770d000e7bb7a3db8e65d",
1697
- vkSha256: "d74cf842d204cdf271c06a69482ddff11568e89630346b634d486205bec4bd9e"
1698
- },
1699
- samples: [
1700
- {
1701
- gasUsed: "1013031",
1702
- transactionHash: "0x14678b9811132c703f7593ee8e4c1dcaf478e11cf4ca06615cf432c9866b3bc3",
1703
- blockNumber: "53",
1704
- blockHash: "0x433f2aa3603339fcb28150f0fa6cc45f696cd04808fca1edb0798d674d6488f6",
1705
- calldataBytes: 9604
1706
- },
1707
- {
1708
- gasUsed: "1012983",
1709
- transactionHash: "0xa4be323a92ee04c57343c79997480fd32cbb6982641c8982504337f634e5d19b",
1710
- blockNumber: "53",
1711
- blockHash: "0x7e283b15e8f895ddc75e93041590b0fc7ade0833405e2fa2b349b63649b244d6",
1712
- calldataBytes: 9604
1713
- },
1714
- {
1715
- gasUsed: "1013043",
1716
- transactionHash: "0x4795ce2a29ea83ea3d44a92624fbd52ab370e6140404d94ecff0e5dee9c04e65",
1717
- blockNumber: "53",
1718
- blockHash: "0x90c7422c05e18142fe87c610e13eca9379055d4086019e46d4cacab875959a42",
1719
- calldataBytes: 9604
1720
- }
1721
- ]
1722
- }
1723
- ]
1724
- }
1725
- ];
1726
-
1727
- // src/gas-estimation.ts
1728
- var word = /^0x[0-9a-fA-F]{64}$/;
1729
- var address = /^0x[0-9a-fA-F]{40}$/;
1730
- var decimal = /^(0|[1-9][0-9]*)$/;
1731
- var shapeKeys = [
1732
- "kind",
1733
- "target",
1734
- "capacity",
1735
- "noteInputs",
1736
- "noteOutputs",
1737
- "sourceTrees",
1738
- "creditInputs",
1739
- "creditOutputs",
1740
- "creditRemainders",
1741
- "funding",
1742
- "permit",
1743
- "deliveryBytes"
1744
- ];
1745
- function copyGasBenchmarks(profiles) {
1746
- const copy = structuredClone([...profiles]);
1747
- for (const p of copy) {
1748
- if (p.formatVersion !== 1 || !p.id || !decimal.test(p.deployment.chainId) || !address.test(p.deployment.protocolAddress) || !address.test(p.deployment.tokenAddress) || !p.deployment.runtimeCodeHash || !word.test(p.deployment.runtimeCodeHash) || p.source.verifier !== "real" || !/^[0-9a-f]{40}$/i.test(p.source.protocolCommit) || !p.source.measuredAt || !Array.isArray(p.source.assumptions) || !p.source.assumptions.every((assumption) => typeof assumption === "string") || !p.measurements.length)
1749
- throw new Error("invalid gas benchmark profile");
1750
- if (p.source.fingerprints && ![
1751
- "protocolSourceSha256",
1752
- "dirtyDiffSha256",
1753
- "compiledArtifactsSha256",
1754
- "creditManifestSha256",
1755
- "userManifestSha256",
1756
- "sdkSourceSha256"
1757
- ].every((key) => {
1758
- const v = p.source.fingerprints[key];
1759
- return typeof v === "string" && /^[a-f0-9]{64}$/i.test(v);
1760
- }))
1761
- throw new Error("invalid benchmark source fingerprint");
1762
- if (p.source.blockGasLimit !== void 0 && (!decimal.test(p.source.blockGasLimit) || BigInt(p.source.blockGasLimit) <= 0n))
1763
- throw new Error("invalid benchmark block gas limit");
1764
- if (p.source.runtimeContracts && !Object.values(p.source.runtimeContracts).every(
1765
- (v) => address.test(v.address) && word.test(v.runtimeCodeHash)
1766
- ))
1767
- throw new Error("invalid benchmark runtime identity");
1768
- if (p.source.toolchain && (!["solidity", "barretenberg", "noir", "evmVersion", "anvil"].every((key) => {
1769
- const v = p.source.toolchain[key];
1770
- return typeof v === "string" && v.length > 0;
1771
- }) || !Number.isSafeInteger(p.source.toolchain.optimizerRuns) || p.source.toolchain.optimizerRuns < 0))
1772
- throw new Error("invalid benchmark toolchain");
1773
- for (const m of p.measurements) {
1774
- if (!m.id || !m.samples.length || !["none", "caller", "signature"].includes(m.shape.funding) || typeof m.shape.permit !== "boolean")
1775
- throw new Error("invalid gas benchmark measurement");
1776
- for (const key of shapeKeys) {
1777
- const value = m.shape[key];
1778
- if (!["kind", "target", "funding", "permit"].includes(key) && (!Number.isSafeInteger(value) || Number(value) < 0))
1779
- throw new Error("invalid gas benchmark shape");
1780
- }
1781
- if (m.circuit && (![m.circuit.artifactSha256, m.circuit.vkSha256].every(
1782
- (hash2) => /^[a-f0-9]{64}$/i.test(hash2)
1783
- ) || !m.circuit.circuitName || !m.circuit.target))
1784
- throw new Error("invalid gas benchmark circuit identity");
1785
- const hashes = /* @__PURE__ */ new Set();
1786
- for (const sample of m.samples) {
1787
- if (typeof sample.gasUsed !== "string" || !decimal.test(sample.gasUsed) || BigInt(sample.gasUsed) <= 0n || !word.test(sample.transactionHash) || !word.test(sample.blockHash) || !decimal.test(sample.blockNumber) || !Number.isSafeInteger(sample.calldataBytes) || sample.calldataBytes < 0 || hashes.has(sample.transactionHash.toLowerCase()))
1788
- throw new Error("invalid gas benchmark receipt");
1789
- hashes.add(sample.transactionHash.toLowerCase());
1790
- }
1791
- }
1792
- }
1793
- return copy;
1794
- }
1795
- function defineGasBenchmarks(input) {
1796
- if (!Array.isArray(input)) throw new Error("invalid gas benchmark catalog");
1797
- try {
1798
- return copyGasBenchmarks(input);
1799
- } catch {
1800
- throw new Error("invalid gas benchmark catalog");
1801
- }
1802
- }
1803
- var defaultProfiles = defineGasBenchmarks(gas_benchmarks_default);
1804
- function sameDeployment(a, b) {
1805
- return a.chainId === b.chainId && a.protocolAddress.toLowerCase() === b.protocolAddress.toLowerCase() && a.tokenAddress.toLowerCase() === b.tokenAddress.toLowerCase() && a.runtimeCodeHash?.toLowerCase() === b.runtimeCodeHash?.toLowerCase();
1806
- }
1807
- function sameCircuit(a, b) {
1808
- return a === null ? b === null : b !== null && a.circuitName === b.circuitName && a.target === b.target && a.artifactSha256.toLowerCase() === b.artifactSha256.toLowerCase() && a.vkSha256.toLowerCase() === b.vkSha256.toLowerCase();
1809
- }
1810
- function estimateBenchmarkGas(plan, protocol, profiles) {
1811
- const credit = plan.credit;
1812
- const deliveries = credit?.deliveries ?? plan.outputs.map((out) => out.delivery);
1813
- const request = {
1814
- deployment: {
1815
- chainId: plan.context.chainId.toString(),
1816
- protocolAddress: plan.context.protocolAddress,
1817
- runtimeCodeHash: protocol.expectedRuntimeCodeHash ?? null,
1818
- tokenAddress: plan.context.tokenAddress
1819
- },
1820
- shape: {
1821
- kind: plan.kind,
1822
- target: plan.statement?.target ?? "evm",
1823
- capacity: plan.capacity ?? 0,
1824
- noteInputs: plan.inputs.length,
1825
- noteOutputs: plan.outputs.length,
1826
- sourceTrees: operationSources(plan).length,
1827
- creditInputs: credit?.inputs.length ?? 0,
1828
- creditOutputs: credit?.outputs.length ?? 0,
1829
- creditRemainders: credit?.draw?.remainderCommitments.filter((hash2) => BigInt(hash2) !== 0n).length ?? 0,
1830
- funding: plan.fundingMode,
1831
- permit: (plan.funding.permit?.deadline ?? 0n) !== 0n,
1832
- deliveryBytes: deliveries.reduce(
1833
- (sum, d) => sum + (d.ciphertext.length - 2) / 2 + (d.clue.length - 2) / 2,
1834
- 0
1835
- )
1836
- },
1837
- circuit: plan.statement ? {
1838
- circuitName: plan.statement.circuitName,
1839
- target: plan.statement.target,
1840
- artifactSha256: plan.statement.artifactSha256,
1841
- vkSha256: plan.statement.vkSha256
1842
- } : null
1843
- };
1844
- const base = { source: "benchmark", request };
1845
- if (request.shape.target === "noir-recursive")
1846
- return { ...base, available: false, reason: "recursive-member-only" };
1847
- const candidates = (profiles ?? defaultProfiles).filter(
1848
- (p) => sameDeployment(p.deployment, request.deployment)
1849
- );
1850
- if (!request.deployment.runtimeCodeHash || !candidates.length)
1851
- return { ...base, available: false, reason: "deployment-not-covered" };
1852
- const exact = candidates.flatMap(
1853
- (profile) => profile.measurements.filter(
1854
- (m) => shapeKeys.every((key) => m.shape[key] === request.shape[key]) && sameCircuit(m.circuit, request.circuit)
1855
- ).map((measurement) => ({ profile, measurement }))
1856
- );
1857
- const mean = (measurement) => {
1858
- const count = BigInt(measurement.samples.length);
1859
- return (measurement.samples.reduce((sum, s) => sum + BigInt(s.gasUsed), 0n) + count - 1n) / count;
1860
- };
1861
- exact.sort(
1862
- (a, b) => mean(a.measurement) > mean(b.measurement) ? -1 : mean(a.measurement) < mean(b.measurement) ? 1 : a.measurement.id.localeCompare(b.measurement.id)
1863
- );
1864
- if (exact.length) {
1865
- const { profile, measurement } = exact[0];
1866
- const gas = measurement.samples.map((sample) => BigInt(sample.gasUsed));
1867
- const count = BigInt(gas.length);
1868
- return {
1869
- ...base,
1870
- available: true,
1871
- gasUnits: (gas.reduce((sum, value) => sum + value, 0n) + count - 1n) / count,
1872
- range: {
1873
- min: gas.reduce((a, b) => a < b ? a : b),
1874
- max: gas.reduce((a, b) => a > b ? a : b),
1875
- kind: "observed"
1876
- },
1877
- samples: gas.length,
1878
- profileId: profile.id,
1879
- measurementId: measurement.id,
1880
- evidence: structuredClone(profile.source)
1881
- };
1882
- }
1883
- return { ...base, available: false, reason: "shape-not-covered" };
1884
- }
1885
- function estimateShapeGas(request, profiles = defaultProfiles) {
1886
- if (request.shape.target === "noir-recursive") {
1887
- throw new Error(
1888
- "Estimate gas for the complete aggregate, not an individual recursive member"
1889
- );
1890
- }
1891
- const measurements = profiles.flatMap((profile) => profile.measurements);
1892
- const matching = measurements.filter(
1893
- (measurement) => measurement.shape.kind === request.shape.kind && measurement.shape.target === request.shape.target && sameCircuit(measurement.circuit, request.circuit)
1894
- );
1895
- const exact = matching.filter(
1896
- (measurement) => shapeKeys.every((key) => measurement.shape[key] === request.shape[key])
1897
- );
1898
- if (exact.length) {
1899
- const means = exact.map((m) => {
1900
- const count = BigInt(m.samples.length);
1901
- return (m.samples.reduce((sum, s) => sum + BigInt(s.gasUsed), 0n) + count - 1n) / count;
1902
- });
1903
- return { gasUnits: means.reduce((max, v) => v > max ? v : max) };
1904
- }
1905
- if (["create-credit", "draw-credit", "top-up-credit", "cancel-credit"].includes(
1906
- request.shape.kind
1907
- ) && !matching.length)
1908
- throw new Error("No current Credit gas reference for this artifact and verification key");
1909
- const candidates = matching.length ? matching : measurements.filter(
1910
- (measurement) => measurement.shape.kind === request.shape.kind && measurement.shape.target === request.shape.target
1911
- );
1912
- if (!candidates.length) throw new Error("No gas reference for this operation kind and target");
1913
- const dimensions = [
1914
- "noteInputs",
1915
- "noteOutputs",
1916
- "sourceTrees",
1917
- "creditInputs",
1918
- "creditOutputs",
1919
- "creditRemainders",
1920
- "deliveryBytes",
1921
- ...!matching.length ? ["capacity"] : []
1922
- ];
1923
- const groups = /* @__PURE__ */ new Map();
1924
- for (const candidate of candidates) {
1925
- const key = JSON.stringify([
1926
- shapeKeys.map((k) => candidate.shape[k]),
1927
- candidate.circuit?.circuitName,
1928
- candidate.circuit?.target,
1929
- candidate.circuit?.artifactSha256.toLowerCase(),
1930
- candidate.circuit?.vkSha256.toLowerCase()
1931
- ]);
1932
- const previous = groups.get(key);
1933
- groups.set(
1934
- key,
1935
- previous ? { ...candidate, samples: [...previous.samples, ...candidate.samples] } : candidate
1936
- );
1937
- }
1938
- const estimates = [...groups.values()].map((measurement) => {
1939
- let numerator = 1n;
1940
- let denominator = 1n;
1941
- for (const key of dimensions) {
1942
- const current2 = BigInt(request.shape[key]) + 1n;
1943
- const baseline = BigInt(measurement.shape[key]) + 1n;
1944
- if (current2 * denominator > numerator * baseline) {
1945
- numerator = current2;
1946
- denominator = baseline;
1947
- }
1948
- }
1949
- let gas = measurement.samples.reduce(
1950
- (max, sample) => BigInt(sample.gasUsed) > max ? BigInt(sample.gasUsed) : max,
1951
- 0n
1952
- );
1953
- gas = (gas * numerator + denominator - 1n) / denominator;
1954
- if (request.shape.funding === "signature" && measurement.shape.funding !== "signature")
1955
- gas *= 2n;
1956
- if (request.shape.permit && !measurement.shape.permit) gas *= 2n;
1957
- return gas;
1958
- });
1959
- return { gasUnits: estimates.reduce((min, gas) => gas < min ? gas : min) };
1960
- }
1961
- function estimateGasReference(plan, protocol, profiles) {
1962
- const reference2 = estimateBenchmarkGas(plan, protocol, profiles);
1963
- if (reference2.available) return { gasUnits: reference2.gasUnits };
1964
- return estimateShapeGas(reference2.request);
1965
- }
1966
-
1967
- // src/session/protocol-events.ts
1968
- import { invisiProtocolAbi } from "@invisi-labs/protocol/contracts";
1969
- import { Interface } from "ethers";
1970
- var protocolInterface = new Interface(invisiProtocolAbi);
1971
- function decodeProtocolEvent(log) {
1972
- const decoded = protocolInterface.parseLog(log);
1973
- if (!decoded) throw new Error("Unknown protocol receipt event");
1974
- const encoded = protocolInterface.encodeEventLog(decoded.fragment, decoded.args);
1975
- if (encoded.data.toLowerCase() !== log.data.toLowerCase() || encoded.topics.length !== log.topics.length || encoded.topics.some(
1976
- (topic, index2) => topic.toLowerCase() !== log.topics[index2].toLowerCase()
1977
- ))
1978
- throw new Error("Noncanonical protocol receipt event");
1979
- const args = decoded.args.toObject(true);
1980
- for (const key of [
1981
- "tokens",
1982
- "commitments",
1983
- "nullifiers",
1984
- "outputCommitments",
1985
- "leafIndices",
1986
- "remainderLeafIndices"
1987
- ]) {
1988
- const values = decoded.args.getValue(key);
1989
- if (values) args[key] = values.toArray(true);
1990
- }
1991
- for (const key of ["sources", "deliveries"]) {
1992
- const values = decoded.args.getValue(key);
1993
- if (values) args[key] = values.map((value) => value.toObject(true));
1994
- }
1995
- const params = decoded.args.getValue("params");
1996
- if (params) {
1997
- const source = params.getValue("creation") ?? params;
1998
- const target = params.getValue("creation") ? args.params.creation : args.params;
1999
- for (const key of ["nullifiers", "remainderCommitments", "expiries", "recoveryAmounts"]) {
2000
- const values = source.getValue(key);
2001
- if (values) target[key] = values.toArray(true);
2002
- }
2003
- const sources = source.getValue("sources");
2004
- if (sources) target.sources = sources.map((value) => value.toObject(true));
2005
- }
2006
- return { eventName: decoded.name, args };
2007
- }
2008
-
2009
- // src/session/receipt-logs.ts
2010
- function readProtocolLogs(receipt, protocolAddress) {
2011
- if (receipt.status !== "success" || !/^0x[0-9a-fA-F]{64}$/.test(receipt.transactionHash) || typeof receipt.block.number !== "bigint" || receipt.block.number < 0n || !/^0x[0-9a-fA-F]{64}$/.test(receipt.block.hash))
2012
- throw new Error("Invalid canonical protocol receipt");
2013
- const seen = /* @__PURE__ */ new Set();
2014
- return receipt.logs.filter((log) => log.address.toLowerCase() === protocolAddress.toLowerCase()).map((log) => {
2015
- if (log.transactionHash.toLowerCase() !== receipt.transactionHash.toLowerCase() || !Number.isSafeInteger(log.logIndex) || log.logIndex < 0 || seen.has(log.logIndex))
2016
- throw new Error("Invalid canonical receipt log identity");
2017
- seen.add(log.logIndex);
2018
- const decoded = decodeProtocolEvent(log);
2019
- return {
2020
- address: log.address,
2021
- eventName: decoded.eventName,
2022
- args: decoded.args,
2023
- blockNumber: receipt.block.number,
2024
- blockHash: receipt.block.hash,
2025
- transactionHash: receipt.transactionHash.toLowerCase(),
2026
- logIndex: log.logIndex,
2027
- removed: false
2028
- };
2029
- }).sort((a, b) => a.logIndex - b.logIndex);
2030
- }
2031
-
2032
- // src/session/discovery.ts
2033
- import { MAX_CIPHERTEXT_BYTES } from "@invisi-labs/core";
2034
- import { isAddress } from "ethers";
2035
- import {
2036
- decodeAddress,
2037
- ReceivingAddress
2038
- } from "@invisi-labs/core";
2039
- import { normalizeOpaqueDelivery } from "@invisi-labs/protocol";
2040
- var EVENTS = /* @__PURE__ */ new Set([
2041
- "CommitmentsInserted",
2042
- "BatchOutputs",
2043
- "Shield",
2044
- "Transact",
2045
- "CrossTreeTransact",
2046
- "CreditCreated",
2047
- "CreditDraw",
2048
- "CreditToppedUp",
2049
- "CreditCancelled"
2050
- ]);
2051
- function check(ok, message) {
2052
- if (!ok) throw new Error(message);
2053
- }
2054
- function object(value) {
2055
- check(value && typeof value === "object" && !Array.isArray(value), "invalid event object");
2056
- return value;
2057
- }
2058
- function array(value) {
2059
- check(Array.isArray(value), "invalid event array");
2060
- check(
2061
- Array.from({ length: value.length }, (_, i) => i in value).every(Boolean),
2062
- "sparse event array"
2063
- );
2064
- return value;
2065
- }
2066
- function integer(value) {
2067
- check(
2068
- typeof value === "bigint" || typeof value === "number" && Number.isSafeInteger(value),
2069
- "invalid event integer"
2070
- );
2071
- const n = BigInt(value);
2072
- check(n >= 0n, "negative event integer");
2073
- return n;
2074
- }
2075
- function index(value) {
2076
- const n = integer(value);
2077
- check(n < 65536n, "invalid event leaf index");
2078
- return Number(n);
2079
- }
2080
- function hash(value) {
2081
- check(typeof value === "string" && /^0x[0-9a-fA-F]{64}$/.test(value), "invalid event hash");
2082
- return value.toLowerCase();
2083
- }
2084
- function contextCheck(context) {
2085
- check(context.chainId >= 0n && context.chainId < 1n << 64n, "invalid discovery chain");
2086
- check(
2087
- isAddress(context.protocolAddress) && BigInt(context.protocolAddress) !== 0n,
2088
- "invalid discovery instance/token"
2089
- );
2090
- }
2091
- var position = (tree, at) => `${tree}:${at}`;
2092
- function extractDeliveryCandidates(logs, context, confirmedThrough) {
2093
- contextCheck(context);
2094
- check(confirmedThrough >= 0n, "invalid confirmed height");
2095
- const relevant = logs.filter(
2096
- (log) => log.address.toLowerCase() === context.protocolAddress.toLowerCase() && EVENTS.has(log.eventName)
2097
- );
2098
- const insertions = /* @__PURE__ */ new Map();
2099
- const metadata = (log) => {
2100
- check(!log.removed, "discovery resync required after reorg");
2101
- check(
2102
- typeof log.blockNumber === "bigint" && log.blockNumber >= 0n && log.blockNumber <= confirmedThrough,
2103
- "event is not confirmed"
2104
- );
2105
- check(Number.isSafeInteger(log.logIndex) && log.logIndex >= 0, "invalid log position");
2106
- return {
2107
- blockNumber: log.blockNumber,
2108
- blockHash: hash(log.blockHash),
2109
- transactionHash: hash(log.transactionHash)
2110
- };
2111
- };
2112
- const insertionKey = (log, tree, at) => `${hash(log.transactionHash)}:${position(tree, at)}`;
2113
- for (const log of relevant) {
2114
- metadata(log);
2115
- if (log.eventName !== "CommitmentsInserted" && log.eventName !== "BatchOutputs") continue;
2116
- const a = object(log.args), tree = integer(a.treeId), start = index(a.startLeafIndex), leaves = array(a.commitments);
2117
- check(tree > 0n && tree < 1n << 64n, "invalid insertion tree");
2118
- check(start + leaves.length <= 65536, "insertion exceeds tree capacity");
2119
- for (const [i, leaf] of leaves.entries()) {
2120
- const key = insertionKey(log, tree, start + i), value = hash(leaf), previous = insertions.get(key);
2121
- check(!previous || previous === value, "conflicting insertion events");
2122
- insertions.set(key, value);
2123
- }
2124
- }
2125
- const results = /* @__PURE__ */ new Map();
2126
- const add = (log, tree, at, commitment, role, wire, token = log.args?.token ?? log.args?.params?.token ?? log.args?.params?.creation?.token) => {
2127
- check(tree > 0n && tree < 1n << 64n, "invalid output tree");
2128
- const inserted = insertions.get(insertionKey(log, tree, at));
2129
- check(inserted, "delivery has no matching canonical insertion");
2130
- if (commitment !== void 0)
2131
- check(hash(commitment) === inserted, "delivery commitment conflicts with insertion");
2132
- const delivery = normalizeOpaqueDelivery(wire, { allowEmpty: role === "funds" });
2133
- check(
2134
- typeof token === "string" && isAddress(token) && BigInt(token) !== 0n,
2135
- "invalid event token"
2136
- );
2137
- const value = {
2138
- tokenAddress: token,
2139
- treeId: tree,
2140
- leafIndex: at,
2141
- commitment: inserted,
2142
- role,
2143
- delivery,
2144
- ...metadata(log)
2145
- };
2146
- const key = `${insertionKey(log, tree, at)}:${role}`, previous = results.get(key);
2147
- check(
2148
- !previous || previous.tokenAddress.toLowerCase() === token.toLowerCase() && previous.delivery.ciphertext === delivery.ciphertext && previous.delivery.clue === delivery.clue && previous.blockHash === value.blockHash,
2149
- "conflicting delivery events"
2150
- );
2151
- results.set(key, value);
2152
- };
2153
- const creation = (log, a, fields) => {
2154
- const tree = integer(a.outputTreeId), leaves = array(a.leafIndices), ds = array(a.deliveries);
2155
- const change = hash(fields.changeCommitment), hasChange = BigInt(change) !== 0n;
2156
- check(
2157
- ds.length === 3 && leaves.length === (hasChange ? 2 : 1),
2158
- "invalid Credit creation delivery slots"
2159
- );
2160
- add(log, tree, index(leaves[0]), fields.creditCommitment, "owner", ds[0]);
2161
- add(log, tree, index(leaves[0]), fields.creditCommitment, "spender", ds[1]);
2162
- if (hasChange) add(log, tree, index(leaves[1]), change, "funds", ds[2]);
2163
- else normalizeOpaqueDelivery(ds[2], { empty: true });
2164
- };
2165
- for (const log of relevant) {
2166
- const a = object(log.args);
2167
- if (log.eventName === "Shield") {
2168
- const ds = array(a.deliveries), tree = integer(a.treeId), start = index(a.startLeafIndex);
2169
- check(start + ds.length <= 65536, "shield exceeds tree capacity");
2170
- ds.forEach((d, i) => add(log, tree, start + i, void 0, "funds", d));
2171
- } else if (log.eventName === "Transact" || log.eventName === "CrossTreeTransact") {
2172
- const cs = array(a.outputCommitments), ds = array(a.deliveries), leaves = array(a.leafIndices), tree = integer(a.outputTreeId);
2173
- check(
2174
- cs.length === ds.length && cs.length === leaves.length,
2175
- "invalid transact delivery slots"
2176
- );
2177
- cs.forEach((c, i) => add(log, tree, index(leaves[i]), c, "funds", ds[i]));
2178
- } else if (log.eventName === "BatchOutputs") {
2179
- const tokens = array(a.tokens);
2180
- const cs = array(a.commitments), tree = integer(a.treeId), start = index(a.startLeafIndex), packed = a.packedDeliveries;
2181
- check(
2182
- typeof packed === "string" && /^0x(?:[0-9a-fA-F]{2})*$/.test(packed),
2183
- "invalid packed deliveries"
2184
- );
2185
- check(tokens.length === cs.length, "batch token count mismatch");
2186
- check(start + cs.length <= 65536, "batch exceeds tree capacity");
2187
- let offset = 2;
2188
- cs.forEach((c, i) => {
2189
- check(offset + 4 <= packed.length, "truncated delivery length prefix");
2190
- const length = Number.parseInt(packed.slice(offset, offset + 4), 16);
2191
- offset += 4;
2192
- check(
2193
- length <= MAX_CIPHERTEXT_BYTES && offset + length * 2 + (length === 0 ? 0 : 136) <= packed.length,
2194
- "invalid packed delivery length"
2195
- );
2196
- const ciphertext = `0x${packed.slice(offset, offset + length * 2)}`;
2197
- offset += length * 2;
2198
- const clue = length === 0 ? "0x" : `0x${packed.slice(offset, offset + 136)}`;
2199
- if (length !== 0) offset += 136;
2200
- add(log, tree, start + i, c, "funds", { ciphertext, clue }, tokens[i]);
2201
- });
2202
- check(offset === packed.length, "trailing packed delivery bytes");
2203
- } else if (log.eventName === "CreditCreated") creation(log, a, a);
2204
- else if (log.eventName === "CreditToppedUp")
2205
- creation(log, a, object(object(a.params).creation));
2206
- else if (log.eventName === "CreditDraw") {
2207
- const p = object(a.params), cs = array(p.remainderCommitments), ds = array(a.deliveries), leaves = array(a.remainderLeafIndices), tree = integer(a.outputTreeId);
2208
- check(
2209
- ds.length === 2 * cs.length && leaves.length === cs.length,
2210
- "invalid draw delivery slots"
2211
- );
2212
- cs.forEach((c, i) => {
2213
- if (BigInt(hash(c)) === 0n) {
2214
- check(integer(leaves[i]) === 0n, "absent remainder has nonzero position");
2215
- normalizeOpaqueDelivery(ds[2 * i], { empty: true });
2216
- normalizeOpaqueDelivery(ds[2 * i + 1], { empty: true });
2217
- } else {
2218
- add(log, tree, index(leaves[i]), c, "owner", ds[2 * i]);
2219
- add(log, tree, index(leaves[i]), c, "spender", ds[2 * i + 1]);
2220
- }
2221
- });
2222
- }
2223
- }
2224
- return [...results.values()];
2225
- }
2226
- async function decryptCandidates(logs, options) {
2227
- contextCheck(options.context);
2228
- decodeAddress(ReceivingAddress.fromIdentity(options.viewing.ownerAddress).toString());
2229
- check(
2230
- !logs.some(
2231
- (log) => log.address.toLowerCase() === options.context.protocolAddress.toLowerCase() && log.removed
2232
- ),
2233
- "discovery resync required after reorg"
2234
- );
2235
- const candidates = extractDeliveryCandidates(logs, options.context, options.confirmedThrough);
2236
- const positions = /* @__PURE__ */ new Map();
2237
- const unique = /* @__PURE__ */ new Map();
2238
- for (const candidate of candidates) {
2239
- const key = position(candidate.treeId, candidate.leafIndex);
2240
- const previous = positions.get(key);
2241
- check(
2242
- !previous || previous.commitment === candidate.commitment && previous.blockHash === candidate.blockHash && previous.transactionHash === candidate.transactionHash && previous.tokenAddress.toLowerCase() === candidate.tokenAddress.toLowerCase(),
2243
- "conflicting canonical position"
2244
- );
2245
- positions.set(key, candidate);
2246
- unique.set(`${key}:${candidate.role}`, candidate);
2247
- }
2248
- const notes = [];
2249
- const credits = [];
2250
- for (const candidate of unique.values()) {
2251
- const { delivery, role, ...positionData } = candidate;
2252
- const context = {
2253
- chainId: options.context.chainId,
2254
- protocolAddress: BigInt(options.context.protocolAddress),
2255
- tokenAddress: BigInt(candidate.tokenAddress),
2256
- outputCommitment: candidate.commitment
2257
- };
2258
- try {
2259
- if (role === "funds") {
2260
- if (delivery.ciphertext === "0x") continue;
2261
- const note = await options.viewing.decryptNote(delivery.ciphertext, context);
2262
- notes.push({ ...positionData, note });
2263
- } else {
2264
- const state = await options.viewing.decryptCredit(delivery.ciphertext, {
2265
- ...context,
2266
- role
2267
- });
2268
- credits.push({ ...positionData, role, state });
2269
- }
2270
- } catch {
2271
- }
2272
- }
2273
- return { notes, credits };
2274
- }
2275
-
2276
- // src/session/DisclosureVerifier.ts
2277
- function check2(value, message) {
2278
- if (!value) throw new Error(message);
2279
- }
2280
- function reference(value) {
2281
- check2(/^0x[0-9a-fA-F]{64}$/.test(value.transactionHash), "invalid disclosure transaction hash");
2282
- check2(
2283
- typeof value.treeId === "bigint" && value.treeId > 0n && value.treeId < 1n << 64n,
2284
- "invalid disclosure tree ID"
2285
- );
2286
- check2(
2287
- Number.isSafeInteger(value.leafIndex) && value.leafIndex >= 0 && value.leafIndex < 65536,
2288
- "invalid disclosure leaf index"
2289
- );
2290
- check2(["funds", "owner", "spender"].includes(value.role), "invalid disclosure reference role");
2291
- return {
2292
- transactionHash: value.transactionHash.toLowerCase(),
2293
- treeId: value.treeId,
2294
- leafIndex: value.leafIndex,
2295
- role: value.role
2296
- };
2297
- }
2298
- var DisclosureVerifier = class {
2299
- #protocol;
2300
- #reader;
2301
- #confirmations;
2302
- constructor(options) {
2303
- const confirmations = options.confirmations ?? 1;
2304
- check2(
2305
- Number.isSafeInteger(confirmations) && confirmations >= 1,
2306
- "invalid disclosure confirmations"
2307
- );
2308
- this.#protocol = options.protocol;
2309
- this.#reader = "provider" in options ? new EthersChainReader(options.provider) : options.reader;
2310
- this.#confirmations = BigInt(confirmations);
2311
- Object.freeze(this);
2312
- }
2313
- async barrier(block) {
2314
- await this.#protocol.validateDeployment(this.#reader);
2315
- const canonical2 = await this.#reader.getBlock(block.number);
2316
- check2(
2317
- canonical2.number === block.number && canonical2.hash.toLowerCase() === block.hash.toLowerCase(),
2318
- "disclosure canonical block changed; reorg verification required"
2319
- );
2320
- const head = await this.#reader.getLatestBlockNumber();
2321
- check2(
2322
- head >= block.number && head - block.number + 1n >= this.#confirmations,
2323
- "insufficient disclosure confirmations"
2324
- );
2325
- check2(
2326
- await this.#reader.getChainId() === this.#protocol.context.chainId,
2327
- "disclosure chain changed during verification"
2328
- );
2329
- return head - block.number + 1n;
2330
- }
2331
- /** Resolve the exact inserted output and its delivery from a successful canonical receipt. */
2332
- async readOutput(value) {
2333
- const selected = reference(value);
2334
- await this.#protocol.validateDeployment(this.#reader);
2335
- const received = await this.#reader.getReceipt(selected.transactionHash);
2336
- check2(received, "disclosure transaction receipt is unavailable");
2337
- const receipt = structuredClone(received);
2338
- check2(receipt.status === "success", "disclosure requires a successful transaction receipt");
2339
- check2(
2340
- receipt.transactionHash.toLowerCase() === selected.transactionHash,
2341
- "disclosure receipt transaction mismatch"
2342
- );
2343
- check2(
2344
- typeof receipt.block.number === "bigint" && receipt.block.number >= 0n && /^0x[0-9a-fA-F]{64}$/.test(receipt.block.hash),
2345
- "invalid disclosure receipt block"
2346
- );
2347
- const { context } = this.#protocol;
2348
- const logs = readProtocolLogs(receipt, context.protocolAddress);
2349
- const candidates = extractDeliveryCandidates(logs, context, receipt.block.number).filter(
2350
- (candidate2) => candidate2.treeId === selected.treeId && candidate2.leafIndex === selected.leafIndex && candidate2.role === selected.role && candidate2.tokenAddress.toLowerCase() === context.tokenAddress.toLowerCase()
2351
- );
2352
- check2(
2353
- candidates.length === 1,
2354
- "disclosure output has no unique canonical insertion and delivery"
2355
- );
2356
- const candidate = candidates[0];
2357
- const confirmations = await this.barrier(receipt.block);
2358
- return Object.freeze({
2359
- reference: Object.freeze(selected),
2360
- block: Object.freeze({ ...receipt.block }),
2361
- confirmations,
2362
- output: Object.freeze({
2363
- chainId: context.chainId,
2364
- protocolAddress: BigInt(context.protocolAddress),
2365
- tokenAddress: BigInt(context.tokenAddress),
2366
- outputCommitment: candidate.commitment,
2367
- role: selected.role,
2368
- ciphertext: candidate.delivery.ciphertext
2369
- })
2370
- });
2371
- }
2372
- async verify(disclosure, value) {
2373
- const evidence = await this.readOutput(value);
2374
- const result = await disclosure.verify(evidence.output);
2375
- const confirmations = await this.barrier(evidence.block);
2376
- return Object.freeze({
2377
- result: Object.freeze(result),
2378
- block: evidence.block,
2379
- confirmations,
2380
- output: Object.freeze({
2381
- ...evidence.reference,
2382
- commitment: evidence.output.outputCommitment
2383
- })
2384
- });
2385
- }
2386
- toJSON() {
2387
- return { disclosureVerifier: true, confirmations: this.#confirmations.toString() };
2388
- }
2389
- [/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
2390
- return this.toJSON();
2391
- }
2392
- };
2393
-
2394
- // src/session/store.ts
2395
- import { FIELD_MODULUS, normalizeCreditDeliveryState } from "@invisi-labs/core";
2396
- import { sha256 } from "@noble/hashes/sha256";
2397
- import { bytesToHex, utf8ToBytes } from "@noble/hashes/utils";
2398
- function scopeKey(scope) {
2399
- if (typeof scope.namespace !== "string" || !scope.namespace.length || scope.namespace.length > 256)
2400
- throw new Error("invalid wallet namespace");
2401
- if (typeof scope.chainId !== "bigint" || scope.chainId < 0n || scope.chainId >= 1n << 64n)
2402
- throw new Error("invalid scope chain");
2403
- for (const address2 of [scope.protocolAddress])
2404
- if (!/^0x[0-9a-fA-F]{40}$/.test(address2) || BigInt(address2) === 0n)
2405
- throw new Error("invalid scope deployment");
2406
- if (!/^0x[0-9a-fA-F]{40}$/.test(scope.ownerAddress) || BigInt(scope.ownerAddress) <= 0n || BigInt(scope.ownerAddress) >= 1n << 160n)
2407
- throw new Error("invalid scope wallet");
2408
- return bytesToHex(
2409
- sha256(
2410
- utf8ToBytes(
2411
- "Invisi.WalletScope.v1:" + JSON.stringify([
2412
- scope.namespace,
2413
- scope.chainId.toString(),
2414
- scope.protocolAddress.toLowerCase(),
2415
- scope.ownerAddress.toLowerCase()
2416
- ])
2417
- )
2418
- )
2419
- );
2420
- }
2421
- function initialState(scope) {
2422
- scopeKey(scope);
2423
- return {
2424
- schemaVersion: 1,
2425
- scope: { ...scope },
2426
- revision: 0,
2427
- notes: {},
2428
- credits: {},
2429
- reservations: {},
2430
- operations: {}
2431
- };
2432
- }
2433
- function validateState(state, scope, revision) {
2434
- if (!state || state.schemaVersion !== 1 || scopeKey(state.scope) !== scopeKey(scope) || state.revision !== revision)
2435
- throw new Error("wallet state scope/schema/revision mismatch");
2436
- if (!Number.isSafeInteger(revision) || revision < 0)
2437
- throw new Error("invalid wallet state revision");
2438
- for (const field of [state.notes, state.credits, state.reservations, state.operations])
2439
- if (!field || typeof field !== "object" || Array.isArray(field))
2440
- throw new Error("invalid wallet state records");
2441
- for (const record of Object.values(state.notes)) {
2442
- if (typeof record.note.tokenAddress !== "bigint" || record.note.tokenAddress <= 0n || record.note.tokenAddress >= 1n << 160n || record.note.chainId !== scope.chainId || record.note.protocolAddress !== BigInt(scope.protocolAddress) || record.note.ownerAddress.toLowerCase() !== scope.ownerAddress.toLowerCase() || typeof record.note.amount !== "bigint" || record.note.amount <= 0n || record.note.amount >= 1n << 128n)
2443
- throw new Error("invalid stored note context or amount");
2444
- if (!["unspent", "unknown", "spent"].includes(record.spent))
2445
- throw new Error("invalid spent state");
2446
- }
2447
- for (const record of Object.values(state.credits)) {
2448
- const note = normalizeCreditDeliveryState(record.state).note;
2449
- if (note.chainId !== scope.chainId || note.protocolAddress !== BigInt(scope.protocolAddress) || !["owner", "spender"].includes(record.role) || (record.role === "owner" ? note.ownerWalletIdentity : note.spenderWalletIdentity).toLowerCase() !== scope.ownerAddress.toLowerCase() || !["unspent", "unknown", "spent"].includes(record.spent))
2450
- throw new Error("invalid stored Credit context or role");
2451
- }
2452
- for (const record of [...Object.values(state.notes), ...Object.values(state.credits)]) {
2453
- if (!/^0x[0-9a-fA-F]{64}$/.test(record.commitment) || BigInt(record.commitment) <= 0n || BigInt(record.commitment) >= FIELD_MODULUS || typeof record.treeId !== "bigint" || record.treeId < 1n || record.treeId >= 1n << 64n || !Number.isInteger(record.leafIndex) || record.leafIndex < 0 || record.leafIndex >= 65536 || typeof record.blockNumber !== "bigint" || record.blockNumber < 0n || !/^0x[0-9a-fA-F]{64}$/.test(record.blockHash))
2454
- throw new Error("invalid stored receipt position");
2455
- }
2456
- for (const [id, operation] of Object.entries(state.reservations))
2457
- if (!state.operations[operation] || !state.notes[id] && !Object.values(state.credits).some(
2458
- (record) => creditReservationKey(record.commitment) === id
2459
- ) && !["submitted", "uncertain", "reorged"].includes(
2460
- state.operations[operation].status
2461
- ))
2462
- throw new Error("orphan input reservation");
2463
- }
2464
- var TransactionalWalletStore = class {
2465
- persistent;
2466
- #records;
2467
- #codec;
2468
- constructor(records, codec, options) {
2469
- this.#records = records;
2470
- this.#codec = codec;
2471
- this.persistent = options.persistent;
2472
- }
2473
- async readSnapshot(scope) {
2474
- const key = scopeKey(scope), record = await this.#records.read(key);
2475
- if (!record) return initialState(scope);
2476
- const state = await this.#codec.decode(record.data, { key, revision: record.revision });
2477
- validateState(state, scope, record.revision);
2478
- return state;
2479
- }
2480
- async transaction(scope, action) {
2481
- if (action.constructor.name === "AsyncFunction")
2482
- throw new Error("wallet transaction action must be synchronous");
2483
- const copied = { ...scope }, key = scopeKey(copied);
2484
- for (let attempt = 0; attempt < 100; attempt++) {
2485
- const draft = await this.readSnapshot(copied), previous = draft.revision;
2486
- const result = action(draft);
2487
- if (result && typeof result === "object" && "then" in result) {
2488
- Promise.resolve(result).catch(() => {
2489
- });
2490
- throw new Error("wallet transaction action must be synchronous");
2491
- }
2492
- validateState(draft, copied, previous);
2493
- if (!Number.isSafeInteger(previous + 1))
2494
- throw new Error("wallet state revision exhausted");
2495
- draft.revision = previous + 1;
2496
- const data = await this.#codec.encode(draft, { key, revision: draft.revision });
2497
- if (await this.#records.compareAndSwap(key, previous, {
2498
- revision: draft.revision,
2499
- data
2500
- }))
2501
- return result;
2502
- }
2503
- throw new Error("wallet transaction contention limit exceeded");
2504
- }
2505
- toJSON() {
2506
- return { walletStore: true, persistent: this.persistent };
2507
- }
2508
- [/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
2509
- return this.toJSON();
2510
- }
2511
- };
2512
- var MemoryAtomicRecords = class {
2513
- #values = /* @__PURE__ */ new Map();
2514
- async read(key) {
2515
- const value = this.#values.get(key);
2516
- return value ? { revision: value.revision, data: Uint8Array.from(value.data) } : void 0;
2517
- }
2518
- async compareAndSwap(key, previousRevision, next) {
2519
- if ((this.#values.get(key)?.revision ?? 0) !== previousRevision) return false;
2520
- this.#values.set(key, { revision: next.revision, data: Uint8Array.from(next.data) });
2521
- return true;
2522
- }
2523
- };
2524
-
2525
- // src/session/operation-execution.ts
2526
- import { Signature, SigningKey, getBytes as getBytes2, concat, verifyTypedData } from "ethers";
2527
- import {
2528
- computeWalletAuthorizationDigest,
2529
- AuthorizedStatement,
2530
- computeOwnerAddress,
2531
- createSigningRequest,
2532
- walletAuthorizationTypedData
2533
- } from "@invisi-labs/core";
2534
- import { WitnessBuilder } from "@invisi-labs/protocol";
2535
-
2536
- // src/session/proof-integrity.ts
2537
- import { getBytes } from "ethers";
2538
- import { sha256 as sha2562 } from "@noble/hashes/sha256";
2539
- import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
2540
- function check3(ok, message) {
2541
- if (!ok) throw new Error(message);
2542
- }
2543
- function sameStatement(proof, expected) {
2544
- check3(
2545
- proof.formatVersion === 1 && proof.bbVersion === "6.0.0" && proof.circuitName === expected.circuitName && proof.target === expected.target && proof.artifactSha256 === expected.artifactSha256 && proof.vkSha256 === expected.vkSha256,
2546
- "proof release/target mismatch"
2547
- );
2548
- check3(
2549
- proof.publicInputs.length === expected.expectedPublicInputs.length && proof.publicInputs.every((word2, i) => word2 === expected.expectedPublicInputs[i]),
2550
- "proof public statement mismatch"
2551
- );
2552
- check3(
2553
- /^0x(?:[a-fA-F0-9]{2})+$/.test(proof.proofHex) && bytesToHex2(sha2562(getBytes(proof.proofHex))) === proof.proofSha256,
2554
- "proof integrity mismatch"
2555
- );
2556
- }
2557
-
2558
- // src/session/operation-execution.ts
2559
- async function authorizeOperation(plan, provider) {
2560
- if (provider.ownerAddress !== plan.scope.ownerAddress)
2561
- throw new Error("wallet authorization capability mismatch");
2562
- const request = authorizationRequest(plan);
2563
- const digest = computeWalletAuthorizationDigest(request);
2564
- const signed = await provider.authorize(structuredClone(request));
2565
- if (signed.ownerAddress !== plan.scope.ownerAddress || signed.digest !== digest)
2566
- throw new Error("wallet authorization statement mismatch");
2567
- return signed;
2568
- }
2569
- async function proveOperation(protocol, plan, authorization, prover, options) {
2570
- if (Object.hasOwn(options, "target")) {
2571
- throw new Error("prove accepts execution, not a backend target");
2572
- }
2573
- const { execution = "single", ...proverOptions } = options;
2574
- if (execution !== "single" && execution !== "aggregate") {
2575
- throw new Error("execution must be single or aggregate");
2576
- }
2577
- const frozen = statement(plan);
2578
- if (execution === "aggregate" && (plan.kind !== "transfer" || plan.capacity !== 14)) {
2579
- throw new Error("aggregate execution requires a 14-slot transfer");
2580
- }
2581
- if (plan.kind === "transfer") {
2582
- plan.statement = WitnessBuilder.statement(
2583
- frozen.circuitName,
2584
- frozen.expectedPublicInputs,
2585
- execution === "aggregate" ? "noir-recursive" : "evm"
2586
- );
2587
- }
2588
- const request = await witnessFor(protocol, plan, authorization);
2589
- if (JSON.stringify({ ...request, witness: void 0 }) !== JSON.stringify(plan.statement))
2590
- throw new Error("prepared proof statement changed");
2591
- try {
2592
- const proof = publicProof(await prover.prove(request, proverOptions));
2593
- sameStatement(proof, plan.statement);
2594
- if (await prover.verify(
2595
- structuredClone(proof),
2596
- structuredClone(plan.statement),
2597
- proverOptions
2598
- ) !== true)
2599
- throw new Error("proof verification failed");
2600
- return proof;
2601
- } catch {
2602
- options.signal?.throwIfAborted();
2603
- throw new Error("operation proof generation or verification failed");
2604
- }
2605
- }
2606
- async function signOperationFunding(saved, signer, verifier) {
2607
- const payer = saved.plan.funding.payer;
2608
- if (signer.address.toLowerCase() !== payer.toLowerCase())
2609
- throw new Error("funding signer is not the payer");
2610
- const typed = await fundingTypedData(saved);
2611
- const signature = await signer.signTypedData(structuredClone(typed));
2612
- return verifyFundingSignature(typed, payer, signature, verifier);
2613
- }
2614
- function walletSigningRequest(plan) {
2615
- return createSigningRequest(walletAuthorizationTypedData(authorizationRequest(plan)));
2616
- }
2617
- async function acceptWalletSignature(plan, signature) {
2618
- const request = authorizationRequest(plan);
2619
- const digest = computeWalletAuthorizationDigest(request);
2620
- try {
2621
- const signed = Signature.from(signature);
2622
- const publicKey = getBytes2(SigningKey.recoverPublicKey(digest, signed));
2623
- const owner = await computeOwnerAddress(publicKey);
2624
- if (owner.toLowerCase() !== plan.scope.ownerAddress.toLowerCase()) {
2625
- throw new Error("wallet signature identity mismatch");
2626
- }
2627
- return new AuthorizedStatement(plan.scope.ownerAddress, digest, {
2628
- public_key_x: Array.from(publicKey.slice(1, 33)),
2629
- public_key_y: Array.from(publicKey.slice(33)),
2630
- signature: Array.from(getBytes2(concat([signed.r, signed.s])))
2631
- });
2632
- } catch {
2633
- throw new Error("invalid wallet authorization signature");
2634
- }
2635
- }
2636
- async function fundingSigningRequest(saved, runtime) {
2637
- const plan = saved.plan;
2638
- if (plan.fundingMode !== "signature") {
2639
- throw new Error("operation does not require a funding signature");
2640
- }
2641
- if (plan.kind !== "shield" && !saved.proof) {
2642
- throw new Error("proof must precede funding authorization");
2643
- }
2644
- await runtime.options.protocol.validateDeployment(runtime.reader);
2645
- const block = await runtime.reader.getBlock(await runtime.reader.getLatestBlockNumber());
2646
- if (block.timestamp > plan.deadline || block.timestamp > (plan.funding.deadline ?? 0n)) {
2647
- throw new Error("funding authorization expired");
2648
- }
2649
- if (await runtime.reader.getFundingNonce(plan.context, plan.funding.payer, block) !== plan.funding.sigNonce) {
2650
- throw new Error("funding nonce changed; prepare again");
2651
- }
2652
- const request = createSigningRequest(await fundingTypedData(saved));
2653
- if ((await runtime.reader.getBlock(block.number)).hash !== block.hash) {
2654
- throw new Error("canonical funding block changed");
2655
- }
2656
- return request;
2657
- }
2658
- async function acceptFundingSignature(saved, signature, runtime) {
2659
- if (!/^0x(?:[a-fA-F0-9]{2})+$/.test(signature)) {
2660
- throw new Error("invalid EVM funding signature");
2661
- }
2662
- const request = await fundingSigningRequest(saved, runtime);
2663
- return verifyFundingSignature(
2664
- request,
2665
- saved.plan.funding.payer,
2666
- signature,
2667
- runtime.options.fundingVerifier
2668
- );
2669
- }
2670
- async function verifyFundingSignature(request, payer, signature, verifier) {
2671
- if (!/^0x(?:[a-fA-F0-9]{2})+$/.test(signature)) {
2672
- throw new Error("invalid EVM funding signature");
2673
- }
2674
- const types = Object.fromEntries(
2675
- Object.entries(request.types).map(([name, fields]) => [name, [...fields]])
2676
- );
2677
- let validEOA = false;
2678
- try {
2679
- validEOA = verifyTypedData(request.domain, types, request.message, signature).toLowerCase() === payer.toLowerCase();
2680
- if (validEOA) {
2681
- signature = Signature.from(signature).serialized;
2682
- }
2683
- } catch {
2684
- validEOA = false;
2685
- }
2686
- const valid = verifier ? await verifier.verifyTypedData({
2687
- ...structuredClone(request),
2688
- address: payer,
2689
- signature
2690
- }) : validEOA;
2691
- if (valid !== true) {
2692
- throw new Error("invalid EVM funding signature");
2693
- }
2694
- return signature;
2695
- }
2696
-
2697
- // src/session/operation-preview.ts
2698
- import { normalizeFunding } from "@invisi-labs/protocol";
2699
- function operationPreview(plan, status) {
2700
- const p = plan;
2701
- const fee = p.params ?? p.shieldParams ?? p.credit?.creation ?? p.credit?.cancel;
2702
- const funding = normalizeFunding(p.funding);
2703
- return {
2704
- id: p.id,
2705
- kind: p.kind,
2706
- status,
2707
- context: { ...p.context },
2708
- inputs: inputFacts(p).length,
2709
- inputDetails: [
2710
- ...p.inputs.map((input) => ({
2711
- kind: "notes",
2712
- commitment: input.commitment,
2713
- amount: input.note.amount,
2714
- owner: input.note.ownerAddress,
2715
- treeId: input.treeId,
2716
- leafIndex: input.leafIndex
2717
- })),
2718
- ...(p.credit?.inputs ?? []).map((input) => ({
2719
- kind: "credits",
2720
- commitment: input.commitment,
2721
- amount: input.state.note.amount,
2722
- owner: input.state.note.ownerWalletIdentity,
2723
- spender: input.state.note.spenderWalletIdentity,
2724
- expiry: input.state.note.expiry,
2725
- role: input.role,
2726
- treeId: input.treeId,
2727
- leafIndex: input.leafIndex
2728
- }))
2729
- ],
2730
- funding: {
2731
- payer: funding.payer,
2732
- amount: funding.amount,
2733
- authorization: p.fundingMode,
2734
- sigNonce: funding.sigNonce,
2735
- deadline: funding.deadline,
2736
- permit: { deadline: funding.permit.deadline }
2737
- },
2738
- creditOutputs: p.credit?.outputs.map((output) => ({
2739
- commitment: output.commitment,
2740
- amount: output.state.note.amount,
2741
- expiry: output.state.note.expiry,
2742
- owner: output.state.note.ownerWalletIdentity,
2743
- spender: output.state.note.spenderWalletIdentity,
2744
- ownerPayout: output.state.note.ownerPayout,
2745
- spenderPayout: output.state.note.spenderPayout
2746
- })),
2747
- outputs: p.outputs.map((output) => ({
2748
- commitment: output.commitment,
2749
- to: output.address,
2750
- amount: output.amount,
2751
- change: output.change
2752
- })),
2753
- capacity: p.capacity,
2754
- deadline: p.deadline,
2755
- feeRecipient: fee?.feeRecipient,
2756
- feeAmount: fee?.feeAmount ?? 0n,
2757
- fundingAmount: p.funding.amount ?? 0n,
2758
- fundingPayer: p.funding.payer,
2759
- withdrawalAmount: p.params?.withdrawalAmount ?? p.credit?.draw?.totalAmount ?? (p.credit?.cancel ? p.credit.cancel.amount - (p.credit.cancel.feeAmount ?? 0n) : void 0) ?? 0n,
2760
- withdrawalAddress: p.params?.withdrawalAddress ?? p.credit?.draw?.spender ?? p.credit?.cancel?.owner,
2761
- permissions: {
2762
- walletAuthorization: requiresAuthorization(p),
2763
- proof: p.kind !== "shield",
2764
- fundingAuthorization: p.fundingMode === "signature"
2765
- }
2766
- };
2767
- }
2768
-
2769
- // src/session/Operation.ts
2770
- import { MissingCapabilityError } from "@invisi-labs/core";
2771
- import { normalizeFunding as normalizeFunding2 } from "@invisi-labs/protocol";
2772
-
2773
- // src/session/operation-confirmation.ts
2774
- import { computeCreditNullifier } from "@invisi-labs/core";
2775
-
2776
- // src/session/aggregate-receipt.ts
2777
- import { Interface as Interface2 } from "ethers";
2778
- import { invisiProtocolAbi as invisiProtocolAbi2 } from "@invisi-labs/protocol/contracts";
2779
- import { buildTransactCalldata } from "@invisi-labs/protocol";
2780
- var aggregateAbi = invisiProtocolAbi2.filter(
2781
- (item) => item.type === "function" && item.name === "transact" && item.inputs.length === 2 && item.inputs[1]?.type === "tuple[]"
2782
- );
2783
- function matchesAggregateTransaction(saved, transaction) {
2784
- const plan = saved.plan;
2785
- if (plan.statement?.target !== "noir-recursive" || !plan.params || !saved.externalized || transaction.to.toLowerCase() !== plan.context.protocolAddress.toLowerCase() || transaction.value !== 0n)
2786
- return false;
2787
- try {
2788
- const decoded = new Interface2(aggregateAbi).parseTransaction({ data: transaction.data }), requests = decoded.args[1].map((request) => {
2789
- const member = request.toObject(true);
2790
- member.params.sources = request.params.sources.map(
2791
- (source) => source.toObject(true)
2792
- );
2793
- member.params.nullifiers = request.params.nullifiers.toArray(true);
2794
- member.params.outputCommitments = request.params.outputCommitments.toArray(true);
2795
- member.deliveries = request.deliveries.map(
2796
- (delivery) => delivery.toObject(true)
2797
- );
2798
- member.funding.permit.v = Number(member.funding.permit.v);
2799
- return {
2800
- params: member.params,
2801
- deliveries: member.deliveries,
2802
- funding: member.funding
2803
- };
2804
- });
2805
- if (decoded.name !== "transact" || !Array.isArray(requests) || ![4, 8, 12].includes(requests.length))
2806
- return false;
2807
- const canonical2 = (request) => buildTransactCalldata({
2808
- context: { ...plan.context, tokenAddress: request.params.token },
2809
- proof: "0x00",
2810
- params: request.params,
2811
- deliveries: request.deliveries,
2812
- funding: request.funding,
2813
- caller: transaction.from
2814
- }).data.toLowerCase();
2815
- const expected = buildTransactCalldata({
2816
- context: plan.context,
2817
- proof: "0x00",
2818
- params: plan.params,
2819
- deliveries: plan.outputs.map((output) => output.delivery),
2820
- funding: plan.funding,
2821
- caller: transaction.from
2822
- }).data.toLowerCase();
2823
- return requests.filter((request) => canonical2(request) === expected).length === 1;
2824
- } catch {
2825
- return false;
2826
- }
2827
- }
2828
-
2829
- // src/session/receipts.ts
2830
- function canonical(value) {
2831
- return JSON.stringify(value, (_, item) => {
2832
- if (typeof item === "bigint") {
2833
- return ["bigint", item.toString()];
2834
- }
2835
- if (item instanceof Uint8Array) {
2836
- return Array.from(item);
2837
- }
2838
- if (item && typeof item === "object" && !Array.isArray(item)) {
2839
- return Object.fromEntries(
2840
- Object.keys(item).sort().map((key) => [key, item[key]])
2841
- );
2842
- }
2843
- return item;
2844
- });
2845
- }
2846
- function validateInheritance(state, record) {
2847
- const source = record.receivingKeySource;
2848
- if (!source) return false;
2849
- const parent = state.credits[source.commitment + ":" + record.role];
2850
- if (!parent) {
2851
- throw new Error("Credit receiving inheritance has no authenticated parent");
2852
- }
2853
- const previous = parent.state;
2854
- const successor = record.state;
2855
- const immutableFields = [
2856
- "chainId",
2857
- "protocolAddress",
2858
- "tokenAddress",
2859
- "spenderWalletIdentity",
2860
- "ownerWalletIdentity",
2861
- "spenderPayout",
2862
- "ownerPayout",
2863
- "creditSharedKey"
2864
- ];
2865
- if (immutableFields.some((field) => previous.note[field] !== successor.note[field]) || canonical(previous.ownerReceivingKeys) !== canonical(successor.ownerReceivingKeys) || canonical(previous.spenderReceivingKeys) !== canonical(successor.spenderReceivingKeys)) {
2866
- throw new Error("Credit receiving inheritance changed immutable fields");
2867
- }
2868
- if (source.kind === "draw") {
2869
- if (successor.note.amount >= previous.note.amount || successor.note.expiry !== previous.note.expiry) {
2870
- throw new Error("invalid Credit receiving inheritance");
2871
- }
2872
- } else if (source.kind !== "top-up" || successor.note.amount <= previous.note.amount || successor.note.expiry < previous.note.expiry) {
2873
- throw new Error("invalid Credit receiving inheritance");
2874
- }
2875
- return true;
2876
- }
2877
- function mergeSpentObservation(previous, incoming) {
2878
- const next = incoming.checkedThrough;
2879
- const old = previous.checkedThrough;
2880
- if (!next || incoming.spent === "unknown") {
2881
- return;
2882
- }
2883
- if (old && next.number < old.number) {
2884
- return;
2885
- }
2886
- if (old && next.number === old.number && next.hash !== old.hash) {
2887
- throw new Error("canonical spent checkpoint conflict requires resync");
2888
- }
2889
- if (previous.spent === "spent" && incoming.spent !== "spent") {
2890
- throw new Error("canonical spent observation conflict requires resync");
2891
- }
2892
- previous.spent = incoming.spent;
2893
- previous.checkedThrough = { ...next };
2894
- }
2895
- function mergeReceiptRecords(state, batch) {
2896
- if (state.invalidated) {
2897
- throw new Error("wallet inventory is invalidated");
2898
- }
2899
- const checkpoint = { ...batch.checkpoint };
2900
- for (const record of [...batch.notes, ...batch.credits]) {
2901
- if (record.blockNumber > checkpoint.number) {
2902
- throw new Error("receipt exceeds confirmed checkpoint");
2903
- }
2904
- const atPosition = [...Object.values(state.notes), ...Object.values(state.credits)].filter(
2905
- (existing) => existing.treeId === record.treeId && existing.leafIndex === record.leafIndex
2906
- );
2907
- if (atPosition.some(
2908
- (existing) => existing.commitment !== record.commitment || existing.blockHash !== record.blockHash
2909
- )) {
2910
- throw new Error("canonical position conflict requires resync");
2911
- }
2912
- if ("note" in record) {
2913
- const previous = state.notes[record.commitment];
2914
- if (previous) {
2915
- if (canonical(previous.note) !== canonical(record.note)) {
2916
- throw new Error("canonical note preimage conflict");
2917
- }
2918
- mergeSpentObservation(previous, record);
2919
- continue;
2920
- }
2921
- state.notes[record.commitment] = record;
2922
- } else {
2923
- const key = record.commitment + ":" + record.role;
2924
- const previous = state.credits[key];
2925
- const inherited = validateInheritance(state, record);
2926
- if (previous) {
2927
- if (canonical(previous.state.note) !== canonical(record.state.note)) {
2928
- throw new Error("canonical Credit preimage conflict");
2929
- }
2930
- if (canonical(previous.state) !== canonical(record.state)) {
2931
- if (!inherited) {
2932
- if (previous.receivingKeySource) {
2933
- mergeSpentObservation(previous, record);
2934
- continue;
2935
- }
2936
- throw new Error("Credit receiving metadata conflict");
2937
- }
2938
- previous.state = record.state;
2939
- previous.receivingKeySource = record.receivingKeySource;
2940
- } else if (inherited) {
2941
- previous.receivingKeySource = record.receivingKeySource;
2942
- }
2943
- mergeSpentObservation(previous, record);
2944
- continue;
2945
- }
2946
- state.credits[key] = record;
2947
- }
2948
- }
2949
- }
2950
-
2951
- // src/session/operation-confirmation.ts
2952
- function check4(ok, message) {
2953
- if (!ok) {
2954
- throw new Error(message);
2955
- }
2956
- }
2957
- async function barrier(runtime, state, block) {
2958
- const checkpoints = [
2959
- state.observedThrough,
2960
- ...block ? [{ number: block.number, hash: block.hash }] : []
2961
- ];
2962
- for (const point of checkpoints) {
2963
- if (point && (await runtime.reader.getBlock(point.number)).hash !== point.hash) {
2964
- await runtime.store.transaction(runtime.scope, (draft) => {
2965
- draft.invalidated = "Canonical operation checkpoint changed; full resync required";
2966
- for (const record of [
2967
- ...Object.values(draft.notes),
2968
- ...Object.values(draft.credits)
2969
- ]) {
2970
- record.spent = "unknown";
2971
- }
2972
- for (const operation of Object.values(draft.operations)) {
2973
- if (["failed", "expired"].includes(operation.status) && !operation.payload?.externalized) {
2974
- continue;
2975
- }
2976
- operation.status = "reorged";
2977
- for (const id of operation.inputs) {
2978
- if (!draft.reservations[id]) {
2979
- draft.reservations[id] = operation.id;
2980
- }
2981
- }
2982
- }
2983
- });
2984
- throw new Error("canonical operation checkpoint changed; full resync required");
2985
- }
2986
- }
2987
- }
2988
- function current(state, id, generation) {
2989
- check4(!state.invalidated, "wallet requires canonical resync");
2990
- const record = state.operations[id];
2991
- const saved = record?.payload;
2992
- check4(record && saved.generation === generation && !saved.claim, "stale operation recovery");
2993
- return { record, saved };
2994
- }
2995
- function observe(state, block) {
2996
- if (state.observedThrough?.number === block.number) {
2997
- check4(state.observedThrough.hash === block.hash, "operation checkpoint conflict");
2998
- }
2999
- if (!state.observedThrough || state.observedThrough.number < block.number) {
3000
- state.observedThrough = { number: block.number, hash: block.hash };
3001
- }
3002
- }
3003
- async function confirmOperation(runtime, id, generation, hash2, signal) {
3004
- const { reader, store, scope, options } = runtime;
3005
- const state = await store.readSnapshot(scope);
3006
- const { saved } = current(state, id, generation);
3007
- const plan = saved.plan;
3008
- await options.protocol.validateDeployment(reader);
3009
- await barrier(runtime, state);
3010
- const receipt = await reader.getReceipt(hash2);
3011
- if (!receipt) {
3012
- return void 0;
3013
- }
3014
- check4(receipt.transactionHash === hash2, "receipt transaction identity mismatch");
3015
- await barrier(runtime, state, receipt.block);
3016
- const transaction = await reader.getTransaction(hash2);
3017
- check4(
3018
- transaction && transaction.transactionHash === hash2,
3019
- "confirmed transaction differs from the frozen operation"
3020
- );
3021
- let matchesRequest;
3022
- if (plan.statement?.target === "noir-recursive") {
3023
- matchesRequest = matchesAggregateTransaction(saved, transaction);
3024
- } else {
3025
- matchesRequest = !!saved.call && transaction.to.toLowerCase() === saved.call.to.toLowerCase() && transaction.value === saved.call.value && transaction.data.toLowerCase() === saved.call.data.toLowerCase();
3026
- }
3027
- check4(matchesRequest, "confirmed transaction differs from the frozen operation");
3028
- check4(
3029
- receipt.status === "success" || receipt.status === "reverted",
3030
- "receipt execution status is missing"
3031
- );
3032
- if (receipt.status === "reverted") {
3033
- return void 0;
3034
- }
3035
- const candidates = extractDeliveryCandidates(
3036
- readProtocolLogs(receipt, plan.context.protocolAddress),
3037
- plan.context,
3038
- receipt.block.number
3039
- );
3040
- const latest = await reader.getLatestBlockNumber();
3041
- const height = [latest, receipt.block.number, state.observedThrough?.number ?? 0n].reduce(
3042
- (a, b) => a > b ? a : b
3043
- );
3044
- const spentBlock = await reader.getBlock(height);
3045
- check4(spentBlock.number === height, "spent-state canonical block mismatch");
3046
- const notes = [];
3047
- for (const output of plan.outputs) {
3048
- const candidate = candidates.find(
3049
- (value) => value.role === "funds" && value.commitment === output.commitment
3050
- );
3051
- check4(candidate, "confirmed output is missing from canonical receipt");
3052
- if (!output.note || output.note.ownerAddress !== scope.ownerAddress) {
3053
- continue;
3054
- }
3055
- const input = {
3056
- treeId: candidate.treeId,
3057
- leafIndex: candidate.leafIndex,
3058
- commitment: candidate.commitment
3059
- };
3060
- check4(options.protocolRpc, "membership provider required for confirmed owned output");
3061
- const proof = await options.protocolRpc.getMembership(plan.context, input, receipt.block);
3062
- await verifyMembership(reader, plan.context, receipt.block, input, proof);
3063
- notes.push({
3064
- ...input,
3065
- note: structuredClone(output.note),
3066
- blockNumber: receipt.block.number,
3067
- blockHash: receipt.block.hash,
3068
- transactionHash: hash2,
3069
- spent: "unknown"
3070
- });
3071
- }
3072
- const credits = [];
3073
- for (const output of plan.credit?.outputs ?? []) {
3074
- const n = output.state.note;
3075
- for (const role of ["owner", "spender"]) {
3076
- if ((role === "owner" ? n.ownerWalletIdentity : n.spenderWalletIdentity) !== scope.ownerAddress) {
3077
- continue;
3078
- }
3079
- const candidate = candidates.find(
3080
- (value) => value.role === role && value.commitment === output.commitment
3081
- );
3082
- check4(candidate, "confirmed Credit output is missing from canonical receipt");
3083
- const input = {
3084
- treeId: candidate.treeId,
3085
- leafIndex: candidate.leafIndex,
3086
- commitment: candidate.commitment
3087
- };
3088
- check4(options.protocolRpc, "membership provider required for confirmed Credit");
3089
- const proof = await options.protocolRpc.getMembership(
3090
- plan.context,
3091
- input,
3092
- receipt.block
3093
- );
3094
- await verifyMembership(reader, plan.context, receipt.block, input, proof);
3095
- const index2 = plan.credit?.draw?.remainderCommitments.indexOf(output.commitment);
3096
- const parent = plan.credit?.topUp ? plan.credit.inputs[0] : index2 !== void 0 && index2 >= 0 ? plan.credit?.inputs[index2] : void 0;
3097
- const receivingKeySource = parent && state.credits[parent.commitment + ":" + role] ? {
3098
- kind: plan.credit?.topUp ? "top-up" : "draw",
3099
- commitment: parent.commitment
3100
- } : void 0;
3101
- credits.push({
3102
- ...input,
3103
- state: structuredClone(output.state),
3104
- role,
3105
- blockNumber: receipt.block.number,
3106
- blockHash: receipt.block.hash,
3107
- transactionHash: hash2,
3108
- spent: "unknown",
3109
- ...receivingKeySource ? { receivingKeySource } : {}
3110
- });
3111
- }
3112
- }
3113
- if (credits.length) {
3114
- const nullifiers = await Promise.all(
3115
- credits.map(
3116
- async (record) => computeCreditNullifier(
3117
- plan.context.chainId,
3118
- record.state.note.creditSharedKey,
3119
- await creditLeaf(record.state)
3120
- )
3121
- )
3122
- );
3123
- const values = await reader.isSpent(plan.context, nullifiers, spentBlock);
3124
- check4(
3125
- values.length === credits.length && values.every((value) => typeof value === "boolean"),
3126
- "invalid Credit spent-state response"
3127
- );
3128
- credits.forEach((record, i) => {
3129
- record.spent = values[i] ? "spent" : "unspent";
3130
- record.checkedThrough = { number: spentBlock.number, hash: spentBlock.hash };
3131
- });
3132
- }
3133
- const facts = inputFacts(plan);
3134
- const nfs = facts.map((input) => input.nullifier);
3135
- const spent = nfs.length ? await reader.isSpent(plan.context, nfs, spentBlock) : [];
3136
- check4(
3137
- spent.length === nfs.length && spent.every((value) => value === true),
3138
- "successful operation inputs are not consumed"
3139
- );
3140
- const nullifier = options.wallet.exportNullifier();
3141
- if (notes.length) {
3142
- const values = await reader.isSpent(
3143
- plan.context,
3144
- await Promise.all(
3145
- notes.map(
3146
- (note) => nullifier.compute(plan.context.chainId, note.commitment, note.note.nonce)
3147
- )
3148
- ),
3149
- spentBlock
3150
- );
3151
- check4(
3152
- values.length === notes.length && values.every((value) => typeof value === "boolean"),
3153
- "invalid output spent-state response"
3154
- );
3155
- notes.forEach((note, i) => {
3156
- note.spent = values[i] ? "spent" : "unspent";
3157
- note.checkedThrough = { number: spentBlock.number, hash: spentBlock.hash };
3158
- });
3159
- }
3160
- signal?.throwIfAborted();
3161
- await barrier(runtime, state, receipt.block);
3162
- await barrier(runtime, state, spentBlock);
3163
- return store.transaction(scope, (draft) => {
3164
- signal?.throwIfAborted();
3165
- const { record, saved: active } = current(draft, id, generation);
3166
- for (const point of [draft.observedThrough]) {
3167
- check4(
3168
- !point || point.number < spentBlock.number || point.number === spentBlock.number && point.hash === spentBlock.hash,
3169
- "wallet advanced or changed during confirmation; retry"
3170
- );
3171
- }
3172
- mergeReceiptRecords(draft, {
3173
- notes,
3174
- credits,
3175
- checkpoint: { number: receipt.block.number, hash: receipt.block.hash }
3176
- });
3177
- for (const fact of facts) {
3178
- const input = draft[fact.kind][fact.key];
3179
- if (input) {
3180
- mergeSpentObservation(input, {
3181
- spent: "spent",
3182
- checkedThrough: { number: spentBlock.number, hash: spentBlock.hash }
3183
- });
3184
- }
3185
- if (fact.kind === "credits" && input) {
3186
- for (const other of Object.values(draft.credits)) {
3187
- if (other.commitment === input.commitment) {
3188
- mergeSpentObservation(other, {
3189
- spent: "spent",
3190
- checkedThrough: { number: spentBlock.number, hash: spentBlock.hash }
3191
- });
3192
- }
3193
- }
3194
- }
3195
- if (draft.reservations[fact.reservationKey] === id) {
3196
- delete draft.reservations[fact.reservationKey];
3197
- }
3198
- }
3199
- observe(draft, spentBlock);
3200
- record.status = "confirmed";
3201
- record.transactionHash = hash2;
3202
- active.generation++;
3203
- return { status: record.status, saved: structuredClone(active) };
3204
- });
3205
- }
3206
- async function reconcileOperation(runtime, id, generation, signal) {
3207
- const { reader, store, scope, options } = runtime;
3208
- const state = await store.readSnapshot(scope);
3209
- const { record, saved } = current(state, id, generation);
3210
- const plan = saved.plan;
3211
- await options.protocol.validateDeployment(reader);
3212
- await barrier(runtime, state);
3213
- const block = await reader.getBlock(await reader.getLatestBlockNumber());
3214
- const facts = inputFacts(plan);
3215
- const nfs = facts.map((input) => input.nullifier);
3216
- const spent = nfs.length ? await reader.isSpent(plan.context, nfs, block) : [];
3217
- check4(
3218
- spent.length === nfs.length && spent.every((value) => typeof value === "boolean"),
3219
- "invalid reconciliation spent-state response"
3220
- );
3221
- const expired = operationExpired(plan, block.timestamp);
3222
- const impossible = spent.some((value) => value);
3223
- signal?.throwIfAborted();
3224
- await barrier(runtime, state, block);
3225
- return store.transaction(scope, (draft) => {
3226
- signal?.throwIfAborted();
3227
- const { record: active, saved: next } = current(draft, id, generation);
3228
- for (const point of [
3229
- draft.observedThrough,
3230
- ...facts.map((fact) => draft[fact.kind][fact.key]?.checkedThrough)
3231
- ]) {
3232
- check4(
3233
- !point || point.number < block.number || point.number === block.number && point.hash === block.hash,
3234
- "wallet advanced or changed during reconciliation; retry"
3235
- );
3236
- }
3237
- if (expired || impossible) {
3238
- active.status = expired ? "expired" : "failed";
3239
- facts.forEach((fact, i) => {
3240
- const input = draft[fact.kind][fact.key];
3241
- if (input) {
3242
- mergeSpentObservation(input, {
3243
- spent: spent[i] ? "spent" : "unspent",
3244
- checkedThrough: { number: block.number, hash: block.hash }
3245
- });
3246
- if (fact.kind === "credits") {
3247
- for (const other of Object.values(draft.credits)) {
3248
- if (other.commitment === input.commitment) {
3249
- mergeSpentObservation(other, {
3250
- spent: spent[i] ? "spent" : "unspent",
3251
- checkedThrough: { number: block.number, hash: block.hash }
3252
- });
3253
- }
3254
- }
3255
- }
3256
- }
3257
- if (draft.reservations[fact.reservationKey] === id) {
3258
- delete draft.reservations[fact.reservationKey];
3259
- }
3260
- });
3261
- observe(draft, block);
3262
- } else if (next.externalized || active.status === "reorged") {
3263
- active.status = "uncertain";
3264
- }
3265
- next.generation++;
3266
- return { status: active.status, saved: structuredClone(next) };
3267
- });
3268
- }
3269
-
3270
- // src/session/Operation.ts
3271
- function check5(ok, message) {
3272
- if (!ok) {
3273
- throw new Error(message);
3274
- }
3275
- }
3276
- var Operation = class _Operation {
3277
- #runtime;
3278
- #saved;
3279
- #authorization;
3280
- status;
3281
- constructor(runtime, saved, status, authorization) {
3282
- this.#runtime = runtime;
3283
- this.#saved = structuredClone(saved);
3284
- this.status = status;
3285
- this.#authorization = authorization;
3286
- Object.freeze(this);
3287
- }
3288
- static async prepare(runtime, plan) {
3289
- const saved = { plan: structuredClone(plan), generation: 0 };
3290
- await runtime.store.transaction(runtime.scope, (state) => {
3291
- check5(!state.invalidated, "wallet state requires canonical resync");
3292
- check5(!state.operations[plan.id], "operation already exists");
3293
- const facts = inputFacts(plan);
3294
- for (const input of facts) {
3295
- const record = state[input.kind][input.key];
3296
- check5(
3297
- record && record.spent === "unspent" && !state.reservations[input.reservationKey],
3298
- "input unavailable or already reserved"
3299
- );
3300
- }
3301
- state.operations[plan.id] = {
3302
- id: plan.id,
3303
- status: "prepared",
3304
- inputs: facts.map((input) => input.reservationKey),
3305
- deadline: plan.deadline,
3306
- payload: saved
3307
- };
3308
- for (const input of facts) {
3309
- state.reservations[input.reservationKey] = plan.id;
3310
- }
3311
- });
3312
- return new _Operation(runtime, saved, "prepared");
3313
- }
3314
- static async resume(runtime, id) {
3315
- const result = await runtime.store.transaction(runtime.scope, (state) => {
3316
- const record = state.operations[id];
3317
- check5(record, "unknown operation");
3318
- const saved = record.payload;
3319
- check5(
3320
- saved?.plan?.version === 1 && saved.plan.id === id && Number.isSafeInteger(saved.generation) && saved.generation >= 0 && saved.generation < Number.MAX_SAFE_INTEGER,
3321
- "invalid operation payload"
3322
- );
3323
- const context = runtime.options.protocol.context;
3324
- const actual = saved.plan.context;
3325
- check5(
3326
- scopeKey(saved.plan.scope) === scopeKey(runtime.scope) && actual.chainId === context.chainId && actual.protocolAddress.toLowerCase() === context.protocolAddress.toLowerCase() && actual.tokenAddress.toLowerCase() === context.tokenAddress.toLowerCase(),
3327
- "recovered operation scope/deployment context mismatch"
3328
- );
3329
- if (saved.plan.kind !== "shield") {
3330
- statement(saved.plan);
3331
- }
3332
- if (saved.proof) {
3333
- sameStatement(saved.proof, saved.plan.statement);
3334
- }
3335
- saved.generation++;
3336
- delete saved.claim;
3337
- return new _Operation(runtime, saved, record.status);
3338
- });
3339
- if (result.#saved.call) {
3340
- const expected = await result.encode(result.#saved);
3341
- check5(
3342
- expected.to === result.#saved.call.to && expected.value === result.#saved.call.value && expected.data === result.#saved.call.data,
3343
- "recovered transaction differs from frozen operation"
3344
- );
3345
- }
3346
- return result;
3347
- }
3348
- /** Public non-sendable intent for a firm quote before wallet authorization. */
3349
- async exportBroadcasterIntent() {
3350
- check5(
3351
- ["prepared", "authorized"].includes(this.status),
3352
- "quote intent requires a prepared operation"
3353
- );
3354
- return exportBroadcasterIntent(this.#saved.plan);
3355
- }
3356
- broadcasterQuote() {
3357
- return this.#saved.broadcasterQuote ? structuredClone(this.#saved.broadcasterQuote) : void 0;
3358
- }
3359
- async withBroadcaster(client, options) {
3360
- check5(this.status === "prepared", "broadcaster must attach before signing");
3361
- const { prepareIntent, prepareBroadcasterPlan } = await import("./broadcaster-preparation-QVL62KM6.js");
3362
- const runtime = this.#runtime;
3363
- const reprepare = (intent) => prepareIntent(
3364
- {
3365
- options: runtime.options,
3366
- scope: runtime.scope,
3367
- reader: runtime.reader,
3368
- readInventory: async () => {
3369
- const state = await runtime.store.readSnapshot(runtime.scope);
3370
- for (const [key, owner] of Object.entries(state.reservations))
3371
- if (owner === this.id) delete state.reservations[key];
3372
- return state;
3373
- },
3374
- complete: async (plan) => plan
3375
- },
3376
- intent
3377
- );
3378
- const selected = await prepareBroadcasterPlan(this.#saved.plan, reprepare, client, options);
3379
- const saved = await runtime.store.transaction(runtime.scope, (state) => {
3380
- const record = state.operations[this.id];
3381
- const old = record?.payload;
3382
- check5(
3383
- record?.status === "prepared" && old?.generation === this.#saved.generation && !old.claim && !old.externalized,
3384
- "stale operation or active worker"
3385
- );
3386
- check5(!state.invalidated, "wallet state requires canonical resync");
3387
- const nextPlan = { ...selected.plan, id: this.id };
3388
- const facts = inputFacts(nextPlan);
3389
- for (const fact of facts)
3390
- check5(
3391
- state[fact.kind][fact.key]?.spent === "unspent" && (!state.reservations[fact.reservationKey] || state.reservations[fact.reservationKey] === this.id),
3392
- "input unavailable or already reserved"
3393
- );
3394
- for (const [key, owner] of Object.entries(state.reservations))
3395
- if (owner === this.id) delete state.reservations[key];
3396
- for (const fact of facts) state.reservations[fact.reservationKey] = this.id;
3397
- const next = {
3398
- plan: nextPlan,
3399
- broadcasterQuote: selected.quote,
3400
- generation: old.generation + 1
3401
- };
3402
- record.payload = next;
3403
- record.inputs = facts.map((fact) => fact.reservationKey);
3404
- record.deadline = nextPlan.deadline;
3405
- return structuredClone(next);
3406
- });
3407
- return new _Operation(runtime, saved, "prepared");
3408
- }
3409
- get id() {
3410
- return this.#saved.plan.id;
3411
- }
3412
- get kind() {
3413
- return this.#saved.plan.kind;
3414
- }
3415
- estimateGas() {
3416
- return estimateGasReference(
3417
- this.#saved.plan,
3418
- this.#runtime.options.protocol,
3419
- this.#runtime.options.gasBenchmarks
3420
- );
3421
- }
3422
- preview() {
3423
- return operationPreview(this.#saved.plan, this.status);
3424
- }
3425
- current(record) {
3426
- check5(record, "unknown operation");
3427
- const saved = record.payload;
3428
- check5(
3429
- saved.generation === this.#saved.generation && !saved.claim,
3430
- "stale operation handle or active worker; recover the operation"
3431
- );
3432
- return saved;
3433
- }
3434
- async stage(stage, allowed, work, signal) {
3435
- signal?.throwIfAborted();
3436
- const { store, scope } = this.#runtime;
3437
- const token = crypto.randomUUID();
3438
- const saved = await store.transaction(scope, (state) => {
3439
- check5(!state.invalidated, "wallet requires canonical resync");
3440
- const record = state.operations[this.id];
3441
- const current2 = this.current(record);
3442
- check5(allowed.includes(record.status), `invalid operation stage for ${stage}`);
3443
- current2.generation++;
3444
- current2.claim = { stage, token };
3445
- return structuredClone(current2);
3446
- });
3447
- try {
3448
- const next = await work(saved);
3449
- signal?.throwIfAborted();
3450
- await store.transaction(scope, (state) => {
3451
- check5(!state.invalidated, "wallet invalidated during operation");
3452
- const record = state.operations[this.id];
3453
- const current2 = record?.payload;
3454
- check5(
3455
- record && current2?.generation === saved.generation && current2.claim?.token === token && allowed.includes(record.status),
3456
- "stale operation worker after recovery"
3457
- );
3458
- delete saved.claim;
3459
- record.status = next.status;
3460
- record.payload = structuredClone(saved);
3461
- });
3462
- return new _Operation(
3463
- this.#runtime,
3464
- saved,
3465
- next.status,
3466
- next.authorization ?? this.#authorization
3467
- );
3468
- } catch (error) {
3469
- await store.transaction(scope, (state) => {
3470
- const current2 = state.operations[this.id]?.payload;
3471
- if (current2?.claim?.token === token) {
3472
- delete current2.claim;
3473
- }
3474
- });
3475
- throw error;
3476
- }
3477
- }
3478
- async signingCurrent() {
3479
- await this.#runtime.store.transaction(this.#runtime.scope, (state) => {
3480
- check5(!state.invalidated, "wallet state requires canonical resync");
3481
- this.current(state.operations[this.id]);
3482
- });
3483
- }
3484
- /** Public EIP-712 request; signing transport and key custody belong to the caller. */
3485
- async exportWalletAuthorization(options = {}) {
3486
- options.signal?.throwIfAborted();
3487
- await this.signingCurrent();
3488
- check5(
3489
- requiresAuthorization(this.#saved.plan),
3490
- "operation does not require wallet authorization"
3491
- );
3492
- check5(
3493
- ["prepared", "authorized"].includes(this.status),
3494
- "operation is not awaiting wallet authorization"
3495
- );
3496
- return walletSigningRequest(this.#saved.plan);
3497
- }
3498
- /** Attach an external EOA signature, retaining its witness only at the private proving boundary. */
3499
- async withWalletSignature(signature, options = {}) {
3500
- options.signal?.throwIfAborted();
3501
- await this.signingCurrent();
3502
- check5(
3503
- requiresAuthorization(this.#saved.plan),
3504
- "operation does not require wallet authorization"
3505
- );
3506
- check5(
3507
- ["prepared", "authorized"].includes(this.status),
3508
- "operation is not awaiting wallet authorization"
3509
- );
3510
- const authorization = await acceptWalletSignature(this.#saved.plan, signature);
3511
- return this.stage(
3512
- "wallet authorization",
3513
- ["prepared", "authorized"],
3514
- async () => ({ status: "authorized", authorization }),
3515
- options.signal
3516
- );
3517
- }
3518
- /** Export only after proving when the funding authorization binds an actual proof hash. */
3519
- async exportFundingAuthorization(options = {}) {
3520
- options.signal?.throwIfAborted();
3521
- await this.signingCurrent();
3522
- check5(
3523
- this.status === (this.kind === "shield" ? "prepared" : "proved"),
3524
- "operation is not awaiting funding authorization or proof"
3525
- );
3526
- const request = await fundingSigningRequest(this.#saved, this.#runtime);
3527
- options.signal?.throwIfAborted();
3528
- await this.signingCurrent();
3529
- return request;
3530
- }
3531
- /** Verify an external signature against this handle's own frozen operation. */
3532
- async withFundingSignature(signature, options = {}) {
3533
- options.signal?.throwIfAborted();
3534
- await this.signingCurrent();
3535
- check5(
3536
- this.status === (this.kind === "shield" ? "prepared" : "proved"),
3537
- "operation is not awaiting funding authorization or proof"
3538
- );
3539
- const verified = await acceptFundingSignature(this.#saved, signature, this.#runtime);
3540
- return this.stage(
3541
- "funding authorization",
3542
- this.kind === "shield" ? ["prepared"] : ["proved"],
3543
- async (saved) => {
3544
- saved.plan.funding.signature = verified;
3545
- if (saved.plan.statement?.target !== "noir-recursive") {
3546
- saved.call = await this.encode(saved);
3547
- }
3548
- return { status: "ready" };
3549
- },
3550
- options.signal
3551
- );
3552
- }
3553
- async authorize(options = {}) {
3554
- check5(
3555
- requiresAuthorization(this.#saved.plan),
3556
- "operation does not require wallet authorization"
3557
- );
3558
- const provider = this.#runtime.authorization();
3559
- check5(
3560
- provider.ownerAddress === this.#runtime.scope.ownerAddress,
3561
- "wallet authorization capability mismatch"
3562
- );
3563
- return this.stage(
3564
- "wallet authorization",
3565
- ["prepared", "authorized"],
3566
- async (saved) => {
3567
- const authorization = await authorizeOperation(saved.plan, provider);
3568
- return { status: "authorized", authorization };
3569
- },
3570
- options.signal
3571
- );
3572
- }
3573
- async prove(suppliedOptions = {}) {
3574
- const options = { ...suppliedOptions };
3575
- check5(
3576
- !this.#saved.broadcasterQuote || options.execution !== "aggregate",
3577
- "a broadcaster quote requires direct execution"
3578
- );
3579
- const plan = this.#saved.plan;
3580
- check5(plan.kind !== "shield", "shield requires no proof");
3581
- if (requiresAuthorization(plan)) {
3582
- check5(
3583
- this.#authorization,
3584
- "local wallet authorization required; authorize again after recovery"
3585
- );
3586
- }
3587
- const prover = this.#runtime.options.prover;
3588
- if (!prover) {
3589
- throw new MissingCapabilityError("prover");
3590
- }
3591
- return this.stage(
3592
- "proof",
3593
- requiresAuthorization(plan) ? ["authorized"] : ["prepared"],
3594
- async (saved) => {
3595
- const p = saved.plan;
3596
- saved.proof = await proveOperation(
3597
- this.#runtime.options.protocol,
3598
- p,
3599
- this.#authorization,
3600
- prover,
3601
- options
3602
- );
3603
- if (p.fundingMode === "signature") {
3604
- return { status: "proved" };
3605
- }
3606
- if (p.statement?.target !== "noir-recursive") {
3607
- saved.call = await this.encode(saved);
3608
- }
3609
- return { status: "ready" };
3610
- },
3611
- options.signal
3612
- );
3613
- }
3614
- encode(saved) {
3615
- return encodeOperation(saved);
3616
- }
3617
- async authorizeFunding(options = {}) {
3618
- const p = this.#saved.plan;
3619
- check5(p.fundingMode === "signature", "operation does not require a funding signature");
3620
- check5(p.kind === "shield" || this.#saved.proof, "proof must precede funding authorization");
3621
- const signer = this.#runtime.options.fundingSigner;
3622
- if (!signer) {
3623
- throw new MissingCapabilityError("EVM funding signer");
3624
- }
3625
- check5(
3626
- signer.address.toLowerCase() === p.funding.payer.toLowerCase(),
3627
- "funding signer is not the payer"
3628
- );
3629
- return this.stage(
3630
- "funding authorization",
3631
- p.kind === "shield" ? ["prepared"] : ["proved"],
3632
- async (saved) => {
3633
- saved.plan.funding.signature = await signOperationFunding(
3634
- saved,
3635
- signer,
3636
- this.#runtime.options.fundingVerifier
3637
- );
3638
- if (saved.plan.statement?.target !== "noir-recursive") {
3639
- saved.call = await this.encode(saved);
3640
- }
3641
- return { status: "ready" };
3642
- },
3643
- options.signal
3644
- );
3645
- }
3646
- /** Shield caller funding needs no wallet signing or proof; this step only encodes its frozen request. */
3647
- async ready() {
3648
- check5(
3649
- this.kind === "shield" && this.#saved.plan.fundingMode === "caller",
3650
- "operation needs authorization or proof first"
3651
- );
3652
- return this.stage("encoding", ["prepared"], async (saved) => {
3653
- saved.call = await this.encode(saved);
3654
- return { status: "ready" };
3655
- });
3656
- }
3657
- async validateExport(signal) {
3658
- signal?.throwIfAborted();
3659
- const { reader, options: runtimeOptions } = this.#runtime;
3660
- await runtimeOptions.protocol.validateDeployment(reader);
3661
- const head = await reader.getBlock(await reader.getLatestBlockNumber());
3662
- const plan = this.#saved.plan;
3663
- check5(!operationExpired(plan, head.timestamp), "operation has expired");
3664
- if (plan.fundingMode === "signature") {
3665
- check5(head.timestamp <= (plan.funding.deadline ?? 0n), "funding authorization expired");
3666
- check5(
3667
- await reader.getFundingNonce(plan.context, plan.funding.payer, head) === plan.funding.sigNonce,
3668
- "funding nonce changed; prepare again"
3669
- );
3670
- }
3671
- for (const source of operationSources(plan)) {
3672
- check5(
3673
- await reader.isKnownRoot(plan.context, source.treeId, source.merkleRoot, head),
3674
- "source root is no longer accepted; prepare again"
3675
- );
3676
- }
3677
- const nullifiers = inputFacts(plan).map((input) => input.nullifier);
3678
- if (nullifiers.length) {
3679
- const spent = await reader.isSpent(plan.context, nullifiers, head);
3680
- check5(
3681
- spent.length === nullifiers.length && spent.every((value) => value === false),
3682
- "input spent or invalid spent response"
3683
- );
3684
- }
3685
- signal?.throwIfAborted();
3686
- }
3687
- async exportTransaction(options = {}) {
3688
- check5(
3689
- this.#saved.plan.statement?.target !== "noir-recursive",
3690
- "recursive operations must be exported as aggregate members"
3691
- );
3692
- await this.validateExport(options.signal);
3693
- const result = await this.#runtime.store.transaction(this.#runtime.scope, (state) => {
3694
- options.signal?.throwIfAborted();
3695
- const record = state.operations[this.id];
3696
- const saved = this.current(record);
3697
- check5(record.status === "ready" && saved.call, "operation is not ready");
3698
- saved.externalized = true;
3699
- return structuredClone(saved.call);
3700
- });
3701
- return result;
3702
- }
3703
- async exportAggregateMember() {
3704
- return this.#runtime.store.transaction(this.#runtime.scope, (state) => {
3705
- const record = state.operations[this.id];
3706
- const saved = this.current(record);
3707
- const plan = saved.plan;
3708
- check5(
3709
- ["ready", "uncertain"].includes(record.status) && plan.params && saved.proof && plan.statement?.target === "noir-recursive" && plan.statement.circuitName === "transact_user_slots14",
3710
- "operation is not a ready recursive slots14 aggregate member"
3711
- );
3712
- sameStatement(saved.proof, statement(plan));
3713
- check5(
3714
- saved.proof.proofHex.length === 2 + 458 * 64,
3715
- "recursive member proof must have 458 fields"
3716
- );
3717
- saved.externalized = true;
3718
- return {
3719
- bundle: publicProof(saved.proof),
3720
- statement: structuredClone(plan.statement),
3721
- context: { ...plan.context },
3722
- request: {
3723
- params: structuredClone(plan.params),
3724
- deliveries: plan.outputs.map((output) => structuredClone(output.delivery)),
3725
- funding: normalizeFunding2(plan.funding)
3726
- }
3727
- };
3728
- });
3729
- }
3730
- async abandon() {
3731
- const saved = await this.#runtime.store.transaction(this.#runtime.scope, (state) => {
3732
- const record = state.operations[this.id];
3733
- const current2 = this.current(record);
3734
- check5(
3735
- !current2.externalized,
3736
- "externalized or broadcast operation requires chain reconciliation"
3737
- );
3738
- check5(
3739
- !["confirmed", "reorged"].includes(record.status),
3740
- "operation requires chain reconciliation"
3741
- );
3742
- for (const id of record.inputs) {
3743
- if (state.reservations[id] === this.id) {
3744
- delete state.reservations[id];
3745
- }
3746
- }
3747
- record.status = "failed";
3748
- current2.generation++;
3749
- return structuredClone(current2);
3750
- });
3751
- return new _Operation(this.#runtime, saved, "failed");
3752
- }
3753
- /** Record an application-owned signed/broadcast transaction. This never sends or waits. */
3754
- async trackTransaction(transactionHash) {
3755
- check5(/^0x[a-fA-F0-9]{64}$/.test(transactionHash), "invalid transaction hash");
3756
- const saved = await this.#runtime.store.transaction(this.#runtime.scope, (state) => {
3757
- check5(!state.invalidated, "wallet requires canonical resync");
3758
- const record = state.operations[this.id];
3759
- const current2 = this.current(record);
3760
- check5(
3761
- ["ready", "uncertain", "submitted"].includes(record.status),
3762
- "operation is not ready"
3763
- );
3764
- check5(
3765
- current2.externalized,
3766
- "export the transaction or aggregate member before tracking"
3767
- );
3768
- for (const input of record.inputs) {
3769
- check5(state.reservations[input] === this.id, "operation input reservation lost");
3770
- }
3771
- current2.generation++;
3772
- current2.externalized = true;
3773
- record.transactionHash = transactionHash;
3774
- record.status = "uncertain";
3775
- return structuredClone(current2);
3776
- });
3777
- return new _Operation(this.#runtime, saved, "uncertain");
3778
- }
3779
- async reconcile(options = {}) {
3780
- options.signal?.throwIfAborted();
3781
- const state = await this.#runtime.store.readSnapshot(this.#runtime.scope);
3782
- const record = state.operations[this.id];
3783
- this.current(record);
3784
- check5(!state.invalidated, "wallet requires canonical resync");
3785
- const hash2 = options.transactionHash ?? record.transactionHash;
3786
- let outcome;
3787
- if (hash2) {
3788
- outcome = await confirmOperation(
3789
- this.#runtime,
3790
- this.id,
3791
- this.#saved.generation,
3792
- hash2,
3793
- options.signal
3794
- );
3795
- }
3796
- outcome ??= await reconcileOperation(
3797
- this.#runtime,
3798
- this.id,
3799
- this.#saved.generation,
3800
- options.signal
3801
- );
3802
- return new _Operation(this.#runtime, outcome.saved, outcome.status);
3803
- }
3804
- toJSON() {
3805
- return { id: this.id, kind: this.kind, status: this.status };
3806
- }
3807
- [/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
3808
- return this.toJSON();
3809
- }
3810
- };
3811
-
3812
- // src/session/WalletSession.ts
3813
- import { Wallet } from "@invisi-labs/core";
3814
-
3815
- // src/session/history.ts
3816
- function walletHistory(state, options = {}) {
3817
- const token = options.tokenAddress?.toLowerCase();
3818
- const outgoing = [];
3819
- for (const record of Object.values(state.operations)) {
3820
- const saved = record.payload;
3821
- if (!saved?.plan || token && saved.plan.context.tokenAddress.toLowerCase() !== token) {
3822
- continue;
3823
- }
3824
- const plan = saved.plan;
3825
- outgoing.push({
3826
- ...operationPreview(plan, record.status),
3827
- preparedAt: { ...plan.preparedAt },
3828
- ...record.transactionHash ? { transactionHash: record.transactionHash } : {},
3829
- outputs: plan.outputs.map((output) => ({
3830
- to: output.address,
3831
- amount: output.amount,
3832
- change: output.change,
3833
- commitment: output.commitment,
3834
- payload: Uint8Array.from(output.note?.payload ?? [])
3835
- }))
3836
- });
3837
- }
3838
- outgoing.sort(
3839
- (a, b) => a.preparedAt.number === b.preparedAt.number ? a.id.localeCompare(b.id) : a.preparedAt.number > b.preparedAt.number ? -1 : 1
3840
- );
3841
- const incoming = [];
3842
- for (const record of Object.values(state.notes)) {
3843
- const tokenAddress = `0x${record.note.tokenAddress.toString(16).padStart(40, "0")}`;
3844
- if (token && tokenAddress !== token) continue;
3845
- incoming.push({
3846
- commitment: record.commitment,
3847
- treeId: record.treeId,
3848
- leafIndex: record.leafIndex,
3849
- blockNumber: record.blockNumber,
3850
- blockHash: record.blockHash,
3851
- ...record.transactionHash ? { transactionHash: record.transactionHash } : {},
3852
- tokenAddress,
3853
- amount: record.note.amount,
3854
- payload: Uint8Array.from(record.note.payload ?? []),
3855
- spent: record.spent
3856
- });
3857
- }
3858
- incoming.sort(
3859
- (a, b) => a.blockNumber === b.blockNumber ? a.commitment.localeCompare(b.commitment) : a.blockNumber > b.blockNumber ? -1 : 1
3860
- );
3861
- return structuredClone({
3862
- revision: state.revision,
3863
- checkedThrough: state.discoveryThrough ?? null,
3864
- invalidated: !!state.invalidated,
3865
- outgoing,
3866
- incoming
3867
- });
3868
- }
3869
-
3870
- // src/session/WalletSession.ts
3871
- import { getAddress } from "ethers";
3872
- import { MissingCapabilityError as MissingCapabilityError2 } from "@invisi-labs/core";
3873
-
3874
- // src/session/refresh.ts
3875
- import { MAX_UPDATE_BLOCKS } from "@invisi-labs/rpc";
3876
- async function refreshWallet(runtime, options) {
3877
- const { signal } = options;
3878
- try {
3879
- signal?.throwIfAborted();
3880
- if (typeof options.fromBlock !== "bigint" || options.fromBlock < runtime.fromBlock)
3881
- throw new Error("refresh range precedes deployment");
3882
- const pageSize = options.pageSize ?? MAX_UPDATE_BLOCKS;
3883
- if (!Number.isInteger(pageSize) || pageSize < 1 || pageSize > MAX_UPDATE_BLOCKS)
3884
- throw new Error(`refresh page size must be 1..${MAX_UPDATE_BLOCKS}`);
3885
- const status = await runtime.provider.getStatus(runtime.context, {
3886
- ...signal ? { signal } : {}
3887
- });
3888
- if (!status.indexedHead) throw new Error("Protocol RPC has not indexed any blocks");
3889
- const toBlock = options.toBlock ?? status.indexedHead.number;
3890
- if (typeof toBlock !== "bigint" || toBlock < options.fromBlock || toBlock > status.indexedHead.number)
3891
- throw new Error("refresh range is outside indexed history");
3892
- const target = await runtime.reader.getBlock(toBlock);
3893
- if (target.number !== toBlock)
3894
- throw new Error("Chain RPC returned the wrong refresh anchor");
3895
- let result;
3896
- let notes = 0;
3897
- let credits = 0;
3898
- for (let from = options.fromBlock; from <= toBlock; from += BigInt(pageSize)) {
3899
- signal?.throwIfAborted();
3900
- const end = from + BigInt(pageSize) - 1n;
3901
- const page = await runtime.provider.getUpdates(runtime.context, {
3902
- fromBlock: from,
3903
- toBlock: end < toBlock ? end : toBlock,
3904
- ...options.detectionKey ? { detectionKey: options.detectionKey } : {},
3905
- ...signal ? { signal } : {}
3906
- });
3907
- if (page.block.number !== (end < toBlock ? end : toBlock))
3908
- throw new Error("Protocol RPC returned the wrong page anchor");
3909
- signal?.throwIfAborted();
3910
- if (page.transactionHashes.length === 0 && (result || from + BigInt(pageSize) <= toBlock))
3911
- continue;
3912
- const firstApplication = result === void 0;
3913
- result = await runtime.apply(
3914
- {
3915
- context: runtime.context,
3916
- transactionHashes: page.transactionHashes,
3917
- block: target
3918
- },
3919
- {
3920
- ...signal ? { signal } : {},
3921
- ...firstApplication && options.reset ? { reset: true } : {}
3922
- }
3923
- );
3924
- notes += result.notes;
3925
- credits += result.credits;
3926
- }
3927
- return { ...result, notes, credits };
3928
- } finally {
3929
- options.detectionKey?.fill(0);
3930
- }
3931
- }
3932
-
3933
- // src/session/WalletUpdater.ts
3934
- import { NullifierCapability } from "@invisi-labs/core";
3935
-
3936
- // src/session/inventory.ts
3937
- import {
3938
- computeCreditCommitment,
3939
- computeCreditNullifier as computeCreditNullifier2,
3940
- computeCreditSharedKeyHash,
3941
- recoverCreditRemainder
3942
- } from "@invisi-labs/core";
3943
- var CanonicalConflict = class extends Error {
3944
- };
3945
- var CreditMetadataMismatch = class extends Error {
3946
- };
3947
- function check6(value, message) {
3948
- if (!value) {
3949
- throw new Error(message);
3950
- }
3951
- }
3952
- var clone = (value) => structuredClone(value);
3953
- var InventoryProcessor = class {
3954
- #options;
3955
- constructor(options) {
3956
- this.#options = { ...options, scope: Object.freeze({ ...options.scope }) };
3957
- }
3958
- reorgOperations(state) {
3959
- for (const operation of Object.values(state.operations)) {
3960
- if (["failed", "expired"].includes(operation.status) && !operation.payload?.externalized) {
3961
- continue;
3962
- }
3963
- operation.status = "reorged";
3964
- for (const id of operation.inputs) {
3965
- if (!state.reservations[id]) {
3966
- state.reservations[id] = operation.id;
3967
- }
3968
- }
3969
- }
3970
- }
3971
- async invalidate() {
3972
- const { store, scope } = this.#options;
3973
- await store.transaction(scope, (state) => {
3974
- state.invalidated = "Canonical history changed; rebuild inventory from canonical data";
3975
- for (const record of [...Object.values(state.notes), ...Object.values(state.credits)]) {
3976
- record.spent = "unknown";
3977
- }
3978
- this.reorgOperations(state);
3979
- });
3980
- }
3981
- checkSnapshotKeys(record) {
3982
- const expected = this.#options.receivingKeys;
3983
- const keys = record.role === "owner" ? record.state.ownerReceivingKeys : record.state.spenderReceivingKeys;
3984
- if (expected && !keys.viewingPublicKey.every((byte, i) => byte === expected.viewingPublicKey[i])) {
3985
- throw new CreditMetadataMismatch("Credit receiving key snapshot mismatch");
3986
- }
3987
- const clue = expected?.clueKey;
3988
- if (clue && !keys.clueKey.every((byte, i) => byte === clue[i])) {
3989
- throw new CreditMetadataMismatch("Credit clue key snapshot mismatch");
3990
- }
3991
- }
3992
- async creditNullifier(state) {
3993
- const n = state.note;
3994
- return computeCreditNullifier2(
3995
- n.chainId,
3996
- n.creditSharedKey,
3997
- await computeCreditCommitment(
3998
- n.chainId,
3999
- n.spenderWalletIdentity,
4000
- n.ownerWalletIdentity,
4001
- n.spenderPayout,
4002
- n.ownerPayout,
4003
- n.tokenAddress,
4004
- n.amount,
4005
- n.nonce,
4006
- n.expiry,
4007
- await computeCreditSharedKeyHash(n.creditSharedKey),
4008
- n
4009
- )
4010
- );
4011
- }
4012
- async recoverCredits(base, found, logs, snapshot) {
4013
- const known = /* @__PURE__ */ new Map();
4014
- const byNullifier = /* @__PURE__ */ new Map();
4015
- const cachedNullifiers = /* @__PURE__ */ new Map();
4016
- const recovered = [];
4017
- const foundByKey = new Map(
4018
- found.map((record) => [record.commitment + ":" + record.role, record])
4019
- );
4020
- const remember = async (record) => {
4021
- const key = record.commitment + ":" + record.role;
4022
- let nullifier = cachedNullifiers.get(record.commitment);
4023
- if (!nullifier) {
4024
- nullifier = await this.creditNullifier(record.state);
4025
- cachedNullifiers.set(record.commitment, nullifier);
4026
- }
4027
- known.set(key, record);
4028
- let members = byNullifier.get(nullifier);
4029
- if (!members) {
4030
- members = /* @__PURE__ */ new Set();
4031
- byNullifier.set(nullifier, members);
4032
- }
4033
- members.add(key);
4034
- };
4035
- const matching = (nullifier) => [...byNullifier.get(nullifier) ?? []].map((key) => known.get(key));
4036
- for (const record of Object.values(base.credits)) {
4037
- await remember(record);
4038
- }
4039
- for (const record of found) {
4040
- try {
4041
- this.checkSnapshotKeys(record);
4042
- await remember({ ...record, spent: "unknown" });
4043
- } catch (error) {
4044
- if (!(error instanceof CreditMetadataMismatch)) {
4045
- throw error;
4046
- }
4047
- }
4048
- }
4049
- const context = {
4050
- chainId: this.#options.scope.chainId,
4051
- protocolAddress: BigInt(this.#options.scope.protocolAddress)
4052
- };
4053
- for (const event of logs) {
4054
- if (event.eventName === "CreditDraw") {
4055
- const block = await this.#options.reader.getBlock(event.blockNumber);
4056
- if (block.hash !== event.blockHash)
4057
- throw new CanonicalConflict("draw block changed during Credit recovery");
4058
- const args = event.args;
4059
- const params = args.params;
4060
- const indices = args.remainderLeafIndices;
4061
- check6(
4062
- Array.isArray(params.nullifiers) && params.nullifiers.length === params.remainderCommitments.length && params.nullifiers.length === params.recoveryAmounts.length && params.nullifiers.length === params.expiries.length && params.nullifiers.length === indices.length,
4063
- "invalid draw recovery slots"
4064
- );
4065
- for (const [index2, nullifier] of params.nullifiers.entries()) {
4066
- for (const previous of matching(nullifier)) {
4067
- check6(
4068
- previous.state.note.expiry === params.expiries[index2],
4069
- "draw recovery expiry mismatch"
4070
- );
4071
- const remainder = await recoverCreditRemainder(
4072
- context,
4073
- previous.state.note,
4074
- {
4075
- timestamp: block.timestamp,
4076
- creditNullifier: nullifier,
4077
- remainderCommitment: params.remainderCommitments[index2],
4078
- recoveryAmount: BigInt(params.recoveryAmounts[index2])
4079
- }
4080
- );
4081
- if (!remainder) {
4082
- continue;
4083
- }
4084
- const child = foundByKey.get(
4085
- params.remainderCommitments[index2] + ":" + previous.role
4086
- );
4087
- const payload = child?.state.note.payload;
4088
- const record = {
4089
- commitment: params.remainderCommitments[index2],
4090
- treeId: BigInt(args.outputTreeId),
4091
- leafIndex: Number(indices[index2]),
4092
- blockNumber: event.blockNumber,
4093
- blockHash: event.blockHash,
4094
- transactionHash: event.transactionHash,
4095
- role: previous.role,
4096
- state: {
4097
- ...clone(previous.state),
4098
- note: {
4099
- ...remainder,
4100
- ...payload === void 0 ? {} : { payload: clone(payload) }
4101
- }
4102
- },
4103
- receivingKeySource: { kind: "draw", commitment: previous.commitment },
4104
- spent: "unknown"
4105
- };
4106
- check6(
4107
- await snapshot.getLeaf(record.treeId, record.leafIndex) === BigInt(record.commitment),
4108
- "draw recovery canonical leaf mismatch"
4109
- );
4110
- this.checkSnapshotKeys(record);
4111
- await remember(record);
4112
- recovered.push(record);
4113
- }
4114
- }
4115
- } else if (event.eventName === "CreditToppedUp") {
4116
- const params = event.args.params;
4117
- for (const previous of matching(params.creditNullifier)) {
4118
- const child = foundByKey.get(
4119
- params.creation.creditCommitment + ":" + previous.role
4120
- );
4121
- if (!child) {
4122
- continue;
4123
- }
4124
- const old = previous.state.note;
4125
- const next = child.state.note;
4126
- if ([
4127
- "chainId",
4128
- "protocolAddress",
4129
- "tokenAddress",
4130
- "spenderWalletIdentity",
4131
- "ownerWalletIdentity",
4132
- "spenderPayout",
4133
- "ownerPayout",
4134
- "creditSharedKey"
4135
- ].some(
4136
- (field) => old[field] !== next[field]
4137
- ) || next.amount <= old.amount || next.expiry < old.expiry) {
4138
- continue;
4139
- }
4140
- const repaired = {
4141
- ...clone(child),
4142
- state: {
4143
- note: clone(next),
4144
- ownerReceivingKeys: clone(previous.state.ownerReceivingKeys),
4145
- spenderReceivingKeys: clone(previous.state.spenderReceivingKeys)
4146
- },
4147
- receivingKeySource: { kind: "top-up", commitment: previous.commitment }
4148
- };
4149
- this.checkSnapshotKeys(repaired);
4150
- await remember(repaired);
4151
- recovered.push(repaired);
4152
- }
4153
- }
4154
- }
4155
- return recovered;
4156
- }
4157
- };
4158
-
4159
- // src/session/WalletUpdater.ts
4160
- var check7 = (value, message) => {
4161
- if (!value) throw new Error(message);
4162
- };
4163
- var position2 = (treeId, leafIndex) => `${treeId}:${leafIndex}`;
4164
- var WalletUpdater = class extends InventoryProcessor {
4165
- #options;
4166
- constructor(options) {
4167
- super(options);
4168
- this.#options = { ...options };
4169
- check7(
4170
- options.viewing.ownerAddress === options.scope.ownerAddress,
4171
- "viewing capability wallet mismatch"
4172
- );
4173
- }
4174
- applyUpdates(batch, options = {}) {
4175
- return this.run(structuredClone(batch), { ...options });
4176
- }
4177
- async run(batch, options) {
4178
- const { reader, protocol, scope, store, viewing } = this.#options;
4179
- const nullifier = NullifierCapability.fromIdentity(scope.ownerAddress);
4180
- const { signal, reset } = options;
4181
- signal?.throwIfAborted();
4182
- const context = protocol.context;
4183
- check7(
4184
- batch.context.chainId === context.chainId && batch.context.protocolAddress.toLowerCase() === context.protocolAddress.toLowerCase(),
4185
- "update deployment context mismatch"
4186
- );
4187
- check7(
4188
- batch.block.number >= protocol.deployment.protocol.fromBlock,
4189
- "update precedes deployment"
4190
- );
4191
- await protocol.validateDeployment(reader);
4192
- const base = await store.readSnapshot(scope);
4193
- check7(reset || !base.invalidated, "wallet state is invalidated; rebuild required");
4194
- try {
4195
- if (!reset) {
4196
- for (const cursor of [base.observedThrough]) {
4197
- if (!cursor) continue;
4198
- if ((await reader.getBlock(cursor.number)).hash !== cursor.hash)
4199
- throw new CanonicalConflict("Canonical history changed after a reorg");
4200
- check7(
4201
- cursor.number <= batch.block.number,
4202
- "update target precedes wallet checkpoint"
4203
- );
4204
- }
4205
- } else {
4206
- base.notes = {};
4207
- base.credits = {};
4208
- }
4209
- const block = await reader.getBlock(batch.block.number);
4210
- check7(
4211
- block.hash === batch.block.hash && block.number === batch.block.number,
4212
- "update target block is not canonical"
4213
- );
4214
- const receipts = [];
4215
- for (const hash2 of new Set(batch.transactionHashes)) {
4216
- signal?.throwIfAborted();
4217
- check7(/^0x[0-9a-fA-F]{64}$/.test(hash2), "invalid candidate transaction hash");
4218
- const receipt = await reader.getReceipt(hash2);
4219
- check7(
4220
- receipt && receipt.status === "success" && receipt.transactionHash.toLowerCase() === hash2.toLowerCase(),
4221
- "invalid or unsuccessful candidate receipt"
4222
- );
4223
- check7(
4224
- receipt.block.number >= protocol.deployment.protocol.fromBlock && receipt.block.number <= block.number,
4225
- "candidate receipt outside update range"
4226
- );
4227
- if ((await reader.getBlock(receipt.block.number)).hash !== receipt.block.hash)
4228
- throw new CanonicalConflict("Candidate receipt disagrees with canonical chain");
4229
- receipts.push(receipt);
4230
- }
4231
- const logs = receipts.flatMap(
4232
- (receipt) => readProtocolLogs(receipt, context.protocolAddress)
4233
- );
4234
- logs.sort(
4235
- (a, b) => a.blockNumber < b.blockNumber ? -1 : a.blockNumber > b.blockNumber ? 1 : a.logIndex - b.logIndex
4236
- );
4237
- const leaves = /* @__PURE__ */ new Map();
4238
- for (const event of logs) {
4239
- if (event.eventName !== "CommitmentsInserted" && event.eventName !== "BatchOutputs")
4240
- continue;
4241
- const { treeId, startLeafIndex, commitments } = event.args;
4242
- for (const [i, commitment] of commitments.entries()) {
4243
- const key = position2(treeId, Number(startLeafIndex) + i);
4244
- check7(
4245
- !leaves.has(key) || leaves.get(key) === BigInt(commitment),
4246
- "conflicting canonical insertion"
4247
- );
4248
- leaves.set(key, BigInt(commitment));
4249
- }
4250
- }
4251
- const getLeaf = (tree, index2) => {
4252
- const leaf = leaves.get(position2(tree, index2));
4253
- check7(leaf !== void 0, "missing canonical insertion");
4254
- return leaf;
4255
- };
4256
- const decrypted = await decryptCandidates(logs, {
4257
- context,
4258
- viewing,
4259
- confirmedThrough: block.number
4260
- });
4261
- const notes = decrypted.notes.map((record) => ({
4262
- ...record,
4263
- spent: "unknown"
4264
- }));
4265
- const incoming = decrypted.credits.map((record) => ({
4266
- ...record,
4267
- spent: "unknown"
4268
- }));
4269
- const recovered = await this.recoverCredits(base, incoming, logs, { getLeaf });
4270
- const creditsByKey = new Map(
4271
- incoming.map((record) => [record.commitment + ":" + record.role, record])
4272
- );
4273
- for (const record of recovered)
4274
- creditsByKey.set(record.commitment + ":" + record.role, record);
4275
- const credits = [...creditsByKey.values()].filter((record) => {
4276
- try {
4277
- this.checkSnapshotKeys(record);
4278
- return true;
4279
- } catch (error) {
4280
- if (error instanceof CreditMetadataMismatch) return false;
4281
- throw error;
4282
- }
4283
- }).sort(
4284
- (a, b) => a.blockNumber < b.blockNumber ? -1 : a.blockNumber > b.blockNumber ? 1 : a.treeId < b.treeId ? -1 : a.treeId > b.treeId ? 1 : a.leafIndex - b.leafIndex
4285
- );
4286
- for (const record of [...notes, ...credits]) {
4287
- signal?.throwIfAborted();
4288
- const proof = await this.#options.protocolRpc.getMembership(context, record, block);
4289
- const tokenAddress = "note" in record ? record.note.tokenAddress : record.state.note.tokenAddress;
4290
- await verifyMembership(
4291
- reader,
4292
- {
4293
- ...context,
4294
- tokenAddress: `0x${tokenAddress.toString(16).padStart(40, "0")}`
4295
- },
4296
- block,
4297
- record,
4298
- proof
4299
- );
4300
- }
4301
- const allNotes = {
4302
- ...base.notes,
4303
- ...Object.fromEntries(notes.map((record) => [record.commitment, record]))
4304
- };
4305
- const allCredits = {
4306
- ...base.credits,
4307
- ...Object.fromEntries(
4308
- credits.map((record) => [record.commitment + ":" + record.role, record])
4309
- )
4310
- };
4311
- const observations = [];
4312
- for (const [id, record] of Object.entries(allNotes))
4313
- observations.push({
4314
- kind: "notes",
4315
- id,
4316
- nullifier: await nullifier.compute(
4317
- scope.chainId,
4318
- record.commitment,
4319
- record.note.nonce
4320
- )
4321
- });
4322
- for (const [id, record] of Object.entries(allCredits))
4323
- observations.push({
4324
- kind: "credits",
4325
- id,
4326
- nullifier: await this.creditNullifier(record.state)
4327
- });
4328
- const spent = observations.length ? await reader.isSpent(
4329
- context,
4330
- observations.map((item) => item.nullifier),
4331
- block
4332
- ) : [];
4333
- check7(
4334
- spent.length === observations.length && spent.every((value) => typeof value === "boolean"),
4335
- "invalid spent-state response"
4336
- );
4337
- signal?.throwIfAborted();
4338
- if ((await reader.getBlock(block.number)).hash !== block.hash)
4339
- throw new CanonicalConflict("Canonical block changed during update");
4340
- await store.transaction(scope, (draft) => {
4341
- signal?.throwIfAborted();
4342
- check7(draft.revision === base.revision, "wallet changed during update; retry");
4343
- if (reset) {
4344
- this.reorgOperations(draft);
4345
- draft.notes = {};
4346
- draft.credits = {};
4347
- delete draft.observedThrough;
4348
- delete draft.discoveryThrough;
4349
- delete draft.invalidated;
4350
- }
4351
- mergeReceiptRecords(draft, { notes, credits, checkpoint: block });
4352
- observations.forEach((item, index2) => {
4353
- const record = draft[item.kind][item.id];
4354
- if (record) {
4355
- mergeSpentObservation(record, {
4356
- spent: spent[index2] ? "spent" : "unspent",
4357
- checkedThrough: { number: block.number, hash: block.hash }
4358
- });
4359
- }
4360
- });
4361
- draft.observedThrough = { number: block.number, hash: block.hash };
4362
- });
4363
- return {
4364
- block,
4365
- notes: notes.length,
4366
- credits: credits.length,
4367
- balances: walletBalances(await store.readSnapshot(scope))
4368
- };
4369
- } catch (error) {
4370
- if (error instanceof CanonicalConflict) await this.invalidate();
4371
- throw error;
4372
- }
4373
- }
4374
- };
4375
-
4376
- // src/session/WalletSession.ts
4377
- var WalletSession = class {
4378
- #options;
4379
- #updater;
4380
- #listeners = /* @__PURE__ */ new Set();
4381
- #sending = /* @__PURE__ */ new Set();
4382
- #refreshQueue = Promise.resolve();
4383
- scope;
4384
- protocol;
4385
- constructor(options) {
4386
- if ("addressLookup" in options || "addressResolver" in options)
4387
- throw new TypeError(
4388
- "Recipient lookup belongs to each EVM output; caller resolver injection is not supported"
4389
- );
4390
- options = configureRecipientInfrastructure(options);
4391
- if ("ciphertextCodecs" in options || "envelopeVersion" in options) {
4392
- throw new Error(
4393
- "SDK envelope versions are fixed; encode application payload bytes externally"
4394
- );
4395
- }
4396
- const store = options.store;
4397
- this.#options = {
4398
- ...options,
4399
- ...store ? {
4400
- store: {
4401
- persistent: store.persistent,
4402
- readSnapshot: (scope) => store.readSnapshot(scope),
4403
- transaction: async (scope, action) => {
4404
- const result = await store.transaction(scope, action);
4405
- if (scopeKey(scope) === scopeKey(this.scope)) {
4406
- for (const listener of [...this.#listeners]) {
4407
- try {
4408
- listener();
4409
- } catch {
4410
- }
4411
- }
4412
- }
4413
- return result;
4414
- }
4415
- }
4416
- } : {},
4417
- ...options.gasBenchmarks ? { gasBenchmarks: copyGasBenchmarks(options.gasBenchmarks) } : {}
4418
- };
4419
- this.protocol = options.protocol;
4420
- this.scope = Object.freeze({
4421
- namespace: options.namespace ?? "default",
4422
- ...options.protocol.context,
4423
- ownerAddress: options.wallet.ownerAddress
4424
- });
4425
- scopeKey(this.scope);
4426
- Object.freeze(this);
4427
- }
4428
- /** Delegate sending to ethers; managed operations additionally retain the resulting hash. */
4429
- async sendTransaction(input, options = {}) {
4430
- const signer = this.#options.signer;
4431
- if (!signer) throw new MissingCapabilityError2("ethers signer");
4432
- const operation = input instanceof Operation ? input : void 0;
4433
- if (operation && this.#sending.has(operation.id))
4434
- throw new Error("operation is already being sent by this session");
4435
- if (operation) this.#sending.add(operation.id);
4436
- const overrides = { ...options };
4437
- const plain = operation ? void 0 : { ...input };
4438
- try {
4439
- if (!signer.provider) throw new MissingCapabilityError2("connected ethers signer");
4440
- if ((await signer.provider.getNetwork()).chainId !== this.protocol.context.chainId) {
4441
- throw new Error("signer-provider session chain mismatch");
4442
- }
4443
- if (operation) {
4444
- if (!this.#options.store) throw new MissingCapabilityError2("wallet store");
4445
- const state = await this.#options.store.readSnapshot(this.scope);
4446
- if (!state.operations[operation.id])
4447
- throw new Error("operation does not belong to this wallet session");
4448
- }
4449
- const call = operation ? await operation.exportTransaction() : plain;
4450
- const transaction = await signer.sendTransaction({
4451
- ...overrides,
4452
- to: call.to,
4453
- data: call.data,
4454
- value: call.value,
4455
- chainId: this.protocol.context.chainId
4456
- });
4457
- if (operation) {
4458
- try {
4459
- await operation.trackTransaction(transaction.hash);
4460
- } catch (cause) {
4461
- throw new Error(
4462
- `Transaction ${transaction.hash} was sent but its operation association could not be saved; resume and reconcile this hash`,
4463
- { cause }
4464
- );
4465
- }
4466
- }
4467
- return transaction;
4468
- } finally {
4469
- if (operation) this.#sending.delete(operation.id);
4470
- }
4471
- }
4472
- runtime(tokenAddress) {
4473
- const options = this.#options;
4474
- if (!options.store) {
4475
- throw new MissingCapabilityError2("wallet store");
4476
- }
4477
- if (!options.chainReader) {
4478
- throw new MissingCapabilityError2("chain reader");
4479
- }
4480
- return {
4481
- options: { ...options, protocol: options.protocol.forToken(tokenAddress) },
4482
- scope: this.scope,
4483
- store: options.store,
4484
- reader: options.chainReader,
4485
- authorization: () => {
4486
- if (options.authorization) return options.authorization;
4487
- if (options.wallet instanceof Wallet) return options.wallet.exportAuthorization();
4488
- throw new MissingCapabilityError2("wallet authorization");
4489
- }
4490
- };
4491
- }
4492
- updater() {
4493
- if (this.#updater) return this.#updater;
4494
- const options = this.#options;
4495
- if (!options.store || !options.chainReader || !options.protocolRpc)
4496
- throw new MissingCapabilityError2("wallet store, chain reader and Protocol RPC");
4497
- const viewing = options.viewing ?? (options.wallet instanceof Wallet ? options.wallet.getViewer() : void 0);
4498
- if (!viewing) throw new MissingCapabilityError2("viewing");
4499
- const receivingAddress = options.wallet.getReceivingAddress();
4500
- const receivingKeys = receivingAddress.kind === "long" ? receivingAddress.getReceivingKeys() : void 0;
4501
- this.#updater = new WalletUpdater({
4502
- protocol: options.protocol,
4503
- scope: this.scope,
4504
- store: options.store,
4505
- reader: options.chainReader,
4506
- viewing,
4507
- protocolRpc: options.protocolRpc,
4508
- ...receivingKeys ? { receivingKeys } : {}
4509
- });
4510
- return this.#updater;
4511
- }
4512
- /** Local session commits only. Host applications own cross-tab/store subscriptions. */
4513
- subscribe(listener) {
4514
- this.#listeners.add(listener);
4515
- return () => {
4516
- this.#listeners.delete(listener);
4517
- };
4518
- }
4519
- /** Detached history for wallet UI; construction records do not imply chain success. */
4520
- async getHistory(options = {}) {
4521
- const tokenAddress = options.tokenAddress ? getAddress(options.tokenAddress) : void 0;
4522
- const store = this.#options.store;
4523
- if (!store) throw new MissingCapabilityError2("wallet store");
4524
- return walletHistory(
4525
- await store.readSnapshot(this.scope),
4526
- tokenAddress ? { tokenAddress } : {}
4527
- );
4528
- }
4529
- async balance(tokenAddress) {
4530
- const store = this.#options.store;
4531
- if (!store) {
4532
- throw new MissingCapabilityError2("wallet store");
4533
- }
4534
- return walletBalance(await store.readSnapshot(this.scope), getAddress(tokenAddress));
4535
- }
4536
- /** Pull explicitly selected indexed pages; no chain scanning or public tree reconstruction. */
4537
- async refresh(options) {
4538
- const provider = this.#options.protocolRpc;
4539
- const reader = this.#options.chainReader;
4540
- if (!reader) throw new MissingCapabilityError2("chain reader");
4541
- if (!provider) throw new MissingCapabilityError2("Protocol RPC");
4542
- const updater = this.updater();
4543
- const request = {
4544
- ...options,
4545
- ...options.detectionKey ? { detectionKey: options.detectionKey.slice() } : {}
4546
- };
4547
- const task = this.#refreshQueue.then(async () => {
4548
- const result = await refreshWallet(
4549
- {
4550
- provider,
4551
- reader,
4552
- context: this.protocol.context,
4553
- fromBlock: this.protocol.deployment.protocol.fromBlock,
4554
- apply: (batch, settings) => updater.applyUpdates(batch, settings)
4555
- },
4556
- request
4557
- );
4558
- await this.#options.store.transaction(this.scope, (state) => {
4559
- request.signal?.throwIfAborted();
4560
- if (state.invalidated) throw new Error("wallet requires canonical resync");
4561
- const previous = state.discoveryThrough;
4562
- const start = previous ? previous.number + 1n : this.protocol.deployment.protocol.fromBlock;
4563
- if (request.fromBlock <= start && (!previous || result.block.number >= previous.number)) {
4564
- state.discoveryThrough = {
4565
- number: result.block.number,
4566
- hash: result.block.hash
4567
- };
4568
- }
4569
- });
4570
- return result;
4571
- });
4572
- this.#refreshQueue = task.catch(() => {
4573
- });
4574
- return task;
4575
- }
4576
- preparation(tokenAddress) {
4577
- const runtime = this.runtime(tokenAddress);
4578
- return new TransactionPreparation({
4579
- options: runtime.options,
4580
- scope: runtime.scope,
4581
- reader: runtime.reader,
4582
- readInventory: () => runtime.store.readSnapshot(runtime.scope),
4583
- complete: (plan) => Operation.prepare(runtime, plan)
4584
- });
4585
- }
4586
- async prepareTransfer(options) {
4587
- return prepareWithErrors("prepareTransfer", async () => {
4588
- return this.preparation(options.tokenAddress).prepareTransfer(options);
4589
- });
4590
- }
4591
- async prepareShield(options) {
4592
- return prepareWithErrors("prepareShield", async () => {
4593
- return this.preparation(options.tokenAddress).prepareShield(options);
4594
- });
4595
- }
4596
- async prepareCreateCredit(options) {
4597
- return prepareWithErrors("prepareCreateCredit", async () => {
4598
- return this.preparation(options.tokenAddress).prepareCreateCredit(options);
4599
- });
4600
- }
4601
- async prepareDrawCredit(options) {
4602
- return prepareWithErrors("prepareDrawCredit", async () => {
4603
- return this.preparation(options.tokenAddress).prepareDrawCredit(options);
4604
- });
4605
- }
4606
- async prepareTopUpCredit(options) {
4607
- return prepareWithErrors("prepareTopUpCredit", async () => {
4608
- return this.preparation(options.tokenAddress).prepareTopUpCredit(options);
4609
- });
4610
- }
4611
- async prepareCancelCredit(options) {
4612
- return prepareWithErrors("prepareCancelCredit", async () => {
4613
- return this.preparation(options.tokenAddress).prepareCancelCredit(options);
4614
- });
4615
- }
4616
- async resume(operationId) {
4617
- const store = this.#options.store;
4618
- if (!store) throw new MissingCapabilityError2("wallet store");
4619
- const state = await store.readSnapshot(this.scope);
4620
- const saved = state.operations[operationId]?.payload;
4621
- if (!saved?.plan) throw new Error("operation not found");
4622
- return Operation.resume(this.runtime(saved.plan.context.tokenAddress), operationId);
4623
- }
4624
- toJSON() {
4625
- return { walletSession: true, ownerAddress: this.scope.ownerAddress };
4626
- }
4627
- [/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
4628
- return this.toJSON();
4629
- }
4630
- };
4631
-
4632
- // src/session/codec.ts
4633
- function encode(value) {
4634
- if (typeof value === "bigint") return ["bigint", value.toString()];
4635
- if (value instanceof Uint8Array) return ["bytes", Array.from(value)];
4636
- if (Array.isArray(value)) return ["array", value.map(encode)];
4637
- if (value && typeof value === "object")
4638
- return ["object", Object.entries(value).map(([key, item]) => [key, encode(item)])];
4639
- if (value === void 0) return ["undefined"];
4640
- if (value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value))
4641
- return ["value", value];
4642
- throw new Error("unsupported wallet record value");
4643
- }
4644
- function decode(node) {
4645
- if (!Array.isArray(node)) throw new Error("invalid wallet record encoding");
4646
- const [type, value] = node;
4647
- if (type === "bigint" && typeof value === "string" && /^-?(0|[1-9][0-9]*)$/.test(value))
4648
- return BigInt(value);
4649
- if (type === "bytes" && Array.isArray(value) && value.every((n) => Number.isInteger(n) && n >= 0 && n < 256))
4650
- return Uint8Array.from(value);
4651
- if (type === "array" && Array.isArray(value)) return value.map(decode);
4652
- if (type === "object" && Array.isArray(value))
4653
- return Object.fromEntries(
4654
- value.map((pair) => {
4655
- if (!Array.isArray(pair) || pair.length !== 2 || typeof pair[0] !== "string")
4656
- throw new Error("invalid object record");
4657
- return [pair[0], decode(pair[1])];
4658
- })
4659
- );
4660
- if (type === "undefined" && node.length === 1) return void 0;
4661
- if (type === "value" && (value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value)))
4662
- return value;
4663
- throw new Error("invalid wallet record node");
4664
- }
4665
- function serializeState(state) {
4666
- return new TextEncoder().encode(JSON.stringify(encode(state)));
4667
- }
4668
- function deserializeState(data) {
4669
- return decode(
4670
- JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(data))
4671
- );
4672
- }
4673
- var MemoryRecordCodec = class {
4674
- async encode(state) {
4675
- return serializeState(state);
4676
- }
4677
- async decode(data) {
4678
- return deserializeState(data);
4679
- }
4680
- };
4681
-
4682
- // src/session/index.ts
4683
- var MemoryWalletStore = class extends TransactionalWalletStore {
4684
- constructor() {
4685
- super(new MemoryAtomicRecords(), new MemoryRecordCodec(), { persistent: false });
4686
- }
4687
- };
4688
-
4689
- export {
4690
- copyGasBenchmarks,
4691
- defineGasBenchmarks,
4692
- estimateGasReference,
4693
- sameStatement,
4694
- proveOperation,
4695
- walletSigningRequest,
4696
- acceptWalletSignature,
4697
- fundingSigningRequest,
4698
- acceptFundingSignature,
4699
- operationPreview,
4700
- serializeState,
4701
- deserializeState,
4702
- readProtocolLogs,
4703
- decryptCandidates,
4704
- DisclosureVerifier,
4705
- TransactionalWalletStore,
4706
- MemoryAtomicRecords,
4707
- Operation,
4708
- WalletSession,
4709
- MemoryWalletStore
4710
- };
4711
- //# sourceMappingURL=chunk-4SD3MW6N.js.map