@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,456 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PrivacyCash Privacy Backend
|
|
3
|
+
*
|
|
4
|
+
* Implements the PrivacyBackend interface using PrivacyCash pool mixing.
|
|
5
|
+
* PrivacyCash is a Tornado Cash-style mixer for Solana that provides
|
|
6
|
+
* anonymity through fixed-size deposit pools.
|
|
7
|
+
*
|
|
8
|
+
* ## Key Characteristics
|
|
9
|
+
*
|
|
10
|
+
* - **Pool Mixing**: Users deposit into fixed-size pools and withdraw to fresh addresses
|
|
11
|
+
* - **Anonymity Set**: Privacy comes from the number of depositors in each pool
|
|
12
|
+
* - **Fixed Amounts**: Only supports specific pool sizes (0.1, 1, 10, 100 SOL)
|
|
13
|
+
* - **No Compliance**: Does not support viewing keys or selective disclosure
|
|
14
|
+
*
|
|
15
|
+
* ## Trade-offs vs SIP Native
|
|
16
|
+
*
|
|
17
|
+
* | Feature | PrivacyCash | SIP Native |
|
|
18
|
+
* |---------|-------------|------------|
|
|
19
|
+
* | Amount hidden | No (fixed pools) | Yes (Pedersen) |
|
|
20
|
+
* | Sender hidden | Yes (pool mixing) | Yes (stealth) |
|
|
21
|
+
* | Compliance | No | Yes (viewing keys) |
|
|
22
|
+
* | Anonymity set | Yes (pool size) | No |
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* import { PrivacyCashBackend, PrivacyBackendRegistry } from '@sip-protocol/sdk'
|
|
27
|
+
*
|
|
28
|
+
* const backend = new PrivacyCashBackend({
|
|
29
|
+
* rpcUrl: 'https://api.mainnet-beta.solana.com',
|
|
30
|
+
* })
|
|
31
|
+
*
|
|
32
|
+
* const registry = new PrivacyBackendRegistry()
|
|
33
|
+
* registry.register(backend, { priority: 80 })
|
|
34
|
+
*
|
|
35
|
+
* // Check if available for 1 SOL transfer
|
|
36
|
+
* const availability = await backend.checkAvailability({
|
|
37
|
+
* chain: 'solana',
|
|
38
|
+
* sender: '...',
|
|
39
|
+
* recipient: '...',
|
|
40
|
+
* mint: null,
|
|
41
|
+
* amount: BigInt(1_000_000_000), // 1 SOL
|
|
42
|
+
* decimals: 9,
|
|
43
|
+
* })
|
|
44
|
+
*
|
|
45
|
+
* if (availability.available) {
|
|
46
|
+
* console.log(`Estimated cost: ${availability.estimatedCost}`)
|
|
47
|
+
* }
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* @see https://github.com/Privacy-Cash/privacy-cash-sdk
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
import type {
|
|
54
|
+
PrivacyBackend,
|
|
55
|
+
BackendType,
|
|
56
|
+
BackendCapabilities,
|
|
57
|
+
TransferParams,
|
|
58
|
+
TransactionResult,
|
|
59
|
+
AvailabilityResult,
|
|
60
|
+
} from './interface'
|
|
61
|
+
|
|
62
|
+
import {
|
|
63
|
+
SOL_POOL_AMOUNTS,
|
|
64
|
+
SPL_TOKEN_MINTS,
|
|
65
|
+
findNearestPoolSize,
|
|
66
|
+
isValidPoolAmount,
|
|
67
|
+
getAvailablePoolSizes,
|
|
68
|
+
type PrivacyCashSPLToken,
|
|
69
|
+
type PoolInfo,
|
|
70
|
+
type IPrivacyCashSDK,
|
|
71
|
+
} from './privacycash-types'
|
|
72
|
+
import { createPrivacyLogger } from '../privacy-logger'
|
|
73
|
+
|
|
74
|
+
/** Privacy-aware logger for PrivacyCash backend */
|
|
75
|
+
const privacyCashLogger = createPrivacyLogger('PrivacyCash')
|
|
76
|
+
|
|
77
|
+
import { randomBytes, bytesToHex } from '@noble/hashes/utils'
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Default estimated anonymity set size
|
|
81
|
+
* In production, this would be fetched from the pool
|
|
82
|
+
*/
|
|
83
|
+
const DEFAULT_ANONYMITY_SET = 50
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Estimated time for pool operations (deposit + withdrawal)
|
|
87
|
+
* Pool mixing typically requires waiting for more deposits
|
|
88
|
+
*/
|
|
89
|
+
const ESTIMATED_TIME_MS = 30000 // 30 seconds minimum
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Base cost for PrivacyCash operations (in lamports)
|
|
93
|
+
* Includes: deposit tx + withdrawal tx + relayer fee
|
|
94
|
+
*/
|
|
95
|
+
const BASE_COST_LAMPORTS = BigInt(10_000_000) // ~0.01 SOL
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Configuration options for PrivacyCash backend
|
|
99
|
+
*/
|
|
100
|
+
export interface PrivacyCashBackendConfig {
|
|
101
|
+
/** Solana RPC endpoint URL */
|
|
102
|
+
rpcUrl?: string
|
|
103
|
+
/** Network type */
|
|
104
|
+
network?: 'mainnet-beta' | 'devnet'
|
|
105
|
+
/** Relayer URL for withdrawals */
|
|
106
|
+
relayerUrl?: string
|
|
107
|
+
/** Minimum anonymity set required for withdrawals */
|
|
108
|
+
minAnonymitySet?: number
|
|
109
|
+
/** Custom SDK instance (for testing) */
|
|
110
|
+
sdk?: IPrivacyCashSDK
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* PrivacyCash capabilities (static)
|
|
115
|
+
*/
|
|
116
|
+
const PRIVACYCASH_CAPABILITIES: BackendCapabilities = {
|
|
117
|
+
hiddenAmount: false, // Fixed pool sizes, amount is known
|
|
118
|
+
hiddenSender: true, // Pool mixing hides sender
|
|
119
|
+
hiddenRecipient: true, // Withdrawal to fresh address
|
|
120
|
+
hiddenCompute: false, // No compute privacy
|
|
121
|
+
complianceSupport: false, // No viewing keys
|
|
122
|
+
anonymitySet: DEFAULT_ANONYMITY_SET,
|
|
123
|
+
setupRequired: false, // No setup needed
|
|
124
|
+
latencyEstimate: 'medium', // Need to wait for pool
|
|
125
|
+
supportedTokens: 'all', // SOL + USDC/USDT
|
|
126
|
+
minAmount: SOL_POOL_AMOUNTS[0], // Smallest pool
|
|
127
|
+
maxAmount: SOL_POOL_AMOUNTS[SOL_POOL_AMOUNTS.length - 1], // Largest pool
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* PrivacyCash Privacy Backend
|
|
132
|
+
*
|
|
133
|
+
* Uses pool mixing for transaction privacy on Solana.
|
|
134
|
+
* Integrates with the PrivacyCash protocol as an alternative
|
|
135
|
+
* to SIP Native's cryptographic approach.
|
|
136
|
+
*/
|
|
137
|
+
export class PrivacyCashBackend implements PrivacyBackend {
|
|
138
|
+
readonly name = 'privacycash'
|
|
139
|
+
readonly type: BackendType = 'transaction'
|
|
140
|
+
readonly chains: string[] = ['solana']
|
|
141
|
+
|
|
142
|
+
private config: Required<Omit<PrivacyCashBackendConfig, 'sdk'>> & {
|
|
143
|
+
sdk?: IPrivacyCashSDK
|
|
144
|
+
}
|
|
145
|
+
private poolCache: Map<string, PoolInfo> = new Map()
|
|
146
|
+
private poolCacheExpiry: Map<string, number> = new Map()
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Create a new PrivacyCash backend
|
|
150
|
+
*
|
|
151
|
+
* @param config - Backend configuration
|
|
152
|
+
*/
|
|
153
|
+
constructor(config: PrivacyCashBackendConfig = {}) {
|
|
154
|
+
this.config = {
|
|
155
|
+
rpcUrl: config.rpcUrl ?? 'https://api.mainnet-beta.solana.com',
|
|
156
|
+
network: config.network ?? 'mainnet-beta',
|
|
157
|
+
relayerUrl: config.relayerUrl ?? 'https://relayer.privacycash.org',
|
|
158
|
+
minAnonymitySet: config.minAnonymitySet ?? 5,
|
|
159
|
+
sdk: config.sdk,
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Check if backend is available for given parameters
|
|
165
|
+
*/
|
|
166
|
+
async checkAvailability(params: TransferParams): Promise<AvailabilityResult> {
|
|
167
|
+
// Validate amount is non-negative
|
|
168
|
+
if (params.amount < BigInt(0)) {
|
|
169
|
+
return {
|
|
170
|
+
available: false,
|
|
171
|
+
reason: 'Amount cannot be negative',
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Only supports Solana
|
|
176
|
+
if (params.chain !== 'solana') {
|
|
177
|
+
return {
|
|
178
|
+
available: false,
|
|
179
|
+
reason: `PrivacyCash only supports Solana, not '${params.chain}'`,
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Determine if this is SOL or SPL token
|
|
184
|
+
const isSOL = params.mint === null
|
|
185
|
+
const isSupportedSPL = params.mint
|
|
186
|
+
? this.isSupportedSPLToken(params.mint)
|
|
187
|
+
: false
|
|
188
|
+
|
|
189
|
+
if (!isSOL && !isSupportedSPL) {
|
|
190
|
+
return {
|
|
191
|
+
available: false,
|
|
192
|
+
reason: params.mint
|
|
193
|
+
? `Token ${params.mint} not supported. PrivacyCash supports SOL, USDC, and USDT only.`
|
|
194
|
+
: 'Invalid token configuration',
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Check if amount matches a pool size
|
|
199
|
+
if (!isValidPoolAmount(params.amount, isSOL)) {
|
|
200
|
+
const nearestPool = findNearestPoolSize(params.amount, isSOL)
|
|
201
|
+
const availablePools = getAvailablePoolSizes(isSOL)
|
|
202
|
+
.map(p => this.formatAmount(p, params.decimals))
|
|
203
|
+
.join(', ')
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
available: false,
|
|
207
|
+
reason:
|
|
208
|
+
`Amount must match a pool size. ` +
|
|
209
|
+
`Nearest pool: ${this.formatAmount(nearestPool, params.decimals)}. ` +
|
|
210
|
+
`Available pools: ${availablePools}`,
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Check pool liquidity (in production, query actual pool)
|
|
215
|
+
const poolInfo = await this.getPoolInfo(params.amount, isSOL ? undefined : this.getSPLToken(params.mint!))
|
|
216
|
+
|
|
217
|
+
if (poolInfo.depositors < this.config.minAnonymitySet) {
|
|
218
|
+
return {
|
|
219
|
+
available: false,
|
|
220
|
+
reason:
|
|
221
|
+
`Pool anonymity set (${poolInfo.depositors}) below minimum (${this.config.minAnonymitySet}). ` +
|
|
222
|
+
`Wait for more deposits or use a different pool.`,
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Viewing keys are not supported - warn if provided
|
|
227
|
+
if (params.viewingKey) {
|
|
228
|
+
privacyCashLogger.warn(
|
|
229
|
+
'Viewing keys are not supported. Use SIP Native backend for compliance features.'
|
|
230
|
+
)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return {
|
|
234
|
+
available: true,
|
|
235
|
+
estimatedCost: this.estimateCostForTransfer(params),
|
|
236
|
+
estimatedTime: ESTIMATED_TIME_MS,
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Get backend capabilities
|
|
242
|
+
*/
|
|
243
|
+
getCapabilities(): BackendCapabilities {
|
|
244
|
+
return {
|
|
245
|
+
...PRIVACYCASH_CAPABILITIES,
|
|
246
|
+
// Dynamic anonymity set from cache if available
|
|
247
|
+
anonymitySet: this.getAverageAnonymitySet(),
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Execute a privacy-preserving transfer via pool mixing
|
|
253
|
+
*
|
|
254
|
+
* This performs a two-step process:
|
|
255
|
+
* 1. Deposit into the matching pool (returns a secret note)
|
|
256
|
+
* 2. Withdraw to recipient address (using the note)
|
|
257
|
+
*
|
|
258
|
+
* For production use, the note should be stored securely
|
|
259
|
+
* and withdrawal can happen later.
|
|
260
|
+
*/
|
|
261
|
+
async execute(params: TransferParams): Promise<TransactionResult> {
|
|
262
|
+
// Validate availability first
|
|
263
|
+
const availability = await this.checkAvailability(params)
|
|
264
|
+
if (!availability.available) {
|
|
265
|
+
return {
|
|
266
|
+
success: false,
|
|
267
|
+
error: availability.reason,
|
|
268
|
+
backend: this.name,
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
try {
|
|
273
|
+
const isSOL = params.mint === null
|
|
274
|
+
|
|
275
|
+
// In a real implementation with the SDK:
|
|
276
|
+
// 1. const depositResult = await this.sdk.deposit({ amount, wallet })
|
|
277
|
+
// 2. Store depositResult.note securely
|
|
278
|
+
// 3. const withdrawResult = await this.sdk.withdraw({ amount, recipient, note })
|
|
279
|
+
|
|
280
|
+
// Simulated result for now (SDK requires Node 24+)
|
|
281
|
+
const simulatedNote = this.generateSimulatedNote()
|
|
282
|
+
const simulatedSignature = `pc_${Date.now()}_${Math.random().toString(36).slice(2)}`
|
|
283
|
+
|
|
284
|
+
return {
|
|
285
|
+
success: true,
|
|
286
|
+
signature: simulatedSignature,
|
|
287
|
+
backend: this.name,
|
|
288
|
+
metadata: {
|
|
289
|
+
poolSize: params.amount.toString(),
|
|
290
|
+
isSOL,
|
|
291
|
+
token: isSOL ? 'SOL' : this.getSPLToken(params.mint!),
|
|
292
|
+
note: simulatedNote, // In production, this is the withdrawal proof
|
|
293
|
+
anonymitySet: await this.getPoolAnonymitySet(params.amount, isSOL, params.mint),
|
|
294
|
+
timestamp: Date.now(),
|
|
295
|
+
warning: 'Simulated result - SDK integration pending',
|
|
296
|
+
},
|
|
297
|
+
}
|
|
298
|
+
} catch (error) {
|
|
299
|
+
return {
|
|
300
|
+
success: false,
|
|
301
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
302
|
+
backend: this.name,
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Estimate cost for a transfer
|
|
309
|
+
*/
|
|
310
|
+
async estimateCost(params: TransferParams): Promise<bigint> {
|
|
311
|
+
return this.estimateCostForTransfer(params)
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// ─── Private Methods ─────────────────────────────────────────────────────────
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Check if a mint address is a supported SPL token
|
|
318
|
+
*/
|
|
319
|
+
private isSupportedSPLToken(mint: string): boolean {
|
|
320
|
+
return Object.values(SPL_TOKEN_MINTS).includes(mint)
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Get SPL token type from mint address
|
|
325
|
+
*/
|
|
326
|
+
private getSPLToken(mint: string): PrivacyCashSPLToken | undefined {
|
|
327
|
+
for (const [token, address] of Object.entries(SPL_TOKEN_MINTS)) {
|
|
328
|
+
if (address === mint) {
|
|
329
|
+
return token as PrivacyCashSPLToken
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return undefined
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Format amount for display
|
|
337
|
+
*/
|
|
338
|
+
private formatAmount(amount: bigint, decimals: number): string {
|
|
339
|
+
const divisor = BigInt(10 ** decimals)
|
|
340
|
+
const whole = amount / divisor
|
|
341
|
+
const fraction = amount % divisor
|
|
342
|
+
if (fraction === BigInt(0)) {
|
|
343
|
+
return whole.toString()
|
|
344
|
+
}
|
|
345
|
+
return `${whole}.${fraction.toString().padStart(decimals, '0').replace(/0+$/, '')}`
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Estimate cost for a transfer
|
|
350
|
+
*/
|
|
351
|
+
private estimateCostForTransfer(params: TransferParams): bigint {
|
|
352
|
+
// Base cost for deposit + withdrawal transactions
|
|
353
|
+
let cost = BASE_COST_LAMPORTS
|
|
354
|
+
|
|
355
|
+
// SPL token transfers have additional account rent
|
|
356
|
+
if (params.mint !== null) {
|
|
357
|
+
cost += BigInt(2_000_000) // ~0.002 SOL for token accounts
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Relayer fee (typically 0.1% of amount, min 0.001 SOL)
|
|
361
|
+
const relayerFee = params.amount / BigInt(1000)
|
|
362
|
+
const minRelayerFee = BigInt(1_000_000)
|
|
363
|
+
cost += relayerFee > minRelayerFee ? relayerFee : minRelayerFee
|
|
364
|
+
|
|
365
|
+
return cost
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Get pool information (mocked for now)
|
|
370
|
+
*/
|
|
371
|
+
private async getPoolInfo(
|
|
372
|
+
amount: bigint,
|
|
373
|
+
token?: PrivacyCashSPLToken
|
|
374
|
+
): Promise<PoolInfo> {
|
|
375
|
+
const cacheKey = `${amount.toString()}-${token ?? 'SOL'}`
|
|
376
|
+
|
|
377
|
+
// Check cache
|
|
378
|
+
const cached = this.poolCache.get(cacheKey)
|
|
379
|
+
const expiry = this.poolCacheExpiry.get(cacheKey)
|
|
380
|
+
if (cached && expiry && Date.now() < expiry) {
|
|
381
|
+
return cached
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// In production, query the actual pool:
|
|
385
|
+
// const poolInfo = await this.config.sdk?.getPoolInfo(amount, token)
|
|
386
|
+
|
|
387
|
+
// Simulated pool info based on pool size
|
|
388
|
+
// Larger pools typically have more depositors
|
|
389
|
+
const baseDepositors = token ? 30 : 50
|
|
390
|
+
const sizeMultiplier = Number(amount / BigInt(100_000_000))
|
|
391
|
+
const depositors = Math.max(
|
|
392
|
+
10,
|
|
393
|
+
baseDepositors + Math.floor(Math.random() * 20) - Math.floor(sizeMultiplier / 10)
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
const poolInfo: PoolInfo = {
|
|
397
|
+
size: amount,
|
|
398
|
+
depositors,
|
|
399
|
+
liquidity: amount * BigInt(depositors),
|
|
400
|
+
withdrawable: depositors >= this.config.minAnonymitySet,
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// Cache for 60 seconds
|
|
404
|
+
this.poolCache.set(cacheKey, poolInfo)
|
|
405
|
+
this.poolCacheExpiry.set(cacheKey, Date.now() + 60000)
|
|
406
|
+
|
|
407
|
+
return poolInfo
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Get anonymity set for a specific pool
|
|
412
|
+
*/
|
|
413
|
+
private async getPoolAnonymitySet(
|
|
414
|
+
amount: bigint,
|
|
415
|
+
isSOL: boolean,
|
|
416
|
+
mint?: string | null
|
|
417
|
+
): Promise<number> {
|
|
418
|
+
const token = isSOL ? undefined : (mint ? this.getSPLToken(mint) : undefined)
|
|
419
|
+
const poolInfo = await this.getPoolInfo(amount, token)
|
|
420
|
+
return poolInfo.depositors
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Get average anonymity set across cached pools
|
|
425
|
+
*/
|
|
426
|
+
private getAverageAnonymitySet(): number {
|
|
427
|
+
if (this.poolCache.size === 0) {
|
|
428
|
+
return DEFAULT_ANONYMITY_SET
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
let total = 0
|
|
432
|
+
for (const pool of this.poolCache.values()) {
|
|
433
|
+
total += pool.depositors
|
|
434
|
+
}
|
|
435
|
+
return Math.round(total / this.poolCache.size)
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Generate a simulated withdrawal note
|
|
440
|
+
*
|
|
441
|
+
* Uses cryptographically secure random bytes.
|
|
442
|
+
* In production, this comes from the deposit transaction.
|
|
443
|
+
*/
|
|
444
|
+
private generateSimulatedNote(): string {
|
|
445
|
+
const bytes = randomBytes(32)
|
|
446
|
+
return `privacycash:${bytesToHex(bytes)}`
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Clear pool cache
|
|
451
|
+
*/
|
|
452
|
+
clearPoolCache(): void {
|
|
453
|
+
this.poolCache.clear()
|
|
454
|
+
this.poolCacheExpiry.clear()
|
|
455
|
+
}
|
|
456
|
+
}
|