signet.js 0.2.0 → 0.3.1-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +317 -136
- package/dist/index.d.cts +161 -39
- package/dist/index.d.ts +162 -39
- package/dist/index.js +318 -137
- package/package.json +15 -15
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as __export } from "./chunk-BAz01cYq.js";
|
|
2
2
|
import { base58 } from "@scure/base";
|
|
3
3
|
import elliptic from "elliptic";
|
|
4
|
-
import { concat, concatHex, createPublicClient, encodeAbiParameters, encodeFunctionData, getAddress, hashMessage, hashTypedData, hexToBigInt, http, isAddress, keccak256, numberToHex, pad, parseAbiParameters, parseTransaction, recoverAddress, serializeTransaction, toBytes, withRetry } from "viem";
|
|
4
|
+
import { concat, concatHex, createPublicClient, encodeAbiParameters, encodeFunctionData, encodePacked, getAddress, hashMessage, hashTypedData, hexToBigInt, http, isAddress, keccak256, numberToHex, pad, parseAbiParameters, parseTransaction, recoverAddress, serializeTransaction, toBytes, withRetry } from "viem";
|
|
5
5
|
import * as bitcoin from "bitcoinjs-lib";
|
|
6
6
|
import coinselect from "coinselect";
|
|
7
7
|
import { encodeSecp256k1Pubkey } from "@cosmjs/amino";
|
|
@@ -134,7 +134,7 @@ const EPSILON_DERIVATION_PREFIX_V2 = "sig.network v2.0.0 epsilon derivation";
|
|
|
134
134
|
* @param keyVersion - Key version controlling which derivation prefix to use (legacy v1 for 0, CAIP-2 v2 otherwise)
|
|
135
135
|
* @returns The derived child public key in uncompressed SEC1 format (04 || x || y)
|
|
136
136
|
*/
|
|
137
|
-
function deriveChildPublicKey(rootUncompressedPubKeySEC1, predecessorId, path = "", chainId,
|
|
137
|
+
function deriveChildPublicKey(rootUncompressedPubKeySEC1, predecessorId, path = "", chainId, _keyVersion) {
|
|
138
138
|
const ec = new EC("secp256k1");
|
|
139
139
|
const derivationPath = `${EPSILON_DERIVATION_PREFIX_V2}:${chainId}:${predecessorId}:${path}`;
|
|
140
140
|
let scalarHex = "";
|
|
@@ -219,7 +219,7 @@ var EVM = class extends ChainAdapter {
|
|
|
219
219
|
async attachGasAndNonce(transaction) {
|
|
220
220
|
const fees = await fetchEVMFeeProperties(this.client, transaction);
|
|
221
221
|
const nonce = await this.client.getTransactionCount({ address: transaction.from });
|
|
222
|
-
const { from, ...rest } = transaction;
|
|
222
|
+
const { from: _from, ...rest } = transaction;
|
|
223
223
|
return {
|
|
224
224
|
...fees,
|
|
225
225
|
nonce,
|
|
@@ -1348,7 +1348,39 @@ const getRootPublicKey = (contractAddress, chain) => {
|
|
|
1348
1348
|
|
|
1349
1349
|
//#endregion
|
|
1350
1350
|
//#region src/contracts/evm/utils.ts
|
|
1351
|
-
|
|
1351
|
+
/**
|
|
1352
|
+
* Generates a unique request ID for EVM signature requests using keccak256 hashing.
|
|
1353
|
+
*
|
|
1354
|
+
* The request ID is computed by ABI-encoding the request parameters and hashing
|
|
1355
|
+
* the result. This ID is used to track signature requests and match them with
|
|
1356
|
+
* responses from the MPC network.
|
|
1357
|
+
*
|
|
1358
|
+
* @param request - The signature request parameters
|
|
1359
|
+
* @param request.address - The address of the requester (EVM address format)
|
|
1360
|
+
* @param request.payload - The data payload to be signed as a hex string
|
|
1361
|
+
* @param request.path - The derivation path for the signing key
|
|
1362
|
+
* @param request.keyVersion - The version of the signing key
|
|
1363
|
+
* @param request.chainId - The chain ID where the request originated
|
|
1364
|
+
* @param request.algo - The signing algorithm identifier
|
|
1365
|
+
* @param request.dest - The destination identifier for the signature
|
|
1366
|
+
* @param request.params - Additional parameters for the signing process
|
|
1367
|
+
* @returns The keccak256 hash of the encoded request as a hex string
|
|
1368
|
+
*
|
|
1369
|
+
* @example
|
|
1370
|
+
* ```typescript
|
|
1371
|
+
* const requestId = getRequestIdRespond({
|
|
1372
|
+
* address: '0x1234...abcd',
|
|
1373
|
+
* payload: '0xdeadbeef',
|
|
1374
|
+
* path: 'ethereum,1',
|
|
1375
|
+
* keyVersion: 0,
|
|
1376
|
+
* chainId: 1n,
|
|
1377
|
+
* algo: '',
|
|
1378
|
+
* dest: '',
|
|
1379
|
+
* params: '',
|
|
1380
|
+
* })
|
|
1381
|
+
* ```
|
|
1382
|
+
*/
|
|
1383
|
+
const getRequestIdRespond$1 = (request) => {
|
|
1352
1384
|
return keccak256(encodeAbiParameters([
|
|
1353
1385
|
{ type: "address" },
|
|
1354
1386
|
{ type: "bytes" },
|
|
@@ -1555,7 +1587,7 @@ var ChainSignatureContract$2 = class extends ChainSignatureContract {
|
|
|
1555
1587
|
}) {
|
|
1556
1588
|
if (!this.walletClient.account) throw new Error("Wallet client account required to compute requestId");
|
|
1557
1589
|
if (!this.publicClient.chain?.id) throw new Error("Public client chain required to compute requestId");
|
|
1558
|
-
return
|
|
1590
|
+
return getRequestIdRespond$1({
|
|
1559
1591
|
payload: `0x${Buffer.from(args.payload).toString("hex")}`,
|
|
1560
1592
|
path: args.path,
|
|
1561
1593
|
keyVersion: args.key_version,
|
|
@@ -1609,6 +1641,7 @@ var ChainSignatureContract$2 = class extends ChainSignatureContract {
|
|
|
1609
1641
|
//#region src/contracts/evm/index.ts
|
|
1610
1642
|
var evm_exports = /* @__PURE__ */ __export({
|
|
1611
1643
|
ChainSignatureContract: () => ChainSignatureContract$2,
|
|
1644
|
+
getRequestIdRespond: () => getRequestIdRespond$1,
|
|
1612
1645
|
utils: () => utils$1
|
|
1613
1646
|
});
|
|
1614
1647
|
const utils$1 = {
|
|
@@ -2652,24 +2685,33 @@ const EMIT_CPI_INSTRUCTION_DISCRIMINATOR = Buffer.from([
|
|
|
2652
2685
|
]);
|
|
2653
2686
|
var CpiEventParser = class {
|
|
2654
2687
|
/**
|
|
2655
|
-
* Parse CPI events from
|
|
2688
|
+
* Parse CPI events from an already-fetched transaction (emit_cpi! pattern).
|
|
2656
2689
|
*/
|
|
2657
|
-
static
|
|
2690
|
+
static parseCpiEventsFromTransaction(tx, targetProgramId, program) {
|
|
2658
2691
|
const events$1 = [];
|
|
2692
|
+
if (!tx?.meta?.innerInstructions) return events$1;
|
|
2693
|
+
for (const innerIxSet of tx.meta.innerInstructions) for (const instruction of innerIxSet.instructions) {
|
|
2694
|
+
if (!("programId" in instruction) || !("data" in instruction)) continue;
|
|
2695
|
+
if (instruction.programId.toString() !== targetProgramId) continue;
|
|
2696
|
+
const parsedEvent = this.parseInstruction(instruction.data, program);
|
|
2697
|
+
if (parsedEvent) events$1.push(parsedEvent);
|
|
2698
|
+
}
|
|
2699
|
+
return events$1;
|
|
2700
|
+
}
|
|
2701
|
+
/**
|
|
2702
|
+
* Fetch a transaction by signature and parse its CPI events.
|
|
2703
|
+
* Used by the subscription path where only the signature is available.
|
|
2704
|
+
*/
|
|
2705
|
+
static async fetchAndParseCpiEvents(connection, signature, targetProgramId, program) {
|
|
2659
2706
|
try {
|
|
2660
2707
|
const tx = await connection.getParsedTransaction(signature, {
|
|
2661
2708
|
commitment: "confirmed",
|
|
2662
2709
|
maxSupportedTransactionVersion: 0
|
|
2663
2710
|
});
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
const parsedEvent = this.parseInstruction(instruction.data, program);
|
|
2669
|
-
if (parsedEvent) events$1.push(parsedEvent);
|
|
2670
|
-
}
|
|
2671
|
-
} catch {}
|
|
2672
|
-
return events$1;
|
|
2711
|
+
return this.parseCpiEventsFromTransaction(tx, targetProgramId, program);
|
|
2712
|
+
} catch {
|
|
2713
|
+
return [];
|
|
2714
|
+
}
|
|
2673
2715
|
}
|
|
2674
2716
|
/**
|
|
2675
2717
|
* Parse CPI event from instruction data
|
|
@@ -2699,7 +2741,7 @@ var CpiEventParser = class {
|
|
|
2699
2741
|
return connection.onLogs(program.programId, (logs, context) => {
|
|
2700
2742
|
if (logs.err) return;
|
|
2701
2743
|
(async () => {
|
|
2702
|
-
const events$1 = await this.
|
|
2744
|
+
const events$1 = await this.fetchAndParseCpiEvents(connection, logs.signature, program.programId.toString(), program);
|
|
2703
2745
|
for (const event of events$1) {
|
|
2704
2746
|
const handler = eventHandlers.get(event.name);
|
|
2705
2747
|
if (handler) try {
|
|
@@ -2713,17 +2755,103 @@ var CpiEventParser = class {
|
|
|
2713
2755
|
|
|
2714
2756
|
//#endregion
|
|
2715
2757
|
//#region src/contracts/solana/utils.ts
|
|
2716
|
-
|
|
2717
|
-
|
|
2758
|
+
/**
|
|
2759
|
+
* Generates a unique request ID for Solana signature requests using keccak256 hashing.
|
|
2760
|
+
*
|
|
2761
|
+
* The request ID is computed by ABI-encoding the request parameters and hashing
|
|
2762
|
+
* the result. This ID is used to track signature requests and match them with
|
|
2763
|
+
* responses from the MPC network.
|
|
2764
|
+
*
|
|
2765
|
+
* @param request - The signature request parameters
|
|
2766
|
+
* @param request.address - The sender's address (Solana public key as string)
|
|
2767
|
+
* @param request.payload - The data payload to be signed
|
|
2768
|
+
* @param request.path - The derivation path for the signing key
|
|
2769
|
+
* @param request.keyVersion - The version of the signing key
|
|
2770
|
+
* @param request.chainId - The CAIP-2 chain identifier (e.g., 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp')
|
|
2771
|
+
* @param request.algo - The signing algorithm identifier
|
|
2772
|
+
* @param request.dest - The destination identifier for the signature
|
|
2773
|
+
* @param request.params - Additional parameters for the signing process
|
|
2774
|
+
* @returns The keccak256 hash of the encoded request as a hex string
|
|
2775
|
+
*
|
|
2776
|
+
* @example
|
|
2777
|
+
* ```typescript
|
|
2778
|
+
* const requestId = getRequestIdRespond({
|
|
2779
|
+
* address: 'So11111111111111111111111111111111111111112',
|
|
2780
|
+
* payload: new Uint8Array([1, 2, 3, 4]),
|
|
2781
|
+
* path: 'solana,1',
|
|
2782
|
+
* keyVersion: 0,
|
|
2783
|
+
* chainId: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
|
|
2784
|
+
* algo: '',
|
|
2785
|
+
* dest: '',
|
|
2786
|
+
* params: '',
|
|
2787
|
+
* })
|
|
2788
|
+
* ```
|
|
2789
|
+
*/
|
|
2790
|
+
function getRequestIdRespond(request) {
|
|
2791
|
+
const payloadHex = "0x" + Buffer.from(request.payload).toString("hex");
|
|
2718
2792
|
return keccak256(encodeAbiParameters(parseAbiParameters("string, bytes, string, uint32, string, string, string, string"), [
|
|
2719
|
-
address
|
|
2793
|
+
request.address,
|
|
2794
|
+
payloadHex,
|
|
2795
|
+
request.path,
|
|
2796
|
+
request.keyVersion,
|
|
2797
|
+
request.chainId,
|
|
2798
|
+
request.algo,
|
|
2799
|
+
request.dest,
|
|
2800
|
+
request.params
|
|
2801
|
+
]));
|
|
2802
|
+
}
|
|
2803
|
+
/**
|
|
2804
|
+
* Generates a unique request ID for bidirectional sign operations using keccak256 hashing.
|
|
2805
|
+
*
|
|
2806
|
+
* Unlike `getRequestIdRespond`, this function uses packed encoding (solidityPacked)
|
|
2807
|
+
* instead of standard ABI encoding. This is used for cross-chain bidirectional
|
|
2808
|
+
* signing flows where the request originates from a different chain.
|
|
2809
|
+
*
|
|
2810
|
+
* @param request - The bidirectional signature request parameters
|
|
2811
|
+
* @param request.sender - The sender's address (Solana public key as string)
|
|
2812
|
+
* @param request.payload - The data payload to be signed
|
|
2813
|
+
* @param request.caip2Id - The CAIP-2 chain identifier (e.g., 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp')
|
|
2814
|
+
* @param request.keyVersion - The version of the signing key
|
|
2815
|
+
* @param request.path - The derivation path for the signing key
|
|
2816
|
+
* @param request.algo - The signing algorithm identifier
|
|
2817
|
+
* @param request.dest - The destination identifier for the signature
|
|
2818
|
+
* @param request.params - Additional parameters for the signing process
|
|
2819
|
+
* @returns The keccak256 hash of the packed encoded request as a hex string
|
|
2820
|
+
*
|
|
2821
|
+
* @example
|
|
2822
|
+
* ```typescript
|
|
2823
|
+
* const requestId = getRequestIdBidirectional({
|
|
2824
|
+
* sender: 'So11111111111111111111111111111111111111112',
|
|
2825
|
+
* payload: new Uint8Array([1, 2, 3, 4]),
|
|
2826
|
+
* caip2Id: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
|
|
2827
|
+
* keyVersion: 0,
|
|
2828
|
+
* path: 'ethereum,1',
|
|
2829
|
+
* algo: '',
|
|
2830
|
+
* dest: '',
|
|
2831
|
+
* params: '',
|
|
2832
|
+
* })
|
|
2833
|
+
* ```
|
|
2834
|
+
*/
|
|
2835
|
+
function getRequestIdBidirectional(request) {
|
|
2836
|
+
const payloadHex = `0x${Buffer.from(request.payload).toString("hex")}`;
|
|
2837
|
+
return keccak256(encodePacked([
|
|
2838
|
+
"string",
|
|
2839
|
+
"bytes",
|
|
2840
|
+
"string",
|
|
2841
|
+
"uint32",
|
|
2842
|
+
"string",
|
|
2843
|
+
"string",
|
|
2844
|
+
"string",
|
|
2845
|
+
"string"
|
|
2846
|
+
], [
|
|
2847
|
+
request.sender,
|
|
2720
2848
|
payloadHex,
|
|
2721
|
-
|
|
2722
|
-
keyVersion,
|
|
2723
|
-
|
|
2724
|
-
algo,
|
|
2725
|
-
dest,
|
|
2726
|
-
params
|
|
2849
|
+
request.caip2Id,
|
|
2850
|
+
request.keyVersion,
|
|
2851
|
+
request.path,
|
|
2852
|
+
request.algo,
|
|
2853
|
+
request.dest,
|
|
2854
|
+
request.params
|
|
2727
2855
|
]));
|
|
2728
2856
|
}
|
|
2729
2857
|
|
|
@@ -2799,15 +2927,15 @@ var ChainSignatureContract$1 = class extends ChainSignatureContract {
|
|
|
2799
2927
|
}
|
|
2800
2928
|
/**
|
|
2801
2929
|
* Sends a transaction to the program to request a signature, then
|
|
2802
|
-
*
|
|
2803
|
-
*
|
|
2930
|
+
* races a WebSocket listener against polling backfill to find the result.
|
|
2931
|
+
* If the signature is not found within the timeout, it will throw an error.
|
|
2804
2932
|
*/
|
|
2805
2933
|
async sign(args, options) {
|
|
2806
2934
|
const algo = options?.sign?.algo ?? "";
|
|
2807
2935
|
const dest = options?.sign?.dest ?? "";
|
|
2808
2936
|
const params = options?.sign?.params ?? "";
|
|
2809
2937
|
const delay = options?.retry?.delay ?? 5e3;
|
|
2810
|
-
const
|
|
2938
|
+
const timeoutMs = delay * (options?.retry?.retryCount ?? 12);
|
|
2811
2939
|
if (options?.remainingAccounts?.filter((acc) => acc.isSigner)?.some((acc) => !options?.remainingSigners?.some((signer) => signer.publicKey.equals(acc.pubkey)))) throw new Error("All accounts marked as signers must have a corresponding signer");
|
|
2812
2940
|
const requestId = this.getRequestId(args, {
|
|
2813
2941
|
algo,
|
|
@@ -2825,24 +2953,38 @@ var ChainSignatureContract$1 = class extends ChainSignatureContract {
|
|
|
2825
2953
|
const transaction = new Transaction().add(instruction);
|
|
2826
2954
|
transaction.feePayer = this.provider.wallet.publicKey;
|
|
2827
2955
|
const hash = await this.sendAndConfirmWithoutWebSocket(transaction, options?.remainingSigners);
|
|
2956
|
+
const controller = new AbortController();
|
|
2957
|
+
const successPromise = this.waitForEvent({
|
|
2958
|
+
eventName: "signatureRespondedEvent",
|
|
2959
|
+
requestId,
|
|
2960
|
+
signer: this.programId,
|
|
2961
|
+
afterSignature: hash,
|
|
2962
|
+
timeoutMs,
|
|
2963
|
+
backfillIntervalMs: delay,
|
|
2964
|
+
signal: controller.signal
|
|
2965
|
+
});
|
|
2966
|
+
const errorPromise = this.waitForEvent({
|
|
2967
|
+
eventName: "signatureErrorEvent",
|
|
2968
|
+
requestId,
|
|
2969
|
+
signer: this.programId,
|
|
2970
|
+
afterSignature: hash,
|
|
2971
|
+
timeoutMs,
|
|
2972
|
+
backfillIntervalMs: delay,
|
|
2973
|
+
signal: controller.signal
|
|
2974
|
+
}).then((err) => {
|
|
2975
|
+
throw new SignatureContractError(err.error, requestId, { hash });
|
|
2976
|
+
});
|
|
2977
|
+
successPromise.catch(() => {});
|
|
2978
|
+
errorPromise.catch(() => {});
|
|
2828
2979
|
try {
|
|
2829
|
-
const
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
path: args.path,
|
|
2833
|
-
afterSignature: hash,
|
|
2834
|
-
options: {
|
|
2835
|
-
delay,
|
|
2836
|
-
retryCount
|
|
2837
|
-
}
|
|
2838
|
-
});
|
|
2839
|
-
if (!pollResult) throw new SignatureNotFoundError(requestId, { hash });
|
|
2840
|
-
if ("error" in pollResult) throw new SignatureContractError(pollResult.error, requestId, { hash });
|
|
2841
|
-
if (!await verifyRecoveredAddress(pollResult, args.payload, this.requesterAddress, args.path, this, args.key_version)) throw new SigningError(requestId, { hash }, /* @__PURE__ */ new Error("Signature verification failed: recovered address does not match expected address"));
|
|
2842
|
-
return pollResult;
|
|
2980
|
+
const result = await Promise.race([successPromise, errorPromise]);
|
|
2981
|
+
if (!await verifyRecoveredAddress(result, args.payload, this.requesterAddress, args.path, this, args.key_version)) throw new SigningError(requestId, { hash }, /* @__PURE__ */ new Error("Signature verification failed: recovered address does not match expected address"));
|
|
2982
|
+
return result;
|
|
2843
2983
|
} catch (error) {
|
|
2844
2984
|
if (error instanceof SignatureNotFoundError || error instanceof SignatureContractError) throw error;
|
|
2845
2985
|
else throw new SigningError(requestId, { hash }, error instanceof Error ? error : void 0);
|
|
2986
|
+
} finally {
|
|
2987
|
+
controller.abort();
|
|
2846
2988
|
}
|
|
2847
2989
|
}
|
|
2848
2990
|
async sendAndConfirmWithoutWebSocket(transaction, signers) {
|
|
@@ -2866,70 +3008,147 @@ var ChainSignatureContract$1 = class extends ChainSignatureContract {
|
|
|
2866
3008
|
throw new TransactionExpiredTimeoutError(signature, timeout / 1e3);
|
|
2867
3009
|
}
|
|
2868
3010
|
/**
|
|
2869
|
-
*
|
|
2870
|
-
*
|
|
3011
|
+
* Waits for a specific event matching the given requestId by combining
|
|
3012
|
+
* a WebSocket listener (real-time) with polling backfill (resilience).
|
|
2871
3013
|
*/
|
|
2872
|
-
async
|
|
2873
|
-
const
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
3014
|
+
async waitForEvent(options) {
|
|
3015
|
+
const { eventName, requestId, signer, afterSignature, timeoutMs = 6e4, backfillIntervalMs = 5e3, backfillLimit = 50, signal } = options;
|
|
3016
|
+
return await new Promise((resolve, reject) => {
|
|
3017
|
+
let settled = false;
|
|
3018
|
+
const seenSignatures = /* @__PURE__ */ new Set();
|
|
3019
|
+
let lastCheckedSignature = afterSignature;
|
|
3020
|
+
const cleanupFns = [];
|
|
3021
|
+
const cleanup = () => {
|
|
3022
|
+
for (const fn of cleanupFns) try {
|
|
3023
|
+
fn();
|
|
3024
|
+
} catch {}
|
|
3025
|
+
};
|
|
3026
|
+
const settle = (action) => {
|
|
3027
|
+
if (settled) return;
|
|
3028
|
+
settled = true;
|
|
3029
|
+
cleanup();
|
|
3030
|
+
action();
|
|
3031
|
+
};
|
|
3032
|
+
const processEvent = (name, data, txSignature) => {
|
|
3033
|
+
if (settled) return false;
|
|
3034
|
+
if (txSignature && seenSignatures.has(txSignature)) return false;
|
|
3035
|
+
if (txSignature) seenSignatures.add(txSignature);
|
|
3036
|
+
if (name !== eventName) return false;
|
|
3037
|
+
const result = this.mapEventForName(eventName, data, requestId);
|
|
3038
|
+
if (result !== void 0) {
|
|
3039
|
+
settle(() => {
|
|
3040
|
+
resolve(result);
|
|
2887
3041
|
});
|
|
2888
|
-
|
|
2889
|
-
const result = await this.parseLogsForEvents(tx.meta.logMessages, requestId, sig.signature);
|
|
2890
|
-
if (result) return result;
|
|
2891
|
-
}
|
|
3042
|
+
return true;
|
|
2892
3043
|
}
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
3044
|
+
return false;
|
|
3045
|
+
};
|
|
3046
|
+
if (signal) {
|
|
3047
|
+
if (signal.aborted) {
|
|
3048
|
+
settle(() => {
|
|
3049
|
+
reject(signal.reason ?? /* @__PURE__ */ new Error("Aborted"));
|
|
3050
|
+
});
|
|
3051
|
+
return;
|
|
3052
|
+
}
|
|
3053
|
+
const onAbort = () => {
|
|
3054
|
+
settle(() => {
|
|
3055
|
+
reject(signal.reason ?? /* @__PURE__ */ new Error("Aborted"));
|
|
3056
|
+
});
|
|
3057
|
+
};
|
|
3058
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
3059
|
+
cleanupFns.push(() => {
|
|
3060
|
+
signal.removeEventListener("abort", onAbort);
|
|
3061
|
+
});
|
|
2899
3062
|
}
|
|
2900
|
-
|
|
3063
|
+
const timeoutId = setTimeout(() => {
|
|
3064
|
+
settle(() => {
|
|
3065
|
+
reject(new SignatureNotFoundError(requestId));
|
|
3066
|
+
});
|
|
3067
|
+
}, timeoutMs);
|
|
3068
|
+
cleanupFns.push(() => {
|
|
3069
|
+
clearTimeout(timeoutId);
|
|
3070
|
+
});
|
|
3071
|
+
const parser = new EventParser(this.program.programId, this.program.coder);
|
|
3072
|
+
const subId = this.connection.onLogs(signer, (logs, _context) => {
|
|
3073
|
+
if (settled) return;
|
|
3074
|
+
if (logs.err) return;
|
|
3075
|
+
for (const evt of parser.parseLogs(logs.logs)) {
|
|
3076
|
+
if (!evt) continue;
|
|
3077
|
+
if (processEvent(evt.name, evt.data, logs.signature)) return;
|
|
3078
|
+
}
|
|
3079
|
+
CpiEventParser.fetchAndParseCpiEvents(this.connection, logs.signature, this.programId.toString(), this.program).then((cpiEvents) => {
|
|
3080
|
+
for (const event of cpiEvents) if (processEvent(event.name, event.data, logs.signature)) return;
|
|
3081
|
+
});
|
|
3082
|
+
}, "confirmed");
|
|
3083
|
+
cleanupFns.push(() => {
|
|
3084
|
+
this.connection.removeOnLogsListener(subId);
|
|
3085
|
+
});
|
|
3086
|
+
const runBackfill = async () => {
|
|
3087
|
+
if (settled) return;
|
|
3088
|
+
try {
|
|
3089
|
+
const signatures = await this.connection.getSignaturesForAddress(signer, {
|
|
3090
|
+
until: lastCheckedSignature,
|
|
3091
|
+
limit: backfillLimit
|
|
3092
|
+
}, "confirmed");
|
|
3093
|
+
if (signatures.length > 0) lastCheckedSignature = signatures[0].signature;
|
|
3094
|
+
for (const sig of signatures) {
|
|
3095
|
+
if (settled) return;
|
|
3096
|
+
if (seenSignatures.has(sig.signature)) continue;
|
|
3097
|
+
const tx = await this.connection.getParsedTransaction(sig.signature, {
|
|
3098
|
+
commitment: "confirmed",
|
|
3099
|
+
maxSupportedTransactionVersion: 0
|
|
3100
|
+
});
|
|
3101
|
+
if (!tx) continue;
|
|
3102
|
+
const cpiEvents = CpiEventParser.parseCpiEventsFromTransaction(tx, this.programId.toString(), this.program);
|
|
3103
|
+
for (const event of cpiEvents) if (processEvent(event.name, event.data, sig.signature)) return;
|
|
3104
|
+
const logs = tx.meta?.logMessages;
|
|
3105
|
+
if (logs) for (const evt of parser.parseLogs(logs)) {
|
|
3106
|
+
if (!evt) continue;
|
|
3107
|
+
if (processEvent(evt.name, evt.data, sig.signature)) return;
|
|
3108
|
+
}
|
|
3109
|
+
}
|
|
3110
|
+
} catch {}
|
|
3111
|
+
};
|
|
3112
|
+
runBackfill();
|
|
3113
|
+
const intervalId = setInterval(() => {
|
|
3114
|
+
runBackfill();
|
|
3115
|
+
}, backfillIntervalMs);
|
|
3116
|
+
cleanupFns.push(() => {
|
|
3117
|
+
clearInterval(intervalId);
|
|
3118
|
+
});
|
|
3119
|
+
});
|
|
2901
3120
|
}
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
if (mapped) return mapped;
|
|
2910
|
-
}
|
|
2911
|
-
const parser = new EventParser(this.program.programId, this.program.coder);
|
|
2912
|
-
for (const evt of parser.parseLogs(logs)) {
|
|
2913
|
-
if (!evt) continue;
|
|
2914
|
-
const mapped = this.mapEventToResult(evt.name, evt.name === "signatureRespondedEvent" ? evt.data : evt.data, requestId);
|
|
2915
|
-
if (mapped) return mapped;
|
|
2916
|
-
}
|
|
3121
|
+
mapRespondToResult(data, requestId) {
|
|
3122
|
+
if ("0x" + Buffer.from(data.requestId).toString("hex") !== requestId) return void 0;
|
|
3123
|
+
return {
|
|
3124
|
+
r: Buffer.from(data.signature.bigR.x).toString("hex"),
|
|
3125
|
+
s: Buffer.from(data.signature.s).toString("hex"),
|
|
3126
|
+
v: data.signature.recoveryId + 27
|
|
3127
|
+
};
|
|
2917
3128
|
}
|
|
2918
|
-
|
|
3129
|
+
mapRespondErrorToResult(data, requestId) {
|
|
2919
3130
|
const eventRequestIdHex = "0x" + Buffer.from(data.requestId).toString("hex");
|
|
2920
|
-
if (
|
|
2921
|
-
|
|
2922
|
-
return {
|
|
2923
|
-
r: Buffer.from(d.signature.bigR.x).toString("hex"),
|
|
2924
|
-
s: Buffer.from(d.signature.s).toString("hex"),
|
|
2925
|
-
v: d.signature.recoveryId + 27
|
|
2926
|
-
};
|
|
2927
|
-
}
|
|
2928
|
-
if (name === "signatureErrorEvent" && eventRequestIdHex === requestId) return {
|
|
3131
|
+
if (eventRequestIdHex !== requestId) return void 0;
|
|
3132
|
+
return {
|
|
2929
3133
|
requestId: eventRequestIdHex,
|
|
2930
3134
|
error: data.error
|
|
2931
3135
|
};
|
|
2932
3136
|
}
|
|
3137
|
+
mapRespondBidirectionalToResult(data, requestId) {
|
|
3138
|
+
if ("0x" + Buffer.from(data.requestId).toString("hex") !== requestId) return void 0;
|
|
3139
|
+
return {
|
|
3140
|
+
serializedOutput: data.serializedOutput,
|
|
3141
|
+
signature: data.signature
|
|
3142
|
+
};
|
|
3143
|
+
}
|
|
3144
|
+
mapEventForName(eventName, data, requestId) {
|
|
3145
|
+
switch (eventName) {
|
|
3146
|
+
case "signatureRespondedEvent": return this.mapRespondToResult(data, requestId);
|
|
3147
|
+
case "signatureErrorEvent": return this.mapRespondErrorToResult(data, requestId);
|
|
3148
|
+
case "respondBidirectionalEvent": return this.mapRespondBidirectionalToResult(data, requestId);
|
|
3149
|
+
default: return;
|
|
3150
|
+
}
|
|
3151
|
+
}
|
|
2933
3152
|
/**
|
|
2934
3153
|
* Generates the request ID for a signature request allowing to track the response.
|
|
2935
3154
|
*/
|
|
@@ -2938,7 +3157,7 @@ var ChainSignatureContract$1 = class extends ChainSignatureContract {
|
|
|
2938
3157
|
dest: "",
|
|
2939
3158
|
params: ""
|
|
2940
3159
|
}) {
|
|
2941
|
-
return
|
|
3160
|
+
return getRequestIdRespond({
|
|
2942
3161
|
payload: args.payload,
|
|
2943
3162
|
path: args.path,
|
|
2944
3163
|
keyVersion: args.key_version,
|
|
@@ -2949,52 +3168,14 @@ var ChainSignatureContract$1 = class extends ChainSignatureContract {
|
|
|
2949
3168
|
chainId: KDF_CHAIN_IDS.SOLANA
|
|
2950
3169
|
});
|
|
2951
3170
|
}
|
|
2952
|
-
/**
|
|
2953
|
-
* Subscribes to program events using Anchor's EventParser for regular events,
|
|
2954
|
-
* and CPI parsing for emit_cpi!-emitted events. Returns an unsubscribe fn.
|
|
2955
|
-
*/
|
|
2956
|
-
async subscribeToEvents(handlers) {
|
|
2957
|
-
const commitment = "confirmed";
|
|
2958
|
-
const cpiHandlers = /* @__PURE__ */ new Map();
|
|
2959
|
-
if (handlers.onSignatureResponded) {
|
|
2960
|
-
const onSignatureResponded = handlers.onSignatureResponded;
|
|
2961
|
-
cpiHandlers.set("signatureRespondedEvent", async (e, s) => {
|
|
2962
|
-
await onSignatureResponded(e, s);
|
|
2963
|
-
});
|
|
2964
|
-
}
|
|
2965
|
-
if (handlers.onSignatureError) {
|
|
2966
|
-
const onSignatureError = handlers.onSignatureError;
|
|
2967
|
-
cpiHandlers.set("signatureErrorEvent", async (e, s) => {
|
|
2968
|
-
await onSignatureError(e, s);
|
|
2969
|
-
});
|
|
2970
|
-
}
|
|
2971
|
-
const cpiSubId = CpiEventParser.subscribeToCpiEvents(this.connection, this.program, cpiHandlers);
|
|
2972
|
-
const parser = new EventParser(this.program.programId, this.program.coder);
|
|
2973
|
-
const subId = this.connection.onLogs(this.program.programId, (logs, context) => {
|
|
2974
|
-
if (logs.err) return;
|
|
2975
|
-
for (const evt of parser.parseLogs(logs.logs)) {
|
|
2976
|
-
if (!evt) continue;
|
|
2977
|
-
if (evt.name === "signatureRespondedEvent") {
|
|
2978
|
-
const onSignatureResponded = handlers.onSignatureResponded;
|
|
2979
|
-
if (onSignatureResponded) onSignatureResponded(evt.data, context.slot);
|
|
2980
|
-
}
|
|
2981
|
-
if (evt.name === "signatureErrorEvent") {
|
|
2982
|
-
const onSignatureError = handlers.onSignatureError;
|
|
2983
|
-
if (onSignatureError) onSignatureError(evt.data, context.slot);
|
|
2984
|
-
}
|
|
2985
|
-
}
|
|
2986
|
-
}, commitment);
|
|
2987
|
-
return async () => {
|
|
2988
|
-
await this.connection.removeOnLogsListener(subId);
|
|
2989
|
-
await this.connection.removeOnLogsListener(cpiSubId);
|
|
2990
|
-
};
|
|
2991
|
-
}
|
|
2992
3171
|
};
|
|
2993
3172
|
|
|
2994
3173
|
//#endregion
|
|
2995
3174
|
//#region src/contracts/solana/index.ts
|
|
2996
3175
|
var solana_exports = /* @__PURE__ */ __export({
|
|
2997
3176
|
ChainSignatureContract: () => ChainSignatureContract$1,
|
|
3177
|
+
getRequestIdBidirectional: () => getRequestIdBidirectional,
|
|
3178
|
+
getRequestIdRespond: () => getRequestIdRespond,
|
|
2998
3179
|
utils: () => utils
|
|
2999
3180
|
});
|
|
3000
3181
|
const utils = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "signet.js",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1-beta.1",
|
|
4
4
|
"description": "A TypeScript library for handling multi-chain transactions and signatures using Signet MPC",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -37,7 +37,9 @@
|
|
|
37
37
|
"docs:dev": "vocs dev",
|
|
38
38
|
"docs:build": "vocs build",
|
|
39
39
|
"docs:preview": "vocs preview",
|
|
40
|
-
"format": "prettier --write ."
|
|
40
|
+
"format": "prettier --write .",
|
|
41
|
+
"lint": "eslint 'src/**/*.ts'",
|
|
42
|
+
"typecheck": "tsc --noEmit"
|
|
41
43
|
},
|
|
42
44
|
"author": "Sig Network",
|
|
43
45
|
"license": "MIT",
|
|
@@ -59,28 +61,26 @@
|
|
|
59
61
|
"@aa-sdk/core": "^4.13.0",
|
|
60
62
|
"@account-kit/infra": "^4.13.0",
|
|
61
63
|
"@account-kit/smart-contracts": "^4.13.0",
|
|
64
|
+
"@eslint/js": "^9.18.0",
|
|
62
65
|
"@noble/curves": "^1.8.1",
|
|
63
66
|
"@nomicfoundation/hardhat-toolbox": "^5.0.0",
|
|
64
67
|
"@types/bn.js": "^5.1.5",
|
|
65
68
|
"@types/elliptic": "^6.4.18",
|
|
66
69
|
"@types/node": "^22.10.10",
|
|
67
|
-
"@
|
|
68
|
-
"babel-jest": "^29.7.0",
|
|
70
|
+
"@types/react": "^19.0.0",
|
|
69
71
|
"dotenv": "^16.4.5",
|
|
70
|
-
"eslint": "^
|
|
71
|
-
"eslint-config-prettier": "^
|
|
72
|
-
"eslint-
|
|
73
|
-
"eslint-plugin-import": "^2.29.1",
|
|
74
|
-
"eslint-plugin-n": "^16.6.2",
|
|
75
|
-
"eslint-plugin-prettier": "^5.1.3",
|
|
76
|
-
"eslint-plugin-promise": "^6.1.1",
|
|
72
|
+
"eslint": "^9.18.0",
|
|
73
|
+
"eslint-config-prettier": "^10.0.0",
|
|
74
|
+
"eslint-plugin-import-x": "^4.6.0",
|
|
77
75
|
"hardhat": "^2.22.18",
|
|
78
|
-
"
|
|
79
|
-
"
|
|
76
|
+
"prettier": "^3.8.0",
|
|
77
|
+
"react": "^19.0.0",
|
|
78
|
+
"react-dom": "^19.0.0",
|
|
80
79
|
"tsdown": "^0.16.6",
|
|
81
|
-
"typescript": "^5.
|
|
80
|
+
"typescript": "^5.9.3",
|
|
81
|
+
"typescript-eslint": "^8.21.0",
|
|
82
82
|
"vitest": "^3.0.4",
|
|
83
|
-
"vocs": "1.
|
|
83
|
+
"vocs": "^1.4.1"
|
|
84
84
|
},
|
|
85
85
|
"dependencies": {
|
|
86
86
|
"@coral-xyz/anchor": "^0.31.0",
|