UNPKG

@bsv/wallet-toolbox

Version:

BRC100 conforming wallet, wallet storage and wallet signer components

305 lines 11.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createSetup = createSetup; exports.burnOneSatTestOutput = burnOneSatTestOutput; exports.createOneSatTestOutput = createOneSatTestOutput; exports.recoverOneSatTestOutputs = recoverOneSatTestOutputs; exports.trackReqByTxid = trackReqByTxid; exports.doubleSpendOldChange = doubleSpendOldChange; exports.createMainReviewSetup = createMainReviewSetup; const sdk_1 = require("@bsv/sdk"); const src_1 = require("../../src"); const TestUtilsWalletStorage_1 = require("./TestUtilsWalletStorage"); const sdk_2 = require("../../src/sdk"); const createAction_1 = require("../../src/storage/methods/createAction"); async function createSetup(chain, options) { const env = TestUtilsWalletStorage_1._tu.getEnv(chain); let identityKey; let filePath; if (options.useTestIdentityKey) { identityKey = env.testIdentityKey; filePath = env.testFilePath; } else { if (options.useIdentityKey2) { identityKey = env.identityKey2; } else { identityKey = env.identityKey; filePath = env.filePath; } } if (!identityKey) throw new src_1.sdk.WERR_INVALID_PARAMETER('identityKey', 'valid'); if (!filePath) filePath = `./backup-${chain}-${identityKey}.sqlite`; const setup = { ...options, ...(await TestUtilsWalletStorage_1._tu.createTestWallet({ chain, rootKeyHex: env.devKeys[identityKey], filePath, setActiveClient: options.setActiveClient, addLocalBackup: false, useMySQLConnectionForClient: options.useMySQLConnectionForClient })) }; console.log(`ACTIVE STORAGE: ${setup.storage.getActiveStoreName()}`); return setup; } async function burnOneSatTestOutput(setup, options = {}, howMany = 1) { const outputs = await setup.wallet.listOutputs({ basket: 'test-output', include: 'entire transactions', limit: 1000 }); while (howMany-- > 0) { const o = outputs.outputs.find(o => o.satoshis === 1); if (!o) break; console.log(`burning ${o.outpoint}`); const inputBEEF = outputs.BEEF; const p2pkh = new sdk_1.P2PKH(); const args = { inputBEEF, inputs: [ { unlockingScriptLength: 108, outpoint: o.outpoint, inputDescription: 'burn 1 sat output' } ], description: 'burn output' }; const bcar = await setup.wallet.createAction(args); expect(bcar.signableTransaction); const st = bcar.signableTransaction; const beef = sdk_1.Beef.fromBinary(st.tx); const tx = beef.findAtomicTransaction(beef.txs.slice(-1)[0].txid); const unlock = p2pkh.unlock(setup.keyDeriver.rootKey, 'all', false); const unlockingScript = (await unlock.sign(tx, 0)).toHex(); const signArgs = { reference: st.reference, spends: { 0: { unlockingScript } } }; const sar = await setup.wallet.signAction(signArgs); console.log(sar.txid); expect(sar.txid); } } async function createOneSatTestOutput(setup, options = {}, howMany = 1) { if (howMany < 1) throw new src_1.sdk.WERR_INVALID_PARAMETER('howMany', 'at least 1'); let car = {}; let noSendChange = undefined; let txids = []; let vargs; for (let i = 0; i < howMany; i++) { const args = { outputs: [ { lockingScript: new sdk_1.P2PKH().lock(sdk_1.PublicKey.fromString(setup.identityKey).toAddress()).toHex(), satoshis: 1, outputDescription: 'test output', customInstructions: JSON.stringify({ type: 'P2PKH', key: 'identity' }), basket: 'test-output' } ], description: 'create test output', options: { ...options, noSendChange } }; vargs = (0, sdk_2.validateCreateActionArgs)(args); car = await setup.wallet.createAction(args); expect(car.txid); txids.push(car.txid); noSendChange = car.noSendChange; const req = await src_1.EntityProvenTxReq.fromStorageTxid(setup.activeStorage, car.txid); expect(req !== undefined && req.history.notes !== undefined); if (req && req.history.notes) { if (vargs.isNoSend) { expect(req.status === 'nosend').toBe(true); expect(req.history.notes.length).toBe(1); const n = req.history.notes[0]; expect(n.what === 'status' && n.status_now === 'nosend').toBe(true); } else { expect(req.status === 'unsent').toBe(true); expect(req.history.notes.length).toBe(1); const n = req.history.notes[0]; expect(n.what === 'status' && n.status_now === 'unsent').toBe(true); } } } if (vargs.isNoSend) { // Create final sending transaction const args = { description: 'send batch', options: { ...options, sendWith: txids } }; vargs = (0, sdk_2.validateCreateActionArgs)(args); car = await setup.wallet.createAction(args); } return car; } async function recoverOneSatTestOutputs(setup, testOptionsMode) { const outputs = await setup.wallet.listOutputs({ basket: 'test-output', include: 'entire transactions', limit: 1000 }); if (outputs.outputs.length > 0) { const args = { inputBEEF: outputs.BEEF, inputs: [], description: 'recover test output' }; if (testOptionsMode === 1) { args.options = { acceptDelayedBroadcast: false }; } const p2pkh = new sdk_1.P2PKH(); for (const o of outputs.outputs) { args.inputs.push({ unlockingScriptLength: 108, outpoint: o.outpoint, inputDescription: 'recovered test output' }); } const car = await setup.wallet.createAction(args); expect(car.signableTransaction); const st = car.signableTransaction; const beef = sdk_1.Beef.fromBinary(st.tx); const tx = beef.findAtomicTransaction(beef.txs.slice(-1)[0].txid); const signArgs = { reference: st.reference, spends: {} // 0: { unlockingScript } }, }; for (let i = 0; i < outputs.outputs.length; i++) { const o = outputs.outputs[i]; const unlock = p2pkh.unlock(setup.keyDeriver.rootKey, 'all', false); const unlockingScript = (await unlock.sign(tx, i)).toHex(); signArgs.spends[i] = { unlockingScript }; } const sar = await setup.wallet.signAction(signArgs); expect(sar.txid); } } async function trackReqByTxid(setup, txid) { var _a; const req = await src_1.EntityProvenTxReq.fromStorageTxid(setup.activeStorage, txid); expect(req !== undefined && req.history.notes !== undefined); if (!req || !req.history.notes) throw new src_1.sdk.WERR_INTERNAL(); let newBlocks = 0; let lastHeight; for (; req.status !== 'completed';) { let height = (_a = setup.monitor.lastNewHeader) === null || _a === void 0 ? void 0 : _a.height; if (req.status === 'unsent') { // send it... } if (req.status === 'sending') { // send it... } if (req.status === 'unmined') { if (height && lastHeight) { if (height === lastHeight) { await (0, src_1.wait)(1000 * 60); } else { newBlocks++; expect(newBlocks < 5); } } } await setup.monitor.runOnce(); await req.refreshFromStorage(setup.activeStorage); lastHeight = height; } } /** * This method will normally throw an error on the initial createAction call due to the output being doublespent * @param setup * @param options * @returns */ async function doubleSpendOldChange(setup, options) { const auth = await setup.wallet.storage.getAuth(true); if (!auth.userId || !setup.wallet.storage.getActive().isStorageProvider) throw new Error('active must be StorageProvider'); const s = setup.wallet.storage.getActive(); const o = (0, src_1.verifyOne)(await s.findOutputs({ partial: { userId: auth.userId, spendable: false, change: true }, paged: { limit: 1 } })); await s.validateOutputScript(o); const lockingScript = sdk_1.Script.fromBinary(o.lockingScript); const otx = (0, src_1.verifyTruthy)(await s.findTransactionById(o.transactionId)); if (otx.status !== 'completed') throw new Error('output must be from completed transaction'); const inputBEEF = (await s.getBeefForTransaction(o.txid, {})).toBinary(); (0, TestUtilsWalletStorage_1.logger)(`spending ${o.txid} vout ${o.vout}`); const sabppp = new src_1.ScriptTemplateBRC29({ derivationPrefix: o.derivationPrefix, derivationSuffix: o.derivationSuffix, keyDeriver: setup.wallet.keyDeriver }); const args = { inputBEEF, inputs: [ { unlockingScriptLength: 108, outpoint: `${o.txid}.${o.vout}`, inputDescription: 'spent change output' } ], description: 'intentional doublespend', options }; let car; try { (0, createAction_1.setDisableDoubleSpendCheckForTest)(true); car = await setup.wallet.createAction(args); } finally { (0, createAction_1.setDisableDoubleSpendCheckForTest)(false); } expect(car.signableTransaction); const st = car.signableTransaction; const beef = sdk_1.Beef.fromBinary(st.tx); const tx = beef.findAtomicTransaction(beef.txs.slice(-1)[0].txid); const unlock = sabppp.unlock(setup.rootKey.toHex(), setup.identityKey, o.satoshis, lockingScript); const unlockingScript = (await unlock.sign(tx, 0)).toHex(); const signArgs = { reference: st.reference, spends: { '0': { unlockingScript } }, options }; const sar = await setup.wallet.signAction(signArgs); return sar; } async function createMainReviewSetup() { const env = TestUtilsWalletStorage_1._tu.getEnv('main'); const knex = src_1.Setup.createMySQLKnex(process.env.MAIN_CLOUD_MYSQL_CONNECTION); const storage = new src_1.StorageKnex({ chain: env.chain, knex: knex, commissionSatoshis: 0, commissionPubKeyHex: undefined, feeModel: { model: 'sat/kb', value: 1 } }); const servicesOptions = src_1.Services.createDefaultOptions(env.chain); if (env.whatsonchainApiKey) servicesOptions.whatsOnChainApiKey = env.whatsonchainApiKey; const services = new src_1.Services(servicesOptions); storage.setServices(services); await storage.makeAvailable(); return { env, storage, services }; } //# sourceMappingURL=localWalletMethods.js.map