UNPKG

@intuweb3/sdk

Version:

INTU SDK - Modern blockchain interaction toolkit

877 lines 41 kB
import { createRandomMessage, createSeed, formTransaction, getMasterPublicKey, parseTransaction, preRegister, registerStepOne, registerStepTwo, registerStepThree, signTransaction, signTransactionWithoutLambda, getPolybaseKey, getUniqueHashFromSignature, } from "./cryptography/index.js"; import { createVault, preRegisterStep, proposeTransaction, userCompleteVault, userConfirmTx, registerUserAll, } from "./web3/signerfunctions.js"; import { getFilteredUserInitializedLogs, getFilteredUserInitializedLogsSingle, _getProposal, _getTransaction, _getTransactions, getVault, } from "./web3/providerfunctions.js"; import { getUserPreRegisterInfos, getUserSignature, getUtilsParams, getUserRegistrationAllInfos, } from "./web3/utils.js"; import { ethers } from "ethers"; import { hexToBytes } from "@noble/hashes/utils"; import { finalizeEvent, getPublicKey } from "nostr-tools/pure"; import { Relay } from "nostr-tools/relay"; import { SimplePool } from "nostr-tools"; import { parseEther } from "viem"; import { createViemClientForTransaction, getVaultContract, } from "./web3/helper/index.js"; import { getProviderForChain } from "../tools/chainList.js"; import { getBestProvider, } from "../utils/reliable-provider.js"; import { getUserPreRegisterInfosDirect, getUserRegistrationAllInfosDirect, getTransactionLeanDirect, getDataWithFallback, } from "./direct/index.js"; let getGraphEndpoint; (async () => { const constants = await import("../tools/constants.js"); getGraphEndpoint = constants.getGraphEndpoint; })(); export async function createIntuAccount(addressList, vaultName, rotationThreshold, transactionThreshold, adminThreshold, signer, returnHash = false) { const { seed } = await createSeed(); const { message } = await createRandomMessage(); let createVaultResult = await createVault(addressList, vaultName, rotationThreshold, transactionThreshold, adminThreshold, message, seed, signer, returnHash); return createVaultResult; } export async function createPolybaseKey(vaultAddress, signer, intuSignature) { let signature = ""; intuSignature ? (signature = intuSignature) : (signature = await getUserSignature(vaultAddress, signer)); return await getPolybaseKey(signature); } export async function preRegistration(vaultAddress, signer, intuSignature, returnHash) { let userAddress = await signer.getAddress(); const chainId = (await signer.provider.getNetwork()).chainId; const provider = await getBestProvider(chainId, signer); const indexerUrl = process.env.INDEXER_URL || process.env.REACT_APP_INDEXER_URL || getGraphEndpoint(chainId); const preRegCheck = await getDataWithFallback(() => getUserPreRegisterInfos(vaultAddress, userAddress, provider), provider, indexerUrl, 50, () => getUserPreRegisterInfosDirect(vaultAddress, userAddress, provider)); if (preRegCheck.registered) { console.log("user already preregistered : ", userAddress); return `User already preregistered : ${userAddress}`; } let signature; intuSignature ? (signature = intuSignature) : (signature = await getUserSignature(vaultAddress, signer)); const { encryptionKey, megaPublicKey, encMegaSecretKey } = await preRegister(signature); let dbKey = await getPolybaseKey(signature); let sk = dbKey.key; let pkfinal = getPublicKey(hexToBytes(String(sk))); let rh = returnHash || false; return await preRegisterStep(vaultAddress, encryptionKey, megaPublicKey, encMegaSecretKey, pkfinal, signer, rh); } export async function automateRegistration(vaultAddress, signer, nostrNode, intuSignature) { console.log("Starting automated registration for vault:", vaultAddress); const startTime = Date.now(); let retries = 0; let maxRetries = 200; let signature = ""; const sleep = (delay) => new Promise((resolve) => setTimeout(resolve, delay)); intuSignature ? (signature = intuSignature) : (signature = await getUserSignature(vaultAddress, signer)); const userAddress = await signer.getAddress(); const chainId = (await signer.provider.getNetwork()).chainId; const provider = await getBestProvider(chainId, signer); const vaultContract = await getVaultContract(vaultAddress, provider); let { users, createdDate } = await vaultContract.vaultInfos(); let seed, threshold, index, megaPkArray, encMegaSecretKey, dbKeyArray; const userIndex = users.findIndex((address) => userAddress == address); let result = await getUtilsParams(vaultAddress, userAddress, provider); seed = result.seed; index = result.index; megaPkArray = result.megaPkArray; encMegaSecretKey = result.encMegaSecretKey[userIndex]; threshold = result.threshold; dbKeyArray = result.dbKeyArray; console.log("Waiting for all users to complete pre-registration..."); while (dbKeyArray.filter(Boolean).length < users.length) { if (retries < maxRetries) { console.log(`Waiting for pre-registration: ${dbKeyArray.filter(Boolean).length}/${users.length} users ready`); await sleep(750); result = await getUtilsParams(vaultAddress, userAddress, provider); dbKeyArray = [...result.dbKeyArray]; seed = result.seed; index = result.index; megaPkArray = result.megaPkArray; encMegaSecretKey = result.encMegaSecretKey[userIndex]; threshold = result.threshold; retries++; } else { console.log("⚠️ [AutoReg] Max retries reached, proceeding anyway (this will probably fail)"); break; } } console.log("All users pre-registered, proceeding to NOSTR setup"); retries = 0; let true_threshold = Math.ceil((megaPkArray.length * threshold) / 100); let round1counter = []; let round2counter = []; let round3counter = []; let pedersenDealingsKeyArray = []; let pedersenDealingsKappaArray = []; let pedersenDealingsLambdaArray = []; let pedersenOpeningsKeyArray = []; let pedersenOpeningsKappaArray = []; let pedersenOpeningsLambdaArray = []; let simpleKeyDealingsArray = []; let simpleLambdaDealingsArray = []; let pedersenKeyTranscriptsArray = []; let pedersenKappaTranscriptsArray = []; let pedersenLambdaTranscriptsArray = []; let dealingsKappaTimesLambdaArray = []; let simpleKeyOpeningsArray = []; let simpleKappaOpeningsArray = []; let dealingKeyTimesLambdaArray = []; let simpleKeyTranscriptsArray = []; let simpleKappaTranscriptsArray = []; dealingsKappaTimesLambdaArray = new Array(users.length).fill(""); simpleKeyOpeningsArray = new Array(users.length).fill(""); simpleKappaOpeningsArray = new Array(users.length).fill(""); dealingKeyTimesLambdaArray = new Array(users.length).fill(""); simpleKeyTranscriptsArray = new Array(users.length).fill(""); simpleKappaTranscriptsArray = new Array(users.length).fill(""); console.log("Setting up NOSTR relays..."); let preRelays = ["wss://nostr.intu.xyz"]; if (nostrNode) { preRelays.unshift(nostrNode); } let relays = []; for (const relayUrl of preRelays) { try { await Relay.connect(relayUrl); relays.push(relayUrl); console.log(`Connected to NOSTR relay: ${relayUrl}`); break; } catch (error) { console.error(`Error connecting to relay ${relayUrl}:`, error); } } if (relays.length === 0) { console.error("No NOSTR relays available"); throw new Error("No relays available"); } const pool = new SimplePool(); let dbKey = await getPolybaseKey(signature); let sk = dbKey.key; let h; try { h = pool.subscribeMany(relays, [ { kinds: [1], since: Number(createdDate), }, ], { onevent(event) { try { let data = JSON.parse(event.content); if ("pedersen_key_dealing" in data) { pedersenDealingsKeyArray[data.u] = data.pedersen_key_dealing; pedersenDealingsKappaArray[data.u] = data.pedersen_kappa_dealing; pedersenDealingsLambdaArray[data.u] = data.pedersen_lambda_dealing; round1counter[data.u] = 1; } else if ("simple_key_dealing" in data) { pedersenOpeningsKeyArray[data.u] = data.pedersen_key_opening; pedersenOpeningsKappaArray[data.u] = data.pedersen_kappa_opening; pedersenOpeningsLambdaArray[data.u] = data.pedersen_lambda_opening; simpleKeyDealingsArray[data.u] = data.simple_key_dealing; simpleLambdaDealingsArray[data.u] = data.simple_lambda_dealing; pedersenKeyTranscriptsArray[data.u] = data.pedersen_key_transcript; pedersenKappaTranscriptsArray[data.u] = data.pedersen_kappa_transcript; pedersenLambdaTranscriptsArray[data.u] = data.pedersen_lambda_transcript; round2counter[data.u] = 1; } else if ("dealing_kappa_times_lambda" in data) { simpleKeyOpeningsArray[data.u] = data.simple_key_opening; simpleKappaOpeningsArray[data.u] = data.simple_kappa_opening; dealingKeyTimesLambdaArray[data.u] = data.dealing_key_times_lambda; dealingsKappaTimesLambdaArray[data.u] = data.dealing_kappa_times_lambda; simpleKeyTranscriptsArray[data.u] = data.simple_key_transcript; simpleKappaTranscriptsArray[data.u] = data.simple_kappa_transcript; round3counter[data.u] = 1; } } catch (parseError) { console.error("❌ [AutoReg] Error parsing NOSTR event:", parseError); } }, }); if (!h) { throw new Error("Failed to create subscription"); } } catch (error) { console.error("Error connecting to NOSTR relay(s): " + relays + " ERROR: ", error); throw error; } console.log("🚀 [AutoReg] Starting registration step 1..."); const { pedersenDealingArray } = await registerStepOne(seed, true_threshold, index, megaPkArray); let step1Data = { u: userIndex, pedersen_key_dealing: pedersenDealingArray[0], pedersen_kappa_dealing: pedersenDealingArray[1], pedersen_lambda_dealing: pedersenDealingArray[2], }; let eventTemplate1 = { kind: 1, created_at: Math.floor(Date.now() / 1000), content: JSON.stringify(step1Data), tags: [], }; const signedEvent1 = finalizeEvent(eventTemplate1, hexToBytes(String(sk))); console.log("📤 [AutoReg] Publishing step 1 data to NOSTR..."); await pool.publish(relays, signedEvent1); console.log("✅ [AutoReg] Step 1 data published successfully"); let completeProcess = false; const bigUpdater = async () => { try { if (retries > maxRetries) { console.log("⚠️ [AutoReg] Max retries reached in bigUpdater"); return false; } const round1Complete = round1counter.filter(Number).length; const round2Complete = round2counter.filter(Number).length; const round3Complete = round3counter.filter(Number).length; if (pedersenDealingsKeyArray.length === users.length && simpleKeyDealingsArray.length === users.length && dealingsKappaTimesLambdaArray.length === users.length) { if (dealingsKappaTimesLambdaArray.every(Boolean)) { console.log("🎉 [AutoReg] All rounds complete!"); completeProcess = true; } } if (!completeProcess) { if (retries % 10 === 0) { console.log(`📊 [AutoReg] Progress: R1:${round1Complete}/${users.length}, R2:${round2Complete}/${users.length}, R3:${round3Complete}/${users.length}`); } if (round1counter.filter(Number).length === users.length && !pedersenOpeningsKeyArray[userIndex]) { console.log("🚀 [AutoReg] All users completed step 1, starting step 2..."); const { pedersenOpeningArray, simpleDealingArray, pedersenTranscriptArray, } = await registerStepTwo(seed, true_threshold, index, megaPkArray, signature, encMegaSecretKey, pedersenDealingsKeyArray, pedersenDealingsKappaArray, pedersenDealingsLambdaArray); let step2Data = { u: userIndex, pedersen_key_opening: pedersenOpeningArray[0], pedersen_kappa_opening: pedersenOpeningArray[1], pedersen_lambda_opening: pedersenOpeningArray[2], simple_key_dealing: simpleDealingArray[0], simple_lambda_dealing: simpleDealingArray[1], pedersen_key_transcript: pedersenTranscriptArray[0], pedersen_kappa_transcript: pedersenTranscriptArray[1], pedersen_lambda_transcript: pedersenTranscriptArray[2], }; let eventTemplate2 = { kind: 1, created_at: Math.floor(Date.now() / 1000), content: JSON.stringify(step2Data), tags: [], }; const signedEvent2 = finalizeEvent(eventTemplate2, hexToBytes(String(sk))); console.log("📤 [AutoReg] Publishing step 2 data to NOSTR..."); await pool.publish(relays, signedEvent2); console.log("✅ [AutoReg] Step 2 completed and published"); } else if (pedersenOpeningsKeyArray[userIndex] && round2counter.filter(Number).length !== users.length) { if (retries % 20 === 0) { console.log("⏳ [AutoReg] Waiting for other users to complete step 2..."); } } if (round2counter.filter(Number).length === users.length && !dealingsKappaTimesLambdaArray[userIndex]) { console.log("🚀 [AutoReg] All users completed step 2, starting step 3..."); const { simpleOpeningArray, multiplyDealingArray, simpleTranscriptArray, } = await registerStepThree(seed, true_threshold, index, megaPkArray, signature, encMegaSecretKey, simpleKeyDealingsArray, simpleLambdaDealingsArray, pedersenKeyTranscriptsArray[userIndex], pedersenKappaTranscriptsArray[userIndex], pedersenOpeningsLambdaArray[userIndex]); let step3Data = { u: userIndex, simple_key_opening: simpleOpeningArray[0], simple_kappa_opening: simpleOpeningArray[1], dealing_key_times_lambda: multiplyDealingArray[0], dealing_kappa_times_lambda: multiplyDealingArray[1], simple_key_transcript: simpleTranscriptArray[0], simple_kappa_transcript: simpleTranscriptArray[1], }; let eventTemplate3 = { kind: 1, created_at: Math.floor(Date.now() / 1000), content: JSON.stringify(step3Data), tags: [], }; const signedEvent3 = finalizeEvent(eventTemplate3, hexToBytes(String(sk))); console.log("📤 [AutoReg] Publishing step 3 data to NOSTR..."); await pool.publish(relays, signedEvent3); console.log("✅ [AutoReg] Step 3 completed and published"); } else if (dealingsKappaTimesLambdaArray[userIndex] && round3counter.filter(Number).length !== users.length) { if (retries % 20 === 0) { console.log("⏳ [AutoReg] Current user completed all steps! Waiting for others to complete step 3..."); } } if (round3counter.filter(Number).length === users.length) { completeProcess = true; await h.close(); return true; } } } catch (error) { console.error("An error occurred in bigUpdater:", error); } return true; }; async function keepCheckingUntilTrue() { try { console.log("🔄 [AutoReg] Starting main processing loop..."); while (!completeProcess) { try { await sleep(500); retries++; if (retries % 20 === 0) { console.log(`🔄 [AutoReg] Loop iteration ${retries}/${maxRetries}`); } const bigUpdaterResult = await bigUpdater(); if (!bigUpdaterResult) { console.log("❌ [AutoReg] bigUpdater returned false - max retries reached, exiting loop"); break; } } catch (error) { console.error("❌ [AutoReg] Error in processing loop:", error); break; } } const endTime = Date.now(); console.log(`Registration completed in ${endTime - startTime} ms`); return completeProcess; } catch (error) { console.error("❌ [AutoReg] Error in keepCheckingUntilTrue:", error); return false; } } const finalResult = await keepCheckingUntilTrue(); await h.close(); return finalResult; } export async function registerAllSteps(vaultAddress, signer, intuSignature, nostrNode, returnHash) { let signature = ""; let rh = returnHash || false; intuSignature ? (signature = intuSignature) : (signature = await getUserSignature(vaultAddress, signer)); let pko = "", pkao = "", plo = "", skd = "", sld = "", pkt = "", pkat = "", plt = ""; let step1array = []; let step3array = []; let b64s1; let b64s3; let dbKey = await getPolybaseKey(signature); let pkfinal = getPublicKey(hexToBytes(String(dbKey.key))); const pool = new SimplePool(); let preRelays = ["wss://nostr.intu.xyz"]; if (nostrNode) { preRelays.unshift(nostrNode); } let relays = []; for (const relayUrl of preRelays) { try { console.log(`🔌 Attempting to connect to NOSTR relay: ${relayUrl}`); const relay = await Relay.connect(relayUrl); relays.push(relayUrl); console.log(`✅ Successfully connected to NOSTR relay: ${relayUrl}`); break; } catch (error) { console.error(`Error connecting to relay ${relayUrl}:`, error); } } if (relays.length === 0) { throw new Error("No relays available"); } let h = pool.subscribeMany(relays, [ { authors: [pkfinal], }, ], { onevent(event) { let data = JSON.parse(event.content); data.pedersen_key_dealing ? (step1array = [ data.pedersen_key_dealing, data.pedersen_kappa_dealing, data.pedersen_lambda_dealing, ]) : ""; data.pedersen_key_opening ? (pko = data.pedersen_key_opening) : ""; data.pedersen_kappa_opening ? (pkao = data.pedersen_kappa_opening) : ""; data.pedersen_lambda_opening ? (plo = data.pedersen_lambda_opening) : ""; data.simple_key_dealing ? (skd = data.simple_key_dealing) : ""; data.simple_lambda_dealing ? (sld = data.simple_lambda_dealing) : ""; data.pedersen_key_transcript ? (pkt = data.pedersen_key_transcript) : ""; data.pedersen_kappa_transcript ? (pkat = data.pedersen_kappa_transcript) : ""; data.pedersen_lambda_transcript ? (plt = data.pedersen_lambda_transcript) : ""; data.simple_key_opening ? (step3array = [ data.simple_key_opening, data.simple_kappa_opening, data.dealing_key_times_lambda, data.dealing_kappa_times_lambda, data.simple_key_transcript, data.simple_kappa_transcript, ]) : ""; if (step1array.length > 1) { b64s1 = btoa(JSON.stringify(step1array)); } if (step3array.length > 1) { b64s3 = btoa(JSON.stringify(step3array)); } }, oneose() { h.close(); }, }); const sleep = (delay) => new Promise((resolve) => setTimeout(resolve, delay)); while (!(b64s1 && pko && pkao && plo && skd && sld && pkt && pkat && plt && b64s3)) { await sleep(500); } return await registerUserAll(vaultAddress, b64s1, pko, pkao, plo, skd, sld, pkt, pkat, plt, b64s3, signer, rh); } export async function completeVault(vaultAddress, signer, returnHash) { const retryWithDelay = async (fn, retries = 5, delay = 1000) => { try { return await fn(); } catch (error) { console.log(`Attempt failed, retries left: ${retries}. Error:`, error?.message || error); if (retries === 0) throw error; await new Promise((resolve) => setTimeout(resolve, delay)); return retryWithDelay(fn, retries - 1, delay); } }; return retryWithDelay(async () => { let mpk = ""; let rh = returnHash || false; const chainId = (await signer.provider.getNetwork()).chainId; const provider = await getBestProvider(chainId, signer); const vaultContract = await getVaultContract(vaultAddress, provider); const { users, completed, createdDate } = await retryWithDelay(() => vaultContract.vaultInfos(), 5, 2000); if (completed) { return "Vault is already completed."; } if (users.length >= 3) { const finalUsers = [users[0], users[1], users[2]]; const userAddress = await signer.getAddress(); try { const indexerUrl = process.env.INDEXER_URL || process.env.REACT_APP_INDEXER_URL || getGraphEndpoint(chainId); const userRegistrationAll = await getDataWithFallback(() => getUserRegistrationAllInfos(vaultAddress, provider), provider, indexerUrl, 50, () => getUserRegistrationAllInfosDirect(vaultAddress, provider)); if (!userRegistrationAll || userRegistrationAll.length === 0) { console.log("❌ [CompleteVault] No user registration data available yet, retrying..."); throw new Error("No user registration data available yet"); } const hasAnyData = userRegistrationAll.some((data) => data !== null); if (!hasAnyData) { console.log("❌ [CompleteVault] No user registration data has content yet, retrying..."); throw new Error("No user registration data has content yet"); } const userIndex = users.findIndex((address) => address.toLowerCase() === userAddress.toLowerCase()); if (userIndex === -1) { throw new Error("User not found in vault members"); } if (!userRegistrationAll[0] || !userRegistrationAll[1] || !userRegistrationAll[2]) { console.log("⏳ [CompleteVault] Registration data not available for all users, retrying..."); throw new Error("Registration data not available for all users"); } if (!userRegistrationAll[userIndex]) { console.log(`❌ [CompleteVault] User registration data not yet available for user ${userIndex}, retrying...`); throw new Error("User registration data not yet available"); } const step3Crypto = userRegistrationAll[userIndex].step3Crypto; if (!step3Crypto) { console.log("❌ [CompleteVault] Step 3 crypto data not yet available, retrying..."); throw new Error("Step 3 crypto data not yet available"); } try { let step3Result = JSON.parse(atob(step3Crypto)); if (!Array.isArray(step3Result) || step3Result.length < 5) { throw new Error(`Invalid step3Result format: ${JSON.stringify(step3Result)}`); } mpk = await getMasterPublicKey(step3Result[4]); const MPK = "0x" + mpk; return await userCompleteVault(vaultAddress, finalUsers, MPK, signer, rh); } catch (parseError) { console.error("❌ [CompleteVault] Error parsing step3Crypto:", parseError); throw parseError; } } catch (error) { throw error; } } return "Not enough users or data not available"; }); } export async function submitTransaction(to, value, chainId, nonce, data, gasPrice, gas, vaultAddress, signer, notes = "n/a", returnHash = false, sendingProvider) { let date = new Date(); let provider; let client; let signerAddress; if (!sendingProvider) { provider = await getProviderForChain(chainId); } else { if (typeof sendingProvider === "string") { provider = new ethers.providers.StaticJsonRpcProvider(sendingProvider); } else { provider = sendingProvider; } } client = await createViemClientForTransaction(provider); signerAddress = await signer.getAddress(); let decimal = 18; let finalGasPrice; let gasInfo = await provider.getFeeData(); if (gasPrice === undefined || gasPrice === null || gasPrice === "") { if (gasInfo.gasPrice) { finalGasPrice = gasInfo.gasPrice.mul(105).div(100); } else { throw new Error("Unable to determine gas price"); } } else { finalGasPrice = ethers.BigNumber.from(gasPrice); } let gE = null; const networkChainId = (await signer.provider.getNetwork()).chainId; const readProvider = await getBestProvider(Number(networkChainId), signer); const vc = await getVaultContract(vaultAddress, readProvider); const gvc = await vc.vaultInfos(); let masterPublicKey = gvc.masterPublicKey; try { if (data) { gE = await client.estimateGas({ account: masterPublicKey, to: to, value: parseEther(String(value)), data: data, }); } else { gE = await client.estimateGas({ account: masterPublicKey, to: to, value: parseEther(String(value)), }); } } catch (e) { console.warn(`You are likely experiencing an error because the account ${masterPublicKey} doesn't have enough funds to cover the gas+value being requested to transfer on ${chainId}`); console.log(e); return; } let finalGasLimit; if (gas === undefined || gas === null || gas === "") { if (gE) { finalGasLimit = ethers.BigNumber.from(gE).mul(105).div(100); } else { throw new Error("Unable to determine gas limit"); } } else { finalGasLimit = ethers.BigNumber.from(gas); } const formTxResponse = await formTransaction(to, String(value), String(chainId), String(nonce), String(data), finalGasPrice.toString(), finalGasLimit.toString(), String(decimal)); const response = await proposeTransaction(vaultAddress, formTxResponse, signer, notes, returnHash); let date2 = new Date(); if (process.env.DEBUG) { console.log("SUBMIT TX TIME : ", date2.getTime() - date.getTime()); } return response; } export { getUserPreRegisterInfos, getUserSignature, getUtilsParams, getUserRegistrationAllInfos, getRegistrationStep3InfosDB, getRegistrationReshareStep3InfosDB, } from "./web3/utils.js"; export { getUniqueHashFromSignature }; export async function combineSignedTx(vaultAddress, txId, signer, experimental) { const userAddress = await signer.getAddress(); const sleep = (delay) => new Promise((resolve) => setTimeout(resolve, delay)); const retryWithDelay = async (fn, retries = 5, delay = 1000) => { try { return await fn(); } catch (error) { console.log(`Attempt failed, retries left: ${retries}. Error:`, error?.message || error); if (retries === 0) throw error; await sleep(delay); return retryWithDelay(fn, retries - 1, delay); } }; const chainId = (await signer.provider.getNetwork()).chainId; const provider = await getBestProvider(chainId, signer); const vaultContract = await getVaultContract(vaultAddress, provider); const { users, completed, createdDate } = await retryWithDelay(() => vaultContract.vaultInfos(), 5, 2000); if (!completed) { throw new Error("Vault is not completed yet"); } const userIndex = users.findIndex((address) => address.toLowerCase() === userAddress.toLowerCase()); if (userIndex === -1) { throw new Error("User not found in vault members"); } const proposal = await _getProposal(vaultAddress, txId, provider, ethers.utils.defaultAbiCoder); if (!proposal) { throw new Error("Proposal not found"); } const transaction = await _getTransaction(vaultAddress, txId, provider); if (!transaction) { throw new Error("Transaction not found"); } const userRegistrationAll = await getUserRegistrationAllInfos(vaultAddress, provider); if (!userRegistrationAll || !userRegistrationAll[userIndex]) { throw new Error("User registration data not found"); } const step3Crypto = userRegistrationAll[userIndex].step3Crypto; if (!step3Crypto) { throw new Error("Step 3 crypto data not found"); } const step3Result = JSON.parse(atob(step3Crypto)); const masterPublicKey = await getMasterPublicKey(step3Result[4]); const signature = await getUserSignature(vaultAddress, signer); const transactionData = transaction.transactionData; const result = await getUtilsParams(vaultAddress, userAddress, provider); const { seed, threshold, index } = result; let signatureResult; if (!experimental) { signatureResult = await signTransaction(seed, threshold, index, transactionData, signature, step3Result[3], step3Result[0], step3Result[1], step3Result[2], step3Result[4], step3Result[5], step3Result[6]); } else { signatureResult = await signTransactionWithoutLambda(seed, transactionData, signature, step3Result[0], step3Result[1], step3Result[4], step3Result[5]); } return await userConfirmTx(vaultAddress, txId, signatureResult.signedTransaction, signer, experimental || false); } export async function getVaults(userAddress, provider) { console.log("start get vaults"); const userTransactionCount = await provider.getTransactionCount(userAddress); if (userTransactionCount === 0) { return []; } let vaultData; let vaultAddresses = await getFilteredUserInitializedLogs(userAddress, provider); if ((vaultAddresses && vaultAddresses.length === 0) || vaultAddresses === undefined) { return []; } vaultData = await Promise.all(vaultAddresses.map(async (vaultAddress) => { try { const vault = await getVault(vaultAddress, provider); const transactions = await _getTransactions(vaultAddress, provider); const proposals = []; for (let i = 1; i <= vault.proposalCount; i++) { try { const proposal = await _getProposal(vaultAddress, i, provider, ethers.utils.defaultAbiCoder); proposals.push(proposal); } catch (error) { console.warn(`Could not fetch proposal ${i} for vault ${vaultAddress}:`, error); } } return { ...vault, proposals, transactions: transactions || [], }; } catch (error) { console.error(`Error fetching vault data for ${vaultAddress}:`, error); return null; } })); return vaultData.filter(Boolean); } export async function signTx(vaultAddress, txId, signer, intuSignature, experimental, returnHash) { let date = new Date(); const userAddress = await signer.getAddress(); let signature = ""; let transactionData; let megaPkArray; let encMegaSecretKey; let seed; let threshold; let index; let rh = returnHash || false; intuSignature ? (signature = intuSignature) : (signature = await getUserSignature(vaultAddress, signer)); const chainId = (await signer.provider.getNetwork()).chainId; const provider = await getBestProvider(chainId, signer); const gvc = await getVaultContract(vaultAddress, provider); const { users, resharingOccurred } = await gvc.vaultInfos(); const userIndex = users.findIndex((address) => userAddress == address); if (!seed || !threshold || !index || !megaPkArray || !encMegaSecretKey) { const utilsParams = await getUtilsParams(vaultAddress, userAddress, provider); seed = utilsParams.seed; threshold = utilsParams.threshold; index = utilsParams.index; megaPkArray = utilsParams.megaPkArray; encMegaSecretKey = utilsParams.encMegaSecretKey[userIndex]; } const thresholdCount = Math.ceil((megaPkArray.length * threshold) / 100); if (typeof txId === "bigint") { txId = Number(txId); } else if (typeof txId === "string") { txId = parseInt(txId, 10); } const indexerUrl = process.env.INDEXER_URL || process.env.REACT_APP_INDEXER_URL || getGraphEndpoint(chainId); const { getBlockHeightFromRPC, getBlockHeightFromIndexer } = await import("./direct/index.js"); let useRpcFallback = false; try { const rpcHeight = await getBlockHeightFromRPC(provider); const indexerHeight = await getBlockHeightFromIndexer(indexerUrl, chainId); const blockDifference = rpcHeight - indexerHeight; if (blockDifference > 50) { console.log(`⚠️ [SIGN_TX] Indexer is ${blockDifference} blocks behind RPC (threshold: 50). Using RPC fallback.`); useRpcFallback = true; } } catch (error) { console.log("⚠️ [SIGN_TX] Block height check failed, proceeding with indexer"); } let transaction; if (useRpcFallback) { transaction = await getTransactionLeanDirect(vaultAddress, txId, provider); } else { transaction = await _getTransaction(vaultAddress, txId, provider); } transactionData = transaction.transactionData; let userRegistrationAll; if (useRpcFallback) { userRegistrationAll = await getUserRegistrationAllInfosDirect(vaultAddress, provider); } else { userRegistrationAll = await getUserRegistrationAllInfos(vaultAddress, provider); } if (!userRegistrationAll || !userRegistrationAll[userIndex]) { throw new Error("User registration data not found"); } const step3Crypto = userRegistrationAll[userIndex].step3Crypto; if (!step3Crypto) { throw new Error("Step 3 crypto data not found"); } const step3Result = JSON.parse(atob(step3Crypto)); let signatureResult; if (!experimental) { signatureResult = await signTransaction(seed, thresholdCount, index, transactionData, signature, step3Result[3], step3Result[0], step3Result[1], step3Result[2], step3Result[4], step3Result[5], step3Result[6]); } else { signatureResult = await signTransactionWithoutLambda(seed, transactionData, signature, step3Result[0], step3Result[1], step3Result[4], step3Result[5]); } return await userConfirmTx(vaultAddress, txId, signatureResult.signedTransaction, signer, rh); } export async function getAllTransactions(vaultAddress, provider) { const date1 = new Date(); const allTransactions = await _getTransactions(vaultAddress, provider).then(async (transactions) => { return await Promise.all(transactions.map(async (transaction) => { const parseTx = await parseTransaction(transaction.transactionData); let transactionObj = { id: transaction.txId, transactionData: transaction.transactionHash, chainId: parseTx.chainId, data: parseTx.data, gas: parseTx.gas, gasPrice: parseTx.gasPrice, nonce: parseTx.nonce, to: parseTx.to, value: parseTx.value, signedTransactionsNeeded: transaction.signedTransactionsNeeded, userSignedTransactions: transaction.userSignedTransactions, transactionNotes: transaction.transactionNotes, }; return transactionObj; })); }); const date2 = new Date(); if (process.env.DEBUG) { console.log("Time to get all transactions : ", date2.getTime() - date1.getTime()); } return allTransactions; } const retryWithDelay = async (fn, retries = 3, delay = 1000) => { try { return await fn(); } catch (error) { if (retries === 0) throw error; await new Promise((resolve) => setTimeout(resolve, delay)); return retryWithDelay(fn, retries - 1, delay); } }; export async function getTransaction(vaultAddress, txId, provider) { return retryWithDelay(async () => { const transaction = await _getTransaction(vaultAddress, txId, provider); if (!transaction?.transactionData) { throw new Error("Transaction data not available"); } const parseTx = await parseTransaction(transaction.transactionData); return { ...transaction, chainId: parseTx.chainId, data: parseTx.data, gas: parseTx.gas, gasPrice: parseTx.gasPrice, nonce: parseTx.nonce, to: parseTx.to, value: parseTx.value, }; }); } export async function getVaultSingle(userAddress, provider) { const userTransactionCount = await provider.getTransactionCount(userAddress); if (userTransactionCount === 0) { return null; } let vaultAddresses = await getFilteredUserInitializedLogsSingle(userAddress, provider); if (!vaultAddresses?.length) { return null; } const lastVaultAddress = vaultAddresses[vaultAddresses.length - 1]; const vault = await getVault(lastVaultAddress, provider); const proposals = []; for (let i = 1; i <= vault.proposalCount; i++) { try { const proposal = await _getProposal(vault.vaultAddress, i, provider, ethers.utils.defaultAbiCoder); proposals.push(proposal); } catch (error) { console.warn(`Could not fetch proposal ${i} for vault ${vault.vaultAddress}:`, error); } } const transactions = await getAllTransactions(vault.vaultAddress, provider); return { ...vault, proposals, transactions, }; } //# sourceMappingURL=index.native.js.map