@sip-protocol/sdk 0.7.2 → 0.7.4
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/LICENSE +21 -0
- package/README.md +267 -0
- package/dist/{TransportWebUSB-TQ7WZ4LE.mjs → TransportWebUSB-YQMAGJAJ.mjs} +12 -9
- package/dist/browser.d.mts +10 -4
- package/dist/browser.d.ts +10 -4
- package/dist/browser.js +48874 -18336
- package/dist/browser.mjs +674 -48
- package/dist/chunk-4GRJ5MAW.mjs +152 -0
- package/dist/chunk-5D7A3L3W.mjs +717 -0
- package/dist/chunk-64AYA5F5.mjs +7834 -0
- package/dist/chunk-GMDGB22A.mjs +379 -0
- package/dist/chunk-I534WKN7.mjs +328 -0
- package/dist/chunk-IBZVA5Y7.mjs +1003 -0
- package/dist/chunk-PRRZAWJE.mjs +223 -0
- package/dist/{chunk-UJCSKKID.mjs → chunk-XGB3TDIC.mjs} +13 -1
- package/dist/chunk-YWGJ77A2.mjs +33806 -0
- package/dist/{chunk-6WGN57S2.mjs → chunk-Z3K7W5S3.mjs} +48 -0
- package/dist/constants-LHAAUC2T.mjs +51 -0
- package/dist/dist-2OGQ7FED.mjs +3957 -0
- package/dist/dist-IFHPYLDX.mjs +254 -0
- package/dist/fulfillment_proof-ANHVPKTB.mjs +21 -0
- package/dist/funding_proof-ICFZ5LHY.mjs +21 -0
- package/dist/index-DXh2IGkz.d.ts +24681 -0
- package/dist/index-DeE1ZzA4.d.mts +24681 -0
- package/dist/index.d.mts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.js +48676 -17318
- package/dist/index.mjs +583 -19
- package/dist/interface-Bf7w1PLW.d.mts +679 -0
- package/dist/interface-Bf7w1PLW.d.ts +679 -0
- package/dist/{noir-DKfEzWy9.d.mts → noir-kzbLVTei.d.mts} +31 -21
- package/dist/{noir-DKfEzWy9.d.ts → noir-kzbLVTei.d.ts} +31 -21
- package/dist/proofs/halo2.d.mts +151 -0
- package/dist/proofs/halo2.d.ts +151 -0
- package/dist/proofs/halo2.js +350 -0
- package/dist/proofs/halo2.mjs +11 -0
- package/dist/proofs/kimchi.d.mts +160 -0
- package/dist/proofs/kimchi.d.ts +160 -0
- package/dist/proofs/kimchi.js +431 -0
- package/dist/proofs/kimchi.mjs +13 -0
- package/dist/proofs/noir.d.mts +1 -1
- package/dist/proofs/noir.d.ts +1 -1
- package/dist/proofs/noir.js +74 -18
- package/dist/proofs/noir.mjs +84 -24
- package/dist/solana-U3MEGU7W.mjs +280 -0
- package/dist/validity_proof-3POXLPNY.mjs +21 -0
- package/package.json +54 -21
- package/src/adapters/index.ts +41 -0
- package/src/adapters/jupiter.ts +571 -0
- package/src/adapters/near-intents.ts +135 -0
- package/src/advisor/advisor.ts +653 -0
- package/src/advisor/index.ts +54 -0
- package/src/advisor/tools.ts +303 -0
- package/src/advisor/types.ts +164 -0
- package/src/chains/ethereum/announcement.ts +536 -0
- package/src/chains/ethereum/bnb-optimizations.ts +474 -0
- package/src/chains/ethereum/commitment.ts +522 -0
- package/src/chains/ethereum/constants.ts +462 -0
- package/src/chains/ethereum/deployment.ts +596 -0
- package/src/chains/ethereum/gas-estimation.ts +538 -0
- package/src/chains/ethereum/index.ts +268 -0
- package/src/chains/ethereum/optimizations.ts +614 -0
- package/src/chains/ethereum/privacy-adapter.ts +855 -0
- package/src/chains/ethereum/registry.ts +584 -0
- package/src/chains/ethereum/rpc.ts +905 -0
- package/src/chains/ethereum/stealth.ts +491 -0
- package/src/chains/ethereum/token.ts +790 -0
- package/src/chains/ethereum/transfer.ts +637 -0
- package/src/chains/ethereum/types.ts +456 -0
- package/src/chains/ethereum/viewing-key.ts +455 -0
- package/src/chains/near/commitment.ts +608 -0
- package/src/chains/near/constants.ts +284 -0
- package/src/chains/near/function-call.ts +871 -0
- package/src/chains/near/history.ts +654 -0
- package/src/chains/near/implicit-account.ts +840 -0
- package/src/chains/near/index.ts +393 -0
- package/src/chains/near/native-transfer.ts +658 -0
- package/src/chains/near/nep141.ts +775 -0
- package/src/chains/near/privacy-adapter.ts +889 -0
- package/src/chains/near/resolver.ts +971 -0
- package/src/chains/near/rpc.ts +1016 -0
- package/src/chains/near/stealth.ts +419 -0
- package/src/chains/near/types.ts +317 -0
- package/src/chains/near/viewing-key.ts +876 -0
- package/src/chains/solana/anchor-transfer.ts +386 -0
- package/src/chains/solana/commitment.ts +577 -0
- package/src/chains/solana/constants.ts +126 -12
- package/src/chains/solana/ephemeral-keys.ts +543 -0
- package/src/chains/solana/index.ts +276 -1
- package/src/chains/solana/key-derivation.ts +418 -0
- package/src/chains/solana/kit-compat.ts +334 -0
- package/src/chains/solana/optimizations.ts +560 -0
- package/src/chains/solana/privacy-adapter.ts +605 -0
- package/src/chains/solana/providers/generic.ts +201 -0
- package/src/chains/solana/providers/helius-enhanced-types.ts +336 -0
- package/src/chains/solana/providers/helius-enhanced.ts +623 -0
- package/src/chains/solana/providers/helius.ts +402 -0
- package/src/chains/solana/providers/index.ts +85 -0
- package/src/chains/solana/providers/interface.ts +221 -0
- package/src/chains/solana/providers/quicknode.ts +409 -0
- package/src/chains/solana/providers/triton.ts +426 -0
- package/src/chains/solana/providers/webhook.ts +790 -0
- package/src/chains/solana/rpc-client.ts +1150 -0
- package/src/chains/solana/scan.ts +170 -73
- package/src/chains/solana/sol-transfer.ts +732 -0
- package/src/chains/solana/spl-transfer.ts +886 -0
- package/src/chains/solana/stealth-scanner.ts +703 -0
- package/src/chains/solana/sunspot-verifier.ts +453 -0
- package/src/chains/solana/transaction-builder.ts +755 -0
- package/src/chains/solana/transfer.ts +74 -5
- package/src/chains/solana/types.ts +77 -7
- package/src/chains/solana/utils.ts +110 -0
- package/src/chains/solana/viewing-key.ts +807 -0
- package/src/compliance/fireblocks.ts +921 -0
- package/src/compliance/index.ts +37 -0
- package/src/compliance/range-sas.ts +956 -0
- package/src/config/endpoints.ts +100 -0
- package/src/crypto.ts +11 -8
- package/src/errors.ts +82 -0
- package/src/evm/erc4337-relayer.ts +830 -0
- package/src/evm/index.ts +47 -0
- package/src/fees/calculator.ts +396 -0
- package/src/fees/index.ts +87 -0
- package/src/fees/near-contract.ts +429 -0
- package/src/fees/types.ts +268 -0
- package/src/index.ts +785 -1
- package/src/intent.ts +6 -3
- package/src/logger.ts +324 -0
- package/src/network/index.ts +80 -0
- package/src/network/proxy.ts +691 -0
- package/src/optimizations/index.ts +541 -0
- package/src/oracle/types.ts +1 -0
- package/src/privacy-backends/arcium-types.ts +727 -0
- package/src/privacy-backends/arcium.ts +719 -0
- package/src/privacy-backends/combined-privacy.ts +866 -0
- package/src/privacy-backends/cspl-token.ts +595 -0
- package/src/privacy-backends/cspl-types.ts +512 -0
- package/src/privacy-backends/cspl.ts +907 -0
- package/src/privacy-backends/health.ts +488 -0
- package/src/privacy-backends/inco-types.ts +323 -0
- package/src/privacy-backends/inco.ts +616 -0
- package/src/privacy-backends/index.ts +336 -0
- package/src/privacy-backends/interface.ts +906 -0
- package/src/privacy-backends/lru-cache.ts +343 -0
- package/src/privacy-backends/magicblock.ts +458 -0
- package/src/privacy-backends/mock.ts +258 -0
- package/src/privacy-backends/privacycash-types.ts +278 -0
- package/src/privacy-backends/privacycash.ts +456 -0
- package/src/privacy-backends/private-swap.ts +570 -0
- package/src/privacy-backends/rate-limiter.ts +683 -0
- package/src/privacy-backends/registry.ts +690 -0
- package/src/privacy-backends/router.ts +626 -0
- package/src/privacy-backends/shadowwire.ts +449 -0
- package/src/privacy-backends/sip-native.ts +256 -0
- package/src/privacy-logger.ts +191 -0
- package/src/production-safety.ts +373 -0
- package/src/proofs/aggregator.ts +1029 -0
- package/src/proofs/browser-composer.ts +1150 -0
- package/src/proofs/browser.ts +113 -25
- package/src/proofs/cache/index.ts +127 -0
- package/src/proofs/cache/interface.ts +545 -0
- package/src/proofs/cache/key-generator.ts +188 -0
- package/src/proofs/cache/lru-cache.ts +481 -0
- package/src/proofs/cache/multi-tier-cache.ts +575 -0
- package/src/proofs/cache/persistent-cache.ts +788 -0
- package/src/proofs/compliance-proof.ts +872 -0
- package/src/proofs/composer/base.ts +923 -0
- package/src/proofs/composer/index.ts +25 -0
- package/src/proofs/composer/interface.ts +518 -0
- package/src/proofs/composer/types.ts +383 -0
- package/src/proofs/converters/halo2.ts +452 -0
- package/src/proofs/converters/index.ts +208 -0
- package/src/proofs/converters/interface.ts +363 -0
- package/src/proofs/converters/kimchi.ts +462 -0
- package/src/proofs/converters/noir.ts +451 -0
- package/src/proofs/fallback.ts +888 -0
- package/src/proofs/halo2.ts +42 -0
- package/src/proofs/index.ts +471 -0
- package/src/proofs/interface.ts +13 -0
- package/src/proofs/kimchi.ts +42 -0
- package/src/proofs/lazy.ts +1004 -0
- package/src/proofs/mock.ts +25 -1
- package/src/proofs/noir.ts +111 -30
- package/src/proofs/orchestrator.ts +960 -0
- package/src/proofs/parallel/concurrency.ts +297 -0
- package/src/proofs/parallel/dependency-graph.ts +602 -0
- package/src/proofs/parallel/executor.ts +420 -0
- package/src/proofs/parallel/index.ts +131 -0
- package/src/proofs/parallel/interface.ts +685 -0
- package/src/proofs/parallel/worker-pool.ts +644 -0
- package/src/proofs/providers/halo2.ts +560 -0
- package/src/proofs/providers/index.ts +34 -0
- package/src/proofs/providers/kimchi.ts +641 -0
- package/src/proofs/validator.ts +881 -0
- package/src/proofs/verifier.ts +867 -0
- package/src/quantum/index.ts +112 -0
- package/src/quantum/winternitz-vault.ts +639 -0
- package/src/quantum/wots.ts +611 -0
- package/src/settlement/backends/direct-chain.ts +1 -0
- package/src/settlement/index.ts +9 -0
- package/src/settlement/router.ts +732 -46
- package/src/solana/index.ts +72 -0
- package/src/solana/jito-relayer.ts +687 -0
- package/src/solana/noir-verifier-types.ts +430 -0
- package/src/solana/noir-verifier.ts +816 -0
- package/src/stealth/address-derivation.ts +193 -0
- package/src/stealth/ed25519.ts +431 -0
- package/src/stealth/index.ts +233 -0
- package/src/stealth/meta-address.ts +221 -0
- package/src/stealth/secp256k1.ts +368 -0
- package/src/stealth/utils.ts +194 -0
- package/src/stealth.ts +50 -1504
- package/src/surveillance/algorithms/address-reuse.ts +143 -0
- package/src/surveillance/algorithms/cluster.ts +247 -0
- package/src/surveillance/algorithms/exchange.ts +295 -0
- package/src/surveillance/algorithms/temporal.ts +337 -0
- package/src/surveillance/analyzer.ts +442 -0
- package/src/surveillance/index.ts +64 -0
- package/src/surveillance/scoring.ts +372 -0
- package/src/surveillance/types.ts +264 -0
- package/src/sync/index.ts +106 -0
- package/src/sync/manager.ts +504 -0
- package/src/sync/mock-provider.ts +318 -0
- package/src/sync/oblivious.ts +625 -0
- package/src/tokens/index.ts +15 -0
- package/src/tokens/registry.ts +301 -0
- package/src/utils/deprecation.ts +94 -0
- package/src/utils/index.ts +9 -0
- package/src/wallet/ethereum/index.ts +68 -0
- package/src/wallet/ethereum/metamask-privacy.ts +420 -0
- package/src/wallet/ethereum/multi-wallet.ts +646 -0
- package/src/wallet/ethereum/privacy-adapter.ts +700 -0
- package/src/wallet/ethereum/types.ts +3 -1
- package/src/wallet/ethereum/walletconnect-adapter.ts +675 -0
- package/src/wallet/hardware/index.ts +10 -0
- package/src/wallet/hardware/ledger-privacy.ts +414 -0
- package/src/wallet/index.ts +71 -0
- package/src/wallet/near/adapter.ts +626 -0
- package/src/wallet/near/index.ts +86 -0
- package/src/wallet/near/meteor-wallet.ts +1153 -0
- package/src/wallet/near/my-near-wallet.ts +790 -0
- package/src/wallet/near/wallet-selector.ts +702 -0
- package/src/wallet/solana/adapter.ts +6 -4
- package/src/wallet/solana/index.ts +13 -0
- package/src/wallet/solana/privacy-adapter.ts +567 -0
- package/src/wallet/sui/types.ts +6 -4
- package/src/zcash/rpc-client.ts +13 -6
- package/dist/chunk-3INS3PR5.mjs +0 -884
- package/dist/chunk-3OVABDRH.mjs +0 -17096
- package/dist/chunk-DLDWZFYC.mjs +0 -1495
- package/dist/chunk-E6SZWREQ.mjs +0 -57
- package/dist/chunk-G33LB27A.mjs +0 -16166
- package/dist/chunk-HGU6HZRC.mjs +0 -231
- package/dist/chunk-L2K34JCU.mjs +0 -1496
- package/dist/chunk-SN4ZDTVW.mjs +0 -16166
- package/dist/constants-VOI7BSLK.mjs +0 -27
- package/dist/index-BYZbDjal.d.ts +0 -11390
- package/dist/index-CHB3KuOB.d.mts +0 -11859
- package/dist/index-CzWPI6Le.d.ts +0 -11859
- package/dist/index-xbWjohNq.d.mts +0 -11390
- package/dist/solana-5EMCTPTS.mjs +0 -46
- package/dist/solana-Q4NAVBTS.mjs +0 -46
|
@@ -0,0 +1,719 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Arcium Privacy Backend
|
|
3
|
+
*
|
|
4
|
+
* Implements the PrivacyBackend interface using Arcium MPC (Multi-Party Computation).
|
|
5
|
+
* Arcium provides compute privacy - hiding what happens inside smart contracts.
|
|
6
|
+
*
|
|
7
|
+
* ## Key Characteristics
|
|
8
|
+
*
|
|
9
|
+
* - **MPC Computation**: Encrypted data processed by multiple nodes
|
|
10
|
+
* - **Compute Privacy**: Hides contract execution logic, not transaction details
|
|
11
|
+
* - **Circuit-Based**: Computations defined by pre-uploaded circuits
|
|
12
|
+
* - **Cluster Coordination**: MPC nodes coordinate to produce results
|
|
13
|
+
*
|
|
14
|
+
* ## Trade-offs vs Transaction Backends
|
|
15
|
+
*
|
|
16
|
+
* | Feature | Arcium (Compute) | SIP Native (Transaction) |
|
|
17
|
+
* |---------|------------------|--------------------------|
|
|
18
|
+
* | Hides sender | ❌ | ✅ Stealth addresses |
|
|
19
|
+
* | Hides amount | ❌ (in tx) | ✅ Pedersen |
|
|
20
|
+
* | Hides computation | ✅ MPC | ❌ |
|
|
21
|
+
* | Setup required | ✅ Circuit upload | ❌ |
|
|
22
|
+
* | Latency | Slow (MPC coord) | Fast |
|
|
23
|
+
*
|
|
24
|
+
* ## Use Cases
|
|
25
|
+
*
|
|
26
|
+
* - Private DEX swap logic (hide slippage, routing)
|
|
27
|
+
* - Private auctions (hide bid amounts during bidding)
|
|
28
|
+
* - Private lending (hide collateral ratios)
|
|
29
|
+
* - Private governance (hide vote weights)
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* import { ArciumBackend, PrivacyBackendRegistry } from '@sip-protocol/sdk'
|
|
34
|
+
*
|
|
35
|
+
* const backend = new ArciumBackend({
|
|
36
|
+
* rpcUrl: 'https://api.devnet.solana.com',
|
|
37
|
+
* network: 'devnet',
|
|
38
|
+
* })
|
|
39
|
+
*
|
|
40
|
+
* const registry = new PrivacyBackendRegistry()
|
|
41
|
+
* registry.register(backend, { priority: 70 })
|
|
42
|
+
*
|
|
43
|
+
* // Execute private computation
|
|
44
|
+
* const result = await backend.executeComputation({
|
|
45
|
+
* chain: 'solana',
|
|
46
|
+
* circuitId: 'private-swap',
|
|
47
|
+
* encryptedInputs: [encryptedAmount, encryptedPrice],
|
|
48
|
+
* cluster: 'devnet-cluster-1',
|
|
49
|
+
* })
|
|
50
|
+
*
|
|
51
|
+
* if (result.success) {
|
|
52
|
+
* console.log(`Computation ${result.computationId} completed`)
|
|
53
|
+
* }
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* @see https://docs.arcium.com/developers
|
|
57
|
+
*/
|
|
58
|
+
|
|
59
|
+
import type {
|
|
60
|
+
PrivacyBackend,
|
|
61
|
+
BackendType,
|
|
62
|
+
BackendCapabilities,
|
|
63
|
+
TransferParams,
|
|
64
|
+
TransactionResult,
|
|
65
|
+
ComputationParams,
|
|
66
|
+
ComputationResult,
|
|
67
|
+
AvailabilityResult,
|
|
68
|
+
BackendParams,
|
|
69
|
+
ComputationStatus,
|
|
70
|
+
CipherType,
|
|
71
|
+
} from './interface'
|
|
72
|
+
|
|
73
|
+
import {
|
|
74
|
+
isComputationParams,
|
|
75
|
+
withTimeout,
|
|
76
|
+
ComputationTimeoutError,
|
|
77
|
+
} from './interface'
|
|
78
|
+
|
|
79
|
+
import {
|
|
80
|
+
ARCIUM_CLUSTERS,
|
|
81
|
+
DEFAULT_COMPUTATION_TIMEOUT_MS,
|
|
82
|
+
ESTIMATED_COMPUTATION_TIME_MS,
|
|
83
|
+
BASE_COMPUTATION_COST_LAMPORTS,
|
|
84
|
+
COST_PER_ENCRYPTED_INPUT_LAMPORTS,
|
|
85
|
+
COST_PER_INPUT_KB_LAMPORTS,
|
|
86
|
+
BYTES_PER_KB,
|
|
87
|
+
DEFAULT_MAX_ENCRYPTED_INPUTS,
|
|
88
|
+
DEFAULT_MAX_INPUT_SIZE_BYTES,
|
|
89
|
+
DEFAULT_MAX_TOTAL_INPUT_SIZE_BYTES,
|
|
90
|
+
DEFAULT_MAX_COMPUTATION_COST_LAMPORTS,
|
|
91
|
+
ArciumError,
|
|
92
|
+
// Environment variable configuration
|
|
93
|
+
resolveRpcUrl,
|
|
94
|
+
resolveNetwork,
|
|
95
|
+
resolveTimeout,
|
|
96
|
+
resolveCluster,
|
|
97
|
+
type ArciumNetwork,
|
|
98
|
+
type IArciumClient,
|
|
99
|
+
type ComputationInfo,
|
|
100
|
+
type ArciumLimitsConfig,
|
|
101
|
+
type ArciumLimitsResolved,
|
|
102
|
+
} from './arcium-types'
|
|
103
|
+
|
|
104
|
+
import { createPrivacyLogger } from '../privacy-logger'
|
|
105
|
+
|
|
106
|
+
const arciumLogger = createPrivacyLogger('Arcium')
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Configuration options for Arcium backend
|
|
110
|
+
*/
|
|
111
|
+
export interface ArciumBackendConfig {
|
|
112
|
+
/** Solana RPC endpoint URL */
|
|
113
|
+
rpcUrl?: string
|
|
114
|
+
/** Network type */
|
|
115
|
+
network?: ArciumNetwork
|
|
116
|
+
/** Default MPC cluster to use */
|
|
117
|
+
cluster?: string
|
|
118
|
+
/** Default cipher for encryption */
|
|
119
|
+
defaultCipher?: CipherType
|
|
120
|
+
/** Computation timeout in milliseconds */
|
|
121
|
+
timeout?: number
|
|
122
|
+
/** Custom SDK client (for testing) */
|
|
123
|
+
client?: IArciumClient
|
|
124
|
+
/** Enable debug mode (includes stack traces in error responses) */
|
|
125
|
+
debug?: boolean
|
|
126
|
+
/** Configurable validation limits */
|
|
127
|
+
limits?: ArciumLimitsConfig
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Arcium capabilities (static)
|
|
132
|
+
*/
|
|
133
|
+
const ARCIUM_CAPABILITIES: BackendCapabilities = {
|
|
134
|
+
hiddenAmount: false, // Arcium hides compute, not amounts
|
|
135
|
+
hiddenSender: false, // Arcium doesn't hide transaction sender
|
|
136
|
+
hiddenRecipient: false, // Arcium doesn't hide transaction recipient
|
|
137
|
+
hiddenCompute: true, // PRIMARY PURPOSE: Hide computation logic
|
|
138
|
+
complianceSupport: false, // No viewing keys for MPC
|
|
139
|
+
anonymitySet: undefined, // Not applicable for MPC
|
|
140
|
+
setupRequired: true, // Need circuit upload before use
|
|
141
|
+
latencyEstimate: 'slow', // MPC coordination takes time
|
|
142
|
+
supportedTokens: 'all', // Can work with any token in compute
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Arcium MPC Compute Privacy Backend
|
|
147
|
+
*
|
|
148
|
+
* Provides compute privacy through Multi-Party Computation.
|
|
149
|
+
* Use this backend to hide smart contract execution logic.
|
|
150
|
+
*/
|
|
151
|
+
export class ArciumBackend implements PrivacyBackend {
|
|
152
|
+
readonly name = 'arcium'
|
|
153
|
+
readonly type: BackendType = 'compute'
|
|
154
|
+
readonly chains: string[] = ['solana']
|
|
155
|
+
|
|
156
|
+
private config: Required<Omit<ArciumBackendConfig, 'client' | 'limits'>> & {
|
|
157
|
+
client?: IArciumClient
|
|
158
|
+
}
|
|
159
|
+
private computationCache: Map<string, ComputationInfo> = new Map()
|
|
160
|
+
private limits: ArciumLimitsResolved
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Create a new Arcium backend
|
|
164
|
+
*
|
|
165
|
+
* Configuration is resolved with the following priority:
|
|
166
|
+
* 1. Environment variables (highest priority)
|
|
167
|
+
* 2. Config parameters
|
|
168
|
+
* 3. Default values
|
|
169
|
+
*
|
|
170
|
+
* @param config - Backend configuration
|
|
171
|
+
* @throws {ArciumError} If network is invalid
|
|
172
|
+
* @throws {Error} If limits are invalid (non-positive values)
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```bash
|
|
176
|
+
* # Configure via environment variables
|
|
177
|
+
* export ARCIUM_RPC_URL_DEVNET=https://my-rpc.example.com
|
|
178
|
+
* export ARCIUM_NETWORK=devnet
|
|
179
|
+
* export ARCIUM_TIMEOUT_MS=600000
|
|
180
|
+
* ```
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```typescript
|
|
184
|
+
* // Or configure via constructor
|
|
185
|
+
* const backend = new ArciumBackend({
|
|
186
|
+
* rpcUrl: 'https://my-rpc.example.com',
|
|
187
|
+
* network: 'devnet',
|
|
188
|
+
* timeout: 600_000,
|
|
189
|
+
* })
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
192
|
+
constructor(config: ArciumBackendConfig = {}) {
|
|
193
|
+
// Resolve network first (needed for other resolvers)
|
|
194
|
+
const network = resolveNetwork(config.network)
|
|
195
|
+
|
|
196
|
+
// Validate network parameter if explicitly provided
|
|
197
|
+
if (config.network !== undefined) {
|
|
198
|
+
const validNetworks: ArciumNetwork[] = ['devnet', 'testnet', 'mainnet-beta']
|
|
199
|
+
if (!validNetworks.includes(config.network)) {
|
|
200
|
+
throw new ArciumError(
|
|
201
|
+
`Invalid Arcium network '${config.network}'. Valid networks: ${validNetworks.join(', ')}`,
|
|
202
|
+
'ARCIUM_INVALID_NETWORK',
|
|
203
|
+
{
|
|
204
|
+
context: {
|
|
205
|
+
receivedNetwork: config.network,
|
|
206
|
+
validNetworks,
|
|
207
|
+
},
|
|
208
|
+
}
|
|
209
|
+
)
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
this.config = {
|
|
214
|
+
rpcUrl: resolveRpcUrl(network, config.rpcUrl),
|
|
215
|
+
network,
|
|
216
|
+
cluster: resolveCluster(network, config.cluster),
|
|
217
|
+
defaultCipher: config.defaultCipher ?? 'aes256',
|
|
218
|
+
timeout: resolveTimeout(config.timeout),
|
|
219
|
+
client: config.client,
|
|
220
|
+
debug: config.debug ?? false,
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Resolve limits with defaults
|
|
224
|
+
this.limits = {
|
|
225
|
+
maxEncryptedInputs:
|
|
226
|
+
config.limits?.maxEncryptedInputs ?? DEFAULT_MAX_ENCRYPTED_INPUTS,
|
|
227
|
+
maxInputSizeBytes:
|
|
228
|
+
config.limits?.maxInputSizeBytes ?? DEFAULT_MAX_INPUT_SIZE_BYTES,
|
|
229
|
+
maxTotalInputSizeBytes:
|
|
230
|
+
config.limits?.maxTotalInputSizeBytes ?? DEFAULT_MAX_TOTAL_INPUT_SIZE_BYTES,
|
|
231
|
+
maxComputationCostLamports:
|
|
232
|
+
config.limits?.maxComputationCostLamports ?? DEFAULT_MAX_COMPUTATION_COST_LAMPORTS,
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Validate configured limits are positive
|
|
236
|
+
if (this.limits.maxEncryptedInputs <= 0) {
|
|
237
|
+
throw new Error('maxEncryptedInputs must be positive')
|
|
238
|
+
}
|
|
239
|
+
if (this.limits.maxInputSizeBytes <= 0) {
|
|
240
|
+
throw new Error('maxInputSizeBytes must be positive')
|
|
241
|
+
}
|
|
242
|
+
if (this.limits.maxTotalInputSizeBytes <= 0) {
|
|
243
|
+
throw new Error('maxTotalInputSizeBytes must be positive')
|
|
244
|
+
}
|
|
245
|
+
if (this.limits.maxComputationCostLamports <= BigInt(0)) {
|
|
246
|
+
throw new Error('maxComputationCostLamports must be positive')
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Get the current resolved limits configuration
|
|
252
|
+
* @returns A copy of the resolved limits
|
|
253
|
+
*/
|
|
254
|
+
getLimits(): ArciumLimitsResolved {
|
|
255
|
+
return { ...this.limits }
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Check if backend is available for given parameters
|
|
260
|
+
*/
|
|
261
|
+
async checkAvailability(params: BackendParams): Promise<AvailabilityResult> {
|
|
262
|
+
// Must be computation params for Arcium
|
|
263
|
+
if (!isComputationParams(params)) {
|
|
264
|
+
return {
|
|
265
|
+
available: false,
|
|
266
|
+
reason:
|
|
267
|
+
'Arcium is a compute backend. Use ComputationParams with circuitId and encryptedInputs.',
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return this.checkComputeAvailability(params)
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Check availability for computation params
|
|
276
|
+
*/
|
|
277
|
+
/**
|
|
278
|
+
* Format bytes into human-readable string
|
|
279
|
+
*/
|
|
280
|
+
private formatBytes(bytes: number): string {
|
|
281
|
+
if (bytes >= 1_048_576) {
|
|
282
|
+
return `${Math.round(bytes / 1_048_576)} MB`
|
|
283
|
+
}
|
|
284
|
+
if (bytes >= 1024) {
|
|
285
|
+
return `${Math.round(bytes / 1024)} KB`
|
|
286
|
+
}
|
|
287
|
+
return `${bytes} bytes`
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
private async checkComputeAvailability(
|
|
291
|
+
params: ComputationParams
|
|
292
|
+
): Promise<AvailabilityResult> {
|
|
293
|
+
// Validate chain
|
|
294
|
+
if (params.chain !== 'solana') {
|
|
295
|
+
return {
|
|
296
|
+
available: false,
|
|
297
|
+
reason: `Arcium only supports Solana, not '${params.chain}'`,
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Validate circuitId
|
|
302
|
+
if (!params.circuitId || params.circuitId.trim() === '') {
|
|
303
|
+
return {
|
|
304
|
+
available: false,
|
|
305
|
+
reason: 'circuitId is required for Arcium computations',
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Validate encrypted inputs
|
|
310
|
+
if (!params.encryptedInputs || params.encryptedInputs.length === 0) {
|
|
311
|
+
return {
|
|
312
|
+
available: false,
|
|
313
|
+
reason: 'encryptedInputs array is required and must not be empty',
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Validate number of inputs doesn't exceed maximum
|
|
318
|
+
if (params.encryptedInputs.length > this.limits.maxEncryptedInputs) {
|
|
319
|
+
arciumLogger.warn('Validation failed: too many inputs', {
|
|
320
|
+
amount: params.encryptedInputs.length,
|
|
321
|
+
})
|
|
322
|
+
return {
|
|
323
|
+
available: false,
|
|
324
|
+
reason: `Too many encrypted inputs: ${params.encryptedInputs.length} exceeds maximum of ${this.limits.maxEncryptedInputs}`,
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Validate each input is a valid Uint8Array with size bounds
|
|
329
|
+
let totalInputSize = 0
|
|
330
|
+
for (let i = 0; i < params.encryptedInputs.length; i++) {
|
|
331
|
+
const input = params.encryptedInputs[i]
|
|
332
|
+
if (!(input instanceof Uint8Array) || input.length === 0) {
|
|
333
|
+
return {
|
|
334
|
+
available: false,
|
|
335
|
+
reason: `encryptedInputs[${i}] must be a non-empty Uint8Array`,
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
if (input.length > this.limits.maxInputSizeBytes) {
|
|
339
|
+
arciumLogger.warn('Validation failed: input too large', {
|
|
340
|
+
amount: input.length,
|
|
341
|
+
})
|
|
342
|
+
return {
|
|
343
|
+
available: false,
|
|
344
|
+
reason: `encryptedInputs[${i}] size ${input.length} bytes exceeds maximum of ${this.formatBytes(this.limits.maxInputSizeBytes)}`,
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
totalInputSize += input.length
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Validate total input size
|
|
351
|
+
if (totalInputSize > this.limits.maxTotalInputSizeBytes) {
|
|
352
|
+
arciumLogger.warn('Validation failed: total input size exceeded', {
|
|
353
|
+
amount: totalInputSize,
|
|
354
|
+
})
|
|
355
|
+
return {
|
|
356
|
+
available: false,
|
|
357
|
+
reason: `Total input size ${this.formatBytes(totalInputSize)} exceeds maximum of ${this.formatBytes(this.limits.maxTotalInputSizeBytes)}`,
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Validate cipher type if provided
|
|
362
|
+
if (params.cipher) {
|
|
363
|
+
const validCiphers: CipherType[] = ['aes128', 'aes192', 'aes256', 'rescue']
|
|
364
|
+
if (!validCiphers.includes(params.cipher)) {
|
|
365
|
+
return {
|
|
366
|
+
available: false,
|
|
367
|
+
reason: `Invalid cipher '${params.cipher}'. Supported: ${validCiphers.join(', ')}`,
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// In production, would check:
|
|
373
|
+
// - Circuit exists and is valid
|
|
374
|
+
// - Cluster is available
|
|
375
|
+
// - User has permissions
|
|
376
|
+
|
|
377
|
+
return {
|
|
378
|
+
available: true,
|
|
379
|
+
estimatedCost: this.estimateComputeCost(params),
|
|
380
|
+
estimatedTime: ESTIMATED_COMPUTATION_TIME_MS,
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Get backend capabilities
|
|
386
|
+
*/
|
|
387
|
+
getCapabilities(): BackendCapabilities {
|
|
388
|
+
return { ...ARCIUM_CAPABILITIES }
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Execute a privacy-preserving transfer
|
|
393
|
+
*
|
|
394
|
+
* Arcium is a compute backend - this method returns an error
|
|
395
|
+
* directing users to use executeComputation() instead.
|
|
396
|
+
*/
|
|
397
|
+
async execute(_params: TransferParams): Promise<TransactionResult> {
|
|
398
|
+
return {
|
|
399
|
+
success: false,
|
|
400
|
+
error:
|
|
401
|
+
'Arcium is a compute privacy backend. ' +
|
|
402
|
+
'Use executeComputation() for MPC operations. ' +
|
|
403
|
+
'For transaction privacy, use SIPNativeBackend or PrivacyCashBackend.',
|
|
404
|
+
backend: this.name,
|
|
405
|
+
metadata: {
|
|
406
|
+
hint: 'executeComputation',
|
|
407
|
+
paramsType: 'ComputationParams',
|
|
408
|
+
},
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Execute a privacy-preserving computation via MPC
|
|
414
|
+
*
|
|
415
|
+
* This submits encrypted data to the Arcium MPC network for processing.
|
|
416
|
+
* The computation is defined by a pre-uploaded circuit.
|
|
417
|
+
*
|
|
418
|
+
* @param params - Computation parameters
|
|
419
|
+
* @returns Computation result with ID for tracking
|
|
420
|
+
*/
|
|
421
|
+
async executeComputation(
|
|
422
|
+
params: ComputationParams
|
|
423
|
+
): Promise<ComputationResult> {
|
|
424
|
+
// Validate availability first
|
|
425
|
+
const availability = await this.checkComputeAvailability(params)
|
|
426
|
+
if (!availability.available) {
|
|
427
|
+
return {
|
|
428
|
+
success: false,
|
|
429
|
+
error: availability.reason,
|
|
430
|
+
backend: this.name,
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
try {
|
|
435
|
+
const cluster = params.cluster ?? this.config.cluster
|
|
436
|
+
const cipher = params.cipher ?? this.config.defaultCipher
|
|
437
|
+
|
|
438
|
+
// In a real implementation with the SDK:
|
|
439
|
+
// 1. const client = await this.getClient()
|
|
440
|
+
// 2. const computationId = await client.submitComputation({
|
|
441
|
+
// circuitId: params.circuitId,
|
|
442
|
+
// encryptedInputs: params.encryptedInputs,
|
|
443
|
+
// cluster,
|
|
444
|
+
// callback: params.callbackAddress,
|
|
445
|
+
// })
|
|
446
|
+
// 3. Optionally await finalization
|
|
447
|
+
|
|
448
|
+
// Simulated result (SDK integration pending)
|
|
449
|
+
const simulatedComputationId = this.generateComputationId()
|
|
450
|
+
|
|
451
|
+
// Cache the computation info
|
|
452
|
+
const info: ComputationInfo = {
|
|
453
|
+
id: simulatedComputationId,
|
|
454
|
+
status: 'submitted',
|
|
455
|
+
circuitId: params.circuitId,
|
|
456
|
+
cluster,
|
|
457
|
+
submittedAt: Date.now(),
|
|
458
|
+
}
|
|
459
|
+
this.computationCache.set(simulatedComputationId, info)
|
|
460
|
+
|
|
461
|
+
return {
|
|
462
|
+
success: true,
|
|
463
|
+
computationId: simulatedComputationId,
|
|
464
|
+
backend: this.name,
|
|
465
|
+
status: 'submitted',
|
|
466
|
+
metadata: {
|
|
467
|
+
circuitId: params.circuitId,
|
|
468
|
+
cluster,
|
|
469
|
+
cipher,
|
|
470
|
+
inputCount: params.encryptedInputs.length,
|
|
471
|
+
network: this.config.network,
|
|
472
|
+
submittedAt: Date.now(),
|
|
473
|
+
warning: 'Simulated result - SDK integration pending',
|
|
474
|
+
},
|
|
475
|
+
}
|
|
476
|
+
} catch (error) {
|
|
477
|
+
return {
|
|
478
|
+
success: false,
|
|
479
|
+
error: this.formatErrorMessage(error),
|
|
480
|
+
backend: this.name,
|
|
481
|
+
status: 'failed',
|
|
482
|
+
metadata: this.config.debug ? this.getErrorMetadata(error) : undefined,
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Estimate cost for an operation
|
|
489
|
+
*/
|
|
490
|
+
async estimateCost(params: BackendParams): Promise<bigint> {
|
|
491
|
+
if (isComputationParams(params)) {
|
|
492
|
+
return this.estimateComputeCost(params)
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// Transfer params - return 0 as we don't support transfers
|
|
496
|
+
return BigInt(0)
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Get computation status
|
|
501
|
+
*
|
|
502
|
+
* @param computationId - Computation to check
|
|
503
|
+
* @returns Current status or undefined if not found
|
|
504
|
+
*/
|
|
505
|
+
async getComputationStatus(
|
|
506
|
+
computationId: string
|
|
507
|
+
): Promise<ComputationStatus | undefined> {
|
|
508
|
+
// Check cache first
|
|
509
|
+
const cached = this.computationCache.get(computationId)
|
|
510
|
+
if (cached) {
|
|
511
|
+
return cached.status
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// In production, would query the Arcium network:
|
|
515
|
+
// const client = await this.getClient()
|
|
516
|
+
// return client.getComputationStatus(computationId)
|
|
517
|
+
|
|
518
|
+
return undefined
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* Get computation info
|
|
523
|
+
*
|
|
524
|
+
* @param computationId - Computation to query
|
|
525
|
+
* @returns Computation info or undefined if not found
|
|
526
|
+
*/
|
|
527
|
+
async getComputationInfo(
|
|
528
|
+
computationId: string
|
|
529
|
+
): Promise<ComputationInfo | undefined> {
|
|
530
|
+
// Check cache
|
|
531
|
+
const cached = this.computationCache.get(computationId)
|
|
532
|
+
if (cached) {
|
|
533
|
+
return cached
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// In production, would query the Arcium network
|
|
537
|
+
return undefined
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* Wait for computation to complete
|
|
542
|
+
*
|
|
543
|
+
* @param computationId - Computation to wait for
|
|
544
|
+
* @param timeout - Optional timeout override (defaults to config.timeout)
|
|
545
|
+
* @returns Computation result
|
|
546
|
+
* @throws {ComputationTimeoutError} If computation exceeds timeout
|
|
547
|
+
*/
|
|
548
|
+
async awaitComputation(
|
|
549
|
+
computationId: string,
|
|
550
|
+
timeout?: number
|
|
551
|
+
): Promise<ComputationResult> {
|
|
552
|
+
const timeoutMs = timeout ?? this.config.timeout
|
|
553
|
+
|
|
554
|
+
// Check if computation exists before waiting
|
|
555
|
+
const info = this.computationCache.get(computationId)
|
|
556
|
+
if (!info) {
|
|
557
|
+
return {
|
|
558
|
+
success: false,
|
|
559
|
+
error: `Computation ${computationId} not found`,
|
|
560
|
+
backend: this.name,
|
|
561
|
+
status: 'failed',
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// Wrap the polling/waiting logic with timeout
|
|
566
|
+
return withTimeout(
|
|
567
|
+
this.pollComputationResult(computationId, info),
|
|
568
|
+
timeoutMs,
|
|
569
|
+
() => {
|
|
570
|
+
throw new ComputationTimeoutError(computationId, timeoutMs, this.name)
|
|
571
|
+
}
|
|
572
|
+
)
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Poll for computation result (simulation)
|
|
577
|
+
*
|
|
578
|
+
* In production, this would poll the Arcium network for completion.
|
|
579
|
+
* Currently simulates immediate completion for testing.
|
|
580
|
+
*/
|
|
581
|
+
private async pollComputationResult(
|
|
582
|
+
computationId: string,
|
|
583
|
+
info: ComputationInfo
|
|
584
|
+
): Promise<ComputationResult> {
|
|
585
|
+
// In production, would poll the Arcium network:
|
|
586
|
+
// const client = await this.getClient()
|
|
587
|
+
// const output = await client.awaitFinalization(computationId)
|
|
588
|
+
|
|
589
|
+
// Simulated: Mark as completed immediately
|
|
590
|
+
info.status = 'completed'
|
|
591
|
+
info.completedAt = Date.now()
|
|
592
|
+
this.computationCache.set(computationId, info)
|
|
593
|
+
|
|
594
|
+
return {
|
|
595
|
+
success: true,
|
|
596
|
+
computationId,
|
|
597
|
+
output: new Uint8Array([0, 1, 2, 3]), // Simulated output
|
|
598
|
+
backend: this.name,
|
|
599
|
+
status: 'completed',
|
|
600
|
+
completedAt: info.completedAt,
|
|
601
|
+
metadata: {
|
|
602
|
+
circuitId: info.circuitId,
|
|
603
|
+
cluster: info.cluster,
|
|
604
|
+
duration: info.completedAt - info.submittedAt,
|
|
605
|
+
warning: 'Simulated result - SDK integration pending',
|
|
606
|
+
},
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
// ─── Private Methods ─────────────────────────────────────────────────────────
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* Estimate cost for a computation
|
|
614
|
+
*/
|
|
615
|
+
private estimateComputeCost(params: ComputationParams): bigint {
|
|
616
|
+
let cost = BASE_COMPUTATION_COST_LAMPORTS
|
|
617
|
+
|
|
618
|
+
// More inputs = higher cost
|
|
619
|
+
const inputCost =
|
|
620
|
+
BigInt(params.encryptedInputs.length) * COST_PER_ENCRYPTED_INPUT_LAMPORTS
|
|
621
|
+
cost += inputCost
|
|
622
|
+
|
|
623
|
+
// Larger inputs = higher cost
|
|
624
|
+
const totalInputSize = params.encryptedInputs.reduce(
|
|
625
|
+
(sum, input) => sum + input.length,
|
|
626
|
+
0
|
|
627
|
+
)
|
|
628
|
+
const sizeCost =
|
|
629
|
+
BigInt(Math.ceil(totalInputSize / BYTES_PER_KB)) * COST_PER_INPUT_KB_LAMPORTS
|
|
630
|
+
cost += sizeCost
|
|
631
|
+
|
|
632
|
+
// Cap at maximum reasonable cost to prevent unexpected charges
|
|
633
|
+
if (cost > this.limits.maxComputationCostLamports) {
|
|
634
|
+
return this.limits.maxComputationCostLamports
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
return cost
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* Generate a unique computation ID
|
|
642
|
+
*/
|
|
643
|
+
private generateComputationId(): string {
|
|
644
|
+
const timestamp = Date.now().toString(36)
|
|
645
|
+
const random = Math.random().toString(36).slice(2, 10)
|
|
646
|
+
return `arcium_${timestamp}_${random}`
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* Clear computation cache
|
|
651
|
+
*/
|
|
652
|
+
clearComputationCache(): void {
|
|
653
|
+
this.computationCache.clear()
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* Get cached computation count
|
|
658
|
+
*/
|
|
659
|
+
getCachedComputationCount(): number {
|
|
660
|
+
return this.computationCache.size
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
// ─── Error Handling Helpers ─────────────────────────────────────────────────
|
|
664
|
+
|
|
665
|
+
/**
|
|
666
|
+
* Format an error message for user-facing output
|
|
667
|
+
*
|
|
668
|
+
* Include error type for better debugging while keeping the message clear.
|
|
669
|
+
*/
|
|
670
|
+
private formatErrorMessage(error: unknown): string {
|
|
671
|
+
if (error instanceof Error) {
|
|
672
|
+
const errorType = error.name !== 'Error' ? `[${error.name}] ` : ''
|
|
673
|
+
return `${errorType}${error.message}`
|
|
674
|
+
}
|
|
675
|
+
return 'Unknown error occurred'
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
/**
|
|
679
|
+
* Get detailed error metadata for debugging
|
|
680
|
+
*
|
|
681
|
+
* Only called when debug mode is enabled. Includes stack trace and
|
|
682
|
+
* error chain information for troubleshooting.
|
|
683
|
+
*/
|
|
684
|
+
private getErrorMetadata(error: unknown): Record<string, unknown> {
|
|
685
|
+
const metadata: Record<string, unknown> = {
|
|
686
|
+
timestamp: new Date().toISOString(),
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
if (error instanceof Error) {
|
|
690
|
+
metadata.errorName = error.name
|
|
691
|
+
metadata.errorMessage = error.message
|
|
692
|
+
metadata.stack = error.stack
|
|
693
|
+
|
|
694
|
+
// Preserve error cause chain
|
|
695
|
+
if (error.cause) {
|
|
696
|
+
metadata.cause =
|
|
697
|
+
error.cause instanceof Error
|
|
698
|
+
? {
|
|
699
|
+
name: error.cause.name,
|
|
700
|
+
message: error.cause.message,
|
|
701
|
+
stack: error.cause.stack,
|
|
702
|
+
}
|
|
703
|
+
: String(error.cause)
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// Handle SIPError-specific fields
|
|
707
|
+
if ('code' in error && typeof (error as Record<string, unknown>).code === 'string') {
|
|
708
|
+
metadata.errorCode = (error as Record<string, unknown>).code
|
|
709
|
+
}
|
|
710
|
+
if ('context' in error) {
|
|
711
|
+
metadata.errorContext = (error as Record<string, unknown>).context
|
|
712
|
+
}
|
|
713
|
+
} else {
|
|
714
|
+
metadata.rawError = String(error)
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
return metadata
|
|
718
|
+
}
|
|
719
|
+
}
|