๐ src/web3/client/types.ts
D-OPEN SOVEREIGN
1import type { TransactionRequest, WalletClient } from 'viem';
2
3export interface ContractAddresses {
4 factory: string;
5 bouncerStorage: string;
6 scientistStorage: string;
7 backupStorage: string;
8 projectManagerStorage: string;
9 subscriptionManager?: string;
10 libraryRegistryStorage?: string;
11 publicLibraryStorage?: string;
12}
13
14export interface StripeDonation {
15 stripePaymentId: string;
16 amountUSD: bigint;
17 username: string;
18 donor: string;
19 country: string;
20 language: string;
21 timestamp: number;
22 chainId: number | string;
23}
24
25export interface BouncerStorageReadAPI {
26 hasAccount(address: string): Promise<boolean>;
27 userInfos(address: string): Promise<[username: string, country: string, language: string, userId: number]>;
28 userData(userId: number): Promise<[id: number, addr: string, username: string, language: string, country: string]>;
29 getUsernameByAddress(address: string): Promise<string>;
30 userIdOf(address: string): Promise<number>;
31 userIdToUsername(userId: number): Promise<string>;
32 usernameToUserId(username: string): Promise<number>;
33 userAddr(userId: number): Promise<string>;
34 getAccountCountByCountryLanguage(country: string, language: string): Promise<number>;
35 getAllLocationCounts(): Promise<any[]>;
36 getActiveLocationCount(): Promise<number>;
37 nbAccounts(): Promise<number>;
38 identityStats(): Promise<[nbVerbs: number, nbAdjectives: number]>;
39 isAuthorized(address: string): Promise<boolean>;
40 getLatestRegisteredUser(): Promise<string | null>;
41 getTokenName(): Promise<string>;
42}
43
44export interface ArchivistStorageReadAPI {
45 userLevel(userId: number): Promise<number>;
46 isAuthorized(address: string): Promise<boolean>;
47 // BackupStorage's userId-keyed patch history โ the on-chain source subscription
48 // patch-resolution reads from (spec ยง15.2/implementation plan: bypasses Arweave
49 // TX lookups entirely; loadActions/loadActionsSince already exist on IBackup).
50 nbWrites(userId: number): Promise<number>;
51 loadActions(userId: number): Promise<[bigint[], bigint[], string[]]>;
52 loadActionsSince(userId: number, index: number): Promise<[bigint[], bigint[], string[]]>;
53}
54
55export interface ScientistStorageReadAPI {
56 getLastMonthId(): Promise<number>;
57 getDeploymentDate(): Promise<[year: number, month: number]>;
58 getStatsRaw(action: number, objectType: number, monthId: number): Promise<[bigint[], number[]]>;
59 isAuthorized(address: string): Promise<boolean>;
60}
61
62export interface ProjectManagerStorageReadAPI {
63 nbProjects(): Promise<number>;
64 getProjectSupportedLanguages(projectId: number): Promise<Array<string>>;
65 addressDonationsPerProject(address: string): Promise<Array<number>>;
66 balanceOfAddress(address: string): Promise<{
67 total: number;
68 donations: number;
69 unspent: number;
70 }>;
71 loadProject(projectId: number): Promise<{
72 id: number;
73 balance: number;
74 versions: any[];
75 availableLanguages: string[];
76 }>;
77 projectVotingBalances(projectId: number): Promise<number>;
78 getWeeklyDonations(week: number): Promise<StripeDonation[]>;
79 getDonationsRange(fromWeek: number, toWeek: number): Promise<StripeDonation[]>;
80 isAuthorized(address: string): Promise<boolean>;
81 // Per-language/per-version accessors (verified against the deployed ABI) โ
82 // `lang` is always a human-readable code ("eng"), converted to/from bytes4
83 // internally, matching the convention FactoryWriteAPI.donateToProject etc.
84 // already use. Needed for admin tooling that must compare a project's state
85 // across every language/version it has, not just the latest (loadProject
86 // above only resolves the current version per language).
87 admin(): Promise<string>;
88 getNbLanguages(projectId: number): Promise<number>;
89 getLanguageAtIndex(projectId: number, index: number): Promise<string>;
90 getNbVersions(projectId: number, lang: string): Promise<number>;
91 getVersion(projectId: number, lang: string, versionNumber: number): Promise<ProjectVersion>;
92 getVotingBalance(projectId: number, lang: string): Promise<bigint>;
93 getUserBalances(address: string): Promise<[donated: bigint, allocated: bigint, remaining: bigint]>;
94}
95
96export interface FactoryReadAPI {
97 nbWritesByUsername(username: string): Promise<number>;
98 loadUsername(username: string): Promise<[bigint[], bigint[], string[]]>;
99 loadUsernameSince(username: string, index: number): Promise<[bigint[], bigint[], string[]]>;
100 load(): Promise<[bigint[], bigint[], string[]]>;
101 isAuthorized(address: string): Promise<boolean>;
102 owner(): Promise<string>;
103 oracleSigner(): Promise<string>;
104 bouncerStorage(): Promise<string>;
105 scientistStorage(): Promise<string>;
106 backupStorage(): Promise<string>;
107 projectManagerStorage(): Promise<string>;
108 usedPaymentIntents(paymentIntentId: string): Promise<boolean>;
109}
110
111export interface TransactionOptions {
112 feeLimit?: number;
113 gasLimit?: bigint;
114 value?: number;
115 onAccepted?: (txId: string) => void;
116}
117
118export interface FactoryWriteAPI {
119 register(country: string, language: string, paymentValue: number, options?: TransactionOptions): Promise<any>;
120 unregister(options?: TransactionOptions): Promise<any>;
121 save(patches: Array<bigint>, level: number, textIndex: Array<number>, text: Array<string>, options?: TransactionOptions): Promise<any>;
122 // Names/arg lists match Factory.sol's actual on-chain signatures (verified
123 // against the deployed ABI) โ these are admin-only operations (Factory owner),
124 // distinct from the public donor journey (register/save/donateToProject below).
125 createProject(
126 lang: string,
127 uri: string,
128 publicationDate: number,
129 name: string,
130 headline: string,
131 arweaveAddressLogo: string,
132 arweaveAddressBanner: string,
133 descriptionMarkdown: string,
134 minimumFundingBeforeStartWork: number,
135 maximumFunding: number,
136 tags: number[],
137 complexity: number,
138 options?: TransactionOptions
139 ): Promise<any>;
140 addProjectVersion(
141 projectId: number,
142 lang: string,
143 publicationDate: number,
144 uri: string,
145 name: string,
146 headline: string,
147 arweaveAddressLogo: string,
148 arweaveAddressBanner: string,
149 descriptionMarkdown: string,
150 minimumFundingBeforeStartWork: number,
151 maximumFunding: number,
152 tags: number[],
153 status: number,
154 complexity: number,
155 options?: TransactionOptions
156 ): Promise<any>;
157 deleteProject(projectId: number, lang: string, options?: TransactionOptions): Promise<any>;
158 registerStripe(country: string, language: string, paymentIntentId: string, votes: bigint, signature: string, options?: TransactionOptions): Promise<any>;
159 fundStripe(paymentIntentId: string, votes: bigint, signature: string, options?: TransactionOptions): Promise<any>;
160 donateToProject(projectId: number, lang: string, amount: number, options?: TransactionOptions): Promise<any>;
161}
162
163export interface AddressRegistryWriteAPI {
164 addData(key: string, value: string, options?: TransactionOptions): Promise<any>;
165}
166
167export interface AddressRegistryContractRecord {
168 contractAddress: string;
169 abiUrl: string;
170}
171
172export interface AddressRegistryUpdateInfo {
173 timestamp: number;
174 blockNumber: bigint;
175 transactionHash: string;
176}
177
178export interface AddressRegistryReadAPI {
179 getLatestContract(name: string): Promise<[address: string, abiUrl: string]>;
180 getContractHistory(name: string): Promise<AddressRegistryContractRecord[]>;
181 getAllContractNames(): Promise<string[]>;
182 getLatestData(key: string): Promise<string>;
183 getAllDataKeys(): Promise<string[]>;
184 getLastUpdateInfo(name: string): Promise<AddressRegistryUpdateInfo | null>;
185 admin(): Promise<string>;
186}
187
188export interface CollectionInput {
189 id: string;
190 slug: string;
191 manifestUrl: string;
192 importerUsername: string;
193 owner: string;
194 fileCount: number;
195 libraryType: number;
196 publicLibraryId: number;
197 country: string;
198 language: string;
199 isPublic: boolean;
200 initialBookCount: number;
201 dSafeBookCount: number;
202}
203
204export interface Collection extends CollectionInput {
205 verified: boolean;
206 createdAt: number;
207 updatedAt: number;
208 importStatus: number;
209 published: boolean;
210}
211
212export interface LibraryRegistryStorageReadAPI {
213 getUnverifiedCollectionIds(): Promise<string[]>;
214 getVerifiedCollectionIds(): Promise<string[]>;
215 getCollection(id: string): Promise<Collection>;
216}
217
218export interface LibraryRegistryStorageWriteAPI {
219 addUnverifiedCollection(input: CollectionInput, options?: TransactionOptions): Promise<any>;
220 verifyCollection(id: string, options?: TransactionOptions): Promise<any>;
221 rejectCollection(id: string, options?: TransactionOptions): Promise<any>;
222 updateCollectionStats(id: string, initialBookCount: number, dSafeBookCount: number, options?: TransactionOptions): Promise<any>;
223 setImportStatus(id: string, status: number, options?: TransactionOptions): Promise<any>;
224 setPublished(id: string, isPublished: boolean, options?: TransactionOptions): Promise<any>;
225 setCollectionPublicLibrary(id: string, publicLibraryId: number, options?: TransactionOptions): Promise<any>;
226 setPublicLibraryStorage(storageAddr: string, options?: TransactionOptions): Promise<any>;
227}
228
229export enum LibraryOwnership {
230 Public = 0,
231 Private = 1
232}
233
234export enum PreferredFormat {
235 MARC21 = 0,
236 UNIMARC = 1,
237 MARCXML = 2,
238 DublinCore = 3,
239 MODS = 4,
240 BIBFRAME = 5,
241 ONIX = 6,
242 OPDS = 7,
243 InternetArchive = 8,
244 HathiTrust = 9,
245 EAD = 10,
246 Other = 11
247}
248
249export interface PublicLibraryInput {
250 name: string;
251 physicalAddress: string;
252 country: string;
253 language: string;
254 ownership: LibraryOwnership | number;
255 website: string;
256 preferredFormat: PreferredFormat | number;
257}
258
259export interface PublicLibrary extends PublicLibraryInput {
260 id: number;
261 createdAt: number;
262 updatedAt: number;
263}
264
265export interface PublicLibraryStorageReadAPI {
266 libraryExists(id: number): Promise<boolean>;
267 getPublicLibrary(id: number): Promise<PublicLibrary>;
268 nbLibraries(): Promise<number>;
269}
270
271export interface PublicLibraryStorageWriteAPI {
272 addPublicLibrary(input: PublicLibraryInput, options?: TransactionOptions): Promise<any>;
273 updatePublicLibrary(id: number, input: PublicLibraryInput, options?: TransactionOptions): Promise<any>;
274}
275
276export interface SubscriptionManagerReadAPI {
277 getSubscriptions(userId: number): Promise<number[]>;
278 getSubscriptionCount(userId: number): Promise<bigint>;
279 isSubscribed(subscriber: number, target: number): Promise<boolean>;
280 scoreOf(userId: number): Promise<bigint>;
281}
282
283export interface SubscriptionManagerWriteAPI {
284 subscribeTo(subscriber: number, target: number, options?: TransactionOptions): Promise<any>;
285 unsubscribeFrom(subscriber: number, target: number, options?: TransactionOptions): Promise<any>;
286}
287
288export interface ReadOnlyDomainAPI {
289 readonly chainId: number;
290 readonly ready: Promise<void>;
291 readonly bouncerStorage: BouncerStorageReadAPI;
292 readonly scientistStorage: ScientistStorageReadAPI;
293 readonly archivistStorage: ArchivistStorageReadAPI;
294 readonly projectManagerStorage: ProjectManagerStorageReadAPI;
295 readonly factory: FactoryReadAPI;
296 readonly addressRegistry: AddressRegistryReadAPI;
297 readonly subscriptionManager: SubscriptionManagerReadAPI;
298 readonly libraryRegistryStorage: LibraryRegistryStorageReadAPI;
299 readonly publicLibraryStorage: PublicLibraryStorageReadAPI;
300 getUsdPrice(): Promise<number>;
301 getRegistryStatus(): Promise<any>;
302}
303
304export interface WriteOnlyDomainAPI {
305 readonly factory: FactoryWriteAPI;
306 readonly subscriptionManager: SubscriptionManagerWriteAPI;
307 readonly addressRegistry: AddressRegistryWriteAPI;
308 readonly libraryRegistryStorage: LibraryRegistryStorageWriteAPI;
309 readonly publicLibraryStorage: PublicLibraryStorageWriteAPI;
310}
311
312export interface ProjectVersion {
313 uri: string;
314 publicationDate: Date;
315 name: string;
316 headline: string;
317 descriptionMarkdown: string;
318 arweaveAddressLogo: string;
319 arweaveAddressBanner: string;
320 minimumFundingBeforeStartWork: number;
321 maximumFunding: number;
322 tags: Array<number>;
323 status: number;
324 complexity: number;
325}
326
327export interface Project {
328 id: number;
329 balance: number;
330 availableLanguages: Array<string>;
331 versions: Array<ProjectVersion>;
332}
333
334export type ErrorCode =
335 | 'REVERT'
336 | 'INSUFFICIENT_FUNDS'
337 | 'NONCE_TOO_LOW'
338 | 'USER_REJECTED'
339 | 'NETWORK_ERROR'
340 | 'TIMEOUT'
341 | 'INVALID_ARGUMENT'
342 | 'INVALID_COMPRESSED_ACTIONS'
343 | 'UNSUPPORTED_OPERATION'
344 | 'SWITCH_CHAIN_ERROR'
345 | 'SWITCH_TO_UNSUPPORTED_CHAIN'
346 | 'NO_WALLET_CONNECTED'
347 | 'WALLET_NOT_INSTALLED'
348 | 'UNKNOWN';
349
350export interface NormalizedError {
351 code: ErrorCode;
352 message: string;
353 reason?: string;
354 data?: any;
355 originalError?: any;
356}
357
358export type WalletType = 'metamask' | 'private_key';
359
360export interface ConnectResult {
361 address: string;
362 chainId: number;
363}
364
365export interface WalletConnector {
366 readonly type: WalletType;
367 isAvailable(): boolean;
368 connect(): Promise<ConnectResult>;
369 getAccounts(): Promise<string[]>;
370 getChainId(): Promise<number>;
371 requestSwitchChain(chainId: number): Promise<void>;
372 sendTransaction(tx: TransactionRequest, chainId: number): Promise<string>;
373 signMessage(message: string): Promise<string>;
374 onAccountChanged(cb: (address: string) => void): () => void;
375 onChainChanged(cb: (chainId: number) => void): () => void;
376 disconnect(): void;
377}
378
379// EVM-specific capability, kept off the base WalletConnector to preserve the
380// adapter-agnostic boundary (viem must not leak onto the behavioral interface โ
381// mirrors why `publicClient` is kept off ReadOnlyDomainAPI). Only EVM connectors
382// implement this; it's how session/writeClient.ts builds an EvmWriteClient
383// without coupling WalletConnector itself to viem.
384export interface EvmWalletConnector extends WalletConnector {
385 getWalletClient(chainId: number): Promise<WalletClient>;
386}
387
388