@intuweb3/sdk
Version:
INTU SDK - Modern blockchain interaction toolkit
877 lines • 41 kB
JavaScript
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