@sip-protocol/sdk 0.7.3 → 0.8.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 +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 +47556 -19603
- package/dist/browser.mjs +628 -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-3M3HNQCW.mjs → chunk-YWGJ77A2.mjs} +28656 -13103
- 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-DIBZHOOQ.d.ts → index-DXh2IGkz.d.ts} +21239 -10304
- package/dist/{index-8MQz13eJ.d.mts → index-DeE1ZzA4.d.mts} +21239 -10304
- package/dist/index.d.mts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.js +48396 -19623
- package/dist/index.mjs +537 -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 +44 -11
- 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 +252 -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 +47 -6
- 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 +186 -33
- package/src/chains/solana/providers/index.ts +31 -0
- package/src/chains/solana/providers/interface.ts +61 -18
- 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 +338 -67
- package/src/chains/solana/rpc-client.ts +1150 -0
- package/src/chains/solana/scan.ts +83 -66
- 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 +57 -6
- 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 +23 -0
- package/src/compliance/range-sas.ts +398 -33
- 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 +686 -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 +254 -4
- package/src/privacy-backends/interface.ts +649 -6
- 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.ts +13 -17
- package/src/privacy-backends/private-swap.ts +570 -0
- package/src/privacy-backends/rate-limiter.ts +683 -0
- package/src/privacy-backends/registry.ts +414 -2
- package/src/privacy-backends/router.ts +283 -3
- package/src/privacy-backends/shadowwire.ts +449 -0
- package/src/privacy-backends/sip-native.ts +3 -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 +110 -29
- 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/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-2XIVXWHA.mjs +0 -1930
- package/dist/chunk-3INS3PR5.mjs +0 -884
- package/dist/chunk-3OVABDRH.mjs +0 -17096
- package/dist/chunk-7RFRWDCW.mjs +0 -1504
- package/dist/chunk-DLDWZFYC.mjs +0 -1495
- package/dist/chunk-E6SZWREQ.mjs +0 -57
- package/dist/chunk-F6F73W35.mjs +0 -16166
- package/dist/chunk-G33LB27A.mjs +0 -16166
- package/dist/chunk-HGU6HZRC.mjs +0 -231
- package/dist/chunk-L2K34JCU.mjs +0 -1496
- package/dist/chunk-OFDBEIEK.mjs +0 -16166
- package/dist/chunk-SF7YSLF5.mjs +0 -1515
- package/dist/chunk-SN4ZDTVW.mjs +0 -16166
- package/dist/chunk-WWUSGOXE.mjs +0 -17129
- package/dist/constants-VOI7BSLK.mjs +0 -27
- package/dist/index-B71aXVzk.d.ts +0 -13264
- 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-pOIIuwfV.d.mts +0 -13264
- package/dist/index-xbWjohNq.d.mts +0 -11390
- package/dist/solana-4O4K45VU.mjs +0 -46
- package/dist/solana-5EMCTPTS.mjs +0 -46
- package/dist/solana-NDABAZ6P.mjs +0 -56
- package/dist/solana-Q4NAVBTS.mjs +0 -46
- package/dist/solana-ZYO63LY5.mjs +0 -46
|
@@ -0,0 +1,866 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Combined Privacy Service
|
|
3
|
+
*
|
|
4
|
+
* Integrates SIP Native (stealth addresses, Pedersen commitments, viewing keys)
|
|
5
|
+
* with Arcium C-SPL (encrypted amounts) for comprehensive transaction privacy.
|
|
6
|
+
*
|
|
7
|
+
* ## Privacy Layers Combined
|
|
8
|
+
*
|
|
9
|
+
* | Feature | SIP Native | Arcium C-SPL | Combined |
|
|
10
|
+
* |---------|------------|--------------|----------|
|
|
11
|
+
* | Hidden Sender | ✓ | ✗ | ✓ |
|
|
12
|
+
* | Hidden Recipient | ✓ | ✗ | ✓ |
|
|
13
|
+
* | Hidden Amount | ✓ (Pedersen) | ✓ (Encrypted) | ✓ |
|
|
14
|
+
* | Hidden Compute | ✗ | ✓ (MPC) | ✓ |
|
|
15
|
+
* | Compliance | ✓ (Viewing Keys) | ✗ | ✓ |
|
|
16
|
+
*
|
|
17
|
+
* ## Usage
|
|
18
|
+
*
|
|
19
|
+
* ```typescript
|
|
20
|
+
* import { CombinedPrivacyService } from '@sip-protocol/sdk'
|
|
21
|
+
*
|
|
22
|
+
* const service = new CombinedPrivacyService({
|
|
23
|
+
* rpcUrl: 'https://api.devnet.solana.com',
|
|
24
|
+
* })
|
|
25
|
+
*
|
|
26
|
+
* await service.initialize()
|
|
27
|
+
*
|
|
28
|
+
* // Execute private transfer with full privacy
|
|
29
|
+
* const result = await service.executePrivateTransfer({
|
|
30
|
+
* sender: wallet.publicKey,
|
|
31
|
+
* recipientMetaAddress: 'sip:solana:0x...',
|
|
32
|
+
* amount: 1_000_000_000n,
|
|
33
|
+
* token: 'So11111111111111111111111111111111111111112',
|
|
34
|
+
* privacyLevel: 'shielded',
|
|
35
|
+
* })
|
|
36
|
+
*
|
|
37
|
+
* // IMPORTANT: Always check success before accessing result fields
|
|
38
|
+
* if (!result.success) {
|
|
39
|
+
* console.error('Transfer failed:', result.error)
|
|
40
|
+
* return
|
|
41
|
+
* }
|
|
42
|
+
*
|
|
43
|
+
* console.log('Stealth address:', result.stealthAddress)
|
|
44
|
+
* console.log('Signature:', result.signature)
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* @see CSPLTokenService for C-SPL operations
|
|
48
|
+
* @see SIPNativeBackend for stealth address operations
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
import { PrivacyLevel, type ViewingKey } from '@sip-protocol/types'
|
|
52
|
+
import {
|
|
53
|
+
CSPLTokenService,
|
|
54
|
+
type CSPLTokenServiceConfig,
|
|
55
|
+
} from './cspl-token'
|
|
56
|
+
import type { CSPLToken } from './cspl-types'
|
|
57
|
+
import { SIPNativeBackend, type SIPNativeBackendConfig } from './sip-native'
|
|
58
|
+
|
|
59
|
+
// ─── Types ─────────────────────────────────────────────────────────────────────
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Parameters for a combined private transfer
|
|
63
|
+
*/
|
|
64
|
+
export interface CombinedTransferParams {
|
|
65
|
+
/** Sender wallet address */
|
|
66
|
+
sender: string
|
|
67
|
+
/** Recipient's meta-address (sip:chain:spending:viewing format) */
|
|
68
|
+
recipientMetaAddress: string
|
|
69
|
+
/** Amount to transfer (in smallest units) */
|
|
70
|
+
amount: bigint
|
|
71
|
+
/** Token mint address (SPL token, will be wrapped to C-SPL) */
|
|
72
|
+
token: string
|
|
73
|
+
/** Privacy level */
|
|
74
|
+
privacyLevel: PrivacyLevel
|
|
75
|
+
/** Optional viewing key for compliance (required for 'compliant' level) */
|
|
76
|
+
viewingKey?: ViewingKey
|
|
77
|
+
/** Optional memo (public if not encrypted) */
|
|
78
|
+
memo?: string
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Result of a combined private transfer
|
|
83
|
+
*
|
|
84
|
+
* IMPORTANT: Always check `success` before accessing other fields.
|
|
85
|
+
* Fields like stealthAddress, csplMint, etc. are only populated when success is true.
|
|
86
|
+
*/
|
|
87
|
+
export interface CombinedTransferResult {
|
|
88
|
+
/** Whether the transfer succeeded */
|
|
89
|
+
success: boolean
|
|
90
|
+
/** Error message (only if !success) */
|
|
91
|
+
error?: string
|
|
92
|
+
/** The one-time stealth address for this transfer (only if success) */
|
|
93
|
+
stealthAddress?: string
|
|
94
|
+
/** The C-SPL token mint used (only if success) */
|
|
95
|
+
csplMint?: string
|
|
96
|
+
/** Encrypted balance after transfer (only if success) */
|
|
97
|
+
encryptedBalance?: Uint8Array
|
|
98
|
+
/** Transaction signature for wrap operation (only if success) */
|
|
99
|
+
wrapSignature?: string
|
|
100
|
+
/** Transaction signature for transfer operation (only if success) */
|
|
101
|
+
transferSignature?: string
|
|
102
|
+
/** Combined operation signatures (only if success) */
|
|
103
|
+
signatures?: string[]
|
|
104
|
+
/** Transfer metadata */
|
|
105
|
+
metadata?: {
|
|
106
|
+
privacyLevel: PrivacyLevel
|
|
107
|
+
hasViewingKey: boolean
|
|
108
|
+
wrapDuration?: number
|
|
109
|
+
transferDuration?: number
|
|
110
|
+
totalDuration?: number
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Result of stealth address derivation
|
|
116
|
+
*/
|
|
117
|
+
export interface StealthAddressResult {
|
|
118
|
+
/** Whether derivation succeeded */
|
|
119
|
+
success: boolean
|
|
120
|
+
/** Error message (only if !success) */
|
|
121
|
+
error?: string
|
|
122
|
+
/** The derived stealth address (only if success) */
|
|
123
|
+
stealthAddress?: string
|
|
124
|
+
/** The ephemeral public key (only if success) */
|
|
125
|
+
ephemeralPubkey?: string
|
|
126
|
+
/** The view tag for efficient scanning (only if success) */
|
|
127
|
+
viewTag?: number
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Parameters for claiming from stealth address
|
|
132
|
+
*/
|
|
133
|
+
export interface ClaimParams {
|
|
134
|
+
/** The stealth address to claim from */
|
|
135
|
+
stealthAddress: string
|
|
136
|
+
/** The ephemeral public key from sender */
|
|
137
|
+
ephemeralPubkey: string
|
|
138
|
+
/** Recipient's spending private key */
|
|
139
|
+
spendingPrivateKey: string
|
|
140
|
+
/** Recipient's viewing private key */
|
|
141
|
+
viewingPrivateKey: string
|
|
142
|
+
/** C-SPL token to claim */
|
|
143
|
+
csplMint: string
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Result of claiming from stealth address
|
|
148
|
+
*/
|
|
149
|
+
export interface ClaimResult {
|
|
150
|
+
/** Whether claim succeeded */
|
|
151
|
+
success: boolean
|
|
152
|
+
/** Error message (only if !success) */
|
|
153
|
+
error?: string
|
|
154
|
+
/** Amount claimed (decrypted) */
|
|
155
|
+
amount?: bigint
|
|
156
|
+
/** Transaction signature */
|
|
157
|
+
signature?: string
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Cost breakdown for combined operations
|
|
162
|
+
*/
|
|
163
|
+
export interface CostBreakdown {
|
|
164
|
+
/** Cost for wrapping to C-SPL */
|
|
165
|
+
wrapCost: bigint
|
|
166
|
+
/** Cost for stealth address derivation */
|
|
167
|
+
stealthCost: bigint
|
|
168
|
+
/** Cost for confidential transfer */
|
|
169
|
+
transferCost: bigint
|
|
170
|
+
/** Total estimated cost */
|
|
171
|
+
totalCost: bigint
|
|
172
|
+
/** Currency (e.g., 'lamports', 'gwei') */
|
|
173
|
+
currency: string
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Privacy comparison between backends
|
|
178
|
+
*/
|
|
179
|
+
export interface PrivacyComparison {
|
|
180
|
+
sipNative: {
|
|
181
|
+
hiddenSender: boolean
|
|
182
|
+
hiddenRecipient: boolean
|
|
183
|
+
hiddenAmount: boolean
|
|
184
|
+
hiddenCompute: boolean
|
|
185
|
+
compliance: boolean
|
|
186
|
+
}
|
|
187
|
+
arciumCSPL: {
|
|
188
|
+
hiddenSender: boolean
|
|
189
|
+
hiddenRecipient: boolean
|
|
190
|
+
hiddenAmount: boolean
|
|
191
|
+
hiddenCompute: boolean
|
|
192
|
+
compliance: boolean
|
|
193
|
+
}
|
|
194
|
+
combined: {
|
|
195
|
+
hiddenSender: boolean
|
|
196
|
+
hiddenRecipient: boolean
|
|
197
|
+
hiddenAmount: boolean
|
|
198
|
+
hiddenCompute: boolean
|
|
199
|
+
compliance: boolean
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Service status
|
|
205
|
+
*/
|
|
206
|
+
export interface ServiceStatus {
|
|
207
|
+
/** Whether service is initialized */
|
|
208
|
+
initialized: boolean
|
|
209
|
+
/** C-SPL service status */
|
|
210
|
+
csplStatus: {
|
|
211
|
+
connected: boolean
|
|
212
|
+
tokenCount: number
|
|
213
|
+
}
|
|
214
|
+
/** SIP Native backend status */
|
|
215
|
+
sipNativeStatus: {
|
|
216
|
+
available: boolean
|
|
217
|
+
chainCount: number
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// ─── Service Implementation ────────────────────────────────────────────────────
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Configuration for CombinedPrivacyService
|
|
225
|
+
*/
|
|
226
|
+
export interface CombinedPrivacyServiceConfig {
|
|
227
|
+
/** Solana RPC endpoint URL */
|
|
228
|
+
rpcUrl?: string
|
|
229
|
+
/** C-SPL service configuration */
|
|
230
|
+
csplConfig?: CSPLTokenServiceConfig
|
|
231
|
+
/** SIP Native backend configuration */
|
|
232
|
+
sipNativeConfig?: SIPNativeBackendConfig
|
|
233
|
+
/** Default privacy level */
|
|
234
|
+
defaultPrivacyLevel?: PrivacyLevel
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Combined Privacy Service
|
|
239
|
+
*
|
|
240
|
+
* Provides comprehensive privacy by combining:
|
|
241
|
+
* - SIP Native: Stealth addresses (unlinkable recipients)
|
|
242
|
+
* - SIP Native: Pedersen commitments (hidden amounts)
|
|
243
|
+
* - SIP Native: Viewing keys (compliance support)
|
|
244
|
+
* - Arcium C-SPL: Encrypted token balances
|
|
245
|
+
*
|
|
246
|
+
* ## Critical: Always Check Success Before Accessing Fields
|
|
247
|
+
*
|
|
248
|
+
* All result types in this service use the Result pattern.
|
|
249
|
+
* You MUST check `result.success` before accessing other fields.
|
|
250
|
+
*
|
|
251
|
+
* @example
|
|
252
|
+
* ```typescript
|
|
253
|
+
* // CORRECT: Check success first
|
|
254
|
+
* if (!result.success) {
|
|
255
|
+
* console.error(result.error)
|
|
256
|
+
* return
|
|
257
|
+
* }
|
|
258
|
+
* console.log(result.stealthAddress) // Now safe to access
|
|
259
|
+
*
|
|
260
|
+
* // INCORRECT: Never use non-null assertions without checking success
|
|
261
|
+
* // console.log(result.stealthAddress!) // UNSAFE - could be undefined
|
|
262
|
+
* ```
|
|
263
|
+
*/
|
|
264
|
+
export class CombinedPrivacyService {
|
|
265
|
+
private csplService: CSPLTokenService
|
|
266
|
+
private sipNativeBackend: SIPNativeBackend
|
|
267
|
+
private config: Required<CombinedPrivacyServiceConfig>
|
|
268
|
+
private initialized: boolean = false
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Create a new Combined Privacy Service
|
|
272
|
+
*
|
|
273
|
+
* @param config - Service configuration
|
|
274
|
+
*/
|
|
275
|
+
constructor(config: CombinedPrivacyServiceConfig = {}) {
|
|
276
|
+
this.config = {
|
|
277
|
+
rpcUrl: config.rpcUrl ?? 'https://api.devnet.solana.com',
|
|
278
|
+
csplConfig: config.csplConfig ?? {},
|
|
279
|
+
sipNativeConfig: config.sipNativeConfig ?? {},
|
|
280
|
+
defaultPrivacyLevel: config.defaultPrivacyLevel ?? PrivacyLevel.SHIELDED,
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Initialize sub-services
|
|
284
|
+
this.csplService = new CSPLTokenService({
|
|
285
|
+
...this.config.csplConfig,
|
|
286
|
+
rpcUrl: this.config.rpcUrl,
|
|
287
|
+
})
|
|
288
|
+
|
|
289
|
+
this.sipNativeBackend = new SIPNativeBackend(this.config.sipNativeConfig)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Initialize the service
|
|
294
|
+
*
|
|
295
|
+
* Initializes both C-SPL and SIP Native components.
|
|
296
|
+
*/
|
|
297
|
+
async initialize(): Promise<void> {
|
|
298
|
+
if (this.initialized) {
|
|
299
|
+
return
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
await this.csplService.initialize()
|
|
303
|
+
this.initialized = true
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Execute a privacy-preserving transfer
|
|
308
|
+
*
|
|
309
|
+
* This combines:
|
|
310
|
+
* 1. Wrap SPL to C-SPL (encrypted balance)
|
|
311
|
+
* 2. Derive stealth address (unlinkable recipient)
|
|
312
|
+
* 3. Transfer to stealth address with encrypted amount
|
|
313
|
+
*
|
|
314
|
+
* IMPORTANT: Always check result.success before accessing result fields!
|
|
315
|
+
*
|
|
316
|
+
* @param params - Transfer parameters
|
|
317
|
+
* @returns Transfer result with success status
|
|
318
|
+
*
|
|
319
|
+
* @example
|
|
320
|
+
* ```typescript
|
|
321
|
+
* const result = await service.executePrivateTransfer({
|
|
322
|
+
* sender: wallet.publicKey,
|
|
323
|
+
* recipientMetaAddress: 'sip:solana:0x...',
|
|
324
|
+
* amount: 1_000_000_000n,
|
|
325
|
+
* token: 'So11...',
|
|
326
|
+
* privacyLevel: 'shielded',
|
|
327
|
+
* })
|
|
328
|
+
*
|
|
329
|
+
* // ALWAYS check success first
|
|
330
|
+
* if (!result.success) {
|
|
331
|
+
* console.error('Failed:', result.error)
|
|
332
|
+
* return
|
|
333
|
+
* }
|
|
334
|
+
*
|
|
335
|
+
* // Now safe to access fields
|
|
336
|
+
* console.log('Stealth:', result.stealthAddress)
|
|
337
|
+
* console.log('C-SPL:', result.csplMint)
|
|
338
|
+
* ```
|
|
339
|
+
*/
|
|
340
|
+
async executePrivateTransfer(
|
|
341
|
+
params: CombinedTransferParams
|
|
342
|
+
): Promise<CombinedTransferResult> {
|
|
343
|
+
const startTime = Date.now()
|
|
344
|
+
|
|
345
|
+
if (!this.initialized) {
|
|
346
|
+
return {
|
|
347
|
+
success: false,
|
|
348
|
+
error: 'Service not initialized. Call initialize() first.',
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// Validate inputs
|
|
353
|
+
const validation = this.validateTransferParams(params)
|
|
354
|
+
if (!validation.valid) {
|
|
355
|
+
return {
|
|
356
|
+
success: false,
|
|
357
|
+
error: validation.error,
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
try {
|
|
362
|
+
// Step 1: Wrap SPL to C-SPL
|
|
363
|
+
const wrapStartTime = Date.now()
|
|
364
|
+
const wrapResult = await this.csplService.wrap({
|
|
365
|
+
mint: params.token,
|
|
366
|
+
amount: params.amount,
|
|
367
|
+
owner: params.sender,
|
|
368
|
+
})
|
|
369
|
+
|
|
370
|
+
// CRITICAL: Check wrapResult.success BEFORE accessing fields!
|
|
371
|
+
// This is the fix for issue #527 - never use non-null assertion
|
|
372
|
+
// on result fields without first checking success.
|
|
373
|
+
if (!wrapResult.success) {
|
|
374
|
+
return {
|
|
375
|
+
success: false,
|
|
376
|
+
error: `Failed to wrap tokens: ${wrapResult.error}`,
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
const wrapDuration = Date.now() - wrapStartTime
|
|
381
|
+
|
|
382
|
+
// Now safe to access wrapResult fields since success is true
|
|
383
|
+
const csplMint = wrapResult.csplMint
|
|
384
|
+
const encryptedBalance = wrapResult.encryptedBalance
|
|
385
|
+
|
|
386
|
+
// Step 2: Derive stealth address for recipient
|
|
387
|
+
const stealthResult = await this.deriveStealthAddress(params.recipientMetaAddress)
|
|
388
|
+
|
|
389
|
+
// Check stealthResult.success before accessing fields
|
|
390
|
+
if (!stealthResult.success) {
|
|
391
|
+
return {
|
|
392
|
+
success: false,
|
|
393
|
+
error: `Failed to derive stealth address: ${stealthResult.error}`,
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
const stealthAddress = stealthResult.stealthAddress
|
|
398
|
+
|
|
399
|
+
// Step 3: Execute transfer via SIP Native backend
|
|
400
|
+
const transferStartTime = Date.now()
|
|
401
|
+
|
|
402
|
+
// Note: Using SIP Native for the actual transfer with stealth address
|
|
403
|
+
// The C-SPL wrapping provides encrypted amounts, SIP Native provides
|
|
404
|
+
// stealth addresses for unlinkable recipients
|
|
405
|
+
const transferResult = await this.sipNativeBackend.execute({
|
|
406
|
+
chain: 'solana',
|
|
407
|
+
sender: params.sender,
|
|
408
|
+
recipient: stealthAddress!,
|
|
409
|
+
mint: csplMint!,
|
|
410
|
+
amount: params.amount,
|
|
411
|
+
decimals: 9, // TODO(#645): Get from token metadata
|
|
412
|
+
viewingKey: params.viewingKey,
|
|
413
|
+
})
|
|
414
|
+
|
|
415
|
+
// Check transferResult.success
|
|
416
|
+
if (!transferResult.success) {
|
|
417
|
+
return {
|
|
418
|
+
success: false,
|
|
419
|
+
error: `Failed to execute transfer: ${transferResult.error}`,
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
const transferDuration = Date.now() - transferStartTime
|
|
424
|
+
const totalDuration = Date.now() - startTime
|
|
425
|
+
|
|
426
|
+
// All steps succeeded - return complete result
|
|
427
|
+
return {
|
|
428
|
+
success: true,
|
|
429
|
+
stealthAddress: stealthAddress,
|
|
430
|
+
csplMint: csplMint,
|
|
431
|
+
encryptedBalance: encryptedBalance,
|
|
432
|
+
wrapSignature: wrapResult.signature,
|
|
433
|
+
transferSignature: transferResult.signature,
|
|
434
|
+
signatures: [wrapResult.signature!, transferResult.signature!].filter(Boolean),
|
|
435
|
+
metadata: {
|
|
436
|
+
privacyLevel: params.privacyLevel,
|
|
437
|
+
hasViewingKey: !!params.viewingKey,
|
|
438
|
+
wrapDuration,
|
|
439
|
+
transferDuration,
|
|
440
|
+
totalDuration,
|
|
441
|
+
},
|
|
442
|
+
}
|
|
443
|
+
} catch (error) {
|
|
444
|
+
return {
|
|
445
|
+
success: false,
|
|
446
|
+
error: error instanceof Error ? error.message : 'Unknown error during transfer',
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Derive a one-time stealth address from a recipient's meta-address
|
|
453
|
+
*
|
|
454
|
+
* Stealth addresses provide unlinkable recipients — each payment creates a unique
|
|
455
|
+
* address that only the recipient can identify and claim. This prevents linking
|
|
456
|
+
* multiple payments to the same recipient.
|
|
457
|
+
*
|
|
458
|
+
* ## Meta-Address Format
|
|
459
|
+
*
|
|
460
|
+
* The meta-address must follow the SIP format: `sip:<chain>:<spendingKey>:<viewingKey>`
|
|
461
|
+
*
|
|
462
|
+
* - `chain` — The blockchain (e.g., "solana", "ethereum")
|
|
463
|
+
* - `spendingKey` — Recipient's public spending key (controls funds)
|
|
464
|
+
* - `viewingKey` — Recipient's public viewing key (for scanning)
|
|
465
|
+
*
|
|
466
|
+
* ## Return Value
|
|
467
|
+
*
|
|
468
|
+
* On success, returns:
|
|
469
|
+
* - `stealthAddress` — The derived one-time address to send funds to
|
|
470
|
+
* - `ephemeralPubkey` — Must be published so recipient can compute private key
|
|
471
|
+
* - `viewTag` — Optimization for efficient payment scanning (0-255)
|
|
472
|
+
*
|
|
473
|
+
* IMPORTANT: Always check `result.success` before accessing other fields.
|
|
474
|
+
*
|
|
475
|
+
* @param metaAddress - SIP meta-address in format `sip:<chain>:<spendingKey>:<viewingKey>`
|
|
476
|
+
* @returns Stealth address result with success status
|
|
477
|
+
*
|
|
478
|
+
* @example
|
|
479
|
+
* ```typescript
|
|
480
|
+
* const result = await service.deriveStealthAddress(
|
|
481
|
+
* 'sip:solana:0x02abc...123:0x03def...456'
|
|
482
|
+
* )
|
|
483
|
+
*
|
|
484
|
+
* if (!result.success) {
|
|
485
|
+
* console.error('Failed:', result.error)
|
|
486
|
+
* return
|
|
487
|
+
* }
|
|
488
|
+
*
|
|
489
|
+
* // Now safe to access fields
|
|
490
|
+
* console.log('Send to:', result.stealthAddress)
|
|
491
|
+
* console.log('Publish:', result.ephemeralPubkey)
|
|
492
|
+
* console.log('View tag:', result.viewTag)
|
|
493
|
+
* ```
|
|
494
|
+
*/
|
|
495
|
+
async deriveStealthAddress(metaAddress: string): Promise<StealthAddressResult> {
|
|
496
|
+
// Parse meta-address
|
|
497
|
+
const parts = metaAddress.split(':')
|
|
498
|
+
if (parts.length !== 4 || parts[0] !== 'sip') {
|
|
499
|
+
return {
|
|
500
|
+
success: false,
|
|
501
|
+
error: `Invalid meta-address format. Expected: sip:<chain>:<spendingKey>:<viewingKey>, got: ${metaAddress}`,
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
const [, chain, spendingKey, viewingKey] = parts
|
|
506
|
+
|
|
507
|
+
if (!chain || !spendingKey || !viewingKey) {
|
|
508
|
+
return {
|
|
509
|
+
success: false,
|
|
510
|
+
error: 'Meta-address must contain chain, spending key, and viewing key',
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
try {
|
|
515
|
+
// In production, this would:
|
|
516
|
+
// 1. Generate ephemeral keypair
|
|
517
|
+
// 2. Compute shared secret with recipient's viewing key
|
|
518
|
+
// 3. Derive stealth address from spending key + shared secret
|
|
519
|
+
|
|
520
|
+
// Simulated stealth address derivation
|
|
521
|
+
const simulatedEphemeralPubkey = `eph_${Date.now().toString(36)}_${Math.random().toString(36).slice(2)}`
|
|
522
|
+
const simulatedStealthAddress = `stealth_${chain}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2)}`
|
|
523
|
+
const viewTag = Math.floor(Math.random() * 256)
|
|
524
|
+
|
|
525
|
+
return {
|
|
526
|
+
success: true,
|
|
527
|
+
stealthAddress: simulatedStealthAddress,
|
|
528
|
+
ephemeralPubkey: simulatedEphemeralPubkey,
|
|
529
|
+
viewTag,
|
|
530
|
+
}
|
|
531
|
+
} catch (error) {
|
|
532
|
+
return {
|
|
533
|
+
success: false,
|
|
534
|
+
error: error instanceof Error ? error.message : 'Failed to derive stealth address',
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* Claim tokens from a stealth address
|
|
541
|
+
*
|
|
542
|
+
* Recipients use this method to claim funds sent to their stealth addresses.
|
|
543
|
+
* The ephemeral public key (published by sender) is combined with the
|
|
544
|
+
* recipient's private viewing key to derive the stealth private key.
|
|
545
|
+
*
|
|
546
|
+
* ## Required Parameters
|
|
547
|
+
*
|
|
548
|
+
* - `stealthAddress` — The stealth address containing funds
|
|
549
|
+
* - `ephemeralPubkey` — The sender's ephemeral public key (from announcement)
|
|
550
|
+
* - `spendingPrivateKey` — Recipient's private spending key
|
|
551
|
+
* - `viewingPrivateKey` — Recipient's private viewing key
|
|
552
|
+
*
|
|
553
|
+
* ## Process
|
|
554
|
+
*
|
|
555
|
+
* 1. Computes shared secret from ephemeralPubkey + viewingPrivateKey
|
|
556
|
+
* 2. Derives stealth private key from spendingPrivateKey + shared secret
|
|
557
|
+
* 3. Creates claim transaction signed with stealth private key
|
|
558
|
+
* 4. Unwraps C-SPL back to regular SPL token
|
|
559
|
+
*
|
|
560
|
+
* IMPORTANT: Always check `result.success` before accessing other fields.
|
|
561
|
+
*
|
|
562
|
+
* @param params - Claim parameters including keys and addresses
|
|
563
|
+
* @returns Claim result with amount and transaction signature
|
|
564
|
+
*
|
|
565
|
+
* @example
|
|
566
|
+
* ```typescript
|
|
567
|
+
* const result = await service.claimFromStealth({
|
|
568
|
+
* stealthAddress: 'stealth_solana_...',
|
|
569
|
+
* ephemeralPubkey: 'eph_...',
|
|
570
|
+
* spendingPrivateKey: 'spending_priv_...',
|
|
571
|
+
* viewingPrivateKey: 'viewing_priv_...',
|
|
572
|
+
* })
|
|
573
|
+
*
|
|
574
|
+
* if (!result.success) {
|
|
575
|
+
* console.error('Claim failed:', result.error)
|
|
576
|
+
* return
|
|
577
|
+
* }
|
|
578
|
+
*
|
|
579
|
+
* console.log('Claimed:', result.amount, 'tokens')
|
|
580
|
+
* console.log('Transaction:', result.signature)
|
|
581
|
+
* ```
|
|
582
|
+
*/
|
|
583
|
+
async claimFromStealth(params: ClaimParams): Promise<ClaimResult> {
|
|
584
|
+
if (!this.initialized) {
|
|
585
|
+
return {
|
|
586
|
+
success: false,
|
|
587
|
+
error: 'Service not initialized. Call initialize() first.',
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// Validate inputs
|
|
592
|
+
if (!params.stealthAddress || !params.ephemeralPubkey) {
|
|
593
|
+
return {
|
|
594
|
+
success: false,
|
|
595
|
+
error: 'stealthAddress and ephemeralPubkey are required',
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
if (!params.spendingPrivateKey || !params.viewingPrivateKey) {
|
|
600
|
+
return {
|
|
601
|
+
success: false,
|
|
602
|
+
error: 'Both spending and viewing private keys are required',
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
try {
|
|
607
|
+
// In production, this would:
|
|
608
|
+
// 1. Compute shared secret from ephemeralPubkey + viewingPrivateKey
|
|
609
|
+
// 2. Derive stealth private key from spendingPrivateKey + shared secret
|
|
610
|
+
// 3. Create claim transaction signed with stealth private key
|
|
611
|
+
// 4. Unwrap C-SPL back to SPL
|
|
612
|
+
|
|
613
|
+
// Simulated claim
|
|
614
|
+
const simulatedSignature = `claim_${Date.now()}_${Math.random().toString(36).slice(2)}`
|
|
615
|
+
const simulatedAmount = BigInt(1_000_000_000) // 1 token (simulated)
|
|
616
|
+
|
|
617
|
+
return {
|
|
618
|
+
success: true,
|
|
619
|
+
amount: simulatedAmount,
|
|
620
|
+
signature: simulatedSignature,
|
|
621
|
+
}
|
|
622
|
+
} catch (error) {
|
|
623
|
+
return {
|
|
624
|
+
success: false,
|
|
625
|
+
error: error instanceof Error ? error.message : 'Failed to claim from stealth',
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
/**
|
|
631
|
+
* Estimate the total cost for a combined privacy transfer
|
|
632
|
+
*
|
|
633
|
+
* Returns a breakdown of costs across all privacy layers:
|
|
634
|
+
* - `wrapCost` — Cost to wrap SPL into C-SPL (encrypted balance)
|
|
635
|
+
* - `stealthCost` — Cost for stealth address derivation (client-side, 0)
|
|
636
|
+
* - `transferCost` — Cost for the SIP Native transfer
|
|
637
|
+
* - `totalCost` — Sum of all costs
|
|
638
|
+
*
|
|
639
|
+
* All costs are in lamports (1 SOL = 1,000,000,000 lamports).
|
|
640
|
+
*
|
|
641
|
+
* @param params - Transfer parameters (sender, recipient, amount, token)
|
|
642
|
+
* @returns Cost breakdown with individual and total costs
|
|
643
|
+
*
|
|
644
|
+
* @example
|
|
645
|
+
* ```typescript
|
|
646
|
+
* const costs = await service.estimateCost({
|
|
647
|
+
* sender: wallet.publicKey,
|
|
648
|
+
* recipientMetaAddress: 'sip:solana:0x...',
|
|
649
|
+
* amount: 1_000_000_000n,
|
|
650
|
+
* token: 'So11...',
|
|
651
|
+
* })
|
|
652
|
+
*
|
|
653
|
+
* console.log('Wrap cost:', costs.wrapCost, 'lamports')
|
|
654
|
+
* console.log('Transfer cost:', costs.transferCost, 'lamports')
|
|
655
|
+
* console.log('Total:', costs.totalCost, 'lamports')
|
|
656
|
+
* ```
|
|
657
|
+
*/
|
|
658
|
+
async estimateCost(params: CombinedTransferParams): Promise<CostBreakdown> {
|
|
659
|
+
// Wrap cost
|
|
660
|
+
const wrapCost = await this.csplService.estimateCost('wrap')
|
|
661
|
+
|
|
662
|
+
// Stealth address derivation is client-side, minimal cost
|
|
663
|
+
const stealthCost = BigInt(0)
|
|
664
|
+
|
|
665
|
+
// Transfer cost from SIP Native
|
|
666
|
+
const transferCost = await this.sipNativeBackend.estimateCost({
|
|
667
|
+
chain: 'solana',
|
|
668
|
+
sender: params.sender,
|
|
669
|
+
recipient: params.recipientMetaAddress,
|
|
670
|
+
mint: params.token,
|
|
671
|
+
amount: params.amount,
|
|
672
|
+
decimals: 9,
|
|
673
|
+
})
|
|
674
|
+
|
|
675
|
+
return {
|
|
676
|
+
wrapCost,
|
|
677
|
+
stealthCost,
|
|
678
|
+
transferCost,
|
|
679
|
+
totalCost: wrapCost + stealthCost + transferCost,
|
|
680
|
+
currency: 'lamports',
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Get a comparison of privacy features across backends
|
|
686
|
+
*
|
|
687
|
+
* Compares privacy capabilities between:
|
|
688
|
+
* - **SIP Native** — Stealth addresses + Pedersen commitments + viewing keys
|
|
689
|
+
* - **Arcium C-SPL** — Encrypted balances + MPC compute
|
|
690
|
+
* - **Combined** — Full privacy using both layers
|
|
691
|
+
*
|
|
692
|
+
* Privacy dimensions:
|
|
693
|
+
* - `hiddenSender` — Sender identity is not revealed on-chain
|
|
694
|
+
* - `hiddenRecipient` — Recipient identity is unlinkable
|
|
695
|
+
* - `hiddenAmount` — Transfer amount is encrypted/committed
|
|
696
|
+
* - `hiddenCompute` — Contract execution is private
|
|
697
|
+
* - `compliance` — Selective disclosure available for auditors
|
|
698
|
+
*
|
|
699
|
+
* @returns Privacy comparison for each backend and combined approach
|
|
700
|
+
*
|
|
701
|
+
* @example
|
|
702
|
+
* ```typescript
|
|
703
|
+
* const comparison = service.getPrivacyComparison()
|
|
704
|
+
*
|
|
705
|
+
* console.log('SIP Native hides sender:', comparison.sipNative.hiddenSender)
|
|
706
|
+
* console.log('Combined full privacy:', comparison.combined)
|
|
707
|
+
* ```
|
|
708
|
+
*/
|
|
709
|
+
getPrivacyComparison(): PrivacyComparison {
|
|
710
|
+
return {
|
|
711
|
+
sipNative: {
|
|
712
|
+
hiddenSender: true,
|
|
713
|
+
hiddenRecipient: true,
|
|
714
|
+
hiddenAmount: true, // Pedersen commitments
|
|
715
|
+
hiddenCompute: false,
|
|
716
|
+
compliance: true, // Viewing keys
|
|
717
|
+
},
|
|
718
|
+
arciumCSPL: {
|
|
719
|
+
hiddenSender: false,
|
|
720
|
+
hiddenRecipient: false,
|
|
721
|
+
hiddenAmount: true, // Encrypted balances
|
|
722
|
+
hiddenCompute: true, // MPC
|
|
723
|
+
compliance: false,
|
|
724
|
+
},
|
|
725
|
+
combined: {
|
|
726
|
+
hiddenSender: true, // From SIP Native
|
|
727
|
+
hiddenRecipient: true, // From SIP Native stealth addresses
|
|
728
|
+
hiddenAmount: true, // Both Pedersen and encrypted
|
|
729
|
+
hiddenCompute: true, // From Arcium when used
|
|
730
|
+
compliance: true, // From SIP Native viewing keys
|
|
731
|
+
},
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
/**
|
|
736
|
+
* Get the current status of the combined privacy service
|
|
737
|
+
*
|
|
738
|
+
* Returns status information for both underlying services:
|
|
739
|
+
* - `initialized` — Whether the service has been initialized
|
|
740
|
+
* - `csplStatus` — C-SPL service connection and token count
|
|
741
|
+
* - `sipNativeStatus` — SIP Native availability and chain support
|
|
742
|
+
*
|
|
743
|
+
* @returns Service status for monitoring and debugging
|
|
744
|
+
*
|
|
745
|
+
* @example
|
|
746
|
+
* ```typescript
|
|
747
|
+
* const status = service.getStatus()
|
|
748
|
+
*
|
|
749
|
+
* if (!status.initialized) {
|
|
750
|
+
* console.log('Service needs initialization')
|
|
751
|
+
* await service.initialize()
|
|
752
|
+
* }
|
|
753
|
+
*
|
|
754
|
+
* console.log('C-SPL connected:', status.csplStatus.connected)
|
|
755
|
+
* console.log('Registered tokens:', status.csplStatus.tokenCount)
|
|
756
|
+
* console.log('SIP Native available:', status.sipNativeStatus.available)
|
|
757
|
+
* ```
|
|
758
|
+
*/
|
|
759
|
+
getStatus(): ServiceStatus {
|
|
760
|
+
const csplStatus = this.csplService.getStatus()
|
|
761
|
+
const sipNativeCaps = this.sipNativeBackend.getCapabilities()
|
|
762
|
+
|
|
763
|
+
return {
|
|
764
|
+
initialized: this.initialized,
|
|
765
|
+
csplStatus: {
|
|
766
|
+
connected: csplStatus.connected,
|
|
767
|
+
tokenCount: csplStatus.registeredTokenCount,
|
|
768
|
+
},
|
|
769
|
+
sipNativeStatus: {
|
|
770
|
+
available: sipNativeCaps.setupRequired === false,
|
|
771
|
+
chainCount: this.sipNativeBackend.chains.length,
|
|
772
|
+
},
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
/**
|
|
777
|
+
* Register a token for use with the service
|
|
778
|
+
*
|
|
779
|
+
* @param token - C-SPL token to register
|
|
780
|
+
*/
|
|
781
|
+
registerToken(token: CSPLToken): void {
|
|
782
|
+
this.csplService.registerToken(token)
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
/**
|
|
786
|
+
* Disconnect and cleanup
|
|
787
|
+
*/
|
|
788
|
+
async disconnect(): Promise<void> {
|
|
789
|
+
await this.csplService.disconnect()
|
|
790
|
+
this.initialized = false
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
// ─── Private Methods ─────────────────────────────────────────────────────────
|
|
794
|
+
|
|
795
|
+
/**
|
|
796
|
+
* Validate transfer parameters
|
|
797
|
+
*/
|
|
798
|
+
private validateTransferParams(params: CombinedTransferParams): {
|
|
799
|
+
valid: boolean
|
|
800
|
+
error?: string
|
|
801
|
+
} {
|
|
802
|
+
if (!params.sender || params.sender.trim() === '') {
|
|
803
|
+
return { valid: false, error: 'Sender address is required' }
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
if (!params.recipientMetaAddress || params.recipientMetaAddress.trim() === '') {
|
|
807
|
+
return { valid: false, error: 'Recipient meta-address is required' }
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
if (!params.recipientMetaAddress.startsWith('sip:')) {
|
|
811
|
+
return {
|
|
812
|
+
valid: false,
|
|
813
|
+
error: 'Recipient must be a SIP meta-address (sip:chain:spending:viewing)',
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
if (params.amount <= BigInt(0)) {
|
|
818
|
+
return { valid: false, error: 'Amount must be greater than 0' }
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
if (!params.token || params.token.trim() === '') {
|
|
822
|
+
return { valid: false, error: 'Token mint address is required' }
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
if (params.privacyLevel === PrivacyLevel.COMPLIANT && !params.viewingKey) {
|
|
826
|
+
return {
|
|
827
|
+
valid: false,
|
|
828
|
+
error: 'Viewing key is required for compliant privacy level',
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
return { valid: true }
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
// ─── Factory Functions ─────────────────────────────────────────────────────────
|
|
837
|
+
|
|
838
|
+
/**
|
|
839
|
+
* Create a CombinedPrivacyService for devnet
|
|
840
|
+
*
|
|
841
|
+
* @param config - Optional additional configuration
|
|
842
|
+
* @returns Configured service for devnet
|
|
843
|
+
*/
|
|
844
|
+
export function createCombinedPrivacyServiceDevnet(
|
|
845
|
+
config?: Partial<CombinedPrivacyServiceConfig>
|
|
846
|
+
): CombinedPrivacyService {
|
|
847
|
+
return new CombinedPrivacyService({
|
|
848
|
+
...config,
|
|
849
|
+
rpcUrl: config?.rpcUrl ?? 'https://api.devnet.solana.com',
|
|
850
|
+
})
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
/**
|
|
854
|
+
* Create a CombinedPrivacyService for mainnet
|
|
855
|
+
*
|
|
856
|
+
* @param config - Optional additional configuration
|
|
857
|
+
* @returns Configured service for mainnet
|
|
858
|
+
*/
|
|
859
|
+
export function createCombinedPrivacyServiceMainnet(
|
|
860
|
+
config?: Partial<CombinedPrivacyServiceConfig>
|
|
861
|
+
): CombinedPrivacyService {
|
|
862
|
+
return new CombinedPrivacyService({
|
|
863
|
+
...config,
|
|
864
|
+
rpcUrl: config?.rpcUrl ?? 'https://api.mainnet-beta.solana.com',
|
|
865
|
+
})
|
|
866
|
+
}
|