UNPKG

@silvana-one/coordination

Version:

Silvana Coordination Client

142 lines 4.74 kB
import { ParallelTransactionExecutor, } from "@mysten/sui/transactions"; import { suiClient } from "./sui-client.js"; import { nanoid } from "nanoid"; import { sleep } from "./sleep.js"; const executors = {}; const locks = {}; const LOCK_TIMEOUT = 1000 * 60 * 2; // 5 minutes async function getLock(address) { const id = nanoid(); let locked = false; const start = Date.now(); while (!locked && Date.now() - start < LOCK_TIMEOUT) { if (locks[address]) { await sleep(Math.floor(Math.random() * 10) + 10); } else { locks[address] = id; await sleep(10); if (locks[address] === id) { locked = true; return id; } } } return undefined; } async function releaseLock(params) { const { address, id } = params; if (locks[address] === id) { locks[address] = undefined; } } function getExecutor(keyPair) { const keyPairId = keyPair.toSuiAddress(); if (!executors[keyPairId]) { executors[keyPairId] = new ParallelTransactionExecutor({ client: suiClient, signer: keyPair, initialCoinBalance: 500000000n, minimumCoinBalance: 300000000n, maxPoolSize: 5, }); locks[keyPairId] = undefined; } return executors[keyPairId]; } export async function executeTx(params) { let lockId; let address; try { const { tx, keyPair, useParallelExecutor = false, showErrors = true, } = params; let executedTx; let start = 0; let end = 0; if (useParallelExecutor) { address = keyPair.toSuiAddress(); lockId = await getLock(address); if (!lockId) { throw new Error("Failed to get lock"); } start = Date.now(); const executor = getExecutor(keyPair); executedTx = (await executor.executeTransaction(tx, { showEffects: true, showObjectChanges: true, showInput: true, showEvents: true, showBalanceChanges: true, })).data; end = Date.now(); await waitTx(executedTx.digest); await sleep(1000); await releaseLock({ address: address, id: lockId }); } else { address = keyPair.toSuiAddress(); lockId = await getLock(address); if (!lockId) { throw new Error("Failed to get lock"); } const signedTx = await tx.sign({ signer: keyPair, client: suiClient, }); start = Date.now(); // const dryRun = await suiClient.devInspectTransactionBlock({ // sender: keypair.toSuiAddress(), // transactionBlock: signedTx.bytes // }); // dryRun.effects.gasUsed.computationCost // const gasPrice = await suiClient.getReferenceGasPrice(); executedTx = await suiClient.executeTransactionBlock({ transactionBlock: signedTx.bytes, signature: signedTx.signature, options: { showEffects: true, showObjectChanges: true, showInput: true, showEvents: true, showBalanceChanges: true, }, }); end = Date.now(); await releaseLock({ address, id: lockId }); } if (executedTx?.effects?.status?.status === "failure") { if (showErrors) { console.log(`Errors for tx ${executedTx.digest}:`, executedTx?.effects?.status?.error); throw new Error(`tx execution failed: ${executedTx.digest}`); } } return { tx: executedTx, digest: executedTx.digest, events: executedTx?.events?.[0]?.parsedJson, executeTime: end - start, }; } catch (error) { if (lockId && address) { await releaseLock({ address, id: lockId }); } console.error("Error in executeTx", error.message); return undefined; } } export async function waitTx(digest) { console.time(`wait sui tx`); const txWaitResult = await suiClient.waitForTransaction({ digest, options: { showEffects: true, showObjectChanges: true, showInput: true, showEvents: true, showBalanceChanges: true, }, }); console.timeEnd(`wait sui tx`); return txWaitResult; } //# sourceMappingURL=execute.js.map