UNPKG

shield-bridge-sdk

Version:
195 lines (194 loc) 7.9 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import { expose } from 'threads/worker'; import { RpcReadAdapter } from '@taquito/taquito'; import { SaplingToolkit, InMemorySpendingKey, InMemoryViewingKey, SaplingTransactionViewer, } from '@taquito/sapling'; import { RpcClient } from '@taquito/rpc'; import { PrefixV2, b58Encode } from '@taquito/utils'; import * as sapling from '@airgap/sapling-wasm'; import * as bip39 from 'bip39'; const SECRET_KEY_METHOD = 'secretKey'; const MNEMONIC_METHOD = 'mnemonic'; const VIEWING_KEY_METHOD = 'viewingKey'; let iMSK; let iMVK; let sTk; let isViewOnly = false; let currentSaplingDetails = null; let currentRpcAdapter = null; const createExtendedSpendingKey = (mnemonic) => __awaiter(void 0, void 0, void 0, function* () { const fullSeed = yield bip39.mnemonicToSeed(mnemonic); const first32 = fullSeed.subarray(0, 32); const second32 = fullSeed.subarray(32); const seed = Buffer.from( // eslint-disable-next-line no-bitwise first32.map((byte, index) => byte ^ second32[index])); const spendingKeyArr = new Uint8Array(yield sapling.getExtendedSpendingKey(seed, 'm/')); return b58Encode(spendingKeyArr, PrefixV2.SaplingSpendingKey); }); const loadSaplingSecret = (_a) => __awaiter(void 0, [_a], void 0, function* ({ sk, saplingDetails, rpcUrl, skType = MNEMONIC_METHOD, }) { try { const secretKey = sk; const loadAccountMethod = skType; // Reset previous state iMSK = null; iMVK = null; isViewOnly = false; if (loadAccountMethod === SECRET_KEY_METHOD) { iMSK = new InMemorySpendingKey(secretKey); } else if (loadAccountMethod === MNEMONIC_METHOD) { iMSK = yield InMemorySpendingKey.fromMnemonic(secretKey); } else if (loadAccountMethod === VIEWING_KEY_METHOD) { iMVK = new InMemoryViewingKey(secretKey); isViewOnly = true; } else { throw new Error('Invalid account loading method provided'); } // Store sapling details and RPC adapter for later use currentSaplingDetails = saplingDetails; currentRpcAdapter = new RpcReadAdapter(new RpcClient(rpcUrl)); } catch (err) { iMSK = null; iMVK = null; sTk = null; isViewOnly = false; currentSaplingDetails = null; currentRpcAdapter = null; throw err; } try { // Create toolkit - only works with spending key for transactions if (!isViewOnly) { sTk = new SaplingToolkit({ saplingSigner: iMSK }, saplingDetails, currentRpcAdapter); } else { // For view-only mode, we don't need SaplingToolkit for transactions // The viewing key will be used directly for balance and transaction queries sTk = null; } } catch (err) { iMSK = null; iMVK = null; sTk = null; isViewOnly = false; currentSaplingDetails = null; currentRpcAdapter = null; throw err; } }); const getViewingKey = () => __awaiter(void 0, void 0, void 0, function* () { if (isViewOnly && iMVK) { // Already have viewing key, return it as hex string const fvk = iMVK.getFullViewingKey(); return Buffer.from(fvk).toString('hex'); } if (iMSK) { // Get viewing key from spending key const viewingKeyProvider = yield iMSK.getSaplingViewingKeyProvider(); const fvk = viewingKeyProvider.getFullViewingKey(); return Buffer.from(fvk).toString('hex'); } throw new Error('No spending key or viewing key loaded'); }); const getPaymentAddress = () => __awaiter(void 0, void 0, void 0, function* () { if (isViewOnly && iMVK) { return iMVK.getAddress(); } if (iMSK) { const viewingKeyProvider = yield iMSK.getSaplingViewingKeyProvider(); return viewingKeyProvider.getAddress(); } throw new Error('No spending key or viewing key loaded'); }); const prepareShieldedTransaction = (shieldTransactions) => { if (isViewOnly) { throw new Error('Cannot prepare transactions with a viewing key. A spending key is required.'); } return sTk.prepareShieldedTransaction(shieldTransactions); }; const prepareUnshieldedTransaction = (unshieldTransaction) => { if (isViewOnly) { throw new Error('Cannot prepare transactions with a viewing key. A spending key is required.'); } return sTk.prepareUnshieldedTransaction(unshieldTransaction); }; const prepareSaplingTransaction = (saplingTransactions = []) => { if (isViewOnly) { throw new Error('Cannot prepare transactions with a viewing key. A spending key is required.'); } return sTk.prepareSaplingTransaction(saplingTransactions); }; const getSaplingBalance = () => __awaiter(void 0, void 0, void 0, function* () { let txViewer; if (isViewOnly && iMVK) { // Create transaction viewer from viewing key if (!currentSaplingDetails || !currentRpcAdapter) { throw new Error('Sapling details not initialized'); } const saplingContractId = currentSaplingDetails.saplingId ? { saplingId: currentSaplingDetails.saplingId } : { contractAddress: currentSaplingDetails.contractAddress }; txViewer = new SaplingTransactionViewer(iMVK, saplingContractId, currentRpcAdapter); } else if (sTk) { txViewer = yield sTk.getSaplingTransactionViewer(); } else { throw new Error('No sapling toolkit or viewing key available'); } const balance = yield txViewer.getBalance(); return balance.toNumber(); }); const getSaplingTransactions = () => __awaiter(void 0, void 0, void 0, function* () { let txViewer; if (isViewOnly && iMVK) { // Create transaction viewer from viewing key if (!currentSaplingDetails || !currentRpcAdapter) { throw new Error('Sapling details not initialized'); } const saplingContractId = currentSaplingDetails.saplingId ? { saplingId: currentSaplingDetails.saplingId } : { contractAddress: currentSaplingDetails.contractAddress }; txViewer = new SaplingTransactionViewer(iMVK, saplingContractId, currentRpcAdapter); } else if (sTk) { txViewer = yield sTk.getSaplingTransactionViewer(); } else { throw new Error('No sapling toolkit or viewing key available'); } const transactionHistory = yield txViewer.getIncomingAndOutgoingTransactions(); return { incoming: transactionHistory.incoming.map((tx) => (Object.assign(Object.assign({}, tx), { value: tx.value.toNumber() }))), outgoing: transactionHistory.outgoing.map((tx) => (Object.assign(Object.assign({}, tx), { value: tx.value.toNumber() }))), }; }); const reInitializeSapling = () => { iMSK = null; sTk = null; }; const saplingWorker = { createExtendedSpendingKey, loadSaplingSecret, getPaymentAddress, getViewingKey, prepareShieldedTransaction, prepareUnshieldedTransaction, prepareSaplingTransaction, getSaplingBalance, getSaplingTransactions, reInitializeSapling, }; expose(saplingWorker);