@interfold/sdk 0.12.1 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +91 -35
- package/dist/contracts/index.cjs +11 -10
- package/dist/contracts/index.cjs.map +1 -1
- package/dist/contracts/index.js +11 -10
- package/dist/contracts/index.js.map +1 -1
- package/dist/crypto/index.cjs.map +1 -1
- package/dist/crypto/index.js.map +1 -1
- package/dist/events/index.cjs +162 -7
- package/dist/events/index.cjs.map +1 -1
- package/dist/events/index.d.ts +48 -1
- package/dist/events/index.js +162 -8
- package/dist/events/index.js.map +1 -1
- package/dist/index.cjs +182 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.js +182 -18
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@ pnpm add @interfold/sdk
|
|
|
24
24
|
## Quick Start
|
|
25
25
|
|
|
26
26
|
```typescript
|
|
27
|
-
import { InterfoldSDK, InterfoldEventType, RegistryEventType } from '@interfold/sdk'
|
|
27
|
+
import { CommitteeSize, InterfoldSDK, InterfoldEventType, RegistryEventType } from '@interfold/sdk'
|
|
28
28
|
import { createPublicClient, createWalletClient, http, custom } from 'viem'
|
|
29
29
|
import { sepolia } from 'viem/chains'
|
|
30
30
|
|
|
@@ -49,8 +49,8 @@ const sdk = new InterfoldSDK({
|
|
|
49
49
|
feeToken: '0x...', // Your ERC-20 fee token address
|
|
50
50
|
},
|
|
51
51
|
chain: sepolia,
|
|
52
|
-
//
|
|
53
|
-
thresholdBfvParamsPresetName: '
|
|
52
|
+
// 'INSECURE_THRESHOLD_512' for local dev and Sepolia; 'SECURE_THRESHOLD_8192' for production
|
|
53
|
+
thresholdBfvParamsPresetName: 'INSECURE_THRESHOLD_512',
|
|
54
54
|
})
|
|
55
55
|
|
|
56
56
|
// Listen to events with the unified event system
|
|
@@ -58,19 +58,24 @@ sdk.onInterfoldEvent(InterfoldEventType.E3_REQUESTED, (event) => {
|
|
|
58
58
|
console.log('E3 Requested:', event.data)
|
|
59
59
|
})
|
|
60
60
|
|
|
61
|
-
sdk.onInterfoldEvent(RegistryEventType.
|
|
62
|
-
console.log('Committee
|
|
61
|
+
sdk.onInterfoldEvent(RegistryEventType.COMMITTEE_RANDOMNESS_REQUESTED, (event) => {
|
|
62
|
+
console.log('Committee randomness requested:', event.data)
|
|
63
63
|
})
|
|
64
64
|
|
|
65
65
|
// Interact with contracts
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
const now = BigInt(Math.floor(Date.now() / 1000))
|
|
67
|
+
const requestParams = {
|
|
68
|
+
committeeSize: CommitteeSize.Minimum,
|
|
69
|
+
inputWindow: [now, now + 300n] as const,
|
|
69
70
|
e3Program: '0x...',
|
|
70
|
-
|
|
71
|
+
paramSet: 0, // Insecure512 for development
|
|
71
72
|
computeProviderParams: '0x...',
|
|
72
73
|
customParams: '0x...',
|
|
73
|
-
}
|
|
74
|
+
}
|
|
75
|
+
const quote = await sdk.getE3Quote(requestParams)
|
|
76
|
+
const approvalHash = await sdk.approveFeeToken(quote)
|
|
77
|
+
await sdk.waitForTransaction(approvalHash)
|
|
78
|
+
const hash = await sdk.requestE3({ ...requestParams, maxFee: quote })
|
|
74
79
|
```
|
|
75
80
|
|
|
76
81
|
### Factory Method
|
|
@@ -90,8 +95,8 @@ const sdk = InterfoldSDK.create({
|
|
|
90
95
|
},
|
|
91
96
|
chain: sepolia,
|
|
92
97
|
privateKey: '0x...', // optional — omit for read-only
|
|
93
|
-
//
|
|
94
|
-
thresholdBfvParamsPresetName: '
|
|
98
|
+
// 'INSECURE_THRESHOLD_512' for local dev and Sepolia; 'SECURE_THRESHOLD_8192' for production
|
|
99
|
+
thresholdBfvParamsPresetName: 'INSECURE_THRESHOLD_512',
|
|
95
100
|
})
|
|
96
101
|
```
|
|
97
102
|
|
|
@@ -137,17 +142,15 @@ enum InterfoldEventType {
|
|
|
137
142
|
PLAINTEXT_OUTPUT_PUBLISHED = 'PlaintextOutputPublished',
|
|
138
143
|
|
|
139
144
|
// E3 Program Management
|
|
140
|
-
|
|
141
|
-
E3_PROGRAM_DISABLED = 'E3ProgramDisabled',
|
|
145
|
+
E3_PROGRAM_REGISTERED = 'E3ProgramRegistered',
|
|
142
146
|
|
|
143
147
|
// Encryption Scheme Management
|
|
144
148
|
ENCRYPTION_SCHEME_ENABLED = 'EncryptionSchemeEnabled',
|
|
145
|
-
ENCRYPTION_SCHEME_DISABLED = 'EncryptionSchemeDisabled',
|
|
146
149
|
|
|
147
150
|
// Configuration
|
|
148
151
|
CIPHERNODE_REGISTRY_SET = 'CiphernodeRegistrySet',
|
|
149
152
|
MAX_DURATION_SET = 'MaxDurationSet',
|
|
150
|
-
|
|
153
|
+
PARAM_SET_REGISTERED = 'ParamSetRegistered',
|
|
151
154
|
OWNERSHIP_TRANSFERRED = 'OwnershipTransferred',
|
|
152
155
|
INITIALIZED = 'Initialized',
|
|
153
156
|
}
|
|
@@ -157,15 +160,45 @@ enum InterfoldEventType {
|
|
|
157
160
|
|
|
158
161
|
```typescript
|
|
159
162
|
enum RegistryEventType {
|
|
163
|
+
// On-chain legacy event retained only for pre-VRF registry logs. The
|
|
164
|
+
// ciphernode runtime creates its separate durable CommitteeRequested event
|
|
165
|
+
// after the Registry accepts a VRF response.
|
|
160
166
|
COMMITTEE_REQUESTED = 'CommitteeRequested',
|
|
167
|
+
COMMITTEE_RANDOMNESS_REQUESTED = 'CommitteeRandomnessRequested',
|
|
168
|
+
RANDOMNESS_CIRCUIT_BREAKER_TRIPPED = 'RandomnessCircuitBreakerTripped',
|
|
161
169
|
COMMITTEE_PUBLISHED = 'CommitteePublished',
|
|
162
|
-
COMMITTEE_FINALIZED = '
|
|
170
|
+
COMMITTEE_FINALIZED = 'SortitionCommitteeFinalized',
|
|
163
171
|
INTERFOLD_SET = 'InterfoldSet',
|
|
164
172
|
OWNERSHIP_TRANSFERRED = 'OwnershipTransferred',
|
|
165
173
|
INITIALIZED = 'Initialized',
|
|
166
174
|
}
|
|
167
175
|
```
|
|
168
176
|
|
|
177
|
+
### Randomness Provider Events
|
|
178
|
+
|
|
179
|
+
The provider address is frozen for each E3 and can change after governance rotation, so it is not
|
|
180
|
+
part of the static SDK contract addresses. Read `provider`, `requestId`, and `e3Id` from
|
|
181
|
+
`CommitteeRandomnessRequested`, then watch that provider through the main SDK:
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
await sdk.onRandomnessProviderEvent(
|
|
185
|
+
provider,
|
|
186
|
+
RandomnessProviderEventType.RANDOMNESS_FULFILLED,
|
|
187
|
+
({ data }) => {
|
|
188
|
+
console.log(data.requestId, data.e3Id, data.fulfilledAt)
|
|
189
|
+
},
|
|
190
|
+
)
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Use `sdk.getHistoricalRandomnessProviderEvents` with explicit block bounds to recover earlier
|
|
194
|
+
fulfillments. Start the live watcher at `historicalToBlock + 1n` so the historical and live ranges
|
|
195
|
+
do not overlap. Historical reads are split into bounded RPC queries, and live watchers suppress
|
|
196
|
+
duplicate delivery of the same log. `RandomnessFulfilled` proves that the provider stored a
|
|
197
|
+
response. The Registry remains authoritative about whether that response was timely and usable. If
|
|
198
|
+
the listener config does not define `fromBlock`, the history method requires it as an argument.
|
|
199
|
+
Subscribers that share one provider and event watcher must use the same explicit `fromBlock`, or
|
|
200
|
+
omit it to join the active watcher.
|
|
201
|
+
|
|
169
202
|
### Event Data Structure
|
|
170
203
|
|
|
171
204
|
Each event follows a consistent structure:
|
|
@@ -209,8 +242,8 @@ function MyComponent() {
|
|
|
209
242
|
feeToken: '0x...',
|
|
210
243
|
},
|
|
211
244
|
autoConnect: true,
|
|
212
|
-
//
|
|
213
|
-
thresholdBfvParamsPresetName: '
|
|
245
|
+
// 'INSECURE_THRESHOLD_512' for local dev and Sepolia; 'SECURE_THRESHOLD_8192' for production
|
|
246
|
+
thresholdBfvParamsPresetName: 'INSECURE_THRESHOLD_512',
|
|
214
247
|
})
|
|
215
248
|
|
|
216
249
|
useEffect(() => {
|
|
@@ -272,8 +305,8 @@ import {
|
|
|
272
305
|
getThresholdBfvParamsSet,
|
|
273
306
|
} from '@interfold/sdk'
|
|
274
307
|
|
|
275
|
-
//
|
|
276
|
-
const presetName = '
|
|
308
|
+
// 'INSECURE_THRESHOLD_512' for local dev and Sepolia; 'SECURE_THRESHOLD_8192' for production
|
|
309
|
+
const presetName = 'INSECURE_THRESHOLD_512'
|
|
277
310
|
|
|
278
311
|
const publicKey = await generatePublicKey(presetName)
|
|
279
312
|
const encrypted = await encryptNumber(42n, publicKey, presetName)
|
|
@@ -311,13 +344,14 @@ await sdk.approveFeeToken(amount: bigint);
|
|
|
311
344
|
|
|
312
345
|
// Request a new E3 computation
|
|
313
346
|
await sdk.requestE3({
|
|
314
|
-
|
|
347
|
+
committeeSize: CommitteeSize.Minimum,
|
|
315
348
|
inputWindow: [bigint, bigint],
|
|
316
349
|
e3Program: `0x${string}`,
|
|
317
|
-
|
|
350
|
+
paramSet: 0,
|
|
318
351
|
computeProviderParams: `0x${string}`,
|
|
319
|
-
customParams
|
|
320
|
-
|
|
352
|
+
customParams: '0x',
|
|
353
|
+
maxFee: amount,
|
|
354
|
+
gasLimit: 1_500_000n
|
|
321
355
|
});
|
|
322
356
|
|
|
323
357
|
// Publish ciphertext output
|
|
@@ -331,9 +365,9 @@ const stage = await sdk.getE3Stage(e3Id: bigint);
|
|
|
331
365
|
const reason = await sdk.getFailureReason(e3Id: bigint);
|
|
332
366
|
```
|
|
333
367
|
|
|
334
|
-
The original requester can cancel
|
|
335
|
-
|
|
336
|
-
|
|
368
|
+
The original requester can cancel only while the E3 is `Requested`, after the randomness deadline,
|
|
369
|
+
and only if no timely VRF result is usable. A valid result disables cancellation. The failure path
|
|
370
|
+
returns all service fee escrow and keeps the flat randomness fee charged.
|
|
337
371
|
|
|
338
372
|
```ts
|
|
339
373
|
const hash = await sdk.cancelE3(e3Id)
|
|
@@ -434,13 +468,35 @@ interface SDKConfig {
|
|
|
434
468
|
`thresholdBfvParamsPresetName` selects the BFV parameter set used for encryption. It must match the
|
|
435
469
|
on-chain `paramSet` index registered in the Interfold contract:
|
|
436
470
|
|
|
437
|
-
| Preset name | On-chain `paramSet` index | Use case
|
|
438
|
-
| -------------------------- | ------------------------- |
|
|
439
|
-
| `'INSECURE_THRESHOLD_512'` | `0` | Local development and
|
|
440
|
-
| `'SECURE_THRESHOLD_8192'` | `1` | Production — full security parameters (N=8192, L=
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
471
|
+
| Preset name | On-chain `paramSet` index | Use case |
|
|
472
|
+
| -------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------ |
|
|
473
|
+
| `'INSECURE_THRESHOLD_512'` | `0` | Local development and Sepolia — small polynomial degree (N=512), fast but not cryptographically secure |
|
|
474
|
+
| `'SECURE_THRESHOLD_8192'` | `1` | Production — full security parameters (N=8192, L=3 CRT moduli) |
|
|
475
|
+
|
|
476
|
+
| Network | Preset | `paramSet` |
|
|
477
|
+
| ---------------------- | -------------------------- | ---------- |
|
|
478
|
+
| Local development | `'INSECURE_THRESHOLD_512'` | `0` |
|
|
479
|
+
| Sepolia testnet | `'INSECURE_THRESHOLD_512'` | `0` |
|
|
480
|
+
| Mainnet and production | `'SECURE_THRESHOLD_8192'` | `1` |
|
|
481
|
+
|
|
482
|
+
Use `'INSECURE_THRESHOLD_512'` on Sepolia: the Sepolia ciphernodes run the insecure preset, and the
|
|
483
|
+
circuit artifacts bundled in this package are compiled for it. Use `'SECURE_THRESHOLD_8192'` in
|
|
484
|
+
production, together with your own `secure-8192` circuit artifacts (see
|
|
485
|
+
[Proving](#proving-embedded-circuits-or-your-own)).
|
|
486
|
+
|
|
487
|
+
### Proving: embedded circuits or your own
|
|
488
|
+
|
|
489
|
+
`generateProof()`, `encryptNumberAndGenProof()`, and `encryptVectorAndGenProof()` run the
|
|
490
|
+
user-data-encryption (UDE) circuits bundled in this package. Those artifacts are compiled with
|
|
491
|
+
`--preset insecure-512 --committee minimum` (`scripts/compile-circuits.sh`), so they only match
|
|
492
|
+
`'INSECURE_THRESHOLD_512'` and a minimum-size committee. With `'SECURE_THRESHOLD_8192'`,
|
|
493
|
+
`encryptNumberAndGenInputs()` returns N=8192 circuit inputs that the bundled N=512 circuits cannot
|
|
494
|
+
execute.
|
|
495
|
+
|
|
496
|
+
For on-chain Honk verification, compile your own UDE, app, and fold circuits for the preset and
|
|
497
|
+
committee your deployment uses, emit the Solidity verifier from them, and feed them the witness from
|
|
498
|
+
`encryptNumberAndGenInputs()`. `examples/CRISP` in the monorepo shows the full flow. Secure
|
|
499
|
+
artifacts may ship here in a later release.
|
|
444
500
|
|
|
445
501
|
## Error Handling
|
|
446
502
|
|
package/dist/contracts/index.cjs
CHANGED
|
@@ -43,6 +43,15 @@ var SDKError = class extends Error {
|
|
|
43
43
|
function isValidAddress(address) {
|
|
44
44
|
return /^0x[a-fA-F0-9]{40}$/.test(address);
|
|
45
45
|
}
|
|
46
|
+
function cryptoConfigIdForParamSet(paramSet) {
|
|
47
|
+
if (paramSet === 0) {
|
|
48
|
+
return "0x04f3677e73b0f5066d6caf5cbd92e3fb2e38338edaf5cfc971ab28f7b684da78";
|
|
49
|
+
}
|
|
50
|
+
if (paramSet === 1) {
|
|
51
|
+
return "0xd9c86e581f8291ffb5b63595600e8d096ed30b16e2e0a6634a76c22b1f58fb4e";
|
|
52
|
+
}
|
|
53
|
+
throw new SDKError(`Unsupported BFV parameter set: ${paramSet}`, "UNSUPPORTED_CRYPTO_CONFIG");
|
|
54
|
+
}
|
|
46
55
|
|
|
47
56
|
// src/contracts/types.ts
|
|
48
57
|
function validateCommitteeSize(value) {
|
|
@@ -172,11 +181,7 @@ var ContractClient = class _ContractClient {
|
|
|
172
181
|
}
|
|
173
182
|
const committeeSize = validateCommitteeSize(params.committeeSize);
|
|
174
183
|
const maxFee = params.maxFee ?? await this.getE3Quote(params);
|
|
175
|
-
const expectedCryptoConfigId =
|
|
176
|
-
address: this.contracts.interfold,
|
|
177
|
-
abi: import_types.Interfold__factory.abi,
|
|
178
|
-
functionName: "activeCryptoConfigId"
|
|
179
|
-
});
|
|
184
|
+
const expectedCryptoConfigId = cryptoConfigIdForParamSet(params.paramSet);
|
|
180
185
|
const { request } = await this.publicClient.simulateContract({
|
|
181
186
|
address: this.contracts.interfold,
|
|
182
187
|
abi: import_types.Interfold__factory.abi,
|
|
@@ -261,11 +266,7 @@ var ContractClient = class _ContractClient {
|
|
|
261
266
|
async getE3Quote(requestParams) {
|
|
262
267
|
try {
|
|
263
268
|
const committeeSize = validateCommitteeSize(requestParams.committeeSize);
|
|
264
|
-
const expectedCryptoConfigId =
|
|
265
|
-
address: this.contracts.interfold,
|
|
266
|
-
abi: import_types.Interfold__factory.abi,
|
|
267
|
-
functionName: "activeCryptoConfigId"
|
|
268
|
-
});
|
|
269
|
+
const expectedCryptoConfigId = cryptoConfigIdForParamSet(requestParams.paramSet);
|
|
269
270
|
return this.publicClient.readContract({
|
|
270
271
|
address: this.contracts.interfold,
|
|
271
272
|
abi: import_types.Interfold__factory.abi,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/contracts/index.ts","../../src/contracts/contract-client.ts","../../src/utils.ts","../../src/contracts/types.ts"],"sourcesContent":["// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nexport { ContractClient } from './contract-client'\nexport type { ContractClientConfig } from './contract-client'\nexport type { ContractAddresses, E3, E3RequestParams } from './types'\nexport { E3Stage, FailureReason } from './types'\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport {\n type Abi,\n type Chain,\n type Hash,\n type PublicClient,\n type TransactionReceipt,\n type WalletClient,\n createPublicClient,\n createWalletClient,\n http,\n webSocket,\n} from 'viem'\nimport { privateKeyToAccount } from 'viem/accounts'\n\nimport { CiphernodeRegistryOwnable__factory, Interfold__factory, InterfoldToken__factory } from '@interfold/contracts/types'\nimport type { ContractAddresses, E3, E3RequestParams, E3Stage, FailureReason } from './types'\nimport { validateCommitteeSize } from './types'\nimport { SDKError, isValidAddress } from '../utils'\n\nexport interface ContractClientConfig {\n publicClient: PublicClient\n walletClient?: WalletClient\n contracts: ContractAddresses\n}\n\nexport class ContractClient {\n private publicClient: PublicClient\n private walletClient?: WalletClient\n private contracts: ContractAddresses\n private contractInfo: {\n interfold: { address: `0x${string}`; abi: Abi }\n ciphernodeRegistry: { address: `0x${string}`; abi: Abi }\n feeToken: { address: `0x${string}`; abi: Abi }\n }\n\n constructor(config: ContractClientConfig) {\n const { publicClient, walletClient, contracts } = config\n\n if (!isValidAddress(contracts.interfold)) {\n throw new SDKError('Invalid Interfold contract address', 'INVALID_ADDRESS')\n }\n if (!isValidAddress(contracts.ciphernodeRegistry)) {\n throw new SDKError('Invalid CiphernodeRegistry contract address', 'INVALID_ADDRESS')\n }\n if (!isValidAddress(contracts.feeToken)) {\n throw new SDKError('Invalid FeeToken contract address', 'INVALID_ADDRESS')\n }\n\n this.publicClient = publicClient\n this.walletClient = walletClient\n this.contracts = contracts\n\n this.contractInfo = {\n interfold: {\n address: contracts.interfold,\n abi: Interfold__factory.abi,\n },\n ciphernodeRegistry: {\n address: contracts.ciphernodeRegistry,\n abi: CiphernodeRegistryOwnable__factory.abi,\n },\n feeToken: {\n address: contracts.feeToken,\n abi: InterfoldToken__factory.abi,\n },\n }\n }\n\n public static create(options: {\n rpcUrl: string\n contracts: ContractAddresses\n privateKey?: `0x${string}`\n chain: Chain\n }): ContractClient {\n const isWebSocket = options.rpcUrl.startsWith('ws://') || options.rpcUrl.startsWith('wss://')\n const transport = isWebSocket\n ? webSocket(options.rpcUrl, {\n keepAlive: { interval: 30_000 },\n reconnect: { attempts: 5, delay: 2_000 },\n })\n : http(options.rpcUrl)\n\n const publicClient = createPublicClient({\n chain: options.chain,\n transport,\n }) as PublicClient\n\n let walletClient: WalletClient | undefined\n if (options.privateKey) {\n const account = privateKeyToAccount(options.privateKey)\n walletClient = createWalletClient({\n account,\n chain: options.chain,\n transport,\n })\n }\n\n return new ContractClient({ publicClient, walletClient, contracts: options.contracts })\n }\n\n public getPublicClient(): PublicClient {\n return this.publicClient\n }\n\n public async approveFeeToken(amount: bigint): Promise<Hash> {\n if (!this.walletClient) {\n throw new SDKError('Wallet client required for write operations', 'NO_WALLET')\n }\n\n try {\n const account = this.walletClient.account\n if (!account) {\n throw new SDKError('No account connected', 'NO_ACCOUNT')\n }\n\n const { request } = await this.publicClient.simulateContract({\n address: this.contracts.feeToken,\n abi: InterfoldToken__factory.abi,\n functionName: 'approve',\n args: [this.contracts.interfold, amount],\n account,\n })\n\n return await this.walletClient.writeContract(request)\n } catch (error) {\n throw new SDKError(`Failed to approve fee token: ${error}`, 'APPROVE_FEE_TOKEN_FAILED')\n }\n }\n\n public async requestE3(params: E3RequestParams): Promise<Hash> {\n if (!this.walletClient) {\n throw new SDKError('Wallet client required for write operations', 'NO_WALLET')\n }\n\n try {\n const account = this.walletClient.account\n if (!account) {\n throw new SDKError('No account connected', 'NO_ACCOUNT')\n }\n\n const committeeSize = validateCommitteeSize(params.committeeSize)\n const maxFee = params.maxFee ?? (await this.getE3Quote(params))\n const expectedCryptoConfigId = await this.publicClient.readContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'activeCryptoConfigId',\n })\n\n const { request } = await this.publicClient.simulateContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'request',\n args: [\n {\n committeeSize,\n inputWindow: params.inputWindow,\n e3Program: params.e3Program,\n paramSet: params.paramSet,\n computeProviderParams: params.computeProviderParams,\n customParams: params.customParams || '0x',\n expectedFeeToken: this.contracts.feeToken,\n expectedCryptoConfigId,\n maxFee,\n },\n ],\n account,\n gas: params.gasLimit,\n })\n\n return await this.walletClient.writeContract(request)\n } catch (error) {\n throw new SDKError(`Failed to request E3: ${error}`, 'REQUEST_E3_FAILED')\n }\n }\n\n public async cancelE3(e3Id: bigint): Promise<Hash> {\n if (!this.walletClient) {\n throw new SDKError('Wallet client required for write operations', 'NO_WALLET')\n }\n const account = this.walletClient.account\n if (!account) {\n throw new SDKError('No account connected', 'NO_ACCOUNT')\n }\n\n try {\n const { request } = await this.publicClient.simulateContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'cancelE3',\n args: [e3Id],\n account,\n })\n\n return await this.walletClient.writeContract(request)\n } catch (error) {\n throw new SDKError(`Failed to cancel E3: ${error}`, 'CANCEL_E3_FAILED')\n }\n }\n\n public async publishCiphertextOutput(\n e3Id: bigint,\n ciphertextOutput: `0x${string}`,\n ciphertextCommitment: `0x${string}`,\n proof: `0x${string}`,\n gasLimit?: bigint,\n ): Promise<Hash> {\n if (!this.walletClient) {\n throw new SDKError('Wallet client required for write operations', 'NO_WALLET')\n }\n\n try {\n const account = this.walletClient.account\n if (!account) {\n throw new SDKError('No account connected', 'NO_ACCOUNT')\n }\n\n const { request } = await this.publicClient.simulateContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'publishCiphertextOutput',\n args: [e3Id, ciphertextOutput, ciphertextCommitment, proof],\n account,\n gas: gasLimit,\n })\n\n return await this.walletClient.writeContract(request)\n } catch (error) {\n throw new SDKError(`Failed to publish ciphertext output: ${error}`, 'PUBLISH_CIPHERTEXT_OUTPUT_FAILED')\n }\n }\n\n public async getE3(e3Id: bigint): Promise<E3> {\n try {\n const result: E3 = await this.publicClient.readContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'getE3',\n args: [e3Id],\n })\n\n return result\n } catch (error) {\n throw new SDKError(`Failed to get E3: ${error}`, 'GET_E3_FAILED')\n }\n }\n\n public async getE3Quote(requestParams: E3RequestParams): Promise<bigint> {\n try {\n const committeeSize = validateCommitteeSize(requestParams.committeeSize)\n const expectedCryptoConfigId = await this.publicClient.readContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'activeCryptoConfigId',\n })\n\n return this.publicClient.readContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'getE3Quote',\n args: [\n {\n committeeSize,\n inputWindow: requestParams.inputWindow,\n e3Program: requestParams.e3Program,\n paramSet: requestParams.paramSet,\n computeProviderParams: requestParams.computeProviderParams,\n customParams: requestParams.customParams || '0x',\n expectedFeeToken: this.contracts.feeToken,\n expectedCryptoConfigId,\n maxFee: requestParams.maxFee ?? 0n,\n },\n ],\n })\n } catch (error) {\n throw new SDKError(`Failed to get E3 quote: ${error}`, 'GET_E3_QUOTE_FAILED')\n }\n }\n\n public async getFailureReason(e3Id: bigint): Promise<FailureReason> {\n try {\n return this.publicClient.readContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'getFailureReason',\n args: [e3Id],\n })\n } catch (error) {\n throw new SDKError(`Failed to get failure reason: ${error}`, 'GET_FAILURE_REASON_FAILED')\n }\n }\n\n public async getE3PublicKey(e3Id: bigint): Promise<`0x${string}`> {\n try {\n const result: `0x${string}` = await this.publicClient.readContract({\n address: this.contracts.ciphernodeRegistry,\n abi: CiphernodeRegistryOwnable__factory.abi,\n functionName: 'committeePublicKey',\n args: [e3Id],\n })\n\n return result\n } catch (error) {\n throw new SDKError(`Failed to get E3 public key: ${error}`, 'GET_E3_PUBLIC_KEY_FAILED')\n }\n }\n\n public async getE3Stage(e3Id: bigint): Promise<E3Stage> {\n try {\n return this.publicClient.readContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'getE3Stage',\n args: [e3Id],\n })\n } catch (error) {\n throw new SDKError(`Failed to get E3 stage: ${error}`, 'GET_E3_STAGE_FAILED')\n }\n }\n\n public async estimateGas(\n functionName: string,\n args: readonly unknown[],\n contractAddress: `0x${string}`,\n abi: Abi,\n value?: bigint,\n ): Promise<bigint> {\n if (!this.walletClient) {\n throw new SDKError('Wallet client required for gas estimation', 'NO_WALLET')\n }\n\n try {\n const account = this.walletClient.account\n if (!account) {\n throw new SDKError('No account connected', 'NO_ACCOUNT')\n }\n\n const estimateParams = {\n address: contractAddress,\n abi,\n functionName,\n args,\n account,\n ...(value !== undefined && { value }),\n }\n\n return await this.publicClient.estimateContractGas(estimateParams)\n } catch (error) {\n throw new SDKError(`Failed to estimate gas: ${error}`, 'GAS_ESTIMATION_FAILED')\n }\n }\n\n public async waitForTransaction(hash: Hash): Promise<TransactionReceipt> {\n try {\n return await this.publicClient.waitForTransactionReceipt({\n hash,\n confirmations: 1,\n })\n } catch (error) {\n throw new SDKError(`Failed to wait for transaction: ${error}`, 'TRANSACTION_WAIT_FAILED')\n }\n }\n}\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport { type Address, type Hash, type Log, PublicClient, encodeAbiParameters } from 'viem'\nimport type { BfvParams } from './types'\n\nexport class SDKError extends Error {\n constructor(\n message: string,\n public readonly code?: string,\n ) {\n super(message)\n this.name = 'SDKError'\n }\n}\n\nexport function isValidAddress(address: string): address is Address {\n return /^0x[a-fA-F0-9]{40}$/.test(address)\n}\n\nexport function isValidHash(hash: string): hash is Hash {\n return /^0x[a-fA-F0-9]{64}$/.test(hash)\n}\n\nexport function formatEventName(contractName: string, eventName: string): string {\n return `${contractName}.${eventName}`\n}\n\nexport function parseEventData<T>(log: Log): T {\n return log.data as unknown as T\n}\n\n/**\n * Sleep for a specified number of milliseconds\n */\nexport const sleep = (ms: number): Promise<void> => {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nexport function formatBigInt(value: bigint): string {\n return value.toString()\n}\n\nexport function parseBigInt(value: string): bigint {\n return BigInt(value)\n}\n\nexport function generateEventId(log: Log): string {\n return `${log.blockHash}-${log.logIndex}`\n}\n\n/**\n * Get the current timestamp in seconds\n * from onchain\n * @param publicClient - The public client to use\n */\nexport async function getCurrentTimestamp(publicClient: PublicClient): Promise<bigint> {\n const block = await publicClient.getBlock()\n return block.timestamp\n}\n\n// Compute provider parameters structure\nexport interface ComputeProviderParams {\n name: string\n parallel: boolean\n batch_size: number\n}\n\n// Default compute provider configuration\nexport const DEFAULT_COMPUTE_PROVIDER_PARAMS: ComputeProviderParams = {\n name: 'risc0',\n parallel: false,\n batch_size: 2,\n}\n\n// Default E3 configuration (`committeeSize` is `IInterfold.CommitteeSize`, not circuit N_PARTIES).\nexport const DEFAULT_E3_CONFIG = {\n committeeSize: 0, // CommitteeSize.Minimum\n duration: 1800, // 30 minutes in seconds\n payment_amount: '0', // 0 ETH in wei\n} as const\n\n/**\n * Encode BFV parameters for the smart contract\n * BFV (Brakerski-Fan-Vercauteren) is a type of fully homomorphic encryption\n */\nexport function encodeBfvParams(params: BfvParams): `0x${string}` {\n const { degree, plaintextModulus, moduli, error1Variance } = params\n\n if (error1Variance === undefined) {\n throw new SDKError(\n 'error1Variance is required in ProtocolParams. All BFV parameter sets must specify error1_variance.',\n 'MISSING_ERROR1_VARIANCE',\n )\n }\n\n return encodeAbiParameters(\n [\n {\n name: 'bfvParams',\n type: 'tuple',\n components: [\n { name: 'degree', type: 'uint256' },\n { name: 'plaintext_modulus', type: 'uint256' },\n { name: 'moduli', type: 'uint256[]' },\n { name: 'error1_variance', type: 'string' },\n ],\n },\n ],\n [\n {\n degree: BigInt(degree),\n plaintext_modulus: BigInt(plaintextModulus),\n moduli: [...moduli],\n error1_variance: error1Variance,\n },\n ],\n )\n}\n\n/**\n * Encode compute provider parameters for the smart contract'\n * If mock is true, the compute provider parameters will return 32 bytes of 0x00\n */\nexport function encodeComputeProviderParams(params: ComputeProviderParams, mock: boolean = false): `0x${string}` {\n if (mock) {\n return `0x${'00'.repeat(32)}` as `0x${string}`\n }\n\n const jsonString = JSON.stringify(params)\n const encoder = new TextEncoder()\n const bytes = encoder.encode(jsonString)\n\n return `0x${Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('')}`\n}\n\n/**\n * Encode custom parameters for the smart contract.\n */\nexport function encodeCustomParams(params: Record<string, unknown>): `0x${string}` {\n const jsonString = JSON.stringify(params)\n const encoder = new TextEncoder()\n const bytes = encoder.encode(jsonString)\n\n return `0x${Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('')}`\n}\n\n// inputWindow[0] is always larger than now and dkg deadline\nexport const inputWindowStartBuffer = 15n\n\n/**\n * Calculate start window for E3 request\n * @dev This function can be used for testing purposes, or for E3s which need to start as soon as possible.\n * @param publicClient - The public client to use\n * @param duration - The duration of the input window in seconds\n * @param startBuffer - Buffer in seconds added to current timestamp for input window start\n */\nexport async function calculateInputWindow(\n publicClient: PublicClient,\n duration: number = DEFAULT_E3_CONFIG.duration,\n startBuffer: bigint = inputWindowStartBuffer,\n): Promise<[bigint, bigint]> {\n const now = await getCurrentTimestamp(publicClient)\n return [BigInt(now) + startBuffer, BigInt(now) + startBuffer + BigInt(duration)]\n}\n\n/**\n * Decode plaintextOutput bytes to get the actual result number\n */\nexport function decodePlaintextOutput(plaintextOutput: string): number | null {\n try {\n // Remove '0x' prefix if present\n const hex = plaintextOutput.startsWith('0x') ? plaintextOutput.slice(2) : plaintextOutput\n\n // Convert hex to bytes\n const bytes = new Uint8Array(hex.match(/.{1,2}/g)?.map((byte) => parseInt(byte, 16)) || [])\n\n if (bytes.length < 8) {\n console.warn('Plaintext output too short for u64 decoding')\n return null\n }\n\n // Decode first u64 (8 bytes) as little-endian\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n const result = view.getBigUint64(0, true) // true for little-endian\n\n return Number(result)\n } catch (error) {\n console.error('Failed to decode plaintext output:', error)\n return null\n }\n}\n\n// Helper function to convert proof bytes to field elements\nexport function proofToFields(proof: Uint8Array): string[] {\n const fields: string[] = []\n for (let i = 0; i < proof.length; i += 32) {\n const chunk = proof.slice(i, i + 32)\n fields.push('0x' + Buffer.from(chunk).toString('hex'))\n }\n return fields\n}\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport { SDKError } from '../utils'\n\nexport interface ContractAddresses {\n interfold: `0x${string}`\n ciphernodeRegistry: `0x${string}`\n feeToken: `0x${string}`\n}\n\n/** On-chain `IInterfold.CommitteeSize`: Minimum (N=3), Micro (N=9), Small (N=19). */\nexport enum CommitteeSize {\n Minimum = 0,\n Micro = 1,\n Small = 2,\n}\n\n/** Fail fast on out-of-range committee sizes before they hit the contract. */\nexport function validateCommitteeSize(value: number | CommitteeSize): CommitteeSize {\n if (!Number.isInteger(value) || value < CommitteeSize.Minimum || value > CommitteeSize.Small) {\n throw new SDKError(\n `Invalid committeeSize ${value}. Use CommitteeSize.Minimum (0), CommitteeSize.Micro (1), or CommitteeSize.Small (2).`,\n 'INVALID_COMMITTEE_SIZE',\n )\n }\n return value\n}\n\nexport enum ParamSet {\n Insecure512 = 0,\n Secure8192 = 1,\n}\n\nexport interface E3 {\n seed: bigint\n committeeSize: number\n requestBlock: bigint\n inputWindow: readonly [bigint, bigint]\n encryptionSchemeId: string\n e3Program: string\n paramSet: number\n decryptionVerifier: string\n committeePublicKey: string\n ciphertextOutput: string\n ciphertextCommitment: string\n plaintextOutput: string\n}\n\nexport interface RequestParams {\n gasLimit?: bigint\n}\n\nexport interface E3RequestParams extends RequestParams {\n committeeSize: number\n inputWindow: readonly [bigint, bigint]\n e3Program: `0x${string}`\n paramSet: number\n computeProviderParams: `0x${string}`\n customParams?: `0x${string}`\n /** Maximum fee token amount accepted. Defaults to a fresh quote. */\n maxFee?: bigint\n}\n\nexport enum E3Stage {\n None,\n Requested,\n CommitteeFinalized,\n KeyPublished,\n CiphertextReady,\n Complete,\n Failed,\n}\n\nexport enum FailureReason {\n None,\n CommitteeFormationTimeout,\n InsufficientCommitteeMembers,\n DKGTimeout,\n DKGInvalidShares,\n NoInputsReceived,\n ComputeTimeout,\n ComputeProviderExpired,\n ComputeProviderFailed,\n RequesterCancelled,\n DecryptionTimeout,\n DecryptionInvalidShares,\n VerificationFailed,\n}\n"],"mappings":"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","names":["import_viem","E3Stage","FailureReason"]}
|
|
1
|
+
{"version":3,"sources":["../../src/contracts/index.ts","../../src/contracts/contract-client.ts","../../src/utils.ts","../../src/contracts/types.ts"],"sourcesContent":["// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nexport { ContractClient } from './contract-client'\nexport type { ContractClientConfig } from './contract-client'\nexport type { ContractAddresses, E3, E3RequestParams } from './types'\nexport { E3Stage, FailureReason } from './types'\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport {\n type Abi,\n type Chain,\n type Hash,\n type PublicClient,\n type TransactionReceipt,\n type WalletClient,\n createPublicClient,\n createWalletClient,\n http,\n webSocket,\n} from 'viem'\nimport { privateKeyToAccount } from 'viem/accounts'\n\nimport { CiphernodeRegistryOwnable__factory, Interfold__factory, InterfoldToken__factory } from '@interfold/contracts/types'\nimport type { ContractAddresses, E3, E3RequestParams, E3Stage, FailureReason } from './types'\nimport { validateCommitteeSize } from './types'\nimport { SDKError, cryptoConfigIdForParamSet, isValidAddress } from '../utils'\n\nexport interface ContractClientConfig {\n publicClient: PublicClient\n walletClient?: WalletClient\n contracts: ContractAddresses\n}\n\nexport class ContractClient {\n private publicClient: PublicClient\n private walletClient?: WalletClient\n private contracts: ContractAddresses\n private contractInfo: {\n interfold: { address: `0x${string}`; abi: Abi }\n ciphernodeRegistry: { address: `0x${string}`; abi: Abi }\n feeToken: { address: `0x${string}`; abi: Abi }\n }\n\n constructor(config: ContractClientConfig) {\n const { publicClient, walletClient, contracts } = config\n\n if (!isValidAddress(contracts.interfold)) {\n throw new SDKError('Invalid Interfold contract address', 'INVALID_ADDRESS')\n }\n if (!isValidAddress(contracts.ciphernodeRegistry)) {\n throw new SDKError('Invalid CiphernodeRegistry contract address', 'INVALID_ADDRESS')\n }\n if (!isValidAddress(contracts.feeToken)) {\n throw new SDKError('Invalid FeeToken contract address', 'INVALID_ADDRESS')\n }\n\n this.publicClient = publicClient\n this.walletClient = walletClient\n this.contracts = contracts\n\n this.contractInfo = {\n interfold: {\n address: contracts.interfold,\n abi: Interfold__factory.abi,\n },\n ciphernodeRegistry: {\n address: contracts.ciphernodeRegistry,\n abi: CiphernodeRegistryOwnable__factory.abi,\n },\n feeToken: {\n address: contracts.feeToken,\n abi: InterfoldToken__factory.abi,\n },\n }\n }\n\n public static create(options: {\n rpcUrl: string\n contracts: ContractAddresses\n privateKey?: `0x${string}`\n chain: Chain\n }): ContractClient {\n const isWebSocket = options.rpcUrl.startsWith('ws://') || options.rpcUrl.startsWith('wss://')\n const transport = isWebSocket\n ? webSocket(options.rpcUrl, {\n keepAlive: { interval: 30_000 },\n reconnect: { attempts: 5, delay: 2_000 },\n })\n : http(options.rpcUrl)\n\n const publicClient = createPublicClient({\n chain: options.chain,\n transport,\n }) as PublicClient\n\n let walletClient: WalletClient | undefined\n if (options.privateKey) {\n const account = privateKeyToAccount(options.privateKey)\n walletClient = createWalletClient({\n account,\n chain: options.chain,\n transport,\n })\n }\n\n return new ContractClient({ publicClient, walletClient, contracts: options.contracts })\n }\n\n public getPublicClient(): PublicClient {\n return this.publicClient\n }\n\n public async approveFeeToken(amount: bigint): Promise<Hash> {\n if (!this.walletClient) {\n throw new SDKError('Wallet client required for write operations', 'NO_WALLET')\n }\n\n try {\n const account = this.walletClient.account\n if (!account) {\n throw new SDKError('No account connected', 'NO_ACCOUNT')\n }\n\n const { request } = await this.publicClient.simulateContract({\n address: this.contracts.feeToken,\n abi: InterfoldToken__factory.abi,\n functionName: 'approve',\n args: [this.contracts.interfold, amount],\n account,\n })\n\n return await this.walletClient.writeContract(request)\n } catch (error) {\n throw new SDKError(`Failed to approve fee token: ${error}`, 'APPROVE_FEE_TOKEN_FAILED')\n }\n }\n\n public async requestE3(params: E3RequestParams): Promise<Hash> {\n if (!this.walletClient) {\n throw new SDKError('Wallet client required for write operations', 'NO_WALLET')\n }\n\n try {\n const account = this.walletClient.account\n if (!account) {\n throw new SDKError('No account connected', 'NO_ACCOUNT')\n }\n\n const committeeSize = validateCommitteeSize(params.committeeSize)\n const maxFee = params.maxFee ?? (await this.getE3Quote(params))\n const expectedCryptoConfigId = cryptoConfigIdForParamSet(params.paramSet)\n\n const { request } = await this.publicClient.simulateContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'request',\n args: [\n {\n committeeSize,\n inputWindow: params.inputWindow,\n e3Program: params.e3Program,\n paramSet: params.paramSet,\n computeProviderParams: params.computeProviderParams,\n customParams: params.customParams || '0x',\n expectedFeeToken: this.contracts.feeToken,\n expectedCryptoConfigId,\n maxFee,\n },\n ],\n account,\n gas: params.gasLimit,\n })\n\n return await this.walletClient.writeContract(request)\n } catch (error) {\n throw new SDKError(`Failed to request E3: ${error}`, 'REQUEST_E3_FAILED')\n }\n }\n\n public async cancelE3(e3Id: bigint): Promise<Hash> {\n if (!this.walletClient) {\n throw new SDKError('Wallet client required for write operations', 'NO_WALLET')\n }\n const account = this.walletClient.account\n if (!account) {\n throw new SDKError('No account connected', 'NO_ACCOUNT')\n }\n\n try {\n const { request } = await this.publicClient.simulateContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'cancelE3',\n args: [e3Id],\n account,\n })\n\n return await this.walletClient.writeContract(request)\n } catch (error) {\n throw new SDKError(`Failed to cancel E3: ${error}`, 'CANCEL_E3_FAILED')\n }\n }\n\n public async publishCiphertextOutput(\n e3Id: bigint,\n ciphertextOutput: `0x${string}`,\n ciphertextCommitment: `0x${string}`,\n proof: `0x${string}`,\n gasLimit?: bigint,\n ): Promise<Hash> {\n if (!this.walletClient) {\n throw new SDKError('Wallet client required for write operations', 'NO_WALLET')\n }\n\n try {\n const account = this.walletClient.account\n if (!account) {\n throw new SDKError('No account connected', 'NO_ACCOUNT')\n }\n\n const { request } = await this.publicClient.simulateContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'publishCiphertextOutput',\n args: [e3Id, ciphertextOutput, ciphertextCommitment, proof],\n account,\n gas: gasLimit,\n })\n\n return await this.walletClient.writeContract(request)\n } catch (error) {\n throw new SDKError(`Failed to publish ciphertext output: ${error}`, 'PUBLISH_CIPHERTEXT_OUTPUT_FAILED')\n }\n }\n\n public async getE3(e3Id: bigint): Promise<E3> {\n try {\n const result: E3 = await this.publicClient.readContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'getE3',\n args: [e3Id],\n })\n\n return result\n } catch (error) {\n throw new SDKError(`Failed to get E3: ${error}`, 'GET_E3_FAILED')\n }\n }\n\n public async getE3Quote(requestParams: E3RequestParams): Promise<bigint> {\n try {\n const committeeSize = validateCommitteeSize(requestParams.committeeSize)\n const expectedCryptoConfigId = cryptoConfigIdForParamSet(requestParams.paramSet)\n\n return this.publicClient.readContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'getE3Quote',\n args: [\n {\n committeeSize,\n inputWindow: requestParams.inputWindow,\n e3Program: requestParams.e3Program,\n paramSet: requestParams.paramSet,\n computeProviderParams: requestParams.computeProviderParams,\n customParams: requestParams.customParams || '0x',\n expectedFeeToken: this.contracts.feeToken,\n expectedCryptoConfigId,\n maxFee: requestParams.maxFee ?? 0n,\n },\n ],\n })\n } catch (error) {\n throw new SDKError(`Failed to get E3 quote: ${error}`, 'GET_E3_QUOTE_FAILED')\n }\n }\n\n public async getFailureReason(e3Id: bigint): Promise<FailureReason> {\n try {\n return this.publicClient.readContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'getFailureReason',\n args: [e3Id],\n })\n } catch (error) {\n throw new SDKError(`Failed to get failure reason: ${error}`, 'GET_FAILURE_REASON_FAILED')\n }\n }\n\n public async getE3PublicKey(e3Id: bigint): Promise<`0x${string}`> {\n try {\n const result: `0x${string}` = await this.publicClient.readContract({\n address: this.contracts.ciphernodeRegistry,\n abi: CiphernodeRegistryOwnable__factory.abi,\n functionName: 'committeePublicKey',\n args: [e3Id],\n })\n\n return result\n } catch (error) {\n throw new SDKError(`Failed to get E3 public key: ${error}`, 'GET_E3_PUBLIC_KEY_FAILED')\n }\n }\n\n public async getE3Stage(e3Id: bigint): Promise<E3Stage> {\n try {\n return this.publicClient.readContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'getE3Stage',\n args: [e3Id],\n })\n } catch (error) {\n throw new SDKError(`Failed to get E3 stage: ${error}`, 'GET_E3_STAGE_FAILED')\n }\n }\n\n public async estimateGas(\n functionName: string,\n args: readonly unknown[],\n contractAddress: `0x${string}`,\n abi: Abi,\n value?: bigint,\n ): Promise<bigint> {\n if (!this.walletClient) {\n throw new SDKError('Wallet client required for gas estimation', 'NO_WALLET')\n }\n\n try {\n const account = this.walletClient.account\n if (!account) {\n throw new SDKError('No account connected', 'NO_ACCOUNT')\n }\n\n const estimateParams = {\n address: contractAddress,\n abi,\n functionName,\n args,\n account,\n ...(value !== undefined && { value }),\n }\n\n return await this.publicClient.estimateContractGas(estimateParams)\n } catch (error) {\n throw new SDKError(`Failed to estimate gas: ${error}`, 'GAS_ESTIMATION_FAILED')\n }\n }\n\n public async waitForTransaction(hash: Hash): Promise<TransactionReceipt> {\n try {\n return await this.publicClient.waitForTransactionReceipt({\n hash,\n confirmations: 1,\n })\n } catch (error) {\n throw new SDKError(`Failed to wait for transaction: ${error}`, 'TRANSACTION_WAIT_FAILED')\n }\n }\n}\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport { type Address, type Hash, type Log, PublicClient, encodeAbiParameters } from 'viem'\nimport type { BfvParams } from './types'\n\nexport class SDKError extends Error {\n constructor(\n message: string,\n public readonly code?: string,\n ) {\n super(message)\n this.name = 'SDKError'\n }\n}\n\nexport function isValidAddress(address: string): address is Address {\n return /^0x[a-fA-F0-9]{40}$/.test(address)\n}\n\nexport function isValidHash(hash: string): hash is Hash {\n return /^0x[a-fA-F0-9]{64}$/.test(hash)\n}\n\nexport function formatEventName(contractName: string, eventName: string): string {\n return `${contractName}.${eventName}`\n}\n\nexport function parseEventData<T>(log: Log): T {\n return log.data as unknown as T\n}\n\n/**\n * Sleep for a specified number of milliseconds\n */\nexport const sleep = (ms: number): Promise<void> => {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nexport function formatBigInt(value: bigint): string {\n return value.toString()\n}\n\nexport function parseBigInt(value: string): bigint {\n return BigInt(value)\n}\n\nexport function generateEventId(log: Log): string {\n return `${log.blockHash}-${log.logIndex}`\n}\n\n/**\n * Get the current timestamp in seconds\n * from onchain\n * @param publicClient - The public client to use\n */\nexport async function getCurrentTimestamp(publicClient: PublicClient): Promise<bigint> {\n const block = await publicClient.getBlock()\n return block.timestamp\n}\n\n// Compute provider parameters structure\nexport interface ComputeProviderParams {\n name: string\n parallel: boolean\n batch_size: number\n}\n\n// Default compute provider configuration\nexport const DEFAULT_COMPUTE_PROVIDER_PARAMS: ComputeProviderParams = {\n name: 'risc0',\n parallel: false,\n batch_size: 2,\n}\n\n// Default E3 configuration (`committeeSize` is `IInterfold.CommitteeSize`, not circuit N_PARTIES).\nexport const DEFAULT_E3_CONFIG = {\n committeeSize: 0, // CommitteeSize.Minimum\n duration: 1800, // 30 minutes in seconds\n payment_amount: '0', // 0 ETH in wei\n} as const\n\nexport function cryptoConfigIdForParamSet(paramSet: number): Hash {\n if (paramSet === 0) {\n return '0x04f3677e73b0f5066d6caf5cbd92e3fb2e38338edaf5cfc971ab28f7b684da78'\n }\n if (paramSet === 1) {\n return '0xd9c86e581f8291ffb5b63595600e8d096ed30b16e2e0a6634a76c22b1f58fb4e'\n }\n throw new SDKError(`Unsupported BFV parameter set: ${paramSet}`, 'UNSUPPORTED_CRYPTO_CONFIG')\n}\n\n/**\n * Encode BFV parameters for the smart contract\n * BFV (Brakerski-Fan-Vercauteren) is a type of fully homomorphic encryption\n */\nexport function encodeBfvParams(params: BfvParams): `0x${string}` {\n const { degree, plaintextModulus, moduli, error1Variance } = params\n\n if (error1Variance === undefined) {\n throw new SDKError(\n 'error1Variance is required in ProtocolParams. All BFV parameter sets must specify error1_variance.',\n 'MISSING_ERROR1_VARIANCE',\n )\n }\n\n return encodeAbiParameters(\n [\n {\n name: 'bfvParams',\n type: 'tuple',\n components: [\n { name: 'degree', type: 'uint256' },\n { name: 'plaintext_modulus', type: 'uint256' },\n { name: 'moduli', type: 'uint256[]' },\n { name: 'error1_variance', type: 'string' },\n ],\n },\n ],\n [\n {\n degree: BigInt(degree),\n plaintext_modulus: BigInt(plaintextModulus),\n moduli: [...moduli],\n error1_variance: error1Variance,\n },\n ],\n )\n}\n\n/**\n * Encode compute provider parameters for the smart contract'\n * If mock is true, the compute provider parameters will return 32 bytes of 0x00\n */\nexport function encodeComputeProviderParams(params: ComputeProviderParams, mock: boolean = false): `0x${string}` {\n if (mock) {\n return `0x${'00'.repeat(32)}` as `0x${string}`\n }\n\n const jsonString = JSON.stringify(params)\n const encoder = new TextEncoder()\n const bytes = encoder.encode(jsonString)\n\n return `0x${Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('')}`\n}\n\n/**\n * Encode custom parameters for the smart contract.\n */\nexport function encodeCustomParams(params: Record<string, unknown>): `0x${string}` {\n const jsonString = JSON.stringify(params)\n const encoder = new TextEncoder()\n const bytes = encoder.encode(jsonString)\n\n return `0x${Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('')}`\n}\n\n// inputWindow[0] is always larger than now and dkg deadline\nexport const inputWindowStartBuffer = 15n\n\n/**\n * Calculate start window for E3 request\n * @dev This function can be used for testing purposes, or for E3s which need to start as soon as possible.\n * @param publicClient - The public client to use\n * @param duration - The duration of the input window in seconds\n * @param startBuffer - Buffer in seconds added to current timestamp for input window start\n */\nexport async function calculateInputWindow(\n publicClient: PublicClient,\n duration: number = DEFAULT_E3_CONFIG.duration,\n startBuffer: bigint = inputWindowStartBuffer,\n): Promise<[bigint, bigint]> {\n const now = await getCurrentTimestamp(publicClient)\n return [BigInt(now) + startBuffer, BigInt(now) + startBuffer + BigInt(duration)]\n}\n\n/**\n * Decode plaintextOutput bytes to get the actual result number\n */\nexport function decodePlaintextOutput(plaintextOutput: string): number | null {\n try {\n // Remove '0x' prefix if present\n const hex = plaintextOutput.startsWith('0x') ? plaintextOutput.slice(2) : plaintextOutput\n\n // Convert hex to bytes\n const bytes = new Uint8Array(hex.match(/.{1,2}/g)?.map((byte) => parseInt(byte, 16)) || [])\n\n if (bytes.length < 8) {\n console.warn('Plaintext output too short for u64 decoding')\n return null\n }\n\n // Decode first u64 (8 bytes) as little-endian\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n const result = view.getBigUint64(0, true) // true for little-endian\n\n return Number(result)\n } catch (error) {\n console.error('Failed to decode plaintext output:', error)\n return null\n }\n}\n\n// Helper function to convert proof bytes to field elements\nexport function proofToFields(proof: Uint8Array): string[] {\n const fields: string[] = []\n for (let i = 0; i < proof.length; i += 32) {\n const chunk = proof.slice(i, i + 32)\n fields.push('0x' + Buffer.from(chunk).toString('hex'))\n }\n return fields\n}\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport { SDKError } from '../utils'\n\nexport interface ContractAddresses {\n interfold: `0x${string}`\n ciphernodeRegistry: `0x${string}`\n feeToken: `0x${string}`\n}\n\n/** On-chain `IInterfold.CommitteeSize`: Minimum (N=3), Micro (N=9), Small (N=19). */\nexport enum CommitteeSize {\n Minimum = 0,\n Micro = 1,\n Small = 2,\n}\n\n/** Fail fast on out-of-range committee sizes before they hit the contract. */\nexport function validateCommitteeSize(value: number | CommitteeSize): CommitteeSize {\n if (!Number.isInteger(value) || value < CommitteeSize.Minimum || value > CommitteeSize.Small) {\n throw new SDKError(\n `Invalid committeeSize ${value}. Use CommitteeSize.Minimum (0), CommitteeSize.Micro (1), or CommitteeSize.Small (2).`,\n 'INVALID_COMMITTEE_SIZE',\n )\n }\n return value\n}\n\nexport enum ParamSet {\n Insecure512 = 0,\n Secure8192 = 1,\n}\n\nexport interface E3 {\n seed: bigint\n committeeSize: number\n requestBlock: bigint\n inputWindow: readonly [bigint, bigint]\n encryptionSchemeId: string\n e3Program: string\n paramSet: number\n decryptionVerifier: string\n committeePublicKey: string\n ciphertextOutput: string\n ciphertextCommitment: string\n plaintextOutput: string\n}\n\nexport interface RequestParams {\n gasLimit?: bigint\n}\n\nexport interface E3RequestParams extends RequestParams {\n committeeSize: number\n inputWindow: readonly [bigint, bigint]\n e3Program: `0x${string}`\n paramSet: number\n computeProviderParams: `0x${string}`\n customParams?: `0x${string}`\n /** Maximum fee token amount accepted. Defaults to a fresh quote. */\n maxFee?: bigint\n}\n\nexport enum E3Stage {\n None,\n Requested,\n CommitteeFinalized,\n KeyPublished,\n CiphertextReady,\n Complete,\n Failed,\n}\n\nexport enum FailureReason {\n None,\n CommitteeFormationTimeout,\n InsufficientCommitteeMembers,\n DKGTimeout,\n DKGInvalidShares,\n NoInputsReceived,\n ComputeTimeout,\n ComputeProviderExpired,\n ComputeProviderFailed,\n RequesterCancelled,\n DecryptionTimeout,\n DecryptionInvalidShares,\n VerificationFailed,\n}\n"],"mappings":"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","names":["import_viem","E3Stage","FailureReason"]}
|
package/dist/contracts/index.js
CHANGED
|
@@ -20,6 +20,15 @@ var SDKError = class extends Error {
|
|
|
20
20
|
function isValidAddress(address) {
|
|
21
21
|
return /^0x[a-fA-F0-9]{40}$/.test(address);
|
|
22
22
|
}
|
|
23
|
+
function cryptoConfigIdForParamSet(paramSet) {
|
|
24
|
+
if (paramSet === 0) {
|
|
25
|
+
return "0x04f3677e73b0f5066d6caf5cbd92e3fb2e38338edaf5cfc971ab28f7b684da78";
|
|
26
|
+
}
|
|
27
|
+
if (paramSet === 1) {
|
|
28
|
+
return "0xd9c86e581f8291ffb5b63595600e8d096ed30b16e2e0a6634a76c22b1f58fb4e";
|
|
29
|
+
}
|
|
30
|
+
throw new SDKError(`Unsupported BFV parameter set: ${paramSet}`, "UNSUPPORTED_CRYPTO_CONFIG");
|
|
31
|
+
}
|
|
23
32
|
|
|
24
33
|
// src/contracts/types.ts
|
|
25
34
|
function validateCommitteeSize(value) {
|
|
@@ -149,11 +158,7 @@ var ContractClient = class _ContractClient {
|
|
|
149
158
|
}
|
|
150
159
|
const committeeSize = validateCommitteeSize(params.committeeSize);
|
|
151
160
|
const maxFee = params.maxFee ?? await this.getE3Quote(params);
|
|
152
|
-
const expectedCryptoConfigId =
|
|
153
|
-
address: this.contracts.interfold,
|
|
154
|
-
abi: Interfold__factory.abi,
|
|
155
|
-
functionName: "activeCryptoConfigId"
|
|
156
|
-
});
|
|
161
|
+
const expectedCryptoConfigId = cryptoConfigIdForParamSet(params.paramSet);
|
|
157
162
|
const { request } = await this.publicClient.simulateContract({
|
|
158
163
|
address: this.contracts.interfold,
|
|
159
164
|
abi: Interfold__factory.abi,
|
|
@@ -238,11 +243,7 @@ var ContractClient = class _ContractClient {
|
|
|
238
243
|
async getE3Quote(requestParams) {
|
|
239
244
|
try {
|
|
240
245
|
const committeeSize = validateCommitteeSize(requestParams.committeeSize);
|
|
241
|
-
const expectedCryptoConfigId =
|
|
242
|
-
address: this.contracts.interfold,
|
|
243
|
-
abi: Interfold__factory.abi,
|
|
244
|
-
functionName: "activeCryptoConfigId"
|
|
245
|
-
});
|
|
246
|
+
const expectedCryptoConfigId = cryptoConfigIdForParamSet(requestParams.paramSet);
|
|
246
247
|
return this.publicClient.readContract({
|
|
247
248
|
address: this.contracts.interfold,
|
|
248
249
|
abi: Interfold__factory.abi,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/contracts/contract-client.ts","../../src/utils.ts","../../src/contracts/types.ts"],"sourcesContent":["// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport {\n type Abi,\n type Chain,\n type Hash,\n type PublicClient,\n type TransactionReceipt,\n type WalletClient,\n createPublicClient,\n createWalletClient,\n http,\n webSocket,\n} from 'viem'\nimport { privateKeyToAccount } from 'viem/accounts'\n\nimport { CiphernodeRegistryOwnable__factory, Interfold__factory, InterfoldToken__factory } from '@interfold/contracts/types'\nimport type { ContractAddresses, E3, E3RequestParams, E3Stage, FailureReason } from './types'\nimport { validateCommitteeSize } from './types'\nimport { SDKError, isValidAddress } from '../utils'\n\nexport interface ContractClientConfig {\n publicClient: PublicClient\n walletClient?: WalletClient\n contracts: ContractAddresses\n}\n\nexport class ContractClient {\n private publicClient: PublicClient\n private walletClient?: WalletClient\n private contracts: ContractAddresses\n private contractInfo: {\n interfold: { address: `0x${string}`; abi: Abi }\n ciphernodeRegistry: { address: `0x${string}`; abi: Abi }\n feeToken: { address: `0x${string}`; abi: Abi }\n }\n\n constructor(config: ContractClientConfig) {\n const { publicClient, walletClient, contracts } = config\n\n if (!isValidAddress(contracts.interfold)) {\n throw new SDKError('Invalid Interfold contract address', 'INVALID_ADDRESS')\n }\n if (!isValidAddress(contracts.ciphernodeRegistry)) {\n throw new SDKError('Invalid CiphernodeRegistry contract address', 'INVALID_ADDRESS')\n }\n if (!isValidAddress(contracts.feeToken)) {\n throw new SDKError('Invalid FeeToken contract address', 'INVALID_ADDRESS')\n }\n\n this.publicClient = publicClient\n this.walletClient = walletClient\n this.contracts = contracts\n\n this.contractInfo = {\n interfold: {\n address: contracts.interfold,\n abi: Interfold__factory.abi,\n },\n ciphernodeRegistry: {\n address: contracts.ciphernodeRegistry,\n abi: CiphernodeRegistryOwnable__factory.abi,\n },\n feeToken: {\n address: contracts.feeToken,\n abi: InterfoldToken__factory.abi,\n },\n }\n }\n\n public static create(options: {\n rpcUrl: string\n contracts: ContractAddresses\n privateKey?: `0x${string}`\n chain: Chain\n }): ContractClient {\n const isWebSocket = options.rpcUrl.startsWith('ws://') || options.rpcUrl.startsWith('wss://')\n const transport = isWebSocket\n ? webSocket(options.rpcUrl, {\n keepAlive: { interval: 30_000 },\n reconnect: { attempts: 5, delay: 2_000 },\n })\n : http(options.rpcUrl)\n\n const publicClient = createPublicClient({\n chain: options.chain,\n transport,\n }) as PublicClient\n\n let walletClient: WalletClient | undefined\n if (options.privateKey) {\n const account = privateKeyToAccount(options.privateKey)\n walletClient = createWalletClient({\n account,\n chain: options.chain,\n transport,\n })\n }\n\n return new ContractClient({ publicClient, walletClient, contracts: options.contracts })\n }\n\n public getPublicClient(): PublicClient {\n return this.publicClient\n }\n\n public async approveFeeToken(amount: bigint): Promise<Hash> {\n if (!this.walletClient) {\n throw new SDKError('Wallet client required for write operations', 'NO_WALLET')\n }\n\n try {\n const account = this.walletClient.account\n if (!account) {\n throw new SDKError('No account connected', 'NO_ACCOUNT')\n }\n\n const { request } = await this.publicClient.simulateContract({\n address: this.contracts.feeToken,\n abi: InterfoldToken__factory.abi,\n functionName: 'approve',\n args: [this.contracts.interfold, amount],\n account,\n })\n\n return await this.walletClient.writeContract(request)\n } catch (error) {\n throw new SDKError(`Failed to approve fee token: ${error}`, 'APPROVE_FEE_TOKEN_FAILED')\n }\n }\n\n public async requestE3(params: E3RequestParams): Promise<Hash> {\n if (!this.walletClient) {\n throw new SDKError('Wallet client required for write operations', 'NO_WALLET')\n }\n\n try {\n const account = this.walletClient.account\n if (!account) {\n throw new SDKError('No account connected', 'NO_ACCOUNT')\n }\n\n const committeeSize = validateCommitteeSize(params.committeeSize)\n const maxFee = params.maxFee ?? (await this.getE3Quote(params))\n const expectedCryptoConfigId = await this.publicClient.readContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'activeCryptoConfigId',\n })\n\n const { request } = await this.publicClient.simulateContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'request',\n args: [\n {\n committeeSize,\n inputWindow: params.inputWindow,\n e3Program: params.e3Program,\n paramSet: params.paramSet,\n computeProviderParams: params.computeProviderParams,\n customParams: params.customParams || '0x',\n expectedFeeToken: this.contracts.feeToken,\n expectedCryptoConfigId,\n maxFee,\n },\n ],\n account,\n gas: params.gasLimit,\n })\n\n return await this.walletClient.writeContract(request)\n } catch (error) {\n throw new SDKError(`Failed to request E3: ${error}`, 'REQUEST_E3_FAILED')\n }\n }\n\n public async cancelE3(e3Id: bigint): Promise<Hash> {\n if (!this.walletClient) {\n throw new SDKError('Wallet client required for write operations', 'NO_WALLET')\n }\n const account = this.walletClient.account\n if (!account) {\n throw new SDKError('No account connected', 'NO_ACCOUNT')\n }\n\n try {\n const { request } = await this.publicClient.simulateContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'cancelE3',\n args: [e3Id],\n account,\n })\n\n return await this.walletClient.writeContract(request)\n } catch (error) {\n throw new SDKError(`Failed to cancel E3: ${error}`, 'CANCEL_E3_FAILED')\n }\n }\n\n public async publishCiphertextOutput(\n e3Id: bigint,\n ciphertextOutput: `0x${string}`,\n ciphertextCommitment: `0x${string}`,\n proof: `0x${string}`,\n gasLimit?: bigint,\n ): Promise<Hash> {\n if (!this.walletClient) {\n throw new SDKError('Wallet client required for write operations', 'NO_WALLET')\n }\n\n try {\n const account = this.walletClient.account\n if (!account) {\n throw new SDKError('No account connected', 'NO_ACCOUNT')\n }\n\n const { request } = await this.publicClient.simulateContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'publishCiphertextOutput',\n args: [e3Id, ciphertextOutput, ciphertextCommitment, proof],\n account,\n gas: gasLimit,\n })\n\n return await this.walletClient.writeContract(request)\n } catch (error) {\n throw new SDKError(`Failed to publish ciphertext output: ${error}`, 'PUBLISH_CIPHERTEXT_OUTPUT_FAILED')\n }\n }\n\n public async getE3(e3Id: bigint): Promise<E3> {\n try {\n const result: E3 = await this.publicClient.readContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'getE3',\n args: [e3Id],\n })\n\n return result\n } catch (error) {\n throw new SDKError(`Failed to get E3: ${error}`, 'GET_E3_FAILED')\n }\n }\n\n public async getE3Quote(requestParams: E3RequestParams): Promise<bigint> {\n try {\n const committeeSize = validateCommitteeSize(requestParams.committeeSize)\n const expectedCryptoConfigId = await this.publicClient.readContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'activeCryptoConfigId',\n })\n\n return this.publicClient.readContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'getE3Quote',\n args: [\n {\n committeeSize,\n inputWindow: requestParams.inputWindow,\n e3Program: requestParams.e3Program,\n paramSet: requestParams.paramSet,\n computeProviderParams: requestParams.computeProviderParams,\n customParams: requestParams.customParams || '0x',\n expectedFeeToken: this.contracts.feeToken,\n expectedCryptoConfigId,\n maxFee: requestParams.maxFee ?? 0n,\n },\n ],\n })\n } catch (error) {\n throw new SDKError(`Failed to get E3 quote: ${error}`, 'GET_E3_QUOTE_FAILED')\n }\n }\n\n public async getFailureReason(e3Id: bigint): Promise<FailureReason> {\n try {\n return this.publicClient.readContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'getFailureReason',\n args: [e3Id],\n })\n } catch (error) {\n throw new SDKError(`Failed to get failure reason: ${error}`, 'GET_FAILURE_REASON_FAILED')\n }\n }\n\n public async getE3PublicKey(e3Id: bigint): Promise<`0x${string}`> {\n try {\n const result: `0x${string}` = await this.publicClient.readContract({\n address: this.contracts.ciphernodeRegistry,\n abi: CiphernodeRegistryOwnable__factory.abi,\n functionName: 'committeePublicKey',\n args: [e3Id],\n })\n\n return result\n } catch (error) {\n throw new SDKError(`Failed to get E3 public key: ${error}`, 'GET_E3_PUBLIC_KEY_FAILED')\n }\n }\n\n public async getE3Stage(e3Id: bigint): Promise<E3Stage> {\n try {\n return this.publicClient.readContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'getE3Stage',\n args: [e3Id],\n })\n } catch (error) {\n throw new SDKError(`Failed to get E3 stage: ${error}`, 'GET_E3_STAGE_FAILED')\n }\n }\n\n public async estimateGas(\n functionName: string,\n args: readonly unknown[],\n contractAddress: `0x${string}`,\n abi: Abi,\n value?: bigint,\n ): Promise<bigint> {\n if (!this.walletClient) {\n throw new SDKError('Wallet client required for gas estimation', 'NO_WALLET')\n }\n\n try {\n const account = this.walletClient.account\n if (!account) {\n throw new SDKError('No account connected', 'NO_ACCOUNT')\n }\n\n const estimateParams = {\n address: contractAddress,\n abi,\n functionName,\n args,\n account,\n ...(value !== undefined && { value }),\n }\n\n return await this.publicClient.estimateContractGas(estimateParams)\n } catch (error) {\n throw new SDKError(`Failed to estimate gas: ${error}`, 'GAS_ESTIMATION_FAILED')\n }\n }\n\n public async waitForTransaction(hash: Hash): Promise<TransactionReceipt> {\n try {\n return await this.publicClient.waitForTransactionReceipt({\n hash,\n confirmations: 1,\n })\n } catch (error) {\n throw new SDKError(`Failed to wait for transaction: ${error}`, 'TRANSACTION_WAIT_FAILED')\n }\n }\n}\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport { type Address, type Hash, type Log, PublicClient, encodeAbiParameters } from 'viem'\nimport type { BfvParams } from './types'\n\nexport class SDKError extends Error {\n constructor(\n message: string,\n public readonly code?: string,\n ) {\n super(message)\n this.name = 'SDKError'\n }\n}\n\nexport function isValidAddress(address: string): address is Address {\n return /^0x[a-fA-F0-9]{40}$/.test(address)\n}\n\nexport function isValidHash(hash: string): hash is Hash {\n return /^0x[a-fA-F0-9]{64}$/.test(hash)\n}\n\nexport function formatEventName(contractName: string, eventName: string): string {\n return `${contractName}.${eventName}`\n}\n\nexport function parseEventData<T>(log: Log): T {\n return log.data as unknown as T\n}\n\n/**\n * Sleep for a specified number of milliseconds\n */\nexport const sleep = (ms: number): Promise<void> => {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nexport function formatBigInt(value: bigint): string {\n return value.toString()\n}\n\nexport function parseBigInt(value: string): bigint {\n return BigInt(value)\n}\n\nexport function generateEventId(log: Log): string {\n return `${log.blockHash}-${log.logIndex}`\n}\n\n/**\n * Get the current timestamp in seconds\n * from onchain\n * @param publicClient - The public client to use\n */\nexport async function getCurrentTimestamp(publicClient: PublicClient): Promise<bigint> {\n const block = await publicClient.getBlock()\n return block.timestamp\n}\n\n// Compute provider parameters structure\nexport interface ComputeProviderParams {\n name: string\n parallel: boolean\n batch_size: number\n}\n\n// Default compute provider configuration\nexport const DEFAULT_COMPUTE_PROVIDER_PARAMS: ComputeProviderParams = {\n name: 'risc0',\n parallel: false,\n batch_size: 2,\n}\n\n// Default E3 configuration (`committeeSize` is `IInterfold.CommitteeSize`, not circuit N_PARTIES).\nexport const DEFAULT_E3_CONFIG = {\n committeeSize: 0, // CommitteeSize.Minimum\n duration: 1800, // 30 minutes in seconds\n payment_amount: '0', // 0 ETH in wei\n} as const\n\n/**\n * Encode BFV parameters for the smart contract\n * BFV (Brakerski-Fan-Vercauteren) is a type of fully homomorphic encryption\n */\nexport function encodeBfvParams(params: BfvParams): `0x${string}` {\n const { degree, plaintextModulus, moduli, error1Variance } = params\n\n if (error1Variance === undefined) {\n throw new SDKError(\n 'error1Variance is required in ProtocolParams. All BFV parameter sets must specify error1_variance.',\n 'MISSING_ERROR1_VARIANCE',\n )\n }\n\n return encodeAbiParameters(\n [\n {\n name: 'bfvParams',\n type: 'tuple',\n components: [\n { name: 'degree', type: 'uint256' },\n { name: 'plaintext_modulus', type: 'uint256' },\n { name: 'moduli', type: 'uint256[]' },\n { name: 'error1_variance', type: 'string' },\n ],\n },\n ],\n [\n {\n degree: BigInt(degree),\n plaintext_modulus: BigInt(plaintextModulus),\n moduli: [...moduli],\n error1_variance: error1Variance,\n },\n ],\n )\n}\n\n/**\n * Encode compute provider parameters for the smart contract'\n * If mock is true, the compute provider parameters will return 32 bytes of 0x00\n */\nexport function encodeComputeProviderParams(params: ComputeProviderParams, mock: boolean = false): `0x${string}` {\n if (mock) {\n return `0x${'00'.repeat(32)}` as `0x${string}`\n }\n\n const jsonString = JSON.stringify(params)\n const encoder = new TextEncoder()\n const bytes = encoder.encode(jsonString)\n\n return `0x${Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('')}`\n}\n\n/**\n * Encode custom parameters for the smart contract.\n */\nexport function encodeCustomParams(params: Record<string, unknown>): `0x${string}` {\n const jsonString = JSON.stringify(params)\n const encoder = new TextEncoder()\n const bytes = encoder.encode(jsonString)\n\n return `0x${Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('')}`\n}\n\n// inputWindow[0] is always larger than now and dkg deadline\nexport const inputWindowStartBuffer = 15n\n\n/**\n * Calculate start window for E3 request\n * @dev This function can be used for testing purposes, or for E3s which need to start as soon as possible.\n * @param publicClient - The public client to use\n * @param duration - The duration of the input window in seconds\n * @param startBuffer - Buffer in seconds added to current timestamp for input window start\n */\nexport async function calculateInputWindow(\n publicClient: PublicClient,\n duration: number = DEFAULT_E3_CONFIG.duration,\n startBuffer: bigint = inputWindowStartBuffer,\n): Promise<[bigint, bigint]> {\n const now = await getCurrentTimestamp(publicClient)\n return [BigInt(now) + startBuffer, BigInt(now) + startBuffer + BigInt(duration)]\n}\n\n/**\n * Decode plaintextOutput bytes to get the actual result number\n */\nexport function decodePlaintextOutput(plaintextOutput: string): number | null {\n try {\n // Remove '0x' prefix if present\n const hex = plaintextOutput.startsWith('0x') ? plaintextOutput.slice(2) : plaintextOutput\n\n // Convert hex to bytes\n const bytes = new Uint8Array(hex.match(/.{1,2}/g)?.map((byte) => parseInt(byte, 16)) || [])\n\n if (bytes.length < 8) {\n console.warn('Plaintext output too short for u64 decoding')\n return null\n }\n\n // Decode first u64 (8 bytes) as little-endian\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n const result = view.getBigUint64(0, true) // true for little-endian\n\n return Number(result)\n } catch (error) {\n console.error('Failed to decode plaintext output:', error)\n return null\n }\n}\n\n// Helper function to convert proof bytes to field elements\nexport function proofToFields(proof: Uint8Array): string[] {\n const fields: string[] = []\n for (let i = 0; i < proof.length; i += 32) {\n const chunk = proof.slice(i, i + 32)\n fields.push('0x' + Buffer.from(chunk).toString('hex'))\n }\n return fields\n}\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport { SDKError } from '../utils'\n\nexport interface ContractAddresses {\n interfold: `0x${string}`\n ciphernodeRegistry: `0x${string}`\n feeToken: `0x${string}`\n}\n\n/** On-chain `IInterfold.CommitteeSize`: Minimum (N=3), Micro (N=9), Small (N=19). */\nexport enum CommitteeSize {\n Minimum = 0,\n Micro = 1,\n Small = 2,\n}\n\n/** Fail fast on out-of-range committee sizes before they hit the contract. */\nexport function validateCommitteeSize(value: number | CommitteeSize): CommitteeSize {\n if (!Number.isInteger(value) || value < CommitteeSize.Minimum || value > CommitteeSize.Small) {\n throw new SDKError(\n `Invalid committeeSize ${value}. Use CommitteeSize.Minimum (0), CommitteeSize.Micro (1), or CommitteeSize.Small (2).`,\n 'INVALID_COMMITTEE_SIZE',\n )\n }\n return value\n}\n\nexport enum ParamSet {\n Insecure512 = 0,\n Secure8192 = 1,\n}\n\nexport interface E3 {\n seed: bigint\n committeeSize: number\n requestBlock: bigint\n inputWindow: readonly [bigint, bigint]\n encryptionSchemeId: string\n e3Program: string\n paramSet: number\n decryptionVerifier: string\n committeePublicKey: string\n ciphertextOutput: string\n ciphertextCommitment: string\n plaintextOutput: string\n}\n\nexport interface RequestParams {\n gasLimit?: bigint\n}\n\nexport interface E3RequestParams extends RequestParams {\n committeeSize: number\n inputWindow: readonly [bigint, bigint]\n e3Program: `0x${string}`\n paramSet: number\n computeProviderParams: `0x${string}`\n customParams?: `0x${string}`\n /** Maximum fee token amount accepted. Defaults to a fresh quote. */\n maxFee?: bigint\n}\n\nexport enum E3Stage {\n None,\n Requested,\n CommitteeFinalized,\n KeyPublished,\n CiphertextReady,\n Complete,\n Failed,\n}\n\nexport enum FailureReason {\n None,\n CommitteeFormationTimeout,\n InsufficientCommitteeMembers,\n DKGTimeout,\n DKGInvalidShares,\n NoInputsReceived,\n ComputeTimeout,\n ComputeProviderExpired,\n ComputeProviderFailed,\n RequesterCancelled,\n DecryptionTimeout,\n DecryptionInvalidShares,\n VerificationFailed,\n}\n"],"mappings":"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","names":["E3Stage","FailureReason"]}
|
|
1
|
+
{"version":3,"sources":["../../src/contracts/contract-client.ts","../../src/utils.ts","../../src/contracts/types.ts"],"sourcesContent":["// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport {\n type Abi,\n type Chain,\n type Hash,\n type PublicClient,\n type TransactionReceipt,\n type WalletClient,\n createPublicClient,\n createWalletClient,\n http,\n webSocket,\n} from 'viem'\nimport { privateKeyToAccount } from 'viem/accounts'\n\nimport { CiphernodeRegistryOwnable__factory, Interfold__factory, InterfoldToken__factory } from '@interfold/contracts/types'\nimport type { ContractAddresses, E3, E3RequestParams, E3Stage, FailureReason } from './types'\nimport { validateCommitteeSize } from './types'\nimport { SDKError, cryptoConfigIdForParamSet, isValidAddress } from '../utils'\n\nexport interface ContractClientConfig {\n publicClient: PublicClient\n walletClient?: WalletClient\n contracts: ContractAddresses\n}\n\nexport class ContractClient {\n private publicClient: PublicClient\n private walletClient?: WalletClient\n private contracts: ContractAddresses\n private contractInfo: {\n interfold: { address: `0x${string}`; abi: Abi }\n ciphernodeRegistry: { address: `0x${string}`; abi: Abi }\n feeToken: { address: `0x${string}`; abi: Abi }\n }\n\n constructor(config: ContractClientConfig) {\n const { publicClient, walletClient, contracts } = config\n\n if (!isValidAddress(contracts.interfold)) {\n throw new SDKError('Invalid Interfold contract address', 'INVALID_ADDRESS')\n }\n if (!isValidAddress(contracts.ciphernodeRegistry)) {\n throw new SDKError('Invalid CiphernodeRegistry contract address', 'INVALID_ADDRESS')\n }\n if (!isValidAddress(contracts.feeToken)) {\n throw new SDKError('Invalid FeeToken contract address', 'INVALID_ADDRESS')\n }\n\n this.publicClient = publicClient\n this.walletClient = walletClient\n this.contracts = contracts\n\n this.contractInfo = {\n interfold: {\n address: contracts.interfold,\n abi: Interfold__factory.abi,\n },\n ciphernodeRegistry: {\n address: contracts.ciphernodeRegistry,\n abi: CiphernodeRegistryOwnable__factory.abi,\n },\n feeToken: {\n address: contracts.feeToken,\n abi: InterfoldToken__factory.abi,\n },\n }\n }\n\n public static create(options: {\n rpcUrl: string\n contracts: ContractAddresses\n privateKey?: `0x${string}`\n chain: Chain\n }): ContractClient {\n const isWebSocket = options.rpcUrl.startsWith('ws://') || options.rpcUrl.startsWith('wss://')\n const transport = isWebSocket\n ? webSocket(options.rpcUrl, {\n keepAlive: { interval: 30_000 },\n reconnect: { attempts: 5, delay: 2_000 },\n })\n : http(options.rpcUrl)\n\n const publicClient = createPublicClient({\n chain: options.chain,\n transport,\n }) as PublicClient\n\n let walletClient: WalletClient | undefined\n if (options.privateKey) {\n const account = privateKeyToAccount(options.privateKey)\n walletClient = createWalletClient({\n account,\n chain: options.chain,\n transport,\n })\n }\n\n return new ContractClient({ publicClient, walletClient, contracts: options.contracts })\n }\n\n public getPublicClient(): PublicClient {\n return this.publicClient\n }\n\n public async approveFeeToken(amount: bigint): Promise<Hash> {\n if (!this.walletClient) {\n throw new SDKError('Wallet client required for write operations', 'NO_WALLET')\n }\n\n try {\n const account = this.walletClient.account\n if (!account) {\n throw new SDKError('No account connected', 'NO_ACCOUNT')\n }\n\n const { request } = await this.publicClient.simulateContract({\n address: this.contracts.feeToken,\n abi: InterfoldToken__factory.abi,\n functionName: 'approve',\n args: [this.contracts.interfold, amount],\n account,\n })\n\n return await this.walletClient.writeContract(request)\n } catch (error) {\n throw new SDKError(`Failed to approve fee token: ${error}`, 'APPROVE_FEE_TOKEN_FAILED')\n }\n }\n\n public async requestE3(params: E3RequestParams): Promise<Hash> {\n if (!this.walletClient) {\n throw new SDKError('Wallet client required for write operations', 'NO_WALLET')\n }\n\n try {\n const account = this.walletClient.account\n if (!account) {\n throw new SDKError('No account connected', 'NO_ACCOUNT')\n }\n\n const committeeSize = validateCommitteeSize(params.committeeSize)\n const maxFee = params.maxFee ?? (await this.getE3Quote(params))\n const expectedCryptoConfigId = cryptoConfigIdForParamSet(params.paramSet)\n\n const { request } = await this.publicClient.simulateContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'request',\n args: [\n {\n committeeSize,\n inputWindow: params.inputWindow,\n e3Program: params.e3Program,\n paramSet: params.paramSet,\n computeProviderParams: params.computeProviderParams,\n customParams: params.customParams || '0x',\n expectedFeeToken: this.contracts.feeToken,\n expectedCryptoConfigId,\n maxFee,\n },\n ],\n account,\n gas: params.gasLimit,\n })\n\n return await this.walletClient.writeContract(request)\n } catch (error) {\n throw new SDKError(`Failed to request E3: ${error}`, 'REQUEST_E3_FAILED')\n }\n }\n\n public async cancelE3(e3Id: bigint): Promise<Hash> {\n if (!this.walletClient) {\n throw new SDKError('Wallet client required for write operations', 'NO_WALLET')\n }\n const account = this.walletClient.account\n if (!account) {\n throw new SDKError('No account connected', 'NO_ACCOUNT')\n }\n\n try {\n const { request } = await this.publicClient.simulateContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'cancelE3',\n args: [e3Id],\n account,\n })\n\n return await this.walletClient.writeContract(request)\n } catch (error) {\n throw new SDKError(`Failed to cancel E3: ${error}`, 'CANCEL_E3_FAILED')\n }\n }\n\n public async publishCiphertextOutput(\n e3Id: bigint,\n ciphertextOutput: `0x${string}`,\n ciphertextCommitment: `0x${string}`,\n proof: `0x${string}`,\n gasLimit?: bigint,\n ): Promise<Hash> {\n if (!this.walletClient) {\n throw new SDKError('Wallet client required for write operations', 'NO_WALLET')\n }\n\n try {\n const account = this.walletClient.account\n if (!account) {\n throw new SDKError('No account connected', 'NO_ACCOUNT')\n }\n\n const { request } = await this.publicClient.simulateContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'publishCiphertextOutput',\n args: [e3Id, ciphertextOutput, ciphertextCommitment, proof],\n account,\n gas: gasLimit,\n })\n\n return await this.walletClient.writeContract(request)\n } catch (error) {\n throw new SDKError(`Failed to publish ciphertext output: ${error}`, 'PUBLISH_CIPHERTEXT_OUTPUT_FAILED')\n }\n }\n\n public async getE3(e3Id: bigint): Promise<E3> {\n try {\n const result: E3 = await this.publicClient.readContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'getE3',\n args: [e3Id],\n })\n\n return result\n } catch (error) {\n throw new SDKError(`Failed to get E3: ${error}`, 'GET_E3_FAILED')\n }\n }\n\n public async getE3Quote(requestParams: E3RequestParams): Promise<bigint> {\n try {\n const committeeSize = validateCommitteeSize(requestParams.committeeSize)\n const expectedCryptoConfigId = cryptoConfigIdForParamSet(requestParams.paramSet)\n\n return this.publicClient.readContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'getE3Quote',\n args: [\n {\n committeeSize,\n inputWindow: requestParams.inputWindow,\n e3Program: requestParams.e3Program,\n paramSet: requestParams.paramSet,\n computeProviderParams: requestParams.computeProviderParams,\n customParams: requestParams.customParams || '0x',\n expectedFeeToken: this.contracts.feeToken,\n expectedCryptoConfigId,\n maxFee: requestParams.maxFee ?? 0n,\n },\n ],\n })\n } catch (error) {\n throw new SDKError(`Failed to get E3 quote: ${error}`, 'GET_E3_QUOTE_FAILED')\n }\n }\n\n public async getFailureReason(e3Id: bigint): Promise<FailureReason> {\n try {\n return this.publicClient.readContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'getFailureReason',\n args: [e3Id],\n })\n } catch (error) {\n throw new SDKError(`Failed to get failure reason: ${error}`, 'GET_FAILURE_REASON_FAILED')\n }\n }\n\n public async getE3PublicKey(e3Id: bigint): Promise<`0x${string}`> {\n try {\n const result: `0x${string}` = await this.publicClient.readContract({\n address: this.contracts.ciphernodeRegistry,\n abi: CiphernodeRegistryOwnable__factory.abi,\n functionName: 'committeePublicKey',\n args: [e3Id],\n })\n\n return result\n } catch (error) {\n throw new SDKError(`Failed to get E3 public key: ${error}`, 'GET_E3_PUBLIC_KEY_FAILED')\n }\n }\n\n public async getE3Stage(e3Id: bigint): Promise<E3Stage> {\n try {\n return this.publicClient.readContract({\n address: this.contracts.interfold,\n abi: Interfold__factory.abi,\n functionName: 'getE3Stage',\n args: [e3Id],\n })\n } catch (error) {\n throw new SDKError(`Failed to get E3 stage: ${error}`, 'GET_E3_STAGE_FAILED')\n }\n }\n\n public async estimateGas(\n functionName: string,\n args: readonly unknown[],\n contractAddress: `0x${string}`,\n abi: Abi,\n value?: bigint,\n ): Promise<bigint> {\n if (!this.walletClient) {\n throw new SDKError('Wallet client required for gas estimation', 'NO_WALLET')\n }\n\n try {\n const account = this.walletClient.account\n if (!account) {\n throw new SDKError('No account connected', 'NO_ACCOUNT')\n }\n\n const estimateParams = {\n address: contractAddress,\n abi,\n functionName,\n args,\n account,\n ...(value !== undefined && { value }),\n }\n\n return await this.publicClient.estimateContractGas(estimateParams)\n } catch (error) {\n throw new SDKError(`Failed to estimate gas: ${error}`, 'GAS_ESTIMATION_FAILED')\n }\n }\n\n public async waitForTransaction(hash: Hash): Promise<TransactionReceipt> {\n try {\n return await this.publicClient.waitForTransactionReceipt({\n hash,\n confirmations: 1,\n })\n } catch (error) {\n throw new SDKError(`Failed to wait for transaction: ${error}`, 'TRANSACTION_WAIT_FAILED')\n }\n }\n}\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport { type Address, type Hash, type Log, PublicClient, encodeAbiParameters } from 'viem'\nimport type { BfvParams } from './types'\n\nexport class SDKError extends Error {\n constructor(\n message: string,\n public readonly code?: string,\n ) {\n super(message)\n this.name = 'SDKError'\n }\n}\n\nexport function isValidAddress(address: string): address is Address {\n return /^0x[a-fA-F0-9]{40}$/.test(address)\n}\n\nexport function isValidHash(hash: string): hash is Hash {\n return /^0x[a-fA-F0-9]{64}$/.test(hash)\n}\n\nexport function formatEventName(contractName: string, eventName: string): string {\n return `${contractName}.${eventName}`\n}\n\nexport function parseEventData<T>(log: Log): T {\n return log.data as unknown as T\n}\n\n/**\n * Sleep for a specified number of milliseconds\n */\nexport const sleep = (ms: number): Promise<void> => {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nexport function formatBigInt(value: bigint): string {\n return value.toString()\n}\n\nexport function parseBigInt(value: string): bigint {\n return BigInt(value)\n}\n\nexport function generateEventId(log: Log): string {\n return `${log.blockHash}-${log.logIndex}`\n}\n\n/**\n * Get the current timestamp in seconds\n * from onchain\n * @param publicClient - The public client to use\n */\nexport async function getCurrentTimestamp(publicClient: PublicClient): Promise<bigint> {\n const block = await publicClient.getBlock()\n return block.timestamp\n}\n\n// Compute provider parameters structure\nexport interface ComputeProviderParams {\n name: string\n parallel: boolean\n batch_size: number\n}\n\n// Default compute provider configuration\nexport const DEFAULT_COMPUTE_PROVIDER_PARAMS: ComputeProviderParams = {\n name: 'risc0',\n parallel: false,\n batch_size: 2,\n}\n\n// Default E3 configuration (`committeeSize` is `IInterfold.CommitteeSize`, not circuit N_PARTIES).\nexport const DEFAULT_E3_CONFIG = {\n committeeSize: 0, // CommitteeSize.Minimum\n duration: 1800, // 30 minutes in seconds\n payment_amount: '0', // 0 ETH in wei\n} as const\n\nexport function cryptoConfigIdForParamSet(paramSet: number): Hash {\n if (paramSet === 0) {\n return '0x04f3677e73b0f5066d6caf5cbd92e3fb2e38338edaf5cfc971ab28f7b684da78'\n }\n if (paramSet === 1) {\n return '0xd9c86e581f8291ffb5b63595600e8d096ed30b16e2e0a6634a76c22b1f58fb4e'\n }\n throw new SDKError(`Unsupported BFV parameter set: ${paramSet}`, 'UNSUPPORTED_CRYPTO_CONFIG')\n}\n\n/**\n * Encode BFV parameters for the smart contract\n * BFV (Brakerski-Fan-Vercauteren) is a type of fully homomorphic encryption\n */\nexport function encodeBfvParams(params: BfvParams): `0x${string}` {\n const { degree, plaintextModulus, moduli, error1Variance } = params\n\n if (error1Variance === undefined) {\n throw new SDKError(\n 'error1Variance is required in ProtocolParams. All BFV parameter sets must specify error1_variance.',\n 'MISSING_ERROR1_VARIANCE',\n )\n }\n\n return encodeAbiParameters(\n [\n {\n name: 'bfvParams',\n type: 'tuple',\n components: [\n { name: 'degree', type: 'uint256' },\n { name: 'plaintext_modulus', type: 'uint256' },\n { name: 'moduli', type: 'uint256[]' },\n { name: 'error1_variance', type: 'string' },\n ],\n },\n ],\n [\n {\n degree: BigInt(degree),\n plaintext_modulus: BigInt(plaintextModulus),\n moduli: [...moduli],\n error1_variance: error1Variance,\n },\n ],\n )\n}\n\n/**\n * Encode compute provider parameters for the smart contract'\n * If mock is true, the compute provider parameters will return 32 bytes of 0x00\n */\nexport function encodeComputeProviderParams(params: ComputeProviderParams, mock: boolean = false): `0x${string}` {\n if (mock) {\n return `0x${'00'.repeat(32)}` as `0x${string}`\n }\n\n const jsonString = JSON.stringify(params)\n const encoder = new TextEncoder()\n const bytes = encoder.encode(jsonString)\n\n return `0x${Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('')}`\n}\n\n/**\n * Encode custom parameters for the smart contract.\n */\nexport function encodeCustomParams(params: Record<string, unknown>): `0x${string}` {\n const jsonString = JSON.stringify(params)\n const encoder = new TextEncoder()\n const bytes = encoder.encode(jsonString)\n\n return `0x${Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('')}`\n}\n\n// inputWindow[0] is always larger than now and dkg deadline\nexport const inputWindowStartBuffer = 15n\n\n/**\n * Calculate start window for E3 request\n * @dev This function can be used for testing purposes, or for E3s which need to start as soon as possible.\n * @param publicClient - The public client to use\n * @param duration - The duration of the input window in seconds\n * @param startBuffer - Buffer in seconds added to current timestamp for input window start\n */\nexport async function calculateInputWindow(\n publicClient: PublicClient,\n duration: number = DEFAULT_E3_CONFIG.duration,\n startBuffer: bigint = inputWindowStartBuffer,\n): Promise<[bigint, bigint]> {\n const now = await getCurrentTimestamp(publicClient)\n return [BigInt(now) + startBuffer, BigInt(now) + startBuffer + BigInt(duration)]\n}\n\n/**\n * Decode plaintextOutput bytes to get the actual result number\n */\nexport function decodePlaintextOutput(plaintextOutput: string): number | null {\n try {\n // Remove '0x' prefix if present\n const hex = plaintextOutput.startsWith('0x') ? plaintextOutput.slice(2) : plaintextOutput\n\n // Convert hex to bytes\n const bytes = new Uint8Array(hex.match(/.{1,2}/g)?.map((byte) => parseInt(byte, 16)) || [])\n\n if (bytes.length < 8) {\n console.warn('Plaintext output too short for u64 decoding')\n return null\n }\n\n // Decode first u64 (8 bytes) as little-endian\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n const result = view.getBigUint64(0, true) // true for little-endian\n\n return Number(result)\n } catch (error) {\n console.error('Failed to decode plaintext output:', error)\n return null\n }\n}\n\n// Helper function to convert proof bytes to field elements\nexport function proofToFields(proof: Uint8Array): string[] {\n const fields: string[] = []\n for (let i = 0; i < proof.length; i += 32) {\n const chunk = proof.slice(i, i + 32)\n fields.push('0x' + Buffer.from(chunk).toString('hex'))\n }\n return fields\n}\n","// SPDX-License-Identifier: LGPL-3.0-only\n//\n// This file is provided WITHOUT ANY WARRANTY;\n// without even the implied warranty of MERCHANTABILITY\n// or FITNESS FOR A PARTICULAR PURPOSE.\n\nimport { SDKError } from '../utils'\n\nexport interface ContractAddresses {\n interfold: `0x${string}`\n ciphernodeRegistry: `0x${string}`\n feeToken: `0x${string}`\n}\n\n/** On-chain `IInterfold.CommitteeSize`: Minimum (N=3), Micro (N=9), Small (N=19). */\nexport enum CommitteeSize {\n Minimum = 0,\n Micro = 1,\n Small = 2,\n}\n\n/** Fail fast on out-of-range committee sizes before they hit the contract. */\nexport function validateCommitteeSize(value: number | CommitteeSize): CommitteeSize {\n if (!Number.isInteger(value) || value < CommitteeSize.Minimum || value > CommitteeSize.Small) {\n throw new SDKError(\n `Invalid committeeSize ${value}. Use CommitteeSize.Minimum (0), CommitteeSize.Micro (1), or CommitteeSize.Small (2).`,\n 'INVALID_COMMITTEE_SIZE',\n )\n }\n return value\n}\n\nexport enum ParamSet {\n Insecure512 = 0,\n Secure8192 = 1,\n}\n\nexport interface E3 {\n seed: bigint\n committeeSize: number\n requestBlock: bigint\n inputWindow: readonly [bigint, bigint]\n encryptionSchemeId: string\n e3Program: string\n paramSet: number\n decryptionVerifier: string\n committeePublicKey: string\n ciphertextOutput: string\n ciphertextCommitment: string\n plaintextOutput: string\n}\n\nexport interface RequestParams {\n gasLimit?: bigint\n}\n\nexport interface E3RequestParams extends RequestParams {\n committeeSize: number\n inputWindow: readonly [bigint, bigint]\n e3Program: `0x${string}`\n paramSet: number\n computeProviderParams: `0x${string}`\n customParams?: `0x${string}`\n /** Maximum fee token amount accepted. Defaults to a fresh quote. */\n maxFee?: bigint\n}\n\nexport enum E3Stage {\n None,\n Requested,\n CommitteeFinalized,\n KeyPublished,\n CiphertextReady,\n Complete,\n Failed,\n}\n\nexport enum FailureReason {\n None,\n CommitteeFormationTimeout,\n InsufficientCommitteeMembers,\n DKGTimeout,\n DKGInvalidShares,\n NoInputsReceived,\n ComputeTimeout,\n ComputeProviderExpired,\n ComputeProviderFailed,\n RequesterCancelled,\n DecryptionTimeout,\n DecryptionInvalidShares,\n VerificationFailed,\n}\n"],"mappings":"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","names":["E3Stage","FailureReason"]}
|