@sip-protocol/sdk 0.5.1 → 0.6.1
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 +58 -0
- package/dist/TransportWebUSB-TQ7WZ4LE.mjs +3098 -0
- package/dist/browser.d.mts +4 -4
- package/dist/browser.d.ts +4 -4
- package/dist/browser.js +10133 -4664
- package/dist/browser.mjs +32 -1
- package/dist/chunk-7QZPORY5.mjs +15604 -0
- package/dist/chunk-C2NPCUAJ.mjs +17010 -0
- package/dist/chunk-FCVLFUIC.mjs +16699 -0
- package/dist/chunk-G5UHXECN.mjs +16340 -0
- package/dist/chunk-GEDEIZHJ.mjs +16798 -0
- package/dist/chunk-KBS3OMSZ.mjs +14737 -0
- package/dist/chunk-MTNYSNR7.mjs +16269 -0
- package/dist/chunk-O5PIB2EA.mjs +16698 -0
- package/dist/chunk-PCFM7FQO.mjs +17010 -0
- package/dist/chunk-QK464ARC.mjs +16946 -0
- package/dist/chunk-TK3FWQNC.mjs +14737 -0
- package/dist/chunk-UJCSKKID.mjs +30 -0
- package/dist/chunk-VNBMNGC3.mjs +16698 -0
- package/dist/chunk-W5TUELDQ.mjs +16947 -0
- package/dist/index-05W_S8A7.d.mts +9237 -0
- package/dist/index-C5ehlFhR.d.mts +9443 -0
- package/dist/index-CD_zShu-.d.ts +10870 -0
- package/dist/index-CNzhx-WH.d.mts +9316 -0
- package/dist/index-CQBYdLYy.d.mts +10976 -0
- package/dist/index-Cg9TYEPv.d.mts +11321 -0
- package/dist/index-CqSppS4i.d.ts +9237 -0
- package/dist/index-CqZJOO8C.d.mts +11323 -0
- package/dist/index-CywN9Bnp.d.ts +11321 -0
- package/dist/index-DBa_jiZF.d.mts +9606 -0
- package/dist/index-DHy5ZjCD.d.ts +10976 -0
- package/dist/index-DLNdSQFQ.d.ts +9316 -0
- package/dist/index-DfsVsmxu.d.ts +11323 -0
- package/dist/index-Ink8HnKW.d.ts +9606 -0
- package/dist/index-ObjwyVDX.d.mts +10870 -0
- package/dist/index-h7B23m5b.d.ts +9443 -0
- package/dist/index-m0xbSfmT.d.mts +11318 -0
- package/dist/index-rWLEgvhN.d.ts +11318 -0
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +10112 -4637
- package/dist/index.mjs +32 -1
- package/dist/noir-DKfEzWy9.d.mts +482 -0
- package/dist/noir-DKfEzWy9.d.ts +482 -0
- package/dist/proofs/noir.d.mts +1 -1
- package/dist/proofs/noir.d.ts +1 -1
- package/dist/proofs/noir.js +12 -3
- package/dist/proofs/noir.mjs +13 -3
- package/package.json +5 -3
- package/src/adapters/near-intents.ts +13 -3
- package/src/auction/index.ts +20 -0
- package/src/auction/sealed-bid.ts +1037 -0
- package/src/compliance/derivation.ts +13 -3
- package/src/compliance/reports.ts +5 -4
- package/src/cosmos/ibc-stealth.ts +2 -2
- package/src/cosmos/stealth.ts +2 -2
- package/src/crypto.ts +79 -9
- package/src/governance/index.ts +19 -0
- package/src/governance/private-vote.ts +1116 -0
- package/src/index.ts +50 -2
- package/src/intent.ts +227 -12
- package/src/nft/index.ts +27 -0
- package/src/nft/private-nft.ts +811 -0
- package/src/privacy.ts +88 -2
- package/src/proofs/browser-utils.ts +1 -7
- package/src/proofs/noir.ts +34 -7
- package/src/settlement/backends/direct-chain.ts +14 -3
- package/src/sip.ts +324 -25
- package/src/stealth.ts +120 -9
- package/src/types/browser.d.ts +67 -0
- package/src/validation.ts +4 -2
- package/src/wallet/bitcoin/adapter.ts +159 -15
- package/src/wallet/bitcoin/types.ts +340 -15
- package/src/wallet/cosmos/mock.ts +16 -12
- package/src/wallet/hardware/ledger.ts +83 -14
- package/src/wallet/hardware/types.ts +2 -0
package/src/privacy.ts
CHANGED
|
@@ -48,7 +48,41 @@ export interface PrivacyConfig {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
|
-
* Get privacy configuration for a privacy level
|
|
51
|
+
* Get privacy configuration for a given privacy level
|
|
52
|
+
*
|
|
53
|
+
* Returns a configuration object that determines which privacy features
|
|
54
|
+
* to enable for an intent. Used internally by the SDK to configure
|
|
55
|
+
* privacy behavior.
|
|
56
|
+
*
|
|
57
|
+
* **Privacy Levels:**
|
|
58
|
+
* - `'transparent'`: No privacy, fully public on-chain
|
|
59
|
+
* - `'shielded'`: Full privacy, hidden sender/amount/recipient
|
|
60
|
+
* - `'compliant'`: Privacy with viewing key for regulatory compliance
|
|
61
|
+
*
|
|
62
|
+
* @param level - Privacy level to configure
|
|
63
|
+
* @param viewingKey - Required for compliant mode, optional otherwise
|
|
64
|
+
* @returns Configuration object specifying privacy features
|
|
65
|
+
*
|
|
66
|
+
* @throws {ValidationError} If compliant mode specified without viewing key
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* // Transparent (no privacy)
|
|
71
|
+
* const config = getPrivacyConfig('transparent')
|
|
72
|
+
* // { level: 'transparent', useStealth: false, encryptData: false }
|
|
73
|
+
*
|
|
74
|
+
* // Shielded (full privacy)
|
|
75
|
+
* const config = getPrivacyConfig('shielded')
|
|
76
|
+
* // { level: 'shielded', useStealth: true, encryptData: true }
|
|
77
|
+
*
|
|
78
|
+
* // Compliant (privacy + audit)
|
|
79
|
+
* const viewingKey = generateViewingKey()
|
|
80
|
+
* const config = getPrivacyConfig('compliant', viewingKey)
|
|
81
|
+
* // { level: 'compliant', viewingKey, useStealth: true, encryptData: true }
|
|
82
|
+
* ```
|
|
83
|
+
*
|
|
84
|
+
* @see {@link PrivacyLevel} for available privacy levels
|
|
85
|
+
* @see {@link generateViewingKey} to create viewing keys
|
|
52
86
|
*/
|
|
53
87
|
export function getPrivacyConfig(
|
|
54
88
|
level: PrivacyLevel,
|
|
@@ -96,7 +130,59 @@ export function getPrivacyConfig(
|
|
|
96
130
|
}
|
|
97
131
|
|
|
98
132
|
/**
|
|
99
|
-
* Generate a new viewing key
|
|
133
|
+
* Generate a new viewing key for compliant privacy mode
|
|
134
|
+
*
|
|
135
|
+
* Creates a cryptographically random viewing key that enables selective
|
|
136
|
+
* disclosure of transaction details to auditors or regulators while
|
|
137
|
+
* maintaining on-chain privacy.
|
|
138
|
+
*
|
|
139
|
+
* **Use Cases:**
|
|
140
|
+
* - Regulatory compliance (AML/KYC audits)
|
|
141
|
+
* - Internal accounting and reconciliation
|
|
142
|
+
* - Voluntary disclosure to trusted parties
|
|
143
|
+
* - Hierarchical key management (via derivation paths)
|
|
144
|
+
*
|
|
145
|
+
* **Security:**
|
|
146
|
+
* - Keep viewing keys secret - they decrypt all transaction details
|
|
147
|
+
* - Use hierarchical derivation for key management (BIP32-style paths)
|
|
148
|
+
* - Rotate keys periodically for forward secrecy
|
|
149
|
+
*
|
|
150
|
+
* @param path - Hierarchical derivation path (BIP32-style, e.g., "m/0", "m/44'/0'/0'")
|
|
151
|
+
* @returns Viewing key object with key, path, and hash
|
|
152
|
+
*
|
|
153
|
+
* @example Generate master viewing key
|
|
154
|
+
* ```typescript
|
|
155
|
+
* const masterKey = generateViewingKey('m/0')
|
|
156
|
+
* console.log(masterKey.key) // "0xabc123..."
|
|
157
|
+
* console.log(masterKey.path) // "m/0"
|
|
158
|
+
* console.log(masterKey.hash) // "0xdef456..." (for identification)
|
|
159
|
+
* ```
|
|
160
|
+
*
|
|
161
|
+
* @example Generate organization-specific keys
|
|
162
|
+
* ```typescript
|
|
163
|
+
* const auditKey = generateViewingKey('m/0/audit')
|
|
164
|
+
* const accountingKey = generateViewingKey('m/0/accounting')
|
|
165
|
+
*
|
|
166
|
+
* // Share different keys with different departments
|
|
167
|
+
* shareWithAuditor(auditKey)
|
|
168
|
+
* shareWithAccounting(accountingKey)
|
|
169
|
+
* ```
|
|
170
|
+
*
|
|
171
|
+
* @example Use in compliant intent
|
|
172
|
+
* ```typescript
|
|
173
|
+
* const viewingKey = generateViewingKey()
|
|
174
|
+
*
|
|
175
|
+
* const intent = await sip.createIntent({
|
|
176
|
+
* input: { asset: { chain: 'near', symbol: 'NEAR', address: null, decimals: 24 }, amount: 100n },
|
|
177
|
+
* output: { asset: { chain: 'zcash', symbol: 'ZEC', address: null, decimals: 8 }, minAmount: 0n, maxSlippage: 0.01 },
|
|
178
|
+
* privacy: PrivacyLevel.COMPLIANT,
|
|
179
|
+
* viewingKey: viewingKey.key,
|
|
180
|
+
* })
|
|
181
|
+
* ```
|
|
182
|
+
*
|
|
183
|
+
* @see {@link deriveViewingKey} to derive child keys hierarchically
|
|
184
|
+
* @see {@link encryptForViewing} to encrypt data with viewing key
|
|
185
|
+
* @see {@link decryptWithViewing} to decrypt data with viewing key
|
|
100
186
|
*/
|
|
101
187
|
export function generateViewingKey(path: string = 'm/0'): ViewingKey {
|
|
102
188
|
const keyBytes = randomBytes(32)
|
|
@@ -241,10 +241,8 @@ export function getMobileDeviceInfo(): MobileDeviceInfo {
|
|
|
241
241
|
isTablet: isTablet(),
|
|
242
242
|
supportsTouch: supportsTouch(),
|
|
243
243
|
deviceMemoryGB:
|
|
244
|
-
// @ts-expect-error - deviceMemory is non-standard
|
|
245
244
|
typeof navigator !== 'undefined' && navigator.deviceMemory
|
|
246
|
-
?
|
|
247
|
-
navigator.deviceMemory
|
|
245
|
+
? navigator.deviceMemory
|
|
248
246
|
: null,
|
|
249
247
|
hardwareConcurrency:
|
|
250
248
|
typeof navigator !== 'undefined' && navigator.hardwareConcurrency
|
|
@@ -487,10 +485,8 @@ export async function estimateAvailableMemory(): Promise<number | null> {
|
|
|
487
485
|
if (!isBrowser()) return null
|
|
488
486
|
|
|
489
487
|
// Use Performance API if available (Chrome)
|
|
490
|
-
// @ts-expect-error - Performance.measureUserAgentSpecificMemory is Chrome-specific
|
|
491
488
|
if (typeof performance !== 'undefined' && performance.measureUserAgentSpecificMemory) {
|
|
492
489
|
try {
|
|
493
|
-
// @ts-expect-error - Chrome-specific API
|
|
494
490
|
const result = await performance.measureUserAgentSpecificMemory()
|
|
495
491
|
return result.bytes
|
|
496
492
|
} catch {
|
|
@@ -499,10 +495,8 @@ export async function estimateAvailableMemory(): Promise<number | null> {
|
|
|
499
495
|
}
|
|
500
496
|
|
|
501
497
|
// Use navigator.deviceMemory if available (Chrome, Opera)
|
|
502
|
-
// @ts-expect-error - deviceMemory is non-standard
|
|
503
498
|
if (typeof navigator !== 'undefined' && navigator.deviceMemory) {
|
|
504
499
|
// Returns approximate device memory in GB
|
|
505
|
-
// @ts-expect-error - deviceMemory is non-standard
|
|
506
500
|
return navigator.deviceMemory * 1024 * 1024 * 1024
|
|
507
501
|
}
|
|
508
502
|
|
package/src/proofs/noir.ts
CHANGED
|
@@ -71,9 +71,25 @@ export interface NoirProviderConfig {
|
|
|
71
71
|
|
|
72
72
|
/**
|
|
73
73
|
* Oracle public key for verifying attestations in fulfillment proofs
|
|
74
|
-
* Required for production use. If not provided
|
|
74
|
+
* Required for production use. If not provided and strictMode is true,
|
|
75
|
+
* fulfillment proof generation will throw an error.
|
|
75
76
|
*/
|
|
76
77
|
oraclePublicKey?: PublicKeyCoordinates
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Enable strict mode for production use
|
|
81
|
+
*
|
|
82
|
+
* When true:
|
|
83
|
+
* - Fulfillment proofs require configured oraclePublicKey
|
|
84
|
+
* - Missing configuration throws errors instead of warnings
|
|
85
|
+
*
|
|
86
|
+
* When false (default):
|
|
87
|
+
* - Placeholder keys are used when oraclePublicKey not configured
|
|
88
|
+
* - Warnings are logged for missing configuration
|
|
89
|
+
*
|
|
90
|
+
* @default false
|
|
91
|
+
*/
|
|
92
|
+
strictMode?: boolean
|
|
77
93
|
}
|
|
78
94
|
|
|
79
95
|
/**
|
|
@@ -114,6 +130,7 @@ export class NoirProofProvider implements ProofProvider {
|
|
|
114
130
|
this.config = {
|
|
115
131
|
backend: 'barretenberg',
|
|
116
132
|
verbose: false,
|
|
133
|
+
strictMode: false,
|
|
117
134
|
...config,
|
|
118
135
|
}
|
|
119
136
|
}
|
|
@@ -588,15 +605,25 @@ export class NoirProofProvider implements ProofProvider {
|
|
|
588
605
|
attestation.blockNumber
|
|
589
606
|
)
|
|
590
607
|
|
|
591
|
-
//
|
|
592
|
-
|
|
608
|
+
// Validate oracle public key configuration
|
|
609
|
+
if (!this.config.oraclePublicKey) {
|
|
610
|
+
if (this.config.strictMode) {
|
|
611
|
+
throw new ProofGenerationError(
|
|
612
|
+
'fulfillment',
|
|
613
|
+
'Oracle public key is required in strict mode. Configure oraclePublicKey in NoirProviderConfig for production use.'
|
|
614
|
+
)
|
|
615
|
+
}
|
|
616
|
+
// Always warn when using placeholder keys, not just in verbose mode
|
|
617
|
+
console.warn(
|
|
618
|
+
'[NoirProofProvider] WARNING: No oracle public key configured. Using placeholder keys. ' +
|
|
619
|
+
'Proofs will NOT be valid for production. Set strictMode: true to enforce configuration.'
|
|
620
|
+
)
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// Use configured oracle public key, or placeholder if not in strict mode
|
|
593
624
|
const oraclePubKeyX = this.config.oraclePublicKey?.x ?? new Array(32).fill(0)
|
|
594
625
|
const oraclePubKeyY = this.config.oraclePublicKey?.y ?? new Array(32).fill(0)
|
|
595
626
|
|
|
596
|
-
if (!this.config.oraclePublicKey && this.config.verbose) {
|
|
597
|
-
console.warn('[NoirProofProvider] Warning: No oracle public key configured. Using placeholder keys.')
|
|
598
|
-
}
|
|
599
|
-
|
|
600
627
|
// Prepare witness inputs for the circuit
|
|
601
628
|
const witnessInputs = {
|
|
602
629
|
// Public inputs
|
|
@@ -39,6 +39,8 @@ import {
|
|
|
39
39
|
ed25519PublicKeyToNearAddress,
|
|
40
40
|
isEd25519Chain,
|
|
41
41
|
} from '../../stealth'
|
|
42
|
+
import { ed25519PublicKeyToAptosAddress } from '../../move/aptos'
|
|
43
|
+
import { ed25519PublicKeyToSuiAddress } from '../../move/sui'
|
|
42
44
|
import { ValidationError } from '../../errors'
|
|
43
45
|
import { randomBytes, bytesToHex } from '@noble/hashes/utils'
|
|
44
46
|
|
|
@@ -161,6 +163,8 @@ export class DirectChainBackend implements SettlementBackend {
|
|
|
161
163
|
'optimism',
|
|
162
164
|
'base',
|
|
163
165
|
'bitcoin',
|
|
166
|
+
'aptos',
|
|
167
|
+
'sui',
|
|
164
168
|
],
|
|
165
169
|
supportedDestinationChains: [
|
|
166
170
|
'ethereum',
|
|
@@ -172,6 +176,8 @@ export class DirectChainBackend implements SettlementBackend {
|
|
|
172
176
|
'optimism',
|
|
173
177
|
'base',
|
|
174
178
|
'bitcoin',
|
|
179
|
+
'aptos',
|
|
180
|
+
'sui',
|
|
175
181
|
],
|
|
176
182
|
supportedPrivacyLevels: [
|
|
177
183
|
PrivacyLevel.TRANSPARENT,
|
|
@@ -280,7 +286,7 @@ export class DirectChainBackend implements SettlementBackend {
|
|
|
280
286
|
: params.recipientMetaAddress
|
|
281
287
|
|
|
282
288
|
if (isEd25519Chain(chain)) {
|
|
283
|
-
// Ed25519 chains (Solana, NEAR)
|
|
289
|
+
// Ed25519 chains (Solana, NEAR, Aptos, Sui)
|
|
284
290
|
const { stealthAddress } = generateEd25519StealthAddress(metaAddr)
|
|
285
291
|
stealthData = stealthAddress
|
|
286
292
|
|
|
@@ -288,11 +294,16 @@ export class DirectChainBackend implements SettlementBackend {
|
|
|
288
294
|
recipientAddress = ed25519PublicKeyToSolanaAddress(stealthAddress.address)
|
|
289
295
|
} else if (chain === 'near') {
|
|
290
296
|
recipientAddress = ed25519PublicKeyToNearAddress(stealthAddress.address)
|
|
297
|
+
} else if (chain === 'aptos') {
|
|
298
|
+
recipientAddress = ed25519PublicKeyToAptosAddress(stealthAddress.address)
|
|
299
|
+
} else if (chain === 'sui') {
|
|
300
|
+
recipientAddress = ed25519PublicKeyToSuiAddress(stealthAddress.address)
|
|
291
301
|
} else {
|
|
302
|
+
// This should not happen if ED25519_CHAINS is kept in sync
|
|
292
303
|
throw new ValidationError(
|
|
293
|
-
`Ed25519 address derivation not implemented for ${chain}
|
|
304
|
+
`Ed25519 address derivation not implemented for ${chain}. Please add support in direct-chain.ts.`,
|
|
294
305
|
'toChain',
|
|
295
|
-
{ chain }
|
|
306
|
+
{ chain, hint: 'Add address derivation function for this chain' }
|
|
296
307
|
)
|
|
297
308
|
}
|
|
298
309
|
} else {
|
package/src/sip.ts
CHANGED
|
@@ -32,50 +32,145 @@ import { isValidChainId } from './validation'
|
|
|
32
32
|
import { NEARIntentsAdapter, type NEARIntentsAdapterConfig, type SwapRequest } from './adapters'
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
|
-
* SIP SDK
|
|
35
|
+
* Configuration options for the SIP SDK client
|
|
36
|
+
*
|
|
37
|
+
* Controls network selection, privacy defaults, proof generation, and settlement backend.
|
|
38
|
+
*
|
|
39
|
+
* @example Basic configuration
|
|
40
|
+
* ```typescript
|
|
41
|
+
* const sip = new SIP({
|
|
42
|
+
* network: 'testnet',
|
|
43
|
+
* defaultPrivacy: PrivacyLevel.SHIELDED
|
|
44
|
+
* })
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* @example Production configuration with NEAR Intents
|
|
48
|
+
* ```typescript
|
|
49
|
+
* const sip = new SIP({
|
|
50
|
+
* network: 'mainnet',
|
|
51
|
+
* mode: 'production',
|
|
52
|
+
* proofProvider: new MockProofProvider(),
|
|
53
|
+
* intentsAdapter: {
|
|
54
|
+
* jwtToken: process.env.NEAR_INTENTS_JWT
|
|
55
|
+
* }
|
|
56
|
+
* })
|
|
57
|
+
* ```
|
|
36
58
|
*/
|
|
37
59
|
export interface SIPConfig {
|
|
38
|
-
/**
|
|
60
|
+
/**
|
|
61
|
+
* Network to operate on
|
|
62
|
+
*
|
|
63
|
+
* - `'mainnet'`: Production network with real assets
|
|
64
|
+
* - `'testnet'`: Test network for development
|
|
65
|
+
*/
|
|
39
66
|
network: 'mainnet' | 'testnet'
|
|
67
|
+
|
|
40
68
|
/**
|
|
41
|
-
*
|
|
69
|
+
* Operating mode for quote fetching and execution
|
|
70
|
+
*
|
|
71
|
+
* - `'demo'`: Returns mock quotes for testing (default)
|
|
72
|
+
* - `'production'`: Uses real NEAR Intents 1Click API
|
|
73
|
+
*
|
|
42
74
|
* @default 'demo'
|
|
43
75
|
*/
|
|
44
76
|
mode?: 'demo' | 'production'
|
|
45
|
-
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Default privacy level for new intents
|
|
80
|
+
*
|
|
81
|
+
* Can be overridden per intent. See {@link PrivacyLevel} for options.
|
|
82
|
+
*
|
|
83
|
+
* @default PrivacyLevel.SHIELDED
|
|
84
|
+
*/
|
|
46
85
|
defaultPrivacy?: PrivacyLevel
|
|
47
|
-
|
|
48
|
-
rpcEndpoints?: Partial<Record<ChainId, string>>
|
|
86
|
+
|
|
49
87
|
/**
|
|
50
|
-
*
|
|
88
|
+
* Custom RPC endpoints for blockchain connections
|
|
51
89
|
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
90
|
+
* Maps chain IDs to RPC URLs. Used for direct blockchain interactions
|
|
91
|
+
* when not using settlement adapters.
|
|
54
92
|
*
|
|
55
93
|
* @example
|
|
56
94
|
* ```typescript
|
|
95
|
+
* {
|
|
96
|
+
* rpcEndpoints: {
|
|
97
|
+
* ethereum: 'https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY',
|
|
98
|
+
* solana: 'https://api.mainnet-beta.solana.com'
|
|
99
|
+
* }
|
|
100
|
+
* }
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
rpcEndpoints?: Partial<Record<ChainId, string>>
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Proof provider for zero-knowledge proof generation
|
|
107
|
+
*
|
|
108
|
+
* Required for SHIELDED and COMPLIANT privacy modes. If not provided,
|
|
109
|
+
* intents will be created without proofs (must be attached later).
|
|
110
|
+
*
|
|
111
|
+
* **Available providers:**
|
|
112
|
+
* - {@link MockProofProvider}: For testing and development
|
|
113
|
+
* - `NoirProofProvider`: For production (import from '@sip-protocol/sdk/proofs/noir')
|
|
114
|
+
* - `BrowserNoirProvider`: For browser environments (import from '@sip-protocol/sdk/browser')
|
|
115
|
+
*
|
|
116
|
+
* @example Testing with mock proofs
|
|
117
|
+
* ```typescript
|
|
57
118
|
* import { MockProofProvider } from '@sip-protocol/sdk'
|
|
58
119
|
*
|
|
59
120
|
* const sip = new SIP({
|
|
60
121
|
* network: 'testnet',
|
|
61
|
-
* proofProvider: new MockProofProvider()
|
|
122
|
+
* proofProvider: new MockProofProvider()
|
|
123
|
+
* })
|
|
124
|
+
* ```
|
|
125
|
+
*
|
|
126
|
+
* @example Production with Noir proofs (Node.js)
|
|
127
|
+
* ```typescript
|
|
128
|
+
* import { NoirProofProvider } from '@sip-protocol/sdk/proofs/noir'
|
|
129
|
+
*
|
|
130
|
+
* const provider = new NoirProofProvider()
|
|
131
|
+
* await provider.initialize()
|
|
132
|
+
*
|
|
133
|
+
* const sip = new SIP({
|
|
134
|
+
* network: 'mainnet',
|
|
135
|
+
* proofProvider: provider
|
|
62
136
|
* })
|
|
63
137
|
* ```
|
|
64
138
|
*/
|
|
65
139
|
proofProvider?: ProofProvider
|
|
140
|
+
|
|
66
141
|
/**
|
|
67
|
-
* NEAR Intents adapter
|
|
142
|
+
* NEAR Intents adapter for production mode
|
|
68
143
|
*
|
|
69
|
-
* Required
|
|
144
|
+
* Required when `mode: 'production'`. Provides connection to the 1Click API
|
|
145
|
+
* for real cross-chain swaps via NEAR Intents.
|
|
70
146
|
*
|
|
71
|
-
*
|
|
147
|
+
* Can be either:
|
|
148
|
+
* - Configuration object ({@link NEARIntentsAdapterConfig})
|
|
149
|
+
* - Pre-configured adapter instance ({@link NEARIntentsAdapter})
|
|
150
|
+
*
|
|
151
|
+
* @example With JWT token
|
|
72
152
|
* ```typescript
|
|
73
153
|
* const sip = new SIP({
|
|
74
154
|
* network: 'mainnet',
|
|
75
155
|
* mode: 'production',
|
|
76
156
|
* intentsAdapter: {
|
|
77
|
-
* jwtToken: process.env.NEAR_INTENTS_JWT
|
|
78
|
-
* }
|
|
157
|
+
* jwtToken: process.env.NEAR_INTENTS_JWT
|
|
158
|
+
* }
|
|
159
|
+
* })
|
|
160
|
+
* ```
|
|
161
|
+
*
|
|
162
|
+
* @example With pre-configured adapter
|
|
163
|
+
* ```typescript
|
|
164
|
+
* import { createNEARIntentsAdapter } from '@sip-protocol/sdk'
|
|
165
|
+
*
|
|
166
|
+
* const adapter = createNEARIntentsAdapter({
|
|
167
|
+
* jwtToken: process.env.NEAR_INTENTS_JWT
|
|
168
|
+
* })
|
|
169
|
+
*
|
|
170
|
+
* const sip = new SIP({
|
|
171
|
+
* network: 'mainnet',
|
|
172
|
+
* mode: 'production',
|
|
173
|
+
* intentsAdapter: adapter
|
|
79
174
|
* })
|
|
80
175
|
* ```
|
|
81
176
|
*/
|
|
@@ -83,33 +178,212 @@ export interface SIPConfig {
|
|
|
83
178
|
}
|
|
84
179
|
|
|
85
180
|
/**
|
|
86
|
-
* Wallet adapter interface
|
|
181
|
+
* Wallet adapter interface for blockchain interactions
|
|
182
|
+
*
|
|
183
|
+
* Provides a unified interface for signing messages and transactions
|
|
184
|
+
* across different blockchain wallets (Ethereum, Solana, etc.).
|
|
185
|
+
*
|
|
186
|
+
* @example Implementing a wallet adapter
|
|
187
|
+
* ```typescript
|
|
188
|
+
* class MyWalletAdapter implements WalletAdapter {
|
|
189
|
+
* chain = 'ethereum' as const
|
|
190
|
+
* address = '0x...'
|
|
191
|
+
*
|
|
192
|
+
* async signMessage(message: string): Promise<string> {
|
|
193
|
+
* return await wallet.signMessage(message)
|
|
194
|
+
* }
|
|
195
|
+
*
|
|
196
|
+
* async signTransaction(tx: unknown): Promise<unknown> {
|
|
197
|
+
* return await wallet.signTransaction(tx)
|
|
198
|
+
* }
|
|
199
|
+
* }
|
|
200
|
+
* ```
|
|
87
201
|
*/
|
|
88
202
|
export interface WalletAdapter {
|
|
89
|
-
/**
|
|
203
|
+
/**
|
|
204
|
+
* Blockchain network this wallet is connected to
|
|
205
|
+
*
|
|
206
|
+
* Must match one of the supported {@link ChainId} values.
|
|
207
|
+
*/
|
|
90
208
|
chain: ChainId
|
|
91
|
-
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Wallet address on the connected chain
|
|
212
|
+
*
|
|
213
|
+
* Format depends on the chain:
|
|
214
|
+
* - Ethereum: `0x...` (checksummed)
|
|
215
|
+
* - Solana: Base58-encoded public key
|
|
216
|
+
* - NEAR: Account ID or implicit address
|
|
217
|
+
*/
|
|
92
218
|
address: string
|
|
93
|
-
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Sign a message with the wallet's private key
|
|
222
|
+
*
|
|
223
|
+
* @param message - UTF-8 string to sign
|
|
224
|
+
* @returns Signature as hex string or base58 (chain-dependent)
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* ```typescript
|
|
228
|
+
* const signature = await wallet.signMessage('Hello SIP!')
|
|
229
|
+
* ```
|
|
230
|
+
*/
|
|
94
231
|
signMessage(message: string): Promise<string>
|
|
95
|
-
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Sign a transaction without broadcasting
|
|
235
|
+
*
|
|
236
|
+
* @param tx - Chain-specific transaction object
|
|
237
|
+
* @returns Signed transaction ready for broadcast
|
|
238
|
+
*
|
|
239
|
+
* @example
|
|
240
|
+
* ```typescript
|
|
241
|
+
* const signedTx = await wallet.signTransaction(tx)
|
|
242
|
+
* ```
|
|
243
|
+
*/
|
|
96
244
|
signTransaction(tx: unknown): Promise<unknown>
|
|
97
|
-
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Sign and broadcast a transaction (optional)
|
|
248
|
+
*
|
|
249
|
+
* If implemented, allows the wallet to handle both signing and sending.
|
|
250
|
+
* If not implemented, caller must broadcast the signed transaction separately.
|
|
251
|
+
*
|
|
252
|
+
* @param tx - Chain-specific transaction object
|
|
253
|
+
* @returns Transaction hash after broadcast
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* ```typescript
|
|
257
|
+
* if (wallet.sendTransaction) {
|
|
258
|
+
* const txHash = await wallet.sendTransaction(tx)
|
|
259
|
+
* }
|
|
260
|
+
* ```
|
|
261
|
+
*/
|
|
98
262
|
sendTransaction?(tx: unknown): Promise<string>
|
|
99
263
|
}
|
|
100
264
|
|
|
101
265
|
/**
|
|
102
|
-
* Extended quote with
|
|
266
|
+
* Extended quote with production-specific metadata
|
|
267
|
+
*
|
|
268
|
+
* In production mode, quotes include deposit addresses and raw API responses
|
|
269
|
+
* from the NEAR 1Click API for advanced use cases.
|
|
103
270
|
*/
|
|
104
271
|
export interface ProductionQuote extends Quote {
|
|
105
|
-
/**
|
|
272
|
+
/**
|
|
273
|
+
* Deposit address for input tokens
|
|
274
|
+
*
|
|
275
|
+
* When using NEAR Intents in production mode, users deposit funds to this
|
|
276
|
+
* address to initiate the swap.
|
|
277
|
+
*
|
|
278
|
+
* Only present in production mode quotes.
|
|
279
|
+
*/
|
|
106
280
|
depositAddress?: string
|
|
107
|
-
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Raw response from NEAR 1Click API
|
|
284
|
+
*
|
|
285
|
+
* Contains the complete quote data from the settlement backend.
|
|
286
|
+
* Useful for debugging or accessing provider-specific metadata.
|
|
287
|
+
*
|
|
288
|
+
* Only present in production mode quotes.
|
|
289
|
+
*/
|
|
108
290
|
rawQuote?: OneClickQuoteResponse
|
|
109
291
|
}
|
|
110
292
|
|
|
111
293
|
/**
|
|
112
|
-
* Main SIP SDK
|
|
294
|
+
* Main SIP SDK client for privacy-preserving cross-chain transactions
|
|
295
|
+
*
|
|
296
|
+
* The SIP class is the primary interface for interacting with the Shielded Intents Protocol.
|
|
297
|
+
* It provides methods for:
|
|
298
|
+
*
|
|
299
|
+
* - Creating shielded intents with privacy guarantees
|
|
300
|
+
* - Fetching quotes from solvers/market makers
|
|
301
|
+
* - Executing cross-chain swaps via settlement backends
|
|
302
|
+
* - Managing stealth addresses and viewing keys
|
|
303
|
+
* - Generating zero-knowledge proofs
|
|
304
|
+
*
|
|
305
|
+
* **Key Concepts:**
|
|
306
|
+
*
|
|
307
|
+
* - **Intent**: A declaration of desired output (e.g., "I want 95+ ZEC on Zcash")
|
|
308
|
+
* - **Privacy Levels**: transparent (public), shielded (private), compliant (private + auditable)
|
|
309
|
+
* - **Stealth Address**: One-time recipient address for unlinkable transactions
|
|
310
|
+
* - **Commitment**: Cryptographic hiding of amounts using Pedersen commitments
|
|
311
|
+
* - **Viewing Key**: Selective disclosure key for compliance/auditing
|
|
312
|
+
*
|
|
313
|
+
* @example Basic usage (demo mode)
|
|
314
|
+
* ```typescript
|
|
315
|
+
* import { SIP, PrivacyLevel } from '@sip-protocol/sdk'
|
|
316
|
+
*
|
|
317
|
+
* // Initialize client
|
|
318
|
+
* const sip = new SIP({ network: 'testnet' })
|
|
319
|
+
*
|
|
320
|
+
* // Create a shielded intent
|
|
321
|
+
* const intent = await sip.createIntent({
|
|
322
|
+
* input: {
|
|
323
|
+
* asset: { chain: 'solana', symbol: 'SOL', address: null, decimals: 9 },
|
|
324
|
+
* amount: 10n * 10n**9n, // 10 SOL
|
|
325
|
+
* },
|
|
326
|
+
* output: {
|
|
327
|
+
* asset: { chain: 'ethereum', symbol: 'ETH', address: null, decimals: 18 },
|
|
328
|
+
* minAmount: 0n, // Accept any amount
|
|
329
|
+
* maxSlippage: 0.01, // 1%
|
|
330
|
+
* },
|
|
331
|
+
* privacy: PrivacyLevel.SHIELDED,
|
|
332
|
+
* })
|
|
333
|
+
*
|
|
334
|
+
* // Get quotes from solvers
|
|
335
|
+
* const quotes = await sip.getQuotes(intent)
|
|
336
|
+
*
|
|
337
|
+
* // Execute with best quote
|
|
338
|
+
* const result = await sip.execute(intent, quotes[0])
|
|
339
|
+
* console.log('Swap completed:', result.txHash)
|
|
340
|
+
* ```
|
|
341
|
+
*
|
|
342
|
+
* @example Production mode with NEAR Intents
|
|
343
|
+
* ```typescript
|
|
344
|
+
* import { SIP, PrivacyLevel, MockProofProvider } from '@sip-protocol/sdk'
|
|
345
|
+
*
|
|
346
|
+
* // Initialize with production backend
|
|
347
|
+
* const sip = new SIP({
|
|
348
|
+
* network: 'mainnet',
|
|
349
|
+
* mode: 'production',
|
|
350
|
+
* proofProvider: new MockProofProvider(), // Use NoirProofProvider in prod
|
|
351
|
+
* intentsAdapter: {
|
|
352
|
+
* jwtToken: process.env.NEAR_INTENTS_JWT,
|
|
353
|
+
* },
|
|
354
|
+
* })
|
|
355
|
+
*
|
|
356
|
+
* // Connect wallet
|
|
357
|
+
* sip.connect(myWalletAdapter)
|
|
358
|
+
*
|
|
359
|
+
* // Generate stealth keys for receiving
|
|
360
|
+
* const stealthMetaAddress = sip.generateStealthKeys('ethereum', 'My Privacy Wallet')
|
|
361
|
+
*
|
|
362
|
+
* // Create intent with stealth recipient
|
|
363
|
+
* const intent = await sip.createIntent({
|
|
364
|
+
* input: { asset: { chain: 'near', symbol: 'NEAR', address: null, decimals: 24 }, amount: 100n },
|
|
365
|
+
* output: { asset: { chain: 'zcash', symbol: 'ZEC', address: null, decimals: 8 }, minAmount: 0n, maxSlippage: 0.01 },
|
|
366
|
+
* privacy: PrivacyLevel.SHIELDED,
|
|
367
|
+
* recipientMetaAddress: sip.getStealthAddress(),
|
|
368
|
+
* })
|
|
369
|
+
*
|
|
370
|
+
* // Get real quotes
|
|
371
|
+
* const quotes = await sip.getQuotes(intent)
|
|
372
|
+
*
|
|
373
|
+
* // Execute with deposit callback
|
|
374
|
+
* const result = await sip.execute(intent, quotes[0], {
|
|
375
|
+
* onDepositRequired: async (depositAddr, amount) => {
|
|
376
|
+
* console.log(`Deposit ${amount} to ${depositAddr}`)
|
|
377
|
+
* const tx = await wallet.transfer(depositAddr, amount)
|
|
378
|
+
* return tx.hash
|
|
379
|
+
* },
|
|
380
|
+
* onStatusUpdate: (status) => console.log('Status:', status),
|
|
381
|
+
* })
|
|
382
|
+
* ```
|
|
383
|
+
*
|
|
384
|
+
* @see {@link SIPConfig} for configuration options
|
|
385
|
+
* @see {@link createShieldedIntent} for intent creation
|
|
386
|
+
* @see {@link PrivacyLevel} for privacy modes
|
|
113
387
|
*/
|
|
114
388
|
export class SIP {
|
|
115
389
|
private config: SIPConfig & { mode: 'demo' | 'production' }
|
|
@@ -124,6 +398,31 @@ export class SIP {
|
|
|
124
398
|
/** Cache of pending swaps by intent ID */
|
|
125
399
|
private pendingSwaps: Map<string, { depositAddress: string; quote: OneClickQuoteResponse }> = new Map()
|
|
126
400
|
|
|
401
|
+
/**
|
|
402
|
+
* Create a new SIP SDK client
|
|
403
|
+
*
|
|
404
|
+
* @param config - Configuration options for the client
|
|
405
|
+
* @throws {ValidationError} If configuration is invalid
|
|
406
|
+
*
|
|
407
|
+
* @example Minimal configuration
|
|
408
|
+
* ```typescript
|
|
409
|
+
* const sip = new SIP({ network: 'testnet' })
|
|
410
|
+
* ```
|
|
411
|
+
*
|
|
412
|
+
* @example Full configuration
|
|
413
|
+
* ```typescript
|
|
414
|
+
* const sip = new SIP({
|
|
415
|
+
* network: 'mainnet',
|
|
416
|
+
* mode: 'production',
|
|
417
|
+
* defaultPrivacy: PrivacyLevel.COMPLIANT,
|
|
418
|
+
* proofProvider: await NoirProofProvider.create(),
|
|
419
|
+
* intentsAdapter: { jwtToken: process.env.JWT },
|
|
420
|
+
* rpcEndpoints: {
|
|
421
|
+
* ethereum: 'https://eth-mainnet.g.alchemy.com/v2/KEY',
|
|
422
|
+
* },
|
|
423
|
+
* })
|
|
424
|
+
* ```
|
|
425
|
+
*/
|
|
127
426
|
constructor(config: SIPConfig) {
|
|
128
427
|
// Validate config
|
|
129
428
|
if (!config || typeof config !== 'object') {
|