@the_library/public 1.0.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +201 -28
- package/assets/branding/pond-enterprise-logo.svg +1 -1
- package/dist/Book-CYyj_y_4.d.ts +621 -0
- package/dist/bookSearchService-YQskauJS.d.ts +300 -0
- package/dist/branding/index.js +1 -66
- package/dist/branding/index.js.map +1 -1
- package/dist/chunk-3XUKOVEF.js +2 -0
- package/dist/chunk-3XUKOVEF.js.map +1 -0
- package/dist/chunk-46FQHZNM.js +2 -0
- package/dist/chunk-46FQHZNM.js.map +1 -0
- package/dist/chunk-7G3BMGV2.js +2 -0
- package/dist/chunk-7G3BMGV2.js.map +1 -0
- package/dist/chunk-D4DXGA2W.js +2 -0
- package/dist/chunk-D4DXGA2W.js.map +1 -0
- package/dist/chunk-EMA2QJTW.js +2 -0
- package/dist/chunk-EMA2QJTW.js.map +1 -0
- package/dist/chunk-FN52YV7L.js +2 -0
- package/dist/chunk-FN52YV7L.js.map +1 -0
- package/dist/chunk-GWQNULP4.js +2 -0
- package/dist/chunk-GWQNULP4.js.map +1 -0
- package/dist/chunk-OELHBR4F.js +2 -0
- package/dist/chunk-OELHBR4F.js.map +1 -0
- package/dist/chunk-PV3X54EU.js +2 -0
- package/dist/chunk-PV3X54EU.js.map +1 -0
- package/dist/chunk-SD3INWZF.js +2 -0
- package/dist/chunk-SD3INWZF.js.map +1 -0
- package/dist/downloader/dl2-sw.js +1 -198
- package/dist/downloader/dl2-sw.js.map +1 -1
- package/dist/downloader/file-worker-v2.js +1 -257
- package/dist/downloader/file-worker-v2.js.map +1 -1
- package/dist/downloader/index.d.ts +30 -2
- package/dist/downloader/index.js +1 -537
- package/dist/downloader/index.js.map +1 -1
- package/dist/downloader/mu-worker-v2.js +1 -196
- package/dist/downloader/mu-worker-v2.js.map +1 -1
- package/dist/downloader/react.d.ts +1 -1
- package/dist/downloader/react.js +1 -31
- package/dist/downloader/react.js.map +1 -1
- package/dist/downloader/solid.d.ts +1 -1
- package/dist/downloader/solid.js +1 -18
- package/dist/downloader/solid.js.map +1 -1
- package/dist/downloader/sw.js +1 -118
- package/dist/downloader/sw.js.map +1 -1
- package/dist/downloader/vue.d.ts +1 -1
- package/dist/downloader/vue.js +1 -18
- package/dist/downloader/vue.js.map +1 -1
- package/dist/enriched-index-T0sDG7JR.d.ts +209 -0
- package/dist/global/public.global.js +68 -0
- package/dist/global/public.manifest.json +484 -0
- package/dist/level-state-DXqglpAX.d.ts +27 -0
- package/dist/models/astro.d.ts +4 -3
- package/dist/models/astro.js +1 -43
- package/dist/models/astro.js.map +1 -1
- package/dist/models/index.d.ts +449 -23
- package/dist/models/index.js +1 -339
- package/dist/models/index.js.map +1 -1
- package/dist/models/models.d.ts +195 -441
- package/dist/models/models.js +1 -45
- package/dist/models/patch-worker.js +1 -542
- package/dist/models/patch-worker.js.map +1 -1
- package/dist/models/react.d.ts +6 -5
- package/dist/models/react.js +1 -72
- package/dist/models/react.js.map +1 -1
- package/dist/models/solid.d.ts +16 -6
- package/dist/models/solid.js +1 -94
- package/dist/models/solid.js.map +1 -1
- package/dist/models/vue.d.ts +89 -7
- package/dist/models/vue.js +1 -97
- package/dist/models/vue.js.map +1 -1
- package/dist/orm-MJTHCG9E.d.ts +1003 -0
- package/dist/{session-vqOnyxga.d.ts → session-JudUKAV7.d.ts} +76 -74
- package/dist/{state-BTsp-E4v.d.ts → state-CkYavOSt.d.ts} +16 -0
- package/dist/{types-Dn0EFMO_.d.ts → types-B-IX3HBn.d.ts} +94 -21
- package/dist/{types-Xb8Ta9tZ.d.ts → types-Blyx2A7F.d.ts} +10 -36
- package/dist/web3/auth.d.ts +89 -0
- package/dist/web3/auth.js +13 -0
- package/dist/web3/auth.js.map +1 -0
- package/dist/web3/index.d.ts +1913 -126
- package/dist/web3/index.js +1 -1019
- package/dist/web3/index.js.map +1 -1
- package/dist/web3/network.d.ts +6 -0
- package/dist/web3/network.js +2 -0
- package/dist/web3/network.js.map +1 -0
- package/dist/web3/registry.d.ts +34 -9
- package/dist/web3/registry.js +1 -22
- package/dist/web3/vue.d.ts +31 -14
- package/dist/web3/vue.js +1 -390
- package/dist/web3/vue.js.map +1 -1
- package/package.json +36 -15
- package/dist/chunk-2HFOWE5R.js +0 -296
- package/dist/chunk-2HFOWE5R.js.map +0 -1
- package/dist/chunk-3L6LH2XK.js +0 -465
- package/dist/chunk-3L6LH2XK.js.map +0 -1
- package/dist/chunk-4CWVFPBN.js +0 -28
- package/dist/chunk-4CWVFPBN.js.map +0 -1
- package/dist/chunk-AGHPATVL.js +0 -65
- package/dist/chunk-AGHPATVL.js.map +0 -1
- package/dist/chunk-JDUYLUDJ.js +0 -4835
- package/dist/chunk-JDUYLUDJ.js.map +0 -1
- package/dist/chunk-OEZK7IX7.js +0 -77
- package/dist/chunk-OEZK7IX7.js.map +0 -1
- package/dist/chunk-PUYDAUCI.js +0 -2873
- package/dist/chunk-PUYDAUCI.js.map +0 -1
- package/dist/chunk-WHWMTS7D.js +0 -99
- package/dist/chunk-WHWMTS7D.js.map +0 -1
- package/dist/chunk-Y7RS6RTM.js +0 -342
- package/dist/chunk-Y7RS6RTM.js.map +0 -1
- package/dist/chunk-ZEZGI2TP.js +0 -197
- package/dist/chunk-ZEZGI2TP.js.map +0 -1
- package/dist/core-dao-core-logo-VDT2I5IW.svg +0 -33
- package/dist/level-state-J3pj64Tr.d.ts +0 -15
- package/dist/models/models_v2.global.js +0 -1
- package/dist/orm-BvkX0aBT.d.ts +0 -507
package/dist/chunk-PUYDAUCI.js
DELETED
|
@@ -1,2873 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
addressLoader
|
|
3
|
-
} from "./chunk-3L6LH2XK.js";
|
|
4
|
-
import {
|
|
5
|
-
getAllPatchesByUsername,
|
|
6
|
-
getNbPatches
|
|
7
|
-
} from "./chunk-ZEZGI2TP.js";
|
|
8
|
-
|
|
9
|
-
// src/web3/network/media/core-dao-core-logo.svg
|
|
10
|
-
var core_dao_core_logo_default = "./core-dao-core-logo-VDT2I5IW.svg";
|
|
11
|
-
|
|
12
|
-
// src/web3/network/chains.ts
|
|
13
|
-
import { defineChain } from "viem";
|
|
14
|
-
var EVM_CHAINS = {
|
|
15
|
-
1116: {
|
|
16
|
-
chainId: 1116,
|
|
17
|
-
name: "Core Blockchain MainNet",
|
|
18
|
-
symbol: "CORE",
|
|
19
|
-
shortName: "TREE",
|
|
20
|
-
decimals: 18,
|
|
21
|
-
explorer: "https://scan.coredao.org",
|
|
22
|
-
rpc: "https://rpc.coredao.org",
|
|
23
|
-
website: "https://coredao.org/",
|
|
24
|
-
main: true,
|
|
25
|
-
logo: core_dao_core_logo_default,
|
|
26
|
-
price: {
|
|
27
|
-
pythOracle: "0xA2aa501b19aff244D90cc15a4Cf739D2725B5729",
|
|
28
|
-
usdPriceId: "0x9b4503710cc8c53f75c30e6e4fda1a7064680ef2e0ee97acd2e3a7c37b3c830c"
|
|
29
|
-
},
|
|
30
|
-
deployed: true,
|
|
31
|
-
addresses: {
|
|
32
|
-
addressRegistry: "0x4c1759dF25AdddbdF5399D332Ac02B2E77ED90fF"
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
1114: {
|
|
36
|
-
chainId: 1114,
|
|
37
|
-
name: "Core Blockchain TestNet",
|
|
38
|
-
symbol: "tCORE2",
|
|
39
|
-
shortName: "SUN",
|
|
40
|
-
decimals: 18,
|
|
41
|
-
explorer: "https://scan.test2.btcs.network",
|
|
42
|
-
rpc: "https://rpc.test2.btcs.network",
|
|
43
|
-
website: "https://coredao.org/",
|
|
44
|
-
main: false,
|
|
45
|
-
logo: core_dao_core_logo_default,
|
|
46
|
-
price: {
|
|
47
|
-
pythOracle: "0x8D254a21b3C86D32F7179855531CE99164721933",
|
|
48
|
-
usdPriceId: "0x9b4503710cc8c53f75c30e6e4fda1a7064680ef2e0ee97acd2e3a7c37b3c830c"
|
|
49
|
-
},
|
|
50
|
-
stagingDeployed: true,
|
|
51
|
-
addresses: {
|
|
52
|
-
stagingAddressRegistry: "0x4AB2FF5fAd69eFe62e7Fce1f06FeE5cfFBC31469"
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
var DEFAULT_CHAIN_ID = 1116;
|
|
57
|
-
function getChain(chainId) {
|
|
58
|
-
const id = typeof chainId === "string" ? parseInt(chainId, 10) : chainId;
|
|
59
|
-
const chain = EVM_CHAINS[id];
|
|
60
|
-
if (!chain) throw new Error(`Chain ${chainId} not configured`);
|
|
61
|
-
return chain;
|
|
62
|
-
}
|
|
63
|
-
function toViemChain(config) {
|
|
64
|
-
return defineChain({
|
|
65
|
-
id: config.chainId,
|
|
66
|
-
name: config.name,
|
|
67
|
-
nativeCurrency: { name: config.symbol, symbol: config.symbol, decimals: config.decimals || 18 },
|
|
68
|
-
rpcUrls: { default: { http: [config.rpc] }, public: { http: [config.rpc] } }
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// src/web3/contracts/pythAbi.ts
|
|
73
|
-
var pythAbi = [
|
|
74
|
-
{
|
|
75
|
-
"inputs": [
|
|
76
|
-
{
|
|
77
|
-
"internalType": "bytes32",
|
|
78
|
-
"name": "id",
|
|
79
|
-
"type": "bytes32"
|
|
80
|
-
}
|
|
81
|
-
],
|
|
82
|
-
"name": "getPriceUnsafe",
|
|
83
|
-
"outputs": [
|
|
84
|
-
{
|
|
85
|
-
"components": [
|
|
86
|
-
{
|
|
87
|
-
"internalType": "int64",
|
|
88
|
-
"name": "price",
|
|
89
|
-
"type": "int64"
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
"internalType": "uint64",
|
|
93
|
-
"name": "conf",
|
|
94
|
-
"type": "uint64"
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
"internalType": "int32",
|
|
98
|
-
"name": "expo",
|
|
99
|
-
"type": "int32"
|
|
100
|
-
},
|
|
101
|
-
{
|
|
102
|
-
"internalType": "uint256",
|
|
103
|
-
"name": "publishTime",
|
|
104
|
-
"type": "uint256"
|
|
105
|
-
}
|
|
106
|
-
],
|
|
107
|
-
"internalType": "struct PythStructs.Price",
|
|
108
|
-
"name": "price",
|
|
109
|
-
"type": "tuple"
|
|
110
|
-
}
|
|
111
|
-
],
|
|
112
|
-
"stateMutability": "view",
|
|
113
|
-
"type": "function"
|
|
114
|
-
},
|
|
115
|
-
{
|
|
116
|
-
"inputs": [
|
|
117
|
-
{
|
|
118
|
-
"internalType": "bytes[]",
|
|
119
|
-
"name": "updateData",
|
|
120
|
-
"type": "bytes[]"
|
|
121
|
-
}
|
|
122
|
-
],
|
|
123
|
-
"name": "getUpdateFee",
|
|
124
|
-
"outputs": [
|
|
125
|
-
{
|
|
126
|
-
"internalType": "uint256",
|
|
127
|
-
"name": "feeAmount",
|
|
128
|
-
"type": "uint256"
|
|
129
|
-
}
|
|
130
|
-
],
|
|
131
|
-
"stateMutability": "view",
|
|
132
|
-
"type": "function"
|
|
133
|
-
},
|
|
134
|
-
{
|
|
135
|
-
"inputs": [
|
|
136
|
-
{
|
|
137
|
-
"internalType": "bytes[]",
|
|
138
|
-
"name": "updateData",
|
|
139
|
-
"type": "bytes[]"
|
|
140
|
-
}
|
|
141
|
-
],
|
|
142
|
-
"name": "updatePriceFeeds",
|
|
143
|
-
"outputs": [],
|
|
144
|
-
"stateMutability": "payable",
|
|
145
|
-
"type": "function"
|
|
146
|
-
}
|
|
147
|
-
];
|
|
148
|
-
|
|
149
|
-
// src/web3/contracts/addressRegistryAbi.ts
|
|
150
|
-
var addressRegistryAbi = [
|
|
151
|
-
{
|
|
152
|
-
"inputs": [],
|
|
153
|
-
"stateMutability": "nonpayable",
|
|
154
|
-
"type": "constructor"
|
|
155
|
-
},
|
|
156
|
-
{
|
|
157
|
-
"anonymous": false,
|
|
158
|
-
"inputs": [
|
|
159
|
-
{
|
|
160
|
-
"indexed": true,
|
|
161
|
-
"internalType": "address",
|
|
162
|
-
"name": "oldAdmin",
|
|
163
|
-
"type": "address"
|
|
164
|
-
},
|
|
165
|
-
{
|
|
166
|
-
"indexed": true,
|
|
167
|
-
"internalType": "address",
|
|
168
|
-
"name": "newAdmin",
|
|
169
|
-
"type": "address"
|
|
170
|
-
}
|
|
171
|
-
],
|
|
172
|
-
"name": "AdminChanged",
|
|
173
|
-
"type": "event"
|
|
174
|
-
},
|
|
175
|
-
{
|
|
176
|
-
"anonymous": false,
|
|
177
|
-
"inputs": [
|
|
178
|
-
{
|
|
179
|
-
"indexed": true,
|
|
180
|
-
"internalType": "string",
|
|
181
|
-
"name": "key",
|
|
182
|
-
"type": "string"
|
|
183
|
-
},
|
|
184
|
-
{
|
|
185
|
-
"indexed": false,
|
|
186
|
-
"internalType": "string",
|
|
187
|
-
"name": "arweaveTxId",
|
|
188
|
-
"type": "string"
|
|
189
|
-
},
|
|
190
|
-
{
|
|
191
|
-
"indexed": false,
|
|
192
|
-
"internalType": "bytes32",
|
|
193
|
-
"name": "sha256Hash",
|
|
194
|
-
"type": "bytes32"
|
|
195
|
-
},
|
|
196
|
-
{
|
|
197
|
-
"indexed": false,
|
|
198
|
-
"internalType": "uint256",
|
|
199
|
-
"name": "version",
|
|
200
|
-
"type": "uint256"
|
|
201
|
-
}
|
|
202
|
-
],
|
|
203
|
-
"name": "BlobRefAdded",
|
|
204
|
-
"type": "event"
|
|
205
|
-
},
|
|
206
|
-
{
|
|
207
|
-
"anonymous": false,
|
|
208
|
-
"inputs": [
|
|
209
|
-
{
|
|
210
|
-
"indexed": true,
|
|
211
|
-
"internalType": "string",
|
|
212
|
-
"name": "name",
|
|
213
|
-
"type": "string"
|
|
214
|
-
},
|
|
215
|
-
{
|
|
216
|
-
"indexed": true,
|
|
217
|
-
"internalType": "address",
|
|
218
|
-
"name": "contractAddress",
|
|
219
|
-
"type": "address"
|
|
220
|
-
},
|
|
221
|
-
{
|
|
222
|
-
"indexed": false,
|
|
223
|
-
"internalType": "string",
|
|
224
|
-
"name": "abiUrl",
|
|
225
|
-
"type": "string"
|
|
226
|
-
},
|
|
227
|
-
{
|
|
228
|
-
"indexed": false,
|
|
229
|
-
"internalType": "uint256",
|
|
230
|
-
"name": "version",
|
|
231
|
-
"type": "uint256"
|
|
232
|
-
}
|
|
233
|
-
],
|
|
234
|
-
"name": "ContractAdded",
|
|
235
|
-
"type": "event"
|
|
236
|
-
},
|
|
237
|
-
{
|
|
238
|
-
"anonymous": false,
|
|
239
|
-
"inputs": [
|
|
240
|
-
{
|
|
241
|
-
"indexed": true,
|
|
242
|
-
"internalType": "string",
|
|
243
|
-
"name": "key",
|
|
244
|
-
"type": "string"
|
|
245
|
-
},
|
|
246
|
-
{
|
|
247
|
-
"indexed": false,
|
|
248
|
-
"internalType": "string",
|
|
249
|
-
"name": "value",
|
|
250
|
-
"type": "string"
|
|
251
|
-
},
|
|
252
|
-
{
|
|
253
|
-
"indexed": false,
|
|
254
|
-
"internalType": "uint256",
|
|
255
|
-
"name": "version",
|
|
256
|
-
"type": "uint256"
|
|
257
|
-
}
|
|
258
|
-
],
|
|
259
|
-
"name": "DataAdded",
|
|
260
|
-
"type": "event"
|
|
261
|
-
},
|
|
262
|
-
{
|
|
263
|
-
"inputs": [
|
|
264
|
-
{
|
|
265
|
-
"internalType": "string",
|
|
266
|
-
"name": "key",
|
|
267
|
-
"type": "string"
|
|
268
|
-
},
|
|
269
|
-
{
|
|
270
|
-
"internalType": "string",
|
|
271
|
-
"name": "arweaveTxId",
|
|
272
|
-
"type": "string"
|
|
273
|
-
},
|
|
274
|
-
{
|
|
275
|
-
"internalType": "bytes32",
|
|
276
|
-
"name": "sha256Hash",
|
|
277
|
-
"type": "bytes32"
|
|
278
|
-
}
|
|
279
|
-
],
|
|
280
|
-
"name": "addBlobRef",
|
|
281
|
-
"outputs": [],
|
|
282
|
-
"stateMutability": "nonpayable",
|
|
283
|
-
"type": "function"
|
|
284
|
-
},
|
|
285
|
-
{
|
|
286
|
-
"inputs": [
|
|
287
|
-
{
|
|
288
|
-
"internalType": "string",
|
|
289
|
-
"name": "name",
|
|
290
|
-
"type": "string"
|
|
291
|
-
},
|
|
292
|
-
{
|
|
293
|
-
"internalType": "address",
|
|
294
|
-
"name": "contractAddress",
|
|
295
|
-
"type": "address"
|
|
296
|
-
},
|
|
297
|
-
{
|
|
298
|
-
"internalType": "string",
|
|
299
|
-
"name": "abiUrl",
|
|
300
|
-
"type": "string"
|
|
301
|
-
}
|
|
302
|
-
],
|
|
303
|
-
"name": "addContract",
|
|
304
|
-
"outputs": [],
|
|
305
|
-
"stateMutability": "nonpayable",
|
|
306
|
-
"type": "function"
|
|
307
|
-
},
|
|
308
|
-
{
|
|
309
|
-
"inputs": [
|
|
310
|
-
{
|
|
311
|
-
"internalType": "string",
|
|
312
|
-
"name": "key",
|
|
313
|
-
"type": "string"
|
|
314
|
-
},
|
|
315
|
-
{
|
|
316
|
-
"internalType": "string",
|
|
317
|
-
"name": "value",
|
|
318
|
-
"type": "string"
|
|
319
|
-
}
|
|
320
|
-
],
|
|
321
|
-
"name": "addData",
|
|
322
|
-
"outputs": [],
|
|
323
|
-
"stateMutability": "nonpayable",
|
|
324
|
-
"type": "function"
|
|
325
|
-
},
|
|
326
|
-
{
|
|
327
|
-
"inputs": [],
|
|
328
|
-
"name": "admin",
|
|
329
|
-
"outputs": [
|
|
330
|
-
{
|
|
331
|
-
"internalType": "address",
|
|
332
|
-
"name": "",
|
|
333
|
-
"type": "address"
|
|
334
|
-
}
|
|
335
|
-
],
|
|
336
|
-
"stateMutability": "view",
|
|
337
|
-
"type": "function"
|
|
338
|
-
},
|
|
339
|
-
{
|
|
340
|
-
"inputs": [
|
|
341
|
-
{
|
|
342
|
-
"internalType": "address",
|
|
343
|
-
"name": "newAdmin",
|
|
344
|
-
"type": "address"
|
|
345
|
-
}
|
|
346
|
-
],
|
|
347
|
-
"name": "changeAdmin",
|
|
348
|
-
"outputs": [],
|
|
349
|
-
"stateMutability": "nonpayable",
|
|
350
|
-
"type": "function"
|
|
351
|
-
},
|
|
352
|
-
{
|
|
353
|
-
"inputs": [],
|
|
354
|
-
"name": "getAllBlobRefKeys",
|
|
355
|
-
"outputs": [
|
|
356
|
-
{
|
|
357
|
-
"internalType": "string[]",
|
|
358
|
-
"name": "",
|
|
359
|
-
"type": "string[]"
|
|
360
|
-
}
|
|
361
|
-
],
|
|
362
|
-
"stateMutability": "view",
|
|
363
|
-
"type": "function"
|
|
364
|
-
},
|
|
365
|
-
{
|
|
366
|
-
"inputs": [],
|
|
367
|
-
"name": "getAllContractNames",
|
|
368
|
-
"outputs": [
|
|
369
|
-
{
|
|
370
|
-
"internalType": "string[]",
|
|
371
|
-
"name": "",
|
|
372
|
-
"type": "string[]"
|
|
373
|
-
}
|
|
374
|
-
],
|
|
375
|
-
"stateMutability": "view",
|
|
376
|
-
"type": "function"
|
|
377
|
-
},
|
|
378
|
-
{
|
|
379
|
-
"inputs": [],
|
|
380
|
-
"name": "getAllDataKeys",
|
|
381
|
-
"outputs": [
|
|
382
|
-
{
|
|
383
|
-
"internalType": "string[]",
|
|
384
|
-
"name": "",
|
|
385
|
-
"type": "string[]"
|
|
386
|
-
}
|
|
387
|
-
],
|
|
388
|
-
"stateMutability": "view",
|
|
389
|
-
"type": "function"
|
|
390
|
-
},
|
|
391
|
-
{
|
|
392
|
-
"inputs": [
|
|
393
|
-
{
|
|
394
|
-
"internalType": "string",
|
|
395
|
-
"name": "key",
|
|
396
|
-
"type": "string"
|
|
397
|
-
},
|
|
398
|
-
{
|
|
399
|
-
"internalType": "uint256",
|
|
400
|
-
"name": "offset",
|
|
401
|
-
"type": "uint256"
|
|
402
|
-
},
|
|
403
|
-
{
|
|
404
|
-
"internalType": "uint256",
|
|
405
|
-
"name": "limit",
|
|
406
|
-
"type": "uint256"
|
|
407
|
-
}
|
|
408
|
-
],
|
|
409
|
-
"name": "getBlobRefHistory",
|
|
410
|
-
"outputs": [
|
|
411
|
-
{
|
|
412
|
-
"components": [
|
|
413
|
-
{
|
|
414
|
-
"internalType": "string",
|
|
415
|
-
"name": "arweaveTxId",
|
|
416
|
-
"type": "string"
|
|
417
|
-
},
|
|
418
|
-
{
|
|
419
|
-
"internalType": "bytes32",
|
|
420
|
-
"name": "sha256Hash",
|
|
421
|
-
"type": "bytes32"
|
|
422
|
-
}
|
|
423
|
-
],
|
|
424
|
-
"internalType": "struct AddressRegistry.BlobRef[]",
|
|
425
|
-
"name": "",
|
|
426
|
-
"type": "tuple[]"
|
|
427
|
-
}
|
|
428
|
-
],
|
|
429
|
-
"stateMutability": "view",
|
|
430
|
-
"type": "function"
|
|
431
|
-
},
|
|
432
|
-
{
|
|
433
|
-
"inputs": [
|
|
434
|
-
{
|
|
435
|
-
"internalType": "string",
|
|
436
|
-
"name": "name",
|
|
437
|
-
"type": "string"
|
|
438
|
-
}
|
|
439
|
-
],
|
|
440
|
-
"name": "getContractHistory",
|
|
441
|
-
"outputs": [
|
|
442
|
-
{
|
|
443
|
-
"components": [
|
|
444
|
-
{
|
|
445
|
-
"internalType": "address",
|
|
446
|
-
"name": "contractAddress",
|
|
447
|
-
"type": "address"
|
|
448
|
-
},
|
|
449
|
-
{
|
|
450
|
-
"internalType": "string",
|
|
451
|
-
"name": "abiUrl",
|
|
452
|
-
"type": "string"
|
|
453
|
-
}
|
|
454
|
-
],
|
|
455
|
-
"internalType": "struct AddressRegistry.ContractRecord[]",
|
|
456
|
-
"name": "",
|
|
457
|
-
"type": "tuple[]"
|
|
458
|
-
}
|
|
459
|
-
],
|
|
460
|
-
"stateMutability": "view",
|
|
461
|
-
"type": "function"
|
|
462
|
-
},
|
|
463
|
-
{
|
|
464
|
-
"inputs": [
|
|
465
|
-
{
|
|
466
|
-
"internalType": "string",
|
|
467
|
-
"name": "key",
|
|
468
|
-
"type": "string"
|
|
469
|
-
}
|
|
470
|
-
],
|
|
471
|
-
"name": "getDataHistory",
|
|
472
|
-
"outputs": [
|
|
473
|
-
{
|
|
474
|
-
"internalType": "string[]",
|
|
475
|
-
"name": "",
|
|
476
|
-
"type": "string[]"
|
|
477
|
-
}
|
|
478
|
-
],
|
|
479
|
-
"stateMutability": "view",
|
|
480
|
-
"type": "function"
|
|
481
|
-
},
|
|
482
|
-
{
|
|
483
|
-
"inputs": [
|
|
484
|
-
{
|
|
485
|
-
"internalType": "string",
|
|
486
|
-
"name": "key",
|
|
487
|
-
"type": "string"
|
|
488
|
-
}
|
|
489
|
-
],
|
|
490
|
-
"name": "getLatestBlobRef",
|
|
491
|
-
"outputs": [
|
|
492
|
-
{
|
|
493
|
-
"internalType": "string",
|
|
494
|
-
"name": "",
|
|
495
|
-
"type": "string"
|
|
496
|
-
},
|
|
497
|
-
{
|
|
498
|
-
"internalType": "bytes32",
|
|
499
|
-
"name": "",
|
|
500
|
-
"type": "bytes32"
|
|
501
|
-
}
|
|
502
|
-
],
|
|
503
|
-
"stateMutability": "view",
|
|
504
|
-
"type": "function"
|
|
505
|
-
},
|
|
506
|
-
{
|
|
507
|
-
"inputs": [
|
|
508
|
-
{
|
|
509
|
-
"internalType": "string",
|
|
510
|
-
"name": "name",
|
|
511
|
-
"type": "string"
|
|
512
|
-
}
|
|
513
|
-
],
|
|
514
|
-
"name": "getLatestContract",
|
|
515
|
-
"outputs": [
|
|
516
|
-
{
|
|
517
|
-
"internalType": "address",
|
|
518
|
-
"name": "",
|
|
519
|
-
"type": "address"
|
|
520
|
-
},
|
|
521
|
-
{
|
|
522
|
-
"internalType": "string",
|
|
523
|
-
"name": "",
|
|
524
|
-
"type": "string"
|
|
525
|
-
}
|
|
526
|
-
],
|
|
527
|
-
"stateMutability": "view",
|
|
528
|
-
"type": "function"
|
|
529
|
-
},
|
|
530
|
-
{
|
|
531
|
-
"inputs": [
|
|
532
|
-
{
|
|
533
|
-
"internalType": "string",
|
|
534
|
-
"name": "key",
|
|
535
|
-
"type": "string"
|
|
536
|
-
}
|
|
537
|
-
],
|
|
538
|
-
"name": "getLatestData",
|
|
539
|
-
"outputs": [
|
|
540
|
-
{
|
|
541
|
-
"internalType": "string",
|
|
542
|
-
"name": "",
|
|
543
|
-
"type": "string"
|
|
544
|
-
}
|
|
545
|
-
],
|
|
546
|
-
"stateMutability": "view",
|
|
547
|
-
"type": "function"
|
|
548
|
-
}
|
|
549
|
-
];
|
|
550
|
-
|
|
551
|
-
// src/web3/client/EvmClient.ts
|
|
552
|
-
import { createPublicClient, http } from "viem";
|
|
553
|
-
|
|
554
|
-
// src/web3/utils/strings.ts
|
|
555
|
-
import { hexToString, stringToHex } from "viem";
|
|
556
|
-
function bytes4ToString(hex) {
|
|
557
|
-
const cleanHex = hex.startsWith("0x") ? hex : "0x" + hex;
|
|
558
|
-
return hexToString(cleanHex).replace(/\0/g, "");
|
|
559
|
-
}
|
|
560
|
-
function stringToBytes4(str) {
|
|
561
|
-
const hex = stringToHex(str);
|
|
562
|
-
return hex.padEnd(10, "0").slice(0, 10);
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
// src/web3/utils/errors.ts
|
|
566
|
-
import {
|
|
567
|
-
BaseError as ViemBaseError,
|
|
568
|
-
ContractFunctionRevertedError,
|
|
569
|
-
InsufficientFundsError,
|
|
570
|
-
NonceTooLowError,
|
|
571
|
-
TimeoutError as ViemTimeoutError,
|
|
572
|
-
UserRejectedRequestError
|
|
573
|
-
} from "viem";
|
|
574
|
-
var cbs = [];
|
|
575
|
-
var Web3Error = class _Web3Error extends Error {
|
|
576
|
-
constructor(code, message, opts) {
|
|
577
|
-
super(message);
|
|
578
|
-
this.name = "Web3Error";
|
|
579
|
-
this.code = code;
|
|
580
|
-
this.reason = opts?.reason;
|
|
581
|
-
this.data = opts?.data;
|
|
582
|
-
this.originalError = opts?.originalError;
|
|
583
|
-
Object.setPrototypeOf(this, _Web3Error.prototype);
|
|
584
|
-
}
|
|
585
|
-
};
|
|
586
|
-
function normalizeError(error) {
|
|
587
|
-
if (error instanceof Web3Error) {
|
|
588
|
-
return error;
|
|
589
|
-
}
|
|
590
|
-
const err = normalizeEVMError(error);
|
|
591
|
-
for (const cb of cbs) {
|
|
592
|
-
try {
|
|
593
|
-
cb(err);
|
|
594
|
-
} catch (cbError) {
|
|
595
|
-
console.error("[web3/errors] registerOnErrorCb listener threw", cbError);
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
return err;
|
|
599
|
-
}
|
|
600
|
-
var commonNormalization = (error) => {
|
|
601
|
-
const message = error?.message || error?.reason || String(error);
|
|
602
|
-
const messageLower = message.toLowerCase();
|
|
603
|
-
if (messageLower.includes("invalid compressedactions format")) {
|
|
604
|
-
return new Web3Error("INVALID_COMPRESSED_ACTIONS", "Invalid compressedActions format", {
|
|
605
|
-
originalError: error
|
|
606
|
-
});
|
|
607
|
-
}
|
|
608
|
-
if (messageLower.includes("switch chain error")) {
|
|
609
|
-
return new Web3Error("SWITCH_CHAIN_ERROR", "Error Switching Chains", {
|
|
610
|
-
data: error.code,
|
|
611
|
-
reason: error.message,
|
|
612
|
-
originalError: error
|
|
613
|
-
});
|
|
614
|
-
}
|
|
615
|
-
if (messageLower.includes("switching accounts while on an unsupported chainid")) {
|
|
616
|
-
return new Web3Error("SWITCH_TO_UNSUPPORTED_CHAIN", messageLower, { originalError: error });
|
|
617
|
-
}
|
|
618
|
-
return null;
|
|
619
|
-
};
|
|
620
|
-
var isRecognizedViemError = (error) => error instanceof UserRejectedRequestError || error instanceof InsufficientFundsError || error instanceof NonceTooLowError || error instanceof ViemTimeoutError || error instanceof ContractFunctionRevertedError;
|
|
621
|
-
function normalizeTypedViemError(error) {
|
|
622
|
-
if (error instanceof ViemBaseError && !isRecognizedViemError(error)) {
|
|
623
|
-
const nested = error.walk(isRecognizedViemError);
|
|
624
|
-
if (nested) {
|
|
625
|
-
return normalizeTypedViemError(nested);
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
if (error instanceof UserRejectedRequestError) {
|
|
629
|
-
return new Web3Error("USER_REJECTED", "User rejected the transaction", {
|
|
630
|
-
reason: error.shortMessage,
|
|
631
|
-
originalError: error
|
|
632
|
-
});
|
|
633
|
-
}
|
|
634
|
-
if (error instanceof InsufficientFundsError) {
|
|
635
|
-
return new Web3Error("INSUFFICIENT_FUNDS", "Insufficient funds for transaction", {
|
|
636
|
-
reason: error.shortMessage,
|
|
637
|
-
originalError: error
|
|
638
|
-
});
|
|
639
|
-
}
|
|
640
|
-
if (error instanceof NonceTooLowError) {
|
|
641
|
-
return new Web3Error("NONCE_TOO_LOW", "Transaction nonce is too low", {
|
|
642
|
-
reason: error.shortMessage,
|
|
643
|
-
originalError: error
|
|
644
|
-
});
|
|
645
|
-
}
|
|
646
|
-
if (error instanceof ViemTimeoutError) {
|
|
647
|
-
return new Web3Error("TIMEOUT", "Request timed out", {
|
|
648
|
-
reason: error.shortMessage,
|
|
649
|
-
originalError: error
|
|
650
|
-
});
|
|
651
|
-
}
|
|
652
|
-
if (error instanceof ContractFunctionRevertedError) {
|
|
653
|
-
return new Web3Error("REVERT", "Transaction reverted by contract", {
|
|
654
|
-
reason: error.reason ?? error.data?.errorName ?? error.shortMessage,
|
|
655
|
-
data: error.data,
|
|
656
|
-
originalError: error
|
|
657
|
-
});
|
|
658
|
-
}
|
|
659
|
-
return null;
|
|
660
|
-
}
|
|
661
|
-
function normalizeEVMError(error) {
|
|
662
|
-
const common = commonNormalization(error);
|
|
663
|
-
if (common) {
|
|
664
|
-
return common;
|
|
665
|
-
}
|
|
666
|
-
const typed = normalizeTypedViemError(error);
|
|
667
|
-
if (typed) {
|
|
668
|
-
return typed;
|
|
669
|
-
}
|
|
670
|
-
const message = error?.message || error?.reason || String(error);
|
|
671
|
-
const messageLower = message.toLowerCase();
|
|
672
|
-
if (messageLower.includes("no account connected to wallet")) {
|
|
673
|
-
return new Web3Error("NO_WALLET_CONNECTED", "No account connected to wallet", { originalError: error });
|
|
674
|
-
}
|
|
675
|
-
if (messageLower.includes("user rejected") || messageLower.includes("user denied") || messageLower.includes("user cancelled") || error?.code === 4001 || error?.code === "ACTION_REJECTED") {
|
|
676
|
-
return new Web3Error("USER_REJECTED", "User rejected the transaction", {
|
|
677
|
-
reason: error?.reason,
|
|
678
|
-
originalError: error
|
|
679
|
-
});
|
|
680
|
-
}
|
|
681
|
-
if (messageLower.includes("insufficient funds") || messageLower.includes("insufficient balance") || error?.code === "INSUFFICIENT_FUNDS") {
|
|
682
|
-
return new Web3Error("INSUFFICIENT_FUNDS", "Insufficient funds for transaction", {
|
|
683
|
-
reason: error?.reason,
|
|
684
|
-
originalError: error
|
|
685
|
-
});
|
|
686
|
-
}
|
|
687
|
-
if (messageLower.includes("nonce too low") || messageLower.includes("nonce has already been used") || error?.code === "NONCE_EXPIRED") {
|
|
688
|
-
return new Web3Error("NONCE_TOO_LOW", "Transaction nonce is too low", {
|
|
689
|
-
reason: error?.reason,
|
|
690
|
-
originalError: error
|
|
691
|
-
});
|
|
692
|
-
}
|
|
693
|
-
if (messageLower.includes("revert") || messageLower.includes("execution reverted") || error?.code === "CALL_EXCEPTION" || error?.code === 3) {
|
|
694
|
-
return new Web3Error("REVERT", "Transaction reverted by contract", {
|
|
695
|
-
reason: error?.reason || extractRevertReason(error),
|
|
696
|
-
data: error?.data,
|
|
697
|
-
originalError: error
|
|
698
|
-
});
|
|
699
|
-
}
|
|
700
|
-
if (messageLower.includes("timeout") || error?.code === "TIMEOUT") {
|
|
701
|
-
return new Web3Error("TIMEOUT", "Request timed out", {
|
|
702
|
-
reason: error?.reason,
|
|
703
|
-
originalError: error
|
|
704
|
-
});
|
|
705
|
-
}
|
|
706
|
-
if (messageLower.includes("network") || messageLower.includes("connection") || error?.code === "NETWORK_ERROR" || error?.code === "ETIMEDOUT") {
|
|
707
|
-
return new Web3Error("NETWORK_ERROR", "Network error occurred", {
|
|
708
|
-
reason: error?.reason,
|
|
709
|
-
originalError: error
|
|
710
|
-
});
|
|
711
|
-
}
|
|
712
|
-
if (messageLower.includes("invalid argument") || error?.code === "INVALID_ARGUMENT") {
|
|
713
|
-
return new Web3Error("INVALID_ARGUMENT", "Invalid argument provided", {
|
|
714
|
-
reason: error?.reason,
|
|
715
|
-
originalError: error
|
|
716
|
-
});
|
|
717
|
-
}
|
|
718
|
-
if (messageLower.includes("unsupported") || error?.code === "UNSUPPORTED_OPERATION") {
|
|
719
|
-
return new Web3Error("UNSUPPORTED_OPERATION", "Unsupported operation", {
|
|
720
|
-
reason: error?.reason,
|
|
721
|
-
originalError: error
|
|
722
|
-
});
|
|
723
|
-
}
|
|
724
|
-
return new Web3Error("UNKNOWN", message || "Unknown error occurred", {
|
|
725
|
-
reason: error?.reason,
|
|
726
|
-
data: error?.data,
|
|
727
|
-
originalError: error
|
|
728
|
-
});
|
|
729
|
-
}
|
|
730
|
-
function extractRevertReason(error) {
|
|
731
|
-
if (error?.reason) return error.reason;
|
|
732
|
-
if (error?.data?.message) return error.data.message;
|
|
733
|
-
const message = error?.message || "";
|
|
734
|
-
const revertMatch = message.match(/revert\s+(.+?)(?:\s|$|")/i);
|
|
735
|
-
if (revertMatch) return revertMatch[1];
|
|
736
|
-
return void 0;
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
// src/web3/client/EvmClient.ts
|
|
740
|
-
var toActionsTuple = (result) => [
|
|
741
|
-
(result?.[0] || []).map((x) => BigInt(x)),
|
|
742
|
-
(result?.[1] || []).map((x) => BigInt(x)),
|
|
743
|
-
(result?.[2] || []).map(String)
|
|
744
|
-
];
|
|
745
|
-
var toStripeDonation = (d) => ({
|
|
746
|
-
stripePaymentId: String(d.stripePaymentId ?? d[0]),
|
|
747
|
-
amountUSD: BigInt(d.amountUSD ?? d[1]),
|
|
748
|
-
username: String(d.username ?? d[2]),
|
|
749
|
-
donor: String(d.donor ?? d[3]),
|
|
750
|
-
country: String(d.country ?? d[4]),
|
|
751
|
-
language: String(d.language ?? d[5]),
|
|
752
|
-
timestamp: Number(d.timestamp ?? d[6]),
|
|
753
|
-
chainId: Number(d.chainId ?? d[7])
|
|
754
|
-
});
|
|
755
|
-
var EvmClient = class {
|
|
756
|
-
constructor(chainId, environment = "production") {
|
|
757
|
-
this._contractAddresses = {};
|
|
758
|
-
this.chainId = chainId;
|
|
759
|
-
this.environment = environment;
|
|
760
|
-
const chainConfig = getChain(chainId);
|
|
761
|
-
this.config = chainConfig;
|
|
762
|
-
const isDeployed = environment === "staging" ? chainConfig.stagingDeployed : chainConfig.deployed;
|
|
763
|
-
if (!isDeployed) {
|
|
764
|
-
throw new Error(`Chain EVM ${chainId} is not deployed for environment ${environment}`);
|
|
765
|
-
}
|
|
766
|
-
this.chain = toViemChain(chainConfig);
|
|
767
|
-
this.publicClient = createPublicClient({
|
|
768
|
-
chain: this.chain,
|
|
769
|
-
transport: http(chainConfig.rpc)
|
|
770
|
-
});
|
|
771
|
-
this.addressRegistry = this.createAddressRegistryReadAPI();
|
|
772
|
-
this.bouncerStorage = this.createBouncerStorageReadAPI();
|
|
773
|
-
this.scientistStorage = this.createScientistStorageReadAPI();
|
|
774
|
-
this.archivistStorage = this.createArchivistReadApi();
|
|
775
|
-
this.factory = this.createFactoryReadAPI();
|
|
776
|
-
this.projectManagerStorage = this.createProjectManagerStorageReadAPI();
|
|
777
|
-
this.subscriptionManager = this.createSubscriptionManagerReadAPI();
|
|
778
|
-
this.libraryRegistryStorage = this.createLibraryRegistryStorageReadAPI();
|
|
779
|
-
this.publicLibraryStorage = this.createPublicLibraryStorageReadAPI();
|
|
780
|
-
this._contractAddresses = { ...chainConfig.addresses || {} };
|
|
781
|
-
this.ready = new Promise(async (resolve, reject) => {
|
|
782
|
-
try {
|
|
783
|
-
console.log(`[EvmClient] Initializing registry for chain ${this.chainId} (env: ${this.environment})...`);
|
|
784
|
-
const staleAddresses = await addressLoader.Initialize(
|
|
785
|
-
this.chainId,
|
|
786
|
-
this.addressRegistry,
|
|
787
|
-
this.activeRegistryAddress,
|
|
788
|
-
true,
|
|
789
|
-
this.environment
|
|
790
|
-
);
|
|
791
|
-
Object.assign(this._contractAddresses, staleAddresses);
|
|
792
|
-
const freshAddresses = await addressLoader.loadAllKeys(this.chainId, this.environment);
|
|
793
|
-
Object.assign(this._contractAddresses, freshAddresses);
|
|
794
|
-
await addressLoader.waitForAbis(this.chainId, this.environment);
|
|
795
|
-
console.log(`[EvmClient] Registry ready for ${this.chainId}. Addresses:`, this._contractAddresses);
|
|
796
|
-
resolve();
|
|
797
|
-
} catch (e) {
|
|
798
|
-
console.error(`[EvmClient] Failed to initialize registry for ${this.chainId}`, e);
|
|
799
|
-
reject(e);
|
|
800
|
-
}
|
|
801
|
-
});
|
|
802
|
-
}
|
|
803
|
-
async getUsdPrice() {
|
|
804
|
-
const { price } = this.config;
|
|
805
|
-
if (price.stable) {
|
|
806
|
-
return 1;
|
|
807
|
-
}
|
|
808
|
-
const { pythOracle, usdPriceId } = price;
|
|
809
|
-
if (!pythOracle || !usdPriceId) {
|
|
810
|
-
throw new Error(`Pyth config missing for chain ${this.chainId}`);
|
|
811
|
-
}
|
|
812
|
-
const fetchFromHermes = async () => {
|
|
813
|
-
const res = await fetch(`https://hermes.pyth.network/v2/updates/price/latest?ids[]=${usdPriceId}`);
|
|
814
|
-
if (!res.ok) throw new Error(`Hermes price fetch failed: ${res.status}`);
|
|
815
|
-
const data = await res.json();
|
|
816
|
-
const parsedPrice = data.parsed?.[0]?.price;
|
|
817
|
-
if (!parsedPrice) throw new Error(`No price data from Hermes for ${usdPriceId}`);
|
|
818
|
-
return Number(parsedPrice.price) * Math.pow(10, Number(parsedPrice.expo));
|
|
819
|
-
};
|
|
820
|
-
if (!this.config.main) {
|
|
821
|
-
return fetchFromHermes();
|
|
822
|
-
}
|
|
823
|
-
try {
|
|
824
|
-
const result = await this.publicClient.readContract({
|
|
825
|
-
address: pythOracle,
|
|
826
|
-
abi: pythAbi,
|
|
827
|
-
functionName: "getPriceUnsafe",
|
|
828
|
-
args: [usdPriceId]
|
|
829
|
-
});
|
|
830
|
-
return Number(result.price) * Math.pow(10, Number(result.expo));
|
|
831
|
-
} catch (e) {
|
|
832
|
-
console.warn(`[EvmClient] On-chain Pyth unavailable for chain ${this.chainId}, falling back to Hermes`);
|
|
833
|
-
return fetchFromHermes();
|
|
834
|
-
}
|
|
835
|
-
}
|
|
836
|
-
get activeRegistryAddress() {
|
|
837
|
-
return (this.environment === "staging" && this.config.addresses?.stagingAddressRegistry ? this.config.addresses.stagingAddressRegistry : this.config.addresses?.addressRegistry) ?? "";
|
|
838
|
-
}
|
|
839
|
-
addresses() {
|
|
840
|
-
return this._contractAddresses;
|
|
841
|
-
}
|
|
842
|
-
// Shared read path for every registry-fetched contract (§4.2a): resolves the
|
|
843
|
-
// address, fetches the ABI via addressLoader (never a static import), reads,
|
|
844
|
-
// and normalizes errors. Collapses what used to be ~15 lines of repeated
|
|
845
|
-
// boilerplate per method (await ready / resolve address / try readContract /
|
|
846
|
-
// catch normalizeError) into one call. Not used by createAddressRegistryReadAPI
|
|
847
|
-
// (bootstrap exception, §4.2a — its own ABI is static and it must not await
|
|
848
|
-
// `ready`) or by methods with genuinely different failure semantics
|
|
849
|
-
// (`hasAccount` swallows errors and returns false instead of throwing).
|
|
850
|
-
// Mirrors EvmWriteClient.requireAbi (§4.2a) — throws an actionable error
|
|
851
|
-
// instead of letting a null ABI reach viem's readContract, which would
|
|
852
|
-
// otherwise fail deep inside viem with an opaque error (or silently
|
|
853
|
-
// misbehave) rather than pointing at the real cause: ABIs not yet synced.
|
|
854
|
-
requireAbi(contractName) {
|
|
855
|
-
const abi = addressLoader.getAbi(this.chainId, contractName, this.environment);
|
|
856
|
-
if (!abi) {
|
|
857
|
-
throw new Error(
|
|
858
|
-
`[EvmClient] ABI for '${contractName}' on chain ${this.chainId} is not loaded. The registry ABI sync may have failed or not completed. Reads are blocked until it is ready.`
|
|
859
|
-
);
|
|
860
|
-
}
|
|
861
|
-
return abi;
|
|
862
|
-
}
|
|
863
|
-
async read(opts) {
|
|
864
|
-
await this.ready;
|
|
865
|
-
const address = this.addresses()[opts.contractKey];
|
|
866
|
-
if (!address) {
|
|
867
|
-
if (opts.whenAddressMissing !== void 0) return opts.whenAddressMissing;
|
|
868
|
-
throw new Error(`[EvmClient] ${String(opts.contractKey)} address missing for chain ${this.chainId}`);
|
|
869
|
-
}
|
|
870
|
-
try {
|
|
871
|
-
const result = await this.publicClient.readContract({
|
|
872
|
-
address,
|
|
873
|
-
abi: this.requireAbi(opts.contractName),
|
|
874
|
-
functionName: opts.functionName,
|
|
875
|
-
args: opts.args ?? []
|
|
876
|
-
});
|
|
877
|
-
return opts.transform ? opts.transform(result) : result;
|
|
878
|
-
} catch (error) {
|
|
879
|
-
throw normalizeError(error);
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
// Bootstrap exception (§4.2a): uses the statically-imported addressRegistryAbi, not
|
|
883
|
-
// addressLoader.getAbi(). addressLoader.Initialize() below calls into this API to fetch
|
|
884
|
-
// every other contract's address/ABI — the registry's own ABI can't come from itself.
|
|
885
|
-
// Must not await `this.ready` either, for the same reason — this is why it doesn't
|
|
886
|
-
// go through the shared `read()` helper above.
|
|
887
|
-
createAddressRegistryReadAPI() {
|
|
888
|
-
return {
|
|
889
|
-
getLatestContract: async (name) => {
|
|
890
|
-
const address = this.activeRegistryAddress;
|
|
891
|
-
if (!address) throw new Error(`[EvmClient] addressRegistry address missing for chain ${this.chainId}`);
|
|
892
|
-
const result = await this.publicClient.readContract({
|
|
893
|
-
address,
|
|
894
|
-
abi: addressRegistryAbi,
|
|
895
|
-
functionName: "getLatestContract",
|
|
896
|
-
args: [name]
|
|
897
|
-
});
|
|
898
|
-
return [result[0], result[1]];
|
|
899
|
-
},
|
|
900
|
-
getContractHistory: async (name) => {
|
|
901
|
-
const address = this.activeRegistryAddress;
|
|
902
|
-
if (!address) throw new Error(`[EvmClient] addressRegistry address missing for chain ${this.chainId}`);
|
|
903
|
-
const result = await this.publicClient.readContract({
|
|
904
|
-
address,
|
|
905
|
-
abi: addressRegistryAbi,
|
|
906
|
-
functionName: "getContractHistory",
|
|
907
|
-
args: [name]
|
|
908
|
-
});
|
|
909
|
-
return result;
|
|
910
|
-
},
|
|
911
|
-
getAllContractNames: async () => {
|
|
912
|
-
const address = this.activeRegistryAddress;
|
|
913
|
-
if (!address) throw new Error(`[EvmClient] addressRegistry address missing for chain ${this.chainId}`);
|
|
914
|
-
const result = await this.publicClient.readContract({
|
|
915
|
-
address,
|
|
916
|
-
abi: addressRegistryAbi,
|
|
917
|
-
functionName: "getAllContractNames",
|
|
918
|
-
args: []
|
|
919
|
-
});
|
|
920
|
-
return result;
|
|
921
|
-
},
|
|
922
|
-
getLatestData: async (key) => {
|
|
923
|
-
const address = this.activeRegistryAddress;
|
|
924
|
-
if (!address) throw new Error(`[EvmClient] addressRegistry address missing for chain ${this.chainId}`);
|
|
925
|
-
const result = await this.publicClient.readContract({
|
|
926
|
-
address,
|
|
927
|
-
abi: addressRegistryAbi,
|
|
928
|
-
functionName: "getLatestData",
|
|
929
|
-
args: [key]
|
|
930
|
-
});
|
|
931
|
-
return String(result);
|
|
932
|
-
},
|
|
933
|
-
getAllDataKeys: async () => {
|
|
934
|
-
const address = this.activeRegistryAddress;
|
|
935
|
-
if (!address) throw new Error(`[EvmClient] addressRegistry address missing for chain ${this.chainId}`);
|
|
936
|
-
const result = await this.publicClient.readContract({
|
|
937
|
-
address,
|
|
938
|
-
abi: addressRegistryAbi,
|
|
939
|
-
functionName: "getAllDataKeys",
|
|
940
|
-
args: []
|
|
941
|
-
});
|
|
942
|
-
return result;
|
|
943
|
-
},
|
|
944
|
-
admin: async () => {
|
|
945
|
-
const address = this.activeRegistryAddress;
|
|
946
|
-
if (!address) throw new Error(`[EvmClient] addressRegistry address missing for chain ${this.chainId}`);
|
|
947
|
-
const result = await this.publicClient.readContract({
|
|
948
|
-
address,
|
|
949
|
-
abi: addressRegistryAbi,
|
|
950
|
-
functionName: "admin",
|
|
951
|
-
args: []
|
|
952
|
-
});
|
|
953
|
-
return String(result);
|
|
954
|
-
},
|
|
955
|
-
getLastUpdateInfo: async (name) => {
|
|
956
|
-
const address = this.activeRegistryAddress;
|
|
957
|
-
if (!address) return null;
|
|
958
|
-
try {
|
|
959
|
-
const logs = await this.publicClient.getLogs({
|
|
960
|
-
address,
|
|
961
|
-
event: {
|
|
962
|
-
type: "event",
|
|
963
|
-
name: "ContractAdded",
|
|
964
|
-
inputs: [
|
|
965
|
-
{ type: "string", name: "name", indexed: true },
|
|
966
|
-
{ type: "address", name: "contractAddress", indexed: true },
|
|
967
|
-
{ type: "string", name: "abiUrl" },
|
|
968
|
-
{ type: "uint256", name: "version" }
|
|
969
|
-
]
|
|
970
|
-
},
|
|
971
|
-
args: { name },
|
|
972
|
-
fromBlock: 0n
|
|
973
|
-
});
|
|
974
|
-
if (logs.length === 0) return null;
|
|
975
|
-
const lastLog = logs[logs.length - 1];
|
|
976
|
-
const block = await this.publicClient.getBlock({ blockNumber: lastLog.blockNumber });
|
|
977
|
-
return {
|
|
978
|
-
timestamp: Number(block.timestamp),
|
|
979
|
-
blockNumber: lastLog.blockNumber,
|
|
980
|
-
transactionHash: lastLog.transactionHash
|
|
981
|
-
};
|
|
982
|
-
} catch (e) {
|
|
983
|
-
console.error(`[EvmClient] Failed to get last update info for ${name}:`, e);
|
|
984
|
-
return null;
|
|
985
|
-
}
|
|
986
|
-
}
|
|
987
|
-
};
|
|
988
|
-
}
|
|
989
|
-
createArchivistReadApi() {
|
|
990
|
-
const contractKey = "backupStorage";
|
|
991
|
-
const contractName = "BackupStorage";
|
|
992
|
-
return {
|
|
993
|
-
userLevel: (userId) => this.read({ contractKey, contractName, functionName: "userLevel", args: [userId], transform: Number }),
|
|
994
|
-
isAuthorized: (userAddress) => this.read({ contractKey, contractName, functionName: "isAuthorized", args: [userAddress], transform: Boolean }),
|
|
995
|
-
nbWrites: (userId) => this.read({ contractKey, contractName, functionName: "nbWrites", args: [userId], transform: Number }),
|
|
996
|
-
loadActions: (userId) => this.read({ contractKey, contractName, functionName: "loadActions", args: [userId], transform: toActionsTuple }),
|
|
997
|
-
loadActionsSince: (userId, index) => this.read({ contractKey, contractName, functionName: "loadActionsSince", args: [userId, index], transform: toActionsTuple })
|
|
998
|
-
};
|
|
999
|
-
}
|
|
1000
|
-
createProjectManagerStorageReadAPI() {
|
|
1001
|
-
return {
|
|
1002
|
-
nbProjects: async () => {
|
|
1003
|
-
await this.ready;
|
|
1004
|
-
const factoryAddress = this.addresses().factory;
|
|
1005
|
-
if (!factoryAddress) {
|
|
1006
|
-
console.error("[EvmClient] Factory address missing in config!");
|
|
1007
|
-
return 0;
|
|
1008
|
-
}
|
|
1009
|
-
try {
|
|
1010
|
-
return await this.read({ contractKey: "factory", contractName: "Factory", functionName: "nbProjects", transform: Number });
|
|
1011
|
-
} catch (error) {
|
|
1012
|
-
console.error("[EvmClient] nbProjects failed:", error);
|
|
1013
|
-
throw error;
|
|
1014
|
-
}
|
|
1015
|
-
},
|
|
1016
|
-
balanceOfAddress: (account) => this.read({
|
|
1017
|
-
contractKey: "projectManagerStorage",
|
|
1018
|
-
contractName: "ProjectManagerStorage",
|
|
1019
|
-
functionName: "getUserBalances",
|
|
1020
|
-
args: [account],
|
|
1021
|
-
transform: (result) => ({
|
|
1022
|
-
total: Number(result[0]),
|
|
1023
|
-
donations: Number(result[1]),
|
|
1024
|
-
unspent: Number(result[2])
|
|
1025
|
-
})
|
|
1026
|
-
}),
|
|
1027
|
-
loadProject: (projectId) => this.read({
|
|
1028
|
-
contractKey: "factory",
|
|
1029
|
-
contractName: "Factory",
|
|
1030
|
-
functionName: "getProject",
|
|
1031
|
-
args: [projectId],
|
|
1032
|
-
transform: (result) => ({
|
|
1033
|
-
id: projectId,
|
|
1034
|
-
balance: Number(result[1]),
|
|
1035
|
-
versions: result[2].map((version) => {
|
|
1036
|
-
version.publicationDate = new Date(Number(version.publicationDate) * 1e3);
|
|
1037
|
-
version.maximumFunding = Number(version.maximumFunding);
|
|
1038
|
-
version.minimumFundingBeforeStartWork = Number(version.minimumFundingBeforeStartWork);
|
|
1039
|
-
version.tags = version.tags.map(Number);
|
|
1040
|
-
version.status = Number(version.status);
|
|
1041
|
-
return version;
|
|
1042
|
-
}),
|
|
1043
|
-
availableLanguages: result[3].map((lang) => bytes4ToString(lang))
|
|
1044
|
-
})
|
|
1045
|
-
}),
|
|
1046
|
-
addressDonationsPerProject: (account) => this.read({
|
|
1047
|
-
contractKey: "factory",
|
|
1048
|
-
contractName: "Factory",
|
|
1049
|
-
functionName: "addressDonationsPerProject",
|
|
1050
|
-
args: [account],
|
|
1051
|
-
transform: (result) => result.map(Number)
|
|
1052
|
-
}),
|
|
1053
|
-
getProjectSupportedLanguages: (projectId) => this.read({
|
|
1054
|
-
contractKey: "factory",
|
|
1055
|
-
contractName: "Factory",
|
|
1056
|
-
functionName: "getProjectSupportedLanguages",
|
|
1057
|
-
args: [projectId],
|
|
1058
|
-
transform: (result) => result.map(String)
|
|
1059
|
-
}),
|
|
1060
|
-
// NOTE: interface declares Promise<number> but this actually returns number[]
|
|
1061
|
-
// (pre-existing mismatch, previously masked by an `any`-typed intermediate —
|
|
1062
|
-
// preserved as-is here rather than silently changed).
|
|
1063
|
-
projectVotingBalances: (projectId) => this.read({
|
|
1064
|
-
contractKey: "factory",
|
|
1065
|
-
contractName: "Factory",
|
|
1066
|
-
functionName: "getProjectAllocatedBudget",
|
|
1067
|
-
args: [projectId],
|
|
1068
|
-
transform: (result) => result.map(Number)
|
|
1069
|
-
}),
|
|
1070
|
-
getWeeklyDonations: (weekNum) => this.read({
|
|
1071
|
-
contractKey: "projectManagerStorage",
|
|
1072
|
-
contractName: "ProjectManagerStorage",
|
|
1073
|
-
functionName: "getWeeklyDonations",
|
|
1074
|
-
args: [BigInt(weekNum)],
|
|
1075
|
-
transform: (result) => result.map(toStripeDonation)
|
|
1076
|
-
}),
|
|
1077
|
-
getDonationsRange: (fromWeek, toWeek) => this.read({
|
|
1078
|
-
contractKey: "projectManagerStorage",
|
|
1079
|
-
contractName: "ProjectManagerStorage",
|
|
1080
|
-
functionName: "getDonationsRange",
|
|
1081
|
-
args: [BigInt(fromWeek), BigInt(toWeek)],
|
|
1082
|
-
transform: (result) => result.map(toStripeDonation)
|
|
1083
|
-
}),
|
|
1084
|
-
isAuthorized: (userAddress) => this.read({
|
|
1085
|
-
contractKey: "projectManagerStorage",
|
|
1086
|
-
contractName: "ProjectManagerStorage",
|
|
1087
|
-
functionName: "isAuthorized",
|
|
1088
|
-
args: [userAddress],
|
|
1089
|
-
transform: Boolean
|
|
1090
|
-
}),
|
|
1091
|
-
admin: () => this.read({
|
|
1092
|
-
contractKey: "projectManagerStorage",
|
|
1093
|
-
contractName: "ProjectManagerStorage",
|
|
1094
|
-
functionName: "admin",
|
|
1095
|
-
transform: String
|
|
1096
|
-
}),
|
|
1097
|
-
getNbLanguages: (projectId) => this.read({
|
|
1098
|
-
contractKey: "projectManagerStorage",
|
|
1099
|
-
contractName: "ProjectManagerStorage",
|
|
1100
|
-
functionName: "getNbLanguages",
|
|
1101
|
-
args: [projectId],
|
|
1102
|
-
transform: Number
|
|
1103
|
-
}),
|
|
1104
|
-
getLanguageAtIndex: (projectId, index) => this.read({
|
|
1105
|
-
contractKey: "projectManagerStorage",
|
|
1106
|
-
contractName: "ProjectManagerStorage",
|
|
1107
|
-
functionName: "getLanguageAtIndex",
|
|
1108
|
-
args: [projectId, index],
|
|
1109
|
-
transform: (result) => bytes4ToString(result)
|
|
1110
|
-
}),
|
|
1111
|
-
getNbVersions: (projectId, lang) => this.read({
|
|
1112
|
-
contractKey: "projectManagerStorage",
|
|
1113
|
-
contractName: "ProjectManagerStorage",
|
|
1114
|
-
functionName: "getNbVersions",
|
|
1115
|
-
args: [projectId, stringToBytes4(lang)],
|
|
1116
|
-
transform: Number
|
|
1117
|
-
}),
|
|
1118
|
-
getVersion: (projectId, lang, versionNumber) => this.read({
|
|
1119
|
-
contractKey: "projectManagerStorage",
|
|
1120
|
-
contractName: "ProjectManagerStorage",
|
|
1121
|
-
functionName: "getVersion",
|
|
1122
|
-
args: [projectId, stringToBytes4(lang), versionNumber],
|
|
1123
|
-
transform: (result) => ({
|
|
1124
|
-
uri: result.uri,
|
|
1125
|
-
publicationDate: new Date(Number(result.publicationDate) * 1e3),
|
|
1126
|
-
name: result.name,
|
|
1127
|
-
headline: result.headline,
|
|
1128
|
-
descriptionMarkdown: result.descriptionMarkdown,
|
|
1129
|
-
arweaveAddressLogo: result.arweaveAddressLogo,
|
|
1130
|
-
arweaveAddressBanner: result.arweaveAddressBanner,
|
|
1131
|
-
minimumFundingBeforeStartWork: Number(result.minimumFundingBeforeStartWork),
|
|
1132
|
-
maximumFunding: Number(result.maximumFunding),
|
|
1133
|
-
tags: result.tags.map(Number),
|
|
1134
|
-
status: Number(result.status),
|
|
1135
|
-
complexity: Number(result.complexity)
|
|
1136
|
-
})
|
|
1137
|
-
}),
|
|
1138
|
-
getVotingBalance: (projectId, lang) => this.read({
|
|
1139
|
-
contractKey: "projectManagerStorage",
|
|
1140
|
-
contractName: "ProjectManagerStorage",
|
|
1141
|
-
functionName: "getVotingBalance",
|
|
1142
|
-
args: [projectId, stringToBytes4(lang)]
|
|
1143
|
-
}),
|
|
1144
|
-
getUserBalances: (address) => this.read({
|
|
1145
|
-
contractKey: "projectManagerStorage",
|
|
1146
|
-
contractName: "ProjectManagerStorage",
|
|
1147
|
-
functionName: "getUserBalances",
|
|
1148
|
-
args: [address],
|
|
1149
|
-
transform: (result) => [BigInt(result[0]), BigInt(result[1]), BigInt(result[2])]
|
|
1150
|
-
})
|
|
1151
|
-
};
|
|
1152
|
-
}
|
|
1153
|
-
createBouncerStorageReadAPI() {
|
|
1154
|
-
const contractKey = "bouncerStorage";
|
|
1155
|
-
const contractName = "BouncerStorage";
|
|
1156
|
-
return {
|
|
1157
|
-
hasAccount: async (userAddress) => {
|
|
1158
|
-
await this.ready;
|
|
1159
|
-
const address = this.addresses().bouncerStorage;
|
|
1160
|
-
if (!address) return false;
|
|
1161
|
-
try {
|
|
1162
|
-
const abi = addressLoader.getAbi(this.chainId, contractName, this.environment);
|
|
1163
|
-
if (!abi) return false;
|
|
1164
|
-
const result = await this.publicClient.readContract({ address, abi, functionName: "hasAccount", args: [userAddress] });
|
|
1165
|
-
return Boolean(result);
|
|
1166
|
-
} catch (error) {
|
|
1167
|
-
console.error(`[EvmClient] hasAccount FAILED for ${userAddress} (returning false):`, error);
|
|
1168
|
-
return false;
|
|
1169
|
-
}
|
|
1170
|
-
},
|
|
1171
|
-
userInfos: (userAddress) => this.read({
|
|
1172
|
-
contractKey,
|
|
1173
|
-
contractName,
|
|
1174
|
-
functionName: "userInfos",
|
|
1175
|
-
args: [userAddress],
|
|
1176
|
-
transform: (result) => [
|
|
1177
|
-
String((result.username ?? result[0]) || ""),
|
|
1178
|
-
String((result.country ?? result[1]) || ""),
|
|
1179
|
-
String((result.language ?? result[2]) || ""),
|
|
1180
|
-
Number((result.newUserId ?? result[3]) || 0)
|
|
1181
|
-
]
|
|
1182
|
-
}),
|
|
1183
|
-
userData: (userId) => this.read({
|
|
1184
|
-
contractKey,
|
|
1185
|
-
contractName,
|
|
1186
|
-
functionName: "userData",
|
|
1187
|
-
args: [userId],
|
|
1188
|
-
transform: (result) => [
|
|
1189
|
-
Number(result.id ?? result[0]),
|
|
1190
|
-
String(result.addr ?? result[1]),
|
|
1191
|
-
String(result.username ?? result[2]),
|
|
1192
|
-
String(result.language ?? result[3]),
|
|
1193
|
-
String(result.country ?? result[4])
|
|
1194
|
-
]
|
|
1195
|
-
}),
|
|
1196
|
-
userIdOf: (userAddress) => this.read({ contractKey, contractName, functionName: "userIdOf", args: [userAddress], transform: Number }),
|
|
1197
|
-
userIdToUsername: (userId) => this.read({ contractKey, contractName, functionName: "userIdToUsername", args: [BigInt(userId)], transform: String }),
|
|
1198
|
-
userAddr: (userId) => this.read({ contractKey, contractName, functionName: "userAddr", args: [BigInt(userId)], transform: String }),
|
|
1199
|
-
getUsernameByAddress: (userAddress) => this.read({ contractKey, contractName, functionName: "getUsernameByAddress", args: [userAddress], transform: String }),
|
|
1200
|
-
getAccountCountByCountryLanguage: (country, language) => this.read({
|
|
1201
|
-
contractKey,
|
|
1202
|
-
contractName,
|
|
1203
|
-
functionName: "getAccountCountByCountryLanguage",
|
|
1204
|
-
args: [country, language],
|
|
1205
|
-
transform: Number
|
|
1206
|
-
}),
|
|
1207
|
-
nbAccounts: () => this.read({ contractKey, contractName, functionName: "nbAccounts", transform: Number }),
|
|
1208
|
-
getAllLocationCounts: () => this.read({
|
|
1209
|
-
contractKey,
|
|
1210
|
-
contractName,
|
|
1211
|
-
functionName: "getAllLocationCounts",
|
|
1212
|
-
transform: (result) => result.map((data) => ({
|
|
1213
|
-
country: String(data.country ?? data[0]),
|
|
1214
|
-
language: String(data.language ?? data[1]),
|
|
1215
|
-
count: Number(data.count ?? data[2])
|
|
1216
|
-
}))
|
|
1217
|
-
}),
|
|
1218
|
-
getActiveLocationCount: () => this.read({ contractKey, contractName, functionName: "getActiveLocationCount", transform: Number }),
|
|
1219
|
-
identityStats: () => this.read({
|
|
1220
|
-
contractKey,
|
|
1221
|
-
contractName,
|
|
1222
|
-
functionName: "identityStats",
|
|
1223
|
-
transform: (result) => [Number(result[0]), Number(result[1])]
|
|
1224
|
-
}),
|
|
1225
|
-
isAuthorized: (userAddress) => this.read({ contractKey, contractName, functionName: "isAuthorized", args: [userAddress], transform: Boolean }),
|
|
1226
|
-
getLatestRegisteredUser: async () => {
|
|
1227
|
-
try {
|
|
1228
|
-
const count = await this.bouncerStorage.nbAccounts();
|
|
1229
|
-
if (count === 0) return null;
|
|
1230
|
-
return await this.bouncerStorage.userAddr(count);
|
|
1231
|
-
} catch (error) {
|
|
1232
|
-
console.error("[EvmClient] getLatestRegisteredUser FAILED:", error);
|
|
1233
|
-
return null;
|
|
1234
|
-
}
|
|
1235
|
-
},
|
|
1236
|
-
getTokenName: () => this.read({ contractKey, contractName, functionName: "getTokenName", transform: String }),
|
|
1237
|
-
usernameToUserId: (username) => this.read({ contractKey, contractName, functionName: "usernameToUserId", args: [username], transform: Number })
|
|
1238
|
-
};
|
|
1239
|
-
}
|
|
1240
|
-
createScientistStorageReadAPI() {
|
|
1241
|
-
const contractKey = "scientistStorage";
|
|
1242
|
-
const contractName = "ScientistStorage";
|
|
1243
|
-
return {
|
|
1244
|
-
getDeploymentDate: () => this.read({
|
|
1245
|
-
contractKey,
|
|
1246
|
-
contractName,
|
|
1247
|
-
functionName: "getDeploymentDate",
|
|
1248
|
-
transform: (result) => [Number(result[0]), Number(result[1])]
|
|
1249
|
-
}),
|
|
1250
|
-
getLastMonthId: () => this.read({ contractKey, contractName, functionName: "getLastMonthId", transform: Number }),
|
|
1251
|
-
getStatsRaw: (action, objectType, monthId) => this.read({
|
|
1252
|
-
contractKey,
|
|
1253
|
-
contractName,
|
|
1254
|
-
functionName: "getStatsRaw",
|
|
1255
|
-
args: [BigInt(action), BigInt(objectType), BigInt(monthId)],
|
|
1256
|
-
transform: (result) => [
|
|
1257
|
-
result[0].map((v) => BigInt(v)),
|
|
1258
|
-
result[1].map((v) => Number(v))
|
|
1259
|
-
]
|
|
1260
|
-
}),
|
|
1261
|
-
isAuthorized: (userAddress) => this.read({ contractKey, contractName, functionName: "isAuthorized", args: [userAddress], transform: Boolean })
|
|
1262
|
-
};
|
|
1263
|
-
}
|
|
1264
|
-
createFactoryReadAPI() {
|
|
1265
|
-
const contractKey = "factory";
|
|
1266
|
-
const contractName = "Factory";
|
|
1267
|
-
return {
|
|
1268
|
-
nbWritesByUsername: (username) => this.read({ contractKey, contractName, functionName: "nbWritesByUsername", args: [username], transform: Number }),
|
|
1269
|
-
loadUsername: (username) => this.read({ contractKey, contractName, functionName: "loadUsername", args: [username], transform: toActionsTuple }),
|
|
1270
|
-
loadUsernameSince: (username, index) => this.read({ contractKey, contractName, functionName: "loadUsernameSince", args: [username, index], transform: toActionsTuple }),
|
|
1271
|
-
load: () => this.read({ contractKey, contractName, functionName: "load", transform: toActionsTuple }),
|
|
1272
|
-
isAuthorized: (userAddress) => this.read({ contractKey, contractName, functionName: "isAuthorized", args: [userAddress], transform: Boolean }),
|
|
1273
|
-
owner: () => this.read({ contractKey, contractName, functionName: "owner", transform: String }),
|
|
1274
|
-
oracleSigner: () => this.read({ contractKey, contractName, functionName: "oracleSigner", transform: String }),
|
|
1275
|
-
bouncerStorage: () => this.read({ contractKey, contractName, functionName: "bouncerStorage", transform: String }),
|
|
1276
|
-
scientistStorage: () => this.read({ contractKey, contractName, functionName: "scientistStorage", transform: String }),
|
|
1277
|
-
backupStorage: () => this.read({ contractKey, contractName, functionName: "backupStorage", transform: String }),
|
|
1278
|
-
projectManagerStorage: () => this.read({ contractKey, contractName, functionName: "projectManagerStorage", transform: String }),
|
|
1279
|
-
usedPaymentIntents: (paymentIntentId) => this.read({ contractKey, contractName, functionName: "usedPaymentIntents", args: [paymentIntentId], transform: Boolean })
|
|
1280
|
-
};
|
|
1281
|
-
}
|
|
1282
|
-
createSubscriptionManagerReadAPI() {
|
|
1283
|
-
const contractKey = "subscriptionManager";
|
|
1284
|
-
const contractName = "SubscriptionManager";
|
|
1285
|
-
return {
|
|
1286
|
-
getSubscriptions: (userId) => this.read({
|
|
1287
|
-
contractKey,
|
|
1288
|
-
contractName,
|
|
1289
|
-
functionName: "getSubscriptions",
|
|
1290
|
-
args: [userId],
|
|
1291
|
-
transform: (result) => [...result],
|
|
1292
|
-
whenAddressMissing: []
|
|
1293
|
-
}),
|
|
1294
|
-
getSubscriptionCount: (userId) => this.read({ contractKey, contractName, functionName: "getSubscriptionCount", args: [userId], transform: BigInt, whenAddressMissing: 0n }),
|
|
1295
|
-
isSubscribed: (subscriber, target) => this.read({
|
|
1296
|
-
contractKey,
|
|
1297
|
-
contractName,
|
|
1298
|
-
functionName: "isSubscribed",
|
|
1299
|
-
args: [subscriber, target],
|
|
1300
|
-
transform: Boolean,
|
|
1301
|
-
whenAddressMissing: false
|
|
1302
|
-
}),
|
|
1303
|
-
scoreOf: (userId) => this.read({ contractKey, contractName, functionName: "scoreOf", args: [userId], transform: BigInt, whenAddressMissing: 0n })
|
|
1304
|
-
};
|
|
1305
|
-
}
|
|
1306
|
-
createLibraryRegistryStorageReadAPI() {
|
|
1307
|
-
const contractKey = "libraryRegistryStorage";
|
|
1308
|
-
const contractName = "LibraryRegistryStorage";
|
|
1309
|
-
return {
|
|
1310
|
-
getUnverifiedCollectionIds: () => this.read({
|
|
1311
|
-
contractKey,
|
|
1312
|
-
contractName,
|
|
1313
|
-
functionName: "getUnverifiedCollectionIds",
|
|
1314
|
-
transform: (result) => [...result]
|
|
1315
|
-
}),
|
|
1316
|
-
getVerifiedCollectionIds: () => this.read({
|
|
1317
|
-
contractKey,
|
|
1318
|
-
contractName,
|
|
1319
|
-
functionName: "getVerifiedCollectionIds",
|
|
1320
|
-
transform: (result) => [...result]
|
|
1321
|
-
}),
|
|
1322
|
-
getCollection: (id) => this.read({
|
|
1323
|
-
contractKey,
|
|
1324
|
-
contractName,
|
|
1325
|
-
functionName: "getCollection",
|
|
1326
|
-
args: [id],
|
|
1327
|
-
transform: (result) => ({
|
|
1328
|
-
id: String(result.id),
|
|
1329
|
-
slug: String(result.slug),
|
|
1330
|
-
manifestUrl: String(result.manifestUrl),
|
|
1331
|
-
importerUsername: String(result.importerUsername),
|
|
1332
|
-
owner: String(result.owner),
|
|
1333
|
-
verified: Boolean(result.verified),
|
|
1334
|
-
fileCount: Number(result.fileCount),
|
|
1335
|
-
libraryType: Number(result.libraryType),
|
|
1336
|
-
publicLibraryId: Number(result.publicLibraryId),
|
|
1337
|
-
country: String(result.country),
|
|
1338
|
-
language: String(result.language),
|
|
1339
|
-
isPublic: Boolean(result.isPublic),
|
|
1340
|
-
createdAt: Number(result.createdAt),
|
|
1341
|
-
updatedAt: Number(result.updatedAt),
|
|
1342
|
-
initialBookCount: Number(result.initialBookCount),
|
|
1343
|
-
dSafeBookCount: Number(result.dSafeBookCount),
|
|
1344
|
-
importStatus: Number(result.importStatus),
|
|
1345
|
-
published: Boolean(result.published)
|
|
1346
|
-
})
|
|
1347
|
-
})
|
|
1348
|
-
};
|
|
1349
|
-
}
|
|
1350
|
-
createPublicLibraryStorageReadAPI() {
|
|
1351
|
-
const contractKey = "publicLibraryStorage";
|
|
1352
|
-
const contractName = "PublicLibraryStorage";
|
|
1353
|
-
return {
|
|
1354
|
-
libraryExists: (id) => this.read({
|
|
1355
|
-
contractKey,
|
|
1356
|
-
contractName,
|
|
1357
|
-
functionName: "libraryExists",
|
|
1358
|
-
args: [id],
|
|
1359
|
-
transform: Boolean
|
|
1360
|
-
}),
|
|
1361
|
-
getPublicLibrary: (id) => this.read({
|
|
1362
|
-
contractKey,
|
|
1363
|
-
contractName,
|
|
1364
|
-
functionName: "getPublicLibrary",
|
|
1365
|
-
args: [id],
|
|
1366
|
-
transform: (result) => ({
|
|
1367
|
-
id: Number(result.id),
|
|
1368
|
-
name: String(result.name),
|
|
1369
|
-
physicalAddress: String(result.physicalAddress),
|
|
1370
|
-
country: String(result.country),
|
|
1371
|
-
language: String(result.language),
|
|
1372
|
-
ownership: Number(result.ownership),
|
|
1373
|
-
website: String(result.website),
|
|
1374
|
-
preferredFormat: Number(result.preferredFormat),
|
|
1375
|
-
createdAt: Number(result.createdAt),
|
|
1376
|
-
updatedAt: Number(result.updatedAt)
|
|
1377
|
-
})
|
|
1378
|
-
}),
|
|
1379
|
-
nbLibraries: () => this.read({
|
|
1380
|
-
contractKey,
|
|
1381
|
-
contractName,
|
|
1382
|
-
functionName: "nbLibraries",
|
|
1383
|
-
transform: Number
|
|
1384
|
-
})
|
|
1385
|
-
};
|
|
1386
|
-
}
|
|
1387
|
-
async getRegistryStatus() {
|
|
1388
|
-
await this.ready;
|
|
1389
|
-
return addressLoader.getLoadingStatus(this.chainId);
|
|
1390
|
-
}
|
|
1391
|
-
};
|
|
1392
|
-
function createEvmClient(chainId = DEFAULT_CHAIN_ID, environment = "production") {
|
|
1393
|
-
return new EvmClient(chainId, environment);
|
|
1394
|
-
}
|
|
1395
|
-
|
|
1396
|
-
// src/web3/client/registry.ts
|
|
1397
|
-
var readOnlyClients = {};
|
|
1398
|
-
var readOnlyStagingClients = {};
|
|
1399
|
-
var evmClients = {};
|
|
1400
|
-
var evmStagingClients = {};
|
|
1401
|
-
for (const [id, config] of Object.entries(EVM_CHAINS)) {
|
|
1402
|
-
const chainId = Number(id);
|
|
1403
|
-
if (config.deployed) {
|
|
1404
|
-
const client = new EvmClient(chainId, "production");
|
|
1405
|
-
evmClients[chainId] = client;
|
|
1406
|
-
readOnlyClients[chainId] = client;
|
|
1407
|
-
}
|
|
1408
|
-
if (config.stagingDeployed) {
|
|
1409
|
-
const client = new EvmClient(chainId, "staging");
|
|
1410
|
-
evmStagingClients[chainId] = client;
|
|
1411
|
-
readOnlyStagingClients[chainId] = client;
|
|
1412
|
-
}
|
|
1413
|
-
}
|
|
1414
|
-
function getReadClient(chainId, environment = "production") {
|
|
1415
|
-
const map = environment === "staging" ? readOnlyStagingClients : readOnlyClients;
|
|
1416
|
-
const client = map[chainId];
|
|
1417
|
-
if (!client) throw new Error(`No read client for chain ${chainId} (${environment})`);
|
|
1418
|
-
return client;
|
|
1419
|
-
}
|
|
1420
|
-
function getEvmClient(chainId, environment = "production") {
|
|
1421
|
-
const map = environment === "staging" ? evmStagingClients : evmClients;
|
|
1422
|
-
const client = map[chainId];
|
|
1423
|
-
if (!client) throw new Error(`No EVM client for chain ${chainId} (${environment})`);
|
|
1424
|
-
return client;
|
|
1425
|
-
}
|
|
1426
|
-
async function getReadyEvmClient(chainId, environment = "production") {
|
|
1427
|
-
const client = getEvmClient(chainId, environment);
|
|
1428
|
-
await client.ready;
|
|
1429
|
-
await addressLoader.waitForAbis(chainId, environment);
|
|
1430
|
-
return client;
|
|
1431
|
-
}
|
|
1432
|
-
|
|
1433
|
-
// src/web3/session/store.ts
|
|
1434
|
-
function createSessionStore() {
|
|
1435
|
-
const PREFIX = "@the_library/web3-session:";
|
|
1436
|
-
const NEW_SEG = "infos_web3_";
|
|
1437
|
-
const ACTIVE_KEY = "active_session";
|
|
1438
|
-
const state = {
|
|
1439
|
-
active: null,
|
|
1440
|
-
known: []
|
|
1441
|
-
};
|
|
1442
|
-
const changeListeners = /* @__PURE__ */ new Set();
|
|
1443
|
-
const notify = () => changeListeners.forEach((l) => l());
|
|
1444
|
-
const getLocalStorageKey = (address, chainId) => {
|
|
1445
|
-
return `${NEW_SEG}${chainId}_${address.toLowerCase()}`;
|
|
1446
|
-
};
|
|
1447
|
-
const persistAccount = (account) => {
|
|
1448
|
-
if (typeof localStorage === "undefined") return;
|
|
1449
|
-
const key = getLocalStorageKey(account.account, account.chainId);
|
|
1450
|
-
localStorage.setItem(PREFIX + key, JSON.stringify(account));
|
|
1451
|
-
};
|
|
1452
|
-
const removePersistedAccount = (address, chainId) => {
|
|
1453
|
-
if (typeof localStorage === "undefined") return;
|
|
1454
|
-
const key = getLocalStorageKey(address, chainId);
|
|
1455
|
-
localStorage.removeItem(PREFIX + key);
|
|
1456
|
-
};
|
|
1457
|
-
const persistActive = () => {
|
|
1458
|
-
if (typeof localStorage === "undefined") return;
|
|
1459
|
-
if (state.active) {
|
|
1460
|
-
localStorage.setItem(
|
|
1461
|
-
PREFIX + ACTIVE_KEY,
|
|
1462
|
-
JSON.stringify({ address: state.active.account, chainId: state.active.chainId })
|
|
1463
|
-
);
|
|
1464
|
-
} else {
|
|
1465
|
-
localStorage.removeItem(PREFIX + ACTIVE_KEY);
|
|
1466
|
-
}
|
|
1467
|
-
};
|
|
1468
|
-
const loadActive = () => {
|
|
1469
|
-
if (typeof localStorage === "undefined") return null;
|
|
1470
|
-
const raw = localStorage.getItem(PREFIX + ACTIVE_KEY);
|
|
1471
|
-
if (!raw) return null;
|
|
1472
|
-
try {
|
|
1473
|
-
const parsed = JSON.parse(raw);
|
|
1474
|
-
return state.known.find(
|
|
1475
|
-
(a) => a.account.toLowerCase() === parsed.address.toLowerCase() && a.chainId === parsed.chainId
|
|
1476
|
-
) || null;
|
|
1477
|
-
} catch {
|
|
1478
|
-
return null;
|
|
1479
|
-
}
|
|
1480
|
-
};
|
|
1481
|
-
function migrateStorageKeys() {
|
|
1482
|
-
if (typeof localStorage === "undefined") return;
|
|
1483
|
-
const OLD_SEG = "infos_evm_";
|
|
1484
|
-
for (let i = 0; i < localStorage.length; i++) {
|
|
1485
|
-
const raw = localStorage.key(i);
|
|
1486
|
-
if (!raw) continue;
|
|
1487
|
-
const bare = raw.startsWith(PREFIX) ? raw.slice(PREFIX.length) : null;
|
|
1488
|
-
if (bare && bare.startsWith(OLD_SEG)) {
|
|
1489
|
-
const newRaw = PREFIX + NEW_SEG + bare.slice(OLD_SEG.length);
|
|
1490
|
-
localStorage.setItem(newRaw, localStorage.getItem(raw));
|
|
1491
|
-
localStorage.removeItem(raw);
|
|
1492
|
-
i--;
|
|
1493
|
-
}
|
|
1494
|
-
}
|
|
1495
|
-
}
|
|
1496
|
-
const store = {
|
|
1497
|
-
getState() {
|
|
1498
|
-
return state;
|
|
1499
|
-
},
|
|
1500
|
-
setActive(account) {
|
|
1501
|
-
state.active = account;
|
|
1502
|
-
if (account) {
|
|
1503
|
-
const exists = state.known.some(
|
|
1504
|
-
(a) => a.account.toLowerCase() === account.account.toLowerCase() && a.chainId === account.chainId
|
|
1505
|
-
);
|
|
1506
|
-
if (!exists) {
|
|
1507
|
-
state.known.push(account);
|
|
1508
|
-
persistAccount(account);
|
|
1509
|
-
}
|
|
1510
|
-
}
|
|
1511
|
-
persistActive();
|
|
1512
|
-
notify();
|
|
1513
|
-
},
|
|
1514
|
-
addKnown(account) {
|
|
1515
|
-
const index = state.known.findIndex(
|
|
1516
|
-
(a) => a.account.toLowerCase() === account.account.toLowerCase() && a.chainId === account.chainId
|
|
1517
|
-
);
|
|
1518
|
-
if (index >= 0) {
|
|
1519
|
-
state.known[index] = account;
|
|
1520
|
-
} else {
|
|
1521
|
-
state.known.push(account);
|
|
1522
|
-
}
|
|
1523
|
-
persistAccount(account);
|
|
1524
|
-
notify();
|
|
1525
|
-
},
|
|
1526
|
-
updateAccount(address, chainId, patch) {
|
|
1527
|
-
const account = state.known.find(
|
|
1528
|
-
(a) => a.account.toLowerCase() === address.toLowerCase() && a.chainId === chainId
|
|
1529
|
-
);
|
|
1530
|
-
if (account) {
|
|
1531
|
-
Object.assign(account, patch);
|
|
1532
|
-
persistAccount(account);
|
|
1533
|
-
if (state.active && state.active.account.toLowerCase() === address.toLowerCase() && state.active.chainId === chainId) {
|
|
1534
|
-
Object.assign(state.active, patch);
|
|
1535
|
-
persistActive();
|
|
1536
|
-
}
|
|
1537
|
-
notify();
|
|
1538
|
-
}
|
|
1539
|
-
},
|
|
1540
|
-
removeAccount(address, chainId) {
|
|
1541
|
-
state.known = state.known.filter(
|
|
1542
|
-
(a) => !(a.account.toLowerCase() === address.toLowerCase() && a.chainId === chainId)
|
|
1543
|
-
);
|
|
1544
|
-
removePersistedAccount(address, chainId);
|
|
1545
|
-
if (state.active && state.active.account.toLowerCase() === address.toLowerCase() && state.active.chainId === chainId) {
|
|
1546
|
-
state.active = null;
|
|
1547
|
-
persistActive();
|
|
1548
|
-
}
|
|
1549
|
-
notify();
|
|
1550
|
-
},
|
|
1551
|
-
clearAll() {
|
|
1552
|
-
if (typeof localStorage !== "undefined") {
|
|
1553
|
-
const keysToRemove = [];
|
|
1554
|
-
for (let i = 0; i < localStorage.length; i++) {
|
|
1555
|
-
const key = localStorage.key(i);
|
|
1556
|
-
if (key && key.startsWith(PREFIX)) {
|
|
1557
|
-
keysToRemove.push(key);
|
|
1558
|
-
}
|
|
1559
|
-
}
|
|
1560
|
-
for (const k of keysToRemove) {
|
|
1561
|
-
localStorage.removeItem(k);
|
|
1562
|
-
}
|
|
1563
|
-
}
|
|
1564
|
-
state.active = null;
|
|
1565
|
-
state.known = [];
|
|
1566
|
-
notify();
|
|
1567
|
-
},
|
|
1568
|
-
setLastSavedPatchIndex(address, chainId, index) {
|
|
1569
|
-
this.updateAccount(address, chainId, { lastPatchIndex: index });
|
|
1570
|
-
},
|
|
1571
|
-
setLastRestorationIndex(address, chainId, index) {
|
|
1572
|
-
this.updateAccount(address, chainId, { lastRestorationIndex: index });
|
|
1573
|
-
},
|
|
1574
|
-
lastSyncCounters(address, chainId) {
|
|
1575
|
-
const account = state.known.find(
|
|
1576
|
-
(a) => a.account.toLowerCase() === address.toLowerCase() && a.chainId === chainId
|
|
1577
|
-
);
|
|
1578
|
-
return {
|
|
1579
|
-
lastPatchIndex: account?.lastPatchIndex ?? 0,
|
|
1580
|
-
lastRestorationIndex: account?.lastRestorationIndex ?? 0
|
|
1581
|
-
};
|
|
1582
|
-
},
|
|
1583
|
-
updateProjectVotes(address, chainId, projectId, amount) {
|
|
1584
|
-
const account = state.known.find(
|
|
1585
|
-
(a) => a.account.toLowerCase() === address.toLowerCase() && a.chainId === chainId
|
|
1586
|
-
);
|
|
1587
|
-
if (account) {
|
|
1588
|
-
const index = projectId - 1;
|
|
1589
|
-
if (index < 0) return;
|
|
1590
|
-
const votes = [...account.donationsPerProject || []];
|
|
1591
|
-
while (votes.length <= index) {
|
|
1592
|
-
votes.push(0);
|
|
1593
|
-
}
|
|
1594
|
-
votes[index] = (votes[index] || 0) + amount;
|
|
1595
|
-
this.updateAccount(address, chainId, { donationsPerProject: votes });
|
|
1596
|
-
}
|
|
1597
|
-
},
|
|
1598
|
-
persist() {
|
|
1599
|
-
for (const a of state.known) {
|
|
1600
|
-
persistAccount(a);
|
|
1601
|
-
}
|
|
1602
|
-
persistActive();
|
|
1603
|
-
},
|
|
1604
|
-
load() {
|
|
1605
|
-
if (typeof localStorage === "undefined") return;
|
|
1606
|
-
migrateStorageKeys();
|
|
1607
|
-
const loadedKnown = [];
|
|
1608
|
-
for (let i = 0; i < localStorage.length; i++) {
|
|
1609
|
-
const rawKey = localStorage.key(i);
|
|
1610
|
-
if (rawKey && rawKey.startsWith(PREFIX + NEW_SEG)) {
|
|
1611
|
-
try {
|
|
1612
|
-
const rawVal = localStorage.getItem(rawKey);
|
|
1613
|
-
if (rawVal) {
|
|
1614
|
-
const account = JSON.parse(rawVal);
|
|
1615
|
-
loadedKnown.push(account);
|
|
1616
|
-
}
|
|
1617
|
-
} catch (e) {
|
|
1618
|
-
console.warn("Failed to parse loaded session account:", e);
|
|
1619
|
-
}
|
|
1620
|
-
}
|
|
1621
|
-
}
|
|
1622
|
-
state.known = loadedKnown;
|
|
1623
|
-
state.active = loadActive();
|
|
1624
|
-
notify();
|
|
1625
|
-
},
|
|
1626
|
-
subscribe(listener) {
|
|
1627
|
-
changeListeners.add(listener);
|
|
1628
|
-
return () => changeListeners.delete(listener);
|
|
1629
|
-
}
|
|
1630
|
-
};
|
|
1631
|
-
return store;
|
|
1632
|
-
}
|
|
1633
|
-
var sessionStore = createSessionStore();
|
|
1634
|
-
var allRegisteredAccounts = () => sessionStore.getState().known.filter((a) => a.hasAccount);
|
|
1635
|
-
|
|
1636
|
-
// src/web3/events/EventBus.ts
|
|
1637
|
-
var EventBus = class {
|
|
1638
|
-
constructor() {
|
|
1639
|
-
this.listeners = /* @__PURE__ */ new Map();
|
|
1640
|
-
}
|
|
1641
|
-
on(eventType, listener) {
|
|
1642
|
-
if (!this.listeners.has(eventType)) {
|
|
1643
|
-
this.listeners.set(eventType, /* @__PURE__ */ new Set());
|
|
1644
|
-
}
|
|
1645
|
-
this.listeners.get(eventType).add(listener);
|
|
1646
|
-
return () => this.off(eventType, listener);
|
|
1647
|
-
}
|
|
1648
|
-
off(eventType, listener) {
|
|
1649
|
-
const listenersSet = this.listeners.get(eventType);
|
|
1650
|
-
if (listenersSet) {
|
|
1651
|
-
listenersSet.delete(listener);
|
|
1652
|
-
if (listenersSet.size === 0) {
|
|
1653
|
-
this.listeners.delete(eventType);
|
|
1654
|
-
}
|
|
1655
|
-
}
|
|
1656
|
-
}
|
|
1657
|
-
emit(eventType, data) {
|
|
1658
|
-
const listenersSet = this.listeners.get(eventType);
|
|
1659
|
-
if (listenersSet) {
|
|
1660
|
-
listenersSet.forEach((listener) => {
|
|
1661
|
-
try {
|
|
1662
|
-
listener(data);
|
|
1663
|
-
} catch (error) {
|
|
1664
|
-
console.error(`Error in event listener for ${eventType}:`, error);
|
|
1665
|
-
}
|
|
1666
|
-
});
|
|
1667
|
-
}
|
|
1668
|
-
}
|
|
1669
|
-
once(eventType, listener) {
|
|
1670
|
-
const wrappedListener = (data) => {
|
|
1671
|
-
listener(data);
|
|
1672
|
-
this.off(eventType, wrappedListener);
|
|
1673
|
-
};
|
|
1674
|
-
return this.on(eventType, wrappedListener);
|
|
1675
|
-
}
|
|
1676
|
-
clear(eventType) {
|
|
1677
|
-
if (eventType) {
|
|
1678
|
-
this.listeners.delete(eventType);
|
|
1679
|
-
} else {
|
|
1680
|
-
this.listeners.clear();
|
|
1681
|
-
}
|
|
1682
|
-
}
|
|
1683
|
-
listenerCount(eventType) {
|
|
1684
|
-
return this.listeners.get(eventType)?.size || 0;
|
|
1685
|
-
}
|
|
1686
|
-
};
|
|
1687
|
-
var globalEventBus = null;
|
|
1688
|
-
function getEventBus() {
|
|
1689
|
-
if (!globalEventBus) {
|
|
1690
|
-
globalEventBus = new EventBus();
|
|
1691
|
-
}
|
|
1692
|
-
return globalEventBus;
|
|
1693
|
-
}
|
|
1694
|
-
|
|
1695
|
-
// src/web3/events/enums.ts
|
|
1696
|
-
var EventName = /* @__PURE__ */ ((EventName2) => {
|
|
1697
|
-
EventName2["WALLET_STATE_CHANGED"] = "wallet:state:changed";
|
|
1698
|
-
EventName2["WALLET_CHAIN_CHANGED"] = "wallet:chain:changed";
|
|
1699
|
-
EventName2["WALLET_ERROR"] = "wallet:error";
|
|
1700
|
-
EventName2["SESSION_UPDATED"] = "session:updated";
|
|
1701
|
-
EventName2["WALLET_DISCONNECTED"] = "wallet:disconnected";
|
|
1702
|
-
EventName2["SESSION_DELETED"] = "session:deleted";
|
|
1703
|
-
EventName2["SAVE_RESTORED"] = "save:restored";
|
|
1704
|
-
EventName2["SUBSCRIPTION_PATCHES_SYNCED"] = "subscription:patches:synced";
|
|
1705
|
-
return EventName2;
|
|
1706
|
-
})(EventName || {});
|
|
1707
|
-
var WalletState = /* @__PURE__ */ ((WalletState2) => {
|
|
1708
|
-
WalletState2["INITIALIZING"] = "INITIALIZING";
|
|
1709
|
-
WalletState2["UPDATING_STATE_STARTED"] = "UPDATING_STATE_STARTED";
|
|
1710
|
-
WalletState2["UPDATING_STATE_DONE"] = "UPDATING_STATE_DONE";
|
|
1711
|
-
WalletState2["UPDATING_STATE_FAILED"] = "UPDATING_STATE_FAILED";
|
|
1712
|
-
WalletState2["READY"] = "READY";
|
|
1713
|
-
WalletState2["INTERNAL_ERROR"] = "INTERNAL_ERROR";
|
|
1714
|
-
WalletState2["NOT_CONNECTED"] = "NOT_CONNECTED";
|
|
1715
|
-
WalletState2["NOT_INSTALLED"] = "NOT_INSTALLED";
|
|
1716
|
-
WalletState2["NOT_ALLOWED"] = "NOT_ALLOWED";
|
|
1717
|
-
WalletState2["NOT_SUPPORTED"] = "NOT_SUPPORTED";
|
|
1718
|
-
WalletState2["NOT_READY"] = "NOT_READY";
|
|
1719
|
-
WalletState2["CONNECT_STARTED"] = "CONNECT_STARTED";
|
|
1720
|
-
WalletState2["CONNECT_DONE"] = "CONNECT_DONE";
|
|
1721
|
-
WalletState2["CONNECT_FAILED"] = "CONNECT_FAILED";
|
|
1722
|
-
WalletState2["TRANSACTION_STARTED"] = "TRANSACTION_STARTED";
|
|
1723
|
-
WalletState2["TRANSACTION_DONE"] = "TRANSACTION_DONE";
|
|
1724
|
-
WalletState2["TRANSACTION_FAILED"] = "TRANSACTION_FAILED";
|
|
1725
|
-
WalletState2["TIMEOUT"] = "TIMEOUT";
|
|
1726
|
-
WalletState2["CHAIN_CHANGED_STARTED"] = "CHAIN_CHANGED_STARTED";
|
|
1727
|
-
WalletState2["CHAIN_CHANGED_DONE"] = "CHAIN_CHANGED_DONE";
|
|
1728
|
-
WalletState2["CHAIN_CHANGED_FAILED"] = "CHAIN_CHANGED_FAILED";
|
|
1729
|
-
WalletState2["WALLET_INSTALLED"] = "WALLET_INSTALLED";
|
|
1730
|
-
return WalletState2;
|
|
1731
|
-
})(WalletState || {});
|
|
1732
|
-
var WalletError = /* @__PURE__ */ ((WalletError2) => {
|
|
1733
|
-
WalletError2["NO_ACCOUNTS"] = "NO_ACCOUNTS";
|
|
1734
|
-
WalletError2["USER_REJECTED"] = "USER_REJECTED";
|
|
1735
|
-
WalletError2["INSUFFICIENT_FUNDS"] = "INSUFFICIENT_FUNDS";
|
|
1736
|
-
WalletError2["LOGIN_INTO_WALLET"] = "LOGIN_INTO_WALLET";
|
|
1737
|
-
WalletError2["REQUEST_ALREADY_PENDING"] = "REQUEST_ALREADY_PENDING";
|
|
1738
|
-
WalletError2["UNKNOWN_ERROR"] = "UNKNOWN_ERROR";
|
|
1739
|
-
WalletError2["CONFIG_MISSING"] = "CONFIG_MISSING";
|
|
1740
|
-
WalletError2["NOT_SUPPORTED"] = "NOT_SUPPORTED";
|
|
1741
|
-
WalletError2["NOT_CONNECTED"] = "NOT_CONNECTED";
|
|
1742
|
-
WalletError2["NOT_INSTALLED"] = "NOT_INSTALLED";
|
|
1743
|
-
WalletError2["NOT_ALLOWED"] = "NOT_ALLOWED";
|
|
1744
|
-
WalletError2["NETWORK_NOT_SUPPORTED"] = "NETWORK_NOT_SUPPORTED";
|
|
1745
|
-
return WalletError2;
|
|
1746
|
-
})(WalletError || {});
|
|
1747
|
-
var WalletUxError = /* @__PURE__ */ ((WalletUxError2) => {
|
|
1748
|
-
WalletUxError2["NO_ACCOUNT_SWITCH"] = "NO_ACCOUNT_SWITCH";
|
|
1749
|
-
WalletUxError2["NO_NETWORK_SWITCH"] = "NO_NETWORK_SWITCH";
|
|
1750
|
-
WalletUxError2["NETWORK_NOT_SUPPORTED"] = "NETWORK_NOT_SUPPORTED";
|
|
1751
|
-
WalletUxError2["NO_INTERNET"] = "NO_INTERNET";
|
|
1752
|
-
WalletUxError2["NO_DISCONNECT"] = "NO_DISCONNECT";
|
|
1753
|
-
WalletUxError2["NO_ACCOUNT_DISCONNECT"] = "NO_ACCOUNT_DISCONNECT";
|
|
1754
|
-
return WalletUxError2;
|
|
1755
|
-
})(WalletUxError || {});
|
|
1756
|
-
|
|
1757
|
-
// src/web3/events/wallet_events.ts
|
|
1758
|
-
var createEmitter = (eventName) => {
|
|
1759
|
-
return (data) => {
|
|
1760
|
-
getEventBus().emit(eventName, data);
|
|
1761
|
-
};
|
|
1762
|
-
};
|
|
1763
|
-
var createListener = (eventName) => {
|
|
1764
|
-
return (listener) => {
|
|
1765
|
-
return getEventBus().on(eventName, listener);
|
|
1766
|
-
};
|
|
1767
|
-
};
|
|
1768
|
-
var WalletEvents = {
|
|
1769
|
-
emitWalletStateEvent: createEmitter("wallet:state:changed" /* WALLET_STATE_CHANGED */),
|
|
1770
|
-
onWalletStateEvent: createListener("wallet:state:changed" /* WALLET_STATE_CHANGED */),
|
|
1771
|
-
emitSessionUpdated: createEmitter("session:updated" /* SESSION_UPDATED */),
|
|
1772
|
-
onSessionUpdated: createListener("session:updated" /* SESSION_UPDATED */),
|
|
1773
|
-
emitChainChanged: createEmitter("wallet:chain:changed" /* WALLET_CHAIN_CHANGED */),
|
|
1774
|
-
onChainChanged: createListener("wallet:chain:changed" /* WALLET_CHAIN_CHANGED */),
|
|
1775
|
-
emitDisconnected: createEmitter("wallet:disconnected" /* WALLET_DISCONNECTED */),
|
|
1776
|
-
onDisconnected: createListener("wallet:disconnected" /* WALLET_DISCONNECTED */),
|
|
1777
|
-
emitWalletSessionDeleted: createEmitter("session:deleted" /* SESSION_DELETED */),
|
|
1778
|
-
onWalletSessionDeleted: createListener("session:deleted" /* SESSION_DELETED */),
|
|
1779
|
-
emitWalletError: createEmitter("wallet:error" /* WALLET_ERROR */),
|
|
1780
|
-
onWalletError: createListener("wallet:error" /* WALLET_ERROR */),
|
|
1781
|
-
emitSaveRestored: createEmitter("save:restored" /* SAVE_RESTORED */),
|
|
1782
|
-
onSaveRestored: createListener("save:restored" /* SAVE_RESTORED */),
|
|
1783
|
-
emitSubscriptionPatchesSynced: createEmitter("subscription:patches:synced" /* SUBSCRIPTION_PATCHES_SYNCED */),
|
|
1784
|
-
onSubscriptionPatchesSynced: createListener("subscription:patches:synced" /* SUBSCRIPTION_PATCHES_SYNCED */)
|
|
1785
|
-
};
|
|
1786
|
-
|
|
1787
|
-
// src/web3/subscription/contract.ts
|
|
1788
|
-
var MULTICALL3_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11";
|
|
1789
|
-
function subscriptionManagerBinding(client) {
|
|
1790
|
-
const address = addressLoader.getAddress(client.chainId, "subscriptionManager", client.environment);
|
|
1791
|
-
const abi = addressLoader.getAbi(client.chainId, "SubscriptionManager", client.environment);
|
|
1792
|
-
if (!address || !abi) return null;
|
|
1793
|
-
return { address, abi };
|
|
1794
|
-
}
|
|
1795
|
-
async function multicallGetSubscriptions(client, userIds) {
|
|
1796
|
-
const result = /* @__PURE__ */ new Map();
|
|
1797
|
-
if (userIds.length === 0) return result;
|
|
1798
|
-
const binding = subscriptionManagerBinding(client);
|
|
1799
|
-
if (binding) {
|
|
1800
|
-
try {
|
|
1801
|
-
const raw = await client.publicClient.multicall({
|
|
1802
|
-
multicallAddress: MULTICALL3_ADDRESS,
|
|
1803
|
-
allowFailure: true,
|
|
1804
|
-
contracts: userIds.map((userId) => ({ ...binding, functionName: "getSubscriptions", args: [userId] }))
|
|
1805
|
-
});
|
|
1806
|
-
userIds.forEach((userId, i) => {
|
|
1807
|
-
const r = raw[i];
|
|
1808
|
-
result.set(userId, r.status === "success" ? (r.result ?? []).map(Number) : []);
|
|
1809
|
-
});
|
|
1810
|
-
return result;
|
|
1811
|
-
} catch (e) {
|
|
1812
|
-
console.warn("[subscription/contract] multicall getSubscriptions failed, falling back to sequential reads", e);
|
|
1813
|
-
}
|
|
1814
|
-
}
|
|
1815
|
-
await Promise.all(
|
|
1816
|
-
userIds.map(async (userId) => {
|
|
1817
|
-
try {
|
|
1818
|
-
result.set(userId, await client.subscriptionManager.getSubscriptions(userId));
|
|
1819
|
-
} catch {
|
|
1820
|
-
result.set(userId, []);
|
|
1821
|
-
}
|
|
1822
|
-
})
|
|
1823
|
-
);
|
|
1824
|
-
return result;
|
|
1825
|
-
}
|
|
1826
|
-
async function multicallGetSubscriptionCounts(client, userIds) {
|
|
1827
|
-
const result = /* @__PURE__ */ new Map();
|
|
1828
|
-
if (userIds.length === 0) return result;
|
|
1829
|
-
const binding = subscriptionManagerBinding(client);
|
|
1830
|
-
if (binding) {
|
|
1831
|
-
try {
|
|
1832
|
-
const raw = await client.publicClient.multicall({
|
|
1833
|
-
multicallAddress: MULTICALL3_ADDRESS,
|
|
1834
|
-
allowFailure: true,
|
|
1835
|
-
contracts: userIds.map((userId) => ({ ...binding, functionName: "getSubscriptionCount", args: [userId] }))
|
|
1836
|
-
});
|
|
1837
|
-
userIds.forEach((userId, i) => {
|
|
1838
|
-
const r = raw[i];
|
|
1839
|
-
result.set(userId, r.status === "success" ? Number(r.result) : 0);
|
|
1840
|
-
});
|
|
1841
|
-
return result;
|
|
1842
|
-
} catch (e) {
|
|
1843
|
-
console.warn("[subscription/contract] multicall getSubscriptionCount failed, falling back to sequential reads", e);
|
|
1844
|
-
}
|
|
1845
|
-
}
|
|
1846
|
-
await Promise.all(
|
|
1847
|
-
userIds.map(async (userId) => {
|
|
1848
|
-
try {
|
|
1849
|
-
result.set(userId, Number(await client.subscriptionManager.getSubscriptionCount(userId)));
|
|
1850
|
-
} catch {
|
|
1851
|
-
result.set(userId, 0);
|
|
1852
|
-
}
|
|
1853
|
-
})
|
|
1854
|
-
);
|
|
1855
|
-
return result;
|
|
1856
|
-
}
|
|
1857
|
-
|
|
1858
|
-
// src/web3/subscription/graph-walk.ts
|
|
1859
|
-
var BATCH_SIZE = 50;
|
|
1860
|
-
var DEFAULT_MAX_WALK_NODES = 1e3;
|
|
1861
|
-
async function walkGraph(client, rootUserId, opts) {
|
|
1862
|
-
const maxWalkNodes = opts?.maxNodes ?? DEFAULT_MAX_WALK_NODES;
|
|
1863
|
-
const maxDepth = opts?.maxDepth;
|
|
1864
|
-
const visited = /* @__PURE__ */ new Set([rootUserId]);
|
|
1865
|
-
const depth = /* @__PURE__ */ new Map([[rootUserId, 0]]);
|
|
1866
|
-
const nodes = /* @__PURE__ */ new Map();
|
|
1867
|
-
const queue = [rootUserId];
|
|
1868
|
-
let depthLimited = false;
|
|
1869
|
-
while (queue.length > 0 && visited.size < maxWalkNodes) {
|
|
1870
|
-
const batch = queue.splice(0, BATCH_SIZE);
|
|
1871
|
-
const results = await multicallGetSubscriptions(client, batch);
|
|
1872
|
-
for (const userId of batch) {
|
|
1873
|
-
const subs = results.get(userId) ?? [];
|
|
1874
|
-
nodes.set(userId, { userId, subscriptions: subs });
|
|
1875
|
-
for (const sub of subs) {
|
|
1876
|
-
if (visited.has(sub) || visited.size >= maxWalkNodes) continue;
|
|
1877
|
-
const nextDepth = (depth.get(userId) ?? 0) + 1;
|
|
1878
|
-
if (maxDepth !== void 0 && nextDepth > maxDepth) {
|
|
1879
|
-
depthLimited = true;
|
|
1880
|
-
continue;
|
|
1881
|
-
}
|
|
1882
|
-
visited.add(sub);
|
|
1883
|
-
depth.set(sub, nextDepth);
|
|
1884
|
-
queue.push(sub);
|
|
1885
|
-
}
|
|
1886
|
-
}
|
|
1887
|
-
}
|
|
1888
|
-
return { rootUserId, nodes, truncated: queue.length > 0 || depthLimited };
|
|
1889
|
-
}
|
|
1890
|
-
|
|
1891
|
-
// src/web3/subscription/patch-resolver.ts
|
|
1892
|
-
async function fetchNodePatches(client, userId, fromIndex) {
|
|
1893
|
-
const [compressedActions, indexes, stringIndexes] = await client.archivistStorage.loadActionsSince(userId, fromIndex);
|
|
1894
|
-
if (!compressedActions || compressedActions.length === 0) return null;
|
|
1895
|
-
return {
|
|
1896
|
-
userId,
|
|
1897
|
-
fromIndex,
|
|
1898
|
-
toIndex: fromIndex + compressedActions.length,
|
|
1899
|
-
raw: { compressedActions, indexes, stringIndexes }
|
|
1900
|
-
};
|
|
1901
|
-
}
|
|
1902
|
-
async function fetchPatches(client, graph, cursor, opts) {
|
|
1903
|
-
const concurrency = opts?.concurrency ?? 4;
|
|
1904
|
-
const userIds = Array.from(graph.nodes.keys());
|
|
1905
|
-
const patches = [];
|
|
1906
|
-
for (let i = 0; i < userIds.length; i += concurrency) {
|
|
1907
|
-
const slice = userIds.slice(i, i + concurrency);
|
|
1908
|
-
const results = await Promise.all(
|
|
1909
|
-
slice.map(
|
|
1910
|
-
(userId) => fetchNodePatches(client, userId, cursor?.get(userId) ?? 0).catch((e) => {
|
|
1911
|
-
console.warn(`[subscription/patch-resolver] failed to fetch patches for userId ${userId}`, e);
|
|
1912
|
-
return null;
|
|
1913
|
-
})
|
|
1914
|
-
)
|
|
1915
|
-
);
|
|
1916
|
-
for (const patch of results) {
|
|
1917
|
-
if (patch) patches.push(patch);
|
|
1918
|
-
}
|
|
1919
|
-
}
|
|
1920
|
-
return patches;
|
|
1921
|
-
}
|
|
1922
|
-
|
|
1923
|
-
// src/web3/subscription/patch-codec.ts
|
|
1924
|
-
function patchToEvmPayload(patch, version) {
|
|
1925
|
-
const raw = patch.raw;
|
|
1926
|
-
return {
|
|
1927
|
-
version,
|
|
1928
|
-
patches: raw.compressedActions,
|
|
1929
|
-
textIndex: raw.indexes.map(Number),
|
|
1930
|
-
textData: raw.stringIndexes
|
|
1931
|
-
};
|
|
1932
|
-
}
|
|
1933
|
-
|
|
1934
|
-
// src/web3/subscription/SubscriptionClient.ts
|
|
1935
|
-
import { deserializePatches, applyRestoredPatches, CURRENT_VERSION } from "@the_library/public/models";
|
|
1936
|
-
var SubscriptionClient = class {
|
|
1937
|
-
constructor(config) {
|
|
1938
|
-
this.client = getEvmClient(config.chainId, config.environment ?? "production");
|
|
1939
|
-
this.defaultMaxWalkNodes = config.maxWalkNodes;
|
|
1940
|
-
this.defaultMaxDepth = config.maxDepth;
|
|
1941
|
-
}
|
|
1942
|
-
async walkGraph(rootUserId, opts) {
|
|
1943
|
-
await this.client.ready;
|
|
1944
|
-
return walkGraph(this.client, rootUserId, {
|
|
1945
|
-
maxNodes: opts?.maxNodes ?? this.defaultMaxWalkNodes,
|
|
1946
|
-
maxDepth: opts?.maxDepth ?? this.defaultMaxDepth
|
|
1947
|
-
});
|
|
1948
|
-
}
|
|
1949
|
-
async fetchPatches(graph, cursor, opts) {
|
|
1950
|
-
await this.client.ready;
|
|
1951
|
-
return fetchPatches(this.client, graph, cursor, opts);
|
|
1952
|
-
}
|
|
1953
|
-
/** Full walk + fetch from scratch. */
|
|
1954
|
-
async sync(rootUserId, opts) {
|
|
1955
|
-
const graph = await this.walkGraph(rootUserId, opts);
|
|
1956
|
-
const patches = await this.fetchPatches(graph, void 0, opts);
|
|
1957
|
-
const countSnapshot = /* @__PURE__ */ new Map();
|
|
1958
|
-
for (const [userId, node] of graph.nodes) {
|
|
1959
|
-
countSnapshot.set(userId, node.subscriptions.length);
|
|
1960
|
-
}
|
|
1961
|
-
const patchIndex = /* @__PURE__ */ new Map();
|
|
1962
|
-
for (const patch of patches) {
|
|
1963
|
-
patchIndex.set(patch.userId, Math.max(patchIndex.get(patch.userId) ?? 0, patch.toIndex));
|
|
1964
|
-
}
|
|
1965
|
-
for (const userId of graph.nodes.keys()) {
|
|
1966
|
-
if (!patchIndex.has(userId)) patchIndex.set(userId, 0);
|
|
1967
|
-
}
|
|
1968
|
-
return {
|
|
1969
|
-
patches,
|
|
1970
|
-
cursor: { rootUserId, knownNodes: graph.nodes, countSnapshot, patchIndex },
|
|
1971
|
-
truncated: graph.truncated
|
|
1972
|
-
};
|
|
1973
|
-
}
|
|
1974
|
-
/**
|
|
1975
|
-
* Incremental sync (spec §8, unchanged algorithm): multicall
|
|
1976
|
-
* getSubscriptionCount for every known node, deep re-walk only the nodes
|
|
1977
|
-
* whose count changed (O4: completeness over cost), then fetch only new
|
|
1978
|
-
* patches per node since the cursor.
|
|
1979
|
-
*/
|
|
1980
|
-
async syncSince(cursor, opts) {
|
|
1981
|
-
await this.client.ready;
|
|
1982
|
-
const knownUserIds = Array.from(cursor.knownNodes.keys());
|
|
1983
|
-
const counts = await multicallGetSubscriptionCounts(this.client, knownUserIds);
|
|
1984
|
-
const changed = knownUserIds.filter((userId) => counts.get(userId) !== cursor.countSnapshot.get(userId));
|
|
1985
|
-
const knownNodes = new Map(cursor.knownNodes);
|
|
1986
|
-
const countSnapshot = new Map(counts.size ? counts : cursor.countSnapshot);
|
|
1987
|
-
let truncated = false;
|
|
1988
|
-
for (const userId of changed) {
|
|
1989
|
-
const subs = await this.client.subscriptionManager.getSubscriptions(userId);
|
|
1990
|
-
knownNodes.set(userId, { userId, subscriptions: subs });
|
|
1991
|
-
countSnapshot.set(userId, subs.length);
|
|
1992
|
-
for (const sub of subs) {
|
|
1993
|
-
if (knownNodes.has(sub)) continue;
|
|
1994
|
-
const subGraph = await this.walkGraph(sub, opts);
|
|
1995
|
-
for (const [id, node] of subGraph.nodes) {
|
|
1996
|
-
if (!knownNodes.has(id)) {
|
|
1997
|
-
knownNodes.set(id, node);
|
|
1998
|
-
countSnapshot.set(id, node.subscriptions.length);
|
|
1999
|
-
}
|
|
2000
|
-
}
|
|
2001
|
-
truncated = truncated || subGraph.truncated;
|
|
2002
|
-
}
|
|
2003
|
-
}
|
|
2004
|
-
if (!knownNodes.has(cursor.rootUserId)) {
|
|
2005
|
-
const subs = await this.client.subscriptionManager.getSubscriptions(cursor.rootUserId);
|
|
2006
|
-
knownNodes.set(cursor.rootUserId, { userId: cursor.rootUserId, subscriptions: subs });
|
|
2007
|
-
countSnapshot.set(cursor.rootUserId, subs.length);
|
|
2008
|
-
}
|
|
2009
|
-
const graph = { rootUserId: cursor.rootUserId, nodes: knownNodes, truncated };
|
|
2010
|
-
const patches = await this.fetchPatches(graph, cursor.patchIndex, opts);
|
|
2011
|
-
const patchIndex = new Map(cursor.patchIndex);
|
|
2012
|
-
for (const patch of patches) {
|
|
2013
|
-
patchIndex.set(patch.userId, Math.max(patchIndex.get(patch.userId) ?? 0, patch.toIndex));
|
|
2014
|
-
}
|
|
2015
|
-
for (const userId of knownNodes.keys()) {
|
|
2016
|
-
if (!patchIndex.has(userId)) patchIndex.set(userId, 0);
|
|
2017
|
-
}
|
|
2018
|
-
return {
|
|
2019
|
-
patches,
|
|
2020
|
-
cursor: { rootUserId: cursor.rootUserId, knownNodes, countSnapshot, patchIndex },
|
|
2021
|
-
truncated
|
|
2022
|
-
};
|
|
2023
|
-
}
|
|
2024
|
-
async getSubscriptions(userId) {
|
|
2025
|
-
await this.client.ready;
|
|
2026
|
-
return this.client.subscriptionManager.getSubscriptions(userId);
|
|
2027
|
-
}
|
|
2028
|
-
async getScore(userId) {
|
|
2029
|
-
await this.client.ready;
|
|
2030
|
-
return this.client.subscriptionManager.scoreOf(userId);
|
|
2031
|
-
}
|
|
2032
|
-
/**
|
|
2033
|
-
* High-level API: load and apply library patches for a user by username.
|
|
2034
|
-
* Orchestrates: username→userId lookup, sync, deserialize, and IndexedDB application.
|
|
2035
|
-
* Errors are caught and logged to console but not thrown (graceful degradation).
|
|
2036
|
-
*/
|
|
2037
|
-
async loadLibraryByUsername(username) {
|
|
2038
|
-
try {
|
|
2039
|
-
await this.client.ready;
|
|
2040
|
-
console.log(`[SubscriptionClient] Starting library load for @${username}...`);
|
|
2041
|
-
console.log(`[SubscriptionClient] Looking up userId for @${username}...`);
|
|
2042
|
-
const userId = await this.client.bouncerStorage.usernameToUserId(username);
|
|
2043
|
-
if (!userId) {
|
|
2044
|
-
console.error(`[SubscriptionClient] Username @${username} not found on-chain`);
|
|
2045
|
-
return;
|
|
2046
|
-
}
|
|
2047
|
-
console.log(`[SubscriptionClient] Resolved @${username} \u2192 userId ${userId}`);
|
|
2048
|
-
console.log(`[SubscriptionClient] Syncing patches for userId ${userId}...`);
|
|
2049
|
-
const result = await this.sync(userId);
|
|
2050
|
-
console.log(`[SubscriptionClient] Fetched ${result.patches.length} patch(es), truncated: ${result.truncated}`);
|
|
2051
|
-
if (result.patches.length > 0) {
|
|
2052
|
-
console.log(`[SubscriptionClient] Applying patches for ${result.patches.length} subscription graph patch(es)...`);
|
|
2053
|
-
for (const patch of result.patches) {
|
|
2054
|
-
try {
|
|
2055
|
-
const patchUsername = await this.client.bouncerStorage.userIdToUsername(patch.userId);
|
|
2056
|
-
if (!patchUsername) {
|
|
2057
|
-
console.warn(`[SubscriptionClient] No username found for userId ${patch.userId}, skipping patch`);
|
|
2058
|
-
continue;
|
|
2059
|
-
}
|
|
2060
|
-
console.log(`[SubscriptionClient] Applying patch for @${patchUsername} (userId ${patch.userId}, index ${patch.fromIndex}\u2013${patch.toIndex})...`);
|
|
2061
|
-
await deserializePatches(patchUsername, patchToEvmPayload(patch, CURRENT_VERSION));
|
|
2062
|
-
const patches = await getAllPatchesByUsername(patchUsername);
|
|
2063
|
-
await applyRestoredPatches(patches, patchUsername);
|
|
2064
|
-
} catch (patchErr) {
|
|
2065
|
-
console.error(`[SubscriptionClient] Failed to apply patch for userId ${patch.userId}:`, patchErr?.message || patchErr);
|
|
2066
|
-
}
|
|
2067
|
-
}
|
|
2068
|
-
}
|
|
2069
|
-
console.log(`[SubscriptionClient] Successfully loaded library for @${username}`);
|
|
2070
|
-
} catch (err) {
|
|
2071
|
-
console.error(`[SubscriptionClient] Failed to load library for @${username}:`, err?.message || err);
|
|
2072
|
-
}
|
|
2073
|
-
}
|
|
2074
|
-
};
|
|
2075
|
-
|
|
2076
|
-
// src/web3/subscription/registry.ts
|
|
2077
|
-
var clients = {};
|
|
2078
|
-
function getSubscriptionClient(chainId, environment = "production") {
|
|
2079
|
-
const key = `${chainId}:${environment}`;
|
|
2080
|
-
if (!clients[key]) {
|
|
2081
|
-
clients[key] = new SubscriptionClient({ chainId, environment });
|
|
2082
|
-
}
|
|
2083
|
-
return clients[key];
|
|
2084
|
-
}
|
|
2085
|
-
|
|
2086
|
-
// src/web3/subscription/sync-cursor.ts
|
|
2087
|
-
import { del, get, set } from "idb-keyval";
|
|
2088
|
-
function serializeCursor(cursor) {
|
|
2089
|
-
return {
|
|
2090
|
-
rootUserId: cursor.rootUserId,
|
|
2091
|
-
knownNodes: Array.from(cursor.knownNodes.entries()),
|
|
2092
|
-
countSnapshot: Array.from(cursor.countSnapshot.entries()),
|
|
2093
|
-
patchIndex: Array.from(cursor.patchIndex.entries())
|
|
2094
|
-
};
|
|
2095
|
-
}
|
|
2096
|
-
function deserializeCursor(serialized) {
|
|
2097
|
-
return {
|
|
2098
|
-
rootUserId: serialized.rootUserId,
|
|
2099
|
-
knownNodes: new Map(serialized.knownNodes),
|
|
2100
|
-
countSnapshot: new Map(serialized.countSnapshot),
|
|
2101
|
-
patchIndex: new Map(serialized.patchIndex)
|
|
2102
|
-
};
|
|
2103
|
-
}
|
|
2104
|
-
function emptyCursor(rootUserId) {
|
|
2105
|
-
return {
|
|
2106
|
-
rootUserId,
|
|
2107
|
-
knownNodes: /* @__PURE__ */ new Map(),
|
|
2108
|
-
countSnapshot: /* @__PURE__ */ new Map(),
|
|
2109
|
-
patchIndex: /* @__PURE__ */ new Map()
|
|
2110
|
-
};
|
|
2111
|
-
}
|
|
2112
|
-
var IDB_KEY_PREFIX = "web3-sdk:subscription-cursor:";
|
|
2113
|
-
var cursorStore = {
|
|
2114
|
-
async get(userId) {
|
|
2115
|
-
try {
|
|
2116
|
-
const serialized = await get(`${IDB_KEY_PREFIX}${userId}`);
|
|
2117
|
-
return serialized ? deserializeCursor(serialized) : void 0;
|
|
2118
|
-
} catch (e) {
|
|
2119
|
-
console.warn(`[cursorStore] Failed to read cursor for userId ${userId}:`, e);
|
|
2120
|
-
return void 0;
|
|
2121
|
-
}
|
|
2122
|
-
},
|
|
2123
|
-
async set(userId, cursor) {
|
|
2124
|
-
try {
|
|
2125
|
-
await set(`${IDB_KEY_PREFIX}${userId}`, serializeCursor(cursor));
|
|
2126
|
-
} catch (e) {
|
|
2127
|
-
console.warn(`[cursorStore] Failed to persist cursor for userId ${userId}:`, e);
|
|
2128
|
-
}
|
|
2129
|
-
},
|
|
2130
|
-
async clear(userId) {
|
|
2131
|
-
try {
|
|
2132
|
-
await del(`${IDB_KEY_PREFIX}${userId}`);
|
|
2133
|
-
} catch {
|
|
2134
|
-
}
|
|
2135
|
-
}
|
|
2136
|
-
};
|
|
2137
|
-
|
|
2138
|
-
// src/web3/session/storage.ts
|
|
2139
|
-
var STORAGE_KEY_PREFIX = "@the_library/web3-cache:";
|
|
2140
|
-
function isLocalStorageAvailable() {
|
|
2141
|
-
if (typeof window === "undefined" || typeof localStorage === "undefined") {
|
|
2142
|
-
return false;
|
|
2143
|
-
}
|
|
2144
|
-
try {
|
|
2145
|
-
const testKey = "__storage_test__";
|
|
2146
|
-
localStorage.setItem(testKey, "test");
|
|
2147
|
-
localStorage.removeItem(testKey);
|
|
2148
|
-
return true;
|
|
2149
|
-
} catch {
|
|
2150
|
-
return false;
|
|
2151
|
-
}
|
|
2152
|
-
}
|
|
2153
|
-
function getItem(key) {
|
|
2154
|
-
if (!isLocalStorageAvailable()) return null;
|
|
2155
|
-
try {
|
|
2156
|
-
const item = localStorage.getItem(STORAGE_KEY_PREFIX + key);
|
|
2157
|
-
return item ? JSON.parse(item) : null;
|
|
2158
|
-
} catch {
|
|
2159
|
-
return null;
|
|
2160
|
-
}
|
|
2161
|
-
}
|
|
2162
|
-
function setItem(key, value) {
|
|
2163
|
-
if (!isLocalStorageAvailable()) return;
|
|
2164
|
-
try {
|
|
2165
|
-
localStorage.setItem(STORAGE_KEY_PREFIX + key, JSON.stringify(value));
|
|
2166
|
-
} catch (error) {
|
|
2167
|
-
console.warn("[session/storage] Failed to save to localStorage:", error);
|
|
2168
|
-
}
|
|
2169
|
-
}
|
|
2170
|
-
|
|
2171
|
-
// src/web3/session/sync.ts
|
|
2172
|
-
import { deserializePatches as deserializePatches2, applyRestoredPatches as applyRestoredPatches2, CURRENT_VERSION as CURRENT_VERSION2 } from "@the_library/public/models";
|
|
2173
|
-
var _syncedThisSession = /* @__PURE__ */ new Map();
|
|
2174
|
-
async function triggerSubscriptionSync(userId, chainId, environment) {
|
|
2175
|
-
const key = `${chainId}:${userId}`;
|
|
2176
|
-
const inFlight = _syncedThisSession.get(key);
|
|
2177
|
-
if (inFlight) return inFlight;
|
|
2178
|
-
const run = (async () => {
|
|
2179
|
-
const subscriptionClient = getSubscriptionClient(chainId, environment);
|
|
2180
|
-
const existingCursor = await cursorStore.get(userId);
|
|
2181
|
-
const result = existingCursor ? await subscriptionClient.syncSince(existingCursor) : await subscriptionClient.sync(userId);
|
|
2182
|
-
let appliedCount = 0;
|
|
2183
|
-
if (result.patches.length > 0) {
|
|
2184
|
-
const client = getReadClient(chainId, environment);
|
|
2185
|
-
await client.ready;
|
|
2186
|
-
for (const patch of result.patches) {
|
|
2187
|
-
try {
|
|
2188
|
-
const username = await client.bouncerStorage.userIdToUsername(patch.userId);
|
|
2189
|
-
if (!username) continue;
|
|
2190
|
-
await deserializePatches2(username, patchToEvmPayload(patch, CURRENT_VERSION2));
|
|
2191
|
-
const patches = await getAllPatchesByUsername(username);
|
|
2192
|
-
await applyRestoredPatches2(patches, username);
|
|
2193
|
-
appliedCount += patch.toIndex - patch.fromIndex;
|
|
2194
|
-
} catch (e) {
|
|
2195
|
-
console.warn(`[session/sync] failed to apply subscription patch for userId ${patch.userId}`, e);
|
|
2196
|
-
}
|
|
2197
|
-
}
|
|
2198
|
-
}
|
|
2199
|
-
await cursorStore.set(userId, result.cursor);
|
|
2200
|
-
WalletEvents.emitSubscriptionPatchesSynced({ rootUserId: userId, chainId, appliedCount, timestamp: Date.now() });
|
|
2201
|
-
})();
|
|
2202
|
-
_syncedThisSession.set(key, run);
|
|
2203
|
-
try {
|
|
2204
|
-
await run;
|
|
2205
|
-
} catch (e) {
|
|
2206
|
-
_syncedThisSession.delete(key);
|
|
2207
|
-
console.warn(`[session/sync] subscription sync failed for userId ${userId}`, e);
|
|
2208
|
-
}
|
|
2209
|
-
}
|
|
2210
|
-
async function syncAccount(address, chainId, wallet, environment = "production", forceRefresh = false) {
|
|
2211
|
-
const existing = sessionStore.getState().known.find((a) => a.account.toLowerCase() === address.toLowerCase() && a.chainId === chainId);
|
|
2212
|
-
if (!forceRefresh && existing?.lastUpdated) {
|
|
2213
|
-
if (existing.hasAccount && existing.userId) {
|
|
2214
|
-
void triggerSubscriptionSync(existing.userId, chainId, environment);
|
|
2215
|
-
}
|
|
2216
|
-
return existing;
|
|
2217
|
-
}
|
|
2218
|
-
const client = getReadClient(chainId, environment);
|
|
2219
|
-
await client.ready;
|
|
2220
|
-
const account = existing ? { ...existing } : {
|
|
2221
|
-
account: address,
|
|
2222
|
-
username: "",
|
|
2223
|
-
hasAccount: false,
|
|
2224
|
-
userId: 0,
|
|
2225
|
-
lastPatchIndex: 0,
|
|
2226
|
-
lastRestorationIndex: 0,
|
|
2227
|
-
chainId,
|
|
2228
|
-
wallet
|
|
2229
|
-
};
|
|
2230
|
-
const hasAccount = await client.bouncerStorage.hasAccount(address);
|
|
2231
|
-
account.hasAccount = hasAccount;
|
|
2232
|
-
if (hasAccount) {
|
|
2233
|
-
const [username, country, language, userId] = await client.bouncerStorage.userInfos(address);
|
|
2234
|
-
account.username = username;
|
|
2235
|
-
account.country = country;
|
|
2236
|
-
account.language = language;
|
|
2237
|
-
account.userId = userId;
|
|
2238
|
-
const { total, donations, unspent } = await client.projectManagerStorage.balanceOfAddress(address);
|
|
2239
|
-
account.projectBalance = { contributions: total, allocated: donations, remaining: unspent };
|
|
2240
|
-
try {
|
|
2241
|
-
account.level = await client.archivistStorage.userLevel(userId);
|
|
2242
|
-
} catch {
|
|
2243
|
-
account.level = 1;
|
|
2244
|
-
}
|
|
2245
|
-
try {
|
|
2246
|
-
account.donationsPerProject = await client.projectManagerStorage.addressDonationsPerProject(address);
|
|
2247
|
-
} catch {
|
|
2248
|
-
account.donationsPerProject = [];
|
|
2249
|
-
}
|
|
2250
|
-
await triggerSubscriptionSync(userId, chainId, environment);
|
|
2251
|
-
}
|
|
2252
|
-
account.lastUpdated = Date.now();
|
|
2253
|
-
sessionStore.addKnown(account);
|
|
2254
|
-
return account;
|
|
2255
|
-
}
|
|
2256
|
-
async function restoreAccountSave(address, chainId, environment = "production") {
|
|
2257
|
-
const known = sessionStore.getState().known.find((a) => a.account.toLowerCase() === address.toLowerCase() && a.chainId === chainId);
|
|
2258
|
-
if (!known || !known.hasAccount) return false;
|
|
2259
|
-
const client = getReadClient(chainId, environment);
|
|
2260
|
-
await client.ready;
|
|
2261
|
-
try {
|
|
2262
|
-
const nbSavedIndex = await client.factory.nbWritesByUsername(known.username);
|
|
2263
|
-
if (nbSavedIndex > known.lastRestorationIndex) {
|
|
2264
|
-
const [compressedActions, indexes, stringIndexes] = await client.factory.loadUsernameSince(
|
|
2265
|
-
known.username,
|
|
2266
|
-
known.lastRestorationIndex
|
|
2267
|
-
);
|
|
2268
|
-
let appliedCount = 0;
|
|
2269
|
-
if (compressedActions && compressedActions.length > 0) {
|
|
2270
|
-
await deserializePatches2("mine", {
|
|
2271
|
-
version: CURRENT_VERSION2,
|
|
2272
|
-
patches: compressedActions,
|
|
2273
|
-
textIndex: indexes.map(Number),
|
|
2274
|
-
textData: stringIndexes
|
|
2275
|
-
});
|
|
2276
|
-
const patches = await getAllPatchesByUsername("mine");
|
|
2277
|
-
await applyRestoredPatches2(patches, "mine");
|
|
2278
|
-
appliedCount = compressedActions.length;
|
|
2279
|
-
}
|
|
2280
|
-
sessionStore.setLastRestorationIndex(address, chainId, nbSavedIndex);
|
|
2281
|
-
WalletEvents.emitSaveRestored({
|
|
2282
|
-
wallet: known.wallet,
|
|
2283
|
-
chainId,
|
|
2284
|
-
account: address,
|
|
2285
|
-
username: known.username,
|
|
2286
|
-
newRestorationIndex: nbSavedIndex,
|
|
2287
|
-
appliedCount,
|
|
2288
|
-
timestamp: Date.now()
|
|
2289
|
-
});
|
|
2290
|
-
}
|
|
2291
|
-
return true;
|
|
2292
|
-
} catch (e) {
|
|
2293
|
-
console.error(`[session/sync] restoreAccountSave failed for ${address} on ${chainId}`, e);
|
|
2294
|
-
return false;
|
|
2295
|
-
}
|
|
2296
|
-
}
|
|
2297
|
-
async function hasUnsavedPatches(address, chainId) {
|
|
2298
|
-
const { lastPatchIndex } = sessionStore.lastSyncCounters(address, chainId);
|
|
2299
|
-
const nbPatches = await getNbPatches("mine");
|
|
2300
|
-
return nbPatches > lastPatchIndex;
|
|
2301
|
-
}
|
|
2302
|
-
async function loadNetworkInfos(chainId, environment = "production", forceRefresh = false) {
|
|
2303
|
-
const key = `networkInfos_${chainId}${environment === "staging" ? "_staging" : ""}`;
|
|
2304
|
-
if (!forceRefresh) {
|
|
2305
|
-
const cached = getItem(key);
|
|
2306
|
-
if (cached) return cached;
|
|
2307
|
-
}
|
|
2308
|
-
const client = getReadClient(chainId, environment);
|
|
2309
|
-
await client.ready;
|
|
2310
|
-
const [locationStats, nbProjects, nbUsers] = await Promise.all([
|
|
2311
|
-
client.bouncerStorage.getAllLocationCounts(),
|
|
2312
|
-
client.projectManagerStorage.nbProjects(),
|
|
2313
|
-
client.bouncerStorage.nbAccounts()
|
|
2314
|
-
]);
|
|
2315
|
-
const result = { nbUsers, nbLocations: locationStats.length, nbProjects, locationStats };
|
|
2316
|
-
setItem(key, result);
|
|
2317
|
-
return result;
|
|
2318
|
-
}
|
|
2319
|
-
|
|
2320
|
-
// src/web3/wallet/registry.ts
|
|
2321
|
-
var connectors = /* @__PURE__ */ new Map();
|
|
2322
|
-
function registerConnector(connector) {
|
|
2323
|
-
connectors.set(connector.type, connector);
|
|
2324
|
-
}
|
|
2325
|
-
function getConnector(type) {
|
|
2326
|
-
return connectors.get(type);
|
|
2327
|
-
}
|
|
2328
|
-
function getRegisteredConnectors() {
|
|
2329
|
-
return Array.from(connectors.values());
|
|
2330
|
-
}
|
|
2331
|
-
|
|
2332
|
-
// src/web3/wallet/credentials.ts
|
|
2333
|
-
var PK_STORAGE_KEY_PREFIX = "wallet_pk_";
|
|
2334
|
-
var STORAGE_KEY_PREFIX2 = "@the_library/web3-session:";
|
|
2335
|
-
var cachedEmail = null;
|
|
2336
|
-
function getCachedEmail() {
|
|
2337
|
-
return cachedEmail;
|
|
2338
|
-
}
|
|
2339
|
-
function setCachedEmail(email) {
|
|
2340
|
-
cachedEmail = email;
|
|
2341
|
-
}
|
|
2342
|
-
function isLocalStorageAvailable2() {
|
|
2343
|
-
if (typeof window === "undefined" || typeof localStorage === "undefined") {
|
|
2344
|
-
return false;
|
|
2345
|
-
}
|
|
2346
|
-
try {
|
|
2347
|
-
const testKey = "__storage_test__";
|
|
2348
|
-
localStorage.setItem(testKey, "test");
|
|
2349
|
-
localStorage.removeItem(testKey);
|
|
2350
|
-
return true;
|
|
2351
|
-
} catch {
|
|
2352
|
-
return false;
|
|
2353
|
-
}
|
|
2354
|
-
}
|
|
2355
|
-
function getItem2(key) {
|
|
2356
|
-
if (!isLocalStorageAvailable2()) {
|
|
2357
|
-
return null;
|
|
2358
|
-
}
|
|
2359
|
-
try {
|
|
2360
|
-
const item = localStorage.getItem(STORAGE_KEY_PREFIX2 + key);
|
|
2361
|
-
return item ? JSON.parse(item) : null;
|
|
2362
|
-
} catch {
|
|
2363
|
-
return null;
|
|
2364
|
-
}
|
|
2365
|
-
}
|
|
2366
|
-
function setItem2(key, value) {
|
|
2367
|
-
if (!isLocalStorageAvailable2()) {
|
|
2368
|
-
return;
|
|
2369
|
-
}
|
|
2370
|
-
try {
|
|
2371
|
-
localStorage.setItem(STORAGE_KEY_PREFIX2 + key, JSON.stringify(value));
|
|
2372
|
-
} catch (error) {
|
|
2373
|
-
console.warn("Failed to save to localStorage:", error);
|
|
2374
|
-
}
|
|
2375
|
-
}
|
|
2376
|
-
function storePrivateKey(chainId, privateKey) {
|
|
2377
|
-
if (!privateKey) {
|
|
2378
|
-
throw new Error("Private key is required");
|
|
2379
|
-
}
|
|
2380
|
-
const key = `${PK_STORAGE_KEY_PREFIX}${chainId}`;
|
|
2381
|
-
setItem2(key, privateKey);
|
|
2382
|
-
}
|
|
2383
|
-
function getPrivateKey(chainId) {
|
|
2384
|
-
const key = `${PK_STORAGE_KEY_PREFIX}${chainId}`;
|
|
2385
|
-
return getItem2(key);
|
|
2386
|
-
}
|
|
2387
|
-
function hasPrivateKey(chainId) {
|
|
2388
|
-
const key = `${PK_STORAGE_KEY_PREFIX}${chainId}`;
|
|
2389
|
-
return !!getItem2(key);
|
|
2390
|
-
}
|
|
2391
|
-
function hasAnyPrivateKey() {
|
|
2392
|
-
if (!isLocalStorageAvailable2()) return false;
|
|
2393
|
-
const prefix = `${STORAGE_KEY_PREFIX2}${PK_STORAGE_KEY_PREFIX}`;
|
|
2394
|
-
for (let i = 0; i < localStorage.length; i++) {
|
|
2395
|
-
if (localStorage.key(i)?.startsWith(prefix)) return true;
|
|
2396
|
-
}
|
|
2397
|
-
return false;
|
|
2398
|
-
}
|
|
2399
|
-
var storeEncryptedPrivateKey = (chainId, privateKey, _email) => storePrivateKey(chainId, privateKey);
|
|
2400
|
-
var getDecryptedPrivateKey = (chainId, _email) => getPrivateKey(chainId);
|
|
2401
|
-
var hasEncryptedPrivateKey = (chainId) => hasPrivateKey(chainId);
|
|
2402
|
-
|
|
2403
|
-
// src/web3/wallet/PrivateKeyConnector.ts
|
|
2404
|
-
import { privateKeyToAccount } from "viem/accounts";
|
|
2405
|
-
import { createWalletClient, http as http2 } from "viem";
|
|
2406
|
-
function normalizePrivateKeyHex(privateKey) {
|
|
2407
|
-
return privateKey.startsWith("0x") ? privateKey : `0x${privateKey}`;
|
|
2408
|
-
}
|
|
2409
|
-
function addressFromPrivateKey(privateKey) {
|
|
2410
|
-
return privateKeyToAccount(normalizePrivateKeyHex(privateKey)).address;
|
|
2411
|
-
}
|
|
2412
|
-
function createPrivateKeyWalletClient(chainId, privateKey) {
|
|
2413
|
-
const account = privateKeyToAccount(normalizePrivateKeyHex(privateKey));
|
|
2414
|
-
const chainConfig = getChain(chainId);
|
|
2415
|
-
return createWalletClient({
|
|
2416
|
-
account,
|
|
2417
|
-
chain: toViemChain(chainConfig),
|
|
2418
|
-
transport: http2(chainConfig.rpc)
|
|
2419
|
-
});
|
|
2420
|
-
}
|
|
2421
|
-
var PrivateKeyConnector = class {
|
|
2422
|
-
constructor() {
|
|
2423
|
-
this.type = "private_key";
|
|
2424
|
-
this.activeChainId = 0;
|
|
2425
|
-
this.chainChangedCallbacks = /* @__PURE__ */ new Set();
|
|
2426
|
-
}
|
|
2427
|
-
isAvailable() {
|
|
2428
|
-
return true;
|
|
2429
|
-
}
|
|
2430
|
-
// chainId is optional on the WalletConnector interface (defaults to DEFAULT_CHAIN_ID) —
|
|
2431
|
-
// callers that know the target chain (e.g. bootstrapWebSDK, UI chain selector) pass it
|
|
2432
|
-
// explicitly rather than relying on whichever key happens to be stored first.
|
|
2433
|
-
async connect(chainId = DEFAULT_CHAIN_ID) {
|
|
2434
|
-
if (!hasPrivateKey(chainId)) {
|
|
2435
|
-
throw new Error(`No private key configured for chain ${chainId}`);
|
|
2436
|
-
}
|
|
2437
|
-
this.activeChainId = chainId;
|
|
2438
|
-
const privateKey = getPrivateKey(chainId);
|
|
2439
|
-
if (!privateKey) {
|
|
2440
|
-
throw new Error(`No private key configured for chain ${chainId}`);
|
|
2441
|
-
}
|
|
2442
|
-
return {
|
|
2443
|
-
address: addressFromPrivateKey(privateKey),
|
|
2444
|
-
chainId
|
|
2445
|
-
};
|
|
2446
|
-
}
|
|
2447
|
-
async getAccounts() {
|
|
2448
|
-
if (!this.activeChainId) return [];
|
|
2449
|
-
const privateKey = getPrivateKey(this.activeChainId);
|
|
2450
|
-
if (!privateKey) return [];
|
|
2451
|
-
return [addressFromPrivateKey(privateKey)];
|
|
2452
|
-
}
|
|
2453
|
-
async getChainId() {
|
|
2454
|
-
return this.activeChainId;
|
|
2455
|
-
}
|
|
2456
|
-
async requestSwitchChain(chainId) {
|
|
2457
|
-
const privateKey = getPrivateKey(chainId);
|
|
2458
|
-
if (!privateKey) {
|
|
2459
|
-
throw new Error(`No private key configured for chain ${chainId}`);
|
|
2460
|
-
}
|
|
2461
|
-
this.activeChainId = chainId;
|
|
2462
|
-
for (const cb of this.chainChangedCallbacks) {
|
|
2463
|
-
cb(chainId);
|
|
2464
|
-
}
|
|
2465
|
-
}
|
|
2466
|
-
async sendTransaction(tx, chainId) {
|
|
2467
|
-
const privateKey = getPrivateKey(chainId);
|
|
2468
|
-
if (!privateKey) {
|
|
2469
|
-
throw new Error(`No private key found for chain ${chainId}`);
|
|
2470
|
-
}
|
|
2471
|
-
const walletClient = createPrivateKeyWalletClient(chainId, privateKey);
|
|
2472
|
-
return await walletClient.sendTransaction(tx);
|
|
2473
|
-
}
|
|
2474
|
-
async signMessage(message) {
|
|
2475
|
-
if (!this.activeChainId) {
|
|
2476
|
-
throw new Error("Wallet not connected");
|
|
2477
|
-
}
|
|
2478
|
-
const privateKey = getPrivateKey(this.activeChainId);
|
|
2479
|
-
if (!privateKey) {
|
|
2480
|
-
throw new Error("No private key found");
|
|
2481
|
-
}
|
|
2482
|
-
const account = privateKeyToAccount(normalizePrivateKeyHex(privateKey));
|
|
2483
|
-
return await account.signMessage({ message });
|
|
2484
|
-
}
|
|
2485
|
-
async getWalletClient(chainId) {
|
|
2486
|
-
const privateKey = getPrivateKey(chainId);
|
|
2487
|
-
if (!privateKey) {
|
|
2488
|
-
throw new Error(`No private key configured for chain ${chainId}`);
|
|
2489
|
-
}
|
|
2490
|
-
return createPrivateKeyWalletClient(chainId, privateKey);
|
|
2491
|
-
}
|
|
2492
|
-
onAccountChanged(cb) {
|
|
2493
|
-
return () => {
|
|
2494
|
-
};
|
|
2495
|
-
}
|
|
2496
|
-
onChainChanged(cb) {
|
|
2497
|
-
this.chainChangedCallbacks.add(cb);
|
|
2498
|
-
return () => {
|
|
2499
|
-
this.chainChangedCallbacks.delete(cb);
|
|
2500
|
-
};
|
|
2501
|
-
}
|
|
2502
|
-
disconnect() {
|
|
2503
|
-
this.activeChainId = 0;
|
|
2504
|
-
}
|
|
2505
|
-
};
|
|
2506
|
-
function createPrivateKeyConnector() {
|
|
2507
|
-
return new PrivateKeyConnector();
|
|
2508
|
-
}
|
|
2509
|
-
|
|
2510
|
-
// src/web3/session/projects.ts
|
|
2511
|
-
var projectLocale = (project, userLanguage, chainId) => {
|
|
2512
|
-
const { decimals } = getChain(chainId);
|
|
2513
|
-
const balance = project.balance / 10 ** decimals;
|
|
2514
|
-
const projectLangIndex = project.availableLanguages.findIndex((lang) => lang === userLanguage);
|
|
2515
|
-
if (projectLangIndex !== -1) {
|
|
2516
|
-
return {
|
|
2517
|
-
lang: project.availableLanguages[projectLangIndex],
|
|
2518
|
-
version: { ...project.versions[projectLangIndex] },
|
|
2519
|
-
id: project.id,
|
|
2520
|
-
balance
|
|
2521
|
-
};
|
|
2522
|
-
}
|
|
2523
|
-
const englishIndex = project.availableLanguages.findIndex((lang) => lang === " eng");
|
|
2524
|
-
if (englishIndex !== -1) {
|
|
2525
|
-
return {
|
|
2526
|
-
lang: " eng",
|
|
2527
|
-
version: { ...project.versions[englishIndex] },
|
|
2528
|
-
id: project.id,
|
|
2529
|
-
balance
|
|
2530
|
-
};
|
|
2531
|
-
}
|
|
2532
|
-
if (project.availableLanguages.length === 0) {
|
|
2533
|
-
throw new Error(`No language available for project ${project.id}`);
|
|
2534
|
-
}
|
|
2535
|
-
return {
|
|
2536
|
-
lang: project.availableLanguages[0],
|
|
2537
|
-
version: { ...project.versions[0] },
|
|
2538
|
-
id: project.id,
|
|
2539
|
-
balance
|
|
2540
|
-
};
|
|
2541
|
-
};
|
|
2542
|
-
var ProjectRegistry = class {
|
|
2543
|
-
projectKey(chainId, language, projectId) {
|
|
2544
|
-
return `${chainId}_${language}_${projectId}_v2`;
|
|
2545
|
-
}
|
|
2546
|
-
nbProjectsKey(chainId, language) {
|
|
2547
|
-
return `${chainId}_${language}_nbProjects_v2`;
|
|
2548
|
-
}
|
|
2549
|
-
nbProjects(chainId, language) {
|
|
2550
|
-
const nb = getItem(this.nbProjectsKey(chainId, language));
|
|
2551
|
-
return nb ? parseInt(nb, 10) : 0;
|
|
2552
|
-
}
|
|
2553
|
-
setNbProjects(chainId, language, nb) {
|
|
2554
|
-
setItem(this.nbProjectsKey(chainId, language), nb.toString());
|
|
2555
|
-
}
|
|
2556
|
-
getProject(chainId, language, projectId) {
|
|
2557
|
-
return getItem(this.projectKey(chainId, language, projectId));
|
|
2558
|
-
}
|
|
2559
|
-
cacheProject(chainId, language, project) {
|
|
2560
|
-
setItem(this.projectKey(chainId, language, project.id), project);
|
|
2561
|
-
}
|
|
2562
|
-
// Preserves position (null for a missing entry) so callers can index this
|
|
2563
|
-
// the same way as loadProjects()'s online path: result[i] is always project
|
|
2564
|
-
// (i+1), whether the data came from a live fetch or this offline fallback.
|
|
2565
|
-
getCachedProjects(chainId, language) {
|
|
2566
|
-
const nbProjects = this.nbProjects(chainId, language);
|
|
2567
|
-
if (nbProjects <= 0) return [];
|
|
2568
|
-
const projects = [];
|
|
2569
|
-
for (let i = 1; i <= nbProjects; i++) {
|
|
2570
|
-
projects.push(this.getProject(chainId, language, i));
|
|
2571
|
-
}
|
|
2572
|
-
return projects;
|
|
2573
|
-
}
|
|
2574
|
-
async loadProject(chainId, language, projectId, refresh = false) {
|
|
2575
|
-
const cached = this.getProject(chainId, language, projectId);
|
|
2576
|
-
if (cached !== null && !refresh) {
|
|
2577
|
-
return cached;
|
|
2578
|
-
}
|
|
2579
|
-
const client = getReadClient(chainId);
|
|
2580
|
-
await client.ready;
|
|
2581
|
-
const loaded = projectLocale(await client.projectManagerStorage.loadProject(projectId), language, chainId);
|
|
2582
|
-
this.cacheProject(chainId, language, loaded);
|
|
2583
|
-
return loaded;
|
|
2584
|
-
}
|
|
2585
|
-
async loadProjects(chainId, language) {
|
|
2586
|
-
let client;
|
|
2587
|
-
try {
|
|
2588
|
-
client = getReadClient(chainId);
|
|
2589
|
-
} catch (e) {
|
|
2590
|
-
console.warn(`[ProjectRegistry] No read client for chain ${chainId} \u2014 returning cached projects only.`, e);
|
|
2591
|
-
return this.getCachedProjects(chainId, language);
|
|
2592
|
-
}
|
|
2593
|
-
await client.ready;
|
|
2594
|
-
const cachedNbProjects = this.nbProjects(chainId, language);
|
|
2595
|
-
const liveNbProjects = await client.projectManagerStorage.nbProjects();
|
|
2596
|
-
if (liveNbProjects !== cachedNbProjects) {
|
|
2597
|
-
this.setNbProjects(chainId, language, liveNbProjects);
|
|
2598
|
-
}
|
|
2599
|
-
const range = Array.from({ length: liveNbProjects }, (_, i) => i + 1);
|
|
2600
|
-
return Promise.all(
|
|
2601
|
-
range.map(
|
|
2602
|
-
(id) => this.loadProject(chainId, language, id).catch((e) => {
|
|
2603
|
-
console.error(`[ProjectRegistry] Error loading project ${id}:`, e);
|
|
2604
|
-
return null;
|
|
2605
|
-
})
|
|
2606
|
-
)
|
|
2607
|
-
);
|
|
2608
|
-
}
|
|
2609
|
-
};
|
|
2610
|
-
var projectRegistry = new ProjectRegistry();
|
|
2611
|
-
var loadProjects = (chainId, language) => projectRegistry.loadProjects(chainId, language);
|
|
2612
|
-
var loadProject = (chainId, language, projectId, refresh = false) => projectRegistry.loadProject(chainId, language, projectId, refresh);
|
|
2613
|
-
|
|
2614
|
-
// src/web3/wallet/MetaMaskConnector.ts
|
|
2615
|
-
import { createWalletClient as createWalletClient2, custom } from "viem";
|
|
2616
|
-
var announcedMetaMaskProvider = null;
|
|
2617
|
-
if (typeof window !== "undefined") {
|
|
2618
|
-
window.addEventListener("eip6963:announceProvider", (event) => {
|
|
2619
|
-
const detail = event.detail;
|
|
2620
|
-
if (detail.info.rdns === "io.metamask" || detail.info.rdns === "io.metamask.flask") {
|
|
2621
|
-
announcedMetaMaskProvider = detail.provider;
|
|
2622
|
-
}
|
|
2623
|
-
});
|
|
2624
|
-
window.dispatchEvent(new Event("eip6963:requestProvider"));
|
|
2625
|
-
}
|
|
2626
|
-
var MetaMaskConnector = class {
|
|
2627
|
-
constructor() {
|
|
2628
|
-
this.type = "metamask";
|
|
2629
|
-
this.accountChangedCallbacks = /* @__PURE__ */ new Set();
|
|
2630
|
-
this.chainChangedCallbacks = /* @__PURE__ */ new Set();
|
|
2631
|
-
this.isListening = false;
|
|
2632
|
-
}
|
|
2633
|
-
getProvider() {
|
|
2634
|
-
if (announcedMetaMaskProvider) return announcedMetaMaskProvider;
|
|
2635
|
-
if (typeof window !== "undefined") {
|
|
2636
|
-
return window.ethereum;
|
|
2637
|
-
}
|
|
2638
|
-
return null;
|
|
2639
|
-
}
|
|
2640
|
-
isAvailable() {
|
|
2641
|
-
const provider = this.getProvider();
|
|
2642
|
-
return !!provider;
|
|
2643
|
-
}
|
|
2644
|
-
setupListeners() {
|
|
2645
|
-
if (this.isListening) return;
|
|
2646
|
-
const provider = this.getProvider();
|
|
2647
|
-
if (!provider) return;
|
|
2648
|
-
if (typeof provider.on === "function") {
|
|
2649
|
-
provider.on("accountsChanged", (accounts) => {
|
|
2650
|
-
const address = accounts[0] || "";
|
|
2651
|
-
for (const cb of this.accountChangedCallbacks) {
|
|
2652
|
-
cb(address);
|
|
2653
|
-
}
|
|
2654
|
-
});
|
|
2655
|
-
provider.on("chainChanged", (chainIdHex) => {
|
|
2656
|
-
const chainId = parseInt(chainIdHex, 16);
|
|
2657
|
-
for (const cb of this.chainChangedCallbacks) {
|
|
2658
|
-
cb(chainId);
|
|
2659
|
-
}
|
|
2660
|
-
});
|
|
2661
|
-
this.isListening = true;
|
|
2662
|
-
}
|
|
2663
|
-
}
|
|
2664
|
-
async connect() {
|
|
2665
|
-
const provider = this.getProvider();
|
|
2666
|
-
if (!provider) {
|
|
2667
|
-
throw new Error("MetaMask provider not found");
|
|
2668
|
-
}
|
|
2669
|
-
this.setupListeners();
|
|
2670
|
-
const accounts = await provider.request({
|
|
2671
|
-
method: "eth_requestAccounts"
|
|
2672
|
-
});
|
|
2673
|
-
const chainIdHex = await provider.request({
|
|
2674
|
-
method: "eth_chainId"
|
|
2675
|
-
});
|
|
2676
|
-
return {
|
|
2677
|
-
address: accounts[0],
|
|
2678
|
-
chainId: parseInt(chainIdHex, 16)
|
|
2679
|
-
};
|
|
2680
|
-
}
|
|
2681
|
-
async getAccounts() {
|
|
2682
|
-
const provider = this.getProvider();
|
|
2683
|
-
if (!provider) return [];
|
|
2684
|
-
try {
|
|
2685
|
-
const accounts = await provider.request({
|
|
2686
|
-
method: "eth_accounts"
|
|
2687
|
-
});
|
|
2688
|
-
return accounts || [];
|
|
2689
|
-
} catch {
|
|
2690
|
-
return [];
|
|
2691
|
-
}
|
|
2692
|
-
}
|
|
2693
|
-
async getChainId() {
|
|
2694
|
-
const provider = this.getProvider();
|
|
2695
|
-
if (!provider) return 0;
|
|
2696
|
-
try {
|
|
2697
|
-
const chainIdHex = await provider.request({
|
|
2698
|
-
method: "eth_chainId"
|
|
2699
|
-
});
|
|
2700
|
-
return parseInt(chainIdHex, 16);
|
|
2701
|
-
} catch {
|
|
2702
|
-
return 0;
|
|
2703
|
-
}
|
|
2704
|
-
}
|
|
2705
|
-
async requestSwitchChain(chainId) {
|
|
2706
|
-
const provider = this.getProvider();
|
|
2707
|
-
if (!provider) {
|
|
2708
|
-
throw new Error("MetaMask provider not found");
|
|
2709
|
-
}
|
|
2710
|
-
const targetChainIdHex = "0x" + chainId.toString(16);
|
|
2711
|
-
try {
|
|
2712
|
-
await provider.request({
|
|
2713
|
-
method: "wallet_switchEthereumChain",
|
|
2714
|
-
params: [{ chainId: targetChainIdHex }]
|
|
2715
|
-
});
|
|
2716
|
-
} catch (switchError) {
|
|
2717
|
-
if (switchError.code === 4902) {
|
|
2718
|
-
const chainConfig = getChain(chainId);
|
|
2719
|
-
if (!chainConfig) {
|
|
2720
|
-
throw new Error(`No configuration found for chain ID: ${chainId}`);
|
|
2721
|
-
}
|
|
2722
|
-
await provider.request({
|
|
2723
|
-
method: "wallet_addEthereumChain",
|
|
2724
|
-
params: [
|
|
2725
|
-
{
|
|
2726
|
-
chainId: targetChainIdHex,
|
|
2727
|
-
chainName: chainConfig.name,
|
|
2728
|
-
rpcUrls: [chainConfig.rpc],
|
|
2729
|
-
blockExplorerUrls: [chainConfig.explorer],
|
|
2730
|
-
nativeCurrency: {
|
|
2731
|
-
decimals: chainConfig.decimals || 18,
|
|
2732
|
-
name: chainConfig.name,
|
|
2733
|
-
symbol: chainConfig.symbol
|
|
2734
|
-
}
|
|
2735
|
-
}
|
|
2736
|
-
]
|
|
2737
|
-
});
|
|
2738
|
-
} else {
|
|
2739
|
-
throw switchError;
|
|
2740
|
-
}
|
|
2741
|
-
}
|
|
2742
|
-
}
|
|
2743
|
-
async sendTransaction(tx, chainId) {
|
|
2744
|
-
const provider = this.getProvider();
|
|
2745
|
-
if (!provider) {
|
|
2746
|
-
throw new Error("MetaMask provider not found");
|
|
2747
|
-
}
|
|
2748
|
-
const accounts = await this.getAccounts();
|
|
2749
|
-
if (accounts.length === 0) {
|
|
2750
|
-
throw new Error("No accounts connected");
|
|
2751
|
-
}
|
|
2752
|
-
const chain = toViemChain(getChain(chainId));
|
|
2753
|
-
const walletClient = createWalletClient2({
|
|
2754
|
-
account: accounts[0],
|
|
2755
|
-
chain,
|
|
2756
|
-
transport: custom(provider)
|
|
2757
|
-
});
|
|
2758
|
-
return await walletClient.sendTransaction(tx);
|
|
2759
|
-
}
|
|
2760
|
-
async signMessage(message) {
|
|
2761
|
-
const provider = this.getProvider();
|
|
2762
|
-
if (!provider) {
|
|
2763
|
-
throw new Error("MetaMask provider not found");
|
|
2764
|
-
}
|
|
2765
|
-
const accounts = await this.getAccounts();
|
|
2766
|
-
if (accounts.length === 0) {
|
|
2767
|
-
throw new Error("No accounts connected");
|
|
2768
|
-
}
|
|
2769
|
-
const walletClient = createWalletClient2({
|
|
2770
|
-
account: accounts[0],
|
|
2771
|
-
transport: custom(provider)
|
|
2772
|
-
});
|
|
2773
|
-
return await walletClient.signMessage({
|
|
2774
|
-
account: accounts[0],
|
|
2775
|
-
message
|
|
2776
|
-
});
|
|
2777
|
-
}
|
|
2778
|
-
async getWalletClient(chainId) {
|
|
2779
|
-
const provider = this.getProvider();
|
|
2780
|
-
if (!provider) {
|
|
2781
|
-
throw new Error("MetaMask provider not found");
|
|
2782
|
-
}
|
|
2783
|
-
const accounts = await this.getAccounts();
|
|
2784
|
-
if (accounts.length === 0) {
|
|
2785
|
-
throw new Error("No accounts connected");
|
|
2786
|
-
}
|
|
2787
|
-
const chain = toViemChain(getChain(chainId));
|
|
2788
|
-
return createWalletClient2({
|
|
2789
|
-
account: accounts[0],
|
|
2790
|
-
chain,
|
|
2791
|
-
transport: custom(provider)
|
|
2792
|
-
});
|
|
2793
|
-
}
|
|
2794
|
-
onAccountChanged(cb) {
|
|
2795
|
-
this.setupListeners();
|
|
2796
|
-
this.accountChangedCallbacks.add(cb);
|
|
2797
|
-
return () => {
|
|
2798
|
-
this.accountChangedCallbacks.delete(cb);
|
|
2799
|
-
};
|
|
2800
|
-
}
|
|
2801
|
-
onChainChanged(cb) {
|
|
2802
|
-
this.setupListeners();
|
|
2803
|
-
this.chainChangedCallbacks.add(cb);
|
|
2804
|
-
return () => {
|
|
2805
|
-
this.chainChangedCallbacks.delete(cb);
|
|
2806
|
-
};
|
|
2807
|
-
}
|
|
2808
|
-
disconnect() {
|
|
2809
|
-
}
|
|
2810
|
-
};
|
|
2811
|
-
function createMetaMaskConnector() {
|
|
2812
|
-
return new MetaMaskConnector();
|
|
2813
|
-
}
|
|
2814
|
-
|
|
2815
|
-
export {
|
|
2816
|
-
EVM_CHAINS,
|
|
2817
|
-
DEFAULT_CHAIN_ID,
|
|
2818
|
-
getChain,
|
|
2819
|
-
toViemChain,
|
|
2820
|
-
pythAbi,
|
|
2821
|
-
addressRegistryAbi,
|
|
2822
|
-
stringToBytes4,
|
|
2823
|
-
normalizeError,
|
|
2824
|
-
EvmClient,
|
|
2825
|
-
createEvmClient,
|
|
2826
|
-
readOnlyClients,
|
|
2827
|
-
readOnlyStagingClients,
|
|
2828
|
-
getReadClient,
|
|
2829
|
-
getEvmClient,
|
|
2830
|
-
getReadyEvmClient,
|
|
2831
|
-
createSessionStore,
|
|
2832
|
-
sessionStore,
|
|
2833
|
-
allRegisteredAccounts,
|
|
2834
|
-
EventBus,
|
|
2835
|
-
getEventBus,
|
|
2836
|
-
EventName,
|
|
2837
|
-
WalletState,
|
|
2838
|
-
WalletError,
|
|
2839
|
-
WalletUxError,
|
|
2840
|
-
WalletEvents,
|
|
2841
|
-
SubscriptionClient,
|
|
2842
|
-
getSubscriptionClient,
|
|
2843
|
-
serializeCursor,
|
|
2844
|
-
deserializeCursor,
|
|
2845
|
-
emptyCursor,
|
|
2846
|
-
cursorStore,
|
|
2847
|
-
syncAccount,
|
|
2848
|
-
restoreAccountSave,
|
|
2849
|
-
hasUnsavedPatches,
|
|
2850
|
-
loadNetworkInfos,
|
|
2851
|
-
registerConnector,
|
|
2852
|
-
getConnector,
|
|
2853
|
-
getRegisteredConnectors,
|
|
2854
|
-
getCachedEmail,
|
|
2855
|
-
setCachedEmail,
|
|
2856
|
-
storePrivateKey,
|
|
2857
|
-
getPrivateKey,
|
|
2858
|
-
hasPrivateKey,
|
|
2859
|
-
hasAnyPrivateKey,
|
|
2860
|
-
storeEncryptedPrivateKey,
|
|
2861
|
-
getDecryptedPrivateKey,
|
|
2862
|
-
hasEncryptedPrivateKey,
|
|
2863
|
-
addressFromPrivateKey,
|
|
2864
|
-
createPrivateKeyWalletClient,
|
|
2865
|
-
PrivateKeyConnector,
|
|
2866
|
-
createPrivateKeyConnector,
|
|
2867
|
-
projectLocale,
|
|
2868
|
-
loadProjects,
|
|
2869
|
-
loadProject,
|
|
2870
|
-
MetaMaskConnector,
|
|
2871
|
-
createMetaMaskConnector
|
|
2872
|
-
};
|
|
2873
|
-
//# sourceMappingURL=chunk-PUYDAUCI.js.map
|