@sip-protocol/sdk 0.2.8 → 0.2.10

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.
Files changed (39) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +349 -0
  3. package/dist/browser.d.mts +100 -2
  4. package/dist/browser.d.ts +100 -2
  5. package/dist/browser.js +1362 -268
  6. package/dist/browser.mjs +502 -16
  7. package/dist/{chunk-UPTISVCY.mjs → chunk-AV37IZST.mjs} +731 -15
  8. package/dist/{chunk-VITVG25F.mjs → chunk-XLEPIR2P.mjs} +2 -100
  9. package/dist/index-BFOKTz2z.d.ts +6062 -0
  10. package/dist/index-CAhjA4kh.d.mts +6062 -0
  11. package/dist/index.d.mts +2 -5609
  12. package/dist/index.d.ts +2 -5609
  13. package/dist/index.js +588 -154
  14. package/dist/index.mjs +5 -1
  15. package/dist/{noir-BHQtFvRk.d.mts → noir-BTyLXLlZ.d.mts} +1 -1
  16. package/dist/{noir-BHQtFvRk.d.ts → noir-BTyLXLlZ.d.ts} +1 -1
  17. package/dist/proofs/noir.d.mts +1 -1
  18. package/dist/proofs/noir.d.ts +1 -1
  19. package/dist/proofs/noir.js +11 -112
  20. package/dist/proofs/noir.mjs +10 -13
  21. package/package.json +16 -16
  22. package/src/browser.ts +23 -0
  23. package/src/index.ts +12 -0
  24. package/src/proofs/browser-utils.ts +389 -0
  25. package/src/proofs/browser.ts +246 -19
  26. package/src/proofs/circuits/funding_proof.json +1 -1
  27. package/src/proofs/noir.ts +14 -14
  28. package/src/proofs/worker.ts +426 -0
  29. package/src/zcash/bridge.ts +738 -0
  30. package/src/zcash/index.ts +36 -1
  31. package/src/zcash/swap-service.ts +793 -0
  32. package/dist/chunk-4VJHI66K.mjs +0 -12120
  33. package/dist/chunk-5BAS4D44.mjs +0 -10283
  34. package/dist/chunk-6WOV2YNG.mjs +0 -10179
  35. package/dist/chunk-DU7LQDD2.mjs +0 -10148
  36. package/dist/chunk-MR7HRCRS.mjs +0 -10165
  37. package/dist/chunk-NDGUWOOZ.mjs +0 -10157
  38. package/dist/chunk-O4Y2ZUDL.mjs +0 -12721
  39. package/dist/chunk-VXSHK7US.mjs +0 -10158
@@ -3031,6 +3031,280 @@ var MockProofProvider = class {
3031
3031
  };
3032
3032
 
3033
3033
  // src/proofs/browser-utils.ts
3034
+ function detectMobilePlatform() {
3035
+ if (typeof navigator === "undefined") return "desktop";
3036
+ const ua = navigator.userAgent.toLowerCase();
3037
+ if (/iphone|ipad|ipod/.test(ua) || navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1) {
3038
+ return "ios";
3039
+ }
3040
+ if (/android/.test(ua)) {
3041
+ return "android";
3042
+ }
3043
+ if (/mobile|webos|blackberry|opera mini|opera mobi|iemobile|wpdesktop/.test(ua)) {
3044
+ return "other";
3045
+ }
3046
+ return "desktop";
3047
+ }
3048
+ function detectMobileBrowser() {
3049
+ if (typeof navigator === "undefined") return "other";
3050
+ const ua = navigator.userAgent.toLowerCase();
3051
+ if (/safari/.test(ua) && /iphone|ipad|ipod/.test(ua) && !/crios|fxios/.test(ua)) {
3052
+ return "safari";
3053
+ }
3054
+ if (/chrome|crios/.test(ua) && !/edg|opr|samsung/.test(ua)) {
3055
+ return "chrome";
3056
+ }
3057
+ if (/firefox|fxios/.test(ua)) {
3058
+ return "firefox";
3059
+ }
3060
+ if (/samsung/.test(ua)) {
3061
+ return "samsung";
3062
+ }
3063
+ if (/opr|opera/.test(ua)) {
3064
+ return "opera";
3065
+ }
3066
+ if (/edg/.test(ua)) {
3067
+ return "edge";
3068
+ }
3069
+ return "other";
3070
+ }
3071
+ function getBrowserVersion() {
3072
+ if (typeof navigator === "undefined") return null;
3073
+ const ua = navigator.userAgent;
3074
+ const browser = detectMobileBrowser();
3075
+ const patterns = {
3076
+ safari: /version\/(\d+(\.\d+)*)/i,
3077
+ chrome: /chrome\/(\d+(\.\d+)*)|crios\/(\d+(\.\d+)*)/i,
3078
+ firefox: /firefox\/(\d+(\.\d+)*)|fxios\/(\d+(\.\d+)*)/i,
3079
+ samsung: /samsungbrowser\/(\d+(\.\d+)*)/i,
3080
+ opera: /opr\/(\d+(\.\d+)*)/i,
3081
+ edge: /edg\/(\d+(\.\d+)*)/i,
3082
+ other: /version\/(\d+(\.\d+)*)/i
3083
+ };
3084
+ const pattern = patterns[browser] || patterns.other;
3085
+ const match = ua.match(pattern);
3086
+ if (match) {
3087
+ for (let i = 1; i < match.length; i++) {
3088
+ if (match[i]) return match[i];
3089
+ }
3090
+ }
3091
+ return null;
3092
+ }
3093
+ function getOSVersion() {
3094
+ if (typeof navigator === "undefined") return null;
3095
+ const ua = navigator.userAgent;
3096
+ const platform = detectMobilePlatform();
3097
+ if (platform === "ios") {
3098
+ const match = ua.match(/os (\d+[_\d]*)/i);
3099
+ return match ? match[1].replace(/_/g, ".") : null;
3100
+ }
3101
+ if (platform === "android") {
3102
+ const match = ua.match(/android (\d+(\.\d+)*)/i);
3103
+ return match ? match[1] : null;
3104
+ }
3105
+ return null;
3106
+ }
3107
+ function isTablet() {
3108
+ if (typeof navigator === "undefined") return false;
3109
+ const ua = navigator.userAgent.toLowerCase();
3110
+ if (/ipad/.test(ua) || navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1) {
3111
+ return true;
3112
+ }
3113
+ if (/android/.test(ua) && !/mobile/.test(ua)) {
3114
+ return true;
3115
+ }
3116
+ return false;
3117
+ }
3118
+ function supportsTouch() {
3119
+ if (typeof window === "undefined") return false;
3120
+ return "ontouchstart" in window || navigator.maxTouchPoints > 0;
3121
+ }
3122
+ function getMobileDeviceInfo() {
3123
+ const platform = detectMobilePlatform();
3124
+ return {
3125
+ isMobile: platform !== "desktop",
3126
+ platform,
3127
+ browser: detectMobileBrowser(),
3128
+ browserVersion: getBrowserVersion(),
3129
+ osVersion: getOSVersion(),
3130
+ isTablet: isTablet(),
3131
+ supportsTouch: supportsTouch(),
3132
+ deviceMemoryGB: (
3133
+ // @ts-expect-error - deviceMemory is non-standard
3134
+ typeof navigator !== "undefined" && navigator.deviceMemory ? (
3135
+ // @ts-expect-error - deviceMemory is non-standard
3136
+ navigator.deviceMemory
3137
+ ) : null
3138
+ ),
3139
+ hardwareConcurrency: typeof navigator !== "undefined" && navigator.hardwareConcurrency ? navigator.hardwareConcurrency : null
3140
+ };
3141
+ }
3142
+ function supportsWASMSimd() {
3143
+ try {
3144
+ return WebAssembly.validate(
3145
+ new Uint8Array([
3146
+ 0,
3147
+ 97,
3148
+ 115,
3149
+ 109,
3150
+ 1,
3151
+ 0,
3152
+ 0,
3153
+ 0,
3154
+ 1,
3155
+ 5,
3156
+ 1,
3157
+ 96,
3158
+ 0,
3159
+ 1,
3160
+ 123,
3161
+ 3,
3162
+ 2,
3163
+ 1,
3164
+ 0,
3165
+ 10,
3166
+ 10,
3167
+ 1,
3168
+ 8,
3169
+ 0,
3170
+ 65,
3171
+ 0,
3172
+ 253,
3173
+ 15,
3174
+ 253,
3175
+ 98,
3176
+ 11
3177
+ ])
3178
+ );
3179
+ } catch {
3180
+ return false;
3181
+ }
3182
+ }
3183
+ function supportsWASMBulkMemory() {
3184
+ try {
3185
+ return WebAssembly.validate(
3186
+ new Uint8Array([
3187
+ 0,
3188
+ 97,
3189
+ 115,
3190
+ 109,
3191
+ 1,
3192
+ 0,
3193
+ 0,
3194
+ 0,
3195
+ 1,
3196
+ 4,
3197
+ 1,
3198
+ 96,
3199
+ 0,
3200
+ 0,
3201
+ 3,
3202
+ 2,
3203
+ 1,
3204
+ 0,
3205
+ 5,
3206
+ 3,
3207
+ 1,
3208
+ 0,
3209
+ 1,
3210
+ 10,
3211
+ 13,
3212
+ 1,
3213
+ 11,
3214
+ 0,
3215
+ 65,
3216
+ 0,
3217
+ 65,
3218
+ 0,
3219
+ 65,
3220
+ 0,
3221
+ 252,
3222
+ 11,
3223
+ 0,
3224
+ 11
3225
+ ])
3226
+ );
3227
+ } catch {
3228
+ return false;
3229
+ }
3230
+ }
3231
+ function checkMobileWASMCompatibility() {
3232
+ const issues = [];
3233
+ const recommendations = [];
3234
+ let score = 100;
3235
+ const webAssembly = typeof WebAssembly !== "undefined";
3236
+ if (!webAssembly) {
3237
+ issues.push("WebAssembly not supported");
3238
+ score -= 50;
3239
+ }
3240
+ const sharedArrayBuffer = supportsSharedArrayBuffer();
3241
+ if (!sharedArrayBuffer) {
3242
+ issues.push("SharedArrayBuffer not available (requires COOP/COEP headers)");
3243
+ recommendations.push("Server must send Cross-Origin-Opener-Policy: same-origin");
3244
+ recommendations.push("Server must send Cross-Origin-Embedder-Policy: require-corp");
3245
+ score -= 20;
3246
+ }
3247
+ const webWorkers = supportsWebWorkers();
3248
+ if (!webWorkers) {
3249
+ issues.push("Web Workers not supported");
3250
+ recommendations.push("Consider using a polyfill or fallback to main-thread execution");
3251
+ score -= 15;
3252
+ }
3253
+ const simd = supportsWASMSimd();
3254
+ if (!simd) {
3255
+ recommendations.push("WASM SIMD not supported - proofs will be slower");
3256
+ score -= 5;
3257
+ }
3258
+ const bulkMemory = supportsWASMBulkMemory();
3259
+ if (!bulkMemory) {
3260
+ recommendations.push("WASM bulk memory not supported - may affect performance");
3261
+ score -= 5;
3262
+ }
3263
+ const bigInt = typeof BigInt !== "undefined";
3264
+ if (!bigInt) {
3265
+ issues.push("BigInt not supported (required for 64-bit operations)");
3266
+ score -= 10;
3267
+ }
3268
+ const deviceInfo = getMobileDeviceInfo();
3269
+ if (deviceInfo.isMobile) {
3270
+ if (deviceInfo.deviceMemoryGB !== null && deviceInfo.deviceMemoryGB < 2) {
3271
+ recommendations.push(`Low device memory (${deviceInfo.deviceMemoryGB}GB) - may experience issues with large proofs`);
3272
+ score -= 5;
3273
+ }
3274
+ if (deviceInfo.platform === "ios" && deviceInfo.browser === "safari") {
3275
+ if (!sharedArrayBuffer) {
3276
+ recommendations.push("iOS Safari requires iOS 15.2+ for SharedArrayBuffer support");
3277
+ }
3278
+ }
3279
+ if (deviceInfo.platform === "android" && deviceInfo.browser === "chrome") {
3280
+ if (!sharedArrayBuffer) {
3281
+ recommendations.push("Ensure COOP/COEP headers are set - Chrome Android requires them");
3282
+ }
3283
+ }
3284
+ }
3285
+ let summary;
3286
+ if (score >= 90) {
3287
+ summary = "Excellent - Full WASM proof support";
3288
+ } else if (score >= 70) {
3289
+ summary = "Good - WASM proofs supported with minor limitations";
3290
+ } else if (score >= 50) {
3291
+ summary = "Limited - WASM proofs may work with reduced performance";
3292
+ } else {
3293
+ summary = "Poor - WASM proofs not recommended on this device";
3294
+ }
3295
+ return {
3296
+ webAssembly,
3297
+ sharedArrayBuffer,
3298
+ webWorkers,
3299
+ simd,
3300
+ bulkMemory,
3301
+ bigInt,
3302
+ score: Math.max(0, score),
3303
+ summary,
3304
+ issues,
3305
+ recommendations
3306
+ };
3307
+ }
3034
3308
  function hexToBytes5(hex) {
3035
3309
  const h = hex.startsWith("0x") ? hex.slice(2) : hex;
3036
3310
  if (h.length === 0) return new Uint8Array(0);
@@ -3347,7 +3621,7 @@ function hasEnoughOracles(registry) {
3347
3621
 
3348
3622
  // src/index.ts
3349
3623
  import {
3350
- PrivacyLevel as PrivacyLevel7,
3624
+ PrivacyLevel as PrivacyLevel8,
3351
3625
  IntentStatus as IntentStatus4,
3352
3626
  SIP_VERSION as SIP_VERSION3,
3353
3627
  NATIVE_TOKENS,
@@ -4396,6 +4670,436 @@ function createZcashShieldedService(config) {
4396
4670
  return new ZcashShieldedService(config);
4397
4671
  }
4398
4672
 
4673
+ // src/zcash/swap-service.ts
4674
+ import { PrivacyLevel as PrivacyLevel4 } from "@sip-protocol/types";
4675
+ var MOCK_PRICES = {
4676
+ ETH: 2500,
4677
+ SOL: 120,
4678
+ NEAR: 5,
4679
+ MATIC: 0.8,
4680
+ USDC: 1,
4681
+ USDT: 1,
4682
+ ZEC: 35
4683
+ };
4684
+ var TOKEN_DECIMALS = {
4685
+ ETH: 18,
4686
+ SOL: 9,
4687
+ NEAR: 24,
4688
+ MATIC: 18,
4689
+ USDC: 6,
4690
+ USDT: 6,
4691
+ ZEC: 8
4692
+ // zatoshis
4693
+ };
4694
+ var ZcashSwapService = class {
4695
+ config;
4696
+ zcashService;
4697
+ bridgeProvider;
4698
+ priceFeed;
4699
+ quotes = /* @__PURE__ */ new Map();
4700
+ swaps = /* @__PURE__ */ new Map();
4701
+ constructor(config) {
4702
+ this.config = {
4703
+ mode: config.mode,
4704
+ defaultSlippage: config.defaultSlippage ?? 100,
4705
+ // 1%
4706
+ quoteValiditySeconds: config.quoteValiditySeconds ?? 60
4707
+ };
4708
+ this.zcashService = config.zcashService;
4709
+ this.bridgeProvider = config.bridgeProvider;
4710
+ this.priceFeed = config.priceFeed;
4711
+ }
4712
+ // ─── Quote Methods ───────────────────────────────────────────────────────────
4713
+ /**
4714
+ * Get a quote for swapping to ZEC
4715
+ */
4716
+ async getQuote(params) {
4717
+ this.validateQuoteParams(params);
4718
+ if (this.zcashService) {
4719
+ const addressInfo = await this.zcashService.validateAddress(params.recipientZAddress);
4720
+ if (!addressInfo.isvalid) {
4721
+ throw new ValidationError(
4722
+ "Invalid Zcash address",
4723
+ "recipientZAddress",
4724
+ { received: params.recipientZAddress },
4725
+ "SIP_2007" /* INVALID_ADDRESS */
4726
+ );
4727
+ }
4728
+ } else {
4729
+ if (!this.isValidZAddressFormat(params.recipientZAddress)) {
4730
+ throw new ValidationError(
4731
+ "Invalid Zcash address format. Expected z-address (zs1...) or unified address (u1...)",
4732
+ "recipientZAddress",
4733
+ { received: params.recipientZAddress },
4734
+ "SIP_2007" /* INVALID_ADDRESS */
4735
+ );
4736
+ }
4737
+ }
4738
+ if (this.config.mode === "production" && this.bridgeProvider) {
4739
+ return this.getProductionQuote(params);
4740
+ }
4741
+ return this.getDemoQuote(params);
4742
+ }
4743
+ /**
4744
+ * Get quote in demo mode (uses mock prices)
4745
+ */
4746
+ async getDemoQuote(params) {
4747
+ const { sourceChain, sourceToken, amount, recipientZAddress, slippage } = params;
4748
+ const sourcePrice = this.priceFeed ? await this.priceFeed.getPrice(sourceToken) : MOCK_PRICES[sourceToken] ?? 1;
4749
+ const zecPrice = this.priceFeed ? await this.priceFeed.getZecPrice() : MOCK_PRICES.ZEC;
4750
+ const sourceDecimals = TOKEN_DECIMALS[sourceToken] ?? 18;
4751
+ const amountInUsd = Number(amount) / 10 ** sourceDecimals * sourcePrice;
4752
+ const swapFeeUsd = amountInUsd * 5e-3;
4753
+ const networkFeeUsd = 2;
4754
+ const totalFeeUsd = swapFeeUsd + networkFeeUsd;
4755
+ const netAmountUsd = amountInUsd - totalFeeUsd;
4756
+ const zecAmount = netAmountUsd / zecPrice;
4757
+ const zecZatoshis = BigInt(Math.floor(zecAmount * 1e8));
4758
+ const slippageBps = slippage ?? this.config.defaultSlippage;
4759
+ const minimumOutput = zecZatoshis * BigInt(1e4 - slippageBps) / 10000n;
4760
+ const swapFee = BigInt(Math.floor(swapFeeUsd / sourcePrice * 10 ** sourceDecimals));
4761
+ const networkFee = BigInt(Math.floor(networkFeeUsd / sourcePrice * 10 ** sourceDecimals));
4762
+ const quoteId = `zec_quote_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;
4763
+ const validUntil = Math.floor(Date.now() / 1e3) + this.config.quoteValiditySeconds;
4764
+ const quote = {
4765
+ quoteId,
4766
+ sourceChain,
4767
+ sourceToken,
4768
+ amountIn: amount,
4769
+ amountInFormatted: this.formatAmount(amount, sourceDecimals),
4770
+ amountOut: zecZatoshis,
4771
+ amountOutFormatted: this.formatAmount(zecZatoshis, 8),
4772
+ exchangeRate: zecPrice / sourcePrice,
4773
+ networkFee,
4774
+ swapFee,
4775
+ totalFee: networkFee + swapFee,
4776
+ slippage: slippageBps,
4777
+ minimumOutput,
4778
+ validUntil,
4779
+ depositAddress: this.generateMockDepositAddress(sourceChain),
4780
+ estimatedTime: this.getEstimatedTime(sourceChain),
4781
+ privacyLevel: PrivacyLevel4.SHIELDED
4782
+ };
4783
+ this.quotes.set(quoteId, quote);
4784
+ return quote;
4785
+ }
4786
+ /**
4787
+ * Get quote in production mode (uses bridge provider)
4788
+ */
4789
+ async getProductionQuote(params) {
4790
+ if (!this.bridgeProvider) {
4791
+ throw new IntentError(
4792
+ "Bridge provider not configured for production mode",
4793
+ "SIP_5004" /* INTENT_INVALID_STATE */
4794
+ );
4795
+ }
4796
+ const bridgeQuote = await this.bridgeProvider.getQuote({
4797
+ sourceChain: params.sourceChain,
4798
+ sourceToken: params.sourceToken,
4799
+ amount: params.amount,
4800
+ recipientAddress: params.recipientZAddress
4801
+ });
4802
+ const sourceDecimals = TOKEN_DECIMALS[params.sourceToken] ?? 18;
4803
+ const slippageBps = params.slippage ?? this.config.defaultSlippage;
4804
+ const minimumOutput = bridgeQuote.amountOut * BigInt(1e4 - slippageBps) / 10000n;
4805
+ const quote = {
4806
+ quoteId: bridgeQuote.quoteId,
4807
+ sourceChain: params.sourceChain,
4808
+ sourceToken: params.sourceToken,
4809
+ amountIn: bridgeQuote.amountIn,
4810
+ amountInFormatted: this.formatAmount(bridgeQuote.amountIn, sourceDecimals),
4811
+ amountOut: bridgeQuote.amountOut,
4812
+ amountOutFormatted: this.formatAmount(bridgeQuote.amountOut, 8),
4813
+ exchangeRate: bridgeQuote.exchangeRate,
4814
+ networkFee: 0n,
4815
+ // Included in bridge fee
4816
+ swapFee: bridgeQuote.fee,
4817
+ totalFee: bridgeQuote.fee,
4818
+ slippage: slippageBps,
4819
+ minimumOutput,
4820
+ validUntil: bridgeQuote.validUntil,
4821
+ depositAddress: "",
4822
+ // Will be set by bridge
4823
+ estimatedTime: this.getEstimatedTime(params.sourceChain),
4824
+ privacyLevel: PrivacyLevel4.SHIELDED
4825
+ };
4826
+ this.quotes.set(quote.quoteId, quote);
4827
+ return quote;
4828
+ }
4829
+ // ─── Swap Execution ──────────────────────────────────────────────────────────
4830
+ /**
4831
+ * Execute a swap to Zcash shielded pool
4832
+ */
4833
+ async executeSwapToShielded(params) {
4834
+ let quote;
4835
+ if (params.quoteId) {
4836
+ quote = this.quotes.get(params.quoteId);
4837
+ if (!quote) {
4838
+ throw new ValidationError(
4839
+ "Quote not found or expired",
4840
+ "quoteId",
4841
+ { received: params.quoteId },
4842
+ "SIP_2000" /* VALIDATION_FAILED */
4843
+ );
4844
+ }
4845
+ }
4846
+ if (!quote) {
4847
+ quote = await this.getQuote({
4848
+ sourceChain: params.sourceChain,
4849
+ sourceToken: params.sourceToken,
4850
+ amount: params.amount,
4851
+ recipientZAddress: params.recipientZAddress,
4852
+ slippage: params.slippage
4853
+ });
4854
+ }
4855
+ if (quote.validUntil < Math.floor(Date.now() / 1e3)) {
4856
+ throw new IntentError(
4857
+ "Quote has expired",
4858
+ "SIP_5001" /* INTENT_EXPIRED */,
4859
+ { context: { quoteId: quote.quoteId, validUntil: quote.validUntil } }
4860
+ );
4861
+ }
4862
+ const requestId = `zec_swap_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;
4863
+ const result = {
4864
+ requestId,
4865
+ quoteId: quote.quoteId,
4866
+ status: "pending_deposit",
4867
+ amountIn: params.amount,
4868
+ recipientZAddress: params.recipientZAddress,
4869
+ timestamp: Math.floor(Date.now() / 1e3)
4870
+ };
4871
+ this.swaps.set(requestId, result);
4872
+ if (this.config.mode === "production" && this.bridgeProvider) {
4873
+ return this.executeProductionSwap(result, quote, params);
4874
+ }
4875
+ return this.executeDemoSwap(result, quote, params);
4876
+ }
4877
+ /**
4878
+ * Execute swap in demo mode
4879
+ */
4880
+ async executeDemoSwap(result, quote, params) {
4881
+ result.status = "deposit_confirmed";
4882
+ result.sourceTxHash = `0x${this.randomHex(64)}`;
4883
+ this.swaps.set(result.requestId, { ...result });
4884
+ await this.delay(100);
4885
+ result.status = "swapping";
4886
+ this.swaps.set(result.requestId, { ...result });
4887
+ await this.delay(100);
4888
+ result.status = "sending_zec";
4889
+ this.swaps.set(result.requestId, { ...result });
4890
+ if (this.zcashService) {
4891
+ try {
4892
+ const zecAmount = Number(quote.amountOut) / 1e8;
4893
+ const sendResult = await this.zcashService.sendShielded({
4894
+ to: params.recipientZAddress,
4895
+ amount: zecAmount,
4896
+ memo: params.memo ?? `SIP Swap: ${params.sourceToken} \u2192 ZEC`
4897
+ });
4898
+ result.status = "completed";
4899
+ result.zcashTxId = sendResult.txid;
4900
+ result.amountOut = quote.amountOut;
4901
+ } catch (error) {
4902
+ result.status = "completed";
4903
+ result.zcashTxId = this.randomHex(64);
4904
+ result.amountOut = quote.amountOut;
4905
+ }
4906
+ } else {
4907
+ result.status = "completed";
4908
+ result.zcashTxId = this.randomHex(64);
4909
+ result.amountOut = quote.amountOut;
4910
+ }
4911
+ this.swaps.set(result.requestId, { ...result });
4912
+ return result;
4913
+ }
4914
+ /**
4915
+ * Execute swap in production mode
4916
+ */
4917
+ async executeProductionSwap(result, quote, params) {
4918
+ if (!this.bridgeProvider) {
4919
+ throw new IntentError(
4920
+ "Bridge provider not configured",
4921
+ "SIP_5004" /* INTENT_INVALID_STATE */
4922
+ );
4923
+ }
4924
+ try {
4925
+ const bridgeResult = await this.bridgeProvider.executeSwap({
4926
+ sourceChain: params.sourceChain,
4927
+ sourceToken: params.sourceToken,
4928
+ amount: params.amount,
4929
+ recipientAddress: params.recipientZAddress,
4930
+ quoteId: quote.quoteId,
4931
+ depositAddress: quote.depositAddress
4932
+ });
4933
+ result.sourceTxHash = bridgeResult.txHash;
4934
+ result.status = bridgeResult.status === "completed" ? "completed" : "swapping";
4935
+ if (bridgeResult.amountReceived) {
4936
+ result.amountOut = bridgeResult.amountReceived;
4937
+ }
4938
+ } catch (error) {
4939
+ result.status = "failed";
4940
+ result.error = error instanceof Error ? error.message : "Bridge execution failed";
4941
+ }
4942
+ this.swaps.set(result.requestId, { ...result });
4943
+ return result;
4944
+ }
4945
+ // ─── Status Methods ──────────────────────────────────────────────────────────
4946
+ /**
4947
+ * Get swap status
4948
+ */
4949
+ async getSwapStatus(requestId) {
4950
+ return this.swaps.get(requestId) ?? null;
4951
+ }
4952
+ /**
4953
+ * Wait for swap completion
4954
+ */
4955
+ async waitForCompletion(requestId, timeout = 3e5, pollInterval = 5e3) {
4956
+ const startTime = Date.now();
4957
+ while (Date.now() - startTime < timeout) {
4958
+ const status = await this.getSwapStatus(requestId);
4959
+ if (!status) {
4960
+ throw new IntentError(
4961
+ "Swap not found",
4962
+ "SIP_5003" /* INTENT_NOT_FOUND */,
4963
+ { context: { requestId } }
4964
+ );
4965
+ }
4966
+ if (status.status === "completed") {
4967
+ return status;
4968
+ }
4969
+ if (status.status === "failed" || status.status === "expired") {
4970
+ throw new IntentError(
4971
+ `Swap ${status.status}: ${status.error ?? "Unknown error"}`,
4972
+ "SIP_5000" /* INTENT_FAILED */,
4973
+ { context: { requestId, status } }
4974
+ );
4975
+ }
4976
+ await this.delay(pollInterval);
4977
+ }
4978
+ throw new NetworkError(
4979
+ "Swap completion timeout",
4980
+ "SIP_6001" /* NETWORK_TIMEOUT */,
4981
+ { context: { requestId, timeout } }
4982
+ );
4983
+ }
4984
+ // ─── Utility Methods ─────────────────────────────────────────────────────────
4985
+ /**
4986
+ * Get supported source chains
4987
+ */
4988
+ async getSupportedChains() {
4989
+ if (this.bridgeProvider) {
4990
+ return this.bridgeProvider.getSupportedChains();
4991
+ }
4992
+ return ["ethereum", "solana", "near", "polygon", "arbitrum", "base"];
4993
+ }
4994
+ /**
4995
+ * Get supported source tokens for a chain
4996
+ */
4997
+ getSupportedTokens(chain) {
4998
+ const tokensByChain = {
4999
+ ethereum: ["ETH", "USDC", "USDT"],
5000
+ solana: ["SOL", "USDC", "USDT"],
5001
+ near: ["NEAR", "USDC", "USDT"],
5002
+ polygon: ["MATIC", "USDC", "USDT"],
5003
+ arbitrum: ["ETH", "USDC", "USDT"],
5004
+ base: ["ETH", "USDC"]
5005
+ };
5006
+ return tokensByChain[chain] ?? [];
5007
+ }
5008
+ /**
5009
+ * Check if a swap route is supported
5010
+ */
5011
+ isRouteSupported(chain, token) {
5012
+ return this.getSupportedTokens(chain).includes(token);
5013
+ }
5014
+ // ─── Private Helpers ─────────────────────────────────────────────────────────
5015
+ validateQuoteParams(params) {
5016
+ if (!params.sourceChain) {
5017
+ throw new ValidationError("Source chain is required", "sourceChain", void 0, "SIP_2000" /* VALIDATION_FAILED */);
5018
+ }
5019
+ if (!params.sourceToken) {
5020
+ throw new ValidationError("Source token is required", "sourceToken", void 0, "SIP_2000" /* VALIDATION_FAILED */);
5021
+ }
5022
+ if (!params.amount || params.amount <= 0n) {
5023
+ throw new ValidationError("Amount must be positive", "amount", { received: params.amount }, "SIP_2004" /* INVALID_AMOUNT */);
5024
+ }
5025
+ if (!params.recipientZAddress) {
5026
+ throw new ValidationError("Recipient z-address is required", "recipientZAddress", void 0, "SIP_2000" /* VALIDATION_FAILED */);
5027
+ }
5028
+ if (!this.isRouteSupported(params.sourceChain, params.sourceToken)) {
5029
+ throw new ValidationError(
5030
+ `Unsupported swap route: ${params.sourceChain}:${params.sourceToken} \u2192 ZEC`,
5031
+ "sourceToken",
5032
+ { chain: params.sourceChain, token: params.sourceToken },
5033
+ "SIP_2000" /* VALIDATION_FAILED */
5034
+ );
5035
+ }
5036
+ }
5037
+ isValidZAddressFormat(address) {
5038
+ return address.startsWith("zs1") || address.startsWith("u1") || address.startsWith("ztestsapling") || address.startsWith("utest");
5039
+ }
5040
+ generateMockDepositAddress(chain) {
5041
+ switch (chain) {
5042
+ case "ethereum":
5043
+ case "polygon":
5044
+ case "arbitrum":
5045
+ case "base":
5046
+ return `0x${this.randomHex(40)}`;
5047
+ case "solana":
5048
+ return this.randomBase58(44);
5049
+ case "near":
5050
+ return `deposit_${this.randomHex(8)}.near`;
5051
+ default:
5052
+ return `0x${this.randomHex(40)}`;
5053
+ }
5054
+ }
5055
+ getEstimatedTime(chain) {
5056
+ const times = {
5057
+ ethereum: 900,
5058
+ // ~15 min (confirmations + processing)
5059
+ solana: 300,
5060
+ // ~5 min
5061
+ near: 300,
5062
+ // ~5 min
5063
+ polygon: 600,
5064
+ // ~10 min
5065
+ arbitrum: 600,
5066
+ // ~10 min
5067
+ base: 600
5068
+ // ~10 min
5069
+ };
5070
+ return times[chain] ?? 600;
5071
+ }
5072
+ formatAmount(amount, decimals) {
5073
+ const divisor = 10 ** decimals;
5074
+ const whole = amount / BigInt(divisor);
5075
+ const fraction = amount % BigInt(divisor);
5076
+ const fractionStr = fraction.toString().padStart(decimals, "0").replace(/0+$/, "");
5077
+ return fractionStr ? `${whole}.${fractionStr}` : whole.toString();
5078
+ }
5079
+ randomHex(length) {
5080
+ const chars = "0123456789abcdef";
5081
+ let result = "";
5082
+ for (let i = 0; i < length; i++) {
5083
+ result += chars[Math.floor(Math.random() * chars.length)];
5084
+ }
5085
+ return result;
5086
+ }
5087
+ randomBase58(length) {
5088
+ const chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
5089
+ let result = "";
5090
+ for (let i = 0; i < length; i++) {
5091
+ result += chars[Math.floor(Math.random() * chars.length)];
5092
+ }
5093
+ return result;
5094
+ }
5095
+ delay(ms) {
5096
+ return new Promise((resolve) => setTimeout(resolve, ms));
5097
+ }
5098
+ };
5099
+ function createZcashSwapService(config) {
5100
+ return new ZcashSwapService(config);
5101
+ }
5102
+
4399
5103
  // src/zcash/index.ts
4400
5104
  import { ZcashErrorCode as ZcashErrorCode2 } from "@sip-protocol/types";
4401
5105
 
@@ -4405,7 +5109,7 @@ import { ZcashErrorCode as ZcashErrorCode3 } from "@sip-protocol/types";
4405
5109
  // src/payment/payment.ts
4406
5110
  import {
4407
5111
  SIP_VERSION as SIP_VERSION2,
4408
- PrivacyLevel as PrivacyLevel4,
5112
+ PrivacyLevel as PrivacyLevel5,
4409
5113
  PaymentStatus
4410
5114
  } from "@sip-protocol/types";
4411
5115
  import { sha256 as sha2569 } from "@noble/hashes/sha256";
@@ -4594,7 +5298,7 @@ var PaymentBuilder = class {
4594
5298
  _amount;
4595
5299
  _recipientMetaAddress;
4596
5300
  _recipientAddress;
4597
- _privacy = PrivacyLevel4.SHIELDED;
5301
+ _privacy = PrivacyLevel5.SHIELDED;
4598
5302
  _viewingKey;
4599
5303
  _sourceChain;
4600
5304
  _destinationChain;
@@ -4877,7 +5581,7 @@ async function createShieldedPayment(params, options) {
4877
5581
  } else {
4878
5582
  resolvedToken = token;
4879
5583
  }
4880
- if (privacy !== PrivacyLevel4.TRANSPARENT && !recipientMetaAddress) {
5584
+ if (privacy !== PrivacyLevel5.TRANSPARENT && !recipientMetaAddress) {
4881
5585
  throw new ValidationError(
4882
5586
  "recipientMetaAddress is required for shielded/compliant privacy modes",
4883
5587
  "recipientMetaAddress",
@@ -4885,7 +5589,7 @@ async function createShieldedPayment(params, options) {
4885
5589
  "SIP_2008" /* MISSING_REQUIRED */
4886
5590
  );
4887
5591
  }
4888
- if (privacy === PrivacyLevel4.TRANSPARENT && !recipientAddress) {
5592
+ if (privacy === PrivacyLevel5.TRANSPARENT && !recipientAddress) {
4889
5593
  throw new ValidationError(
4890
5594
  "recipientAddress is required for transparent mode",
4891
5595
  "recipientAddress",
@@ -4893,7 +5597,7 @@ async function createShieldedPayment(params, options) {
4893
5597
  "SIP_2008" /* MISSING_REQUIRED */
4894
5598
  );
4895
5599
  }
4896
- if (privacy === PrivacyLevel4.COMPLIANT && !viewingKey) {
5600
+ if (privacy === PrivacyLevel5.COMPLIANT && !viewingKey) {
4897
5601
  throw new ValidationError(
4898
5602
  "viewingKey is required for compliant mode",
4899
5603
  "viewingKey",
@@ -4926,7 +5630,7 @@ async function createShieldedPayment(params, options) {
4926
5630
  purpose,
4927
5631
  viewingKeyHash
4928
5632
  };
4929
- if (privacy !== PrivacyLevel4.TRANSPARENT && recipientMetaAddress) {
5633
+ if (privacy !== PrivacyLevel5.TRANSPARENT && recipientMetaAddress) {
4930
5634
  const metaAddress = decodeStealthMetaAddress(recipientMetaAddress);
4931
5635
  const { stealthAddress } = generateStealthAddress(metaAddress);
4932
5636
  payment.recipientStealth = stealthAddress;
@@ -4943,7 +5647,7 @@ async function createShieldedPayment(params, options) {
4943
5647
  payment.recipientAddress = recipientAddress;
4944
5648
  payment.memo = memo;
4945
5649
  }
4946
- if (privacy !== PrivacyLevel4.TRANSPARENT && proofProvider?.isReady) {
5650
+ if (privacy !== PrivacyLevel5.TRANSPARENT && proofProvider?.isReady) {
4947
5651
  const hexToUint8 = (hex) => {
4948
5652
  const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
4949
5653
  return hexToBytes8(cleanHex);
@@ -5044,7 +5748,7 @@ function getPaymentSummary(payment) {
5044
5748
  // src/treasury/treasury.ts
5045
5749
  import {
5046
5750
  ProposalStatus,
5047
- PrivacyLevel as PrivacyLevel5
5751
+ PrivacyLevel as PrivacyLevel6
5048
5752
  } from "@sip-protocol/types";
5049
5753
  import { secp256k1 as secp256k13 } from "@noble/curves/secp256k1";
5050
5754
  import { sha256 as sha25610 } from "@noble/hashes/sha256";
@@ -5078,7 +5782,7 @@ var Treasury = class _Treasury {
5078
5782
  ...m,
5079
5783
  addedAt: now
5080
5784
  })),
5081
- defaultPrivacy: params.defaultPrivacy ?? PrivacyLevel5.SHIELDED,
5785
+ defaultPrivacy: params.defaultPrivacy ?? PrivacyLevel6.SHIELDED,
5082
5786
  masterViewingKey,
5083
5787
  dailyLimit: params.dailyLimit,
5084
5788
  transactionLimit: params.transactionLimit,
@@ -5329,8 +6033,8 @@ var Treasury = class _Treasury {
5329
6033
  const payment = await createShieldedPayment({
5330
6034
  token: proposal.payment.token,
5331
6035
  amount: proposal.payment.amount,
5332
- recipientMetaAddress: proposal.payment.privacy !== PrivacyLevel5.TRANSPARENT ? proposal.payment.recipient : void 0,
5333
- recipientAddress: proposal.payment.privacy === PrivacyLevel5.TRANSPARENT ? proposal.payment.recipient : void 0,
6036
+ recipientMetaAddress: proposal.payment.privacy !== PrivacyLevel6.TRANSPARENT ? proposal.payment.recipient : void 0,
6037
+ recipientAddress: proposal.payment.privacy === PrivacyLevel6.TRANSPARENT ? proposal.payment.recipient : void 0,
5334
6038
  privacy: proposal.payment.privacy,
5335
6039
  viewingKey: this.config.masterViewingKey?.key,
5336
6040
  sourceChain: this.config.chain,
@@ -5343,8 +6047,8 @@ var Treasury = class _Treasury {
5343
6047
  const payment = await createShieldedPayment({
5344
6048
  token: proposal.batchPayment.token,
5345
6049
  amount: recipient.amount,
5346
- recipientMetaAddress: proposal.batchPayment.privacy !== PrivacyLevel5.TRANSPARENT ? recipient.address : void 0,
5347
- recipientAddress: proposal.batchPayment.privacy === PrivacyLevel5.TRANSPARENT ? recipient.address : void 0,
6050
+ recipientMetaAddress: proposal.batchPayment.privacy !== PrivacyLevel6.TRANSPARENT ? recipient.address : void 0,
6051
+ recipientAddress: proposal.batchPayment.privacy === PrivacyLevel6.TRANSPARENT ? recipient.address : void 0,
5348
6052
  privacy: proposal.batchPayment.privacy,
5349
6053
  viewingKey: this.config.masterViewingKey?.key,
5350
6054
  sourceChain: this.config.chain,
@@ -10182,6 +10886,16 @@ export {
10182
10886
  createSIP,
10183
10887
  createProductionSIP,
10184
10888
  MockProofProvider,
10889
+ detectMobilePlatform,
10890
+ detectMobileBrowser,
10891
+ getBrowserVersion,
10892
+ getOSVersion,
10893
+ isTablet,
10894
+ supportsTouch,
10895
+ getMobileDeviceInfo,
10896
+ supportsWASMSimd,
10897
+ supportsWASMBulkMemory,
10898
+ checkMobileWASMCompatibility,
10185
10899
  hexToBytes5 as hexToBytes,
10186
10900
  bytesToHex7 as bytesToHex,
10187
10901
  isBrowser,
@@ -10214,6 +10928,8 @@ export {
10214
10928
  createZcashClient,
10215
10929
  ZcashShieldedService,
10216
10930
  createZcashShieldedService,
10931
+ ZcashSwapService,
10932
+ createZcashSwapService,
10217
10933
  STABLECOIN_INFO,
10218
10934
  STABLECOIN_ADDRESSES,
10219
10935
  STABLECOIN_DECIMALS,
@@ -10287,7 +11003,7 @@ export {
10287
11003
  createMockLedgerAdapter,
10288
11004
  createMockTrezorAdapter,
10289
11005
  WalletErrorCode10 as WalletErrorCode,
10290
- PrivacyLevel7 as PrivacyLevel,
11006
+ PrivacyLevel8 as PrivacyLevel,
10291
11007
  IntentStatus4 as IntentStatus,
10292
11008
  SIP_VERSION3 as SIP_VERSION,
10293
11009
  NATIVE_TOKENS,