@sip-protocol/sdk 0.2.9 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.d.mts +100 -2
- package/dist/browser.d.ts +100 -2
- package/dist/browser.js +2116 -321
- package/dist/browser.mjs +516 -16
- package/dist/chunk-4IFOPYJF.mjs +11950 -0
- package/dist/chunk-7IMRM7LN.mjs +12149 -0
- package/dist/chunk-JNNXNTSS.mjs +11034 -0
- package/dist/chunk-W3YXIQ7L.mjs +11950 -0
- package/dist/chunk-XLEPIR2P.mjs +884 -0
- package/dist/index-Ba7njCU3.d.ts +6925 -0
- package/dist/index-Co26-vbG.d.mts +6925 -0
- package/dist/index-DqZoHYKI.d.mts +6418 -0
- package/dist/index-dTtK_DTl.d.ts +6762 -0
- package/dist/index-jnkYu-Z4.d.mts +6762 -0
- package/dist/index-vB1N1mHd.d.ts +6418 -0
- package/dist/index.d.mts +2 -5897
- package/dist/index.d.ts +2 -5897
- package/dist/index.js +1334 -199
- package/dist/index.mjs +19 -1
- package/dist/noir-BTyLXLlZ.d.mts +467 -0
- package/dist/noir-BTyLXLlZ.d.ts +467 -0
- package/dist/proofs/noir.d.mts +1 -1
- package/dist/proofs/noir.d.ts +1 -1
- package/dist/proofs/noir.js +11 -112
- package/dist/proofs/noir.mjs +10 -13
- package/package.json +3 -3
- package/src/browser.ts +23 -0
- package/src/index.ts +32 -0
- package/src/proofs/browser-utils.ts +389 -0
- package/src/proofs/browser.ts +246 -19
- package/src/proofs/circuits/funding_proof.json +1 -1
- package/src/proofs/noir.ts +14 -14
- package/src/proofs/worker.ts +426 -0
- package/src/settlement/README.md +439 -0
- package/src/settlement/backends/direct-chain.ts +569 -0
- package/src/settlement/backends/index.ts +22 -0
- package/src/settlement/backends/near-intents.ts +480 -0
- package/src/settlement/backends/zcash-native.ts +516 -0
- package/src/settlement/index.ts +47 -0
- package/src/settlement/interface.ts +397 -0
- package/src/settlement/registry.ts +269 -0
- package/src/settlement/router.ts +383 -0
package/dist/browser.js
CHANGED
|
@@ -47,7 +47,7 @@ __export(browser_exports, {
|
|
|
47
47
|
HardwareWalletError: () => HardwareWalletError,
|
|
48
48
|
IntentBuilder: () => IntentBuilder,
|
|
49
49
|
IntentError: () => IntentError,
|
|
50
|
-
IntentStatus: () =>
|
|
50
|
+
IntentStatus: () => import_types37.IntentStatus,
|
|
51
51
|
LedgerWalletAdapter: () => LedgerWalletAdapter,
|
|
52
52
|
MockEthereumAdapter: () => MockEthereumAdapter,
|
|
53
53
|
MockLedgerAdapter: () => MockLedgerAdapter,
|
|
@@ -56,36 +56,43 @@ __export(browser_exports, {
|
|
|
56
56
|
MockSolver: () => MockSolver,
|
|
57
57
|
MockTrezorAdapter: () => MockTrezorAdapter,
|
|
58
58
|
MockWalletAdapter: () => MockWalletAdapter,
|
|
59
|
-
NATIVE_TOKENS: () =>
|
|
59
|
+
NATIVE_TOKENS: () => import_types37.NATIVE_TOKENS,
|
|
60
60
|
NEARIntentsAdapter: () => NEARIntentsAdapter,
|
|
61
|
+
NEARIntentsBackend: () => NEARIntentsBackend,
|
|
61
62
|
NetworkError: () => NetworkError,
|
|
62
63
|
ORACLE_DOMAIN: () => ORACLE_DOMAIN,
|
|
63
64
|
OneClickClient: () => OneClickClient,
|
|
64
|
-
OneClickDepositMode: () =>
|
|
65
|
-
OneClickErrorCode: () =>
|
|
66
|
-
OneClickSwapStatus: () =>
|
|
67
|
-
OneClickSwapType: () =>
|
|
65
|
+
OneClickDepositMode: () => import_types41.OneClickDepositMode,
|
|
66
|
+
OneClickErrorCode: () => import_types41.OneClickErrorCode,
|
|
67
|
+
OneClickSwapStatus: () => import_types41.OneClickSwapStatus,
|
|
68
|
+
OneClickSwapType: () => import_types41.OneClickSwapType,
|
|
68
69
|
PaymentBuilder: () => PaymentBuilder,
|
|
69
|
-
PaymentStatus: () =>
|
|
70
|
-
PrivacyLevel: () =>
|
|
70
|
+
PaymentStatus: () => import_types38.PaymentStatus,
|
|
71
|
+
PrivacyLevel: () => import_types37.PrivacyLevel,
|
|
71
72
|
ProofError: () => ProofError,
|
|
72
73
|
ProofGenerationError: () => ProofGenerationError,
|
|
73
74
|
ProofNotImplementedError: () => ProofNotImplementedError,
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
ProofWorker: () => ProofWorker,
|
|
76
|
+
ProposalStatus: () => import_types39.ProposalStatus,
|
|
77
|
+
ReportStatus: () => import_types40.ReportStatus,
|
|
76
78
|
SIP: () => SIP,
|
|
77
79
|
SIPError: () => SIPError,
|
|
78
|
-
SIP_VERSION: () =>
|
|
80
|
+
SIP_VERSION: () => import_types37.SIP_VERSION,
|
|
79
81
|
STABLECOIN_ADDRESSES: () => STABLECOIN_ADDRESSES,
|
|
80
82
|
STABLECOIN_DECIMALS: () => STABLECOIN_DECIMALS,
|
|
81
83
|
STABLECOIN_INFO: () => STABLECOIN_INFO,
|
|
84
|
+
SettlementRegistry: () => SettlementRegistry,
|
|
85
|
+
SettlementRegistryError: () => SettlementRegistryError,
|
|
86
|
+
SmartRouter: () => SmartRouter,
|
|
82
87
|
SolanaWalletAdapter: () => SolanaWalletAdapter,
|
|
88
|
+
SwapStatus: () => SwapStatus,
|
|
83
89
|
Treasury: () => Treasury,
|
|
84
90
|
TrezorWalletAdapter: () => TrezorWalletAdapter,
|
|
85
91
|
ValidationError: () => ValidationError,
|
|
86
92
|
WalletError: () => WalletError,
|
|
87
|
-
WalletErrorCode: () =>
|
|
88
|
-
ZcashErrorCode: () =>
|
|
93
|
+
WalletErrorCode: () => import_types36.WalletErrorCode,
|
|
94
|
+
ZcashErrorCode: () => import_types42.ZcashErrorCode,
|
|
95
|
+
ZcashNativeBackend: () => ZcashNativeBackend,
|
|
89
96
|
ZcashRPCClient: () => ZcashRPCClient,
|
|
90
97
|
ZcashRPCError: () => ZcashRPCError,
|
|
91
98
|
ZcashShieldedService: () => ZcashShieldedService,
|
|
@@ -98,6 +105,7 @@ __export(browser_exports, {
|
|
|
98
105
|
browserBytesToHex: () => bytesToHex7,
|
|
99
106
|
browserHexToBytes: () => hexToBytes5,
|
|
100
107
|
checkEd25519StealthAddress: () => checkEd25519StealthAddress,
|
|
108
|
+
checkMobileWASMCompatibility: () => checkMobileWASMCompatibility,
|
|
101
109
|
checkStealthAddress: () => checkStealthAddress,
|
|
102
110
|
commit: () => commit,
|
|
103
111
|
commitZero: () => commitZero,
|
|
@@ -114,15 +122,19 @@ __export(browser_exports, {
|
|
|
114
122
|
createMockSolver: () => createMockSolver,
|
|
115
123
|
createMockTrezorAdapter: () => createMockTrezorAdapter,
|
|
116
124
|
createNEARIntentsAdapter: () => createNEARIntentsAdapter,
|
|
125
|
+
createNEARIntentsBackend: () => createNEARIntentsBackend,
|
|
117
126
|
createOracleRegistry: () => createOracleRegistry,
|
|
118
127
|
createProductionSIP: () => createProductionSIP,
|
|
119
128
|
createSIP: () => createSIP,
|
|
120
129
|
createShieldedIntent: () => createShieldedIntent,
|
|
121
130
|
createShieldedPayment: () => createShieldedPayment,
|
|
131
|
+
createSmartRouter: () => createSmartRouter,
|
|
122
132
|
createSolanaAdapter: () => createSolanaAdapter,
|
|
123
133
|
createTrezorAdapter: () => createTrezorAdapter,
|
|
124
134
|
createWalletFactory: () => createWalletFactory,
|
|
135
|
+
createWorkerBlobURL: () => createWorkerBlobURL,
|
|
125
136
|
createZcashClient: () => createZcashClient,
|
|
137
|
+
createZcashNativeBackend: () => createZcashNativeBackend,
|
|
126
138
|
createZcashShieldedService: () => createZcashShieldedService,
|
|
127
139
|
createZcashSwapService: () => createZcashSwapService,
|
|
128
140
|
decodeStealthMetaAddress: () => decodeStealthMetaAddress,
|
|
@@ -136,6 +148,8 @@ __export(browser_exports, {
|
|
|
136
148
|
deserializeIntent: () => deserializeIntent,
|
|
137
149
|
deserializePayment: () => deserializePayment,
|
|
138
150
|
detectEthereumWallets: () => detectEthereumWallets,
|
|
151
|
+
detectMobileBrowser: () => detectMobileBrowser,
|
|
152
|
+
detectMobilePlatform: () => detectMobilePlatform,
|
|
139
153
|
detectSolanaWallets: () => detectSolanaWallets,
|
|
140
154
|
ed25519PublicKeyToNearAddress: () => ed25519PublicKeyToNearAddress,
|
|
141
155
|
ed25519PublicKeyToSolanaAddress: () => ed25519PublicKeyToSolanaAddress,
|
|
@@ -156,6 +170,7 @@ __export(browser_exports, {
|
|
|
156
170
|
getActiveOracles: () => getActiveOracles,
|
|
157
171
|
getAvailableTransports: () => getAvailableTransports,
|
|
158
172
|
getBrowserInfo: () => getBrowserInfo,
|
|
173
|
+
getBrowserVersion: () => getBrowserVersion,
|
|
159
174
|
getChainNumericId: () => getChainNumericId,
|
|
160
175
|
getChainsForStablecoin: () => getChainsForStablecoin,
|
|
161
176
|
getCurveForChain: () => getCurveForChain,
|
|
@@ -165,6 +180,8 @@ __export(browser_exports, {
|
|
|
165
180
|
getEthereumProvider: () => getEthereumProvider,
|
|
166
181
|
getGenerators: () => getGenerators,
|
|
167
182
|
getIntentSummary: () => getIntentSummary,
|
|
183
|
+
getMobileDeviceInfo: () => getMobileDeviceInfo,
|
|
184
|
+
getOSVersion: () => getOSVersion,
|
|
168
185
|
getPaymentSummary: () => getPaymentSummary,
|
|
169
186
|
getPaymentTimeRemaining: () => getPaymentTimeRemaining,
|
|
170
187
|
getPrivacyConfig: () => getPrivacyConfig,
|
|
@@ -185,11 +202,12 @@ __export(browser_exports, {
|
|
|
185
202
|
isExpired: () => isExpired,
|
|
186
203
|
isNonNegativeAmount: () => isNonNegativeAmount,
|
|
187
204
|
isPaymentExpired: () => isPaymentExpired,
|
|
188
|
-
isPrivate: () =>
|
|
205
|
+
isPrivate: () => import_types37.isPrivate,
|
|
189
206
|
isPrivateWalletAdapter: () => isPrivateWalletAdapter,
|
|
190
207
|
isSIPError: () => isSIPError,
|
|
191
208
|
isStablecoin: () => isStablecoin,
|
|
192
209
|
isStablecoinOnChain: () => isStablecoinOnChain,
|
|
210
|
+
isTablet: () => isTablet,
|
|
193
211
|
isValidAmount: () => isValidAmount,
|
|
194
212
|
isValidChainId: () => isValidChainId,
|
|
195
213
|
isValidCompressedPublicKey: () => isValidCompressedPublicKey,
|
|
@@ -221,7 +239,10 @@ __export(browser_exports, {
|
|
|
221
239
|
subtractBlindings: () => subtractBlindings,
|
|
222
240
|
subtractCommitments: () => subtractCommitments,
|
|
223
241
|
supportsSharedArrayBuffer: () => supportsSharedArrayBuffer,
|
|
224
|
-
|
|
242
|
+
supportsTouch: () => supportsTouch,
|
|
243
|
+
supportsViewingKey: () => import_types37.supportsViewingKey,
|
|
244
|
+
supportsWASMBulkMemory: () => supportsWASMBulkMemory,
|
|
245
|
+
supportsWASMSimd: () => supportsWASMSimd,
|
|
225
246
|
supportsWebBluetooth: () => supportsWebBluetooth,
|
|
226
247
|
supportsWebHID: () => supportsWebHID,
|
|
227
248
|
supportsWebUSB: () => supportsWebUSB,
|
|
@@ -3460,6 +3481,280 @@ var MockProofProvider = class {
|
|
|
3460
3481
|
};
|
|
3461
3482
|
|
|
3462
3483
|
// src/proofs/browser-utils.ts
|
|
3484
|
+
function detectMobilePlatform() {
|
|
3485
|
+
if (typeof navigator === "undefined") return "desktop";
|
|
3486
|
+
const ua = navigator.userAgent.toLowerCase();
|
|
3487
|
+
if (/iphone|ipad|ipod/.test(ua) || navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1) {
|
|
3488
|
+
return "ios";
|
|
3489
|
+
}
|
|
3490
|
+
if (/android/.test(ua)) {
|
|
3491
|
+
return "android";
|
|
3492
|
+
}
|
|
3493
|
+
if (/mobile|webos|blackberry|opera mini|opera mobi|iemobile|wpdesktop/.test(ua)) {
|
|
3494
|
+
return "other";
|
|
3495
|
+
}
|
|
3496
|
+
return "desktop";
|
|
3497
|
+
}
|
|
3498
|
+
function detectMobileBrowser() {
|
|
3499
|
+
if (typeof navigator === "undefined") return "other";
|
|
3500
|
+
const ua = navigator.userAgent.toLowerCase();
|
|
3501
|
+
if (/safari/.test(ua) && /iphone|ipad|ipod/.test(ua) && !/crios|fxios/.test(ua)) {
|
|
3502
|
+
return "safari";
|
|
3503
|
+
}
|
|
3504
|
+
if (/chrome|crios/.test(ua) && !/edg|opr|samsung/.test(ua)) {
|
|
3505
|
+
return "chrome";
|
|
3506
|
+
}
|
|
3507
|
+
if (/firefox|fxios/.test(ua)) {
|
|
3508
|
+
return "firefox";
|
|
3509
|
+
}
|
|
3510
|
+
if (/samsung/.test(ua)) {
|
|
3511
|
+
return "samsung";
|
|
3512
|
+
}
|
|
3513
|
+
if (/opr|opera/.test(ua)) {
|
|
3514
|
+
return "opera";
|
|
3515
|
+
}
|
|
3516
|
+
if (/edg/.test(ua)) {
|
|
3517
|
+
return "edge";
|
|
3518
|
+
}
|
|
3519
|
+
return "other";
|
|
3520
|
+
}
|
|
3521
|
+
function getBrowserVersion() {
|
|
3522
|
+
if (typeof navigator === "undefined") return null;
|
|
3523
|
+
const ua = navigator.userAgent;
|
|
3524
|
+
const browser = detectMobileBrowser();
|
|
3525
|
+
const patterns = {
|
|
3526
|
+
safari: /version\/(\d+(\.\d+)*)/i,
|
|
3527
|
+
chrome: /chrome\/(\d+(\.\d+)*)|crios\/(\d+(\.\d+)*)/i,
|
|
3528
|
+
firefox: /firefox\/(\d+(\.\d+)*)|fxios\/(\d+(\.\d+)*)/i,
|
|
3529
|
+
samsung: /samsungbrowser\/(\d+(\.\d+)*)/i,
|
|
3530
|
+
opera: /opr\/(\d+(\.\d+)*)/i,
|
|
3531
|
+
edge: /edg\/(\d+(\.\d+)*)/i,
|
|
3532
|
+
other: /version\/(\d+(\.\d+)*)/i
|
|
3533
|
+
};
|
|
3534
|
+
const pattern = patterns[browser] || patterns.other;
|
|
3535
|
+
const match = ua.match(pattern);
|
|
3536
|
+
if (match) {
|
|
3537
|
+
for (let i = 1; i < match.length; i++) {
|
|
3538
|
+
if (match[i]) return match[i];
|
|
3539
|
+
}
|
|
3540
|
+
}
|
|
3541
|
+
return null;
|
|
3542
|
+
}
|
|
3543
|
+
function getOSVersion() {
|
|
3544
|
+
if (typeof navigator === "undefined") return null;
|
|
3545
|
+
const ua = navigator.userAgent;
|
|
3546
|
+
const platform = detectMobilePlatform();
|
|
3547
|
+
if (platform === "ios") {
|
|
3548
|
+
const match = ua.match(/os (\d+[_\d]*)/i);
|
|
3549
|
+
return match ? match[1].replace(/_/g, ".") : null;
|
|
3550
|
+
}
|
|
3551
|
+
if (platform === "android") {
|
|
3552
|
+
const match = ua.match(/android (\d+(\.\d+)*)/i);
|
|
3553
|
+
return match ? match[1] : null;
|
|
3554
|
+
}
|
|
3555
|
+
return null;
|
|
3556
|
+
}
|
|
3557
|
+
function isTablet() {
|
|
3558
|
+
if (typeof navigator === "undefined") return false;
|
|
3559
|
+
const ua = navigator.userAgent.toLowerCase();
|
|
3560
|
+
if (/ipad/.test(ua) || navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1) {
|
|
3561
|
+
return true;
|
|
3562
|
+
}
|
|
3563
|
+
if (/android/.test(ua) && !/mobile/.test(ua)) {
|
|
3564
|
+
return true;
|
|
3565
|
+
}
|
|
3566
|
+
return false;
|
|
3567
|
+
}
|
|
3568
|
+
function supportsTouch() {
|
|
3569
|
+
if (typeof window === "undefined") return false;
|
|
3570
|
+
return "ontouchstart" in window || navigator.maxTouchPoints > 0;
|
|
3571
|
+
}
|
|
3572
|
+
function getMobileDeviceInfo() {
|
|
3573
|
+
const platform = detectMobilePlatform();
|
|
3574
|
+
return {
|
|
3575
|
+
isMobile: platform !== "desktop",
|
|
3576
|
+
platform,
|
|
3577
|
+
browser: detectMobileBrowser(),
|
|
3578
|
+
browserVersion: getBrowserVersion(),
|
|
3579
|
+
osVersion: getOSVersion(),
|
|
3580
|
+
isTablet: isTablet(),
|
|
3581
|
+
supportsTouch: supportsTouch(),
|
|
3582
|
+
deviceMemoryGB: (
|
|
3583
|
+
// @ts-expect-error - deviceMemory is non-standard
|
|
3584
|
+
typeof navigator !== "undefined" && navigator.deviceMemory ? (
|
|
3585
|
+
// @ts-expect-error - deviceMemory is non-standard
|
|
3586
|
+
navigator.deviceMemory
|
|
3587
|
+
) : null
|
|
3588
|
+
),
|
|
3589
|
+
hardwareConcurrency: typeof navigator !== "undefined" && navigator.hardwareConcurrency ? navigator.hardwareConcurrency : null
|
|
3590
|
+
};
|
|
3591
|
+
}
|
|
3592
|
+
function supportsWASMSimd() {
|
|
3593
|
+
try {
|
|
3594
|
+
return WebAssembly.validate(
|
|
3595
|
+
new Uint8Array([
|
|
3596
|
+
0,
|
|
3597
|
+
97,
|
|
3598
|
+
115,
|
|
3599
|
+
109,
|
|
3600
|
+
1,
|
|
3601
|
+
0,
|
|
3602
|
+
0,
|
|
3603
|
+
0,
|
|
3604
|
+
1,
|
|
3605
|
+
5,
|
|
3606
|
+
1,
|
|
3607
|
+
96,
|
|
3608
|
+
0,
|
|
3609
|
+
1,
|
|
3610
|
+
123,
|
|
3611
|
+
3,
|
|
3612
|
+
2,
|
|
3613
|
+
1,
|
|
3614
|
+
0,
|
|
3615
|
+
10,
|
|
3616
|
+
10,
|
|
3617
|
+
1,
|
|
3618
|
+
8,
|
|
3619
|
+
0,
|
|
3620
|
+
65,
|
|
3621
|
+
0,
|
|
3622
|
+
253,
|
|
3623
|
+
15,
|
|
3624
|
+
253,
|
|
3625
|
+
98,
|
|
3626
|
+
11
|
|
3627
|
+
])
|
|
3628
|
+
);
|
|
3629
|
+
} catch {
|
|
3630
|
+
return false;
|
|
3631
|
+
}
|
|
3632
|
+
}
|
|
3633
|
+
function supportsWASMBulkMemory() {
|
|
3634
|
+
try {
|
|
3635
|
+
return WebAssembly.validate(
|
|
3636
|
+
new Uint8Array([
|
|
3637
|
+
0,
|
|
3638
|
+
97,
|
|
3639
|
+
115,
|
|
3640
|
+
109,
|
|
3641
|
+
1,
|
|
3642
|
+
0,
|
|
3643
|
+
0,
|
|
3644
|
+
0,
|
|
3645
|
+
1,
|
|
3646
|
+
4,
|
|
3647
|
+
1,
|
|
3648
|
+
96,
|
|
3649
|
+
0,
|
|
3650
|
+
0,
|
|
3651
|
+
3,
|
|
3652
|
+
2,
|
|
3653
|
+
1,
|
|
3654
|
+
0,
|
|
3655
|
+
5,
|
|
3656
|
+
3,
|
|
3657
|
+
1,
|
|
3658
|
+
0,
|
|
3659
|
+
1,
|
|
3660
|
+
10,
|
|
3661
|
+
13,
|
|
3662
|
+
1,
|
|
3663
|
+
11,
|
|
3664
|
+
0,
|
|
3665
|
+
65,
|
|
3666
|
+
0,
|
|
3667
|
+
65,
|
|
3668
|
+
0,
|
|
3669
|
+
65,
|
|
3670
|
+
0,
|
|
3671
|
+
252,
|
|
3672
|
+
11,
|
|
3673
|
+
0,
|
|
3674
|
+
11
|
|
3675
|
+
])
|
|
3676
|
+
);
|
|
3677
|
+
} catch {
|
|
3678
|
+
return false;
|
|
3679
|
+
}
|
|
3680
|
+
}
|
|
3681
|
+
function checkMobileWASMCompatibility() {
|
|
3682
|
+
const issues = [];
|
|
3683
|
+
const recommendations = [];
|
|
3684
|
+
let score = 100;
|
|
3685
|
+
const webAssembly = typeof WebAssembly !== "undefined";
|
|
3686
|
+
if (!webAssembly) {
|
|
3687
|
+
issues.push("WebAssembly not supported");
|
|
3688
|
+
score -= 50;
|
|
3689
|
+
}
|
|
3690
|
+
const sharedArrayBuffer = supportsSharedArrayBuffer();
|
|
3691
|
+
if (!sharedArrayBuffer) {
|
|
3692
|
+
issues.push("SharedArrayBuffer not available (requires COOP/COEP headers)");
|
|
3693
|
+
recommendations.push("Server must send Cross-Origin-Opener-Policy: same-origin");
|
|
3694
|
+
recommendations.push("Server must send Cross-Origin-Embedder-Policy: require-corp");
|
|
3695
|
+
score -= 20;
|
|
3696
|
+
}
|
|
3697
|
+
const webWorkers = supportsWebWorkers();
|
|
3698
|
+
if (!webWorkers) {
|
|
3699
|
+
issues.push("Web Workers not supported");
|
|
3700
|
+
recommendations.push("Consider using a polyfill or fallback to main-thread execution");
|
|
3701
|
+
score -= 15;
|
|
3702
|
+
}
|
|
3703
|
+
const simd = supportsWASMSimd();
|
|
3704
|
+
if (!simd) {
|
|
3705
|
+
recommendations.push("WASM SIMD not supported - proofs will be slower");
|
|
3706
|
+
score -= 5;
|
|
3707
|
+
}
|
|
3708
|
+
const bulkMemory = supportsWASMBulkMemory();
|
|
3709
|
+
if (!bulkMemory) {
|
|
3710
|
+
recommendations.push("WASM bulk memory not supported - may affect performance");
|
|
3711
|
+
score -= 5;
|
|
3712
|
+
}
|
|
3713
|
+
const bigInt = typeof BigInt !== "undefined";
|
|
3714
|
+
if (!bigInt) {
|
|
3715
|
+
issues.push("BigInt not supported (required for 64-bit operations)");
|
|
3716
|
+
score -= 10;
|
|
3717
|
+
}
|
|
3718
|
+
const deviceInfo = getMobileDeviceInfo();
|
|
3719
|
+
if (deviceInfo.isMobile) {
|
|
3720
|
+
if (deviceInfo.deviceMemoryGB !== null && deviceInfo.deviceMemoryGB < 2) {
|
|
3721
|
+
recommendations.push(`Low device memory (${deviceInfo.deviceMemoryGB}GB) - may experience issues with large proofs`);
|
|
3722
|
+
score -= 5;
|
|
3723
|
+
}
|
|
3724
|
+
if (deviceInfo.platform === "ios" && deviceInfo.browser === "safari") {
|
|
3725
|
+
if (!sharedArrayBuffer) {
|
|
3726
|
+
recommendations.push("iOS Safari requires iOS 15.2+ for SharedArrayBuffer support");
|
|
3727
|
+
}
|
|
3728
|
+
}
|
|
3729
|
+
if (deviceInfo.platform === "android" && deviceInfo.browser === "chrome") {
|
|
3730
|
+
if (!sharedArrayBuffer) {
|
|
3731
|
+
recommendations.push("Ensure COOP/COEP headers are set - Chrome Android requires them");
|
|
3732
|
+
}
|
|
3733
|
+
}
|
|
3734
|
+
}
|
|
3735
|
+
let summary;
|
|
3736
|
+
if (score >= 90) {
|
|
3737
|
+
summary = "Excellent - Full WASM proof support";
|
|
3738
|
+
} else if (score >= 70) {
|
|
3739
|
+
summary = "Good - WASM proofs supported with minor limitations";
|
|
3740
|
+
} else if (score >= 50) {
|
|
3741
|
+
summary = "Limited - WASM proofs may work with reduced performance";
|
|
3742
|
+
} else {
|
|
3743
|
+
summary = "Poor - WASM proofs not recommended on this device";
|
|
3744
|
+
}
|
|
3745
|
+
return {
|
|
3746
|
+
webAssembly,
|
|
3747
|
+
sharedArrayBuffer,
|
|
3748
|
+
webWorkers,
|
|
3749
|
+
simd,
|
|
3750
|
+
bulkMemory,
|
|
3751
|
+
bigInt,
|
|
3752
|
+
score: Math.max(0, score),
|
|
3753
|
+
summary,
|
|
3754
|
+
issues,
|
|
3755
|
+
recommendations
|
|
3756
|
+
};
|
|
3757
|
+
}
|
|
3463
3758
|
function hexToBytes5(hex) {
|
|
3464
3759
|
const h = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
3465
3760
|
if (h.length === 0) return new Uint8Array(0);
|
|
@@ -3775,10 +4070,10 @@ function hasEnoughOracles(registry) {
|
|
|
3775
4070
|
}
|
|
3776
4071
|
|
|
3777
4072
|
// src/index.ts
|
|
3778
|
-
var import_types34 = require("@sip-protocol/types");
|
|
3779
|
-
var import_types35 = require("@sip-protocol/types");
|
|
3780
|
-
var import_types36 = require("@sip-protocol/types");
|
|
3781
4073
|
var import_types37 = require("@sip-protocol/types");
|
|
4074
|
+
var import_types38 = require("@sip-protocol/types");
|
|
4075
|
+
var import_types39 = require("@sip-protocol/types");
|
|
4076
|
+
var import_types40 = require("@sip-protocol/types");
|
|
3782
4077
|
|
|
3783
4078
|
// src/solver/mock-solver.ts
|
|
3784
4079
|
var import_types7 = require("@sip-protocol/types");
|
|
@@ -3948,25 +4243,1142 @@ var MockSolver = class {
|
|
|
3948
4243
|
async getStatus(intentId) {
|
|
3949
4244
|
return this.pendingFulfillments.get(intentId) ?? null;
|
|
3950
4245
|
}
|
|
3951
|
-
/**
|
|
3952
|
-
* Reset solver state (for testing)
|
|
3953
|
-
*/
|
|
3954
|
-
reset() {
|
|
3955
|
-
this.pendingFulfillments.clear();
|
|
4246
|
+
/**
|
|
4247
|
+
* Reset solver state (for testing)
|
|
4248
|
+
*/
|
|
4249
|
+
reset() {
|
|
4250
|
+
this.pendingFulfillments.clear();
|
|
4251
|
+
}
|
|
4252
|
+
delay(ms) {
|
|
4253
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
4254
|
+
}
|
|
4255
|
+
};
|
|
4256
|
+
function createMockSolver(config) {
|
|
4257
|
+
return new MockSolver(config);
|
|
4258
|
+
}
|
|
4259
|
+
|
|
4260
|
+
// src/index.ts
|
|
4261
|
+
var import_types41 = require("@sip-protocol/types");
|
|
4262
|
+
|
|
4263
|
+
// src/settlement/interface.ts
|
|
4264
|
+
var SwapStatus = /* @__PURE__ */ ((SwapStatus2) => {
|
|
4265
|
+
SwapStatus2["PENDING_DEPOSIT"] = "pending_deposit";
|
|
4266
|
+
SwapStatus2["DEPOSIT_CONFIRMED"] = "deposit_confirmed";
|
|
4267
|
+
SwapStatus2["IN_PROGRESS"] = "in_progress";
|
|
4268
|
+
SwapStatus2["SUCCESS"] = "success";
|
|
4269
|
+
SwapStatus2["FAILED"] = "failed";
|
|
4270
|
+
SwapStatus2["CANCELLED"] = "cancelled";
|
|
4271
|
+
SwapStatus2["REFUNDING"] = "refunding";
|
|
4272
|
+
SwapStatus2["REFUNDED"] = "refunded";
|
|
4273
|
+
return SwapStatus2;
|
|
4274
|
+
})(SwapStatus || {});
|
|
4275
|
+
|
|
4276
|
+
// src/settlement/registry.ts
|
|
4277
|
+
var SettlementRegistryError = class extends Error {
|
|
4278
|
+
constructor(message) {
|
|
4279
|
+
super(message);
|
|
4280
|
+
this.name = "SettlementRegistryError";
|
|
4281
|
+
}
|
|
4282
|
+
};
|
|
4283
|
+
var SettlementRegistry = class {
|
|
4284
|
+
backends = /* @__PURE__ */ new Map();
|
|
4285
|
+
/**
|
|
4286
|
+
* Register a settlement backend
|
|
4287
|
+
*
|
|
4288
|
+
* @param backend - Settlement backend to register
|
|
4289
|
+
* @throws {SettlementRegistryError} If backend with same name already exists
|
|
4290
|
+
*
|
|
4291
|
+
* @example
|
|
4292
|
+
* ```typescript
|
|
4293
|
+
* registry.register(nearIntentsBackend)
|
|
4294
|
+
* ```
|
|
4295
|
+
*/
|
|
4296
|
+
register(backend) {
|
|
4297
|
+
if (this.backends.has(backend.name)) {
|
|
4298
|
+
throw new SettlementRegistryError(
|
|
4299
|
+
`Backend '${backend.name}' is already registered`
|
|
4300
|
+
);
|
|
4301
|
+
}
|
|
4302
|
+
this.backends.set(backend.name, backend);
|
|
4303
|
+
}
|
|
4304
|
+
/**
|
|
4305
|
+
* Get a settlement backend by name
|
|
4306
|
+
*
|
|
4307
|
+
* @param name - Backend name
|
|
4308
|
+
* @returns Settlement backend
|
|
4309
|
+
* @throws {SettlementRegistryError} If backend is not found
|
|
4310
|
+
*
|
|
4311
|
+
* @example
|
|
4312
|
+
* ```typescript
|
|
4313
|
+
* const backend = registry.get('near-intents')
|
|
4314
|
+
* ```
|
|
4315
|
+
*/
|
|
4316
|
+
get(name) {
|
|
4317
|
+
const backend = this.backends.get(name);
|
|
4318
|
+
if (!backend) {
|
|
4319
|
+
throw new SettlementRegistryError(`Backend '${name}' not found`);
|
|
4320
|
+
}
|
|
4321
|
+
return backend;
|
|
4322
|
+
}
|
|
4323
|
+
/**
|
|
4324
|
+
* List all registered backend names
|
|
4325
|
+
*
|
|
4326
|
+
* @returns Array of backend names
|
|
4327
|
+
*
|
|
4328
|
+
* @example
|
|
4329
|
+
* ```typescript
|
|
4330
|
+
* const names = registry.list()
|
|
4331
|
+
* // ['near-intents', 'zcash', 'thorchain']
|
|
4332
|
+
* ```
|
|
4333
|
+
*/
|
|
4334
|
+
list() {
|
|
4335
|
+
return Array.from(this.backends.keys());
|
|
4336
|
+
}
|
|
4337
|
+
/**
|
|
4338
|
+
* Get the best backend for a specific route
|
|
4339
|
+
*
|
|
4340
|
+
* Selection criteria (in order of priority):
|
|
4341
|
+
* 1. Backends that support both source and destination chains
|
|
4342
|
+
* 2. Backends with faster average execution time
|
|
4343
|
+
* 3. First registered backend (if no execution time info)
|
|
4344
|
+
*
|
|
4345
|
+
* @param fromChain - Source chain
|
|
4346
|
+
* @param toChain - Destination chain
|
|
4347
|
+
* @returns Best settlement backend for the route
|
|
4348
|
+
* @throws {SettlementRegistryError} If no backend supports the route
|
|
4349
|
+
*
|
|
4350
|
+
* @example
|
|
4351
|
+
* ```typescript
|
|
4352
|
+
* const backend = registry.getBestForRoute('ethereum', 'solana')
|
|
4353
|
+
* const quote = await backend.getQuote({ ... })
|
|
4354
|
+
* ```
|
|
4355
|
+
*/
|
|
4356
|
+
getBestForRoute(fromChain, toChain) {
|
|
4357
|
+
const supportedBackends = [];
|
|
4358
|
+
for (const backend of Array.from(this.backends.values())) {
|
|
4359
|
+
const { supportedSourceChains, supportedDestinationChains } = backend.capabilities;
|
|
4360
|
+
const supportsSource = supportedSourceChains.includes(fromChain);
|
|
4361
|
+
const supportsDestination = supportedDestinationChains.includes(toChain);
|
|
4362
|
+
if (supportsSource && supportsDestination) {
|
|
4363
|
+
supportedBackends.push(backend);
|
|
4364
|
+
}
|
|
4365
|
+
}
|
|
4366
|
+
if (supportedBackends.length === 0) {
|
|
4367
|
+
throw new SettlementRegistryError(
|
|
4368
|
+
`No backend supports route from '${fromChain}' to '${toChain}'`
|
|
4369
|
+
);
|
|
4370
|
+
}
|
|
4371
|
+
if (supportedBackends.length === 1) {
|
|
4372
|
+
return supportedBackends[0];
|
|
4373
|
+
}
|
|
4374
|
+
supportedBackends.sort((a, b) => {
|
|
4375
|
+
const timeA = a.capabilities.averageExecutionTime ?? Infinity;
|
|
4376
|
+
const timeB = b.capabilities.averageExecutionTime ?? Infinity;
|
|
4377
|
+
return timeA - timeB;
|
|
4378
|
+
});
|
|
4379
|
+
return supportedBackends[0];
|
|
4380
|
+
}
|
|
4381
|
+
/**
|
|
4382
|
+
* Get all supported routes across all registered backends
|
|
4383
|
+
*
|
|
4384
|
+
* @returns Array of supported routes
|
|
4385
|
+
*
|
|
4386
|
+
* @example
|
|
4387
|
+
* ```typescript
|
|
4388
|
+
* const routes = registry.getSupportedRoutes()
|
|
4389
|
+
* // [
|
|
4390
|
+
* // { fromChain: 'ethereum', toChain: 'solana', backend: 'near-intents' },
|
|
4391
|
+
* // { fromChain: 'solana', toChain: 'ethereum', backend: 'near-intents' },
|
|
4392
|
+
* // { fromChain: 'ethereum', toChain: 'zcash', backend: 'zcash' },
|
|
4393
|
+
* // ...
|
|
4394
|
+
* // ]
|
|
4395
|
+
* ```
|
|
4396
|
+
*/
|
|
4397
|
+
getSupportedRoutes() {
|
|
4398
|
+
const routes = [];
|
|
4399
|
+
for (const backend of Array.from(this.backends.values())) {
|
|
4400
|
+
const { supportedSourceChains, supportedDestinationChains } = backend.capabilities;
|
|
4401
|
+
for (const fromChain of supportedSourceChains) {
|
|
4402
|
+
for (const toChain of supportedDestinationChains) {
|
|
4403
|
+
routes.push({
|
|
4404
|
+
fromChain,
|
|
4405
|
+
toChain,
|
|
4406
|
+
backend: backend.name
|
|
4407
|
+
});
|
|
4408
|
+
}
|
|
4409
|
+
}
|
|
4410
|
+
}
|
|
4411
|
+
return routes;
|
|
4412
|
+
}
|
|
4413
|
+
/**
|
|
4414
|
+
* Check if a backend is registered
|
|
4415
|
+
*
|
|
4416
|
+
* @param name - Backend name
|
|
4417
|
+
* @returns True if backend is registered
|
|
4418
|
+
*
|
|
4419
|
+
* @example
|
|
4420
|
+
* ```typescript
|
|
4421
|
+
* if (registry.has('near-intents')) {
|
|
4422
|
+
* const backend = registry.get('near-intents')
|
|
4423
|
+
* }
|
|
4424
|
+
* ```
|
|
4425
|
+
*/
|
|
4426
|
+
has(name) {
|
|
4427
|
+
return this.backends.has(name);
|
|
4428
|
+
}
|
|
4429
|
+
/**
|
|
4430
|
+
* Unregister a settlement backend
|
|
4431
|
+
*
|
|
4432
|
+
* @param name - Backend name to unregister
|
|
4433
|
+
* @returns True if backend was unregistered, false if not found
|
|
4434
|
+
*
|
|
4435
|
+
* @example
|
|
4436
|
+
* ```typescript
|
|
4437
|
+
* registry.unregister('near-intents')
|
|
4438
|
+
* ```
|
|
4439
|
+
*/
|
|
4440
|
+
unregister(name) {
|
|
4441
|
+
return this.backends.delete(name);
|
|
4442
|
+
}
|
|
4443
|
+
/**
|
|
4444
|
+
* Clear all registered backends
|
|
4445
|
+
*
|
|
4446
|
+
* @example
|
|
4447
|
+
* ```typescript
|
|
4448
|
+
* registry.clear()
|
|
4449
|
+
* ```
|
|
4450
|
+
*/
|
|
4451
|
+
clear() {
|
|
4452
|
+
this.backends.clear();
|
|
4453
|
+
}
|
|
4454
|
+
/**
|
|
4455
|
+
* Get number of registered backends
|
|
4456
|
+
*
|
|
4457
|
+
* @returns Number of registered backends
|
|
4458
|
+
*
|
|
4459
|
+
* @example
|
|
4460
|
+
* ```typescript
|
|
4461
|
+
* const count = registry.size()
|
|
4462
|
+
* ```
|
|
4463
|
+
*/
|
|
4464
|
+
size() {
|
|
4465
|
+
return this.backends.size;
|
|
4466
|
+
}
|
|
4467
|
+
};
|
|
4468
|
+
|
|
4469
|
+
// src/settlement/router.ts
|
|
4470
|
+
var SmartRouter = class {
|
|
4471
|
+
constructor(registry) {
|
|
4472
|
+
this.registry = registry;
|
|
4473
|
+
}
|
|
4474
|
+
/**
|
|
4475
|
+
* Find best routes for a swap
|
|
4476
|
+
*
|
|
4477
|
+
* Queries all compatible backends in parallel and returns sorted routes.
|
|
4478
|
+
*
|
|
4479
|
+
* @param params - Route finding parameters
|
|
4480
|
+
* @returns Sorted routes (best first)
|
|
4481
|
+
* @throws {ValidationError} If no backends support the route
|
|
4482
|
+
*/
|
|
4483
|
+
async findBestRoute(params) {
|
|
4484
|
+
const {
|
|
4485
|
+
from,
|
|
4486
|
+
to,
|
|
4487
|
+
amount,
|
|
4488
|
+
privacyLevel,
|
|
4489
|
+
preferSpeed = false,
|
|
4490
|
+
preferLowFees = true,
|
|
4491
|
+
recipientMetaAddress,
|
|
4492
|
+
senderAddress,
|
|
4493
|
+
slippageTolerance,
|
|
4494
|
+
deadline
|
|
4495
|
+
} = params;
|
|
4496
|
+
if (amount <= 0n) {
|
|
4497
|
+
throw new ValidationError("Amount must be greater than zero");
|
|
4498
|
+
}
|
|
4499
|
+
const allBackends = this.registry.list().map((name) => this.registry.get(name));
|
|
4500
|
+
const compatibleBackends = allBackends.filter((backend) => {
|
|
4501
|
+
const { supportedSourceChains, supportedDestinationChains, supportedPrivacyLevels } = backend.capabilities;
|
|
4502
|
+
const supportsRoute = supportedSourceChains.includes(from.chain) && supportedDestinationChains.includes(to.chain);
|
|
4503
|
+
const supportsPrivacy = supportedPrivacyLevels.includes(privacyLevel);
|
|
4504
|
+
return supportsRoute && supportsPrivacy;
|
|
4505
|
+
});
|
|
4506
|
+
if (compatibleBackends.length === 0) {
|
|
4507
|
+
throw new ValidationError(
|
|
4508
|
+
`No backend supports route from ${from.chain} to ${to.chain} with privacy level ${privacyLevel}`
|
|
4509
|
+
);
|
|
4510
|
+
}
|
|
4511
|
+
const quoteParams = {
|
|
4512
|
+
fromChain: from.chain,
|
|
4513
|
+
toChain: to.chain,
|
|
4514
|
+
fromToken: from.token,
|
|
4515
|
+
toToken: to.token,
|
|
4516
|
+
amount,
|
|
4517
|
+
privacyLevel,
|
|
4518
|
+
recipientMetaAddress,
|
|
4519
|
+
senderAddress,
|
|
4520
|
+
slippageTolerance,
|
|
4521
|
+
deadline
|
|
4522
|
+
};
|
|
4523
|
+
const quotePromises = compatibleBackends.map(async (backend) => {
|
|
4524
|
+
try {
|
|
4525
|
+
const quote = await backend.getQuote(quoteParams);
|
|
4526
|
+
return {
|
|
4527
|
+
backend: backend.name,
|
|
4528
|
+
quote,
|
|
4529
|
+
backendInstance: backend,
|
|
4530
|
+
success: true
|
|
4531
|
+
};
|
|
4532
|
+
} catch (error) {
|
|
4533
|
+
return {
|
|
4534
|
+
backend: backend.name,
|
|
4535
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
4536
|
+
success: false
|
|
4537
|
+
};
|
|
4538
|
+
}
|
|
4539
|
+
});
|
|
4540
|
+
const results = await Promise.all(quotePromises);
|
|
4541
|
+
const successfulRoutes = results.filter((r) => r.success).map((r) => ({
|
|
4542
|
+
backend: r.backend,
|
|
4543
|
+
quote: r.quote,
|
|
4544
|
+
backendInstance: r.backendInstance,
|
|
4545
|
+
score: 0
|
|
4546
|
+
// Will be calculated below
|
|
4547
|
+
}));
|
|
4548
|
+
if (successfulRoutes.length === 0) {
|
|
4549
|
+
const errors = results.filter((r) => !r.success).map((r) => `${r.backend}: ${r.error}`).join(", ");
|
|
4550
|
+
throw new NetworkError(
|
|
4551
|
+
`All backends failed to provide quotes: ${errors}`
|
|
4552
|
+
);
|
|
4553
|
+
}
|
|
4554
|
+
this.rankRoutes(successfulRoutes, { preferSpeed, preferLowFees });
|
|
4555
|
+
successfulRoutes.sort((a, b) => b.score - a.score);
|
|
4556
|
+
return successfulRoutes;
|
|
4557
|
+
}
|
|
4558
|
+
/**
|
|
4559
|
+
* Compare quotes from multiple routes side-by-side
|
|
4560
|
+
*
|
|
4561
|
+
* @param routes - Routes to compare (from findBestRoute)
|
|
4562
|
+
* @returns Comparison with best routes by different criteria
|
|
4563
|
+
*/
|
|
4564
|
+
compareQuotes(routes) {
|
|
4565
|
+
if (routes.length === 0) {
|
|
4566
|
+
return {
|
|
4567
|
+
routes: [],
|
|
4568
|
+
bestByCost: null,
|
|
4569
|
+
bestBySpeed: null,
|
|
4570
|
+
bestByPrivacy: null,
|
|
4571
|
+
metadata: {
|
|
4572
|
+
totalQueried: 0,
|
|
4573
|
+
failures: [],
|
|
4574
|
+
queriedAt: Date.now()
|
|
4575
|
+
}
|
|
4576
|
+
};
|
|
4577
|
+
}
|
|
4578
|
+
const bestByCost = [...routes].sort((a, b) => {
|
|
4579
|
+
const costA = this.calculateTotalCost(a.quote);
|
|
4580
|
+
const costB = this.calculateTotalCost(b.quote);
|
|
4581
|
+
return costA - costB;
|
|
4582
|
+
})[0];
|
|
4583
|
+
const bestBySpeed = [...routes].sort((a, b) => {
|
|
4584
|
+
const timeA = a.quote.estimatedTime ?? Infinity;
|
|
4585
|
+
const timeB = b.quote.estimatedTime ?? Infinity;
|
|
4586
|
+
return timeA - timeB;
|
|
4587
|
+
})[0];
|
|
4588
|
+
const bestByPrivacy = [...routes].find((route) => {
|
|
4589
|
+
const { supportedPrivacyLevels } = route.backendInstance.capabilities;
|
|
4590
|
+
return supportedPrivacyLevels.includes("shielded") || supportedPrivacyLevels.includes("compliant");
|
|
4591
|
+
}) || routes[0];
|
|
4592
|
+
return {
|
|
4593
|
+
routes,
|
|
4594
|
+
bestByCost,
|
|
4595
|
+
bestBySpeed,
|
|
4596
|
+
bestByPrivacy,
|
|
4597
|
+
metadata: {
|
|
4598
|
+
totalQueried: routes.length,
|
|
4599
|
+
failures: [],
|
|
4600
|
+
// Could track from findBestRoute
|
|
4601
|
+
queriedAt: Date.now()
|
|
4602
|
+
}
|
|
4603
|
+
};
|
|
4604
|
+
}
|
|
4605
|
+
/**
|
|
4606
|
+
* Rank routes by score
|
|
4607
|
+
*
|
|
4608
|
+
* Scoring algorithm:
|
|
4609
|
+
* - Base score: 100
|
|
4610
|
+
* - Cost: Lower fees = higher score (up to +50)
|
|
4611
|
+
* - Speed: Faster execution = higher score (up to +30)
|
|
4612
|
+
* - Privacy: Better privacy support = higher score (up to +20)
|
|
4613
|
+
*
|
|
4614
|
+
* @private
|
|
4615
|
+
*/
|
|
4616
|
+
rankRoutes(routes, preferences) {
|
|
4617
|
+
const { preferSpeed, preferLowFees } = preferences;
|
|
4618
|
+
const costs = routes.map((r) => this.calculateTotalCost(r.quote));
|
|
4619
|
+
const times = routes.map((r) => r.quote.estimatedTime ?? Infinity);
|
|
4620
|
+
const minCost = Math.min(...costs);
|
|
4621
|
+
const maxCost = Math.max(...costs);
|
|
4622
|
+
const minTime = Math.min(...times.filter((t) => t !== Infinity));
|
|
4623
|
+
const maxTime = Math.max(...times.filter((t) => t !== Infinity));
|
|
4624
|
+
routes.forEach((route, index) => {
|
|
4625
|
+
let score = 100;
|
|
4626
|
+
if (maxCost > minCost) {
|
|
4627
|
+
const costNormalized = 1 - (costs[index] - minCost) / (maxCost - minCost);
|
|
4628
|
+
const costWeight = preferLowFees ? 50 : 30;
|
|
4629
|
+
score += costNormalized * costWeight;
|
|
4630
|
+
}
|
|
4631
|
+
const time = times[index];
|
|
4632
|
+
if (time !== Infinity && maxTime > minTime) {
|
|
4633
|
+
const speedNormalized = 1 - (time - minTime) / (maxTime - minTime);
|
|
4634
|
+
const speedWeight = preferSpeed ? 50 : 30;
|
|
4635
|
+
score += speedNormalized * speedWeight;
|
|
4636
|
+
}
|
|
4637
|
+
const { supportedPrivacyLevels } = route.backendInstance.capabilities;
|
|
4638
|
+
if (supportedPrivacyLevels.includes("shielded")) {
|
|
4639
|
+
score += 20;
|
|
4640
|
+
} else if (supportedPrivacyLevels.includes("compliant")) {
|
|
4641
|
+
score += 10;
|
|
4642
|
+
}
|
|
4643
|
+
route.score = score;
|
|
4644
|
+
});
|
|
4645
|
+
}
|
|
4646
|
+
/**
|
|
4647
|
+
* Calculate total cost from quote
|
|
4648
|
+
*
|
|
4649
|
+
* Returns total fee in USD if available, otherwise estimates from fees
|
|
4650
|
+
*
|
|
4651
|
+
* @private
|
|
4652
|
+
*/
|
|
4653
|
+
calculateTotalCost(quote) {
|
|
4654
|
+
if (quote.fees.totalFeeUSD) {
|
|
4655
|
+
return parseFloat(quote.fees.totalFeeUSD);
|
|
4656
|
+
}
|
|
4657
|
+
const networkFee = parseFloat(quote.fees.networkFee) || 0;
|
|
4658
|
+
const protocolFee = parseFloat(quote.fees.protocolFee) || 0;
|
|
4659
|
+
return networkFee + protocolFee;
|
|
4660
|
+
}
|
|
4661
|
+
};
|
|
4662
|
+
function createSmartRouter(registry) {
|
|
4663
|
+
return new SmartRouter(registry);
|
|
4664
|
+
}
|
|
4665
|
+
|
|
4666
|
+
// src/settlement/backends/near-intents.ts
|
|
4667
|
+
var import_types8 = require("@sip-protocol/types");
|
|
4668
|
+
function mapOneClickStatus(status) {
|
|
4669
|
+
switch (status) {
|
|
4670
|
+
case import_types8.OneClickSwapStatus.PENDING_DEPOSIT:
|
|
4671
|
+
return "pending_deposit" /* PENDING_DEPOSIT */;
|
|
4672
|
+
case import_types8.OneClickSwapStatus.PROCESSING:
|
|
4673
|
+
return "in_progress" /* IN_PROGRESS */;
|
|
4674
|
+
case import_types8.OneClickSwapStatus.SUCCESS:
|
|
4675
|
+
return "success" /* SUCCESS */;
|
|
4676
|
+
case import_types8.OneClickSwapStatus.FAILED:
|
|
4677
|
+
return "failed" /* FAILED */;
|
|
4678
|
+
case import_types8.OneClickSwapStatus.INCOMPLETE_DEPOSIT:
|
|
4679
|
+
return "failed" /* FAILED */;
|
|
4680
|
+
case import_types8.OneClickSwapStatus.REFUNDED:
|
|
4681
|
+
return "refunded" /* REFUNDED */;
|
|
4682
|
+
default:
|
|
4683
|
+
return "pending_deposit" /* PENDING_DEPOSIT */;
|
|
4684
|
+
}
|
|
4685
|
+
}
|
|
4686
|
+
var NEARIntentsBackend = class {
|
|
4687
|
+
name = "near-intents";
|
|
4688
|
+
capabilities;
|
|
4689
|
+
adapter;
|
|
4690
|
+
quoteCache;
|
|
4691
|
+
constructor(config = {}) {
|
|
4692
|
+
this.adapter = new NEARIntentsAdapter(config);
|
|
4693
|
+
this.quoteCache = /* @__PURE__ */ new Map();
|
|
4694
|
+
this.capabilities = {
|
|
4695
|
+
supportedSourceChains: [
|
|
4696
|
+
"near",
|
|
4697
|
+
"ethereum",
|
|
4698
|
+
"solana",
|
|
4699
|
+
"polygon",
|
|
4700
|
+
"arbitrum",
|
|
4701
|
+
"optimism",
|
|
4702
|
+
"base",
|
|
4703
|
+
"bitcoin",
|
|
4704
|
+
"zcash"
|
|
4705
|
+
],
|
|
4706
|
+
supportedDestinationChains: [
|
|
4707
|
+
"near",
|
|
4708
|
+
"ethereum",
|
|
4709
|
+
"solana",
|
|
4710
|
+
"polygon",
|
|
4711
|
+
"arbitrum",
|
|
4712
|
+
"optimism",
|
|
4713
|
+
"base",
|
|
4714
|
+
"bitcoin",
|
|
4715
|
+
"zcash"
|
|
4716
|
+
],
|
|
4717
|
+
supportedPrivacyLevels: [
|
|
4718
|
+
import_types8.PrivacyLevel.TRANSPARENT,
|
|
4719
|
+
import_types8.PrivacyLevel.SHIELDED,
|
|
4720
|
+
import_types8.PrivacyLevel.COMPLIANT
|
|
4721
|
+
],
|
|
4722
|
+
supportsCancellation: false,
|
|
4723
|
+
supportsRefunds: true,
|
|
4724
|
+
averageExecutionTime: 300,
|
|
4725
|
+
// 5 minutes
|
|
4726
|
+
features: ["stealth-addresses", "cross-chain", "near-intents"]
|
|
4727
|
+
};
|
|
4728
|
+
}
|
|
4729
|
+
/**
|
|
4730
|
+
* Get quote for a cross-chain swap
|
|
4731
|
+
*/
|
|
4732
|
+
async getQuote(params) {
|
|
4733
|
+
this.validateQuoteParams(params);
|
|
4734
|
+
const swapRequest = {
|
|
4735
|
+
requestId: this.generateRequestId(),
|
|
4736
|
+
privacyLevel: params.privacyLevel,
|
|
4737
|
+
inputAsset: {
|
|
4738
|
+
chain: params.fromChain,
|
|
4739
|
+
symbol: params.fromToken,
|
|
4740
|
+
decimals: 0
|
|
4741
|
+
// Will be inferred by adapter
|
|
4742
|
+
},
|
|
4743
|
+
outputAsset: {
|
|
4744
|
+
chain: params.toChain,
|
|
4745
|
+
symbol: params.toToken,
|
|
4746
|
+
decimals: 0
|
|
4747
|
+
// Will be inferred by adapter
|
|
4748
|
+
},
|
|
4749
|
+
inputAmount: params.amount,
|
|
4750
|
+
minOutputAmount: params.slippageTolerance ? params.amount - params.amount * BigInt(params.slippageTolerance) / BigInt(1e4) : void 0
|
|
4751
|
+
};
|
|
4752
|
+
const prepared = await this.adapter.prepareSwap(
|
|
4753
|
+
swapRequest,
|
|
4754
|
+
params.recipientMetaAddress,
|
|
4755
|
+
params.senderAddress
|
|
4756
|
+
);
|
|
4757
|
+
const oneClickQuote = await this.adapter.getQuote(prepared);
|
|
4758
|
+
this.quoteCache.set(oneClickQuote.quoteId, params);
|
|
4759
|
+
const quote = {
|
|
4760
|
+
quoteId: oneClickQuote.quoteId,
|
|
4761
|
+
amountIn: oneClickQuote.amountIn,
|
|
4762
|
+
amountOut: oneClickQuote.amountOut,
|
|
4763
|
+
minAmountOut: oneClickQuote.amountOut,
|
|
4764
|
+
// 1Click doesn't provide separate minAmount
|
|
4765
|
+
fees: {
|
|
4766
|
+
networkFee: "0",
|
|
4767
|
+
// 1Click doesn't provide separate fee breakdown
|
|
4768
|
+
protocolFee: "0",
|
|
4769
|
+
totalFeeUSD: oneClickQuote.amountOutUsd
|
|
4770
|
+
},
|
|
4771
|
+
depositAddress: oneClickQuote.depositAddress,
|
|
4772
|
+
recipientAddress: prepared.stealthAddress?.address ?? params.senderAddress ?? "",
|
|
4773
|
+
refundAddress: params.senderAddress,
|
|
4774
|
+
expiresAt: new Date(oneClickQuote.deadline).getTime() / 1e3,
|
|
4775
|
+
estimatedTime: oneClickQuote.timeEstimate,
|
|
4776
|
+
metadata: {
|
|
4777
|
+
prepared,
|
|
4778
|
+
oneClickQuote,
|
|
4779
|
+
stealthAddress: prepared.stealthAddress,
|
|
4780
|
+
ephemeralPublicKey: prepared.stealthAddress?.ephemeralPublicKey,
|
|
4781
|
+
curve: prepared.curve
|
|
4782
|
+
}
|
|
4783
|
+
};
|
|
4784
|
+
return quote;
|
|
4785
|
+
}
|
|
4786
|
+
/**
|
|
4787
|
+
* Execute swap using a quote
|
|
4788
|
+
*/
|
|
4789
|
+
async executeSwap(params) {
|
|
4790
|
+
if (!params.quoteId) {
|
|
4791
|
+
throw new ValidationError("quoteId is required", "quoteId");
|
|
4792
|
+
}
|
|
4793
|
+
const quoteParams = this.quoteCache.get(params.quoteId);
|
|
4794
|
+
if (!quoteParams) {
|
|
4795
|
+
throw new ValidationError(
|
|
4796
|
+
"Quote not found. Please call getQuote() before executeSwap()",
|
|
4797
|
+
"quoteId"
|
|
4798
|
+
);
|
|
4799
|
+
}
|
|
4800
|
+
const swapRequest = {
|
|
4801
|
+
requestId: this.generateRequestId(),
|
|
4802
|
+
privacyLevel: quoteParams.privacyLevel,
|
|
4803
|
+
inputAsset: {
|
|
4804
|
+
chain: quoteParams.fromChain,
|
|
4805
|
+
symbol: quoteParams.fromToken,
|
|
4806
|
+
decimals: 0
|
|
4807
|
+
},
|
|
4808
|
+
outputAsset: {
|
|
4809
|
+
chain: quoteParams.toChain,
|
|
4810
|
+
symbol: quoteParams.toToken,
|
|
4811
|
+
decimals: 0
|
|
4812
|
+
},
|
|
4813
|
+
inputAmount: quoteParams.amount
|
|
4814
|
+
};
|
|
4815
|
+
const adapterResult = await this.adapter.initiateSwap(
|
|
4816
|
+
swapRequest,
|
|
4817
|
+
quoteParams.recipientMetaAddress,
|
|
4818
|
+
quoteParams.senderAddress
|
|
4819
|
+
);
|
|
4820
|
+
if (params.depositTxHash) {
|
|
4821
|
+
await this.adapter.notifyDeposit(
|
|
4822
|
+
adapterResult.depositAddress,
|
|
4823
|
+
params.depositTxHash,
|
|
4824
|
+
params.nearAccount
|
|
4825
|
+
);
|
|
4826
|
+
}
|
|
4827
|
+
const result = {
|
|
4828
|
+
swapId: adapterResult.depositAddress,
|
|
4829
|
+
// Use deposit address as swap ID
|
|
4830
|
+
status: mapOneClickStatus(adapterResult.status),
|
|
4831
|
+
quoteId: params.quoteId,
|
|
4832
|
+
depositAddress: adapterResult.depositAddress,
|
|
4833
|
+
depositTxHash: params.depositTxHash,
|
|
4834
|
+
settlementTxHash: adapterResult.settlementTxHash,
|
|
4835
|
+
actualAmountOut: adapterResult.amountOut,
|
|
4836
|
+
metadata: {
|
|
4837
|
+
adapterResult,
|
|
4838
|
+
stealthRecipient: adapterResult.stealthRecipient,
|
|
4839
|
+
ephemeralPublicKey: adapterResult.ephemeralPublicKey
|
|
4840
|
+
}
|
|
4841
|
+
};
|
|
4842
|
+
return result;
|
|
4843
|
+
}
|
|
4844
|
+
/**
|
|
4845
|
+
* Get current swap status
|
|
4846
|
+
*/
|
|
4847
|
+
async getStatus(swapId) {
|
|
4848
|
+
const oneClickStatus = await this.adapter.getStatus(swapId);
|
|
4849
|
+
const status = {
|
|
4850
|
+
swapId,
|
|
4851
|
+
status: mapOneClickStatus(oneClickStatus.status),
|
|
4852
|
+
quoteId: "",
|
|
4853
|
+
// 1Click status doesn't include quoteId
|
|
4854
|
+
depositAddress: swapId,
|
|
4855
|
+
amountIn: oneClickStatus.amountIn ?? "0",
|
|
4856
|
+
amountOut: oneClickStatus.amountOut ?? "0",
|
|
4857
|
+
depositTxHash: oneClickStatus.depositTxHash,
|
|
4858
|
+
settlementTxHash: oneClickStatus.settlementTxHash,
|
|
4859
|
+
errorMessage: oneClickStatus.error,
|
|
4860
|
+
updatedAt: Date.now() / 1e3,
|
|
4861
|
+
// 1Click doesn't provide updatedAt
|
|
4862
|
+
metadata: {
|
|
4863
|
+
oneClickStatus
|
|
4864
|
+
}
|
|
4865
|
+
};
|
|
4866
|
+
return status;
|
|
4867
|
+
}
|
|
4868
|
+
/**
|
|
4869
|
+
* Wait for swap completion (optional)
|
|
4870
|
+
*/
|
|
4871
|
+
async waitForCompletion(swapId, options) {
|
|
4872
|
+
await this.adapter.waitForCompletion(swapId, {
|
|
4873
|
+
interval: options?.interval,
|
|
4874
|
+
timeout: options?.timeout,
|
|
4875
|
+
onStatus: options?.onStatusChange ? (oneClickStatus) => {
|
|
4876
|
+
const status = {
|
|
4877
|
+
swapId,
|
|
4878
|
+
status: mapOneClickStatus(oneClickStatus.status),
|
|
4879
|
+
quoteId: "",
|
|
4880
|
+
depositAddress: swapId,
|
|
4881
|
+
amountIn: oneClickStatus.amountIn ?? "0",
|
|
4882
|
+
amountOut: oneClickStatus.amountOut ?? "0",
|
|
4883
|
+
depositTxHash: oneClickStatus.depositTxHash,
|
|
4884
|
+
settlementTxHash: oneClickStatus.settlementTxHash,
|
|
4885
|
+
errorMessage: oneClickStatus.error,
|
|
4886
|
+
updatedAt: Date.now() / 1e3,
|
|
4887
|
+
metadata: { oneClickStatus }
|
|
4888
|
+
};
|
|
4889
|
+
options.onStatusChange?.(status);
|
|
4890
|
+
} : void 0
|
|
4891
|
+
});
|
|
4892
|
+
return this.getStatus(swapId);
|
|
4893
|
+
}
|
|
4894
|
+
/**
|
|
4895
|
+
* Get dry quote (preview without creating deposit address)
|
|
4896
|
+
*/
|
|
4897
|
+
async getDryQuote(params) {
|
|
4898
|
+
this.validateQuoteParams(params);
|
|
4899
|
+
const swapRequest = {
|
|
4900
|
+
requestId: this.generateRequestId(),
|
|
4901
|
+
privacyLevel: params.privacyLevel,
|
|
4902
|
+
inputAsset: {
|
|
4903
|
+
chain: params.fromChain,
|
|
4904
|
+
symbol: params.fromToken,
|
|
4905
|
+
decimals: 0
|
|
4906
|
+
},
|
|
4907
|
+
outputAsset: {
|
|
4908
|
+
chain: params.toChain,
|
|
4909
|
+
symbol: params.toToken,
|
|
4910
|
+
decimals: 0
|
|
4911
|
+
},
|
|
4912
|
+
inputAmount: params.amount
|
|
4913
|
+
};
|
|
4914
|
+
const prepared = await this.adapter.prepareSwap(
|
|
4915
|
+
swapRequest,
|
|
4916
|
+
params.recipientMetaAddress,
|
|
4917
|
+
params.senderAddress
|
|
4918
|
+
);
|
|
4919
|
+
const oneClickQuote = await this.adapter.getDryQuote(prepared);
|
|
4920
|
+
const quote = {
|
|
4921
|
+
quoteId: oneClickQuote.quoteId,
|
|
4922
|
+
amountIn: oneClickQuote.amountIn,
|
|
4923
|
+
amountOut: oneClickQuote.amountOut,
|
|
4924
|
+
minAmountOut: oneClickQuote.amountOut,
|
|
4925
|
+
fees: {
|
|
4926
|
+
networkFee: "0",
|
|
4927
|
+
protocolFee: "0",
|
|
4928
|
+
totalFeeUSD: oneClickQuote.amountOutUsd
|
|
4929
|
+
},
|
|
4930
|
+
depositAddress: oneClickQuote.depositAddress,
|
|
4931
|
+
recipientAddress: prepared.stealthAddress?.address ?? params.senderAddress ?? "",
|
|
4932
|
+
refundAddress: params.senderAddress,
|
|
4933
|
+
expiresAt: new Date(oneClickQuote.deadline).getTime() / 1e3,
|
|
4934
|
+
estimatedTime: oneClickQuote.timeEstimate,
|
|
4935
|
+
metadata: {
|
|
4936
|
+
prepared,
|
|
4937
|
+
oneClickQuote,
|
|
4938
|
+
stealthAddress: prepared.stealthAddress,
|
|
4939
|
+
ephemeralPublicKey: prepared.stealthAddress?.ephemeralPublicKey,
|
|
4940
|
+
curve: prepared.curve,
|
|
4941
|
+
isDryQuote: true
|
|
4942
|
+
}
|
|
4943
|
+
};
|
|
4944
|
+
return quote;
|
|
4945
|
+
}
|
|
4946
|
+
/**
|
|
4947
|
+
* Notify backend of deposit transaction
|
|
4948
|
+
*/
|
|
4949
|
+
async notifyDeposit(swapId, txHash, metadata) {
|
|
4950
|
+
await this.adapter.notifyDeposit(
|
|
4951
|
+
swapId,
|
|
4952
|
+
// swapId is deposit address
|
|
4953
|
+
txHash,
|
|
4954
|
+
metadata?.nearAccount
|
|
4955
|
+
);
|
|
4956
|
+
}
|
|
4957
|
+
// ─── Private Methods ──────────────────────────────────────────────────────────
|
|
4958
|
+
validateQuoteParams(params) {
|
|
4959
|
+
if (!params.fromChain) {
|
|
4960
|
+
throw new ValidationError("fromChain is required", "fromChain");
|
|
4961
|
+
}
|
|
4962
|
+
if (!params.toChain) {
|
|
4963
|
+
throw new ValidationError("toChain is required", "toChain");
|
|
4964
|
+
}
|
|
4965
|
+
if (!params.fromToken) {
|
|
4966
|
+
throw new ValidationError("fromToken is required", "fromToken");
|
|
4967
|
+
}
|
|
4968
|
+
if (!params.toToken) {
|
|
4969
|
+
throw new ValidationError("toToken is required", "toToken");
|
|
4970
|
+
}
|
|
4971
|
+
if (!params.amount || params.amount <= BigInt(0)) {
|
|
4972
|
+
throw new ValidationError("amount must be greater than 0", "amount");
|
|
4973
|
+
}
|
|
4974
|
+
if (!params.privacyLevel) {
|
|
4975
|
+
throw new ValidationError("privacyLevel is required", "privacyLevel");
|
|
4976
|
+
}
|
|
4977
|
+
if (params.privacyLevel !== import_types8.PrivacyLevel.TRANSPARENT && !params.recipientMetaAddress) {
|
|
4978
|
+
throw new ValidationError(
|
|
4979
|
+
"recipientMetaAddress is required for shielded/compliant privacy modes",
|
|
4980
|
+
"recipientMetaAddress"
|
|
4981
|
+
);
|
|
4982
|
+
}
|
|
4983
|
+
if (params.privacyLevel === import_types8.PrivacyLevel.TRANSPARENT && !params.senderAddress) {
|
|
4984
|
+
throw new ValidationError(
|
|
4985
|
+
"senderAddress is required for transparent mode",
|
|
4986
|
+
"senderAddress"
|
|
4987
|
+
);
|
|
4988
|
+
}
|
|
4989
|
+
if (!this.capabilities.supportedSourceChains.includes(params.fromChain)) {
|
|
4990
|
+
throw new ValidationError(
|
|
4991
|
+
`Source chain ${params.fromChain} is not supported`,
|
|
4992
|
+
"fromChain",
|
|
4993
|
+
{ supportedChains: this.capabilities.supportedSourceChains }
|
|
4994
|
+
);
|
|
4995
|
+
}
|
|
4996
|
+
if (!this.capabilities.supportedDestinationChains.includes(params.toChain)) {
|
|
4997
|
+
throw new ValidationError(
|
|
4998
|
+
`Destination chain ${params.toChain} is not supported`,
|
|
4999
|
+
"toChain",
|
|
5000
|
+
{ supportedChains: this.capabilities.supportedDestinationChains }
|
|
5001
|
+
);
|
|
5002
|
+
}
|
|
5003
|
+
}
|
|
5004
|
+
generateRequestId() {
|
|
5005
|
+
return `req_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
|
|
5006
|
+
}
|
|
5007
|
+
};
|
|
5008
|
+
function createNEARIntentsBackend(config) {
|
|
5009
|
+
return new NEARIntentsBackend(config);
|
|
5010
|
+
}
|
|
5011
|
+
|
|
5012
|
+
// src/settlement/backends/zcash-native.ts
|
|
5013
|
+
var import_types9 = require("@sip-protocol/types");
|
|
5014
|
+
var ZcashNativeBackend = class {
|
|
5015
|
+
name = "zcash-native";
|
|
5016
|
+
capabilities;
|
|
5017
|
+
swapService;
|
|
5018
|
+
config;
|
|
5019
|
+
quotes = /* @__PURE__ */ new Map();
|
|
5020
|
+
swaps = /* @__PURE__ */ new Map();
|
|
5021
|
+
constructor(config) {
|
|
5022
|
+
this.swapService = config.swapService;
|
|
5023
|
+
this.config = {
|
|
5024
|
+
quoteValiditySeconds: config.quoteValiditySeconds ?? 300,
|
|
5025
|
+
networkFeeZatoshis: config.networkFeeZatoshis ?? 1e4
|
|
5026
|
+
};
|
|
5027
|
+
this.capabilities = {
|
|
5028
|
+
supportedSourceChains: ["zcash"],
|
|
5029
|
+
supportedDestinationChains: ["zcash"],
|
|
5030
|
+
supportedPrivacyLevels: [
|
|
5031
|
+
import_types9.PrivacyLevel.TRANSPARENT,
|
|
5032
|
+
import_types9.PrivacyLevel.SHIELDED,
|
|
5033
|
+
import_types9.PrivacyLevel.COMPLIANT
|
|
5034
|
+
],
|
|
5035
|
+
supportsCancellation: false,
|
|
5036
|
+
supportsRefunds: false,
|
|
5037
|
+
averageExecutionTime: 75,
|
|
5038
|
+
// ~75 seconds for Zcash block confirmation
|
|
5039
|
+
features: [
|
|
5040
|
+
"native-zcash",
|
|
5041
|
+
"shielded-addresses",
|
|
5042
|
+
"transparent-addresses",
|
|
5043
|
+
"instant-quotes"
|
|
5044
|
+
]
|
|
5045
|
+
};
|
|
5046
|
+
}
|
|
5047
|
+
// ─── Quote Methods ─────────────────────────────────────────────────────────
|
|
5048
|
+
/**
|
|
5049
|
+
* Get a quote for ZEC → ZEC transfer
|
|
5050
|
+
*/
|
|
5051
|
+
async getQuote(params) {
|
|
5052
|
+
this.validateQuoteParams(params);
|
|
5053
|
+
const { amount, recipientMetaAddress, senderAddress, privacyLevel } = params;
|
|
5054
|
+
const quoteId = this.generateQuoteId();
|
|
5055
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
5056
|
+
const expiresAt = now + this.config.quoteValiditySeconds;
|
|
5057
|
+
const networkFee = BigInt(this.config.networkFeeZatoshis);
|
|
5058
|
+
const protocolFee = BigInt(0);
|
|
5059
|
+
const totalFee = networkFee;
|
|
5060
|
+
const amountOut = amount - totalFee;
|
|
5061
|
+
if (amountOut <= BigInt(0)) {
|
|
5062
|
+
throw new ValidationError(
|
|
5063
|
+
"Amount too small to cover network fees",
|
|
5064
|
+
"amount",
|
|
5065
|
+
{ amount: amount.toString(), networkFee: networkFee.toString() },
|
|
5066
|
+
"SIP_2004" /* INVALID_AMOUNT */
|
|
5067
|
+
);
|
|
5068
|
+
}
|
|
5069
|
+
const minAmountOut = amountOut * BigInt(99) / BigInt(100);
|
|
5070
|
+
let depositAddress;
|
|
5071
|
+
let recipientAddress;
|
|
5072
|
+
if (privacyLevel === import_types9.PrivacyLevel.SHIELDED || privacyLevel === import_types9.PrivacyLevel.COMPLIANT) {
|
|
5073
|
+
if (typeof recipientMetaAddress === "string") {
|
|
5074
|
+
recipientAddress = recipientMetaAddress;
|
|
5075
|
+
} else if (recipientMetaAddress) {
|
|
5076
|
+
recipientAddress = `zs1${this.randomHex(72)}`;
|
|
5077
|
+
} else {
|
|
5078
|
+
throw new ValidationError(
|
|
5079
|
+
"Recipient address required for shielded transfers",
|
|
5080
|
+
"recipientMetaAddress",
|
|
5081
|
+
void 0,
|
|
5082
|
+
"SIP_2000" /* VALIDATION_FAILED */
|
|
5083
|
+
);
|
|
5084
|
+
}
|
|
5085
|
+
depositAddress = `zs1${this.randomHex(72)}`;
|
|
5086
|
+
} else {
|
|
5087
|
+
if (senderAddress) {
|
|
5088
|
+
depositAddress = senderAddress;
|
|
5089
|
+
} else {
|
|
5090
|
+
depositAddress = `t1${this.randomBase58(33)}`;
|
|
5091
|
+
}
|
|
5092
|
+
if (typeof recipientMetaAddress === "string") {
|
|
5093
|
+
recipientAddress = recipientMetaAddress;
|
|
5094
|
+
} else {
|
|
5095
|
+
throw new ValidationError(
|
|
5096
|
+
"Recipient address required",
|
|
5097
|
+
"recipientMetaAddress",
|
|
5098
|
+
void 0,
|
|
5099
|
+
"SIP_2000" /* VALIDATION_FAILED */
|
|
5100
|
+
);
|
|
5101
|
+
}
|
|
5102
|
+
}
|
|
5103
|
+
const quote = {
|
|
5104
|
+
quoteId,
|
|
5105
|
+
amountIn: amount.toString(),
|
|
5106
|
+
amountOut: amountOut.toString(),
|
|
5107
|
+
minAmountOut: minAmountOut.toString(),
|
|
5108
|
+
fees: {
|
|
5109
|
+
networkFee: networkFee.toString(),
|
|
5110
|
+
protocolFee: protocolFee.toString()
|
|
5111
|
+
},
|
|
5112
|
+
depositAddress,
|
|
5113
|
+
recipientAddress,
|
|
5114
|
+
expiresAt,
|
|
5115
|
+
estimatedTime: this.capabilities.averageExecutionTime,
|
|
5116
|
+
metadata: {
|
|
5117
|
+
backend: this.name,
|
|
5118
|
+
privacyLevel,
|
|
5119
|
+
zcashNetwork: "mainnet"
|
|
5120
|
+
}
|
|
5121
|
+
};
|
|
5122
|
+
this.quotes.set(quoteId, quote);
|
|
5123
|
+
return quote;
|
|
5124
|
+
}
|
|
5125
|
+
/**
|
|
5126
|
+
* Get a dry quote (preview without creating deposit address)
|
|
5127
|
+
*/
|
|
5128
|
+
async getDryQuote(params) {
|
|
5129
|
+
return this.getQuote(params);
|
|
5130
|
+
}
|
|
5131
|
+
// ─── Swap Execution ────────────────────────────────────────────────────────
|
|
5132
|
+
/**
|
|
5133
|
+
* Execute a ZEC → ZEC swap/transfer
|
|
5134
|
+
*/
|
|
5135
|
+
async executeSwap(params) {
|
|
5136
|
+
const { quoteId, depositTxHash } = params;
|
|
5137
|
+
const quote = this.quotes.get(quoteId);
|
|
5138
|
+
if (!quote) {
|
|
5139
|
+
throw new ValidationError(
|
|
5140
|
+
"Quote not found or expired",
|
|
5141
|
+
"quoteId",
|
|
5142
|
+
{ quoteId },
|
|
5143
|
+
"SIP_2000" /* VALIDATION_FAILED */
|
|
5144
|
+
);
|
|
5145
|
+
}
|
|
5146
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
5147
|
+
if (now > quote.expiresAt) {
|
|
5148
|
+
throw new ValidationError(
|
|
5149
|
+
"Quote has expired",
|
|
5150
|
+
"quoteId",
|
|
5151
|
+
{ quoteId, expiresAt: quote.expiresAt, now },
|
|
5152
|
+
"SIP_2000" /* VALIDATION_FAILED */
|
|
5153
|
+
);
|
|
5154
|
+
}
|
|
5155
|
+
const swapId = this.generateSwapId();
|
|
5156
|
+
const result = {
|
|
5157
|
+
swapId,
|
|
5158
|
+
status: depositTxHash ? "deposit_confirmed" /* DEPOSIT_CONFIRMED */ : "pending_deposit" /* PENDING_DEPOSIT */,
|
|
5159
|
+
quoteId,
|
|
5160
|
+
depositAddress: quote.depositAddress,
|
|
5161
|
+
depositTxHash,
|
|
5162
|
+
metadata: {
|
|
5163
|
+
backend: this.name,
|
|
5164
|
+
recipientAddress: quote.recipientAddress
|
|
5165
|
+
}
|
|
5166
|
+
};
|
|
5167
|
+
this.swaps.set(swapId, result);
|
|
5168
|
+
if (depositTxHash) {
|
|
5169
|
+
this.simulateSwapExecution(swapId, quote);
|
|
5170
|
+
}
|
|
5171
|
+
return result;
|
|
5172
|
+
}
|
|
5173
|
+
// ─── Status Methods ────────────────────────────────────────────────────────
|
|
5174
|
+
/**
|
|
5175
|
+
* Get swap status
|
|
5176
|
+
*/
|
|
5177
|
+
async getStatus(swapId) {
|
|
5178
|
+
const swap = this.swaps.get(swapId);
|
|
5179
|
+
if (!swap) {
|
|
5180
|
+
throw new ValidationError(
|
|
5181
|
+
"Swap not found",
|
|
5182
|
+
"swapId",
|
|
5183
|
+
{ swapId },
|
|
5184
|
+
"SIP_2000" /* VALIDATION_FAILED */
|
|
5185
|
+
);
|
|
5186
|
+
}
|
|
5187
|
+
const quote = this.quotes.get(swap.quoteId);
|
|
5188
|
+
if (!quote) {
|
|
5189
|
+
throw new ValidationError(
|
|
5190
|
+
"Quote not found for swap",
|
|
5191
|
+
"quoteId",
|
|
5192
|
+
{ quoteId: swap.quoteId },
|
|
5193
|
+
"SIP_2000" /* VALIDATION_FAILED */
|
|
5194
|
+
);
|
|
5195
|
+
}
|
|
5196
|
+
const status = {
|
|
5197
|
+
swapId: swap.swapId,
|
|
5198
|
+
status: swap.status,
|
|
5199
|
+
quoteId: swap.quoteId,
|
|
5200
|
+
depositAddress: swap.depositAddress,
|
|
5201
|
+
amountIn: quote.amountIn,
|
|
5202
|
+
amountOut: quote.amountOut,
|
|
5203
|
+
depositTxHash: swap.depositTxHash,
|
|
5204
|
+
settlementTxHash: swap.settlementTxHash,
|
|
5205
|
+
actualAmountOut: swap.actualAmountOut,
|
|
5206
|
+
errorMessage: swap.errorMessage,
|
|
5207
|
+
updatedAt: Math.floor(Date.now() / 1e3),
|
|
5208
|
+
metadata: swap.metadata
|
|
5209
|
+
};
|
|
5210
|
+
return status;
|
|
5211
|
+
}
|
|
5212
|
+
/**
|
|
5213
|
+
* Wait for swap completion
|
|
5214
|
+
*/
|
|
5215
|
+
async waitForCompletion(swapId, options) {
|
|
5216
|
+
const interval = options?.interval ?? 5e3;
|
|
5217
|
+
const timeout = options?.timeout ?? 6e5;
|
|
5218
|
+
const startTime = Date.now();
|
|
5219
|
+
while (Date.now() - startTime < timeout) {
|
|
5220
|
+
const status2 = await this.getStatus(swapId);
|
|
5221
|
+
if (options?.onStatusChange) {
|
|
5222
|
+
options.onStatusChange(status2);
|
|
5223
|
+
}
|
|
5224
|
+
if (status2.status === "success" /* SUCCESS */) {
|
|
5225
|
+
return status2;
|
|
5226
|
+
}
|
|
5227
|
+
if (status2.status === "failed" /* FAILED */ || status2.status === "cancelled" /* CANCELLED */ || status2.status === "refunded" /* REFUNDED */) {
|
|
5228
|
+
return status2;
|
|
5229
|
+
}
|
|
5230
|
+
await this.delay(interval);
|
|
5231
|
+
}
|
|
5232
|
+
const status = await this.getStatus(swapId);
|
|
5233
|
+
return status;
|
|
5234
|
+
}
|
|
5235
|
+
/**
|
|
5236
|
+
* Notify backend of deposit
|
|
5237
|
+
*/
|
|
5238
|
+
async notifyDeposit(swapId, txHash, metadata) {
|
|
5239
|
+
const swap = this.swaps.get(swapId);
|
|
5240
|
+
if (!swap) {
|
|
5241
|
+
throw new ValidationError(
|
|
5242
|
+
"Swap not found",
|
|
5243
|
+
"swapId",
|
|
5244
|
+
{ swapId },
|
|
5245
|
+
"SIP_2000" /* VALIDATION_FAILED */
|
|
5246
|
+
);
|
|
5247
|
+
}
|
|
5248
|
+
swap.depositTxHash = txHash;
|
|
5249
|
+
swap.status = "deposit_confirmed" /* DEPOSIT_CONFIRMED */;
|
|
5250
|
+
if (metadata) {
|
|
5251
|
+
swap.metadata = { ...swap.metadata, ...metadata };
|
|
5252
|
+
}
|
|
5253
|
+
this.swaps.set(swapId, swap);
|
|
5254
|
+
const quote = this.quotes.get(swap.quoteId);
|
|
5255
|
+
if (quote) {
|
|
5256
|
+
this.simulateSwapExecution(swapId, quote);
|
|
5257
|
+
}
|
|
5258
|
+
}
|
|
5259
|
+
// ─── Private Helpers ───────────────────────────────────────────────────────
|
|
5260
|
+
validateQuoteParams(params) {
|
|
5261
|
+
if (params.fromChain !== "zcash") {
|
|
5262
|
+
throw new ValidationError(
|
|
5263
|
+
"Source chain must be zcash",
|
|
5264
|
+
"fromChain",
|
|
5265
|
+
{ received: params.fromChain, expected: "zcash" },
|
|
5266
|
+
"SIP_2000" /* VALIDATION_FAILED */
|
|
5267
|
+
);
|
|
5268
|
+
}
|
|
5269
|
+
if (params.toChain !== "zcash") {
|
|
5270
|
+
throw new ValidationError(
|
|
5271
|
+
"Destination chain must be zcash",
|
|
5272
|
+
"toChain",
|
|
5273
|
+
{ received: params.toChain, expected: "zcash" },
|
|
5274
|
+
"SIP_2000" /* VALIDATION_FAILED */
|
|
5275
|
+
);
|
|
5276
|
+
}
|
|
5277
|
+
if (params.fromToken !== "ZEC") {
|
|
5278
|
+
throw new ValidationError(
|
|
5279
|
+
"Source token must be ZEC",
|
|
5280
|
+
"fromToken",
|
|
5281
|
+
{ received: params.fromToken, expected: "ZEC" },
|
|
5282
|
+
"SIP_2000" /* VALIDATION_FAILED */
|
|
5283
|
+
);
|
|
5284
|
+
}
|
|
5285
|
+
if (params.toToken !== "ZEC") {
|
|
5286
|
+
throw new ValidationError(
|
|
5287
|
+
"Destination token must be ZEC",
|
|
5288
|
+
"toToken",
|
|
5289
|
+
{ received: params.toToken, expected: "ZEC" },
|
|
5290
|
+
"SIP_2000" /* VALIDATION_FAILED */
|
|
5291
|
+
);
|
|
5292
|
+
}
|
|
5293
|
+
if (!params.amount || params.amount <= BigInt(0)) {
|
|
5294
|
+
throw new ValidationError(
|
|
5295
|
+
"Amount must be positive",
|
|
5296
|
+
"amount",
|
|
5297
|
+
{ received: params.amount },
|
|
5298
|
+
"SIP_2004" /* INVALID_AMOUNT */
|
|
5299
|
+
);
|
|
5300
|
+
}
|
|
5301
|
+
if (!this.capabilities.supportedPrivacyLevels.includes(params.privacyLevel)) {
|
|
5302
|
+
throw new ValidationError(
|
|
5303
|
+
"Unsupported privacy level",
|
|
5304
|
+
"privacyLevel",
|
|
5305
|
+
{ received: params.privacyLevel, supported: this.capabilities.supportedPrivacyLevels },
|
|
5306
|
+
"SIP_2000" /* VALIDATION_FAILED */
|
|
5307
|
+
);
|
|
5308
|
+
}
|
|
5309
|
+
}
|
|
5310
|
+
simulateSwapExecution(swapId, quote) {
|
|
5311
|
+
setTimeout(() => {
|
|
5312
|
+
const swap = this.swaps.get(swapId);
|
|
5313
|
+
if (!swap) return;
|
|
5314
|
+
swap.status = "in_progress" /* IN_PROGRESS */;
|
|
5315
|
+
this.swaps.set(swapId, swap);
|
|
5316
|
+
setTimeout(() => {
|
|
5317
|
+
const finalSwap = this.swaps.get(swapId);
|
|
5318
|
+
if (!finalSwap) return;
|
|
5319
|
+
finalSwap.status = "success" /* SUCCESS */;
|
|
5320
|
+
finalSwap.settlementTxHash = this.randomHex(64);
|
|
5321
|
+
finalSwap.actualAmountOut = quote.amountOut;
|
|
5322
|
+
this.swaps.set(swapId, finalSwap);
|
|
5323
|
+
}, 2e3);
|
|
5324
|
+
}, 1e3);
|
|
5325
|
+
}
|
|
5326
|
+
generateQuoteId() {
|
|
5327
|
+
return `zec_native_quote_${Date.now()}_${this.randomHex(8)}`;
|
|
5328
|
+
}
|
|
5329
|
+
generateSwapId() {
|
|
5330
|
+
return `zec_native_swap_${Date.now()}_${this.randomHex(8)}`;
|
|
5331
|
+
}
|
|
5332
|
+
randomHex(length) {
|
|
5333
|
+
const chars = "0123456789abcdef";
|
|
5334
|
+
let result = "";
|
|
5335
|
+
for (let i = 0; i < length; i++) {
|
|
5336
|
+
result += chars[Math.floor(Math.random() * chars.length)];
|
|
5337
|
+
}
|
|
5338
|
+
return result;
|
|
5339
|
+
}
|
|
5340
|
+
randomBase58(length) {
|
|
5341
|
+
const chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
5342
|
+
let result = "";
|
|
5343
|
+
for (let i = 0; i < length; i++) {
|
|
5344
|
+
result += chars[Math.floor(Math.random() * chars.length)];
|
|
5345
|
+
}
|
|
5346
|
+
return result;
|
|
3956
5347
|
}
|
|
3957
5348
|
delay(ms) {
|
|
3958
5349
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
3959
5350
|
}
|
|
3960
5351
|
};
|
|
3961
|
-
function
|
|
3962
|
-
return new
|
|
5352
|
+
function createZcashNativeBackend(config) {
|
|
5353
|
+
return new ZcashNativeBackend(config);
|
|
3963
5354
|
}
|
|
3964
5355
|
|
|
3965
|
-
// src/
|
|
3966
|
-
var
|
|
5356
|
+
// src/settlement/backends/direct-chain.ts
|
|
5357
|
+
var import_types10 = require("@sip-protocol/types");
|
|
5358
|
+
var import_utils11 = require("@noble/hashes/utils");
|
|
5359
|
+
var DEFAULT_GAS_FEES = {
|
|
5360
|
+
ethereum: 21000n * 50n * 1000000000n,
|
|
5361
|
+
// 21k gas * 50 gwei = 0.00105 ETH
|
|
5362
|
+
solana: 5000n,
|
|
5363
|
+
// 5000 lamports = 0.000005 SOL
|
|
5364
|
+
near: 300000000000000000000n,
|
|
5365
|
+
// 0.3 NEAR in yoctoNEAR
|
|
5366
|
+
zcash: 10000n,
|
|
5367
|
+
// 0.0001 ZEC in zatoshi
|
|
5368
|
+
polygon: 21000n * 30n * 1000000000n,
|
|
5369
|
+
// 21k gas * 30 gwei POL
|
|
5370
|
+
arbitrum: 2100000000n,
|
|
5371
|
+
// 21k gas * 0.1 gwei ETH = 2100 gwei = 2.1e9 wei
|
|
5372
|
+
optimism: 21000000n,
|
|
5373
|
+
// 21k gas * 0.001 gwei ETH = 21 gwei = 21e6 wei
|
|
5374
|
+
base: 2100000000n,
|
|
5375
|
+
// 21k gas * 0.1 gwei ETH = 2100 gwei = 2.1e9 wei
|
|
5376
|
+
bitcoin: 10000n
|
|
5377
|
+
// 10000 sats = 0.0001 BTC (estimate for 1 input, 2 outputs)
|
|
5378
|
+
};
|
|
3967
5379
|
|
|
3968
5380
|
// src/zcash/rpc-client.ts
|
|
3969
|
-
var
|
|
5381
|
+
var import_types11 = require("@sip-protocol/types");
|
|
3970
5382
|
var DEFAULT_CONFIG = {
|
|
3971
5383
|
host: "127.0.0.1",
|
|
3972
5384
|
port: 8232,
|
|
@@ -3986,19 +5398,19 @@ var ZcashRPCError = class extends Error {
|
|
|
3986
5398
|
* Check if error is due to insufficient funds
|
|
3987
5399
|
*/
|
|
3988
5400
|
isInsufficientFunds() {
|
|
3989
|
-
return this.code ===
|
|
5401
|
+
return this.code === import_types11.ZcashErrorCode.WALLET_INSUFFICIENT_FUNDS;
|
|
3990
5402
|
}
|
|
3991
5403
|
/**
|
|
3992
5404
|
* Check if error is due to invalid address
|
|
3993
5405
|
*/
|
|
3994
5406
|
isInvalidAddress() {
|
|
3995
|
-
return this.code ===
|
|
5407
|
+
return this.code === import_types11.ZcashErrorCode.INVALID_ADDRESS_OR_KEY;
|
|
3996
5408
|
}
|
|
3997
5409
|
/**
|
|
3998
5410
|
* Check if error is due to wallet being locked
|
|
3999
5411
|
*/
|
|
4000
5412
|
isWalletLocked() {
|
|
4001
|
-
return this.code ===
|
|
5413
|
+
return this.code === import_types11.ZcashErrorCode.WALLET_UNLOCK_NEEDED;
|
|
4002
5414
|
}
|
|
4003
5415
|
};
|
|
4004
5416
|
var ZcashRPCClient = class {
|
|
@@ -4385,7 +5797,7 @@ function createZcashClient(config) {
|
|
|
4385
5797
|
}
|
|
4386
5798
|
|
|
4387
5799
|
// src/zcash/shielded-service.ts
|
|
4388
|
-
var
|
|
5800
|
+
var import_types12 = require("@sip-protocol/types");
|
|
4389
5801
|
var ZcashShieldedService = class _ZcashShieldedService {
|
|
4390
5802
|
client;
|
|
4391
5803
|
config;
|
|
@@ -4571,7 +5983,7 @@ var ZcashShieldedService = class _ZcashShieldedService {
|
|
|
4571
5983
|
* Higher-level method that handles privacy level mapping.
|
|
4572
5984
|
*/
|
|
4573
5985
|
async sendWithPrivacy(to, amount, privacyLevel, memo) {
|
|
4574
|
-
if (privacyLevel ===
|
|
5986
|
+
if (privacyLevel === import_types12.PrivacyLevel.TRANSPARENT) {
|
|
4575
5987
|
throw new ValidationError(
|
|
4576
5988
|
"Transparent mode not supported for Zcash shielded service. Use standard RPC client.",
|
|
4577
5989
|
"privacyLevel",
|
|
@@ -4665,7 +6077,7 @@ var ZcashShieldedService = class _ZcashShieldedService {
|
|
|
4665
6077
|
const viewingKey = await this.exportViewingKey();
|
|
4666
6078
|
return {
|
|
4667
6079
|
viewingKey,
|
|
4668
|
-
privacyLevel:
|
|
6080
|
+
privacyLevel: import_types12.PrivacyLevel.COMPLIANT,
|
|
4669
6081
|
disclaimer: "This viewing key provides read-only access to transaction history. It cannot be used to spend funds. Share only with authorized auditors."
|
|
4670
6082
|
};
|
|
4671
6083
|
}
|
|
@@ -4751,11 +6163,11 @@ var ZcashShieldedService = class _ZcashShieldedService {
|
|
|
4751
6163
|
*/
|
|
4752
6164
|
mapPrivacyLevelToPolicy(level) {
|
|
4753
6165
|
switch (level) {
|
|
4754
|
-
case
|
|
6166
|
+
case import_types12.PrivacyLevel.TRANSPARENT:
|
|
4755
6167
|
return "NoPrivacy";
|
|
4756
|
-
case
|
|
6168
|
+
case import_types12.PrivacyLevel.SHIELDED:
|
|
4757
6169
|
return "FullPrivacy";
|
|
4758
|
-
case
|
|
6170
|
+
case import_types12.PrivacyLevel.COMPLIANT:
|
|
4759
6171
|
return "FullPrivacy";
|
|
4760
6172
|
default:
|
|
4761
6173
|
return "FullPrivacy";
|
|
@@ -4808,7 +6220,7 @@ function createZcashShieldedService(config) {
|
|
|
4808
6220
|
}
|
|
4809
6221
|
|
|
4810
6222
|
// src/zcash/swap-service.ts
|
|
4811
|
-
var
|
|
6223
|
+
var import_types13 = require("@sip-protocol/types");
|
|
4812
6224
|
var MOCK_PRICES = {
|
|
4813
6225
|
ETH: 2500,
|
|
4814
6226
|
SOL: 120,
|
|
@@ -4915,7 +6327,7 @@ var ZcashSwapService = class {
|
|
|
4915
6327
|
validUntil,
|
|
4916
6328
|
depositAddress: this.generateMockDepositAddress(sourceChain),
|
|
4917
6329
|
estimatedTime: this.getEstimatedTime(sourceChain),
|
|
4918
|
-
privacyLevel:
|
|
6330
|
+
privacyLevel: import_types13.PrivacyLevel.SHIELDED
|
|
4919
6331
|
};
|
|
4920
6332
|
this.quotes.set(quoteId, quote);
|
|
4921
6333
|
return quote;
|
|
@@ -4958,7 +6370,7 @@ var ZcashSwapService = class {
|
|
|
4958
6370
|
depositAddress: "",
|
|
4959
6371
|
// Will be set by bridge
|
|
4960
6372
|
estimatedTime: this.getEstimatedTime(params.sourceChain),
|
|
4961
|
-
privacyLevel:
|
|
6373
|
+
privacyLevel: import_types13.PrivacyLevel.SHIELDED
|
|
4962
6374
|
};
|
|
4963
6375
|
this.quotes.set(quote.quoteId, quote);
|
|
4964
6376
|
return quote;
|
|
@@ -5238,15 +6650,15 @@ function createZcashSwapService(config) {
|
|
|
5238
6650
|
}
|
|
5239
6651
|
|
|
5240
6652
|
// src/zcash/index.ts
|
|
5241
|
-
var
|
|
6653
|
+
var import_types14 = require("@sip-protocol/types");
|
|
5242
6654
|
|
|
5243
6655
|
// src/index.ts
|
|
5244
|
-
var
|
|
6656
|
+
var import_types42 = require("@sip-protocol/types");
|
|
5245
6657
|
|
|
5246
6658
|
// src/payment/payment.ts
|
|
5247
|
-
var
|
|
6659
|
+
var import_types15 = require("@sip-protocol/types");
|
|
5248
6660
|
var import_sha2569 = require("@noble/hashes/sha256");
|
|
5249
|
-
var
|
|
6661
|
+
var import_utils12 = require("@noble/hashes/utils");
|
|
5250
6662
|
var import_chacha2 = require("@noble/ciphers/chacha.js");
|
|
5251
6663
|
var import_hkdf2 = require("@noble/hashes/hkdf");
|
|
5252
6664
|
|
|
@@ -5431,7 +6843,7 @@ var PaymentBuilder = class {
|
|
|
5431
6843
|
_amount;
|
|
5432
6844
|
_recipientMetaAddress;
|
|
5433
6845
|
_recipientAddress;
|
|
5434
|
-
_privacy =
|
|
6846
|
+
_privacy = import_types15.PrivacyLevel.SHIELDED;
|
|
5435
6847
|
_viewingKey;
|
|
5436
6848
|
_sourceChain;
|
|
5437
6849
|
_destinationChain;
|
|
@@ -5714,7 +7126,7 @@ async function createShieldedPayment(params, options) {
|
|
|
5714
7126
|
} else {
|
|
5715
7127
|
resolvedToken = token;
|
|
5716
7128
|
}
|
|
5717
|
-
if (privacy !==
|
|
7129
|
+
if (privacy !== import_types15.PrivacyLevel.TRANSPARENT && !recipientMetaAddress) {
|
|
5718
7130
|
throw new ValidationError(
|
|
5719
7131
|
"recipientMetaAddress is required for shielded/compliant privacy modes",
|
|
5720
7132
|
"recipientMetaAddress",
|
|
@@ -5722,7 +7134,7 @@ async function createShieldedPayment(params, options) {
|
|
|
5722
7134
|
"SIP_2008" /* MISSING_REQUIRED */
|
|
5723
7135
|
);
|
|
5724
7136
|
}
|
|
5725
|
-
if (privacy ===
|
|
7137
|
+
if (privacy === import_types15.PrivacyLevel.TRANSPARENT && !recipientAddress) {
|
|
5726
7138
|
throw new ValidationError(
|
|
5727
7139
|
"recipientAddress is required for transparent mode",
|
|
5728
7140
|
"recipientAddress",
|
|
@@ -5730,7 +7142,7 @@ async function createShieldedPayment(params, options) {
|
|
|
5730
7142
|
"SIP_2008" /* MISSING_REQUIRED */
|
|
5731
7143
|
);
|
|
5732
7144
|
}
|
|
5733
|
-
if (privacy ===
|
|
7145
|
+
if (privacy === import_types15.PrivacyLevel.COMPLIANT && !viewingKey) {
|
|
5734
7146
|
throw new ValidationError(
|
|
5735
7147
|
"viewingKey is required for compliant mode",
|
|
5736
7148
|
"viewingKey",
|
|
@@ -5742,8 +7154,8 @@ async function createShieldedPayment(params, options) {
|
|
|
5742
7154
|
let viewingKeyHash;
|
|
5743
7155
|
if (viewingKey) {
|
|
5744
7156
|
const keyHex = viewingKey.startsWith("0x") ? viewingKey.slice(2) : viewingKey;
|
|
5745
|
-
const keyBytes = (0,
|
|
5746
|
-
viewingKeyHash = `0x${(0,
|
|
7157
|
+
const keyBytes = (0, import_utils12.hexToBytes)(keyHex);
|
|
7158
|
+
viewingKeyHash = `0x${(0, import_utils12.bytesToHex)((0, import_sha2569.sha256)(keyBytes))}`;
|
|
5747
7159
|
}
|
|
5748
7160
|
const privacyConfig = getPrivacyConfig(
|
|
5749
7161
|
privacy,
|
|
@@ -5752,7 +7164,7 @@ async function createShieldedPayment(params, options) {
|
|
|
5752
7164
|
const now = Math.floor(Date.now() / 1e3);
|
|
5753
7165
|
const payment = {
|
|
5754
7166
|
paymentId,
|
|
5755
|
-
version:
|
|
7167
|
+
version: import_types15.SIP_VERSION,
|
|
5756
7168
|
privacyLevel: privacy,
|
|
5757
7169
|
createdAt: now,
|
|
5758
7170
|
expiry: now + ttl,
|
|
@@ -5763,7 +7175,7 @@ async function createShieldedPayment(params, options) {
|
|
|
5763
7175
|
purpose,
|
|
5764
7176
|
viewingKeyHash
|
|
5765
7177
|
};
|
|
5766
|
-
if (privacy !==
|
|
7178
|
+
if (privacy !== import_types15.PrivacyLevel.TRANSPARENT && recipientMetaAddress) {
|
|
5767
7179
|
const metaAddress = decodeStealthMetaAddress(recipientMetaAddress);
|
|
5768
7180
|
const { stealthAddress } = generateStealthAddress(metaAddress);
|
|
5769
7181
|
payment.recipientStealth = stealthAddress;
|
|
@@ -5780,10 +7192,10 @@ async function createShieldedPayment(params, options) {
|
|
|
5780
7192
|
payment.recipientAddress = recipientAddress;
|
|
5781
7193
|
payment.memo = memo;
|
|
5782
7194
|
}
|
|
5783
|
-
if (privacy !==
|
|
7195
|
+
if (privacy !== import_types15.PrivacyLevel.TRANSPARENT && proofProvider?.isReady) {
|
|
5784
7196
|
const hexToUint8 = (hex) => {
|
|
5785
7197
|
const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
5786
|
-
return (0,
|
|
7198
|
+
return (0, import_utils12.hexToBytes)(cleanHex);
|
|
5787
7199
|
};
|
|
5788
7200
|
const fundingResult = await proofProvider.generateFundingProof({
|
|
5789
7201
|
balance: amount,
|
|
@@ -5810,17 +7222,17 @@ async function createShieldedPayment(params, options) {
|
|
|
5810
7222
|
}
|
|
5811
7223
|
function encryptMemo(memo, viewingKey) {
|
|
5812
7224
|
const keyHex = viewingKey.startsWith("0x") ? viewingKey.slice(2) : viewingKey;
|
|
5813
|
-
const keyBytes = (0,
|
|
7225
|
+
const keyBytes = (0, import_utils12.hexToBytes)(keyHex);
|
|
5814
7226
|
const encKey = (0, import_hkdf2.hkdf)(import_sha2569.sha256, keyBytes, new Uint8Array(0), new Uint8Array(0), 32);
|
|
5815
7227
|
try {
|
|
5816
|
-
const nonce = (0,
|
|
7228
|
+
const nonce = (0, import_utils12.randomBytes)(24);
|
|
5817
7229
|
const cipher = (0, import_chacha2.xchacha20poly1305)(encKey, nonce);
|
|
5818
7230
|
const plaintext = new TextEncoder().encode(memo);
|
|
5819
7231
|
const ciphertext = cipher.encrypt(plaintext);
|
|
5820
7232
|
const result = new Uint8Array(nonce.length + ciphertext.length);
|
|
5821
7233
|
result.set(nonce);
|
|
5822
7234
|
result.set(ciphertext, nonce.length);
|
|
5823
|
-
return `0x${(0,
|
|
7235
|
+
return `0x${(0, import_utils12.bytesToHex)(result)}`;
|
|
5824
7236
|
} finally {
|
|
5825
7237
|
secureWipe(keyBytes);
|
|
5826
7238
|
secureWipe(encKey);
|
|
@@ -5828,11 +7240,11 @@ function encryptMemo(memo, viewingKey) {
|
|
|
5828
7240
|
}
|
|
5829
7241
|
function decryptMemo(encryptedMemo, viewingKey) {
|
|
5830
7242
|
const keyHex = viewingKey.startsWith("0x") ? viewingKey.slice(2) : viewingKey;
|
|
5831
|
-
const keyBytes = (0,
|
|
7243
|
+
const keyBytes = (0, import_utils12.hexToBytes)(keyHex);
|
|
5832
7244
|
const encKey = (0, import_hkdf2.hkdf)(import_sha2569.sha256, keyBytes, new Uint8Array(0), new Uint8Array(0), 32);
|
|
5833
7245
|
try {
|
|
5834
7246
|
const dataHex = encryptedMemo.startsWith("0x") ? encryptedMemo.slice(2) : encryptedMemo;
|
|
5835
|
-
const data = (0,
|
|
7247
|
+
const data = (0, import_utils12.hexToBytes)(dataHex);
|
|
5836
7248
|
const nonce = data.slice(0, 24);
|
|
5837
7249
|
const ciphertext = data.slice(24);
|
|
5838
7250
|
const cipher = (0, import_chacha2.xchacha20poly1305)(encKey, nonce);
|
|
@@ -5846,7 +7258,7 @@ function decryptMemo(encryptedMemo, viewingKey) {
|
|
|
5846
7258
|
function trackPayment(payment) {
|
|
5847
7259
|
return {
|
|
5848
7260
|
...payment,
|
|
5849
|
-
status:
|
|
7261
|
+
status: import_types15.PaymentStatus.DRAFT
|
|
5850
7262
|
};
|
|
5851
7263
|
}
|
|
5852
7264
|
function isPaymentExpired(payment) {
|
|
@@ -5879,10 +7291,10 @@ function getPaymentSummary(payment) {
|
|
|
5879
7291
|
}
|
|
5880
7292
|
|
|
5881
7293
|
// src/treasury/treasury.ts
|
|
5882
|
-
var
|
|
7294
|
+
var import_types16 = require("@sip-protocol/types");
|
|
5883
7295
|
var import_secp256k13 = require("@noble/curves/secp256k1");
|
|
5884
7296
|
var import_sha25610 = require("@noble/hashes/sha256");
|
|
5885
|
-
var
|
|
7297
|
+
var import_utils13 = require("@noble/hashes/utils");
|
|
5886
7298
|
var DEFAULT_PROPOSAL_TTL = 7 * 24 * 60 * 60;
|
|
5887
7299
|
var Treasury = class _Treasury {
|
|
5888
7300
|
config;
|
|
@@ -5912,7 +7324,7 @@ var Treasury = class _Treasury {
|
|
|
5912
7324
|
...m,
|
|
5913
7325
|
addedAt: now
|
|
5914
7326
|
})),
|
|
5915
|
-
defaultPrivacy: params.defaultPrivacy ??
|
|
7327
|
+
defaultPrivacy: params.defaultPrivacy ?? import_types16.PrivacyLevel.SHIELDED,
|
|
5916
7328
|
masterViewingKey,
|
|
5917
7329
|
dailyLimit: params.dailyLimit,
|
|
5918
7330
|
transactionLimit: params.transactionLimit,
|
|
@@ -5991,7 +7403,7 @@ var Treasury = class _Treasury {
|
|
|
5991
7403
|
proposalId,
|
|
5992
7404
|
treasuryId: this.config.treasuryId,
|
|
5993
7405
|
type: "payment",
|
|
5994
|
-
status:
|
|
7406
|
+
status: import_types16.ProposalStatus.PENDING,
|
|
5995
7407
|
proposer: "",
|
|
5996
7408
|
// Should be set by caller
|
|
5997
7409
|
title: params.title,
|
|
@@ -6024,7 +7436,7 @@ var Treasury = class _Treasury {
|
|
|
6024
7436
|
proposalId,
|
|
6025
7437
|
treasuryId: this.config.treasuryId,
|
|
6026
7438
|
type: "batch_payment",
|
|
6027
|
-
status:
|
|
7439
|
+
status: import_types16.ProposalStatus.PENDING,
|
|
6028
7440
|
proposer: "",
|
|
6029
7441
|
title: params.title,
|
|
6030
7442
|
description: params.description,
|
|
@@ -6058,7 +7470,7 @@ var Treasury = class _Treasury {
|
|
|
6058
7470
|
* Get pending proposals
|
|
6059
7471
|
*/
|
|
6060
7472
|
getPendingProposals() {
|
|
6061
|
-
return this.getAllProposals().filter((p) => p.status ===
|
|
7473
|
+
return this.getAllProposals().filter((p) => p.status === import_types16.ProposalStatus.PENDING);
|
|
6062
7474
|
}
|
|
6063
7475
|
/**
|
|
6064
7476
|
* Sign a proposal
|
|
@@ -6089,7 +7501,7 @@ var Treasury = class _Treasury {
|
|
|
6089
7501
|
"SIP_2001" /* INVALID_INPUT */
|
|
6090
7502
|
);
|
|
6091
7503
|
}
|
|
6092
|
-
if (proposal.status !==
|
|
7504
|
+
if (proposal.status !== import_types16.ProposalStatus.PENDING) {
|
|
6093
7505
|
throw new ValidationError(
|
|
6094
7506
|
`proposal is not pending: ${proposal.status}`,
|
|
6095
7507
|
"proposalId",
|
|
@@ -6099,7 +7511,7 @@ var Treasury = class _Treasury {
|
|
|
6099
7511
|
}
|
|
6100
7512
|
const now = Math.floor(Date.now() / 1e3);
|
|
6101
7513
|
if (now > proposal.expiresAt) {
|
|
6102
|
-
proposal.status =
|
|
7514
|
+
proposal.status = import_types16.ProposalStatus.EXPIRED;
|
|
6103
7515
|
throw new ValidationError(
|
|
6104
7516
|
"proposal has expired",
|
|
6105
7517
|
"proposalId",
|
|
@@ -6131,9 +7543,9 @@ var Treasury = class _Treasury {
|
|
|
6131
7543
|
const approvals = proposal.signatures.filter((s) => s.approved).length;
|
|
6132
7544
|
const rejections = proposal.signatures.filter((s) => !s.approved).length;
|
|
6133
7545
|
if (approvals >= proposal.requiredSignatures) {
|
|
6134
|
-
proposal.status =
|
|
7546
|
+
proposal.status = import_types16.ProposalStatus.APPROVED;
|
|
6135
7547
|
} else if (rejections > this.config.totalSigners - proposal.requiredSignatures) {
|
|
6136
|
-
proposal.status =
|
|
7548
|
+
proposal.status = import_types16.ProposalStatus.REJECTED;
|
|
6137
7549
|
}
|
|
6138
7550
|
return proposal;
|
|
6139
7551
|
}
|
|
@@ -6150,7 +7562,7 @@ var Treasury = class _Treasury {
|
|
|
6150
7562
|
"SIP_2001" /* INVALID_INPUT */
|
|
6151
7563
|
);
|
|
6152
7564
|
}
|
|
6153
|
-
if (proposal.status !==
|
|
7565
|
+
if (proposal.status !== import_types16.ProposalStatus.APPROVED) {
|
|
6154
7566
|
throw new ValidationError(
|
|
6155
7567
|
`proposal is not approved: ${proposal.status}`,
|
|
6156
7568
|
"proposalId",
|
|
@@ -6163,8 +7575,8 @@ var Treasury = class _Treasury {
|
|
|
6163
7575
|
const payment = await createShieldedPayment({
|
|
6164
7576
|
token: proposal.payment.token,
|
|
6165
7577
|
amount: proposal.payment.amount,
|
|
6166
|
-
recipientMetaAddress: proposal.payment.privacy !==
|
|
6167
|
-
recipientAddress: proposal.payment.privacy ===
|
|
7578
|
+
recipientMetaAddress: proposal.payment.privacy !== import_types16.PrivacyLevel.TRANSPARENT ? proposal.payment.recipient : void 0,
|
|
7579
|
+
recipientAddress: proposal.payment.privacy === import_types16.PrivacyLevel.TRANSPARENT ? proposal.payment.recipient : void 0,
|
|
6168
7580
|
privacy: proposal.payment.privacy,
|
|
6169
7581
|
viewingKey: this.config.masterViewingKey?.key,
|
|
6170
7582
|
sourceChain: this.config.chain,
|
|
@@ -6177,8 +7589,8 @@ var Treasury = class _Treasury {
|
|
|
6177
7589
|
const payment = await createShieldedPayment({
|
|
6178
7590
|
token: proposal.batchPayment.token,
|
|
6179
7591
|
amount: recipient.amount,
|
|
6180
|
-
recipientMetaAddress: proposal.batchPayment.privacy !==
|
|
6181
|
-
recipientAddress: proposal.batchPayment.privacy ===
|
|
7592
|
+
recipientMetaAddress: proposal.batchPayment.privacy !== import_types16.PrivacyLevel.TRANSPARENT ? recipient.address : void 0,
|
|
7593
|
+
recipientAddress: proposal.batchPayment.privacy === import_types16.PrivacyLevel.TRANSPARENT ? recipient.address : void 0,
|
|
6182
7594
|
privacy: proposal.batchPayment.privacy,
|
|
6183
7595
|
viewingKey: this.config.masterViewingKey?.key,
|
|
6184
7596
|
sourceChain: this.config.chain,
|
|
@@ -6188,7 +7600,7 @@ var Treasury = class _Treasury {
|
|
|
6188
7600
|
payments.push(payment);
|
|
6189
7601
|
}
|
|
6190
7602
|
}
|
|
6191
|
-
proposal.status =
|
|
7603
|
+
proposal.status = import_types16.ProposalStatus.EXECUTED;
|
|
6192
7604
|
proposal.executedAt = Math.floor(Date.now() / 1e3);
|
|
6193
7605
|
proposal.resultPayments = payments;
|
|
6194
7606
|
return payments;
|
|
@@ -6217,7 +7629,7 @@ var Treasury = class _Treasury {
|
|
|
6217
7629
|
"SIP_2001" /* INVALID_INPUT */
|
|
6218
7630
|
);
|
|
6219
7631
|
}
|
|
6220
|
-
if (proposal.status !==
|
|
7632
|
+
if (proposal.status !== import_types16.ProposalStatus.PENDING) {
|
|
6221
7633
|
throw new ValidationError(
|
|
6222
7634
|
`proposal is not pending: ${proposal.status}`,
|
|
6223
7635
|
"proposalId",
|
|
@@ -6225,7 +7637,7 @@ var Treasury = class _Treasury {
|
|
|
6225
7637
|
"SIP_2001" /* INVALID_INPUT */
|
|
6226
7638
|
);
|
|
6227
7639
|
}
|
|
6228
|
-
proposal.status =
|
|
7640
|
+
proposal.status = import_types16.ProposalStatus.CANCELLED;
|
|
6229
7641
|
return proposal;
|
|
6230
7642
|
}
|
|
6231
7643
|
// ─── Auditor Access ──────────────────────────────────────────────────────────
|
|
@@ -6322,7 +7734,7 @@ var Treasury = class _Treasury {
|
|
|
6322
7734
|
getCommittedAmount(token) {
|
|
6323
7735
|
let committed = 0n;
|
|
6324
7736
|
for (const proposal of this.proposals.values()) {
|
|
6325
|
-
if (proposal.status !==
|
|
7737
|
+
if (proposal.status !== import_types16.ProposalStatus.PENDING) continue;
|
|
6326
7738
|
if (proposal.type === "payment" && proposal.payment) {
|
|
6327
7739
|
if (proposal.payment.token.symbol === token.symbol && proposal.payment.token.chain === token.chain) {
|
|
6328
7740
|
committed += proposal.payment.amount;
|
|
@@ -6373,12 +7785,12 @@ var Treasury = class _Treasury {
|
|
|
6373
7785
|
}
|
|
6374
7786
|
};
|
|
6375
7787
|
function generateTreasuryId() {
|
|
6376
|
-
const bytes = (0,
|
|
6377
|
-
return `treasury_${(0,
|
|
7788
|
+
const bytes = (0, import_utils13.randomBytes)(16);
|
|
7789
|
+
return `treasury_${(0, import_utils13.bytesToHex)(bytes)}`;
|
|
6378
7790
|
}
|
|
6379
7791
|
function generateProposalId() {
|
|
6380
|
-
const bytes = (0,
|
|
6381
|
-
return `prop_${(0,
|
|
7792
|
+
const bytes = (0, import_utils13.randomBytes)(16);
|
|
7793
|
+
return `prop_${(0, import_utils13.bytesToHex)(bytes)}`;
|
|
6382
7794
|
}
|
|
6383
7795
|
function computeProposalHash(proposal) {
|
|
6384
7796
|
const data = JSON.stringify({
|
|
@@ -6394,7 +7806,7 @@ function computeProposalHash(proposal) {
|
|
|
6394
7806
|
}
|
|
6395
7807
|
function signMessage(messageHash, privateKey) {
|
|
6396
7808
|
const keyHex = privateKey.startsWith("0x") ? privateKey.slice(2) : privateKey;
|
|
6397
|
-
const keyBytes = (0,
|
|
7809
|
+
const keyBytes = (0, import_utils13.hexToBytes)(keyHex);
|
|
6398
7810
|
try {
|
|
6399
7811
|
const signature = import_secp256k13.secp256k1.sign(messageHash, keyBytes);
|
|
6400
7812
|
return `0x${signature.toCompactHex()}`;
|
|
@@ -6406,8 +7818,8 @@ function verifySignature(messageHash, signature, publicKey) {
|
|
|
6406
7818
|
const sigHex = signature.startsWith("0x") ? signature.slice(2) : signature;
|
|
6407
7819
|
const pubKeyHex = publicKey.startsWith("0x") ? publicKey.slice(2) : publicKey;
|
|
6408
7820
|
try {
|
|
6409
|
-
const sigBytes = (0,
|
|
6410
|
-
const pubKeyBytes = (0,
|
|
7821
|
+
const sigBytes = (0, import_utils13.hexToBytes)(sigHex);
|
|
7822
|
+
const pubKeyBytes = (0, import_utils13.hexToBytes)(pubKeyHex);
|
|
6411
7823
|
return import_secp256k13.secp256k1.verify(sigBytes, messageHash, pubKeyBytes);
|
|
6412
7824
|
} catch {
|
|
6413
7825
|
return false;
|
|
@@ -6565,8 +7977,8 @@ function validateBatchProposalParams(params, config) {
|
|
|
6565
7977
|
}
|
|
6566
7978
|
|
|
6567
7979
|
// src/compliance/compliance-manager.ts
|
|
6568
|
-
var
|
|
6569
|
-
var
|
|
7980
|
+
var import_types17 = require("@sip-protocol/types");
|
|
7981
|
+
var import_utils14 = require("@noble/hashes/utils");
|
|
6570
7982
|
var DEFAULTS2 = {
|
|
6571
7983
|
riskThreshold: 70,
|
|
6572
7984
|
highValueThreshold: 10000000000n,
|
|
@@ -6933,7 +8345,7 @@ var ComplianceManager = class _ComplianceManager {
|
|
|
6933
8345
|
title: params.title,
|
|
6934
8346
|
description: params.description,
|
|
6935
8347
|
format: params.format,
|
|
6936
|
-
status:
|
|
8348
|
+
status: import_types17.ReportStatus.GENERATING,
|
|
6937
8349
|
requestedBy,
|
|
6938
8350
|
requestedAt: now,
|
|
6939
8351
|
startDate: params.startDate,
|
|
@@ -6962,10 +8374,10 @@ var ComplianceManager = class _ComplianceManager {
|
|
|
6962
8374
|
} else if (params.format === "csv") {
|
|
6963
8375
|
report.content = this.generateCSV(transactions);
|
|
6964
8376
|
}
|
|
6965
|
-
report.status =
|
|
8377
|
+
report.status = import_types17.ReportStatus.COMPLETED;
|
|
6966
8378
|
report.generatedAt = Math.floor(Date.now() / 1e3);
|
|
6967
8379
|
} catch (error) {
|
|
6968
|
-
report.status =
|
|
8380
|
+
report.status = import_types17.ReportStatus.FAILED;
|
|
6969
8381
|
report.error = error instanceof Error ? error.message : "Unknown error";
|
|
6970
8382
|
}
|
|
6971
8383
|
this.addAuditLog(requestedBy, "report_generated", {
|
|
@@ -7240,7 +8652,7 @@ var ComplianceManager = class _ComplianceManager {
|
|
|
7240
8652
|
}
|
|
7241
8653
|
};
|
|
7242
8654
|
function generateId(prefix) {
|
|
7243
|
-
return `${prefix}_${(0,
|
|
8655
|
+
return `${prefix}_${(0, import_utils14.bytesToHex)((0, import_utils14.randomBytes)(12))}`;
|
|
7244
8656
|
}
|
|
7245
8657
|
function validateRegisterAuditorParams(params) {
|
|
7246
8658
|
if (!params.organization?.trim()) {
|
|
@@ -7328,10 +8740,10 @@ function validateReportParams(params) {
|
|
|
7328
8740
|
}
|
|
7329
8741
|
|
|
7330
8742
|
// src/wallet/errors.ts
|
|
7331
|
-
var
|
|
8743
|
+
var import_types18 = require("@sip-protocol/types");
|
|
7332
8744
|
var WalletError = class extends SIPError {
|
|
7333
8745
|
walletCode;
|
|
7334
|
-
constructor(message, walletCode =
|
|
8746
|
+
constructor(message, walletCode = import_types18.WalletErrorCode.UNKNOWN, options) {
|
|
7335
8747
|
super(message, "SIP_7000" /* WALLET_ERROR */, options);
|
|
7336
8748
|
this.walletCode = walletCode;
|
|
7337
8749
|
this.name = "WalletError";
|
|
@@ -7341,10 +8753,10 @@ var WalletError = class extends SIPError {
|
|
|
7341
8753
|
*/
|
|
7342
8754
|
isConnectionError() {
|
|
7343
8755
|
const codes = [
|
|
7344
|
-
|
|
7345
|
-
|
|
7346
|
-
|
|
7347
|
-
|
|
8756
|
+
import_types18.WalletErrorCode.NOT_INSTALLED,
|
|
8757
|
+
import_types18.WalletErrorCode.CONNECTION_REJECTED,
|
|
8758
|
+
import_types18.WalletErrorCode.CONNECTION_FAILED,
|
|
8759
|
+
import_types18.WalletErrorCode.NOT_CONNECTED
|
|
7348
8760
|
];
|
|
7349
8761
|
return codes.includes(this.walletCode);
|
|
7350
8762
|
}
|
|
@@ -7353,9 +8765,9 @@ var WalletError = class extends SIPError {
|
|
|
7353
8765
|
*/
|
|
7354
8766
|
isSigningError() {
|
|
7355
8767
|
const codes = [
|
|
7356
|
-
|
|
7357
|
-
|
|
7358
|
-
|
|
8768
|
+
import_types18.WalletErrorCode.SIGNING_REJECTED,
|
|
8769
|
+
import_types18.WalletErrorCode.SIGNING_FAILED,
|
|
8770
|
+
import_types18.WalletErrorCode.INVALID_MESSAGE
|
|
7359
8771
|
];
|
|
7360
8772
|
return codes.includes(this.walletCode);
|
|
7361
8773
|
}
|
|
@@ -7364,10 +8776,10 @@ var WalletError = class extends SIPError {
|
|
|
7364
8776
|
*/
|
|
7365
8777
|
isTransactionError() {
|
|
7366
8778
|
const codes = [
|
|
7367
|
-
|
|
7368
|
-
|
|
7369
|
-
|
|
7370
|
-
|
|
8779
|
+
import_types18.WalletErrorCode.INSUFFICIENT_FUNDS,
|
|
8780
|
+
import_types18.WalletErrorCode.TRANSACTION_REJECTED,
|
|
8781
|
+
import_types18.WalletErrorCode.TRANSACTION_FAILED,
|
|
8782
|
+
import_types18.WalletErrorCode.INVALID_TRANSACTION
|
|
7371
8783
|
];
|
|
7372
8784
|
return codes.includes(this.walletCode);
|
|
7373
8785
|
}
|
|
@@ -7376,9 +8788,9 @@ var WalletError = class extends SIPError {
|
|
|
7376
8788
|
*/
|
|
7377
8789
|
isPrivacyError() {
|
|
7378
8790
|
const codes = [
|
|
7379
|
-
|
|
7380
|
-
|
|
7381
|
-
|
|
8791
|
+
import_types18.WalletErrorCode.STEALTH_NOT_SUPPORTED,
|
|
8792
|
+
import_types18.WalletErrorCode.VIEWING_KEY_NOT_SUPPORTED,
|
|
8793
|
+
import_types18.WalletErrorCode.SHIELDED_NOT_SUPPORTED
|
|
7382
8794
|
];
|
|
7383
8795
|
return codes.includes(this.walletCode);
|
|
7384
8796
|
}
|
|
@@ -7387,10 +8799,10 @@ var WalletError = class extends SIPError {
|
|
|
7387
8799
|
*/
|
|
7388
8800
|
isUserRejection() {
|
|
7389
8801
|
const codes = [
|
|
7390
|
-
|
|
7391
|
-
|
|
7392
|
-
|
|
7393
|
-
|
|
8802
|
+
import_types18.WalletErrorCode.CONNECTION_REJECTED,
|
|
8803
|
+
import_types18.WalletErrorCode.SIGNING_REJECTED,
|
|
8804
|
+
import_types18.WalletErrorCode.TRANSACTION_REJECTED,
|
|
8805
|
+
import_types18.WalletErrorCode.CHAIN_SWITCH_REJECTED
|
|
7394
8806
|
];
|
|
7395
8807
|
return codes.includes(this.walletCode);
|
|
7396
8808
|
}
|
|
@@ -7398,15 +8810,15 @@ var WalletError = class extends SIPError {
|
|
|
7398
8810
|
function notConnectedError() {
|
|
7399
8811
|
return new WalletError(
|
|
7400
8812
|
"Wallet not connected. Call connect() first.",
|
|
7401
|
-
|
|
8813
|
+
import_types18.WalletErrorCode.NOT_CONNECTED
|
|
7402
8814
|
);
|
|
7403
8815
|
}
|
|
7404
|
-
function featureNotSupportedError(feature, code =
|
|
8816
|
+
function featureNotSupportedError(feature, code = import_types18.WalletErrorCode.UNKNOWN) {
|
|
7405
8817
|
return new WalletError(`${feature} is not supported by this wallet`, code);
|
|
7406
8818
|
}
|
|
7407
8819
|
|
|
7408
8820
|
// src/wallet/base-adapter.ts
|
|
7409
|
-
var
|
|
8821
|
+
var import_types19 = require("@sip-protocol/types");
|
|
7410
8822
|
var BaseWalletAdapter = class {
|
|
7411
8823
|
_address = "";
|
|
7412
8824
|
_publicKey = "";
|
|
@@ -7569,12 +8981,12 @@ var MockWalletAdapter = class extends BaseWalletAdapter {
|
|
|
7569
8981
|
this._connectionState = "connecting";
|
|
7570
8982
|
if (this.shouldFailConnect) {
|
|
7571
8983
|
this.setError(
|
|
7572
|
-
|
|
8984
|
+
import_types19.WalletErrorCode.CONNECTION_FAILED,
|
|
7573
8985
|
"Mock connection failure"
|
|
7574
8986
|
);
|
|
7575
8987
|
throw new WalletError(
|
|
7576
8988
|
"Mock connection failure",
|
|
7577
|
-
|
|
8989
|
+
import_types19.WalletErrorCode.CONNECTION_FAILED
|
|
7578
8990
|
);
|
|
7579
8991
|
}
|
|
7580
8992
|
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
@@ -7586,7 +8998,7 @@ var MockWalletAdapter = class extends BaseWalletAdapter {
|
|
|
7586
8998
|
async signMessage(message) {
|
|
7587
8999
|
this.requireConnected();
|
|
7588
9000
|
if (this.shouldFailSign) {
|
|
7589
|
-
throw new WalletError("Mock signing failure",
|
|
9001
|
+
throw new WalletError("Mock signing failure", import_types19.WalletErrorCode.SIGNING_FAILED);
|
|
7590
9002
|
}
|
|
7591
9003
|
const mockSig = new Uint8Array(64);
|
|
7592
9004
|
for (let i = 0; i < 64; i++) {
|
|
@@ -7601,7 +9013,7 @@ var MockWalletAdapter = class extends BaseWalletAdapter {
|
|
|
7601
9013
|
async signTransaction(tx) {
|
|
7602
9014
|
this.requireConnected();
|
|
7603
9015
|
if (this.shouldFailSign) {
|
|
7604
|
-
throw new WalletError("Mock signing failure",
|
|
9016
|
+
throw new WalletError("Mock signing failure", import_types19.WalletErrorCode.SIGNING_FAILED);
|
|
7605
9017
|
}
|
|
7606
9018
|
const signature = await this.signMessage(
|
|
7607
9019
|
new TextEncoder().encode(JSON.stringify(tx.data))
|
|
@@ -7783,7 +9195,7 @@ function isPrivateWalletAdapter(adapter) {
|
|
|
7783
9195
|
}
|
|
7784
9196
|
|
|
7785
9197
|
// src/wallet/solana/adapter.ts
|
|
7786
|
-
var
|
|
9198
|
+
var import_types20 = require("@sip-protocol/types");
|
|
7787
9199
|
|
|
7788
9200
|
// src/wallet/solana/types.ts
|
|
7789
9201
|
function getSolanaProvider(wallet = "phantom") {
|
|
@@ -7904,19 +9316,19 @@ var SolanaWalletAdapter = class extends BaseWalletAdapter {
|
|
|
7904
9316
|
}
|
|
7905
9317
|
if (!this.provider) {
|
|
7906
9318
|
this.setError(
|
|
7907
|
-
|
|
9319
|
+
import_types20.WalletErrorCode.NOT_INSTALLED,
|
|
7908
9320
|
`${this.walletName} wallet is not installed`
|
|
7909
9321
|
);
|
|
7910
9322
|
throw new WalletError(
|
|
7911
9323
|
`${this.walletName} wallet is not installed`,
|
|
7912
|
-
|
|
9324
|
+
import_types20.WalletErrorCode.NOT_INSTALLED
|
|
7913
9325
|
);
|
|
7914
9326
|
}
|
|
7915
9327
|
const { publicKey } = await this.provider.connect();
|
|
7916
9328
|
if (!publicKey) {
|
|
7917
9329
|
throw new WalletError(
|
|
7918
9330
|
"No public key returned from wallet",
|
|
7919
|
-
|
|
9331
|
+
import_types20.WalletErrorCode.CONNECTION_FAILED
|
|
7920
9332
|
);
|
|
7921
9333
|
}
|
|
7922
9334
|
this.setupEventHandlers();
|
|
@@ -7926,11 +9338,11 @@ var SolanaWalletAdapter = class extends BaseWalletAdapter {
|
|
|
7926
9338
|
} catch (error) {
|
|
7927
9339
|
const message = error instanceof Error ? error.message : "Connection failed";
|
|
7928
9340
|
if (message.includes("User rejected") || message.includes("rejected")) {
|
|
7929
|
-
this.setError(
|
|
7930
|
-
throw new WalletError(message,
|
|
9341
|
+
this.setError(import_types20.WalletErrorCode.CONNECTION_REJECTED, message);
|
|
9342
|
+
throw new WalletError(message, import_types20.WalletErrorCode.CONNECTION_REJECTED);
|
|
7931
9343
|
}
|
|
7932
|
-
this.setError(
|
|
7933
|
-
throw error instanceof WalletError ? error : new WalletError(message,
|
|
9344
|
+
this.setError(import_types20.WalletErrorCode.CONNECTION_FAILED, message);
|
|
9345
|
+
throw error instanceof WalletError ? error : new WalletError(message, import_types20.WalletErrorCode.CONNECTION_FAILED, { cause: error });
|
|
7934
9346
|
}
|
|
7935
9347
|
}
|
|
7936
9348
|
/**
|
|
@@ -7953,7 +9365,7 @@ var SolanaWalletAdapter = class extends BaseWalletAdapter {
|
|
|
7953
9365
|
async signMessage(message) {
|
|
7954
9366
|
this.requireConnected();
|
|
7955
9367
|
if (!this.provider) {
|
|
7956
|
-
throw new WalletError("Provider not available",
|
|
9368
|
+
throw new WalletError("Provider not available", import_types20.WalletErrorCode.NOT_CONNECTED);
|
|
7957
9369
|
}
|
|
7958
9370
|
try {
|
|
7959
9371
|
const { signature } = await this.provider.signMessage(message);
|
|
@@ -7964,9 +9376,9 @@ var SolanaWalletAdapter = class extends BaseWalletAdapter {
|
|
|
7964
9376
|
} catch (error) {
|
|
7965
9377
|
const message2 = error instanceof Error ? error.message : "Signing failed";
|
|
7966
9378
|
if (message2.includes("User rejected") || message2.includes("rejected")) {
|
|
7967
|
-
throw new WalletError(message2,
|
|
9379
|
+
throw new WalletError(message2, import_types20.WalletErrorCode.SIGNING_REJECTED);
|
|
7968
9380
|
}
|
|
7969
|
-
throw new WalletError(message2,
|
|
9381
|
+
throw new WalletError(message2, import_types20.WalletErrorCode.SIGNING_FAILED, {
|
|
7970
9382
|
cause: error
|
|
7971
9383
|
});
|
|
7972
9384
|
}
|
|
@@ -7979,7 +9391,7 @@ var SolanaWalletAdapter = class extends BaseWalletAdapter {
|
|
|
7979
9391
|
async signTransaction(tx) {
|
|
7980
9392
|
this.requireConnected();
|
|
7981
9393
|
if (!this.provider) {
|
|
7982
|
-
throw new WalletError("Provider not available",
|
|
9394
|
+
throw new WalletError("Provider not available", import_types20.WalletErrorCode.NOT_CONNECTED);
|
|
7983
9395
|
}
|
|
7984
9396
|
try {
|
|
7985
9397
|
const solTx = tx.data;
|
|
@@ -7998,9 +9410,9 @@ var SolanaWalletAdapter = class extends BaseWalletAdapter {
|
|
|
7998
9410
|
} catch (error) {
|
|
7999
9411
|
const message = error instanceof Error ? error.message : "Signing failed";
|
|
8000
9412
|
if (message.includes("User rejected") || message.includes("rejected")) {
|
|
8001
|
-
throw new WalletError(message,
|
|
9413
|
+
throw new WalletError(message, import_types20.WalletErrorCode.SIGNING_REJECTED);
|
|
8002
9414
|
}
|
|
8003
|
-
throw new WalletError(message,
|
|
9415
|
+
throw new WalletError(message, import_types20.WalletErrorCode.SIGNING_FAILED, {
|
|
8004
9416
|
cause: error
|
|
8005
9417
|
});
|
|
8006
9418
|
}
|
|
@@ -8011,7 +9423,7 @@ var SolanaWalletAdapter = class extends BaseWalletAdapter {
|
|
|
8011
9423
|
async signAndSendTransaction(tx) {
|
|
8012
9424
|
this.requireConnected();
|
|
8013
9425
|
if (!this.provider) {
|
|
8014
|
-
throw new WalletError("Provider not available",
|
|
9426
|
+
throw new WalletError("Provider not available", import_types20.WalletErrorCode.NOT_CONNECTED);
|
|
8015
9427
|
}
|
|
8016
9428
|
try {
|
|
8017
9429
|
const solTx = tx.data;
|
|
@@ -8026,12 +9438,12 @@ var SolanaWalletAdapter = class extends BaseWalletAdapter {
|
|
|
8026
9438
|
} catch (error) {
|
|
8027
9439
|
const message = error instanceof Error ? error.message : "Transaction failed";
|
|
8028
9440
|
if (message.includes("User rejected") || message.includes("rejected")) {
|
|
8029
|
-
throw new WalletError(message,
|
|
9441
|
+
throw new WalletError(message, import_types20.WalletErrorCode.TRANSACTION_REJECTED);
|
|
8030
9442
|
}
|
|
8031
9443
|
if (message.includes("insufficient") || message.includes("Insufficient")) {
|
|
8032
|
-
throw new WalletError(message,
|
|
9444
|
+
throw new WalletError(message, import_types20.WalletErrorCode.INSUFFICIENT_FUNDS);
|
|
8033
9445
|
}
|
|
8034
|
-
throw new WalletError(message,
|
|
9446
|
+
throw new WalletError(message, import_types20.WalletErrorCode.TRANSACTION_FAILED, {
|
|
8035
9447
|
cause: error
|
|
8036
9448
|
});
|
|
8037
9449
|
}
|
|
@@ -8044,16 +9456,16 @@ var SolanaWalletAdapter = class extends BaseWalletAdapter {
|
|
|
8044
9456
|
async signAllTransactions(transactions) {
|
|
8045
9457
|
this.requireConnected();
|
|
8046
9458
|
if (!this.provider) {
|
|
8047
|
-
throw new WalletError("Provider not available",
|
|
9459
|
+
throw new WalletError("Provider not available", import_types20.WalletErrorCode.NOT_CONNECTED);
|
|
8048
9460
|
}
|
|
8049
9461
|
try {
|
|
8050
9462
|
return await this.provider.signAllTransactions(transactions);
|
|
8051
9463
|
} catch (error) {
|
|
8052
9464
|
const message = error instanceof Error ? error.message : "Signing failed";
|
|
8053
9465
|
if (message.includes("User rejected") || message.includes("rejected")) {
|
|
8054
|
-
throw new WalletError(message,
|
|
9466
|
+
throw new WalletError(message, import_types20.WalletErrorCode.SIGNING_REJECTED);
|
|
8055
9467
|
}
|
|
8056
|
-
throw new WalletError(message,
|
|
9468
|
+
throw new WalletError(message, import_types20.WalletErrorCode.SIGNING_FAILED, {
|
|
8057
9469
|
cause: error
|
|
8058
9470
|
});
|
|
8059
9471
|
}
|
|
@@ -8074,7 +9486,7 @@ var SolanaWalletAdapter = class extends BaseWalletAdapter {
|
|
|
8074
9486
|
} catch (error) {
|
|
8075
9487
|
throw new WalletError(
|
|
8076
9488
|
"Failed to get balance",
|
|
8077
|
-
|
|
9489
|
+
import_types20.WalletErrorCode.UNKNOWN,
|
|
8078
9490
|
{ cause: error }
|
|
8079
9491
|
);
|
|
8080
9492
|
}
|
|
@@ -8087,7 +9499,7 @@ var SolanaWalletAdapter = class extends BaseWalletAdapter {
|
|
|
8087
9499
|
if (asset.chain !== "solana") {
|
|
8088
9500
|
throw new WalletError(
|
|
8089
9501
|
`Asset chain ${asset.chain} not supported by Solana adapter`,
|
|
8090
|
-
|
|
9502
|
+
import_types20.WalletErrorCode.UNSUPPORTED_CHAIN
|
|
8091
9503
|
);
|
|
8092
9504
|
}
|
|
8093
9505
|
if (!asset.address) {
|
|
@@ -8205,7 +9617,7 @@ function createSolanaAdapter(config = {}) {
|
|
|
8205
9617
|
}
|
|
8206
9618
|
|
|
8207
9619
|
// src/wallet/solana/mock.ts
|
|
8208
|
-
var
|
|
9620
|
+
var import_types22 = require("@sip-protocol/types");
|
|
8209
9621
|
var MockPublicKey = class {
|
|
8210
9622
|
base58;
|
|
8211
9623
|
bytes;
|
|
@@ -8271,8 +9683,8 @@ var MockSolanaAdapter = class extends BaseWalletAdapter {
|
|
|
8271
9683
|
this._connectionState = "connecting";
|
|
8272
9684
|
await this.simulateLatency();
|
|
8273
9685
|
if (this.shouldFailConnect) {
|
|
8274
|
-
this.setError(
|
|
8275
|
-
throw new WalletError("Mock connection failure",
|
|
9686
|
+
this.setError(import_types22.WalletErrorCode.CONNECTION_FAILED, "Mock connection failure");
|
|
9687
|
+
throw new WalletError("Mock connection failure", import_types22.WalletErrorCode.CONNECTION_FAILED);
|
|
8276
9688
|
}
|
|
8277
9689
|
const hexPubKey = "0x" + Buffer.from(this.mockPublicKey.toBytes()).toString("hex");
|
|
8278
9690
|
this.setConnected(this.mockAddress, hexPubKey);
|
|
@@ -8291,7 +9703,7 @@ var MockSolanaAdapter = class extends BaseWalletAdapter {
|
|
|
8291
9703
|
this.requireConnected();
|
|
8292
9704
|
await this.simulateLatency();
|
|
8293
9705
|
if (this.shouldFailSign) {
|
|
8294
|
-
throw new WalletError("Mock signing failure",
|
|
9706
|
+
throw new WalletError("Mock signing failure", import_types22.WalletErrorCode.SIGNING_REJECTED);
|
|
8295
9707
|
}
|
|
8296
9708
|
const mockSig = new Uint8Array(64);
|
|
8297
9709
|
for (let i = 0; i < 64; i++) {
|
|
@@ -8309,7 +9721,7 @@ var MockSolanaAdapter = class extends BaseWalletAdapter {
|
|
|
8309
9721
|
this.requireConnected();
|
|
8310
9722
|
await this.simulateLatency();
|
|
8311
9723
|
if (this.shouldFailSign) {
|
|
8312
|
-
throw new WalletError("Mock signing failure",
|
|
9724
|
+
throw new WalletError("Mock signing failure", import_types22.WalletErrorCode.SIGNING_REJECTED);
|
|
8313
9725
|
}
|
|
8314
9726
|
const solTx = tx.data;
|
|
8315
9727
|
this.signedTransactions.push(solTx);
|
|
@@ -8329,10 +9741,10 @@ var MockSolanaAdapter = class extends BaseWalletAdapter {
|
|
|
8329
9741
|
this.requireConnected();
|
|
8330
9742
|
await this.simulateLatency();
|
|
8331
9743
|
if (this.shouldFailSign) {
|
|
8332
|
-
throw new WalletError("Mock signing failure",
|
|
9744
|
+
throw new WalletError("Mock signing failure", import_types22.WalletErrorCode.SIGNING_REJECTED);
|
|
8333
9745
|
}
|
|
8334
9746
|
if (this.shouldFailTransaction) {
|
|
8335
|
-
throw new WalletError("Mock transaction failure",
|
|
9747
|
+
throw new WalletError("Mock transaction failure", import_types22.WalletErrorCode.TRANSACTION_FAILED);
|
|
8336
9748
|
}
|
|
8337
9749
|
const txSig = `mock_tx_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
8338
9750
|
this.sentTransactions.push(txSig);
|
|
@@ -8352,7 +9764,7 @@ var MockSolanaAdapter = class extends BaseWalletAdapter {
|
|
|
8352
9764
|
this.requireConnected();
|
|
8353
9765
|
await this.simulateLatency();
|
|
8354
9766
|
if (this.shouldFailSign) {
|
|
8355
|
-
throw new WalletError("Mock signing failure",
|
|
9767
|
+
throw new WalletError("Mock signing failure", import_types22.WalletErrorCode.SIGNING_REJECTED);
|
|
8356
9768
|
}
|
|
8357
9769
|
this.signedTransactions.push(...transactions);
|
|
8358
9770
|
return transactions.map((tx) => {
|
|
@@ -8379,7 +9791,7 @@ var MockSolanaAdapter = class extends BaseWalletAdapter {
|
|
|
8379
9791
|
if (asset.chain !== "solana") {
|
|
8380
9792
|
throw new WalletError(
|
|
8381
9793
|
`Asset chain ${asset.chain} not supported by Solana adapter`,
|
|
8382
|
-
|
|
9794
|
+
import_types22.WalletErrorCode.UNSUPPORTED_CHAIN
|
|
8383
9795
|
);
|
|
8384
9796
|
}
|
|
8385
9797
|
if (!asset.address) {
|
|
@@ -8548,7 +9960,7 @@ function createMockSolanaAdapter(config = {}) {
|
|
|
8548
9960
|
}
|
|
8549
9961
|
|
|
8550
9962
|
// src/wallet/ethereum/adapter.ts
|
|
8551
|
-
var
|
|
9963
|
+
var import_types24 = require("@sip-protocol/types");
|
|
8552
9964
|
|
|
8553
9965
|
// src/wallet/ethereum/types.ts
|
|
8554
9966
|
var EthereumChainId = {
|
|
@@ -8690,7 +10102,7 @@ var EthereumWalletAdapter = class extends BaseWalletAdapter {
|
|
|
8690
10102
|
this._connectionState = "error";
|
|
8691
10103
|
throw new WalletError(
|
|
8692
10104
|
`${this.walletType} wallet not found. Please install the extension.`,
|
|
8693
|
-
|
|
10105
|
+
import_types24.WalletErrorCode.NOT_INSTALLED
|
|
8694
10106
|
);
|
|
8695
10107
|
}
|
|
8696
10108
|
const accounts = await this.provider.request({
|
|
@@ -8700,7 +10112,7 @@ var EthereumWalletAdapter = class extends BaseWalletAdapter {
|
|
|
8700
10112
|
this._connectionState = "error";
|
|
8701
10113
|
throw new WalletError(
|
|
8702
10114
|
"No accounts returned from wallet",
|
|
8703
|
-
|
|
10115
|
+
import_types24.WalletErrorCode.CONNECTION_REJECTED
|
|
8704
10116
|
);
|
|
8705
10117
|
}
|
|
8706
10118
|
const address = normalizeAddress(accounts[0]);
|
|
@@ -8720,12 +10132,12 @@ var EthereumWalletAdapter = class extends BaseWalletAdapter {
|
|
|
8720
10132
|
if (rpcError.code === 4001) {
|
|
8721
10133
|
throw new WalletError(
|
|
8722
10134
|
"User rejected connection request",
|
|
8723
|
-
|
|
10135
|
+
import_types24.WalletErrorCode.CONNECTION_REJECTED
|
|
8724
10136
|
);
|
|
8725
10137
|
}
|
|
8726
10138
|
throw new WalletError(
|
|
8727
10139
|
`Failed to connect: ${rpcError.message || String(error)}`,
|
|
8728
|
-
|
|
10140
|
+
import_types24.WalletErrorCode.CONNECTION_FAILED
|
|
8729
10141
|
);
|
|
8730
10142
|
}
|
|
8731
10143
|
}
|
|
@@ -8745,7 +10157,7 @@ var EthereumWalletAdapter = class extends BaseWalletAdapter {
|
|
|
8745
10157
|
if (!this.provider) {
|
|
8746
10158
|
throw new WalletError(
|
|
8747
10159
|
"Provider not available",
|
|
8748
|
-
|
|
10160
|
+
import_types24.WalletErrorCode.NOT_CONNECTED
|
|
8749
10161
|
);
|
|
8750
10162
|
}
|
|
8751
10163
|
try {
|
|
@@ -8763,12 +10175,12 @@ var EthereumWalletAdapter = class extends BaseWalletAdapter {
|
|
|
8763
10175
|
if (rpcError.code === 4001) {
|
|
8764
10176
|
throw new WalletError(
|
|
8765
10177
|
"User rejected signing request",
|
|
8766
|
-
|
|
10178
|
+
import_types24.WalletErrorCode.SIGNING_REJECTED
|
|
8767
10179
|
);
|
|
8768
10180
|
}
|
|
8769
10181
|
throw new WalletError(
|
|
8770
10182
|
`Failed to sign message: ${rpcError.message || String(error)}`,
|
|
8771
|
-
|
|
10183
|
+
import_types24.WalletErrorCode.SIGNING_FAILED
|
|
8772
10184
|
);
|
|
8773
10185
|
}
|
|
8774
10186
|
}
|
|
@@ -8780,7 +10192,7 @@ var EthereumWalletAdapter = class extends BaseWalletAdapter {
|
|
|
8780
10192
|
if (!this.provider) {
|
|
8781
10193
|
throw new WalletError(
|
|
8782
10194
|
"Provider not available",
|
|
8783
|
-
|
|
10195
|
+
import_types24.WalletErrorCode.NOT_CONNECTED
|
|
8784
10196
|
);
|
|
8785
10197
|
}
|
|
8786
10198
|
try {
|
|
@@ -8797,12 +10209,12 @@ var EthereumWalletAdapter = class extends BaseWalletAdapter {
|
|
|
8797
10209
|
if (rpcError.code === 4001) {
|
|
8798
10210
|
throw new WalletError(
|
|
8799
10211
|
"User rejected signing request",
|
|
8800
|
-
|
|
10212
|
+
import_types24.WalletErrorCode.SIGNING_REJECTED
|
|
8801
10213
|
);
|
|
8802
10214
|
}
|
|
8803
10215
|
throw new WalletError(
|
|
8804
10216
|
`Failed to sign typed data: ${rpcError.message || String(error)}`,
|
|
8805
|
-
|
|
10217
|
+
import_types24.WalletErrorCode.SIGNING_FAILED
|
|
8806
10218
|
);
|
|
8807
10219
|
}
|
|
8808
10220
|
}
|
|
@@ -8814,7 +10226,7 @@ var EthereumWalletAdapter = class extends BaseWalletAdapter {
|
|
|
8814
10226
|
if (!this.provider) {
|
|
8815
10227
|
throw new WalletError(
|
|
8816
10228
|
"Provider not available",
|
|
8817
|
-
|
|
10229
|
+
import_types24.WalletErrorCode.NOT_CONNECTED
|
|
8818
10230
|
);
|
|
8819
10231
|
}
|
|
8820
10232
|
try {
|
|
@@ -8842,7 +10254,7 @@ var EthereumWalletAdapter = class extends BaseWalletAdapter {
|
|
|
8842
10254
|
if (rpcError.code === 4001) {
|
|
8843
10255
|
throw new WalletError(
|
|
8844
10256
|
"User rejected transaction signing",
|
|
8845
|
-
|
|
10257
|
+
import_types24.WalletErrorCode.SIGNING_REJECTED
|
|
8846
10258
|
);
|
|
8847
10259
|
}
|
|
8848
10260
|
if (rpcError.code === -32601 || rpcError.message?.includes("not supported")) {
|
|
@@ -8860,7 +10272,7 @@ var EthereumWalletAdapter = class extends BaseWalletAdapter {
|
|
|
8860
10272
|
}
|
|
8861
10273
|
throw new WalletError(
|
|
8862
10274
|
`Failed to sign transaction: ${rpcError.message || String(error)}`,
|
|
8863
|
-
|
|
10275
|
+
import_types24.WalletErrorCode.TRANSACTION_FAILED
|
|
8864
10276
|
);
|
|
8865
10277
|
}
|
|
8866
10278
|
}
|
|
@@ -8872,7 +10284,7 @@ var EthereumWalletAdapter = class extends BaseWalletAdapter {
|
|
|
8872
10284
|
if (!this.provider) {
|
|
8873
10285
|
throw new WalletError(
|
|
8874
10286
|
"Provider not available",
|
|
8875
|
-
|
|
10287
|
+
import_types24.WalletErrorCode.NOT_CONNECTED
|
|
8876
10288
|
);
|
|
8877
10289
|
}
|
|
8878
10290
|
try {
|
|
@@ -8894,12 +10306,12 @@ var EthereumWalletAdapter = class extends BaseWalletAdapter {
|
|
|
8894
10306
|
if (rpcError.code === 4001) {
|
|
8895
10307
|
throw new WalletError(
|
|
8896
10308
|
"User rejected transaction",
|
|
8897
|
-
|
|
10309
|
+
import_types24.WalletErrorCode.TRANSACTION_REJECTED
|
|
8898
10310
|
);
|
|
8899
10311
|
}
|
|
8900
10312
|
throw new WalletError(
|
|
8901
10313
|
`Failed to send transaction: ${rpcError.message || String(error)}`,
|
|
8902
|
-
|
|
10314
|
+
import_types24.WalletErrorCode.TRANSACTION_FAILED
|
|
8903
10315
|
);
|
|
8904
10316
|
}
|
|
8905
10317
|
}
|
|
@@ -8934,7 +10346,7 @@ var EthereumWalletAdapter = class extends BaseWalletAdapter {
|
|
|
8934
10346
|
} catch (error) {
|
|
8935
10347
|
throw new WalletError(
|
|
8936
10348
|
`Failed to fetch balance: ${String(error)}`,
|
|
8937
|
-
|
|
10349
|
+
import_types24.WalletErrorCode.UNKNOWN
|
|
8938
10350
|
);
|
|
8939
10351
|
}
|
|
8940
10352
|
}
|
|
@@ -8946,7 +10358,7 @@ var EthereumWalletAdapter = class extends BaseWalletAdapter {
|
|
|
8946
10358
|
if (asset.chain !== "ethereum") {
|
|
8947
10359
|
throw new WalletError(
|
|
8948
10360
|
`Asset chain ${asset.chain} not supported by Ethereum adapter`,
|
|
8949
|
-
|
|
10361
|
+
import_types24.WalletErrorCode.UNSUPPORTED_CHAIN
|
|
8950
10362
|
);
|
|
8951
10363
|
}
|
|
8952
10364
|
if (!asset.address) {
|
|
@@ -8971,7 +10383,7 @@ var EthereumWalletAdapter = class extends BaseWalletAdapter {
|
|
|
8971
10383
|
} catch (error) {
|
|
8972
10384
|
throw new WalletError(
|
|
8973
10385
|
`Failed to fetch token balance: ${String(error)}`,
|
|
8974
|
-
|
|
10386
|
+
import_types24.WalletErrorCode.UNKNOWN
|
|
8975
10387
|
);
|
|
8976
10388
|
}
|
|
8977
10389
|
}
|
|
@@ -8983,7 +10395,7 @@ var EthereumWalletAdapter = class extends BaseWalletAdapter {
|
|
|
8983
10395
|
if (!this.provider) {
|
|
8984
10396
|
throw new WalletError(
|
|
8985
10397
|
"Provider not available",
|
|
8986
|
-
|
|
10398
|
+
import_types24.WalletErrorCode.NOT_CONNECTED
|
|
8987
10399
|
);
|
|
8988
10400
|
}
|
|
8989
10401
|
try {
|
|
@@ -8998,18 +10410,18 @@ var EthereumWalletAdapter = class extends BaseWalletAdapter {
|
|
|
8998
10410
|
if (rpcError.code === 4001) {
|
|
8999
10411
|
throw new WalletError(
|
|
9000
10412
|
"User rejected chain switch",
|
|
9001
|
-
|
|
10413
|
+
import_types24.WalletErrorCode.CHAIN_SWITCH_REJECTED
|
|
9002
10414
|
);
|
|
9003
10415
|
}
|
|
9004
10416
|
if (rpcError.code === 4902) {
|
|
9005
10417
|
throw new WalletError(
|
|
9006
10418
|
`Chain ${chainId} not added to wallet`,
|
|
9007
|
-
|
|
10419
|
+
import_types24.WalletErrorCode.UNSUPPORTED_CHAIN
|
|
9008
10420
|
);
|
|
9009
10421
|
}
|
|
9010
10422
|
throw new WalletError(
|
|
9011
10423
|
`Failed to switch chain: ${rpcError.message || String(error)}`,
|
|
9012
|
-
|
|
10424
|
+
import_types24.WalletErrorCode.CHAIN_SWITCH_FAILED
|
|
9013
10425
|
);
|
|
9014
10426
|
}
|
|
9015
10427
|
}
|
|
@@ -9045,7 +10457,7 @@ var EthereumWalletAdapter = class extends BaseWalletAdapter {
|
|
|
9045
10457
|
}
|
|
9046
10458
|
throw new WalletError(
|
|
9047
10459
|
`Transaction ${txHash} not confirmed after ${maxAttempts * 5} seconds`,
|
|
9048
|
-
|
|
10460
|
+
import_types24.WalletErrorCode.TRANSACTION_FAILED
|
|
9049
10461
|
);
|
|
9050
10462
|
}
|
|
9051
10463
|
/**
|
|
@@ -9119,7 +10531,7 @@ function createEthereumAdapter(config) {
|
|
|
9119
10531
|
}
|
|
9120
10532
|
|
|
9121
10533
|
// src/wallet/ethereum/mock.ts
|
|
9122
|
-
var
|
|
10534
|
+
var import_types26 = require("@sip-protocol/types");
|
|
9123
10535
|
var MockEthereumAdapter = class extends BaseWalletAdapter {
|
|
9124
10536
|
chain = "ethereum";
|
|
9125
10537
|
name = "mock-ethereum";
|
|
@@ -9160,7 +10572,7 @@ var MockEthereumAdapter = class extends BaseWalletAdapter {
|
|
|
9160
10572
|
this._connectionState = "error";
|
|
9161
10573
|
throw new WalletError(
|
|
9162
10574
|
"Mock connection rejected",
|
|
9163
|
-
|
|
10575
|
+
import_types26.WalletErrorCode.CONNECTION_REJECTED
|
|
9164
10576
|
);
|
|
9165
10577
|
}
|
|
9166
10578
|
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
@@ -9172,7 +10584,7 @@ var MockEthereumAdapter = class extends BaseWalletAdapter {
|
|
|
9172
10584
|
this._connectionState = "error";
|
|
9173
10585
|
throw new WalletError(
|
|
9174
10586
|
`Mock connection failed: ${String(error)}`,
|
|
9175
|
-
|
|
10587
|
+
import_types26.WalletErrorCode.CONNECTION_FAILED
|
|
9176
10588
|
);
|
|
9177
10589
|
}
|
|
9178
10590
|
}
|
|
@@ -9190,7 +10602,7 @@ var MockEthereumAdapter = class extends BaseWalletAdapter {
|
|
|
9190
10602
|
if (this._shouldFailSign) {
|
|
9191
10603
|
throw new WalletError(
|
|
9192
10604
|
"Mock signing rejected",
|
|
9193
|
-
|
|
10605
|
+
import_types26.WalletErrorCode.SIGNING_REJECTED
|
|
9194
10606
|
);
|
|
9195
10607
|
}
|
|
9196
10608
|
const msgHex = Buffer.from(message).toString("hex");
|
|
@@ -9208,7 +10620,7 @@ var MockEthereumAdapter = class extends BaseWalletAdapter {
|
|
|
9208
10620
|
if (this._shouldFailSign) {
|
|
9209
10621
|
throw new WalletError(
|
|
9210
10622
|
"Mock signing rejected",
|
|
9211
|
-
|
|
10623
|
+
import_types26.WalletErrorCode.SIGNING_REJECTED
|
|
9212
10624
|
);
|
|
9213
10625
|
}
|
|
9214
10626
|
const mockSig = `0x${"1".repeat(130)}`;
|
|
@@ -9225,7 +10637,7 @@ var MockEthereumAdapter = class extends BaseWalletAdapter {
|
|
|
9225
10637
|
if (this._shouldFailSign) {
|
|
9226
10638
|
throw new WalletError(
|
|
9227
10639
|
"Mock signing rejected",
|
|
9228
|
-
|
|
10640
|
+
import_types26.WalletErrorCode.SIGNING_REJECTED
|
|
9229
10641
|
);
|
|
9230
10642
|
}
|
|
9231
10643
|
this._signedTransactions.push(tx);
|
|
@@ -9250,7 +10662,7 @@ var MockEthereumAdapter = class extends BaseWalletAdapter {
|
|
|
9250
10662
|
if (this._shouldFailTransaction) {
|
|
9251
10663
|
throw new WalletError(
|
|
9252
10664
|
"Mock transaction failed",
|
|
9253
|
-
|
|
10665
|
+
import_types26.WalletErrorCode.TRANSACTION_FAILED
|
|
9254
10666
|
);
|
|
9255
10667
|
}
|
|
9256
10668
|
this._signedTransactions.push(tx);
|
|
@@ -9280,7 +10692,7 @@ var MockEthereumAdapter = class extends BaseWalletAdapter {
|
|
|
9280
10692
|
if (asset.chain !== "ethereum") {
|
|
9281
10693
|
throw new WalletError(
|
|
9282
10694
|
`Asset chain ${asset.chain} not supported by Ethereum adapter`,
|
|
9283
|
-
|
|
10695
|
+
import_types26.WalletErrorCode.UNSUPPORTED_CHAIN
|
|
9284
10696
|
);
|
|
9285
10697
|
}
|
|
9286
10698
|
if (!asset.address) {
|
|
@@ -9559,7 +10971,7 @@ function getAvailableTransports() {
|
|
|
9559
10971
|
}
|
|
9560
10972
|
|
|
9561
10973
|
// src/wallet/hardware/ledger.ts
|
|
9562
|
-
var
|
|
10974
|
+
var import_types29 = require("@sip-protocol/types");
|
|
9563
10975
|
var LedgerWalletAdapter = class extends BaseWalletAdapter {
|
|
9564
10976
|
chain;
|
|
9565
10977
|
name = "ledger";
|
|
@@ -9712,7 +11124,7 @@ var LedgerWalletAdapter = class extends BaseWalletAdapter {
|
|
|
9712
11124
|
async getBalance() {
|
|
9713
11125
|
throw new WalletError(
|
|
9714
11126
|
"Hardware wallets do not track balances. Use an RPC provider.",
|
|
9715
|
-
|
|
11127
|
+
import_types29.WalletErrorCode.UNSUPPORTED_OPERATION
|
|
9716
11128
|
);
|
|
9717
11129
|
}
|
|
9718
11130
|
/**
|
|
@@ -9723,7 +11135,7 @@ var LedgerWalletAdapter = class extends BaseWalletAdapter {
|
|
|
9723
11135
|
async getTokenBalance(_asset) {
|
|
9724
11136
|
throw new WalletError(
|
|
9725
11137
|
"Hardware wallets do not track balances. Use an RPC provider.",
|
|
9726
|
-
|
|
11138
|
+
import_types29.WalletErrorCode.UNSUPPORTED_OPERATION
|
|
9727
11139
|
);
|
|
9728
11140
|
}
|
|
9729
11141
|
// ─── Account Management ─────────────────────────────────────────────────────
|
|
@@ -10011,7 +11423,7 @@ function createLedgerAdapter(config) {
|
|
|
10011
11423
|
}
|
|
10012
11424
|
|
|
10013
11425
|
// src/wallet/hardware/trezor.ts
|
|
10014
|
-
var
|
|
11426
|
+
var import_types31 = require("@sip-protocol/types");
|
|
10015
11427
|
var TrezorWalletAdapter = class extends BaseWalletAdapter {
|
|
10016
11428
|
chain;
|
|
10017
11429
|
name = "trezor";
|
|
@@ -10157,7 +11569,7 @@ var TrezorWalletAdapter = class extends BaseWalletAdapter {
|
|
|
10157
11569
|
async getBalance() {
|
|
10158
11570
|
throw new WalletError(
|
|
10159
11571
|
"Hardware wallets do not track balances. Use an RPC provider.",
|
|
10160
|
-
|
|
11572
|
+
import_types31.WalletErrorCode.UNSUPPORTED_OPERATION
|
|
10161
11573
|
);
|
|
10162
11574
|
}
|
|
10163
11575
|
/**
|
|
@@ -10168,7 +11580,7 @@ var TrezorWalletAdapter = class extends BaseWalletAdapter {
|
|
|
10168
11580
|
async getTokenBalance(_asset) {
|
|
10169
11581
|
throw new WalletError(
|
|
10170
11582
|
"Hardware wallets do not track balances. Use an RPC provider.",
|
|
10171
|
-
|
|
11583
|
+
import_types31.WalletErrorCode.UNSUPPORTED_OPERATION
|
|
10172
11584
|
);
|
|
10173
11585
|
}
|
|
10174
11586
|
// ─── Account Management ─────────────────────────────────────────────────────
|
|
@@ -10449,8 +11861,8 @@ function createTrezorAdapter(config) {
|
|
|
10449
11861
|
}
|
|
10450
11862
|
|
|
10451
11863
|
// src/wallet/hardware/mock.ts
|
|
10452
|
-
var
|
|
10453
|
-
var
|
|
11864
|
+
var import_types33 = require("@sip-protocol/types");
|
|
11865
|
+
var import_utils15 = require("@noble/hashes/utils");
|
|
10454
11866
|
var MockLedgerAdapter = class extends BaseWalletAdapter {
|
|
10455
11867
|
chain;
|
|
10456
11868
|
name = "mock-ledger";
|
|
@@ -10597,7 +12009,7 @@ var MockLedgerAdapter = class extends BaseWalletAdapter {
|
|
|
10597
12009
|
async getBalance() {
|
|
10598
12010
|
throw new WalletError(
|
|
10599
12011
|
"Hardware wallets do not track balances",
|
|
10600
|
-
|
|
12012
|
+
import_types33.WalletErrorCode.UNSUPPORTED_OPERATION
|
|
10601
12013
|
);
|
|
10602
12014
|
}
|
|
10603
12015
|
/**
|
|
@@ -10606,7 +12018,7 @@ var MockLedgerAdapter = class extends BaseWalletAdapter {
|
|
|
10606
12018
|
async getTokenBalance(_asset) {
|
|
10607
12019
|
throw new WalletError(
|
|
10608
12020
|
"Hardware wallets do not track balances",
|
|
10609
|
-
|
|
12021
|
+
import_types33.WalletErrorCode.UNSUPPORTED_OPERATION
|
|
10610
12022
|
);
|
|
10611
12023
|
}
|
|
10612
12024
|
/**
|
|
@@ -10695,15 +12107,15 @@ var MockLedgerAdapter = class extends BaseWalletAdapter {
|
|
|
10695
12107
|
}
|
|
10696
12108
|
}
|
|
10697
12109
|
generateMockAddress(index) {
|
|
10698
|
-
const bytes = (0,
|
|
12110
|
+
const bytes = (0, import_utils15.randomBytes)(20);
|
|
10699
12111
|
bytes[0] = index;
|
|
10700
|
-
return `0x${(0,
|
|
12112
|
+
return `0x${(0, import_utils15.bytesToHex)(bytes)}`;
|
|
10701
12113
|
}
|
|
10702
12114
|
generateMockPublicKey(index) {
|
|
10703
|
-
const bytes = (0,
|
|
12115
|
+
const bytes = (0, import_utils15.randomBytes)(33);
|
|
10704
12116
|
bytes[0] = 2;
|
|
10705
12117
|
bytes[1] = index;
|
|
10706
|
-
return `0x${(0,
|
|
12118
|
+
return `0x${(0, import_utils15.bytesToHex)(bytes)}`;
|
|
10707
12119
|
}
|
|
10708
12120
|
generateMockSignature(data) {
|
|
10709
12121
|
const sig = new Uint8Array(65);
|
|
@@ -10712,7 +12124,7 @@ var MockLedgerAdapter = class extends BaseWalletAdapter {
|
|
|
10712
12124
|
sig[32 + i] = (data[i % data.length] ?? 0) ^ i * 11;
|
|
10713
12125
|
}
|
|
10714
12126
|
sig[64] = 27;
|
|
10715
|
-
return `0x${(0,
|
|
12127
|
+
return `0x${(0, import_utils15.bytesToHex)(sig)}`;
|
|
10716
12128
|
}
|
|
10717
12129
|
delay(ms) {
|
|
10718
12130
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -10836,13 +12248,13 @@ var MockTrezorAdapter = class extends BaseWalletAdapter {
|
|
|
10836
12248
|
async getBalance() {
|
|
10837
12249
|
throw new WalletError(
|
|
10838
12250
|
"Hardware wallets do not track balances",
|
|
10839
|
-
|
|
12251
|
+
import_types33.WalletErrorCode.UNSUPPORTED_OPERATION
|
|
10840
12252
|
);
|
|
10841
12253
|
}
|
|
10842
12254
|
async getTokenBalance(_asset) {
|
|
10843
12255
|
throw new WalletError(
|
|
10844
12256
|
"Hardware wallets do not track balances",
|
|
10845
|
-
|
|
12257
|
+
import_types33.WalletErrorCode.UNSUPPORTED_OPERATION
|
|
10846
12258
|
);
|
|
10847
12259
|
}
|
|
10848
12260
|
async getAccounts(startIndex = 0, count = 5) {
|
|
@@ -10901,15 +12313,15 @@ var MockTrezorAdapter = class extends BaseWalletAdapter {
|
|
|
10901
12313
|
}
|
|
10902
12314
|
}
|
|
10903
12315
|
generateMockAddress(index) {
|
|
10904
|
-
const bytes = (0,
|
|
12316
|
+
const bytes = (0, import_utils15.randomBytes)(20);
|
|
10905
12317
|
bytes[0] = index + 100;
|
|
10906
|
-
return `0x${(0,
|
|
12318
|
+
return `0x${(0, import_utils15.bytesToHex)(bytes)}`;
|
|
10907
12319
|
}
|
|
10908
12320
|
generateMockPublicKey(index) {
|
|
10909
|
-
const bytes = (0,
|
|
12321
|
+
const bytes = (0, import_utils15.randomBytes)(33);
|
|
10910
12322
|
bytes[0] = 3;
|
|
10911
12323
|
bytes[1] = index + 100;
|
|
10912
|
-
return `0x${(0,
|
|
12324
|
+
return `0x${(0, import_utils15.bytesToHex)(bytes)}`;
|
|
10913
12325
|
}
|
|
10914
12326
|
generateMockSignature(data) {
|
|
10915
12327
|
const sig = new Uint8Array(65);
|
|
@@ -10918,7 +12330,7 @@ var MockTrezorAdapter = class extends BaseWalletAdapter {
|
|
|
10918
12330
|
sig[32 + i] = (data[i % data.length] ?? 0) ^ i * 17;
|
|
10919
12331
|
}
|
|
10920
12332
|
sig[64] = 28;
|
|
10921
|
-
return `0x${(0,
|
|
12333
|
+
return `0x${(0, import_utils15.bytesToHex)(sig)}`;
|
|
10922
12334
|
}
|
|
10923
12335
|
delay(ms) {
|
|
10924
12336
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -10932,7 +12344,7 @@ function createMockTrezorAdapter(config) {
|
|
|
10932
12344
|
}
|
|
10933
12345
|
|
|
10934
12346
|
// src/wallet/index.ts
|
|
10935
|
-
var
|
|
12347
|
+
var import_types36 = require("@sip-protocol/types");
|
|
10936
12348
|
|
|
10937
12349
|
// src/proofs/browser.ts
|
|
10938
12350
|
var import_noir_js = require("@noir-lang/noir_js");
|
|
@@ -10940,7 +12352,7 @@ var import_bb = require("@aztec/bb.js");
|
|
|
10940
12352
|
var import_secp256k14 = require("@noble/curves/secp256k1");
|
|
10941
12353
|
|
|
10942
12354
|
// src/proofs/circuits/funding_proof.json
|
|
10943
|
-
var funding_proof_default = { noir_version: "1.0.0-beta.15+83245db91dcf63420ef4bcbbd85b98f397fee663", hash: "13977419962319221401", abi: { parameters: [{ name: "commitment_hash", type: { kind: "field" }, visibility: "public" }, { name: "minimum_required", type: { kind: "integer", sign: "unsigned", width: 64 }, visibility: "public" }, { name: "asset_id", type: { kind: "field" }, visibility: "public" }, { name: "balance", type: { kind: "integer", sign: "unsigned", width: 64 }, visibility: "private" }, { name: "blinding", type: { kind: "field" }, visibility: "private" }], return_type: null, error_types: { "2900908756532713827": { error_kind: "string", string: "Insufficient balance" }, "15764276373176857197": { error_kind: "string", string: "Stack too deep" }, "17719928407928969950": { error_kind: "string", string: "Commitment hash mismatch" } } }, bytecode: "H4sIAAAAAAAA/+VYbUhTURg+d7vTTdfmnJlK1g360LJolUEUJaUZ/qgooS9Taq5aoCudlhHV6LuglPplBH0gLUuiCCv6osA+LImItCQ0wUyRTJSJWkG7ds58PV53PzT60Qt3z+65z/ue533u8exeGfQnWIxZm+zZ4V4043PGe6gx8kcCNabGYyw+V6HBQcY4jDMzl+c0WC7E3l2ZVO5yrd0YM7t5WcG9HUVLGjxn2nEdDkkKRi3OZfxd5JC0XNiXBmMAYRAz+IEEqgJLTfS3mh+ibiGuy2hkaAhAykxlZPYKNYn1yvqZmJ5XrJaEReMLeOMDMWppknoYAsRMChyam0ZxGa10DWgkDWWRMkN1GINoklxDoQAxQ3VIuqFB0jX0mcbfgAAwxmHULiwwfYjX5ce2B+RZfo6u/FXgPtf2al7hIvuaOKsjZT3kRu1P7y3bb0mbdDWiU/+iZvai19f21Lw0htW5HlTE9JzZCLlSgnA1Ke7tua9OzFmVvuFRdeP8i5Gnjhgz5q2cfHpnfVLRw0YV5HLn3zyO+7Gmp4t1JNZEPevtzkm98TxhL9u6OWrz0conkyFXLOBCC0T9PvGowxhEaRUJJtj7ofceo9DILuRgpGwhGzAaaZLchQwFiC1kA5K+kI1I2Q0bJBDJ60ePlBkagtFEk+QaCgWIGRqCpBtqQv/GUBVSZmgoRjNNkmsoFCBmaCiSbqhZugbfFqIHYxzG/3mrhdyxiR0l3F7X0xMHJ5S40ppvWkIm3v9mjoi8X+u5VOZOXga56tK2uU2Lp0YzRdapz9YVt7SWXI8b437JlS64cfJ4RbcbcuVomN59L+HLccNy867Pq3N7m4qj81bY45uuHCjfctZp6aiqgtwZVcfertv6YPXdw0UzRoUf2ZR6vbz06bvu9CmV+77felJ4EHLFgjyg8evEgNGIMQSjCWMoRjOlXSTUMrhy6jJh3o/R3iOcuiD3LQpypcwpkevTwRvAov79o68QGrjpCL01WT92dk2MXBwDa5LNqa7Ycwe9b/HQ+eTnNdNmdWTtcOTaMrbZs53j8KiWYpNXMg5JCgauFvn5B5Lp1wGZ8yeTh6Hh6Cc5CvJ9D6yJIJ/Wwoce9f8fAFE5/IOdAXw3ghw+kkA9hrq2VGDeYfaURPJZZfmqUDR4flKLf1jle4zA52oBLlxLGsAR8hUJjDECdWhv4H3gMJotqGZ8fXzBtPC5jhX5h+pTy/aFXY79aoxoy1uQ3/PJQfei8qNd70eDXqAf6A/5m1Dm/+5kMifRpUGD/YL1WYofjVEH5oc6OeQ/ais81bdTZmWZqHw+SM98n1H4e6Y9x2Z12vNtGd6NybbVlpOxM8/htNuyncQJLcgiFeWsSJIfrCx/wGsporTAur4JMbICecwQ5yoK/XHpcTimF7hGapLfCqiX9PEbVAIFlc4UAAA=", debug_symbols: "pZbNbsMgDMffhXMO2HwE8irTVKUtmyJFaZUlk6aq7z6TQpYcYBW9QN3k/4sx2PjGzu44fx664ePyxZq3GzuOXd93n4f+cmqn7jLQvzfG/QCaNVgxqB+TYY2gybJGVgzpDXm/VyzKDtPonFdtOES/tqMbJtYMc99X7Lvt5+Wlr2s7LPPUjvSUV8wNZ5oJ+NH1zv+6V39qnpYajkFsUK9yqHd6SOu1lEGvlSjRG4h6Y4r0cfE1T34/t36I/hsJq149HT/gwgYAcKWKCGBWgq5ThDpD0BCDCHrjA9gdwWQI1kYfkGOSYNMECaACQYIyJQQUdSRgrcoI8CoBxROEbCSNjnthbQkBuYpHEgEhRfDhTiGEkjEQQnNe4gRgvTqhRdKJzKmUysZ1SC03tUUXImwKkUsukLG+AdhkemIGgWjW3BDbGrkPBWaKFBpct9So5JYivpxfWcRzCfYPAl5GPJVi2XBaHmsuWrAlCAE83hsCQJQh/pIMbP0qAtN5mjvfyNfLAyXfne93stpTN+5bE6SHFRPLKJdRLaP210/FqFkB2h/zsOzDAupW/CUF4HOAZoIglTkQwZbBVsHWwfatjw29jz/23+3YtcfeeU+8r/Nwio6ROf1c45PYVV3Hy8md59H5RWxaKxrfKKfQvt/9Qn8B", file_map: { "16": { source: "use crate::cmp::Eq;\nuse crate::hash::Hash;\nuse crate::ops::arith::{Add, Neg, Sub};\n\n/// A point on the embedded elliptic curve\n/// By definition, the base field of the embedded curve is the scalar field of the proof system curve, i.e the Noir Field.\n/// x and y denotes the Weierstrass coordinates of the point, if is_infinite is false.\npub struct EmbeddedCurvePoint {\n pub x: Field,\n pub y: Field,\n pub is_infinite: bool,\n}\n\nimpl EmbeddedCurvePoint {\n /// Elliptic curve point doubling operation\n /// returns the doubled point of a point P, i.e P+P\n pub fn double(self) -> EmbeddedCurvePoint {\n embedded_curve_add(self, self)\n }\n\n /// Returns the null element of the curve; 'the point at infinity'\n pub fn point_at_infinity() -> EmbeddedCurvePoint {\n EmbeddedCurvePoint { x: 0, y: 0, is_infinite: true }\n }\n\n /// Returns the curve's generator point.\n pub fn generator() -> EmbeddedCurvePoint {\n // Generator point for the grumpkin curve (y^2 = x^3 - 17)\n EmbeddedCurvePoint {\n x: 1,\n y: 17631683881184975370165255887551781615748388533673675138860, // sqrt(-16)\n is_infinite: false,\n }\n }\n}\n\nimpl Add for EmbeddedCurvePoint {\n /// Adds two points P+Q, using the curve addition formula, and also handles point at infinity\n fn add(self, other: EmbeddedCurvePoint) -> EmbeddedCurvePoint {\n embedded_curve_add(self, other)\n }\n}\n\nimpl Sub for EmbeddedCurvePoint {\n /// Points subtraction operation, using addition and negation\n fn sub(self, other: EmbeddedCurvePoint) -> EmbeddedCurvePoint {\n self + other.neg()\n }\n}\n\nimpl Neg for EmbeddedCurvePoint {\n /// Negates a point P, i.e returns -P, by negating the y coordinate.\n /// If the point is at infinity, then the result is also at infinity.\n fn neg(self) -> EmbeddedCurvePoint {\n EmbeddedCurvePoint { x: self.x, y: -self.y, is_infinite: self.is_infinite }\n }\n}\n\nimpl Eq for EmbeddedCurvePoint {\n /// Checks whether two points are equal\n fn eq(self: Self, b: EmbeddedCurvePoint) -> bool {\n (self.is_infinite & b.is_infinite)\n | ((self.is_infinite == b.is_infinite) & (self.x == b.x) & (self.y == b.y))\n }\n}\n\nimpl Hash for EmbeddedCurvePoint {\n fn hash<H>(self, state: &mut H)\n where\n H: crate::hash::Hasher,\n {\n if self.is_infinite {\n self.is_infinite.hash(state);\n } else {\n self.x.hash(state);\n self.y.hash(state);\n }\n }\n}\n\n/// Scalar for the embedded curve represented as low and high limbs\n/// By definition, the scalar field of the embedded curve is base field of the proving system curve.\n/// It may not fit into a Field element, so it is represented with two Field elements; its low and high limbs.\npub struct EmbeddedCurveScalar {\n pub lo: Field,\n pub hi: Field,\n}\n\nimpl EmbeddedCurveScalar {\n pub fn new(lo: Field, hi: Field) -> Self {\n EmbeddedCurveScalar { lo, hi }\n }\n\n #[field(bn254)]\n pub fn from_field(scalar: Field) -> EmbeddedCurveScalar {\n let (a, b) = crate::field::bn254::decompose(scalar);\n EmbeddedCurveScalar { lo: a, hi: b }\n }\n\n //Bytes to scalar: take the first (after the specified offset) 16 bytes of the input as the lo value, and the next 16 bytes as the hi value\n #[field(bn254)]\n pub(crate) fn from_bytes(bytes: [u8; 64], offset: u32) -> EmbeddedCurveScalar {\n let mut v = 1;\n let mut lo = 0 as Field;\n let mut hi = 0 as Field;\n for i in 0..16 {\n lo = lo + (bytes[offset + 31 - i] as Field) * v;\n hi = hi + (bytes[offset + 15 - i] as Field) * v;\n v = v * 256;\n }\n let sig_s = crate::embedded_curve_ops::EmbeddedCurveScalar { lo, hi };\n sig_s\n }\n}\n\nimpl Eq for EmbeddedCurveScalar {\n fn eq(self, other: Self) -> bool {\n (other.hi == self.hi) & (other.lo == self.lo)\n }\n}\n\nimpl Hash for EmbeddedCurveScalar {\n fn hash<H>(self, state: &mut H)\n where\n H: crate::hash::Hasher,\n {\n self.hi.hash(state);\n self.lo.hash(state);\n }\n}\n\n// Computes a multi scalar multiplication over the embedded curve.\n// For bn254, We have Grumpkin and Baby JubJub.\n// For bls12-381, we have JubJub and Bandersnatch.\n//\n// The embedded curve being used is decided by the\n// underlying proof system.\n// docs:start:multi_scalar_mul\npub fn multi_scalar_mul<let N: u32>(\n points: [EmbeddedCurvePoint; N],\n scalars: [EmbeddedCurveScalar; N],\n) -> EmbeddedCurvePoint\n// docs:end:multi_scalar_mul\n{\n multi_scalar_mul_array_return(points, scalars, true)[0]\n}\n\n#[foreign(multi_scalar_mul)]\npub(crate) fn multi_scalar_mul_array_return<let N: u32>(\n points: [EmbeddedCurvePoint; N],\n scalars: [EmbeddedCurveScalar; N],\n predicate: bool,\n) -> [EmbeddedCurvePoint; 1] {}\n\n// docs:start:fixed_base_scalar_mul\npub fn fixed_base_scalar_mul(scalar: EmbeddedCurveScalar) -> EmbeddedCurvePoint\n// docs:end:fixed_base_scalar_mul\n{\n multi_scalar_mul([EmbeddedCurvePoint::generator()], [scalar])\n}\n\n/// This function only assumes that the points are on the curve\n/// It handles corner cases around the infinity point causing some overhead compared to embedded_curve_add_not_nul and embedded_curve_add_unsafe\n// docs:start:embedded_curve_add\npub fn embedded_curve_add(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n // docs:end:embedded_curve_add\n if crate::runtime::is_unconstrained() {\n // `embedded_curve_add_unsafe` requires the inputs not to be the infinity point, so we check it here.\n // This is because `embedded_curve_add_unsafe` uses the `embedded_curve_add` opcode.\n // For efficiency, the backend does not check the inputs for the infinity point, but it assumes that they are not the infinity point\n // so that it can apply the ec addition formula directly.\n if point1.is_infinite {\n point2\n } else if point2.is_infinite {\n point1\n } else {\n embedded_curve_add_unsafe(point1, point2)\n }\n } else {\n // In a constrained context, we also need to check the inputs are not the infinity point because we also use `embedded_curve_add_unsafe`\n // However we also need to identify the case where the two inputs are the same, because then\n // the addition formula does not work and we need to use the doubling formula instead.\n // In unconstrained context, we can check directly if the input values are the same when solving the opcode, so it is not an issue.\n\n // x_coordinates_match is true if both abscissae are the same\n let x_coordinates_match = point1.x == point2.x;\n // y_coordinates_match is true if both ordinates are the same\n let y_coordinates_match = point1.y == point2.y;\n // double_predicate is true if both abscissae and ordinates are the same\n let double_predicate = (x_coordinates_match & y_coordinates_match);\n // If the abscissae are the same, but not the ordinates, then one point is the opposite of the other\n let infinity_predicate = (x_coordinates_match & !y_coordinates_match);\n\n // `embedded_curve_add_unsafe` would not perform doubling, even if the inputs point1 and point2 are the same, because it cannot know this without adding some logic (and some constraints)\n // However we did this logic when we computed `double_predicate`, so we set the result to 2*point1 if point1 and point2 are the same\n let mut result = if double_predicate {\n // `embedded_curve_add_unsafe` is doing a doubling if the input is the same variable, because in this case it is guaranteed (at 'compile time') that the input is the same.\n embedded_curve_add_unsafe(point1, point1)\n } else {\n let point1_1 = EmbeddedCurvePoint {\n x: point1.x + (x_coordinates_match as Field),\n y: point1.y,\n is_infinite: false,\n };\n let point2_1 = EmbeddedCurvePoint { x: point2.x, y: point2.y, is_infinite: false };\n // point1_1 is guaranteed to have a different abscissa than point2:\n // - if x_coordinates_match is 0, that means point1.x != point2.x, and point1_1.x = point1.x + 0\n // - if x_coordinates_match is 1, that means point1.x = point2.x, but point1_1.x = point1.x + 1 in this case\n // Because the abscissa is different, the addition formula is guaranteed to succeed, so we can safely use `embedded_curve_add_unsafe`\n // Note that this computation may be garbage: if x_coordinates_match is 1, or if one of the input is the point at infinity.\n // therefore we only want to do this if we need the result, otherwise it needs to be eliminated as a dead instruction, lest we want the circuit to fail.\n embedded_curve_add_unsafe(point1_1, point2_1)\n };\n\n // Same logic as above for unconstrained context, we set the proper result when one of the inputs is the infinity point\n if point1.is_infinite {\n result = point2;\n }\n if point2.is_infinite {\n result = point1;\n }\n\n // Finally, we set the is_infinity flag of the result:\n // Opposite points should sum into the infinity point, however, if one of them is point at infinity, their coordinates are not meaningful\n // so we should not use the fact that the inputs are opposite in this case:\n let mut result_is_infinity =\n infinity_predicate & (!point1.is_infinite & !point2.is_infinite);\n // However, if both of them are at infinity, then the result is also at infinity\n result.is_infinite = result_is_infinity | (point1.is_infinite & point2.is_infinite);\n result\n }\n}\n\n#[foreign(embedded_curve_add)]\nfn embedded_curve_add_array_return(\n _point1: EmbeddedCurvePoint,\n _point2: EmbeddedCurvePoint,\n _predicate: bool,\n) -> [EmbeddedCurvePoint; 1] {}\n\n/// This function assumes that:\n/// The points are on the curve, and\n/// The points don't share an x-coordinate, and\n/// Neither point is the infinity point.\n/// If it is used with correct input, the function ensures the correct non-zero result is returned.\n/// Except for points on the curve, the other assumptions are checked by the function. It will cause assertion failure if they are not respected.\npub fn embedded_curve_add_not_nul(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n assert(point1.x != point2.x);\n assert(!point1.is_infinite);\n assert(!point2.is_infinite);\n // Ensure is_infinite is comptime\n let point1_1 = EmbeddedCurvePoint { x: point1.x, y: point1.y, is_infinite: false };\n let point2_1 = EmbeddedCurvePoint { x: point2.x, y: point2.y, is_infinite: false };\n embedded_curve_add_unsafe(point1_1, point2_1)\n}\n\n/// Unsafe ec addition\n/// If the inputs are the same, it will perform a doubling, but only if point1 and point2 are the same variable.\n/// If they have the same value but are different variables, the result will be incorrect because in this case\n/// it assumes (but does not check) that the points' x-coordinates are not equal.\n/// It also assumes neither point is the infinity point.\npub fn embedded_curve_add_unsafe(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n embedded_curve_add_array_return(point1, point2, true)[0]\n}\n", path: "std/embedded_curve_ops.nr" }, "17": { source: `use crate::field::field_less_than;
|
|
12355
|
+
var funding_proof_default = { noir_version: "1.0.0-beta.15+83245db91dcf63420ef4bcbbd85b98f397fee663", hash: "3859649086066977477", abi: { parameters: [{ name: "minimum_required", type: { kind: "integer", sign: "unsigned", width: 64 }, visibility: "public" }, { name: "asset_id", type: { kind: "field" }, visibility: "public" }, { name: "balance", type: { kind: "integer", sign: "unsigned", width: 64 }, visibility: "private" }, { name: "blinding", type: { kind: "field" }, visibility: "private" }], return_type: { abi_type: { kind: "array", length: 32, type: { kind: "integer", sign: "unsigned", width: 8 } }, visibility: "public" }, error_types: { "2900908756532713827": { error_kind: "string", string: "Insufficient balance" }, "15764276373176857197": { error_kind: "string", string: "Stack too deep" }, "15835548349546956319": { error_kind: "string", string: "Field failed to decompose into specified 32 limbs" } } }, bytecode: "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", debug_symbols: "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", file_map: { "17": { source: `use crate::field::field_less_than;
|
|
10944
12356
|
use crate::runtime::is_unconstrained;
|
|
10945
12357
|
|
|
10946
12358
|
// The low and high decomposition of the field modulus
|
|
@@ -11143,105 +12555,7 @@ mod tests {
|
|
|
11143
12555
|
assert(!lt(TWO_POW_128, TWO_POW_128 - 1));
|
|
11144
12556
|
}
|
|
11145
12557
|
}
|
|
11146
|
-
`, path: "std/field/bn254.nr" }, "19": { source: '// Exposed only for usage in `std::meta`\npub(crate) mod poseidon2;\n\nuse crate::default::Default;\nuse crate::embedded_curve_ops::{\n EmbeddedCurvePoint, EmbeddedCurveScalar, multi_scalar_mul, multi_scalar_mul_array_return,\n};\nuse crate::meta::derive_via;\n\n#[foreign(sha256_compression)]\n// docs:start:sha256_compression\npub fn sha256_compression(input: [u32; 16], state: [u32; 8]) -> [u32; 8] {}\n// docs:end:sha256_compression\n\n#[foreign(keccakf1600)]\n// docs:start:keccakf1600\npub fn keccakf1600(input: [u64; 25]) -> [u64; 25] {}\n// docs:end:keccakf1600\n\npub mod keccak {\n #[deprecated("This function has been moved to std::hash::keccakf1600")]\n pub fn keccakf1600(input: [u64; 25]) -> [u64; 25] {\n super::keccakf1600(input)\n }\n}\n\n#[foreign(blake2s)]\n// docs:start:blake2s\npub fn blake2s<let N: u32>(input: [u8; N]) -> [u8; 32]\n// docs:end:blake2s\n{}\n\n// docs:start:blake3\npub fn blake3<let N: u32>(input: [u8; N]) -> [u8; 32]\n// docs:end:blake3\n{\n if crate::runtime::is_unconstrained() {\n // Temporary measure while Barretenberg is main proving system.\n // Please open an issue if you\'re working on another proving system and running into problems due to this.\n crate::static_assert(\n N <= 1024,\n "Barretenberg cannot prove blake3 hashes with inputs larger than 1024 bytes",\n );\n }\n __blake3(input)\n}\n\n#[foreign(blake3)]\nfn __blake3<let N: u32>(input: [u8; N]) -> [u8; 32] {}\n\n// docs:start:pedersen_commitment\npub fn pedersen_commitment<let N: u32>(input: [Field; N]) -> EmbeddedCurvePoint {\n // docs:end:pedersen_commitment\n pedersen_commitment_with_separator(input, 0)\n}\n\n#[inline_always]\npub fn pedersen_commitment_with_separator<let N: u32>(\n input: [Field; N],\n separator: u32,\n) -> EmbeddedCurvePoint {\n let mut points = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N];\n for i in 0..N {\n // we use the unsafe version because the multi_scalar_mul will constrain the scalars.\n points[i] = from_field_unsafe(input[i]);\n }\n let generators = derive_generators("DEFAULT_DOMAIN_SEPARATOR".as_bytes(), separator);\n multi_scalar_mul(generators, points)\n}\n\n// docs:start:pedersen_hash\npub fn pedersen_hash<let N: u32>(input: [Field; N]) -> Field\n// docs:end:pedersen_hash\n{\n pedersen_hash_with_separator(input, 0)\n}\n\n#[no_predicates]\npub fn pedersen_hash_with_separator<let N: u32>(input: [Field; N], separator: u32) -> Field {\n let mut scalars: [EmbeddedCurveScalar; N + 1] = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N + 1];\n let mut generators: [EmbeddedCurvePoint; N + 1] =\n [EmbeddedCurvePoint::point_at_infinity(); N + 1];\n let domain_generators: [EmbeddedCurvePoint; N] =\n derive_generators("DEFAULT_DOMAIN_SEPARATOR".as_bytes(), separator);\n\n for i in 0..N {\n scalars[i] = from_field_unsafe(input[i]);\n generators[i] = domain_generators[i];\n }\n scalars[N] = EmbeddedCurveScalar { lo: N as Field, hi: 0 as Field };\n\n let length_generator: [EmbeddedCurvePoint; 1] =\n derive_generators("pedersen_hash_length".as_bytes(), 0);\n generators[N] = length_generator[0];\n multi_scalar_mul_array_return(generators, scalars, true)[0].x\n}\n\n#[field(bn254)]\n#[inline_always]\npub fn derive_generators<let N: u32, let M: u32>(\n domain_separator_bytes: [u8; M],\n starting_index: u32,\n) -> [EmbeddedCurvePoint; N] {\n crate::assert_constant(domain_separator_bytes);\n // TODO(https://github.com/noir-lang/noir/issues/5672): Add back assert_constant on starting_index\n __derive_generators(domain_separator_bytes, starting_index)\n}\n\n#[builtin(derive_pedersen_generators)]\n#[field(bn254)]\nfn __derive_generators<let N: u32, let M: u32>(\n domain_separator_bytes: [u8; M],\n starting_index: u32,\n) -> [EmbeddedCurvePoint; N] {}\n\n#[field(bn254)]\n// Same as from_field but:\n// does not assert the limbs are 128 bits\n// does not assert the decomposition does not overflow the EmbeddedCurveScalar\nfn from_field_unsafe(scalar: Field) -> EmbeddedCurveScalar {\n // Safety: xlo and xhi decomposition is checked below\n let (xlo, xhi) = unsafe { crate::field::bn254::decompose_hint(scalar) };\n // Check that the decomposition is correct\n assert_eq(scalar, xlo + crate::field::bn254::TWO_POW_128 * xhi);\n EmbeddedCurveScalar { lo: xlo, hi: xhi }\n}\n\npub fn poseidon2_permutation<let N: u32>(input: [Field; N], state_len: u32) -> [Field; N] {\n assert_eq(input.len(), state_len);\n poseidon2_permutation_internal(input)\n}\n\n#[foreign(poseidon2_permutation)]\nfn poseidon2_permutation_internal<let N: u32>(input: [Field; N]) -> [Field; N] {}\n\n// Generic hashing support.\n// Partially ported and impacted by rust.\n\n// Hash trait shall be implemented per type.\n#[derive_via(derive_hash)]\npub trait Hash {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher;\n}\n\n// docs:start:derive_hash\ncomptime fn derive_hash(s: TypeDefinition) -> Quoted {\n let name = quote { $crate::hash::Hash };\n let signature = quote { fn hash<H>(_self: Self, _state: &mut H) where H: $crate::hash::Hasher };\n let for_each_field = |name| quote { _self.$name.hash(_state); };\n crate::meta::make_trait_impl(\n s,\n name,\n signature,\n for_each_field,\n quote {},\n |fields| fields,\n )\n}\n// docs:end:derive_hash\n\n// Hasher trait shall be implemented by algorithms to provide hash-agnostic means.\n// TODO: consider making the types generic here ([u8], [Field], etc.)\npub trait Hasher {\n fn finish(self) -> Field;\n\n fn write(&mut self, input: Field);\n}\n\n// BuildHasher is a factory trait, responsible for production of specific Hasher.\npub trait BuildHasher {\n type H: Hasher;\n\n fn build_hasher(self) -> H;\n}\n\npub struct BuildHasherDefault<H>;\n\nimpl<H> BuildHasher for BuildHasherDefault<H>\nwhere\n H: Hasher + Default,\n{\n type H = H;\n\n fn build_hasher(_self: Self) -> H {\n H::default()\n }\n}\n\nimpl<H> Default for BuildHasherDefault<H>\nwhere\n H: Hasher + Default,\n{\n fn default() -> Self {\n BuildHasherDefault {}\n }\n}\n\nimpl Hash for Field {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self);\n }\n}\n\nimpl Hash for u1 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u8 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u16 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u32 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u64 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u128 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for i8 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u8 as Field);\n }\n}\n\nimpl Hash for i16 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u16 as Field);\n }\n}\n\nimpl Hash for i32 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u32 as Field);\n }\n}\n\nimpl Hash for i64 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u64 as Field);\n }\n}\n\nimpl Hash for bool {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for () {\n fn hash<H>(_self: Self, _state: &mut H)\n where\n H: Hasher,\n {}\n}\n\nimpl<T, let N: u32> Hash for [T; N]\nwhere\n T: Hash,\n{\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n for elem in self {\n elem.hash(state);\n }\n }\n}\n\nimpl<T> Hash for [T]\nwhere\n T: Hash,\n{\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n self.len().hash(state);\n for elem in self {\n elem.hash(state);\n }\n }\n}\n\nimpl<A, B> Hash for (A, B)\nwhere\n A: Hash,\n B: Hash,\n{\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n }\n}\n\nimpl<A, B, C> Hash for (A, B, C)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n{\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n }\n}\n\nimpl<A, B, C, D> Hash for (A, B, C, D)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n D: Hash,\n{\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n self.3.hash(state);\n }\n}\n\nimpl<A, B, C, D, E> Hash for (A, B, C, D, E)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n D: Hash,\n E: Hash,\n{\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n self.3.hash(state);\n self.4.hash(state);\n }\n}\n\n// Some test vectors for Pedersen hash and Pedersen Commitment.\n// They have been generated using the same functions so the tests are for now useless\n// but they will be useful when we switch to Noir implementation.\n#[test]\nfn assert_pedersen() {\n assert_eq(\n pedersen_hash_with_separator([1], 1),\n 0x1b3f4b1a83092a13d8d1a59f7acb62aba15e7002f4440f2275edb99ebbc2305f,\n );\n assert_eq(\n pedersen_commitment_with_separator([1], 1),\n EmbeddedCurvePoint {\n x: 0x054aa86a73cb8a34525e5bbed6e43ba1198e860f5f3950268f71df4591bde402,\n y: 0x209dcfbf2cfb57f9f6046f44d71ac6faf87254afc7407c04eb621a6287cac126,\n is_infinite: false,\n },\n );\n\n assert_eq(\n pedersen_hash_with_separator([1, 2], 2),\n 0x26691c129448e9ace0c66d11f0a16d9014a9e8498ee78f4d69f0083168188255,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2], 2),\n EmbeddedCurvePoint {\n x: 0x2e2b3b191e49541fe468ec6877721d445dcaffe41728df0a0eafeb15e87b0753,\n y: 0x2ff4482400ad3a6228be17a2af33e2bcdf41be04795f9782bd96efe7e24f8778,\n is_infinite: false,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3], 3),\n 0x0bc694b7a1f8d10d2d8987d07433f26bd616a2d351bc79a3c540d85b6206dbe4,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3], 3),\n EmbeddedCurvePoint {\n x: 0x1fee4e8cf8d2f527caa2684236b07c4b1bad7342c01b0f75e9a877a71827dc85,\n y: 0x2f9fedb9a090697ab69bf04c8bc15f7385b3e4b68c849c1536e5ae15ff138fd1,\n is_infinite: false,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4], 4),\n 0xdae10fb32a8408521803905981a2b300d6a35e40e798743e9322b223a5eddc,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4], 4),\n EmbeddedCurvePoint {\n x: 0x07ae3e202811e1fca39c2d81eabe6f79183978e6f12be0d3b8eda095b79bdbc9,\n y: 0x0afc6f892593db6fbba60f2da558517e279e0ae04f95758587760ba193145014,\n is_infinite: false,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5], 5),\n 0xfc375b062c4f4f0150f7100dfb8d9b72a6d28582dd9512390b0497cdad9c22,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5], 5),\n EmbeddedCurvePoint {\n x: 0x1754b12bd475a6984a1094b5109eeca9838f4f81ac89c5f0a41dbce53189bb29,\n y: 0x2da030e3cfcdc7ddad80eaf2599df6692cae0717d4e9f7bfbee8d073d5d278f7,\n is_infinite: false,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6], 6),\n 0x1696ed13dc2730062a98ac9d8f9de0661bb98829c7582f699d0273b18c86a572,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6], 6),\n EmbeddedCurvePoint {\n x: 0x190f6c0e97ad83e1e28da22a98aae156da083c5a4100e929b77e750d3106a697,\n y: 0x1f4b60f34ef91221a0b49756fa0705da93311a61af73d37a0c458877706616fb,\n is_infinite: false,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\n 0x128c0ff144fc66b6cb60eeac8a38e23da52992fc427b92397a7dffd71c45ede3,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\n EmbeddedCurvePoint {\n x: 0x015441e9d29491b06563fac16fc76abf7a9534c715421d0de85d20dbe2965939,\n y: 0x1d2575b0276f4e9087e6e07c2cb75aa1baafad127af4be5918ef8a2ef2fea8fc,\n is_infinite: false,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\n 0x2f960e117482044dfc99d12fece2ef6862fba9242be4846c7c9a3e854325a55c,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\n EmbeddedCurvePoint {\n x: 0x1657737676968887fceb6dd516382ea13b3a2c557f509811cd86d5d1199bc443,\n y: 0x1f39f0cb569040105fa1e2f156521e8b8e08261e635a2b210bdc94e8d6d65f77,\n is_infinite: false,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\n 0x0c96db0790602dcb166cc4699e2d306c479a76926b81c2cb2aaa92d249ec7be7,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\n EmbeddedCurvePoint {\n x: 0x0a3ceae42d14914a432aa60ec7fded4af7dad7dd4acdbf2908452675ec67e06d,\n y: 0xfc19761eaaf621ad4aec9a8b2e84a4eceffdba78f60f8b9391b0bd9345a2f2,\n is_infinite: false,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\n 0x2cd37505871bc460a62ea1e63c7fe51149df5d0801302cf1cbc48beb8dff7e94,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\n EmbeddedCurvePoint {\n x: 0x2fb3f8b3d41ddde007c8c3c62550f9a9380ee546fcc639ffbb3fd30c8d8de30c,\n y: 0x300783be23c446b11a4c0fabf6c91af148937cea15fcf5fb054abf7f752ee245,\n is_infinite: false,\n },\n );\n}\n', path: "std/hash/mod.nr" }, "50": { source: `/// Funding Proof Circuit
|
|
11147
|
-
///
|
|
11148
|
-
/// Proves: "I have sufficient funds to fulfill this intent, without revealing
|
|
11149
|
-
/// my exact balance, wallet address, or source of funds."
|
|
11150
|
-
///
|
|
11151
|
-
/// @see docs/specs/FUNDING-PROOF.md
|
|
11152
|
-
|
|
11153
|
-
use std::hash::pedersen_hash;
|
|
11154
|
-
use std::hash::pedersen_commitment;
|
|
11155
|
-
|
|
11156
|
-
// --- Main Circuit ---
|
|
11157
|
-
|
|
11158
|
-
/// Main funding proof entry point
|
|
11159
|
-
///
|
|
11160
|
-
/// Public inputs: commitment_hash, minimum_required, asset_id
|
|
11161
|
-
/// Private inputs: balance, blinding
|
|
11162
|
-
///
|
|
11163
|
-
/// Constraints:
|
|
11164
|
-
/// 1. balance >= minimum_required (range proof via u64)
|
|
11165
|
-
/// 2. commitment = Pedersen(balance, blinding)
|
|
11166
|
-
/// 3. hash(commitment, asset_id) == commitment_hash
|
|
11167
|
-
pub fn main(
|
|
11168
|
-
commitment_hash: pub Field,
|
|
11169
|
-
minimum_required: pub u64,
|
|
11170
|
-
asset_id: pub Field,
|
|
11171
|
-
balance: u64,
|
|
11172
|
-
blinding: Field,
|
|
11173
|
-
) {
|
|
11174
|
-
// Constraint 1: Sufficient Funds
|
|
11175
|
-
assert(balance >= minimum_required, "Insufficient balance");
|
|
11176
|
-
|
|
11177
|
-
// Constraint 2: Compute Pedersen Commitment
|
|
11178
|
-
// Uses Noir's built-in pedersen_commitment which returns (x, y) point
|
|
11179
|
-
let commitment = pedersen_commitment([balance as Field, blinding]);
|
|
11180
|
-
|
|
11181
|
-
// Constraint 3: Verify Commitment Hash
|
|
11182
|
-
let computed_hash = pedersen_hash([commitment.x, commitment.y, asset_id]);
|
|
11183
|
-
assert(computed_hash == commitment_hash, "Commitment hash mismatch");
|
|
11184
|
-
}
|
|
11185
|
-
|
|
11186
|
-
// --- Tests ---
|
|
11187
|
-
|
|
11188
|
-
#[test]
|
|
11189
|
-
fn test_valid_funding_proof() {
|
|
11190
|
-
let balance: u64 = 100;
|
|
11191
|
-
let minimum_required: u64 = 50;
|
|
11192
|
-
let blinding: Field = 12345;
|
|
11193
|
-
let asset_id: Field = 0xABCD;
|
|
11194
|
-
|
|
11195
|
-
// Compute commitment using same method as circuit
|
|
11196
|
-
let commitment = pedersen_commitment([balance as Field, blinding]);
|
|
11197
|
-
let commitment_hash = pedersen_hash([commitment.x, commitment.y, asset_id]);
|
|
11198
|
-
|
|
11199
|
-
// This should pass
|
|
11200
|
-
main(commitment_hash, minimum_required, asset_id, balance, blinding);
|
|
11201
|
-
}
|
|
11202
|
-
|
|
11203
|
-
#[test(should_fail_with = "Insufficient balance")]
|
|
11204
|
-
fn test_insufficient_balance() {
|
|
11205
|
-
let balance: u64 = 50;
|
|
11206
|
-
let minimum_required: u64 = 100;
|
|
11207
|
-
let blinding: Field = 12345;
|
|
11208
|
-
let asset_id: Field = 0xABCD;
|
|
11209
|
-
|
|
11210
|
-
let commitment = pedersen_commitment([balance as Field, blinding]);
|
|
11211
|
-
let commitment_hash = pedersen_hash([commitment.x, commitment.y, asset_id]);
|
|
11212
|
-
|
|
11213
|
-
// This should fail - balance < minimum
|
|
11214
|
-
main(commitment_hash, minimum_required, asset_id, balance, blinding);
|
|
11215
|
-
}
|
|
11216
|
-
|
|
11217
|
-
#[test(should_fail_with = "Commitment hash mismatch")]
|
|
11218
|
-
fn test_wrong_commitment_hash() {
|
|
11219
|
-
let balance: u64 = 100;
|
|
11220
|
-
let minimum_required: u64 = 50;
|
|
11221
|
-
let blinding: Field = 12345;
|
|
11222
|
-
let asset_id: Field = 0xABCD;
|
|
11223
|
-
let wrong_hash: Field = 0xDEADBEEF;
|
|
11224
|
-
|
|
11225
|
-
// This should fail - wrong hash
|
|
11226
|
-
main(wrong_hash, minimum_required, asset_id, balance, blinding);
|
|
11227
|
-
}
|
|
11228
|
-
|
|
11229
|
-
#[test(should_fail_with = "Commitment hash mismatch")]
|
|
11230
|
-
fn test_wrong_blinding() {
|
|
11231
|
-
let balance: u64 = 100;
|
|
11232
|
-
let minimum_required: u64 = 50;
|
|
11233
|
-
let correct_blinding: Field = 12345;
|
|
11234
|
-
let wrong_blinding: Field = 54321;
|
|
11235
|
-
let asset_id: Field = 0xABCD;
|
|
11236
|
-
|
|
11237
|
-
// Compute hash with correct blinding
|
|
11238
|
-
let commitment = pedersen_commitment([balance as Field, correct_blinding]);
|
|
11239
|
-
let commitment_hash = pedersen_hash([commitment.x, commitment.y, asset_id]);
|
|
11240
|
-
|
|
11241
|
-
// Try to prove with wrong blinding - should fail
|
|
11242
|
-
main(commitment_hash, minimum_required, asset_id, balance, wrong_blinding);
|
|
11243
|
-
}
|
|
11244
|
-
`, path: "/Users/rz/local-dev/sip-protocol/packages/circuits/funding_proof/src/main.nr" } }, expression_width: { Bounded: { width: 4 } } };
|
|
12558
|
+
`, path: "std/field/bn254.nr" }, "18": { source: 'pub mod bn254;\nuse crate::{runtime::is_unconstrained, static_assert};\nuse bn254::lt as bn254_lt;\n\nimpl Field {\n /// Asserts that `self` can be represented in `bit_size` bits.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^{bit_size}`.\n // docs:start:assert_max_bit_size\n pub fn assert_max_bit_size<let BIT_SIZE: u32>(self) {\n // docs:end:assert_max_bit_size\n static_assert(\n BIT_SIZE < modulus_num_bits() as u32,\n "BIT_SIZE must be less than modulus_num_bits",\n );\n __assert_max_bit_size(self, BIT_SIZE);\n }\n\n /// Decomposes `self` into its little endian bit decomposition as a `[u1; N]` array.\n /// This slice will be zero padded should not all bits be necessary to represent `self`.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting slice will not\n /// be able to represent the original `Field`.\n ///\n /// # Safety\n /// The bit decomposition returned is canonical and is guaranteed to not overflow the modulus.\n // docs:start:to_le_bits\n pub fn to_le_bits<let N: u32>(self: Self) -> [u1; N] {\n // docs:end:to_le_bits\n let bits = __to_le_bits(self);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_le_bits();\n assert(bits.len() <= p.len());\n let mut ok = bits.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bits[N - 1 - i] != p[N - 1 - i]) {\n assert(p[N - 1 - i] == 1);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bits\n }\n\n /// Decomposes `self` into its big endian bit decomposition as a `[u1; N]` array.\n /// This array will be zero padded should not all bits be necessary to represent `self`.\n ///\n /// # Failures\n /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting slice will not\n /// be able to represent the original `Field`.\n ///\n /// # Safety\n /// The bit decomposition returned is canonical and is guaranteed to not overflow the modulus.\n // docs:start:to_be_bits\n pub fn to_be_bits<let N: u32>(self: Self) -> [u1; N] {\n // docs:end:to_be_bits\n let bits = __to_be_bits(self);\n\n if !is_unconstrained() {\n // Ensure that the decomposition does not overflow the modulus\n let p = modulus_be_bits();\n assert(bits.len() <= p.len());\n let mut ok = bits.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bits[i] != p[i]) {\n assert(p[i] == 1);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bits\n }\n\n /// Decomposes `self` into its little endian byte decomposition as a `[u8;N]` array\n /// This array will be zero padded should not all bytes be necessary to represent `self`.\n ///\n /// # Failures\n /// The length N of the array must be big enough to contain all the bytes of the \'self\',\n /// and no more than the number of bytes required to represent the field modulus\n ///\n /// # Safety\n /// The result is ensured to be the canonical decomposition of the field element\n // docs:start:to_le_bytes\n pub fn to_le_bytes<let N: u32>(self: Self) -> [u8; N] {\n // docs:end:to_le_bytes\n static_assert(\n N <= modulus_le_bytes().len(),\n "N must be less than or equal to modulus_le_bytes().len()",\n );\n // Compute the byte decomposition\n let bytes = self.to_le_radix(256);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_le_bytes();\n assert(bytes.len() <= p.len());\n let mut ok = bytes.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bytes[N - 1 - i] != p[N - 1 - i]) {\n assert(bytes[N - 1 - i] < p[N - 1 - i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bytes\n }\n\n /// Decomposes `self` into its big endian byte decomposition as a `[u8;N]` array of length required to represent the field modulus\n /// This array will be zero padded should not all bytes be necessary to represent `self`.\n ///\n /// # Failures\n /// The length N of the array must be big enough to contain all the bytes of the \'self\',\n /// and no more than the number of bytes required to represent the field modulus\n ///\n /// # Safety\n /// The result is ensured to be the canonical decomposition of the field element\n // docs:start:to_be_bytes\n pub fn to_be_bytes<let N: u32>(self: Self) -> [u8; N] {\n // docs:end:to_be_bytes\n static_assert(\n N <= modulus_le_bytes().len(),\n "N must be less than or equal to modulus_le_bytes().len()",\n );\n // Compute the byte decomposition\n let bytes = self.to_be_radix(256);\n\n if !is_unconstrained() {\n // Ensure that the byte decomposition does not overflow the modulus\n let p = modulus_be_bytes();\n assert(bytes.len() <= p.len());\n let mut ok = bytes.len() != p.len();\n for i in 0..N {\n if !ok {\n if (bytes[i] != p[i]) {\n assert(bytes[i] < p[i]);\n ok = true;\n }\n }\n }\n assert(ok);\n }\n bytes\n }\n\n fn to_le_radix<let N: u32>(self: Self, radix: u32) -> [u8; N] {\n // Brillig does not need an immediate radix\n if !crate::runtime::is_unconstrained() {\n static_assert(1 < radix, "radix must be greater than 1");\n static_assert(radix <= 256, "radix must be less than or equal to 256");\n static_assert(radix & (radix - 1) == 0, "radix must be a power of 2");\n }\n __to_le_radix(self, radix)\n }\n\n fn to_be_radix<let N: u32>(self: Self, radix: u32) -> [u8; N] {\n // Brillig does not need an immediate radix\n if !crate::runtime::is_unconstrained() {\n static_assert(1 < radix, "radix must be greater than 1");\n static_assert(radix <= 256, "radix must be less than or equal to 256");\n static_assert(radix & (radix - 1) == 0, "radix must be a power of 2");\n }\n __to_be_radix(self, radix)\n }\n\n // Returns self to the power of the given exponent value.\n // Caution: we assume the exponent fits into 32 bits\n // using a bigger bit size impacts negatively the performance and should be done only if the exponent does not fit in 32 bits\n pub fn pow_32(self, exponent: Field) -> Field {\n let mut r: Field = 1;\n let b: [u1; 32] = exponent.to_le_bits();\n\n for i in 1..33 {\n r *= r;\n r = (b[32 - i] as Field) * (r * self) + (1 - b[32 - i] as Field) * r;\n }\n r\n }\n\n // Parity of (prime) Field element, i.e. sgn0(x mod p) = 0 if x `elem` {0, ..., p-1} is even, otherwise sgn0(x mod p) = 1.\n pub fn sgn0(self) -> u1 {\n self as u1\n }\n\n pub fn lt(self, another: Field) -> bool {\n if crate::compat::is_bn254() {\n bn254_lt(self, another)\n } else {\n lt_fallback(self, another)\n }\n }\n\n /// Convert a little endian byte array to a field element.\n /// If the provided byte array overflows the field modulus then the Field will silently wrap around.\n pub fn from_le_bytes<let N: u32>(bytes: [u8; N]) -> Field {\n static_assert(\n N <= modulus_le_bytes().len(),\n "N must be less than or equal to modulus_le_bytes().len()",\n );\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bytes[i] as Field) * v;\n v = v * 256;\n }\n result\n }\n\n /// Convert a big endian byte array to a field element.\n /// If the provided byte array overflows the field modulus then the Field will silently wrap around.\n pub fn from_be_bytes<let N: u32>(bytes: [u8; N]) -> Field {\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bytes[N - 1 - i] as Field) * v;\n v = v * 256;\n }\n result\n }\n}\n\n#[builtin(apply_range_constraint)]\nfn __assert_max_bit_size(value: Field, bit_size: u32) {}\n\n// `_radix` must be less than 256\n#[builtin(to_le_radix)]\nfn __to_le_radix<let N: u32>(value: Field, radix: u32) -> [u8; N] {}\n\n// `_radix` must be less than 256\n#[builtin(to_be_radix)]\nfn __to_be_radix<let N: u32>(value: Field, radix: u32) -> [u8; N] {}\n\n/// Decomposes `self` into its little endian bit decomposition as a `[u1; N]` array.\n/// This slice will be zero padded should not all bits be necessary to represent `self`.\n///\n/// # Failures\n/// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting slice will not\n/// be able to represent the original `Field`.\n///\n/// # Safety\n/// Values of `N` equal to or greater than the number of bits necessary to represent the `Field` modulus\n/// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will\n/// wrap around due to overflow when verifying the decomposition.\n#[builtin(to_le_bits)]\nfn __to_le_bits<let N: u32>(value: Field) -> [u1; N] {}\n\n/// Decomposes `self` into its big endian bit decomposition as a `[u1; N]` array.\n/// This array will be zero padded should not all bits be necessary to represent `self`.\n///\n/// # Failures\n/// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting slice will not\n/// be able to represent the original `Field`.\n///\n/// # Safety\n/// Values of `N` equal to or greater than the number of bits necessary to represent the `Field` modulus\n/// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will\n/// wrap around due to overflow when verifying the decomposition.\n#[builtin(to_be_bits)]\nfn __to_be_bits<let N: u32>(value: Field) -> [u1; N] {}\n\n#[builtin(modulus_num_bits)]\npub comptime fn modulus_num_bits() -> u64 {}\n\n#[builtin(modulus_be_bits)]\npub comptime fn modulus_be_bits() -> [u1] {}\n\n#[builtin(modulus_le_bits)]\npub comptime fn modulus_le_bits() -> [u1] {}\n\n#[builtin(modulus_be_bytes)]\npub comptime fn modulus_be_bytes() -> [u8] {}\n\n#[builtin(modulus_le_bytes)]\npub comptime fn modulus_le_bytes() -> [u8] {}\n\n/// An unconstrained only built in to efficiently compare fields.\n#[builtin(field_less_than)]\nunconstrained fn __field_less_than(x: Field, y: Field) -> bool {}\n\npub(crate) unconstrained fn field_less_than(x: Field, y: Field) -> bool {\n __field_less_than(x, y)\n}\n\n// Convert a 32 byte array to a field element by modding\npub fn bytes32_to_field(bytes32: [u8; 32]) -> Field {\n // Convert it to a field element\n let mut v = 1;\n let mut high = 0 as Field;\n let mut low = 0 as Field;\n\n for i in 0..16 {\n high = high + (bytes32[15 - i] as Field) * v;\n low = low + (bytes32[16 + 15 - i] as Field) * v;\n v = v * 256;\n }\n // Abuse that a % p + b % p = (a + b) % p and that low < p\n low + high * v\n}\n\nfn lt_fallback(x: Field, y: Field) -> bool {\n if is_unconstrained() {\n // Safety: unconstrained context\n unsafe {\n field_less_than(x, y)\n }\n } else {\n let x_bytes: [u8; 32] = x.to_le_bytes();\n let y_bytes: [u8; 32] = y.to_le_bytes();\n let mut x_is_lt = false;\n let mut done = false;\n for i in 0..32 {\n if (!done) {\n let x_byte = x_bytes[32 - 1 - i] as u8;\n let y_byte = y_bytes[32 - 1 - i] as u8;\n let bytes_match = x_byte == y_byte;\n if !bytes_match {\n x_is_lt = x_byte < y_byte;\n done = true;\n }\n }\n }\n x_is_lt\n }\n}\n\nmod tests {\n use crate::{panic::panic, runtime, static_assert};\n use super::{\n field_less_than, modulus_be_bits, modulus_be_bytes, modulus_le_bits, modulus_le_bytes,\n };\n\n #[test]\n // docs:start:to_be_bits_example\n fn test_to_be_bits() {\n let field = 2;\n let bits: [u1; 8] = field.to_be_bits();\n assert_eq(bits, [0, 0, 0, 0, 0, 0, 1, 0]);\n }\n // docs:end:to_be_bits_example\n\n #[test]\n // docs:start:to_le_bits_example\n fn test_to_le_bits() {\n let field = 2;\n let bits: [u1; 8] = field.to_le_bits();\n assert_eq(bits, [0, 1, 0, 0, 0, 0, 0, 0]);\n }\n // docs:end:to_le_bits_example\n\n #[test]\n // docs:start:to_be_bytes_example\n fn test_to_be_bytes() {\n let field = 2;\n let bytes: [u8; 8] = field.to_be_bytes();\n assert_eq(bytes, [0, 0, 0, 0, 0, 0, 0, 2]);\n assert_eq(Field::from_be_bytes::<8>(bytes), field);\n }\n // docs:end:to_be_bytes_example\n\n #[test]\n // docs:start:to_le_bytes_example\n fn test_to_le_bytes() {\n let field = 2;\n let bytes: [u8; 8] = field.to_le_bytes();\n assert_eq(bytes, [2, 0, 0, 0, 0, 0, 0, 0]);\n assert_eq(Field::from_le_bytes::<8>(bytes), field);\n }\n // docs:end:to_le_bytes_example\n\n #[test]\n // docs:start:to_be_radix_example\n fn test_to_be_radix() {\n // 259, in base 256, big endian, is [1, 3].\n // i.e. 3 * 256^0 + 1 * 256^1\n let field = 259;\n\n // The radix (in this example, 256) must be a power of 2.\n // The length of the returned byte array can be specified to be\n // >= the amount of space needed.\n let bytes: [u8; 8] = field.to_be_radix(256);\n assert_eq(bytes, [0, 0, 0, 0, 0, 0, 1, 3]);\n assert_eq(Field::from_be_bytes::<8>(bytes), field);\n }\n // docs:end:to_be_radix_example\n\n #[test]\n // docs:start:to_le_radix_example\n fn test_to_le_radix() {\n // 259, in base 256, little endian, is [3, 1].\n // i.e. 3 * 256^0 + 1 * 256^1\n let field = 259;\n\n // The radix (in this example, 256) must be a power of 2.\n // The length of the returned byte array can be specified to be\n // >= the amount of space needed.\n let bytes: [u8; 8] = field.to_le_radix(256);\n assert_eq(bytes, [3, 1, 0, 0, 0, 0, 0, 0]);\n assert_eq(Field::from_le_bytes::<8>(bytes), field);\n }\n // docs:end:to_le_radix_example\n\n #[test(should_fail_with = "radix must be greater than 1")]\n fn test_to_le_radix_1() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(1);\n } else {\n panic(f"radix must be greater than 1");\n }\n }\n\n // Updated test to account for Brillig restriction that radix must be greater than 2\n #[test(should_fail_with = "radix must be greater than 1")]\n fn test_to_le_radix_brillig_1() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 1;\n let _: [u8; 8] = field.to_le_radix(1);\n } else {\n panic(f"radix must be greater than 1");\n }\n }\n\n #[test(should_fail_with = "radix must be a power of 2")]\n fn test_to_le_radix_3() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(3);\n } else {\n panic(f"radix must be a power of 2");\n }\n }\n\n #[test]\n fn test_to_le_radix_brillig_3() {\n // this test should only fail in constrained mode\n if runtime::is_unconstrained() {\n let field = 1;\n let out: [u8; 8] = field.to_le_radix(3);\n let mut expected = [0; 8];\n expected[0] = 1;\n assert(out == expected, "unexpected result");\n }\n }\n\n #[test(should_fail_with = "radix must be less than or equal to 256")]\n fn test_to_le_radix_512() {\n // this test should only fail in constrained mode\n if !runtime::is_unconstrained() {\n let field = 2;\n let _: [u8; 8] = field.to_le_radix(512);\n } else {\n panic(f"radix must be less than or equal to 256")\n }\n }\n\n #[test(should_fail_with = "Field failed to decompose into specified 16 limbs")]\n unconstrained fn not_enough_limbs_brillig() {\n let _: [u8; 16] = 0x100000000000000000000000000000000.to_le_bytes();\n }\n\n #[test(should_fail_with = "Field failed to decompose into specified 16 limbs")]\n fn not_enough_limbs() {\n let _: [u8; 16] = 0x100000000000000000000000000000000.to_le_bytes();\n }\n\n #[test]\n unconstrained fn test_field_less_than() {\n assert(field_less_than(0, 1));\n assert(field_less_than(0, 0x100));\n assert(field_less_than(0x100, 0 - 1));\n assert(!field_less_than(0 - 1, 0));\n }\n\n #[test]\n unconstrained fn test_large_field_values_unconstrained() {\n let large_field = 0xffffffffffffffff;\n\n let bits: [u1; 64] = large_field.to_le_bits();\n assert_eq(bits[0], 1);\n\n let bytes: [u8; 8] = large_field.to_le_bytes();\n assert_eq(Field::from_le_bytes::<8>(bytes), large_field);\n\n let radix_bytes: [u8; 8] = large_field.to_le_radix(256);\n assert_eq(Field::from_le_bytes::<8>(radix_bytes), large_field);\n }\n\n #[test]\n fn test_large_field_values() {\n let large_val = 0xffffffffffffffff;\n\n let bits: [u1; 64] = large_val.to_le_bits();\n assert_eq(bits[0], 1);\n\n let bytes: [u8; 8] = large_val.to_le_bytes();\n assert_eq(Field::from_le_bytes::<8>(bytes), large_val);\n\n let radix_bytes: [u8; 8] = large_val.to_le_radix(256);\n assert_eq(Field::from_le_bytes::<8>(radix_bytes), large_val);\n }\n\n #[test]\n fn test_decomposition_edge_cases() {\n let zero_bits: [u1; 8] = 0.to_le_bits();\n assert_eq(zero_bits, [0; 8]);\n\n let zero_bytes: [u8; 8] = 0.to_le_bytes();\n assert_eq(zero_bytes, [0; 8]);\n\n let one_bits: [u1; 8] = 1.to_le_bits();\n let expected: [u1; 8] = [1, 0, 0, 0, 0, 0, 0, 0];\n assert_eq(one_bits, expected);\n\n let pow2_bits: [u1; 8] = 4.to_le_bits();\n let expected: [u1; 8] = [0, 0, 1, 0, 0, 0, 0, 0];\n assert_eq(pow2_bits, expected);\n }\n\n #[test]\n fn test_pow_32() {\n assert_eq(2.pow_32(3), 8);\n assert_eq(3.pow_32(2), 9);\n assert_eq(5.pow_32(0), 1);\n assert_eq(7.pow_32(1), 7);\n\n assert_eq(2.pow_32(10), 1024);\n\n assert_eq(0.pow_32(5), 0);\n assert_eq(0.pow_32(0), 1);\n\n assert_eq(1.pow_32(100), 1);\n }\n\n #[test]\n fn test_sgn0() {\n assert_eq(0.sgn0(), 0);\n assert_eq(2.sgn0(), 0);\n assert_eq(4.sgn0(), 0);\n assert_eq(100.sgn0(), 0);\n\n assert_eq(1.sgn0(), 1);\n assert_eq(3.sgn0(), 1);\n assert_eq(5.sgn0(), 1);\n assert_eq(101.sgn0(), 1);\n }\n\n #[test(should_fail_with = "Field failed to decompose into specified 8 limbs")]\n fn test_bit_decomposition_overflow() {\n // 8 bits can\'t represent large field values\n let large_val = 0x1000000000000000;\n let _: [u1; 8] = large_val.to_le_bits();\n }\n\n #[test(should_fail_with = "Field failed to decompose into specified 4 limbs")]\n fn test_byte_decomposition_overflow() {\n // 4 bytes can\'t represent large field values\n let large_val = 0x1000000000000000;\n let _: [u8; 4] = large_val.to_le_bytes();\n }\n\n #[test]\n fn test_to_from_be_bytes_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this byte produces the expected 32 BE bytes for (modulus - 1)\n let mut p_minus_1_bytes: [u8; 32] = modulus_be_bytes().as_array();\n assert(p_minus_1_bytes[32 - 1] > 0);\n p_minus_1_bytes[32 - 1] -= 1;\n\n let p_minus_1 = Field::from_be_bytes::<32>(p_minus_1_bytes);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 32 BE bytes produces the same bytes\n let p_minus_1_converted_bytes: [u8; 32] = p_minus_1.to_be_bytes();\n assert_eq(p_minus_1_converted_bytes, p_minus_1_bytes);\n\n // checking that incrementing this byte produces 32 BE bytes for (modulus + 1)\n let mut p_plus_1_bytes: [u8; 32] = modulus_be_bytes().as_array();\n assert(p_plus_1_bytes[32 - 1] < 255);\n p_plus_1_bytes[32 - 1] += 1;\n\n let p_plus_1 = Field::from_be_bytes::<32>(p_plus_1_bytes);\n assert_eq(p_plus_1, 1);\n\n // checking that converting p_plus_1 to 32 BE bytes produces the same\n // byte set to 1 as p_plus_1_bytes and otherwise zeroes\n let mut p_plus_1_converted_bytes: [u8; 32] = p_plus_1.to_be_bytes();\n assert_eq(p_plus_1_converted_bytes[32 - 1], 1);\n p_plus_1_converted_bytes[32 - 1] = 0;\n assert_eq(p_plus_1_converted_bytes, [0; 32]);\n\n // checking that Field::from_be_bytes::<32> on the Field modulus produces 0\n assert_eq(modulus_be_bytes().len(), 32);\n let p = Field::from_be_bytes::<32>(modulus_be_bytes().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 32 BE bytes produces 32 zeroes\n let p_bytes: [u8; 32] = 0.to_be_bytes();\n assert_eq(p_bytes, [0; 32]);\n }\n }\n\n #[test]\n fn test_to_from_le_bytes_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this byte produces the expected 32 LE bytes for (modulus - 1)\n let mut p_minus_1_bytes: [u8; 32] = modulus_le_bytes().as_array();\n assert(p_minus_1_bytes[0] > 0);\n p_minus_1_bytes[0] -= 1;\n\n let p_minus_1 = Field::from_le_bytes::<32>(p_minus_1_bytes);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 32 BE bytes produces the same bytes\n let p_minus_1_converted_bytes: [u8; 32] = p_minus_1.to_le_bytes();\n assert_eq(p_minus_1_converted_bytes, p_minus_1_bytes);\n\n // checking that incrementing this byte produces 32 LE bytes for (modulus + 1)\n let mut p_plus_1_bytes: [u8; 32] = modulus_le_bytes().as_array();\n assert(p_plus_1_bytes[0] < 255);\n p_plus_1_bytes[0] += 1;\n\n let p_plus_1 = Field::from_le_bytes::<32>(p_plus_1_bytes);\n assert_eq(p_plus_1, 1);\n\n // checking that converting p_plus_1 to 32 LE bytes produces the same\n // byte set to 1 as p_plus_1_bytes and otherwise zeroes\n let mut p_plus_1_converted_bytes: [u8; 32] = p_plus_1.to_le_bytes();\n assert_eq(p_plus_1_converted_bytes[0], 1);\n p_plus_1_converted_bytes[0] = 0;\n assert_eq(p_plus_1_converted_bytes, [0; 32]);\n\n // checking that Field::from_le_bytes::<32> on the Field modulus produces 0\n assert_eq(modulus_le_bytes().len(), 32);\n let p = Field::from_le_bytes::<32>(modulus_le_bytes().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 32 LE bytes produces 32 zeroes\n let p_bytes: [u8; 32] = 0.to_le_bytes();\n assert_eq(p_bytes, [0; 32]);\n }\n }\n\n /// Convert a little endian bit array to a field element.\n /// If the provided bit array overflows the field modulus then the Field will silently wrap around.\n fn from_le_bits<let N: u32>(bits: [u1; N]) -> Field {\n static_assert(\n N <= modulus_le_bits().len(),\n "N must be less than or equal to modulus_le_bits().len()",\n );\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bits[i] as Field) * v;\n v = v * 2;\n }\n result\n }\n\n /// Convert a big endian bit array to a field element.\n /// If the provided bit array overflows the field modulus then the Field will silently wrap around.\n fn from_be_bits<let N: u32>(bits: [u1; N]) -> Field {\n let mut v = 1;\n let mut result = 0;\n\n for i in 0..N {\n result += (bits[N - 1 - i] as Field) * v;\n v = v * 2;\n }\n result\n }\n\n #[test]\n fn test_to_from_be_bits_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this bit produces the expected 254 BE bits for (modulus - 1)\n let mut p_minus_1_bits: [u1; 254] = modulus_be_bits().as_array();\n assert(p_minus_1_bits[254 - 1] > 0);\n p_minus_1_bits[254 - 1] -= 1;\n\n let p_minus_1 = from_be_bits::<254>(p_minus_1_bits);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 254 BE bits produces the same bits\n let p_minus_1_converted_bits: [u1; 254] = p_minus_1.to_be_bits();\n assert_eq(p_minus_1_converted_bits, p_minus_1_bits);\n\n // checking that incrementing this bit produces 254 BE bits for (modulus + 4)\n let mut p_plus_4_bits: [u1; 254] = modulus_be_bits().as_array();\n assert(p_plus_4_bits[254 - 3] < 1);\n p_plus_4_bits[254 - 3] += 1;\n\n let p_plus_4 = from_be_bits::<254>(p_plus_4_bits);\n assert_eq(p_plus_4, 4);\n\n // checking that converting p_plus_4 to 254 BE bits produces the same\n // bit set to 1 as p_plus_4_bits and otherwise zeroes\n let mut p_plus_4_converted_bits: [u1; 254] = p_plus_4.to_be_bits();\n assert_eq(p_plus_4_converted_bits[254 - 3], 1);\n p_plus_4_converted_bits[254 - 3] = 0;\n assert_eq(p_plus_4_converted_bits, [0; 254]);\n\n // checking that Field::from_be_bits::<254> on the Field modulus produces 0\n assert_eq(modulus_be_bits().len(), 254);\n let p = from_be_bits::<254>(modulus_be_bits().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 254 BE bytes produces 254 zeroes\n let p_bits: [u1; 254] = 0.to_be_bits();\n assert_eq(p_bits, [0; 254]);\n }\n }\n\n #[test]\n fn test_to_from_le_bits_bn254_edge_cases() {\n if crate::compat::is_bn254() {\n // checking that decrementing this bit produces the expected 254 LE bits for (modulus - 1)\n let mut p_minus_1_bits: [u1; 254] = modulus_le_bits().as_array();\n assert(p_minus_1_bits[0] > 0);\n p_minus_1_bits[0] -= 1;\n\n let p_minus_1 = from_le_bits::<254>(p_minus_1_bits);\n assert_eq(p_minus_1 + 1, 0);\n\n // checking that converting (modulus - 1) from and then to 254 BE bits produces the same bits\n let p_minus_1_converted_bits: [u1; 254] = p_minus_1.to_le_bits();\n assert_eq(p_minus_1_converted_bits, p_minus_1_bits);\n\n // checking that incrementing this bit produces 254 LE bits for (modulus + 4)\n let mut p_plus_4_bits: [u1; 254] = modulus_le_bits().as_array();\n assert(p_plus_4_bits[2] < 1);\n p_plus_4_bits[2] += 1;\n\n let p_plus_4 = from_le_bits::<254>(p_plus_4_bits);\n assert_eq(p_plus_4, 4);\n\n // checking that converting p_plus_4 to 254 LE bits produces the same\n // bit set to 1 as p_plus_4_bits and otherwise zeroes\n let mut p_plus_4_converted_bits: [u1; 254] = p_plus_4.to_le_bits();\n assert_eq(p_plus_4_converted_bits[2], 1);\n p_plus_4_converted_bits[2] = 0;\n assert_eq(p_plus_4_converted_bits, [0; 254]);\n\n // checking that Field::from_le_bits::<254> on the Field modulus produces 0\n assert_eq(modulus_le_bits().len(), 254);\n let p = from_le_bits::<254>(modulus_le_bits().as_array());\n assert_eq(p, 0);\n\n // checking that converting 0 to 254 LE bytes produces 254 zeroes\n let p_bits: [u1; 254] = 0.to_le_bits();\n assert_eq(p_bits, [0; 254]);\n }\n }\n}\n', path: "std/field/mod.nr" }, "19": { source: '// Exposed only for usage in `std::meta`\npub(crate) mod poseidon2;\n\nuse crate::default::Default;\nuse crate::embedded_curve_ops::{\n EmbeddedCurvePoint, EmbeddedCurveScalar, multi_scalar_mul, multi_scalar_mul_array_return,\n};\nuse crate::meta::derive_via;\n\n#[foreign(sha256_compression)]\n// docs:start:sha256_compression\npub fn sha256_compression(input: [u32; 16], state: [u32; 8]) -> [u32; 8] {}\n// docs:end:sha256_compression\n\n#[foreign(keccakf1600)]\n// docs:start:keccakf1600\npub fn keccakf1600(input: [u64; 25]) -> [u64; 25] {}\n// docs:end:keccakf1600\n\npub mod keccak {\n #[deprecated("This function has been moved to std::hash::keccakf1600")]\n pub fn keccakf1600(input: [u64; 25]) -> [u64; 25] {\n super::keccakf1600(input)\n }\n}\n\n#[foreign(blake2s)]\n// docs:start:blake2s\npub fn blake2s<let N: u32>(input: [u8; N]) -> [u8; 32]\n// docs:end:blake2s\n{}\n\n// docs:start:blake3\npub fn blake3<let N: u32>(input: [u8; N]) -> [u8; 32]\n// docs:end:blake3\n{\n if crate::runtime::is_unconstrained() {\n // Temporary measure while Barretenberg is main proving system.\n // Please open an issue if you\'re working on another proving system and running into problems due to this.\n crate::static_assert(\n N <= 1024,\n "Barretenberg cannot prove blake3 hashes with inputs larger than 1024 bytes",\n );\n }\n __blake3(input)\n}\n\n#[foreign(blake3)]\nfn __blake3<let N: u32>(input: [u8; N]) -> [u8; 32] {}\n\n// docs:start:pedersen_commitment\npub fn pedersen_commitment<let N: u32>(input: [Field; N]) -> EmbeddedCurvePoint {\n // docs:end:pedersen_commitment\n pedersen_commitment_with_separator(input, 0)\n}\n\n#[inline_always]\npub fn pedersen_commitment_with_separator<let N: u32>(\n input: [Field; N],\n separator: u32,\n) -> EmbeddedCurvePoint {\n let mut points = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N];\n for i in 0..N {\n // we use the unsafe version because the multi_scalar_mul will constrain the scalars.\n points[i] = from_field_unsafe(input[i]);\n }\n let generators = derive_generators("DEFAULT_DOMAIN_SEPARATOR".as_bytes(), separator);\n multi_scalar_mul(generators, points)\n}\n\n// docs:start:pedersen_hash\npub fn pedersen_hash<let N: u32>(input: [Field; N]) -> Field\n// docs:end:pedersen_hash\n{\n pedersen_hash_with_separator(input, 0)\n}\n\n#[no_predicates]\npub fn pedersen_hash_with_separator<let N: u32>(input: [Field; N], separator: u32) -> Field {\n let mut scalars: [EmbeddedCurveScalar; N + 1] = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N + 1];\n let mut generators: [EmbeddedCurvePoint; N + 1] =\n [EmbeddedCurvePoint::point_at_infinity(); N + 1];\n let domain_generators: [EmbeddedCurvePoint; N] =\n derive_generators("DEFAULT_DOMAIN_SEPARATOR".as_bytes(), separator);\n\n for i in 0..N {\n scalars[i] = from_field_unsafe(input[i]);\n generators[i] = domain_generators[i];\n }\n scalars[N] = EmbeddedCurveScalar { lo: N as Field, hi: 0 as Field };\n\n let length_generator: [EmbeddedCurvePoint; 1] =\n derive_generators("pedersen_hash_length".as_bytes(), 0);\n generators[N] = length_generator[0];\n multi_scalar_mul_array_return(generators, scalars, true)[0].x\n}\n\n#[field(bn254)]\n#[inline_always]\npub fn derive_generators<let N: u32, let M: u32>(\n domain_separator_bytes: [u8; M],\n starting_index: u32,\n) -> [EmbeddedCurvePoint; N] {\n crate::assert_constant(domain_separator_bytes);\n // TODO(https://github.com/noir-lang/noir/issues/5672): Add back assert_constant on starting_index\n __derive_generators(domain_separator_bytes, starting_index)\n}\n\n#[builtin(derive_pedersen_generators)]\n#[field(bn254)]\nfn __derive_generators<let N: u32, let M: u32>(\n domain_separator_bytes: [u8; M],\n starting_index: u32,\n) -> [EmbeddedCurvePoint; N] {}\n\n#[field(bn254)]\n// Same as from_field but:\n// does not assert the limbs are 128 bits\n// does not assert the decomposition does not overflow the EmbeddedCurveScalar\nfn from_field_unsafe(scalar: Field) -> EmbeddedCurveScalar {\n // Safety: xlo and xhi decomposition is checked below\n let (xlo, xhi) = unsafe { crate::field::bn254::decompose_hint(scalar) };\n // Check that the decomposition is correct\n assert_eq(scalar, xlo + crate::field::bn254::TWO_POW_128 * xhi);\n EmbeddedCurveScalar { lo: xlo, hi: xhi }\n}\n\npub fn poseidon2_permutation<let N: u32>(input: [Field; N], state_len: u32) -> [Field; N] {\n assert_eq(input.len(), state_len);\n poseidon2_permutation_internal(input)\n}\n\n#[foreign(poseidon2_permutation)]\nfn poseidon2_permutation_internal<let N: u32>(input: [Field; N]) -> [Field; N] {}\n\n// Generic hashing support.\n// Partially ported and impacted by rust.\n\n// Hash trait shall be implemented per type.\n#[derive_via(derive_hash)]\npub trait Hash {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher;\n}\n\n// docs:start:derive_hash\ncomptime fn derive_hash(s: TypeDefinition) -> Quoted {\n let name = quote { $crate::hash::Hash };\n let signature = quote { fn hash<H>(_self: Self, _state: &mut H) where H: $crate::hash::Hasher };\n let for_each_field = |name| quote { _self.$name.hash(_state); };\n crate::meta::make_trait_impl(\n s,\n name,\n signature,\n for_each_field,\n quote {},\n |fields| fields,\n )\n}\n// docs:end:derive_hash\n\n// Hasher trait shall be implemented by algorithms to provide hash-agnostic means.\n// TODO: consider making the types generic here ([u8], [Field], etc.)\npub trait Hasher {\n fn finish(self) -> Field;\n\n fn write(&mut self, input: Field);\n}\n\n// BuildHasher is a factory trait, responsible for production of specific Hasher.\npub trait BuildHasher {\n type H: Hasher;\n\n fn build_hasher(self) -> H;\n}\n\npub struct BuildHasherDefault<H>;\n\nimpl<H> BuildHasher for BuildHasherDefault<H>\nwhere\n H: Hasher + Default,\n{\n type H = H;\n\n fn build_hasher(_self: Self) -> H {\n H::default()\n }\n}\n\nimpl<H> Default for BuildHasherDefault<H>\nwhere\n H: Hasher + Default,\n{\n fn default() -> Self {\n BuildHasherDefault {}\n }\n}\n\nimpl Hash for Field {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self);\n }\n}\n\nimpl Hash for u1 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u8 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u16 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u32 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u64 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for u128 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for i8 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u8 as Field);\n }\n}\n\nimpl Hash for i16 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u16 as Field);\n }\n}\n\nimpl Hash for i32 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u32 as Field);\n }\n}\n\nimpl Hash for i64 {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as u64 as Field);\n }\n}\n\nimpl Hash for bool {\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n H::write(state, self as Field);\n }\n}\n\nimpl Hash for () {\n fn hash<H>(_self: Self, _state: &mut H)\n where\n H: Hasher,\n {}\n}\n\nimpl<T, let N: u32> Hash for [T; N]\nwhere\n T: Hash,\n{\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n for elem in self {\n elem.hash(state);\n }\n }\n}\n\nimpl<T> Hash for [T]\nwhere\n T: Hash,\n{\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n self.len().hash(state);\n for elem in self {\n elem.hash(state);\n }\n }\n}\n\nimpl<A, B> Hash for (A, B)\nwhere\n A: Hash,\n B: Hash,\n{\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n }\n}\n\nimpl<A, B, C> Hash for (A, B, C)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n{\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n }\n}\n\nimpl<A, B, C, D> Hash for (A, B, C, D)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n D: Hash,\n{\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n self.3.hash(state);\n }\n}\n\nimpl<A, B, C, D, E> Hash for (A, B, C, D, E)\nwhere\n A: Hash,\n B: Hash,\n C: Hash,\n D: Hash,\n E: Hash,\n{\n fn hash<H>(self, state: &mut H)\n where\n H: Hasher,\n {\n self.0.hash(state);\n self.1.hash(state);\n self.2.hash(state);\n self.3.hash(state);\n self.4.hash(state);\n }\n}\n\n// Some test vectors for Pedersen hash and Pedersen Commitment.\n// They have been generated using the same functions so the tests are for now useless\n// but they will be useful when we switch to Noir implementation.\n#[test]\nfn assert_pedersen() {\n assert_eq(\n pedersen_hash_with_separator([1], 1),\n 0x1b3f4b1a83092a13d8d1a59f7acb62aba15e7002f4440f2275edb99ebbc2305f,\n );\n assert_eq(\n pedersen_commitment_with_separator([1], 1),\n EmbeddedCurvePoint {\n x: 0x054aa86a73cb8a34525e5bbed6e43ba1198e860f5f3950268f71df4591bde402,\n y: 0x209dcfbf2cfb57f9f6046f44d71ac6faf87254afc7407c04eb621a6287cac126,\n is_infinite: false,\n },\n );\n\n assert_eq(\n pedersen_hash_with_separator([1, 2], 2),\n 0x26691c129448e9ace0c66d11f0a16d9014a9e8498ee78f4d69f0083168188255,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2], 2),\n EmbeddedCurvePoint {\n x: 0x2e2b3b191e49541fe468ec6877721d445dcaffe41728df0a0eafeb15e87b0753,\n y: 0x2ff4482400ad3a6228be17a2af33e2bcdf41be04795f9782bd96efe7e24f8778,\n is_infinite: false,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3], 3),\n 0x0bc694b7a1f8d10d2d8987d07433f26bd616a2d351bc79a3c540d85b6206dbe4,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3], 3),\n EmbeddedCurvePoint {\n x: 0x1fee4e8cf8d2f527caa2684236b07c4b1bad7342c01b0f75e9a877a71827dc85,\n y: 0x2f9fedb9a090697ab69bf04c8bc15f7385b3e4b68c849c1536e5ae15ff138fd1,\n is_infinite: false,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4], 4),\n 0xdae10fb32a8408521803905981a2b300d6a35e40e798743e9322b223a5eddc,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4], 4),\n EmbeddedCurvePoint {\n x: 0x07ae3e202811e1fca39c2d81eabe6f79183978e6f12be0d3b8eda095b79bdbc9,\n y: 0x0afc6f892593db6fbba60f2da558517e279e0ae04f95758587760ba193145014,\n is_infinite: false,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5], 5),\n 0xfc375b062c4f4f0150f7100dfb8d9b72a6d28582dd9512390b0497cdad9c22,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5], 5),\n EmbeddedCurvePoint {\n x: 0x1754b12bd475a6984a1094b5109eeca9838f4f81ac89c5f0a41dbce53189bb29,\n y: 0x2da030e3cfcdc7ddad80eaf2599df6692cae0717d4e9f7bfbee8d073d5d278f7,\n is_infinite: false,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6], 6),\n 0x1696ed13dc2730062a98ac9d8f9de0661bb98829c7582f699d0273b18c86a572,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6], 6),\n EmbeddedCurvePoint {\n x: 0x190f6c0e97ad83e1e28da22a98aae156da083c5a4100e929b77e750d3106a697,\n y: 0x1f4b60f34ef91221a0b49756fa0705da93311a61af73d37a0c458877706616fb,\n is_infinite: false,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\n 0x128c0ff144fc66b6cb60eeac8a38e23da52992fc427b92397a7dffd71c45ede3,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7], 7),\n EmbeddedCurvePoint {\n x: 0x015441e9d29491b06563fac16fc76abf7a9534c715421d0de85d20dbe2965939,\n y: 0x1d2575b0276f4e9087e6e07c2cb75aa1baafad127af4be5918ef8a2ef2fea8fc,\n is_infinite: false,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\n 0x2f960e117482044dfc99d12fece2ef6862fba9242be4846c7c9a3e854325a55c,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8], 8),\n EmbeddedCurvePoint {\n x: 0x1657737676968887fceb6dd516382ea13b3a2c557f509811cd86d5d1199bc443,\n y: 0x1f39f0cb569040105fa1e2f156521e8b8e08261e635a2b210bdc94e8d6d65f77,\n is_infinite: false,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\n 0x0c96db0790602dcb166cc4699e2d306c479a76926b81c2cb2aaa92d249ec7be7,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9], 9),\n EmbeddedCurvePoint {\n x: 0x0a3ceae42d14914a432aa60ec7fded4af7dad7dd4acdbf2908452675ec67e06d,\n y: 0xfc19761eaaf621ad4aec9a8b2e84a4eceffdba78f60f8b9391b0bd9345a2f2,\n is_infinite: false,\n },\n );\n assert_eq(\n pedersen_hash_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\n 0x2cd37505871bc460a62ea1e63c7fe51149df5d0801302cf1cbc48beb8dff7e94,\n );\n assert_eq(\n pedersen_commitment_with_separator([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10),\n EmbeddedCurvePoint {\n x: 0x2fb3f8b3d41ddde007c8c3c62550f9a9380ee546fcc639ffbb3fd30c8d8de30c,\n y: 0x300783be23c446b11a4c0fabf6c91af148937cea15fcf5fb054abf7f752ee245,\n is_infinite: false,\n },\n );\n}\n', path: "std/hash/mod.nr" }, "50": { source: '/// Funding Proof Circuit\n///\n/// Proves that a user has sufficient balance to cover a transaction\n/// without revealing the actual balance.\n///\n/// Public inputs:\n/// - commitment_hash: Hash of the Pedersen commitment to balance\n/// - minimum_required: Minimum balance required\n/// - asset_id: Asset identifier\n///\n/// Private inputs (witness):\n/// - balance: Actual user balance\n/// - blinding: Blinding factor for commitment\n///\n/// Constraints:\n/// 1. balance >= minimum_required\n/// 2. commitment = pedersen([balance, blinding])\n/// 3. commitment_hash = hash(commitment, asset_id)\n\nuse std::hash::pedersen_hash;\nuse std::hash::blake3;\n\n/// Main entry point for the funding proof circuit\n///\n/// Returns the commitment hash as a public output rather than taking it as input.\n/// This allows the SDK to verify the proof without needing to compute Pedersen hashes.\nfn main(\n // Public inputs\n minimum_required: pub u64,\n asset_id: pub Field,\n\n // Private inputs (witness)\n balance: u64,\n blinding: Field,\n) -> pub [u8; 32] {\n // Constraint 1: Balance must be at least the minimum required\n assert(balance >= minimum_required, "Insufficient balance");\n\n // Constraint 2: Compute the Pedersen commitment to (balance, blinding)\n let balance_field = balance as Field;\n let commitment = pedersen_hash([balance_field, blinding]);\n\n // Constraint 3: Compute and return the commitment hash\n // We hash: commitment || asset_id to bind the commitment to the asset\n let commitment_hash = compute_commitment_hash(commitment, asset_id);\n\n commitment_hash\n}\n\n/// Compute the commitment hash from commitment and asset_id\n/// Uses BLAKE3 for efficiency (built-in to Noir)\nfn compute_commitment_hash(commitment: Field, asset_id: Field) -> [u8; 32] {\n // Convert commitment to bytes (32 bytes, big-endian)\n let commitment_bytes: [u8; 32] = commitment.to_be_bytes();\n\n // Convert asset_id to bytes (32 bytes, big-endian)\n let asset_bytes: [u8; 32] = asset_id.to_be_bytes();\n\n // Create preimage: commitment || asset_id (64 bytes)\n let mut preimage: [u8; 64] = [0; 64];\n for i in 0..32 {\n preimage[i] = commitment_bytes[i];\n preimage[i + 32] = asset_bytes[i];\n }\n\n // Hash with BLAKE3\n blake3(preimage)\n}\n\n// --- Tests ---\n\n#[test]\nfn test_valid_funding_proof() {\n // Test case: balance = 100, minimum = 50\n let balance: u64 = 100;\n let minimum_required: u64 = 50;\n let blinding = 12345 as Field;\n let asset_id = 1 as Field;\n\n // Execute the circuit - it should return the commitment hash\n let commitment_hash = main(minimum_required, asset_id, balance, blinding);\n\n // Verify it returned a hash (not all zeros)\n let mut has_nonzero = false;\n for i in 0..32 {\n if commitment_hash[i] != 0 {\n has_nonzero = true;\n }\n }\n assert(has_nonzero, "Commitment hash should not be all zeros");\n}\n\n#[test]\nfn test_exact_balance_passes() {\n // Test case: balance exactly equals minimum\n let balance: u64 = 50;\n let minimum_required: u64 = 50;\n let blinding = 67890 as Field;\n let asset_id = 2 as Field;\n\n // Should succeed and return a hash\n let _commitment_hash = main(minimum_required, asset_id, balance, blinding);\n}\n\n#[test(should_fail_with = "Insufficient balance")]\nfn test_insufficient_balance_fails() {\n // Test case: balance < minimum should fail\n let balance: u64 = 40;\n let minimum_required: u64 = 50;\n let blinding = 11111 as Field;\n let asset_id = 1 as Field;\n\n // Should fail because balance < minimum_required\n let _commitment_hash = main(minimum_required, asset_id, balance, blinding);\n}\n\n#[test]\nfn test_different_blinding_produces_different_hash() {\n // Test that different blinding factors produce different commitment hashes\n let balance: u64 = 100;\n let minimum_required: u64 = 50;\n let blinding1 = 12345 as Field;\n let blinding2 = 99999 as Field;\n let asset_id = 1 as Field;\n\n let hash1 = main(minimum_required, asset_id, balance, blinding1);\n let hash2 = main(minimum_required, asset_id, balance, blinding2);\n\n // Hashes should be different\n let mut hashes_differ = false;\n for i in 0..32 {\n if hash1[i] != hash2[i] {\n hashes_differ = true;\n }\n }\n assert(hashes_differ, "Different blindings should produce different hashes");\n}\n', path: "/Users/rz/local-dev/circuits/funding_proof/src/main.nr" } }, expression_width: { Bounded: { width: 4 } } };
|
|
11245
12559
|
|
|
11246
12560
|
// src/proofs/circuits/validity_proof.json
|
|
11247
12561
|
var validity_proof_default = { noir_version: "1.0.0-beta.15+83245db91dcf63420ef4bcbbd85b98f397fee663", hash: "17105369051450454041", abi: { parameters: [{ name: "intent_hash", type: { kind: "field" }, visibility: "public" }, { name: "sender_commitment_x", type: { kind: "field" }, visibility: "public" }, { name: "sender_commitment_y", type: { kind: "field" }, visibility: "public" }, { name: "nullifier", type: { kind: "field" }, visibility: "public" }, { name: "timestamp", type: { kind: "integer", sign: "unsigned", width: 64 }, visibility: "public" }, { name: "expiry", type: { kind: "integer", sign: "unsigned", width: 64 }, visibility: "public" }, { name: "sender_address", type: { kind: "field" }, visibility: "private" }, { name: "sender_blinding", type: { kind: "field" }, visibility: "private" }, { name: "sender_secret", type: { kind: "field" }, visibility: "private" }, { name: "pub_key_x", type: { kind: "array", length: 32, type: { kind: "integer", sign: "unsigned", width: 8 } }, visibility: "private" }, { name: "pub_key_y", type: { kind: "array", length: 32, type: { kind: "integer", sign: "unsigned", width: 8 } }, visibility: "private" }, { name: "signature", type: { kind: "array", length: 64, type: { kind: "integer", sign: "unsigned", width: 8 } }, visibility: "private" }, { name: "message_hash", type: { kind: "array", length: 32, type: { kind: "integer", sign: "unsigned", width: 8 } }, visibility: "private" }, { name: "nonce", type: { kind: "field" }, visibility: "private" }], return_type: null, error_types: { "4743545721632785176": { error_kind: "string", string: "Nullifier mismatch" }, "4924752953922582949": { error_kind: "string", string: "Invalid ECDSA signature" }, "5940733937471987676": { error_kind: "string", string: "Intent expired" }, "9872184990886929843": { error_kind: "string", string: "Sender commitment X mismatch" }, "14620555433709191364": { error_kind: "string", string: "Sender commitment Y mismatch" }, "15764276373176857197": { error_kind: "string", string: "Stack too deep" } } }, bytecode: "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", debug_symbols: "pZbNjuIwDIDfJeceYsf541VGI1SgM6pUFdSBlVaId9+YxaU9JMuGS+O69dfYsV1f1aHbXb63/fh1/FGbj6vaTf0w9N/b4bhvz/1xTNqr0nwBpzbYKPB/l6A2Ji1RbahRmN6g261RYrY9T13HVgtOop/aqRvPajNehqFRv9rhcn/p59SO9/XcTumpblQ3HtKagF/90LF0a57WOm8aND6MA7rZHPzKHvL2juhh76ypsQ8g9iFU2YvzXme/X/AfCCQAQO4ZAbuOoC0QHIgL4Kx97iGuCK5AiDE8CKgxS/B5AgHYB4HAhhoCGi8E9LaOAO8S0LxAKEYyODmLGGsIqK0kNAJCjgAmjzCWJBDGaV2zCUA/b8KZ7CYKWUk2ih/kaFHZrhIRc4hicfkox2GBcsVVIlinZ8LiQP+D4IOUBgQKOQKWENpJXgKYRSDo5U0EN/eI4HWFGykvYU4JDVk3CnmJGOY2Y5bNfp1VSAVEwLk6gs1WB9q3W1UR8Vqv+gcC3ka81K2K4Yxa6gMjxBqEAS0FYlJy1iGe/QqifxeB+ZZXym+AZ9+lmkJHREksRDIrwme6a/f9tJ7SwGEae9JM5gxXNgv0UFhROO53LHguXRYCu8VC5K3yfKdFAP40C4mLbOUNnywLJBorGicaLxqeEO/miWyIR0bNfxMWQAQUwbBw43BMfbsbOvaIfb6Me3Ew3Z5/n+SJDKqn6bjvDpep42AsptV0/UhnjPHzxgH7Aw==", file_map: { "14": { source: "// docs:start:ecdsa_secp256k1\n/// Verifies a ECDSA signature over the secp256k1 curve.\n/// - inputs:\n/// - x coordinate of public key as 32 bytes\n/// - y coordinate of public key as 32 bytes\n/// - the signature, as a 64 bytes array\n/// The signature internally will be represented as `(r, s)`,\n/// where `r` and `s` are fixed-sized big endian scalar values.\n/// As the `secp256k1` has a 256-bit modulus, we have a 64 byte signature\n/// while `r` and `s` will both be 32 bytes.\n/// We expect `s` to be normalized. This means given the curve's order,\n/// `s` should be less than or equal to `order / 2`.\n/// This is done to prevent malleability.\n/// For more context regarding malleability you can reference BIP 0062.\n/// - the hash of the message, as a vector of bytes\n/// - output: false for failure and true for success\npub fn verify_signature(\n public_key_x: [u8; 32],\n public_key_y: [u8; 32],\n signature: [u8; 64],\n message_hash: [u8; 32],\n) -> bool\n// docs:end:ecdsa_secp256k1\n{\n _verify_signature(public_key_x, public_key_y, signature, message_hash, true)\n}\n\n#[foreign(ecdsa_secp256k1)]\npub fn _verify_signature(\n public_key_x: [u8; 32],\n public_key_y: [u8; 32],\n signature: [u8; 64],\n message_hash: [u8; 32],\n predicate: bool,\n) -> bool {}\n", path: "std/ecdsa_secp256k1.nr" }, "16": { source: "use crate::cmp::Eq;\nuse crate::hash::Hash;\nuse crate::ops::arith::{Add, Neg, Sub};\n\n/// A point on the embedded elliptic curve\n/// By definition, the base field of the embedded curve is the scalar field of the proof system curve, i.e the Noir Field.\n/// x and y denotes the Weierstrass coordinates of the point, if is_infinite is false.\npub struct EmbeddedCurvePoint {\n pub x: Field,\n pub y: Field,\n pub is_infinite: bool,\n}\n\nimpl EmbeddedCurvePoint {\n /// Elliptic curve point doubling operation\n /// returns the doubled point of a point P, i.e P+P\n pub fn double(self) -> EmbeddedCurvePoint {\n embedded_curve_add(self, self)\n }\n\n /// Returns the null element of the curve; 'the point at infinity'\n pub fn point_at_infinity() -> EmbeddedCurvePoint {\n EmbeddedCurvePoint { x: 0, y: 0, is_infinite: true }\n }\n\n /// Returns the curve's generator point.\n pub fn generator() -> EmbeddedCurvePoint {\n // Generator point for the grumpkin curve (y^2 = x^3 - 17)\n EmbeddedCurvePoint {\n x: 1,\n y: 17631683881184975370165255887551781615748388533673675138860, // sqrt(-16)\n is_infinite: false,\n }\n }\n}\n\nimpl Add for EmbeddedCurvePoint {\n /// Adds two points P+Q, using the curve addition formula, and also handles point at infinity\n fn add(self, other: EmbeddedCurvePoint) -> EmbeddedCurvePoint {\n embedded_curve_add(self, other)\n }\n}\n\nimpl Sub for EmbeddedCurvePoint {\n /// Points subtraction operation, using addition and negation\n fn sub(self, other: EmbeddedCurvePoint) -> EmbeddedCurvePoint {\n self + other.neg()\n }\n}\n\nimpl Neg for EmbeddedCurvePoint {\n /// Negates a point P, i.e returns -P, by negating the y coordinate.\n /// If the point is at infinity, then the result is also at infinity.\n fn neg(self) -> EmbeddedCurvePoint {\n EmbeddedCurvePoint { x: self.x, y: -self.y, is_infinite: self.is_infinite }\n }\n}\n\nimpl Eq for EmbeddedCurvePoint {\n /// Checks whether two points are equal\n fn eq(self: Self, b: EmbeddedCurvePoint) -> bool {\n (self.is_infinite & b.is_infinite)\n | ((self.is_infinite == b.is_infinite) & (self.x == b.x) & (self.y == b.y))\n }\n}\n\nimpl Hash for EmbeddedCurvePoint {\n fn hash<H>(self, state: &mut H)\n where\n H: crate::hash::Hasher,\n {\n if self.is_infinite {\n self.is_infinite.hash(state);\n } else {\n self.x.hash(state);\n self.y.hash(state);\n }\n }\n}\n\n/// Scalar for the embedded curve represented as low and high limbs\n/// By definition, the scalar field of the embedded curve is base field of the proving system curve.\n/// It may not fit into a Field element, so it is represented with two Field elements; its low and high limbs.\npub struct EmbeddedCurveScalar {\n pub lo: Field,\n pub hi: Field,\n}\n\nimpl EmbeddedCurveScalar {\n pub fn new(lo: Field, hi: Field) -> Self {\n EmbeddedCurveScalar { lo, hi }\n }\n\n #[field(bn254)]\n pub fn from_field(scalar: Field) -> EmbeddedCurveScalar {\n let (a, b) = crate::field::bn254::decompose(scalar);\n EmbeddedCurveScalar { lo: a, hi: b }\n }\n\n //Bytes to scalar: take the first (after the specified offset) 16 bytes of the input as the lo value, and the next 16 bytes as the hi value\n #[field(bn254)]\n pub(crate) fn from_bytes(bytes: [u8; 64], offset: u32) -> EmbeddedCurveScalar {\n let mut v = 1;\n let mut lo = 0 as Field;\n let mut hi = 0 as Field;\n for i in 0..16 {\n lo = lo + (bytes[offset + 31 - i] as Field) * v;\n hi = hi + (bytes[offset + 15 - i] as Field) * v;\n v = v * 256;\n }\n let sig_s = crate::embedded_curve_ops::EmbeddedCurveScalar { lo, hi };\n sig_s\n }\n}\n\nimpl Eq for EmbeddedCurveScalar {\n fn eq(self, other: Self) -> bool {\n (other.hi == self.hi) & (other.lo == self.lo)\n }\n}\n\nimpl Hash for EmbeddedCurveScalar {\n fn hash<H>(self, state: &mut H)\n where\n H: crate::hash::Hasher,\n {\n self.hi.hash(state);\n self.lo.hash(state);\n }\n}\n\n// Computes a multi scalar multiplication over the embedded curve.\n// For bn254, We have Grumpkin and Baby JubJub.\n// For bls12-381, we have JubJub and Bandersnatch.\n//\n// The embedded curve being used is decided by the\n// underlying proof system.\n// docs:start:multi_scalar_mul\npub fn multi_scalar_mul<let N: u32>(\n points: [EmbeddedCurvePoint; N],\n scalars: [EmbeddedCurveScalar; N],\n) -> EmbeddedCurvePoint\n// docs:end:multi_scalar_mul\n{\n multi_scalar_mul_array_return(points, scalars, true)[0]\n}\n\n#[foreign(multi_scalar_mul)]\npub(crate) fn multi_scalar_mul_array_return<let N: u32>(\n points: [EmbeddedCurvePoint; N],\n scalars: [EmbeddedCurveScalar; N],\n predicate: bool,\n) -> [EmbeddedCurvePoint; 1] {}\n\n// docs:start:fixed_base_scalar_mul\npub fn fixed_base_scalar_mul(scalar: EmbeddedCurveScalar) -> EmbeddedCurvePoint\n// docs:end:fixed_base_scalar_mul\n{\n multi_scalar_mul([EmbeddedCurvePoint::generator()], [scalar])\n}\n\n/// This function only assumes that the points are on the curve\n/// It handles corner cases around the infinity point causing some overhead compared to embedded_curve_add_not_nul and embedded_curve_add_unsafe\n// docs:start:embedded_curve_add\npub fn embedded_curve_add(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n // docs:end:embedded_curve_add\n if crate::runtime::is_unconstrained() {\n // `embedded_curve_add_unsafe` requires the inputs not to be the infinity point, so we check it here.\n // This is because `embedded_curve_add_unsafe` uses the `embedded_curve_add` opcode.\n // For efficiency, the backend does not check the inputs for the infinity point, but it assumes that they are not the infinity point\n // so that it can apply the ec addition formula directly.\n if point1.is_infinite {\n point2\n } else if point2.is_infinite {\n point1\n } else {\n embedded_curve_add_unsafe(point1, point2)\n }\n } else {\n // In a constrained context, we also need to check the inputs are not the infinity point because we also use `embedded_curve_add_unsafe`\n // However we also need to identify the case where the two inputs are the same, because then\n // the addition formula does not work and we need to use the doubling formula instead.\n // In unconstrained context, we can check directly if the input values are the same when solving the opcode, so it is not an issue.\n\n // x_coordinates_match is true if both abscissae are the same\n let x_coordinates_match = point1.x == point2.x;\n // y_coordinates_match is true if both ordinates are the same\n let y_coordinates_match = point1.y == point2.y;\n // double_predicate is true if both abscissae and ordinates are the same\n let double_predicate = (x_coordinates_match & y_coordinates_match);\n // If the abscissae are the same, but not the ordinates, then one point is the opposite of the other\n let infinity_predicate = (x_coordinates_match & !y_coordinates_match);\n\n // `embedded_curve_add_unsafe` would not perform doubling, even if the inputs point1 and point2 are the same, because it cannot know this without adding some logic (and some constraints)\n // However we did this logic when we computed `double_predicate`, so we set the result to 2*point1 if point1 and point2 are the same\n let mut result = if double_predicate {\n // `embedded_curve_add_unsafe` is doing a doubling if the input is the same variable, because in this case it is guaranteed (at 'compile time') that the input is the same.\n embedded_curve_add_unsafe(point1, point1)\n } else {\n let point1_1 = EmbeddedCurvePoint {\n x: point1.x + (x_coordinates_match as Field),\n y: point1.y,\n is_infinite: false,\n };\n let point2_1 = EmbeddedCurvePoint { x: point2.x, y: point2.y, is_infinite: false };\n // point1_1 is guaranteed to have a different abscissa than point2:\n // - if x_coordinates_match is 0, that means point1.x != point2.x, and point1_1.x = point1.x + 0\n // - if x_coordinates_match is 1, that means point1.x = point2.x, but point1_1.x = point1.x + 1 in this case\n // Because the abscissa is different, the addition formula is guaranteed to succeed, so we can safely use `embedded_curve_add_unsafe`\n // Note that this computation may be garbage: if x_coordinates_match is 1, or if one of the input is the point at infinity.\n // therefore we only want to do this if we need the result, otherwise it needs to be eliminated as a dead instruction, lest we want the circuit to fail.\n embedded_curve_add_unsafe(point1_1, point2_1)\n };\n\n // Same logic as above for unconstrained context, we set the proper result when one of the inputs is the infinity point\n if point1.is_infinite {\n result = point2;\n }\n if point2.is_infinite {\n result = point1;\n }\n\n // Finally, we set the is_infinity flag of the result:\n // Opposite points should sum into the infinity point, however, if one of them is point at infinity, their coordinates are not meaningful\n // so we should not use the fact that the inputs are opposite in this case:\n let mut result_is_infinity =\n infinity_predicate & (!point1.is_infinite & !point2.is_infinite);\n // However, if both of them are at infinity, then the result is also at infinity\n result.is_infinite = result_is_infinity | (point1.is_infinite & point2.is_infinite);\n result\n }\n}\n\n#[foreign(embedded_curve_add)]\nfn embedded_curve_add_array_return(\n _point1: EmbeddedCurvePoint,\n _point2: EmbeddedCurvePoint,\n _predicate: bool,\n) -> [EmbeddedCurvePoint; 1] {}\n\n/// This function assumes that:\n/// The points are on the curve, and\n/// The points don't share an x-coordinate, and\n/// Neither point is the infinity point.\n/// If it is used with correct input, the function ensures the correct non-zero result is returned.\n/// Except for points on the curve, the other assumptions are checked by the function. It will cause assertion failure if they are not respected.\npub fn embedded_curve_add_not_nul(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n assert(point1.x != point2.x);\n assert(!point1.is_infinite);\n assert(!point2.is_infinite);\n // Ensure is_infinite is comptime\n let point1_1 = EmbeddedCurvePoint { x: point1.x, y: point1.y, is_infinite: false };\n let point2_1 = EmbeddedCurvePoint { x: point2.x, y: point2.y, is_infinite: false };\n embedded_curve_add_unsafe(point1_1, point2_1)\n}\n\n/// Unsafe ec addition\n/// If the inputs are the same, it will perform a doubling, but only if point1 and point2 are the same variable.\n/// If they have the same value but are different variables, the result will be incorrect because in this case\n/// it assumes (but does not check) that the points' x-coordinates are not equal.\n/// It also assumes neither point is the infinity point.\npub fn embedded_curve_add_unsafe(\n point1: EmbeddedCurvePoint,\n point2: EmbeddedCurvePoint,\n) -> EmbeddedCurvePoint {\n embedded_curve_add_array_return(point1, point2, true)[0]\n}\n", path: "std/embedded_curve_ops.nr" }, "17": { source: `use crate::field::field_less_than;
|
|
@@ -11921,6 +13235,9 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
11921
13235
|
framework = "noir";
|
|
11922
13236
|
_isReady = false;
|
|
11923
13237
|
config;
|
|
13238
|
+
// Mobile device info (cached)
|
|
13239
|
+
deviceInfo = null;
|
|
13240
|
+
wasmCompatibility = null;
|
|
11924
13241
|
// Circuit instances
|
|
11925
13242
|
fundingNoir = null;
|
|
11926
13243
|
fundingBackend = null;
|
|
@@ -11932,17 +13249,25 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
11932
13249
|
worker = null;
|
|
11933
13250
|
workerPending = /* @__PURE__ */ new Map();
|
|
11934
13251
|
constructor(config = {}) {
|
|
13252
|
+
this.deviceInfo = getMobileDeviceInfo();
|
|
13253
|
+
const isMobile = this.deviceInfo.isMobile;
|
|
13254
|
+
const defaultTimeout = isMobile ? 12e4 : 6e4;
|
|
11935
13255
|
this.config = {
|
|
11936
13256
|
useWorker: config.useWorker ?? true,
|
|
11937
13257
|
verbose: config.verbose ?? false,
|
|
11938
13258
|
oraclePublicKey: config.oraclePublicKey ?? void 0,
|
|
11939
|
-
timeout: config.timeout ??
|
|
13259
|
+
timeout: config.timeout ?? defaultTimeout,
|
|
13260
|
+
mobileMode: config.mobileMode ?? isMobile,
|
|
13261
|
+
forceInitialize: config.forceInitialize ?? false
|
|
11940
13262
|
};
|
|
11941
13263
|
if (!isBrowser()) {
|
|
11942
13264
|
console.warn(
|
|
11943
13265
|
"[BrowserNoirProvider] Not running in browser environment. Consider using NoirProofProvider for Node.js."
|
|
11944
13266
|
);
|
|
11945
13267
|
}
|
|
13268
|
+
if (this.config.verbose && this.deviceInfo) {
|
|
13269
|
+
console.log("[BrowserNoirProvider] Device info:", this.deviceInfo);
|
|
13270
|
+
}
|
|
11946
13271
|
}
|
|
11947
13272
|
get isReady() {
|
|
11948
13273
|
return this._isReady;
|
|
@@ -11972,6 +13297,67 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
11972
13297
|
missing
|
|
11973
13298
|
};
|
|
11974
13299
|
}
|
|
13300
|
+
/**
|
|
13301
|
+
* Get detailed mobile device information
|
|
13302
|
+
*/
|
|
13303
|
+
static getMobileInfo() {
|
|
13304
|
+
return getMobileDeviceInfo();
|
|
13305
|
+
}
|
|
13306
|
+
/**
|
|
13307
|
+
* Check mobile WASM compatibility
|
|
13308
|
+
*
|
|
13309
|
+
* Returns detailed compatibility information including:
|
|
13310
|
+
* - Feature support (WASM, SharedArrayBuffer, Workers, SIMD)
|
|
13311
|
+
* - Compatibility score (0-100)
|
|
13312
|
+
* - Issues and recommendations
|
|
13313
|
+
*
|
|
13314
|
+
* @example
|
|
13315
|
+
* ```typescript
|
|
13316
|
+
* const compat = BrowserNoirProvider.checkMobileCompatibility()
|
|
13317
|
+
* if (compat.score < 70) {
|
|
13318
|
+
* console.warn('Limited mobile support:', compat.issues)
|
|
13319
|
+
* }
|
|
13320
|
+
* ```
|
|
13321
|
+
*/
|
|
13322
|
+
static checkMobileCompatibility() {
|
|
13323
|
+
return checkMobileWASMCompatibility();
|
|
13324
|
+
}
|
|
13325
|
+
/**
|
|
13326
|
+
* Check if the current device is mobile
|
|
13327
|
+
*/
|
|
13328
|
+
static isMobile() {
|
|
13329
|
+
return getMobileDeviceInfo().isMobile;
|
|
13330
|
+
}
|
|
13331
|
+
/**
|
|
13332
|
+
* Get recommended configuration for the current device
|
|
13333
|
+
*
|
|
13334
|
+
* Automatically adjusts settings based on device capabilities:
|
|
13335
|
+
* - Mobile devices get longer timeouts
|
|
13336
|
+
* - Low-memory devices disable workers
|
|
13337
|
+
* - Tablets get intermediate settings
|
|
13338
|
+
*/
|
|
13339
|
+
static getRecommendedConfig() {
|
|
13340
|
+
const deviceInfo = getMobileDeviceInfo();
|
|
13341
|
+
const compat = checkMobileWASMCompatibility();
|
|
13342
|
+
const config = {};
|
|
13343
|
+
if (deviceInfo.isMobile) {
|
|
13344
|
+
config.timeout = 12e4;
|
|
13345
|
+
config.mobileMode = true;
|
|
13346
|
+
if (deviceInfo.deviceMemoryGB !== null && deviceInfo.deviceMemoryGB < 2) {
|
|
13347
|
+
config.useWorker = false;
|
|
13348
|
+
}
|
|
13349
|
+
if (deviceInfo.platform === "ios" && deviceInfo.browser === "safari") {
|
|
13350
|
+
config.useWorker = compat.sharedArrayBuffer;
|
|
13351
|
+
}
|
|
13352
|
+
} else if (deviceInfo.isTablet) {
|
|
13353
|
+
config.timeout = 9e4;
|
|
13354
|
+
config.mobileMode = true;
|
|
13355
|
+
}
|
|
13356
|
+
if (compat.score < 50) {
|
|
13357
|
+
config.forceInitialize = false;
|
|
13358
|
+
}
|
|
13359
|
+
return config;
|
|
13360
|
+
}
|
|
11975
13361
|
/**
|
|
11976
13362
|
* Derive secp256k1 public key coordinates from a private key
|
|
11977
13363
|
*/
|
|
@@ -11981,6 +13367,18 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
11981
13367
|
const y = Array.from(uncompressedPubKey.slice(33, 65));
|
|
11982
13368
|
return { x, y };
|
|
11983
13369
|
}
|
|
13370
|
+
/**
|
|
13371
|
+
* Get the cached WASM compatibility info (available after construction)
|
|
13372
|
+
*/
|
|
13373
|
+
getWASMCompatibility() {
|
|
13374
|
+
return this.wasmCompatibility;
|
|
13375
|
+
}
|
|
13376
|
+
/**
|
|
13377
|
+
* Get the cached device info (available after construction)
|
|
13378
|
+
*/
|
|
13379
|
+
getDeviceInfo() {
|
|
13380
|
+
return this.deviceInfo;
|
|
13381
|
+
}
|
|
11984
13382
|
/**
|
|
11985
13383
|
* Initialize the browser provider
|
|
11986
13384
|
*
|
|
@@ -11993,8 +13391,18 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
11993
13391
|
if (this._isReady) {
|
|
11994
13392
|
return;
|
|
11995
13393
|
}
|
|
13394
|
+
this.wasmCompatibility = checkMobileWASMCompatibility();
|
|
13395
|
+
if (this.config.verbose) {
|
|
13396
|
+
console.log("[BrowserNoirProvider] WASM compatibility:", this.wasmCompatibility);
|
|
13397
|
+
}
|
|
13398
|
+
if (this.wasmCompatibility.score < 50 && !this.config.forceInitialize) {
|
|
13399
|
+
throw new ProofError(
|
|
13400
|
+
`Device has poor WASM compatibility (score: ${this.wasmCompatibility.score}). Issues: ${this.wasmCompatibility.issues.join(", ")}. Set forceInitialize: true to override.`,
|
|
13401
|
+
"SIP_4004" /* PROOF_PROVIDER_NOT_READY */
|
|
13402
|
+
);
|
|
13403
|
+
}
|
|
11996
13404
|
const { supported, missing } = _BrowserNoirProvider.checkBrowserSupport();
|
|
11997
|
-
if (!supported) {
|
|
13405
|
+
if (!supported && !this.config.forceInitialize) {
|
|
11998
13406
|
throw new ProofError(
|
|
11999
13407
|
`Browser missing required features: ${missing.join(", ")}`,
|
|
12000
13408
|
"SIP_4004" /* PROOF_PROVIDER_NOT_READY */
|
|
@@ -12058,8 +13466,69 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
12058
13466
|
* Initialize Web Worker for off-main-thread proof generation
|
|
12059
13467
|
*/
|
|
12060
13468
|
async initializeWorker() {
|
|
12061
|
-
if (
|
|
12062
|
-
|
|
13469
|
+
if (!supportsWebWorkers()) {
|
|
13470
|
+
if (this.config.verbose) {
|
|
13471
|
+
console.log("[BrowserNoirProvider] Web Workers not supported, using main thread");
|
|
13472
|
+
}
|
|
13473
|
+
return;
|
|
13474
|
+
}
|
|
13475
|
+
try {
|
|
13476
|
+
const workerCode = this.getWorkerCode();
|
|
13477
|
+
const blob = new Blob([workerCode], { type: "application/javascript" });
|
|
13478
|
+
const workerURL = URL.createObjectURL(blob);
|
|
13479
|
+
this.worker = new Worker(workerURL, { type: "module" });
|
|
13480
|
+
this.worker.onmessage = (event) => {
|
|
13481
|
+
this.handleWorkerMessage(event.data);
|
|
13482
|
+
};
|
|
13483
|
+
this.worker.onerror = (error) => {
|
|
13484
|
+
console.error("[BrowserNoirProvider] Worker error:", error);
|
|
13485
|
+
for (const [id, { reject }] of this.workerPending) {
|
|
13486
|
+
reject(new Error(`Worker error: ${error.message}`));
|
|
13487
|
+
this.workerPending.delete(id);
|
|
13488
|
+
}
|
|
13489
|
+
this.worker?.terminate();
|
|
13490
|
+
this.worker = null;
|
|
13491
|
+
};
|
|
13492
|
+
URL.revokeObjectURL(workerURL);
|
|
13493
|
+
if (this.config.verbose) {
|
|
13494
|
+
console.log("[BrowserNoirProvider] Web Worker initialized successfully");
|
|
13495
|
+
}
|
|
13496
|
+
} catch (error) {
|
|
13497
|
+
if (this.config.verbose) {
|
|
13498
|
+
console.warn("[BrowserNoirProvider] Failed to initialize worker, using main thread:", error);
|
|
13499
|
+
}
|
|
13500
|
+
this.worker = null;
|
|
13501
|
+
}
|
|
13502
|
+
}
|
|
13503
|
+
/**
|
|
13504
|
+
* Get inline worker code for bundler compatibility
|
|
13505
|
+
*/
|
|
13506
|
+
getWorkerCode() {
|
|
13507
|
+
return `
|
|
13508
|
+
self.onmessage = async function(event) {
|
|
13509
|
+
const { id, type } = event.data;
|
|
13510
|
+
// Signal that worker received message but proof gen happens on main thread
|
|
13511
|
+
self.postMessage({ id, type: 'fallback', message: 'Worker initialized, using main thread for proofs' });
|
|
13512
|
+
};
|
|
13513
|
+
`;
|
|
13514
|
+
}
|
|
13515
|
+
/**
|
|
13516
|
+
* Handle messages from worker
|
|
13517
|
+
*/
|
|
13518
|
+
handleWorkerMessage(data) {
|
|
13519
|
+
const pending = this.workerPending.get(data.id);
|
|
13520
|
+
if (!pending) return;
|
|
13521
|
+
switch (data.type) {
|
|
13522
|
+
case "success":
|
|
13523
|
+
this.workerPending.delete(data.id);
|
|
13524
|
+
pending.resolve(data.result);
|
|
13525
|
+
break;
|
|
13526
|
+
case "error":
|
|
13527
|
+
this.workerPending.delete(data.id);
|
|
13528
|
+
pending.reject(new Error(data.error));
|
|
13529
|
+
break;
|
|
13530
|
+
case "fallback":
|
|
13531
|
+
break;
|
|
12063
13532
|
}
|
|
12064
13533
|
}
|
|
12065
13534
|
/**
|
|
@@ -12081,15 +13550,10 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
12081
13550
|
percent: 10,
|
|
12082
13551
|
message: "Preparing witness inputs..."
|
|
12083
13552
|
});
|
|
12084
|
-
const
|
|
12085
|
-
params.balance,
|
|
12086
|
-
params.blindingFactor,
|
|
12087
|
-
params.assetId
|
|
12088
|
-
);
|
|
13553
|
+
const blindingField = this.bytesToField(params.blindingFactor);
|
|
12089
13554
|
const witnessInputs = {
|
|
12090
|
-
commitment_hash: commitmentHash,
|
|
12091
13555
|
minimum_required: params.minimumRequired.toString(),
|
|
12092
|
-
asset_id: this.assetIdToField(params.assetId)
|
|
13556
|
+
asset_id: `0x${this.assetIdToField(params.assetId)}`,
|
|
12093
13557
|
balance: params.balance.toString(),
|
|
12094
13558
|
blinding: blindingField
|
|
12095
13559
|
};
|
|
@@ -12098,7 +13562,7 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
12098
13562
|
percent: 30,
|
|
12099
13563
|
message: "Generating witness..."
|
|
12100
13564
|
});
|
|
12101
|
-
const { witness } = await this.fundingNoir.execute(witnessInputs);
|
|
13565
|
+
const { witness, returnValue } = await this.fundingNoir.execute(witnessInputs);
|
|
12102
13566
|
onProgress?.({
|
|
12103
13567
|
stage: "proving",
|
|
12104
13568
|
percent: 50,
|
|
@@ -12110,10 +13574,12 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
12110
13574
|
percent: 100,
|
|
12111
13575
|
message: "Proof generated successfully"
|
|
12112
13576
|
});
|
|
13577
|
+
const commitmentHashBytes = returnValue;
|
|
13578
|
+
const commitmentHashHex = bytesToHex7(new Uint8Array(commitmentHashBytes));
|
|
12113
13579
|
const publicInputs = [
|
|
12114
|
-
`0x${commitmentHash}`,
|
|
12115
13580
|
`0x${params.minimumRequired.toString(16).padStart(16, "0")}`,
|
|
12116
|
-
`0x${this.assetIdToField(params.assetId)}
|
|
13581
|
+
`0x${this.assetIdToField(params.assetId)}`,
|
|
13582
|
+
`0x${commitmentHashHex}`
|
|
12117
13583
|
];
|
|
12118
13584
|
const proof = {
|
|
12119
13585
|
type: "funding",
|
|
@@ -12515,6 +13981,314 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
12515
13981
|
return { x, y };
|
|
12516
13982
|
}
|
|
12517
13983
|
};
|
|
13984
|
+
|
|
13985
|
+
// src/proofs/worker.ts
|
|
13986
|
+
function createWorkerBlobURL() {
|
|
13987
|
+
const workerCode = `
|
|
13988
|
+
// Proof Generation Worker
|
|
13989
|
+
// This code runs in a separate thread
|
|
13990
|
+
|
|
13991
|
+
let fundingNoir = null;
|
|
13992
|
+
let fundingBackend = null;
|
|
13993
|
+
let validityNoir = null;
|
|
13994
|
+
let validityBackend = null;
|
|
13995
|
+
let fulfillmentNoir = null;
|
|
13996
|
+
let fulfillmentBackend = null;
|
|
13997
|
+
let isReady = false;
|
|
13998
|
+
let config = { verbose: false };
|
|
13999
|
+
|
|
14000
|
+
// Helper to send progress updates
|
|
14001
|
+
function sendProgress(id, stage, percent, message) {
|
|
14002
|
+
self.postMessage({
|
|
14003
|
+
id,
|
|
14004
|
+
type: 'progress',
|
|
14005
|
+
progress: { stage, percent, message }
|
|
14006
|
+
});
|
|
14007
|
+
}
|
|
14008
|
+
|
|
14009
|
+
// Helper to send error
|
|
14010
|
+
function sendError(id, error) {
|
|
14011
|
+
self.postMessage({
|
|
14012
|
+
id,
|
|
14013
|
+
type: 'error',
|
|
14014
|
+
error: error.message || String(error)
|
|
14015
|
+
});
|
|
14016
|
+
}
|
|
14017
|
+
|
|
14018
|
+
// Helper to send success
|
|
14019
|
+
function sendSuccess(id, result) {
|
|
14020
|
+
self.postMessage({
|
|
14021
|
+
id,
|
|
14022
|
+
type: 'success',
|
|
14023
|
+
result
|
|
14024
|
+
});
|
|
14025
|
+
}
|
|
14026
|
+
|
|
14027
|
+
// Initialize circuits (called once)
|
|
14028
|
+
async function initialize(id, initConfig) {
|
|
14029
|
+
try {
|
|
14030
|
+
sendProgress(id, 'initializing', 10, 'Loading Noir JS...');
|
|
14031
|
+
|
|
14032
|
+
// Dynamic imports for Noir
|
|
14033
|
+
const { Noir } = await import('@noir-lang/noir_js');
|
|
14034
|
+
const { UltraHonkBackend } = await import('@aztec/bb.js');
|
|
14035
|
+
|
|
14036
|
+
sendProgress(id, 'initializing', 30, 'Loading circuit artifacts...');
|
|
14037
|
+
|
|
14038
|
+
// Load circuit artifacts
|
|
14039
|
+
const [fundingArtifact, validityArtifact, fulfillmentArtifact] = await Promise.all([
|
|
14040
|
+
fetch(new URL('./circuits/funding_proof.json', import.meta.url)).then(r => r.json()),
|
|
14041
|
+
fetch(new URL('./circuits/validity_proof.json', import.meta.url)).then(r => r.json()),
|
|
14042
|
+
fetch(new URL('./circuits/fulfillment_proof.json', import.meta.url)).then(r => r.json()),
|
|
14043
|
+
]);
|
|
14044
|
+
|
|
14045
|
+
sendProgress(id, 'initializing', 50, 'Initializing backends...');
|
|
14046
|
+
|
|
14047
|
+
// Initialize Noir instances
|
|
14048
|
+
fundingNoir = new Noir(fundingArtifact);
|
|
14049
|
+
fundingBackend = new UltraHonkBackend(fundingArtifact.bytecode);
|
|
14050
|
+
|
|
14051
|
+
sendProgress(id, 'initializing', 70, 'Initializing validity circuit...');
|
|
14052
|
+
validityNoir = new Noir(validityArtifact);
|
|
14053
|
+
validityBackend = new UltraHonkBackend(validityArtifact.bytecode);
|
|
14054
|
+
|
|
14055
|
+
sendProgress(id, 'initializing', 90, 'Initializing fulfillment circuit...');
|
|
14056
|
+
fulfillmentNoir = new Noir(fulfillmentArtifact);
|
|
14057
|
+
fulfillmentBackend = new UltraHonkBackend(fulfillmentArtifact.bytecode);
|
|
14058
|
+
|
|
14059
|
+
config = initConfig || { verbose: false };
|
|
14060
|
+
isReady = true;
|
|
14061
|
+
|
|
14062
|
+
sendProgress(id, 'complete', 100, 'Worker initialized');
|
|
14063
|
+
sendSuccess(id, { initialized: true });
|
|
14064
|
+
} catch (error) {
|
|
14065
|
+
sendError(id, error);
|
|
14066
|
+
}
|
|
14067
|
+
}
|
|
14068
|
+
|
|
14069
|
+
// Generate funding proof
|
|
14070
|
+
async function generateFundingProof(id, params) {
|
|
14071
|
+
if (!isReady) {
|
|
14072
|
+
sendError(id, new Error('Worker not initialized'));
|
|
14073
|
+
return;
|
|
14074
|
+
}
|
|
14075
|
+
|
|
14076
|
+
try {
|
|
14077
|
+
sendProgress(id, 'witness', 20, 'Preparing witness...');
|
|
14078
|
+
|
|
14079
|
+
// Convert blinding factor to field
|
|
14080
|
+
const blindingField = bytesToField(params.blindingFactor);
|
|
14081
|
+
|
|
14082
|
+
const witnessInputs = {
|
|
14083
|
+
minimum_required: params.minimumRequired.toString(),
|
|
14084
|
+
asset_id: '0x' + assetIdToField(params.assetId),
|
|
14085
|
+
balance: params.balance.toString(),
|
|
14086
|
+
blinding: blindingField,
|
|
14087
|
+
};
|
|
14088
|
+
|
|
14089
|
+
sendProgress(id, 'witness', 40, 'Executing circuit...');
|
|
14090
|
+
const { witness, returnValue } = await fundingNoir.execute(witnessInputs);
|
|
14091
|
+
|
|
14092
|
+
sendProgress(id, 'proving', 60, 'Generating proof...');
|
|
14093
|
+
const proofData = await fundingBackend.generateProof(witness);
|
|
14094
|
+
|
|
14095
|
+
sendProgress(id, 'complete', 100, 'Proof generated');
|
|
14096
|
+
|
|
14097
|
+
// Extract commitment hash from return value
|
|
14098
|
+
const commitmentHashHex = bytesToHex(new Uint8Array(returnValue));
|
|
14099
|
+
|
|
14100
|
+
const publicInputs = [
|
|
14101
|
+
'0x' + params.minimumRequired.toString(16).padStart(16, '0'),
|
|
14102
|
+
'0x' + assetIdToField(params.assetId),
|
|
14103
|
+
'0x' + commitmentHashHex,
|
|
14104
|
+
];
|
|
14105
|
+
|
|
14106
|
+
const proof = {
|
|
14107
|
+
type: 'funding',
|
|
14108
|
+
proof: '0x' + bytesToHex(proofData.proof),
|
|
14109
|
+
publicInputs,
|
|
14110
|
+
};
|
|
14111
|
+
|
|
14112
|
+
sendSuccess(id, { proof, publicInputs });
|
|
14113
|
+
} catch (error) {
|
|
14114
|
+
sendError(id, error);
|
|
14115
|
+
}
|
|
14116
|
+
}
|
|
14117
|
+
|
|
14118
|
+
// Helper functions
|
|
14119
|
+
function bytesToField(bytes) {
|
|
14120
|
+
let result = 0n;
|
|
14121
|
+
const len = Math.min(bytes.length, 31);
|
|
14122
|
+
for (let i = 0; i < len; i++) {
|
|
14123
|
+
result = result * 256n + BigInt(bytes[i]);
|
|
14124
|
+
}
|
|
14125
|
+
return result.toString();
|
|
14126
|
+
}
|
|
14127
|
+
|
|
14128
|
+
function assetIdToField(assetId) {
|
|
14129
|
+
if (assetId.startsWith('0x')) {
|
|
14130
|
+
return assetId.slice(2).padStart(64, '0');
|
|
14131
|
+
}
|
|
14132
|
+
const encoder = new TextEncoder();
|
|
14133
|
+
const bytes = encoder.encode(assetId);
|
|
14134
|
+
let result = 0n;
|
|
14135
|
+
for (let i = 0; i < bytes.length && i < 31; i++) {
|
|
14136
|
+
result = result * 256n + BigInt(bytes[i]);
|
|
14137
|
+
}
|
|
14138
|
+
return result.toString(16).padStart(64, '0');
|
|
14139
|
+
}
|
|
14140
|
+
|
|
14141
|
+
function bytesToHex(bytes) {
|
|
14142
|
+
return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');
|
|
14143
|
+
}
|
|
14144
|
+
|
|
14145
|
+
// Message handler
|
|
14146
|
+
self.onmessage = async function(event) {
|
|
14147
|
+
const { id, type, params, config: initConfig } = event.data;
|
|
14148
|
+
|
|
14149
|
+
switch (type) {
|
|
14150
|
+
case 'init':
|
|
14151
|
+
await initialize(id, initConfig);
|
|
14152
|
+
break;
|
|
14153
|
+
case 'generateFundingProof':
|
|
14154
|
+
await generateFundingProof(id, params);
|
|
14155
|
+
break;
|
|
14156
|
+
case 'generateValidityProof':
|
|
14157
|
+
// TODO: Implement
|
|
14158
|
+
sendError(id, new Error('Validity proof not yet implemented in worker'));
|
|
14159
|
+
break;
|
|
14160
|
+
case 'generateFulfillmentProof':
|
|
14161
|
+
// TODO: Implement
|
|
14162
|
+
sendError(id, new Error('Fulfillment proof not yet implemented in worker'));
|
|
14163
|
+
break;
|
|
14164
|
+
case 'destroy':
|
|
14165
|
+
// Cleanup
|
|
14166
|
+
fundingNoir = null;
|
|
14167
|
+
fundingBackend = null;
|
|
14168
|
+
validityNoir = null;
|
|
14169
|
+
validityBackend = null;
|
|
14170
|
+
fulfillmentNoir = null;
|
|
14171
|
+
fulfillmentBackend = null;
|
|
14172
|
+
isReady = false;
|
|
14173
|
+
sendSuccess(id, { destroyed: true });
|
|
14174
|
+
break;
|
|
14175
|
+
default:
|
|
14176
|
+
sendError(id, new Error('Unknown message type: ' + type));
|
|
14177
|
+
}
|
|
14178
|
+
};
|
|
14179
|
+
`;
|
|
14180
|
+
const blob = new Blob([workerCode], { type: "application/javascript" });
|
|
14181
|
+
return URL.createObjectURL(blob);
|
|
14182
|
+
}
|
|
14183
|
+
var ProofWorker = class _ProofWorker {
|
|
14184
|
+
worker = null;
|
|
14185
|
+
pendingRequests = /* @__PURE__ */ new Map();
|
|
14186
|
+
_isReady = false;
|
|
14187
|
+
requestCounter = 0;
|
|
14188
|
+
/**
|
|
14189
|
+
* Check if Web Workers are supported
|
|
14190
|
+
*/
|
|
14191
|
+
static isSupported() {
|
|
14192
|
+
return typeof Worker !== "undefined" && typeof Blob !== "undefined";
|
|
14193
|
+
}
|
|
14194
|
+
/**
|
|
14195
|
+
* Check if worker is initialized and ready
|
|
14196
|
+
*/
|
|
14197
|
+
get isReady() {
|
|
14198
|
+
return this._isReady;
|
|
14199
|
+
}
|
|
14200
|
+
/**
|
|
14201
|
+
* Initialize the worker
|
|
14202
|
+
*/
|
|
14203
|
+
async initialize(config) {
|
|
14204
|
+
if (this._isReady) {
|
|
14205
|
+
return;
|
|
14206
|
+
}
|
|
14207
|
+
if (!_ProofWorker.isSupported()) {
|
|
14208
|
+
throw new Error("Web Workers not supported in this environment");
|
|
14209
|
+
}
|
|
14210
|
+
const workerURL = createWorkerBlobURL();
|
|
14211
|
+
this.worker = new Worker(workerURL, { type: "module" });
|
|
14212
|
+
this.worker.onmessage = (event) => {
|
|
14213
|
+
this.handleWorkerMessage(event.data);
|
|
14214
|
+
};
|
|
14215
|
+
this.worker.onerror = (error) => {
|
|
14216
|
+
console.error("[ProofWorker] Worker error:", error);
|
|
14217
|
+
for (const [id, { reject }] of this.pendingRequests) {
|
|
14218
|
+
reject(new Error(`Worker error: ${error.message}`));
|
|
14219
|
+
this.pendingRequests.delete(id);
|
|
14220
|
+
}
|
|
14221
|
+
};
|
|
14222
|
+
await this.sendRequest("init", void 0, config);
|
|
14223
|
+
this._isReady = true;
|
|
14224
|
+
URL.revokeObjectURL(workerURL);
|
|
14225
|
+
}
|
|
14226
|
+
/**
|
|
14227
|
+
* Generate a proof using the worker
|
|
14228
|
+
*/
|
|
14229
|
+
async generateProof(type, params, onProgress) {
|
|
14230
|
+
if (!this._isReady || !this.worker) {
|
|
14231
|
+
throw new Error("Worker not initialized. Call initialize() first.");
|
|
14232
|
+
}
|
|
14233
|
+
const messageType = type === "funding" ? "generateFundingProof" : type === "validity" ? "generateValidityProof" : "generateFulfillmentProof";
|
|
14234
|
+
return this.sendRequest(messageType, params, void 0, onProgress);
|
|
14235
|
+
}
|
|
14236
|
+
/**
|
|
14237
|
+
* Destroy the worker and free resources
|
|
14238
|
+
*/
|
|
14239
|
+
async destroy() {
|
|
14240
|
+
if (this.worker) {
|
|
14241
|
+
try {
|
|
14242
|
+
await this.sendRequest("destroy");
|
|
14243
|
+
} catch {
|
|
14244
|
+
}
|
|
14245
|
+
this.worker.terminate();
|
|
14246
|
+
this.worker = null;
|
|
14247
|
+
}
|
|
14248
|
+
this._isReady = false;
|
|
14249
|
+
this.pendingRequests.clear();
|
|
14250
|
+
}
|
|
14251
|
+
/**
|
|
14252
|
+
* Send a request to the worker
|
|
14253
|
+
*/
|
|
14254
|
+
sendRequest(type, params, config, onProgress) {
|
|
14255
|
+
return new Promise((resolve, reject) => {
|
|
14256
|
+
if (!this.worker) {
|
|
14257
|
+
reject(new Error("Worker not available"));
|
|
14258
|
+
return;
|
|
14259
|
+
}
|
|
14260
|
+
const id = `req_${++this.requestCounter}_${Date.now()}`;
|
|
14261
|
+
this.pendingRequests.set(id, { resolve, reject, onProgress });
|
|
14262
|
+
const request = { id, type, params, config };
|
|
14263
|
+
this.worker.postMessage(request);
|
|
14264
|
+
});
|
|
14265
|
+
}
|
|
14266
|
+
/**
|
|
14267
|
+
* Handle messages from the worker
|
|
14268
|
+
*/
|
|
14269
|
+
handleWorkerMessage(response) {
|
|
14270
|
+
const pending = this.pendingRequests.get(response.id);
|
|
14271
|
+
if (!pending) {
|
|
14272
|
+
console.warn("[ProofWorker] Received response for unknown request:", response.id);
|
|
14273
|
+
return;
|
|
14274
|
+
}
|
|
14275
|
+
switch (response.type) {
|
|
14276
|
+
case "success":
|
|
14277
|
+
this.pendingRequests.delete(response.id);
|
|
14278
|
+
pending.resolve(response.result);
|
|
14279
|
+
break;
|
|
14280
|
+
case "error":
|
|
14281
|
+
this.pendingRequests.delete(response.id);
|
|
14282
|
+
pending.reject(new Error(response.error));
|
|
14283
|
+
break;
|
|
14284
|
+
case "progress":
|
|
14285
|
+
if (pending.onProgress && response.progress) {
|
|
14286
|
+
pending.onProgress(response.progress);
|
|
14287
|
+
}
|
|
14288
|
+
break;
|
|
14289
|
+
}
|
|
14290
|
+
}
|
|
14291
|
+
};
|
|
12518
14292
|
// Annotate the CommonJS export names for ESM import in node:
|
|
12519
14293
|
0 && (module.exports = {
|
|
12520
14294
|
ATTESTATION_VERSION,
|
|
@@ -12545,6 +14319,7 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
12545
14319
|
MockWalletAdapter,
|
|
12546
14320
|
NATIVE_TOKENS,
|
|
12547
14321
|
NEARIntentsAdapter,
|
|
14322
|
+
NEARIntentsBackend,
|
|
12548
14323
|
NetworkError,
|
|
12549
14324
|
ORACLE_DOMAIN,
|
|
12550
14325
|
OneClickClient,
|
|
@@ -12558,6 +14333,7 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
12558
14333
|
ProofError,
|
|
12559
14334
|
ProofGenerationError,
|
|
12560
14335
|
ProofNotImplementedError,
|
|
14336
|
+
ProofWorker,
|
|
12561
14337
|
ProposalStatus,
|
|
12562
14338
|
ReportStatus,
|
|
12563
14339
|
SIP,
|
|
@@ -12566,13 +14342,18 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
12566
14342
|
STABLECOIN_ADDRESSES,
|
|
12567
14343
|
STABLECOIN_DECIMALS,
|
|
12568
14344
|
STABLECOIN_INFO,
|
|
14345
|
+
SettlementRegistry,
|
|
14346
|
+
SettlementRegistryError,
|
|
14347
|
+
SmartRouter,
|
|
12569
14348
|
SolanaWalletAdapter,
|
|
14349
|
+
SwapStatus,
|
|
12570
14350
|
Treasury,
|
|
12571
14351
|
TrezorWalletAdapter,
|
|
12572
14352
|
ValidationError,
|
|
12573
14353
|
WalletError,
|
|
12574
14354
|
WalletErrorCode,
|
|
12575
14355
|
ZcashErrorCode,
|
|
14356
|
+
ZcashNativeBackend,
|
|
12576
14357
|
ZcashRPCClient,
|
|
12577
14358
|
ZcashRPCError,
|
|
12578
14359
|
ZcashShieldedService,
|
|
@@ -12585,6 +14366,7 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
12585
14366
|
browserBytesToHex,
|
|
12586
14367
|
browserHexToBytes,
|
|
12587
14368
|
checkEd25519StealthAddress,
|
|
14369
|
+
checkMobileWASMCompatibility,
|
|
12588
14370
|
checkStealthAddress,
|
|
12589
14371
|
commit,
|
|
12590
14372
|
commitZero,
|
|
@@ -12601,15 +14383,19 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
12601
14383
|
createMockSolver,
|
|
12602
14384
|
createMockTrezorAdapter,
|
|
12603
14385
|
createNEARIntentsAdapter,
|
|
14386
|
+
createNEARIntentsBackend,
|
|
12604
14387
|
createOracleRegistry,
|
|
12605
14388
|
createProductionSIP,
|
|
12606
14389
|
createSIP,
|
|
12607
14390
|
createShieldedIntent,
|
|
12608
14391
|
createShieldedPayment,
|
|
14392
|
+
createSmartRouter,
|
|
12609
14393
|
createSolanaAdapter,
|
|
12610
14394
|
createTrezorAdapter,
|
|
12611
14395
|
createWalletFactory,
|
|
14396
|
+
createWorkerBlobURL,
|
|
12612
14397
|
createZcashClient,
|
|
14398
|
+
createZcashNativeBackend,
|
|
12613
14399
|
createZcashShieldedService,
|
|
12614
14400
|
createZcashSwapService,
|
|
12615
14401
|
decodeStealthMetaAddress,
|
|
@@ -12623,6 +14409,8 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
12623
14409
|
deserializeIntent,
|
|
12624
14410
|
deserializePayment,
|
|
12625
14411
|
detectEthereumWallets,
|
|
14412
|
+
detectMobileBrowser,
|
|
14413
|
+
detectMobilePlatform,
|
|
12626
14414
|
detectSolanaWallets,
|
|
12627
14415
|
ed25519PublicKeyToNearAddress,
|
|
12628
14416
|
ed25519PublicKeyToSolanaAddress,
|
|
@@ -12643,6 +14431,7 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
12643
14431
|
getActiveOracles,
|
|
12644
14432
|
getAvailableTransports,
|
|
12645
14433
|
getBrowserInfo,
|
|
14434
|
+
getBrowserVersion,
|
|
12646
14435
|
getChainNumericId,
|
|
12647
14436
|
getChainsForStablecoin,
|
|
12648
14437
|
getCurveForChain,
|
|
@@ -12652,6 +14441,8 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
12652
14441
|
getEthereumProvider,
|
|
12653
14442
|
getGenerators,
|
|
12654
14443
|
getIntentSummary,
|
|
14444
|
+
getMobileDeviceInfo,
|
|
14445
|
+
getOSVersion,
|
|
12655
14446
|
getPaymentSummary,
|
|
12656
14447
|
getPaymentTimeRemaining,
|
|
12657
14448
|
getPrivacyConfig,
|
|
@@ -12677,6 +14468,7 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
12677
14468
|
isSIPError,
|
|
12678
14469
|
isStablecoin,
|
|
12679
14470
|
isStablecoinOnChain,
|
|
14471
|
+
isTablet,
|
|
12680
14472
|
isValidAmount,
|
|
12681
14473
|
isValidChainId,
|
|
12682
14474
|
isValidCompressedPublicKey,
|
|
@@ -12708,7 +14500,10 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
|
12708
14500
|
subtractBlindings,
|
|
12709
14501
|
subtractCommitments,
|
|
12710
14502
|
supportsSharedArrayBuffer,
|
|
14503
|
+
supportsTouch,
|
|
12711
14504
|
supportsViewingKey,
|
|
14505
|
+
supportsWASMBulkMemory,
|
|
14506
|
+
supportsWASMSimd,
|
|
12712
14507
|
supportsWebBluetooth,
|
|
12713
14508
|
supportsWebHID,
|
|
12714
14509
|
supportsWebUSB,
|