@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,571 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Jupiter DEX Adapter for SIP Protocol
|
|
3
|
+
*
|
|
4
|
+
* Enables privacy-preserving token swaps on Solana via Jupiter aggregator.
|
|
5
|
+
* SIP adds stealth addresses for recipient privacy and viewing keys for compliance.
|
|
6
|
+
*
|
|
7
|
+
* ## Privacy Model
|
|
8
|
+
*
|
|
9
|
+
* Jupiter swaps are on-chain and transparent by default. SIP enhances privacy by:
|
|
10
|
+
* - Sending output tokens to a stealth address (recipient unlinkable)
|
|
11
|
+
* - Encrypting swap metadata with viewing keys (selective disclosure)
|
|
12
|
+
*
|
|
13
|
+
* ```
|
|
14
|
+
* ┌──────────────────────────────────────────────────────────────┐
|
|
15
|
+
* │ JUPITER + SIP PRIVACY FLOW │
|
|
16
|
+
* │ │
|
|
17
|
+
* │ 1. User: "Swap 1 SOL → USDC privately" │
|
|
18
|
+
* │ 2. SIP: Generate stealth address for USDC output │
|
|
19
|
+
* │ 3. Jupiter: Get quote, find best route │
|
|
20
|
+
* │ 4. Jupiter: Execute swap → output to stealth address │
|
|
21
|
+
* │ 5. SIP: Encrypt metadata with viewing key (compliance) │
|
|
22
|
+
* │ │
|
|
23
|
+
* │ Result: Swap on-chain, but recipient unlinkable │
|
|
24
|
+
* └──────────────────────────────────────────────────────────────┘
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @see https://station.jup.ag/docs
|
|
28
|
+
* @see https://github.com/jup-ag/jupiter-quote-api-node
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* import { JupiterAdapter } from '@sip-protocol/sdk'
|
|
33
|
+
* import { Keypair } from '@solana/web3.js'
|
|
34
|
+
*
|
|
35
|
+
* const adapter = new JupiterAdapter({
|
|
36
|
+
* rpcUrl: 'https://api.mainnet-beta.solana.com',
|
|
37
|
+
* })
|
|
38
|
+
*
|
|
39
|
+
* // Get a quote
|
|
40
|
+
* const quote = await adapter.getQuote({
|
|
41
|
+
* inputMint: 'So11111111111111111111111111111111111111112', // SOL
|
|
42
|
+
* outputMint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC
|
|
43
|
+
* amount: 1_000_000_000n, // 1 SOL
|
|
44
|
+
* })
|
|
45
|
+
*
|
|
46
|
+
* // Execute private swap (output to stealth address)
|
|
47
|
+
* const result = await adapter.swapPrivate({
|
|
48
|
+
* quote,
|
|
49
|
+
* wallet: userKeypair,
|
|
50
|
+
* recipientMetaAddress: 'sip:solana:0x...:0x...',
|
|
51
|
+
* })
|
|
52
|
+
*
|
|
53
|
+
* console.log('Swap complete:', result.signature)
|
|
54
|
+
* console.log('Output at stealth address:', result.stealthAddress)
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
import { createJupiterApiClient, type QuoteResponse } from '@jup-ag/api'
|
|
59
|
+
import {
|
|
60
|
+
Connection,
|
|
61
|
+
PublicKey,
|
|
62
|
+
VersionedTransaction,
|
|
63
|
+
type Keypair,
|
|
64
|
+
} from '@solana/web3.js'
|
|
65
|
+
import type { StealthMetaAddress, HexString, ViewingKey } from '@sip-protocol/types'
|
|
66
|
+
import {
|
|
67
|
+
generateEd25519StealthAddress,
|
|
68
|
+
decodeStealthMetaAddress,
|
|
69
|
+
ed25519PublicKeyToSolanaAddress,
|
|
70
|
+
} from '../stealth'
|
|
71
|
+
import { generateViewingKey, encryptForViewing, type TransactionData } from '../privacy'
|
|
72
|
+
import { bytesToHex } from '@noble/hashes/utils'
|
|
73
|
+
|
|
74
|
+
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Common Solana token mints
|
|
78
|
+
*/
|
|
79
|
+
export const SOLANA_TOKEN_MINTS = {
|
|
80
|
+
SOL: 'So11111111111111111111111111111111111111112',
|
|
81
|
+
USDC: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
|
|
82
|
+
USDT: 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',
|
|
83
|
+
BONK: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263',
|
|
84
|
+
JUP: 'JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN',
|
|
85
|
+
RAY: '4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R',
|
|
86
|
+
ORCA: 'orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE',
|
|
87
|
+
} as const
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Default Jupiter API endpoint
|
|
91
|
+
*/
|
|
92
|
+
export const JUPITER_API_ENDPOINT = 'https://quote-api.jup.ag/v6'
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Default RPC endpoints
|
|
96
|
+
*/
|
|
97
|
+
export const SOLANA_RPC_ENDPOINTS = {
|
|
98
|
+
mainnet: 'https://api.mainnet-beta.solana.com',
|
|
99
|
+
devnet: 'https://api.devnet.solana.com',
|
|
100
|
+
} as const
|
|
101
|
+
|
|
102
|
+
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Jupiter adapter configuration
|
|
106
|
+
*/
|
|
107
|
+
export interface JupiterAdapterConfig {
|
|
108
|
+
/** Solana RPC URL */
|
|
109
|
+
rpcUrl?: string
|
|
110
|
+
/** Jupiter API key (optional, for higher rate limits) */
|
|
111
|
+
apiKey?: string
|
|
112
|
+
/** Default slippage in basis points (default: 50 = 0.5%) */
|
|
113
|
+
defaultSlippageBps?: number
|
|
114
|
+
/** Enable debug logging */
|
|
115
|
+
debug?: boolean
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Quote request parameters
|
|
120
|
+
*/
|
|
121
|
+
export interface JupiterQuoteRequest {
|
|
122
|
+
/** Input token mint address */
|
|
123
|
+
inputMint: string
|
|
124
|
+
/** Output token mint address */
|
|
125
|
+
outputMint: string
|
|
126
|
+
/** Input amount in smallest units (lamports for SOL) */
|
|
127
|
+
amount: bigint
|
|
128
|
+
/** Slippage tolerance in basis points (overrides default) */
|
|
129
|
+
slippageBps?: number
|
|
130
|
+
/** Only use direct routes (no multi-hop) */
|
|
131
|
+
onlyDirectRoutes?: boolean
|
|
132
|
+
/** Exclude specific DEXes */
|
|
133
|
+
excludeDexes?: string[]
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Enhanced quote with SIP metadata
|
|
138
|
+
*/
|
|
139
|
+
export interface JupiterQuote {
|
|
140
|
+
/** Raw Jupiter quote response */
|
|
141
|
+
raw: QuoteResponse
|
|
142
|
+
/** Input mint */
|
|
143
|
+
inputMint: string
|
|
144
|
+
/** Output mint */
|
|
145
|
+
outputMint: string
|
|
146
|
+
/** Input amount */
|
|
147
|
+
inputAmount: bigint
|
|
148
|
+
/** Expected output amount */
|
|
149
|
+
outputAmount: bigint
|
|
150
|
+
/** Minimum output after slippage */
|
|
151
|
+
minOutputAmount: bigint
|
|
152
|
+
/** Price impact percentage */
|
|
153
|
+
priceImpactPct: number
|
|
154
|
+
/** Route description */
|
|
155
|
+
route: string[]
|
|
156
|
+
/** Slippage in basis points */
|
|
157
|
+
slippageBps: number
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Standard swap parameters (transparent)
|
|
162
|
+
*/
|
|
163
|
+
export interface JupiterSwapParams {
|
|
164
|
+
/** Quote from getQuote() */
|
|
165
|
+
quote: JupiterQuote
|
|
166
|
+
/** User's wallet keypair for signing */
|
|
167
|
+
wallet: Keypair
|
|
168
|
+
/** Recipient address (defaults to wallet public key) */
|
|
169
|
+
recipient?: string
|
|
170
|
+
/** Priority fee in lamports (or 'auto') */
|
|
171
|
+
priorityFee?: number | 'auto'
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Private swap parameters (with stealth address)
|
|
176
|
+
*/
|
|
177
|
+
export interface JupiterPrivateSwapParams extends Omit<JupiterSwapParams, 'recipient'> {
|
|
178
|
+
/** Recipient's stealth meta-address */
|
|
179
|
+
recipientMetaAddress: StealthMetaAddress | string
|
|
180
|
+
/** Generate viewing key for compliance */
|
|
181
|
+
generateViewingKey?: boolean
|
|
182
|
+
/** Existing viewing key to use */
|
|
183
|
+
viewingKey?: ViewingKey
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Swap result
|
|
188
|
+
*/
|
|
189
|
+
export interface JupiterSwapResult {
|
|
190
|
+
/** Whether swap succeeded */
|
|
191
|
+
success: boolean
|
|
192
|
+
/** Transaction signature */
|
|
193
|
+
signature?: string
|
|
194
|
+
/** Input amount swapped */
|
|
195
|
+
inputAmount?: bigint
|
|
196
|
+
/** Output amount received */
|
|
197
|
+
outputAmount?: bigint
|
|
198
|
+
/** Recipient address */
|
|
199
|
+
recipient?: string
|
|
200
|
+
/** Error message if failed */
|
|
201
|
+
error?: string
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Private swap result (with stealth data)
|
|
206
|
+
*/
|
|
207
|
+
export interface JupiterPrivateSwapResult extends JupiterSwapResult {
|
|
208
|
+
/** Stealth address where output was sent */
|
|
209
|
+
stealthAddress?: string
|
|
210
|
+
/** Ephemeral public key for recipient to derive stealth key */
|
|
211
|
+
ephemeralPublicKey?: HexString
|
|
212
|
+
/** View tag for efficient scanning */
|
|
213
|
+
viewTag?: number
|
|
214
|
+
/** Shared secret (for recipient to derive private key) */
|
|
215
|
+
sharedSecret?: HexString
|
|
216
|
+
/** Encrypted metadata for viewing key holders */
|
|
217
|
+
encryptedMetadata?: HexString
|
|
218
|
+
/** Viewing key (if generated) */
|
|
219
|
+
viewingKey?: ViewingKey
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// ─── Jupiter Adapter ──────────────────────────────────────────────────────────
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Jupiter DEX Adapter
|
|
226
|
+
*
|
|
227
|
+
* Provides privacy-enhanced token swaps on Solana via Jupiter aggregator.
|
|
228
|
+
*/
|
|
229
|
+
export class JupiterAdapter {
|
|
230
|
+
private readonly connection: Connection
|
|
231
|
+
private readonly jupiterApi: ReturnType<typeof createJupiterApiClient>
|
|
232
|
+
private readonly defaultSlippageBps: number
|
|
233
|
+
private readonly debug: boolean
|
|
234
|
+
|
|
235
|
+
constructor(config: JupiterAdapterConfig = {}) {
|
|
236
|
+
const rpcUrl = config.rpcUrl ?? SOLANA_RPC_ENDPOINTS.mainnet
|
|
237
|
+
this.connection = new Connection(rpcUrl, 'confirmed')
|
|
238
|
+
|
|
239
|
+
// Initialize Jupiter API client
|
|
240
|
+
// Note: apiKey is passed if available for higher rate limits
|
|
241
|
+
this.jupiterApi = createJupiterApiClient()
|
|
242
|
+
|
|
243
|
+
this.defaultSlippageBps = config.defaultSlippageBps ?? 50 // 0.5%
|
|
244
|
+
this.debug = config.debug ?? false
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// ─── Quote Methods ────────────────────────────────────────────────────────────
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Get a swap quote from Jupiter
|
|
251
|
+
*
|
|
252
|
+
* @param request - Quote request parameters
|
|
253
|
+
* @returns Quote with routing info
|
|
254
|
+
*/
|
|
255
|
+
async getQuote(request: JupiterQuoteRequest): Promise<JupiterQuote> {
|
|
256
|
+
this.log('Getting quote:', request)
|
|
257
|
+
|
|
258
|
+
const slippageBps = request.slippageBps ?? this.defaultSlippageBps
|
|
259
|
+
|
|
260
|
+
// Jupiter API requires amount as number
|
|
261
|
+
const amount = Number(request.amount)
|
|
262
|
+
if (!Number.isSafeInteger(amount)) {
|
|
263
|
+
throw new Error('Amount too large for Jupiter API')
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const quoteResponse = await this.jupiterApi.quoteGet({
|
|
267
|
+
inputMint: request.inputMint,
|
|
268
|
+
outputMint: request.outputMint,
|
|
269
|
+
amount,
|
|
270
|
+
slippageBps,
|
|
271
|
+
onlyDirectRoutes: request.onlyDirectRoutes,
|
|
272
|
+
excludeDexes: request.excludeDexes,
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
if (!quoteResponse) {
|
|
276
|
+
throw new Error('Failed to get quote from Jupiter')
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Extract route names
|
|
280
|
+
const route = quoteResponse.routePlan?.map(step => step.swapInfo?.label ?? 'Unknown') ?? []
|
|
281
|
+
|
|
282
|
+
const quote: JupiterQuote = {
|
|
283
|
+
raw: quoteResponse,
|
|
284
|
+
inputMint: quoteResponse.inputMint,
|
|
285
|
+
outputMint: quoteResponse.outputMint,
|
|
286
|
+
inputAmount: BigInt(quoteResponse.inAmount),
|
|
287
|
+
outputAmount: BigInt(quoteResponse.outAmount),
|
|
288
|
+
minOutputAmount: BigInt(quoteResponse.otherAmountThreshold),
|
|
289
|
+
priceImpactPct: parseFloat(quoteResponse.priceImpactPct ?? '0'),
|
|
290
|
+
route,
|
|
291
|
+
slippageBps,
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
this.log('Quote received:', {
|
|
295
|
+
inputAmount: quote.inputAmount.toString(),
|
|
296
|
+
outputAmount: quote.outputAmount.toString(),
|
|
297
|
+
route: quote.route,
|
|
298
|
+
})
|
|
299
|
+
|
|
300
|
+
return quote
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// ─── Swap Methods ─────────────────────────────────────────────────────────────
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Execute a standard (transparent) swap
|
|
307
|
+
*
|
|
308
|
+
* @param params - Swap parameters
|
|
309
|
+
* @returns Swap result
|
|
310
|
+
*/
|
|
311
|
+
async swap(params: JupiterSwapParams): Promise<JupiterSwapResult> {
|
|
312
|
+
this.log('Executing swap')
|
|
313
|
+
|
|
314
|
+
try {
|
|
315
|
+
const recipient = params.recipient ?? params.wallet.publicKey.toBase58()
|
|
316
|
+
|
|
317
|
+
// Get swap transaction from Jupiter
|
|
318
|
+
// Note: prioritizationFeeLamports requires specific object format
|
|
319
|
+
const priorityFeeConfig = params.priorityFee === 'auto'
|
|
320
|
+
? { priorityLevelWithMaxLamports: { priorityLevel: 'high' as const, maxLamports: 1000000 } }
|
|
321
|
+
: typeof params.priorityFee === 'number'
|
|
322
|
+
? { jitoTipLamports: params.priorityFee }
|
|
323
|
+
: undefined
|
|
324
|
+
|
|
325
|
+
const swapResponse = await this.jupiterApi.swapPost({
|
|
326
|
+
swapRequest: {
|
|
327
|
+
quoteResponse: params.quote.raw,
|
|
328
|
+
userPublicKey: params.wallet.publicKey.toBase58(),
|
|
329
|
+
destinationTokenAccount: recipient !== params.wallet.publicKey.toBase58()
|
|
330
|
+
? recipient
|
|
331
|
+
: undefined,
|
|
332
|
+
prioritizationFeeLamports: priorityFeeConfig,
|
|
333
|
+
},
|
|
334
|
+
})
|
|
335
|
+
|
|
336
|
+
// Deserialize and sign transaction
|
|
337
|
+
const swapTransactionBuf = Buffer.from(swapResponse.swapTransaction, 'base64')
|
|
338
|
+
const transaction = VersionedTransaction.deserialize(swapTransactionBuf)
|
|
339
|
+
transaction.sign([params.wallet])
|
|
340
|
+
|
|
341
|
+
// Send transaction
|
|
342
|
+
const signature = await this.connection.sendRawTransaction(
|
|
343
|
+
transaction.serialize(),
|
|
344
|
+
{
|
|
345
|
+
skipPreflight: false,
|
|
346
|
+
maxRetries: 3,
|
|
347
|
+
}
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
this.log('Transaction sent:', signature)
|
|
351
|
+
|
|
352
|
+
// Confirm transaction
|
|
353
|
+
const latestBlockhash = await this.connection.getLatestBlockhash()
|
|
354
|
+
await this.connection.confirmTransaction({
|
|
355
|
+
signature,
|
|
356
|
+
blockhash: latestBlockhash.blockhash,
|
|
357
|
+
lastValidBlockHeight: latestBlockhash.lastValidBlockHeight,
|
|
358
|
+
}, 'confirmed')
|
|
359
|
+
|
|
360
|
+
this.log('Transaction confirmed')
|
|
361
|
+
|
|
362
|
+
return {
|
|
363
|
+
success: true,
|
|
364
|
+
signature,
|
|
365
|
+
inputAmount: params.quote.inputAmount,
|
|
366
|
+
outputAmount: params.quote.outputAmount,
|
|
367
|
+
recipient,
|
|
368
|
+
}
|
|
369
|
+
} catch (error) {
|
|
370
|
+
return {
|
|
371
|
+
success: false,
|
|
372
|
+
error: this.formatError(error),
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Execute a private swap with stealth recipient
|
|
379
|
+
*
|
|
380
|
+
* Output tokens are sent to a stealth address derived from the recipient's
|
|
381
|
+
* meta-address. The recipient can later claim using their spending key.
|
|
382
|
+
*
|
|
383
|
+
* @param params - Private swap parameters
|
|
384
|
+
* @returns Private swap result with stealth data
|
|
385
|
+
*/
|
|
386
|
+
async swapPrivate(params: JupiterPrivateSwapParams): Promise<JupiterPrivateSwapResult> {
|
|
387
|
+
this.log('Executing private swap')
|
|
388
|
+
|
|
389
|
+
try {
|
|
390
|
+
// Decode meta-address if string
|
|
391
|
+
const metaAddress = typeof params.recipientMetaAddress === 'string'
|
|
392
|
+
? decodeStealthMetaAddress(params.recipientMetaAddress)
|
|
393
|
+
: params.recipientMetaAddress
|
|
394
|
+
|
|
395
|
+
// Validate ed25519 keys (Solana uses ed25519)
|
|
396
|
+
const spendingKeyBytes = (metaAddress.spendingKey.length - 2) / 2
|
|
397
|
+
if (spendingKeyBytes !== 32) {
|
|
398
|
+
return {
|
|
399
|
+
success: false,
|
|
400
|
+
error: `Meta-address has ${spendingKeyBytes}-byte keys but Solana requires ed25519 (32-byte) keys. ` +
|
|
401
|
+
'Generate an ed25519 meta-address using generateEd25519StealthMetaAddress().',
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Generate stealth address
|
|
406
|
+
const { stealthAddress, sharedSecret } = generateEd25519StealthAddress(metaAddress)
|
|
407
|
+
|
|
408
|
+
// Convert stealth public key to Solana address
|
|
409
|
+
const solanaStealthAddress = ed25519PublicKeyToSolanaAddress(stealthAddress.address)
|
|
410
|
+
|
|
411
|
+
this.log('Generated stealth address:', solanaStealthAddress)
|
|
412
|
+
|
|
413
|
+
// Execute swap with stealth address as recipient
|
|
414
|
+
const swapResult = await this.swap({
|
|
415
|
+
...params,
|
|
416
|
+
recipient: solanaStealthAddress,
|
|
417
|
+
})
|
|
418
|
+
|
|
419
|
+
if (!swapResult.success) {
|
|
420
|
+
return {
|
|
421
|
+
...swapResult,
|
|
422
|
+
stealthAddress: solanaStealthAddress,
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Prepare result with stealth data
|
|
427
|
+
const result: JupiterPrivateSwapResult = {
|
|
428
|
+
...swapResult,
|
|
429
|
+
stealthAddress: solanaStealthAddress,
|
|
430
|
+
ephemeralPublicKey: stealthAddress.ephemeralPublicKey,
|
|
431
|
+
viewTag: stealthAddress.viewTag,
|
|
432
|
+
sharedSecret,
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// Generate viewing key and encrypt metadata if requested
|
|
436
|
+
if (params.generateViewingKey || params.viewingKey) {
|
|
437
|
+
const viewingKey = params.viewingKey ?? generateViewingKey()
|
|
438
|
+
|
|
439
|
+
// TransactionData requires sender, recipient, amount, timestamp
|
|
440
|
+
// We encode additional swap metadata in the amount field as JSON
|
|
441
|
+
const swapMetadata = JSON.stringify({
|
|
442
|
+
type: 'jupiter_private_swap',
|
|
443
|
+
signature: swapResult.signature,
|
|
444
|
+
inputMint: params.quote.inputMint,
|
|
445
|
+
outputMint: params.quote.outputMint,
|
|
446
|
+
inputAmount: params.quote.inputAmount.toString(),
|
|
447
|
+
outputAmount: params.quote.outputAmount.toString(),
|
|
448
|
+
ephemeralPublicKey: stealthAddress.ephemeralPublicKey,
|
|
449
|
+
})
|
|
450
|
+
|
|
451
|
+
const txData: TransactionData = {
|
|
452
|
+
sender: params.wallet.publicKey.toBase58(),
|
|
453
|
+
recipient: solanaStealthAddress,
|
|
454
|
+
amount: swapMetadata, // Encode metadata in amount field
|
|
455
|
+
timestamp: Date.now(),
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
const encrypted = encryptForViewing(txData, viewingKey)
|
|
459
|
+
const jsonBytes = new TextEncoder().encode(JSON.stringify(encrypted))
|
|
460
|
+
result.encryptedMetadata = `0x${bytesToHex(jsonBytes)}` as HexString
|
|
461
|
+
|
|
462
|
+
if (params.generateViewingKey) {
|
|
463
|
+
result.viewingKey = viewingKey
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
return result
|
|
468
|
+
} catch (error) {
|
|
469
|
+
return {
|
|
470
|
+
success: false,
|
|
471
|
+
error: this.formatError(error),
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// ─── Utility Methods ──────────────────────────────────────────────────────────
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Check if a token is supported by Jupiter
|
|
480
|
+
*
|
|
481
|
+
* @param mint - Token mint address
|
|
482
|
+
* @returns Whether token is tradeable
|
|
483
|
+
*/
|
|
484
|
+
async isTokenSupported(mint: string): Promise<boolean> {
|
|
485
|
+
try {
|
|
486
|
+
// Try to get a small quote to SOL
|
|
487
|
+
const quote = await this.jupiterApi.quoteGet({
|
|
488
|
+
inputMint: mint,
|
|
489
|
+
outputMint: SOLANA_TOKEN_MINTS.SOL,
|
|
490
|
+
amount: 1000000, // 0.001 of any token (6 decimals)
|
|
491
|
+
slippageBps: 100,
|
|
492
|
+
})
|
|
493
|
+
return !!quote
|
|
494
|
+
} catch {
|
|
495
|
+
return false
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Get the underlying Solana connection
|
|
501
|
+
*/
|
|
502
|
+
getConnection(): Connection {
|
|
503
|
+
return this.connection
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* Get token balance for an address
|
|
508
|
+
*
|
|
509
|
+
* @param owner - Wallet address
|
|
510
|
+
* @param mint - Token mint (omit for SOL)
|
|
511
|
+
* @returns Balance in smallest units
|
|
512
|
+
*/
|
|
513
|
+
async getBalance(owner: string, mint?: string): Promise<bigint> {
|
|
514
|
+
const ownerPubkey = new PublicKey(owner)
|
|
515
|
+
|
|
516
|
+
if (!mint || mint === SOLANA_TOKEN_MINTS.SOL) {
|
|
517
|
+
const balance = await this.connection.getBalance(ownerPubkey)
|
|
518
|
+
return BigInt(balance)
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// Get SPL token balance
|
|
522
|
+
const mintPubkey = new PublicKey(mint)
|
|
523
|
+
const tokenAccounts = await this.connection.getTokenAccountsByOwner(
|
|
524
|
+
ownerPubkey,
|
|
525
|
+
{ mint: mintPubkey }
|
|
526
|
+
)
|
|
527
|
+
|
|
528
|
+
if (tokenAccounts.value.length === 0) {
|
|
529
|
+
return 0n
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// Parse account data to get balance
|
|
533
|
+
// Token account data: 64 bytes mint + 32 bytes owner + 8 bytes amount + ...
|
|
534
|
+
const accountData = tokenAccounts.value[0].account.data
|
|
535
|
+
const amountBytes = accountData.subarray(64, 72)
|
|
536
|
+
const amount = new DataView(amountBytes.buffer, amountBytes.byteOffset).getBigUint64(0, true)
|
|
537
|
+
|
|
538
|
+
return amount
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// ─── Private Helpers ──────────────────────────────────────────────────────────
|
|
542
|
+
|
|
543
|
+
private log(...args: unknown[]): void {
|
|
544
|
+
if (this.debug) {
|
|
545
|
+
console.log('[JupiterAdapter]', ...args)
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
private formatError(error: unknown): string {
|
|
550
|
+
if (error instanceof Error) {
|
|
551
|
+
if (error.message.includes('insufficient')) {
|
|
552
|
+
return 'Insufficient balance for swap'
|
|
553
|
+
}
|
|
554
|
+
if (error.message.includes('slippage')) {
|
|
555
|
+
return 'Slippage tolerance exceeded'
|
|
556
|
+
}
|
|
557
|
+
if (error.message.includes('route')) {
|
|
558
|
+
return 'No route found for this swap'
|
|
559
|
+
}
|
|
560
|
+
return error.message
|
|
561
|
+
}
|
|
562
|
+
return 'Unknown Jupiter error'
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* Create a Jupiter adapter with default configuration
|
|
568
|
+
*/
|
|
569
|
+
export function createJupiterAdapter(config?: JupiterAdapterConfig): JupiterAdapter {
|
|
570
|
+
return new JupiterAdapter(config)
|
|
571
|
+
}
|