@zhoujun_aptos/octopus-ts-sdk-min 0.22.6 → 0.22.7

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.
@@ -2371,11 +2371,82 @@ var worker_config_exports = {};
2371
2371
  __export(worker_config_exports, {
2372
2372
  WorkerConfig: () => WorkerConfig,
2373
2373
  get: () => get,
2374
+ getAsync: () => getAsync,
2374
2375
  randWorker: () => randWorker,
2375
2376
  view: () => view
2376
2377
  });
2377
2378
  import { AccountAddress, Deserializer as Deserializer10, Network as Network2, Serializer as Serializer11 } from "@aptos-labs/ts-sdk";
2378
2379
  import { bytesToHex as bytesToHex10, hexToBytes as hexToBytes5 } from "@noble/curves/utils";
2380
+
2381
+ // src/result.ts
2382
+ var Result = class _Result {
2383
+ isOk;
2384
+ okValue;
2385
+ errValue;
2386
+ extra;
2387
+ constructor({ isOk, okValue, errValue, extra }) {
2388
+ this.isOk = isOk;
2389
+ this.okValue = okValue;
2390
+ this.errValue = errValue;
2391
+ this.extra = extra;
2392
+ }
2393
+ static Ok(args) {
2394
+ return new _Result({ isOk: true, okValue: args.value, extra: args.extra });
2395
+ }
2396
+ static Err(args) {
2397
+ return new _Result({ isOk: false, errValue: args.error, extra: args.extra });
2398
+ }
2399
+ /**
2400
+ * You write a closure that either returns a T or throws, and we wrap it to return a Result<T>.
2401
+ * Your closure is also given an `extra` dictionary to record additional context.
2402
+ */
2403
+ static capture({ task, recordsExecutionTimeMs = false }) {
2404
+ const start = performance.now();
2405
+ var extra = {};
2406
+ var error;
2407
+ var okValue;
2408
+ try {
2409
+ okValue = task(extra);
2410
+ } catch (caught) {
2411
+ error = caught;
2412
+ } finally {
2413
+ if (recordsExecutionTimeMs) {
2414
+ extra["_sdk_execution_time_ms"] = performance.now() - start;
2415
+ }
2416
+ if (error !== void 0) {
2417
+ return _Result.Err({ error, extra });
2418
+ } else {
2419
+ return _Result.Ok({ value: okValue, extra });
2420
+ }
2421
+ }
2422
+ }
2423
+ /**
2424
+ * You write an async closure that either returns a T or throws, and we wrap it to return a Result<T>.
2425
+ * Your closure is also given an `extra` dictionary to record additional context.
2426
+ */
2427
+ static async captureAsync({ task, recordsExecutionTimeMs = false }) {
2428
+ var extra = {};
2429
+ const start = performance.now();
2430
+ var error;
2431
+ var okValue;
2432
+ try {
2433
+ okValue = await task(extra);
2434
+ } catch (caught) {
2435
+ error = caught;
2436
+ } finally {
2437
+ if (recordsExecutionTimeMs) {
2438
+ extra["_sdk_execution_time_ms"] = performance.now() - start;
2439
+ }
2440
+ if (error !== void 0) {
2441
+ return _Result.Err({ error, extra });
2442
+ } else {
2443
+ return _Result.Ok({ value: okValue, extra });
2444
+ }
2445
+ }
2446
+ }
2447
+ };
2448
+
2449
+ // src/worker_config.ts
2379
2450
  var WorkerConfig = class _WorkerConfig {
2380
2451
  expiryTimeMicrosecs;
2381
2452
  endpoint;
@@ -2460,6 +2531,23 @@ async function get(workerEndpoint) {
2460
2531
  const hex = await response.text();
2461
2532
  return WorkerConfig.fromHex(hex);
2462
2533
  }
2534
+ async function getAsync(workerEndpoint) {
2535
+ const task = async (extra) => {
2536
+ const url = `${workerEndpoint}/config_bcs`;
2537
+ extra["url"] = url;
2538
+ const response = await fetch(url, {
2539
+ method: "GET"
2540
+ });
2541
+ extra["responseStatus"] = response.status;
2542
+ extra["responseStatusText"] = response.statusText;
2543
+ if (!response.ok) {
2544
+ throw `Failed to fetch worker config: ${response.status} ${response.statusText}`;
2545
+ }
2546
+ const hex = await response.text();
2547
+ return WorkerConfig.fromHex(hex);
2548
+ };
2549
+ return await Result.captureAsync({ task, recordsExecutionTimeMs: true });
2550
+ }
2463
2551
  function randWorker() {
2464
2552
  const addr = new AccountAddress(utils_exports.randBytes(32));
2465
2553
  const encDk = keygen2();
@@ -2495,7 +2583,7 @@ import { bytesToHex as bytesToHex13, hexToBytes as hexToBytes8 } from "@noble/ha
2495
2583
  import * as SolanaSDK from "@solana/web3.js";
2496
2584
 
2497
2585
  // src/threshold-ibe/aptos.ts
2498
- import { AccountAddress as AccountAddress2, AnyPublicKey, AnySignature, Aptos as Aptos2, AptosConfig as AptosConfig2, Deserializer as Deserializer11, Ed25519PublicKey, Ed25519Signature, FederatedKeylessPublicKey, KeylessPublicKey, KeylessSignature, MultiEd25519PublicKey, MultiEd25519Signature, MultiKey, MultiKeySignature, Network as Network3, Serializer as Serializer12 } from "@aptos-labs/ts-sdk";
2586
+ import { AccountAddress as AccountAddress2, AccountPublicKey, AnyPublicKey, AnySignature, Aptos as Aptos2, AptosConfig as AptosConfig2, Deserializer as Deserializer11, Ed25519PublicKey, Ed25519Signature, FederatedKeylessPublicKey, KeylessPublicKey, KeylessSignature, MultiEd25519PublicKey, MultiEd25519Signature, MultiKey, MultiKeySignature, Network as Network3, Serializer as Serializer12 } from "@aptos-labs/ts-sdk";
2499
2587
  import { bytesToHex as bytesToHex11, hexToBytes as hexToBytes6 } from "@noble/hashes/utils";
2500
2588
  var ContractID = class _ContractID {
2501
2589
  chainId;
@@ -2676,64 +2764,76 @@ var ProofOfPermission = class _ProofOfPermission {
2676
2764
  }
2677
2765
  };
2678
2766
  async function verifyPermission({ fullDecryptionDomain, proof }) {
2679
- const aptos = createAptos(getChainNameFromChainId(fullDecryptionDomain.getAptosContractID().chainId));
2680
- const taskVerifySig = async () => {
2767
+ const task = async (extra) => {
2768
+ const aptos = createAptos(getChainNameFromChainId(fullDecryptionDomain.getAptosContractID().chainId));
2769
+ const [verifySigResult, checkAuthKeyResult, checkPermissionResult] = await Promise.all([
2770
+ verifySig({ aptos, fullDecryptionDomain, proof }),
2771
+ checkAuthKey({ aptos, userAddr: proof.userAddr, publicKey: proof.publicKey }),
2772
+ checkPermission({ aptos, fullDecryptionDomain, proof })
2773
+ ]);
2774
+ extra["verifySigResult"] = verifySigResult;
2775
+ extra["checkAuthKeyResult"] = checkAuthKeyResult;
2776
+ extra["checkPermissionResult"] = checkPermissionResult;
2777
+ if (!verifySigResult.isOk || !checkAuthKeyResult.isOk || !checkPermissionResult.isOk) {
2778
+ throw "one or more sub-checks failed";
2779
+ }
2780
+ };
2781
+ return await Result.captureAsync({ task, recordsExecutionTimeMs: true });
2782
+ }
2783
+ async function verifySig({ aptos, fullDecryptionDomain, proof }) {
2784
+ const task = async (extra) => {
2681
2785
  const msgToSign = fullDecryptionDomain.toPrettyMessage();
2682
2786
  const msgToSignHex = bytesToHex11(new TextEncoder().encode(msgToSign));
2683
- const fullMessageFromPetra = proof.fullMessage.includes(msgToSign);
2684
- const fullMessageFromAptosConnect = proof.fullMessage.includes(msgToSignHex);
2685
- if (!fullMessageFromPetra && !fullMessageFromAptosConnect) return false;
2686
- try {
2687
- return await proof.publicKey.verifySignatureAsync({
2688
- aptosConfig: aptos.config,
2689
- message: proof.fullMessage,
2690
- signature: proof.signature
2691
- });
2692
- } catch (error) {
2693
- return false;
2694
- }
2787
+ const fullMessageSeemsFromPetra = proof.fullMessage.includes(msgToSign);
2788
+ const fullMessageSeemsFromAptosConnect = proof.fullMessage.includes(msgToSignHex);
2789
+ extra["msgToSign"] = msgToSign;
2790
+ extra["msgToSignHex"] = msgToSignHex;
2791
+ extra["fullMessageSeemsFromPetra"] = fullMessageSeemsFromPetra;
2792
+ extra["fullMessageSeemsFromAptosConnect"] = fullMessageSeemsFromAptosConnect;
2793
+ if (!fullMessageSeemsFromPetra && !fullMessageSeemsFromAptosConnect) throw "fullMessage does not contain fullDecryptionDomain or its hex";
2794
+ const sigValid = await proof.publicKey.verifySignatureAsync({
2795
+ aptosConfig: aptos.config,
2796
+ message: proof.fullMessage,
2797
+ signature: proof.signature
2798
+ });
2799
+ if (!sigValid) throw "verifySignatureAsync failed";
2695
2800
  };
2696
- const taskCheckAuthKey = async () => {
2697
- try {
2698
- const onChainAuthKeyBytes = await getAccountAuthKeyBytes(aptos, proof.userAddr);
2699
- const userAuthKeyBytes = proof.publicKey.authKey().bcsToBytes();
2700
- const onChainHex = bytesToHex11(onChainAuthKeyBytes);
2701
- const userHex = bytesToHex11(userAuthKeyBytes);
2702
- console.log(`onChainHex: ${onChainHex}`);
2703
- console.log(`userHex : ${userHex}`);
2704
- return onChainHex === userHex;
2705
- } catch (error) {
2706
- return false;
2801
+ return await Result.captureAsync({ task, recordsExecutionTimeMs: true });
2802
+ }
2803
+ async function checkAuthKey({ aptos, userAddr, publicKey }) {
2804
+ const task = async (extra) => {
2805
+ if (!(publicKey instanceof AccountPublicKey)) {
2806
+ throw "publicKey is not an AccountPublicKey";
2707
2807
  }
2808
+ const onChainAuthKeyBytes = await getAccountAuthKeyBytes(aptos, userAddr);
2809
+ const userAuthKeyBytes = publicKey.authKey().bcsToBytes();
2810
+ const onChainHex = bytesToHex11(onChainAuthKeyBytes);
2811
+ const userHex = bytesToHex11(userAuthKeyBytes);
2812
+ extra["onChainHex"] = onChainHex;
2813
+ extra["userHex"] = userHex;
2814
+ if (onChainHex !== userHex) throw "on-chain auth key does not match user auth key";
2708
2815
  };
2709
- const taskCheckPermission = async () => {
2816
+ return await Result.captureAsync({ task, recordsExecutionTimeMs: true });
2817
+ }
2818
+ async function checkPermission({ aptos, fullDecryptionDomain, proof }) {
2819
+ const task = async (extra) => {
2710
2820
  const contractId = fullDecryptionDomain.getAptosContractID();
2711
- try {
2712
- const userIsPermittedMoveVal = await view2(
2713
- aptos,
2714
- `${contractId.moduleAddr.toStringLong()}::${contractId.moduleName}::${contractId.functionName}`,
2715
- [],
2716
- [proof.userAddr, fullDecryptionDomain.domain]
2717
- );
2718
- return userIsPermittedMoveVal?.toString() === "true";
2719
- } catch (error) {
2720
- return false;
2821
+ const viewFunctionInvocationResult = await view2({
2822
+ aptos,
2823
+ func: `${contractId.moduleAddr.toStringLong()}::${contractId.moduleName}::${contractId.functionName}`,
2824
+ typeArguments: [],
2825
+ functionArguments: [proof.userAddr, fullDecryptionDomain.domain]
2826
+ });
2827
+ extra["viewFunctionInvocationResult"] = viewFunctionInvocationResult;
2828
+ if (!viewFunctionInvocationResult.isOk) {
2829
+ throw "view function invocation failed";
2830
+ }
2831
+ const returnedMoveValue = viewFunctionInvocationResult.okValue;
2832
+ if (returnedMoveValue?.toString() !== "true") {
2833
+ throw "access control contract return value is not true";
2721
2834
  }
2722
2835
  };
2723
- const [sigIsValid, authKeyMatches, userIsPermitted] = await Promise.all([
2724
- taskVerifySig(),
2725
- taskCheckAuthKey(),
2726
- taskCheckPermission()
2727
- ]);
2728
- if (!sigIsValid) {
2729
- throw new Error("Signature invalid.");
2730
- }
2731
- if (!authKeyMatches) {
2732
- throw new Error("Authentication key mismatch: on-chain key does not match provided public key.");
2733
- }
2734
- if (!userIsPermitted) {
2735
- throw new Error("Permission denied.");
2736
- }
2836
+ return await Result.captureAsync({ task, recordsExecutionTimeMs: true });
2737
2837
  }
2738
2838
  function getChainNameFromChainId(chainId) {
2739
2839
  if (chainId === 1) {
@@ -2770,18 +2870,22 @@ async function getAccountAuthKeyBytes(aptos, address) {
2770
2870
  const accountInfo = await aptos.getAccountInfo({ accountAddress: address });
2771
2871
  return hexToBytes6(accountInfo.authentication_key.replace("0x", ""));
2772
2872
  }
2773
- async function view2(aptos, func, typeArguments, functionArguments) {
2774
- const result = await aptos.view({
2775
- payload: {
2776
- function: func,
2777
- typeArguments,
2778
- functionArguments
2873
+ async function view2({ aptos, func, typeArguments, functionArguments }) {
2874
+ const task = async (extra) => {
2875
+ const returnedMoveValues = await aptos.view({
2876
+ payload: {
2877
+ function: func,
2878
+ typeArguments,
2879
+ functionArguments
2880
+ }
2881
+ });
2882
+ extra["returnedMoveValues"] = returnedMoveValues;
2883
+ if (returnedMoveValues.length === 0) {
2884
+ throw `aptos.view returned an empty list`;
2779
2885
  }
2780
- });
2781
- if (result.length === 0) {
2782
- throw new Error(`View function returned empty result`);
2783
- }
2784
- return result[0];
2886
+ return returnedMoveValues[0];
2887
+ };
2888
+ return await Result.captureAsync({ task, recordsExecutionTimeMs: true });
2785
2889
  }
2786
2890
 
2787
2891
  // src/threshold-ibe/solana.ts
@@ -2882,76 +2986,107 @@ var ProofOfPermission2 = class _ProofOfPermission {
2882
2986
  }
2883
2987
  };
2884
2988
  async function verifyPermission2({ fullDecryptionDomain, proof }) {
2885
- const txn = proof.inner;
2886
- assertTransactionValid({ txn, fullDecryptionDomain });
2887
- await assertTransactionSimulationPasses(txn, fullDecryptionDomain.getSolanaContractID().knownChainName);
2888
- }
2889
- function assertTransactionValid({ txn, fullDecryptionDomain }) {
2890
- let instructions;
2891
- if (txn instanceof VersionedTransaction) {
2892
- const message = txn.message;
2893
- instructions = message.compiledInstructions.map((ix) => {
2894
- if (ix.programIdIndex >= message.staticAccountKeys.length) {
2895
- throw new Error(`Program ID index ${ix.programIdIndex} is out of bounds for static account keys (length: ${message.staticAccountKeys.length}). Address table lookups are not supported for validation.`);
2896
- }
2897
- const programId = message.staticAccountKeys[ix.programIdIndex];
2898
- return { programId, data: Buffer.from(ix.data) };
2899
- });
2900
- } else {
2901
- instructions = txn.instructions.map((ix) => ({
2902
- programId: ix.programId,
2903
- data: Buffer.from(ix.data)
2904
- }));
2905
- }
2906
- if (instructions.length !== 1) {
2907
- throw new Error(`transaction must contain exactly 1 instruction, found ${instructions.length}`);
2908
- }
2909
- const instruction = instructions[0];
2910
- if (!instruction.programId.equals(fullDecryptionDomain.getSolanaContractID().programId)) {
2911
- throw new Error(`transaction instruction program ID (${instruction.programId.toString()}) does not match contract program ID`);
2912
- }
2913
- const instructionData = instruction.data;
2914
- if (instructionData.length < 12) {
2915
- throw new Error("instruction data too short (must be at least 12 bytes: 8-byte discriminator + 4-byte Vec length)");
2916
- }
2917
- const paramData = instructionData.slice(8);
2918
- const vecLength = paramData.readUInt32LE(0);
2919
- if (paramData.length < 4 + vecLength) {
2920
- throw new Error(`instruction data incomplete: expected ${4 + vecLength} bytes after discriminator, found ${paramData.length}`);
2921
- }
2922
- const fullBlobNameBytes = paramData.slice(4, 4 + vecLength);
2923
- const expectedParamDataLength = 4 + vecLength;
2924
- if (paramData.length > expectedParamDataLength) {
2925
- throw new Error(`instruction data has extra bytes: expected exactly ${expectedParamDataLength} bytes after discriminator, found ${paramData.length}`);
2989
+ var extra = {};
2990
+ try {
2991
+ const txn = proof.inner;
2992
+ const validateTxnResult = validateTxn({ txn, fullDecryptionDomain });
2993
+ if (!validateTxnResult.isOk) {
2994
+ extra["causedBy"] = validateTxnResult.extra;
2995
+ throw "transaction is invalid";
2996
+ }
2997
+ const simulationResult = await assertTransactionSimulationPasses(txn, fullDecryptionDomain.getSolanaContractID().knownChainName);
2998
+ if (!simulationResult.isOk) {
2999
+ extra["causedBy"] = simulationResult.extra;
3000
+ throw "transaction simulation failed";
3001
+ }
3002
+ return Result.Ok({ value: void 0, extra });
3003
+ } catch (error) {
3004
+ return Result.Err({ error, extra });
2926
3005
  }
2927
- if (bytesToHex12(fullBlobNameBytes) !== fullDecryptionDomain.toHex()) {
2928
- throw new Error(`domain mismatch: instruction parameter does not match decryptionContext.domain`);
3006
+ }
3007
+ function validateTxn({ txn, fullDecryptionDomain }) {
3008
+ try {
3009
+ let instructions;
3010
+ if (txn instanceof VersionedTransaction) {
3011
+ const message = txn.message;
3012
+ instructions = message.compiledInstructions.map((ix) => {
3013
+ if (ix.programIdIndex >= message.staticAccountKeys.length) {
3014
+ throw `some program ID index is out of bounds for static account keys (are you using address table lookups? threshold-ibe does not support it yet)`;
3015
+ }
3016
+ const programId = message.staticAccountKeys[ix.programIdIndex];
3017
+ return { programId, data: Buffer.from(ix.data) };
3018
+ });
3019
+ } else {
3020
+ instructions = txn.instructions.map((ix) => ({
3021
+ programId: ix.programId,
3022
+ data: Buffer.from(ix.data)
3023
+ }));
3024
+ }
3025
+ if (instructions.length !== 1) throw `transaction must contain exactly 1 instruction`;
3026
+ const instruction = instructions[0];
3027
+ if (!instruction.programId.equals(fullDecryptionDomain.getSolanaContractID().programId)) {
3028
+ throw `transaction instruction program ID does not match contract program ID`;
3029
+ }
3030
+ const instructionData = instruction.data;
3031
+ if (instructionData.length < 12) {
3032
+ throw "instruction data too short";
3033
+ }
3034
+ const paramData = instructionData.slice(8);
3035
+ const vecLength = paramData.readUInt32LE(0);
3036
+ if (paramData.length < 4 + vecLength) throw `instruction data incomplete`;
3037
+ const domainAsTxnParam = paramData.slice(4, 4 + vecLength);
3038
+ const expectedParamDataLength = 4 + vecLength;
3039
+ if (paramData.length > expectedParamDataLength) {
3040
+ throw `instruction data has extra bytes`;
3041
+ }
3042
+ if (bytesToHex12(domainAsTxnParam) !== bytesToHex12(fullDecryptionDomain.domain)) {
3043
+ throw `instruction parameter does not match decryptionContext.domain`;
3044
+ }
3045
+ return Result.Ok({ value: void 0 });
3046
+ } catch (error) {
3047
+ return Result.Err({ error });
2929
3048
  }
2930
3049
  }
2931
3050
  async function assertTransactionSimulationPasses(txn, chainName) {
2932
- let rpcUrl;
2933
- if (chainName === "localnet" || chainName === "localhost") {
2934
- rpcUrl = "http://127.0.0.1:8899";
2935
- } else if (chainName === "devnet") {
2936
- rpcUrl = "https://api.devnet.solana.com";
2937
- } else if (chainName === "testnet") {
2938
- rpcUrl = "https://api.testnet.solana.com";
2939
- } else if (chainName === "mainnet-beta") {
2940
- rpcUrl = "https://api.mainnet-beta.solana.com";
2941
- } else {
2942
- throw new Error(`Unknown chain name: ${chainName}`);
2943
- }
2944
- const connection = new Connection(rpcUrl, "confirmed");
2945
- let simulation;
2946
- if (txn instanceof VersionedTransaction) {
2947
- simulation = await connection.simulateTransaction(txn, {
2948
- sigVerify: true
2949
- });
2950
- } else {
2951
- simulation = await connection.simulateTransaction(txn);
2952
- }
2953
- if (simulation.value.err) {
2954
- throw new Error(`transaction simulation failed: ${JSON.stringify(simulation.value.err)}`);
3051
+ var extra = {};
3052
+ var error;
3053
+ const start = performance.now();
3054
+ try {
3055
+ let rpcUrl;
3056
+ if (chainName === "localnet" || chainName === "localhost") {
3057
+ rpcUrl = "http://127.0.0.1:8899";
3058
+ } else if (chainName === "devnet") {
3059
+ rpcUrl = "https://api.devnet.solana.com";
3060
+ } else if (chainName === "testnet") {
3061
+ rpcUrl = "https://api.testnet.solana.com";
3062
+ } else if (chainName === "mainnet-beta") {
3063
+ rpcUrl = "https://api.mainnet-beta.solana.com";
3064
+ } else {
3065
+ extra["chainName"] = chainName;
3066
+ throw `unsupported chain name`;
3067
+ }
3068
+ const connection = new Connection(rpcUrl, "confirmed");
3069
+ let simulation;
3070
+ if (txn instanceof VersionedTransaction) {
3071
+ simulation = await connection.simulateTransaction(txn, {
3072
+ sigVerify: true
3073
+ });
3074
+ } else {
3075
+ simulation = await connection.simulateTransaction(txn);
3076
+ }
3077
+ if (simulation.value.err) {
3078
+ extra["simulationError"] = simulation.value.err;
3079
+ throw `transaction simulation failed`;
3080
+ }
3081
+ } catch (caught) {
3082
+ error = caught;
3083
+ } finally {
3084
+ extra["executionTimeMs"] = performance.now() - start;
3085
+ if (error !== void 0) {
3086
+ return Result.Err({ error, extra });
3087
+ } else {
3088
+ return Result.Ok({ value: void 0, extra });
3089
+ }
2955
3090
  }
2956
3091
  }
2957
3092
 
@@ -3057,11 +3192,16 @@ var EncryptionKey2 = class _EncryptionKey {
3057
3192
  this.ibeMpks = ibeMpks;
3058
3193
  }
3059
3194
  static async fetch({ committee }) {
3060
- const ibeMpks = await Promise.all(committee.workerEndpoints.map(async (endpoint) => {
3061
- const config = await worker_config_exports.get(endpoint);
3062
- return config.ibeMpk;
3063
- }));
3064
- return new _EncryptionKey({ ibeMpks });
3195
+ const task = async (extra) => {
3196
+ const workerConfigGetResults = await Promise.all(committee.workerEndpoints.map(async (endpoint) => {
3197
+ return worker_config_exports.getAsync(endpoint);
3198
+ }));
3199
+ extra["workerConfigGetResults"] = workerConfigGetResults;
3200
+ if (workerConfigGetResults.some((result) => !result.isOk)) throw "failed to get all worker configs";
3201
+ const ibeMpks = workerConfigGetResults.map((result) => result.okValue.ibeMpk);
3202
+ return new _EncryptionKey({ ibeMpks });
3203
+ };
3204
+ return await Result.captureAsync({ task, recordsExecutionTimeMs: true });
3065
3205
  }
3066
3206
  };
3067
3207
  var DecryptionKey2 = class _DecryptionKey {
@@ -3070,43 +3210,43 @@ var DecryptionKey2 = class _DecryptionKey {
3070
3210
  this.ibeDecryptionKeys = ibeDecryptionKeys;
3071
3211
  }
3072
3212
  static async fetch({ committee, contractId, domain, proof }) {
3073
- const decKeyLoadResults = await Promise.all(committee.workerEndpoints.map(async (workerEndpoint) => {
3074
- const task = WorkerTask.newThresholdIbeDecryptionKey({ committee, contractId, domain, proof });
3213
+ const task = async (extra) => {
3214
+ extra["committee"] = committee;
3215
+ const decKeyLoadResults = await Promise.all(committee.workerEndpoints.map(async (_workerEndpoint, index) => {
3216
+ return _DecryptionKey.fetchDecKeyShare({ committee, contractId, domain, proof, index });
3217
+ }));
3218
+ extra["decKeyLoadResults"] = decKeyLoadResults;
3219
+ const numSharesCollected = decKeyLoadResults.filter((loadResult) => loadResult.isOk).length;
3220
+ if (numSharesCollected < committee.threshold) throw `failed to collect enough shares`;
3221
+ const decKeyShares = decKeyLoadResults.map((loadResult) => loadResult.okValue ?? null);
3222
+ return new _DecryptionKey(decKeyShares);
3223
+ };
3224
+ return Result.captureAsync({ task, recordsExecutionTimeMs: true });
3225
+ }
3226
+ static async fetchDecKeyShare({ committee, contractId, domain, proof, index }) {
3227
+ const task = async (extra) => {
3228
+ const targetWorkerEndpoint = committee.workerEndpoints[index];
3229
+ const task2 = WorkerTask.newThresholdIbeDecryptionKey({ committee, contractId, domain, proof });
3075
3230
  const controller = new AbortController();
3076
3231
  const timeoutId = setTimeout(() => controller.abort(), 5e3);
3077
3232
  var response = null;
3078
3233
  try {
3079
- response = await fetch(workerEndpoint, {
3234
+ response = await fetch(targetWorkerEndpoint, {
3080
3235
  method: "POST",
3081
- body: task.toHex(),
3236
+ body: task2.toHex(),
3082
3237
  signal: controller.signal
3083
3238
  });
3084
3239
  } catch (error) {
3085
3240
  clearTimeout(timeoutId);
3086
3241
  }
3087
- if (response == null) {
3088
- return new WorkerTimedOut();
3089
- }
3242
+ if (response == null) throw "worker is not responding";
3090
3243
  const responseBody = await response.text();
3091
- if (response.status !== 200) {
3092
- return new WorkerRejected(response.status, responseBody);
3093
- }
3094
- try {
3095
- return IdentityPrivateKey2.fromHex(responseBody);
3096
- } catch (error) {
3097
- return new CouldNotParseDecryptionKey(responseBody);
3098
- }
3099
- }));
3100
- const numSharesCollected = decKeyLoadResults.filter((loadResult) => loadResult instanceof IdentityPrivateKey2).length;
3101
- if (numSharesCollected < committee.threshold) {
3102
- const workerResults = committee.workerEndpoints.map((workerEndpoint, i) => {
3103
- const result = decKeyLoadResults[i];
3104
- return `${workerEndpoint}: ${result instanceof IdentityPrivateKey2 ? "Success" : result.toDisplayString()}`;
3105
- }).join(", ");
3106
- throw new Error(`Failed to collect enough shares to decrypt. Collected ${numSharesCollected} shares, but needed ${committee.threshold} shares. Worker results: ${workerResults}`);
3107
- }
3108
- const decKeys = decKeyLoadResults.map((loadResult) => loadResult instanceof IdentityPrivateKey2 ? loadResult : null);
3109
- return new _DecryptionKey(decKeys);
3244
+ extra["workerResponseStatus"] = response.status;
3245
+ extra["workerResponseBody"] = responseBody;
3246
+ if (response.status !== 200) throw `worker rejected: ${response.status}`;
3247
+ return IdentityPrivateKey2.fromHex(responseBody);
3248
+ };
3249
+ return Result.captureAsync({ task, recordsExecutionTimeMs: true });
3110
3250
  }
3111
3251
  };
3112
3252
  var Ciphertext7 = class _Ciphertext {
@@ -3302,41 +3442,25 @@ function decrypt7({ decryptionKey, ciphertext }) {
3302
3442
  return decrypt6(symmKey, ciphertext.aesCiph);
3303
3443
  }
3304
3444
  async function verifyAndExtract({ ibeMsk, committee, contractId, domain, proof }) {
3305
- const decryptionContext = new FullDecryptionDomain({ committee, contractId, domain });
3306
- if (contractId.scheme == ContractID3.SCHEME_APTOS && proof.scheme == ProofOfPermission3.SCHEME_APTOS) {
3307
- await verifyPermission({ fullDecryptionDomain: decryptionContext, proof: proof.inner });
3308
- } else if (contractId.scheme == ContractID3.SCHEME_SOLANA && proof.scheme == ProofOfPermission3.SCHEME_SOLANA) {
3309
- await verifyPermission2({ fullDecryptionDomain: decryptionContext, proof: proof.inner });
3310
- } else {
3311
- throw new Error(`Unknown scheme: contractId=${contractId.scheme}, proof=${proof.scheme}`);
3312
- }
3313
- return extract2(ibeMsk, decryptionContext.toBytes());
3445
+ const task = async (extra) => {
3446
+ extra["contractIdScheme"] = contractId.scheme;
3447
+ extra["proofScheme"] = proof.scheme;
3448
+ const decryptionContext = new FullDecryptionDomain({ committee, contractId, domain });
3449
+ if (contractId.scheme == ContractID3.SCHEME_APTOS && proof.scheme == ProofOfPermission3.SCHEME_APTOS) {
3450
+ const aptosResult = await verifyPermission({ fullDecryptionDomain: decryptionContext, proof: proof.inner });
3451
+ extra["verifyAptosResult"] = aptosResult;
3452
+ if (!aptosResult.isOk) throw "aptos verification failed";
3453
+ } else if (contractId.scheme == ContractID3.SCHEME_SOLANA && proof.scheme == ProofOfPermission3.SCHEME_SOLANA) {
3454
+ const solanaResult = await verifyPermission2({ fullDecryptionDomain: decryptionContext, proof: proof.inner });
3455
+ extra["verifySolanaResult"] = solanaResult;
3456
+ if (!solanaResult.isOk) throw "solana verification failed";
3457
+ } else {
3458
+ throw "unsupported scheme combination";
3459
+ }
3460
+ return extract2(ibeMsk, decryptionContext.toBytes());
3461
+ };
3462
+ return Result.captureAsync({ task, recordsExecutionTimeMs: true });
3314
3463
  }
3315
- var WorkerTimedOut = class {
3316
- toDisplayString() {
3317
- return "Timed out";
3318
- }
3319
- };
3320
- var WorkerRejected = class {
3321
- statusCode;
3322
- responseBody;
3323
- constructor(statusCode, responseBody) {
3324
- this.statusCode = statusCode;
3325
- this.responseBody = responseBody;
3326
- }
3327
- toDisplayString() {
3328
- return `Rejected: ${this.statusCode} ${this.responseBody}`;
3329
- }
3330
- };
3331
- var CouldNotParseDecryptionKey = class {
3332
- originalHex;
3333
- constructor(originalHex) {
3334
- this.originalHex = originalHex;
3335
- }
3336
- toDisplayString() {
3337
- return `Could not parse decryption key: ${this.originalHex}`;
3338
- }
3339
- };
3340
3464
 
3341
3465
  // src/worker_task.ts
3342
3466
  var TYPE_SILENT_SETUP_DECRYPTION_KEY = 5;
@@ -3566,16 +3690,16 @@ var DecryptionContext = class _DecryptionContext {
3566
3690
  clearTimeout(timeoutId);
3567
3691
  }
3568
3692
  if (response == null) {
3569
- return new WorkerTimedOut2();
3693
+ return new WorkerTimedOut();
3570
3694
  }
3571
3695
  const responseBody = await response.text();
3572
3696
  if (response.status !== 200) {
3573
- return new WorkerRejected2(response.status, responseBody);
3697
+ return new WorkerRejected(response.status, responseBody);
3574
3698
  }
3575
3699
  try {
3576
3700
  return IdentityPrivateKey2.fromHex(responseBody);
3577
3701
  } catch (error) {
3578
- return new CouldNotParseDecryptionKey2(responseBody);
3702
+ return new CouldNotParseDecryptionKey(responseBody);
3579
3703
  }
3580
3704
  }));
3581
3705
  const numSharesCollected = decKeyLoadResults.filter((loadResult) => loadResult instanceof IdentityPrivateKey2).length;
@@ -3681,12 +3805,12 @@ var Decryptor = class {
3681
3805
  return decrypt6(symmKey, ciphertext.aesCiph);
3682
3806
  }
3683
3807
  };
3684
- var WorkerTimedOut2 = class {
3808
+ var WorkerTimedOut = class {
3685
3809
  toDisplayString() {
3686
3810
  return "Timed out";
3687
3811
  }
3688
3812
  };
3689
- var WorkerRejected2 = class {
3813
+ var WorkerRejected = class {
3690
3814
  statusCode;
3691
3815
  responseBody;
3692
3816
  constructor(statusCode, responseBody) {
@@ -3697,7 +3821,7 @@ var WorkerRejected2 = class {
3697
3821
  return `Rejected: ${this.statusCode} ${this.responseBody}`;
3698
3822
  }
3699
3823
  };
3700
- var CouldNotParseDecryptionKey2 = class {
3824
+ var CouldNotParseDecryptionKey = class {
3701
3825
  originalHex;
3702
3826
  constructor(originalHex) {
3703
3827
  this.originalHex = originalHex;
@@ -4261,16 +4385,16 @@ var DecryptionContext2 = class _DecryptionContext {
4261
4385
  clearTimeout(timeoutId);
4262
4386
  }
4263
4387
  if (response == null) {
4264
- return new WorkerTimedOut3();
4388
+ return new WorkerTimedOut2();
4265
4389
  }
4266
4390
  const responseBody = await response.text();
4267
4391
  if (response.status !== 200) {
4268
- return new WorkerRejected3(response.status, responseBody);
4392
+ return new WorkerRejected2(response.status, responseBody);
4269
4393
  }
4270
4394
  try {
4271
4395
  return IdentityPrivateKey2.fromHex(responseBody);
4272
4396
  } catch (error) {
4273
- return new CouldNotParseDecryptionKey3(responseBody);
4397
+ return new CouldNotParseDecryptionKey2(responseBody);
4274
4398
  }
4275
4399
  }));
4276
4400
  const numSharesCollected = decKeyLoadResults.filter((loadResult) => loadResult instanceof IdentityPrivateKey2).length;
@@ -4375,12 +4499,12 @@ var Decryptor2 = class {
4375
4499
  return decrypt6(symmKey, ciphertext.aesCiph);
4376
4500
  }
4377
4501
  };
4378
- var WorkerTimedOut3 = class {
4502
+ var WorkerTimedOut2 = class {
4379
4503
  toDisplayString() {
4380
4504
  return "Timed out";
4381
4505
  }
4382
4506
  };
4383
- var WorkerRejected3 = class {
4507
+ var WorkerRejected2 = class {
4384
4508
  statusCode;
4385
4509
  responseBody;
4386
4510
  constructor(statusCode, responseBody) {
@@ -4391,7 +4515,7 @@ var WorkerRejected3 = class {
4391
4515
  return `Rejected: ${this.statusCode} ${this.responseBody}`;
4392
4516
  }
4393
4517
  };
4394
- var CouldNotParseDecryptionKey3 = class {
4518
+ var CouldNotParseDecryptionKey2 = class {
4395
4519
  originalHex;
4396
4520
  constructor(originalHex) {
4397
4521
  this.originalHex = originalHex;