@sip-protocol/sdk 0.6.6 → 0.6.9

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.js CHANGED
@@ -5439,7 +5439,8 @@ async function createShieldedIntent(params, options) {
5439
5439
  const effectiveAuthSig = authorizationSignature ?? new Uint8Array(64);
5440
5440
  const fundingResult = await proofProvider.generateFundingProof({
5441
5441
  balance: input.amount,
5442
- minimumRequired: output.minAmount,
5442
+ minimumRequired: input.amount,
5443
+ // Fix: Must be same units as balance (input asset)
5443
5444
  blindingFactor: hexToUint8(inputCommitment.blindingFactor),
5444
5445
  assetId: input.asset.symbol,
5445
5446
  userAddress: senderAddress ?? "0x0",
@@ -21291,6 +21292,8 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
21291
21292
  validityBackend = null;
21292
21293
  fulfillmentNoir = null;
21293
21294
  fulfillmentBackend = null;
21295
+ // Mutex for WASM operations (prevents BorrowMutError from concurrent access)
21296
+ wasmMutex = Promise.resolve();
21294
21297
  // Worker instance (optional)
21295
21298
  worker = null;
21296
21299
  workerPending = /* @__PURE__ */ new Map();
@@ -21590,57 +21593,59 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
21590
21593
  if (!this.fundingNoir || !this.fundingBackend) {
21591
21594
  throw new ProofGenerationError("funding", "Funding circuit not initialized");
21592
21595
  }
21593
- try {
21594
- onProgress?.({
21595
- stage: "witness",
21596
- percent: 10,
21597
- message: "Preparing witness inputs..."
21598
- });
21599
- const blindingField = this.bytesToField(params.blindingFactor);
21600
- const witnessInputs = {
21601
- minimum_required: `0x${params.minimumRequired.toString(16)}`,
21602
- asset_id: `0x${this.assetIdToField(params.assetId)}`,
21603
- balance: `0x${params.balance.toString(16)}`,
21604
- blinding: blindingField
21605
- };
21606
- onProgress?.({
21607
- stage: "witness",
21608
- percent: 30,
21609
- message: "Generating witness..."
21610
- });
21611
- const { witness, returnValue } = await this.fundingNoir.execute(witnessInputs);
21612
- onProgress?.({
21613
- stage: "proving",
21614
- percent: 50,
21615
- message: "Generating proof (this may take a moment)..."
21616
- });
21617
- const proofData = await this.fundingBackend.generateProof(witness);
21618
- onProgress?.({
21619
- stage: "complete",
21620
- percent: 100,
21621
- message: "Proof generated successfully"
21622
- });
21623
- const commitmentHashBytes = returnValue;
21624
- const commitmentHashHex = bytesToHex11(new Uint8Array(commitmentHashBytes));
21625
- const publicInputs = [
21626
- `0x${params.minimumRequired.toString(16).padStart(64, "0")}`,
21627
- `0x${this.assetIdToField(params.assetId)}`,
21628
- `0x${commitmentHashHex}`
21629
- ];
21630
- const proof = {
21631
- type: "funding",
21632
- proof: `0x${bytesToHex11(proofData.proof)}`,
21633
- publicInputs
21634
- };
21635
- return { proof, publicInputs };
21636
- } catch (error) {
21637
- const message = error instanceof Error ? error.message : String(error);
21638
- throw new ProofGenerationError(
21639
- "funding",
21640
- `Failed to generate funding proof: ${message}`,
21641
- error instanceof Error ? error : void 0
21642
- );
21643
- }
21596
+ return this.acquireWasmLock(async () => {
21597
+ try {
21598
+ onProgress?.({
21599
+ stage: "witness",
21600
+ percent: 10,
21601
+ message: "Preparing witness inputs..."
21602
+ });
21603
+ const blindingField = this.bytesToField(params.blindingFactor);
21604
+ const witnessInputs = {
21605
+ minimum_required: `0x${params.minimumRequired.toString(16)}`,
21606
+ asset_id: `0x${this.assetIdToField(params.assetId)}`,
21607
+ balance: `0x${params.balance.toString(16)}`,
21608
+ blinding: blindingField
21609
+ };
21610
+ onProgress?.({
21611
+ stage: "witness",
21612
+ percent: 30,
21613
+ message: "Generating witness..."
21614
+ });
21615
+ const { witness, returnValue } = await this.fundingNoir.execute(witnessInputs);
21616
+ onProgress?.({
21617
+ stage: "proving",
21618
+ percent: 50,
21619
+ message: "Generating proof (this may take a moment)..."
21620
+ });
21621
+ const proofData = await this.fundingBackend.generateProof(witness);
21622
+ onProgress?.({
21623
+ stage: "complete",
21624
+ percent: 100,
21625
+ message: "Proof generated successfully"
21626
+ });
21627
+ const commitmentHashBytes = returnValue;
21628
+ const commitmentHashHex = bytesToHex11(new Uint8Array(commitmentHashBytes));
21629
+ const publicInputs = [
21630
+ `0x${params.minimumRequired.toString(16).padStart(64, "0")}`,
21631
+ `0x${this.assetIdToField(params.assetId)}`,
21632
+ `0x${commitmentHashHex}`
21633
+ ];
21634
+ const proof = {
21635
+ type: "funding",
21636
+ proof: `0x${bytesToHex11(proofData.proof)}`,
21637
+ publicInputs
21638
+ };
21639
+ return { proof, publicInputs };
21640
+ } catch (error) {
21641
+ const message = error instanceof Error ? error.message : String(error);
21642
+ throw new ProofGenerationError(
21643
+ "funding",
21644
+ `Failed to generate funding proof: ${message}`,
21645
+ error instanceof Error ? error : void 0
21646
+ );
21647
+ }
21648
+ });
21644
21649
  }
21645
21650
  /**
21646
21651
  * Generate a Validity Proof
@@ -21652,89 +21657,91 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
21652
21657
  if (!this.validityNoir || !this.validityBackend) {
21653
21658
  throw new ProofGenerationError("validity", "Validity circuit not initialized");
21654
21659
  }
21655
- try {
21656
- onProgress?.({
21657
- stage: "witness",
21658
- percent: 10,
21659
- message: "Preparing validity witness..."
21660
- });
21661
- const intentHashField = this.hexToField(params.intentHash);
21662
- const senderAddressField = this.hexToField(params.senderAddress);
21663
- const senderBlindingField = this.bytesToField(params.senderBlinding);
21664
- const senderSecretField = this.bytesToField(params.senderSecret);
21665
- const nonceField = this.bytesToField(params.nonce);
21666
- const { commitmentX, commitmentY } = await this.computeSenderCommitment(
21667
- senderAddressField,
21668
- senderBlindingField
21669
- );
21670
- const nullifier = await this.computeNullifier(senderSecretField, intentHashField, nonceField);
21671
- const signature = Array.from(params.authorizationSignature);
21672
- const messageHash = this.fieldToBytes32(intentHashField);
21673
- let pubKeyX;
21674
- let pubKeyY;
21675
- if (params.senderPublicKey) {
21676
- pubKeyX = Array.from(params.senderPublicKey.x);
21677
- pubKeyY = Array.from(params.senderPublicKey.y);
21678
- } else {
21679
- const coords = this.getPublicKeyCoordinates(params.senderSecret);
21680
- pubKeyX = coords.x;
21681
- pubKeyY = coords.y;
21682
- }
21683
- const witnessInputs = {
21684
- intent_hash: intentHashField,
21685
- sender_commitment_x: commitmentX,
21686
- sender_commitment_y: commitmentY,
21687
- nullifier,
21688
- timestamp: params.timestamp.toString(),
21689
- expiry: params.expiry.toString(),
21690
- sender_address: senderAddressField,
21691
- sender_blinding: senderBlindingField,
21692
- sender_secret: senderSecretField,
21693
- pub_key_x: pubKeyX,
21694
- pub_key_y: pubKeyY,
21695
- signature,
21696
- message_hash: messageHash,
21697
- nonce: nonceField
21698
- };
21699
- onProgress?.({
21700
- stage: "witness",
21701
- percent: 30,
21702
- message: "Generating witness..."
21703
- });
21704
- const { witness } = await this.validityNoir.execute(witnessInputs);
21705
- onProgress?.({
21706
- stage: "proving",
21707
- percent: 50,
21708
- message: "Generating validity proof..."
21709
- });
21710
- const proofData = await this.validityBackend.generateProof(witness);
21711
- onProgress?.({
21712
- stage: "complete",
21713
- percent: 100,
21714
- message: "Validity proof generated"
21715
- });
21716
- const publicInputs = [
21717
- `0x${intentHashField}`,
21718
- `0x${commitmentX}`,
21719
- `0x${commitmentY}`,
21720
- `0x${nullifier}`,
21721
- `0x${params.timestamp.toString(16).padStart(16, "0")}`,
21722
- `0x${params.expiry.toString(16).padStart(16, "0")}`
21723
- ];
21724
- const proof = {
21725
- type: "validity",
21726
- proof: `0x${bytesToHex11(proofData.proof)}`,
21727
- publicInputs
21728
- };
21729
- return { proof, publicInputs };
21730
- } catch (error) {
21731
- const message = error instanceof Error ? error.message : String(error);
21732
- throw new ProofGenerationError(
21733
- "validity",
21734
- `Failed to generate validity proof: ${message}`,
21735
- error instanceof Error ? error : void 0
21736
- );
21737
- }
21660
+ return this.acquireWasmLock(async () => {
21661
+ try {
21662
+ onProgress?.({
21663
+ stage: "witness",
21664
+ percent: 10,
21665
+ message: "Preparing validity witness..."
21666
+ });
21667
+ const intentHashField = this.hexToField(params.intentHash);
21668
+ const senderAddressField = this.hexToField(params.senderAddress);
21669
+ const senderBlindingField = this.bytesToField(params.senderBlinding);
21670
+ const senderSecretField = this.bytesToField(params.senderSecret);
21671
+ const nonceField = this.bytesToField(params.nonce);
21672
+ const { commitmentX, commitmentY } = await this.computeSenderCommitment(
21673
+ senderAddressField,
21674
+ senderBlindingField
21675
+ );
21676
+ const nullifier = await this.computeNullifier(senderSecretField, intentHashField, nonceField);
21677
+ const signature = Array.from(params.authorizationSignature);
21678
+ const messageHash = this.fieldToBytes32(intentHashField);
21679
+ let pubKeyX;
21680
+ let pubKeyY;
21681
+ if (params.senderPublicKey) {
21682
+ pubKeyX = Array.from(params.senderPublicKey.x);
21683
+ pubKeyY = Array.from(params.senderPublicKey.y);
21684
+ } else {
21685
+ const coords = this.getPublicKeyCoordinates(params.senderSecret);
21686
+ pubKeyX = coords.x;
21687
+ pubKeyY = coords.y;
21688
+ }
21689
+ const witnessInputs = {
21690
+ intent_hash: intentHashField,
21691
+ sender_commitment_x: commitmentX,
21692
+ sender_commitment_y: commitmentY,
21693
+ nullifier,
21694
+ timestamp: params.timestamp.toString(),
21695
+ expiry: params.expiry.toString(),
21696
+ sender_address: senderAddressField,
21697
+ sender_blinding: senderBlindingField,
21698
+ sender_secret: senderSecretField,
21699
+ pub_key_x: pubKeyX,
21700
+ pub_key_y: pubKeyY,
21701
+ signature,
21702
+ message_hash: messageHash,
21703
+ nonce: nonceField
21704
+ };
21705
+ onProgress?.({
21706
+ stage: "witness",
21707
+ percent: 30,
21708
+ message: "Generating witness..."
21709
+ });
21710
+ const { witness } = await this.validityNoir.execute(witnessInputs);
21711
+ onProgress?.({
21712
+ stage: "proving",
21713
+ percent: 50,
21714
+ message: "Generating validity proof..."
21715
+ });
21716
+ const proofData = await this.validityBackend.generateProof(witness);
21717
+ onProgress?.({
21718
+ stage: "complete",
21719
+ percent: 100,
21720
+ message: "Validity proof generated"
21721
+ });
21722
+ const publicInputs = [
21723
+ `0x${intentHashField}`,
21724
+ `0x${commitmentX}`,
21725
+ `0x${commitmentY}`,
21726
+ `0x${nullifier}`,
21727
+ `0x${params.timestamp.toString(16).padStart(16, "0")}`,
21728
+ `0x${params.expiry.toString(16).padStart(16, "0")}`
21729
+ ];
21730
+ const proof = {
21731
+ type: "validity",
21732
+ proof: `0x${bytesToHex11(proofData.proof)}`,
21733
+ publicInputs
21734
+ };
21735
+ return { proof, publicInputs };
21736
+ } catch (error) {
21737
+ const message = error instanceof Error ? error.message : String(error);
21738
+ throw new ProofGenerationError(
21739
+ "validity",
21740
+ `Failed to generate validity proof: ${message}`,
21741
+ error instanceof Error ? error : void 0
21742
+ );
21743
+ }
21744
+ });
21738
21745
  }
21739
21746
  /**
21740
21747
  * Generate a Fulfillment Proof
@@ -21746,95 +21753,97 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
21746
21753
  if (!this.fulfillmentNoir || !this.fulfillmentBackend) {
21747
21754
  throw new ProofGenerationError("fulfillment", "Fulfillment circuit not initialized");
21748
21755
  }
21749
- try {
21750
- onProgress?.({
21751
- stage: "witness",
21752
- percent: 10,
21753
- message: "Preparing fulfillment witness..."
21754
- });
21755
- const intentHashField = this.hexToField(params.intentHash);
21756
- const recipientStealthField = this.hexToField(params.recipientStealth);
21757
- const { commitmentX, commitmentY } = await this.computeOutputCommitment(
21758
- params.outputAmount,
21759
- params.outputBlinding
21760
- );
21761
- const solverSecretField = this.bytesToField(params.solverSecret);
21762
- const solverId = await this.computeSolverId(solverSecretField);
21763
- const outputBlindingField = this.bytesToField(params.outputBlinding);
21764
- const attestation = params.oracleAttestation;
21765
- const attestationRecipientField = this.hexToField(attestation.recipient);
21766
- const attestationTxHashField = this.hexToField(attestation.txHash);
21767
- const oracleSignature = Array.from(attestation.signature);
21768
- const oracleMessageHash = await this.computeOracleMessageHash(
21769
- attestation.recipient,
21770
- attestation.amount,
21771
- attestation.txHash,
21772
- attestation.blockNumber
21773
- );
21774
- const oraclePubKeyX = this.config.oraclePublicKey?.x ?? new Array(32).fill(0);
21775
- const oraclePubKeyY = this.config.oraclePublicKey?.y ?? new Array(32).fill(0);
21776
- const witnessInputs = {
21777
- intent_hash: intentHashField,
21778
- output_commitment_x: commitmentX,
21779
- output_commitment_y: commitmentY,
21780
- recipient_stealth: recipientStealthField,
21781
- min_output_amount: params.minOutputAmount.toString(),
21782
- solver_id: solverId,
21783
- fulfillment_time: params.fulfillmentTime.toString(),
21784
- expiry: params.expiry.toString(),
21785
- output_amount: params.outputAmount.toString(),
21786
- output_blinding: outputBlindingField,
21787
- solver_secret: solverSecretField,
21788
- attestation_recipient: attestationRecipientField,
21789
- attestation_amount: attestation.amount.toString(),
21790
- attestation_tx_hash: attestationTxHashField,
21791
- attestation_block: attestation.blockNumber.toString(),
21792
- oracle_signature: oracleSignature,
21793
- oracle_message_hash: oracleMessageHash,
21794
- oracle_pub_key_x: oraclePubKeyX,
21795
- oracle_pub_key_y: oraclePubKeyY
21796
- };
21797
- onProgress?.({
21798
- stage: "witness",
21799
- percent: 30,
21800
- message: "Generating witness..."
21801
- });
21802
- const { witness } = await this.fulfillmentNoir.execute(witnessInputs);
21803
- onProgress?.({
21804
- stage: "proving",
21805
- percent: 50,
21806
- message: "Generating fulfillment proof..."
21807
- });
21808
- const proofData = await this.fulfillmentBackend.generateProof(witness);
21809
- onProgress?.({
21810
- stage: "complete",
21811
- percent: 100,
21812
- message: "Fulfillment proof generated"
21813
- });
21814
- const publicInputs = [
21815
- `0x${intentHashField}`,
21816
- `0x${commitmentX}`,
21817
- `0x${commitmentY}`,
21818
- `0x${recipientStealthField}`,
21819
- `0x${params.minOutputAmount.toString(16).padStart(16, "0")}`,
21820
- `0x${solverId}`,
21821
- `0x${params.fulfillmentTime.toString(16).padStart(16, "0")}`,
21822
- `0x${params.expiry.toString(16).padStart(16, "0")}`
21823
- ];
21824
- const proof = {
21825
- type: "fulfillment",
21826
- proof: `0x${bytesToHex11(proofData.proof)}`,
21827
- publicInputs
21828
- };
21829
- return { proof, publicInputs };
21830
- } catch (error) {
21831
- const message = error instanceof Error ? error.message : String(error);
21832
- throw new ProofGenerationError(
21833
- "fulfillment",
21834
- `Failed to generate fulfillment proof: ${message}`,
21835
- error instanceof Error ? error : void 0
21836
- );
21837
- }
21756
+ return this.acquireWasmLock(async () => {
21757
+ try {
21758
+ onProgress?.({
21759
+ stage: "witness",
21760
+ percent: 10,
21761
+ message: "Preparing fulfillment witness..."
21762
+ });
21763
+ const intentHashField = this.hexToField(params.intentHash);
21764
+ const recipientStealthField = this.hexToField(params.recipientStealth);
21765
+ const { commitmentX, commitmentY } = await this.computeOutputCommitment(
21766
+ params.outputAmount,
21767
+ params.outputBlinding
21768
+ );
21769
+ const solverSecretField = this.bytesToField(params.solverSecret);
21770
+ const solverId = await this.computeSolverId(solverSecretField);
21771
+ const outputBlindingField = this.bytesToField(params.outputBlinding);
21772
+ const attestation = params.oracleAttestation;
21773
+ const attestationRecipientField = this.hexToField(attestation.recipient);
21774
+ const attestationTxHashField = this.hexToField(attestation.txHash);
21775
+ const oracleSignature = Array.from(attestation.signature);
21776
+ const oracleMessageHash = await this.computeOracleMessageHash(
21777
+ attestation.recipient,
21778
+ attestation.amount,
21779
+ attestation.txHash,
21780
+ attestation.blockNumber
21781
+ );
21782
+ const oraclePubKeyX = this.config.oraclePublicKey?.x ?? new Array(32).fill(0);
21783
+ const oraclePubKeyY = this.config.oraclePublicKey?.y ?? new Array(32).fill(0);
21784
+ const witnessInputs = {
21785
+ intent_hash: intentHashField,
21786
+ output_commitment_x: commitmentX,
21787
+ output_commitment_y: commitmentY,
21788
+ recipient_stealth: recipientStealthField,
21789
+ min_output_amount: params.minOutputAmount.toString(),
21790
+ solver_id: solverId,
21791
+ fulfillment_time: params.fulfillmentTime.toString(),
21792
+ expiry: params.expiry.toString(),
21793
+ output_amount: params.outputAmount.toString(),
21794
+ output_blinding: outputBlindingField,
21795
+ solver_secret: solverSecretField,
21796
+ attestation_recipient: attestationRecipientField,
21797
+ attestation_amount: attestation.amount.toString(),
21798
+ attestation_tx_hash: attestationTxHashField,
21799
+ attestation_block: attestation.blockNumber.toString(),
21800
+ oracle_signature: oracleSignature,
21801
+ oracle_message_hash: oracleMessageHash,
21802
+ oracle_pub_key_x: oraclePubKeyX,
21803
+ oracle_pub_key_y: oraclePubKeyY
21804
+ };
21805
+ onProgress?.({
21806
+ stage: "witness",
21807
+ percent: 30,
21808
+ message: "Generating witness..."
21809
+ });
21810
+ const { witness } = await this.fulfillmentNoir.execute(witnessInputs);
21811
+ onProgress?.({
21812
+ stage: "proving",
21813
+ percent: 50,
21814
+ message: "Generating fulfillment proof..."
21815
+ });
21816
+ const proofData = await this.fulfillmentBackend.generateProof(witness);
21817
+ onProgress?.({
21818
+ stage: "complete",
21819
+ percent: 100,
21820
+ message: "Fulfillment proof generated"
21821
+ });
21822
+ const publicInputs = [
21823
+ `0x${intentHashField}`,
21824
+ `0x${commitmentX}`,
21825
+ `0x${commitmentY}`,
21826
+ `0x${recipientStealthField}`,
21827
+ `0x${params.minOutputAmount.toString(16).padStart(16, "0")}`,
21828
+ `0x${solverId}`,
21829
+ `0x${params.fulfillmentTime.toString(16).padStart(16, "0")}`,
21830
+ `0x${params.expiry.toString(16).padStart(16, "0")}`
21831
+ ];
21832
+ const proof = {
21833
+ type: "fulfillment",
21834
+ proof: `0x${bytesToHex11(proofData.proof)}`,
21835
+ publicInputs
21836
+ };
21837
+ return { proof, publicInputs };
21838
+ } catch (error) {
21839
+ const message = error instanceof Error ? error.message : String(error);
21840
+ throw new ProofGenerationError(
21841
+ "fulfillment",
21842
+ `Failed to generate fulfillment proof: ${message}`,
21843
+ error instanceof Error ? error : void 0
21844
+ );
21845
+ }
21846
+ });
21838
21847
  }
21839
21848
  /**
21840
21849
  * Verify a proof
@@ -21861,22 +21870,25 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
21861
21870
  "SIP_4004" /* PROOF_PROVIDER_NOT_READY */
21862
21871
  );
21863
21872
  }
21864
- try {
21865
- const proofHex = proof.proof.startsWith("0x") ? proof.proof.slice(2) : proof.proof;
21866
- const proofBytes = hexToBytes9(proofHex);
21867
- const isValid = await backend.verifyProof({
21868
- proof: proofBytes,
21869
- publicInputs: proof.publicInputs.map(
21870
- (input) => input.startsWith("0x") ? input.slice(2) : input
21871
- )
21872
- });
21873
- return isValid;
21874
- } catch (error) {
21875
- if (this.config.verbose) {
21876
- console.error("[BrowserNoirProvider] Verification error:", error);
21873
+ const backendToUse = backend;
21874
+ return this.acquireWasmLock(async () => {
21875
+ try {
21876
+ const proofHex = proof.proof.startsWith("0x") ? proof.proof.slice(2) : proof.proof;
21877
+ const proofBytes = hexToBytes9(proofHex);
21878
+ const isValid = await backendToUse.verifyProof({
21879
+ proof: proofBytes,
21880
+ publicInputs: proof.publicInputs.map(
21881
+ (input) => input.startsWith("0x") ? input.slice(2) : input
21882
+ )
21883
+ });
21884
+ return isValid;
21885
+ } catch (error) {
21886
+ if (this.config.verbose) {
21887
+ console.error("[BrowserNoirProvider] Verification error:", error);
21888
+ }
21889
+ return false;
21877
21890
  }
21878
- return false;
21879
- }
21891
+ });
21880
21892
  }
21881
21893
  /**
21882
21894
  * Destroy the provider and free resources
@@ -21904,6 +21916,25 @@ var BrowserNoirProvider = class _BrowserNoirProvider {
21904
21916
  this._isReady = false;
21905
21917
  }
21906
21918
  // ─── Private Utility Methods ────────────────────────────────────────────────
21919
+ /**
21920
+ * Acquire WASM mutex lock for exclusive access
21921
+ *
21922
+ * The ACVM WASM module uses Rust RefCell internally which panics on
21923
+ * concurrent mutable borrows. This mutex ensures serial execution.
21924
+ */
21925
+ async acquireWasmLock(operation) {
21926
+ const previousLock = this.wasmMutex;
21927
+ let releaseLock;
21928
+ this.wasmMutex = new Promise((resolve) => {
21929
+ releaseLock = resolve;
21930
+ });
21931
+ try {
21932
+ await previousLock;
21933
+ return await operation();
21934
+ } finally {
21935
+ releaseLock();
21936
+ }
21937
+ }
21907
21938
  ensureReady() {
21908
21939
  if (!this._isReady) {
21909
21940
  throw new ProofError(