UNPKG

@bsv/wallet-toolbox

Version:

BRC100 conforming wallet, wallet storage and wallet signer components

240 lines (197 loc) 10.7 kB
import { WhatsOnChainBroadcaster, WhatsOnChainConfig } from '@bsv/sdk' import { _tu } from '../../../../test/utils/TestUtilsWalletStorage' import { WhatsOnChain } from '../WhatsOnChain' import { Services } from '../../Services' import { sdk, StorageClient, wait } from '../../../index.client' import { Setup, StorageKnex } from '../../../index.all' describe('whatsonchain tests', () => { jest.setTimeout(99999999) test('00', () => {}) if (_tu.noTestEnv('test')) return const envTest = _tu.getEnv('test') const wocTest = new WhatsOnChain(envTest.chain, { apiKey: envTest.taalApiKey }) const envMain = _tu.getEnv('main') const wocMain = new WhatsOnChain(envMain.chain, { apiKey: envMain.taalApiKey }) test('0 getRawTx testnet', async () => { const rawTx = await wocTest.getRawTx('7e5b797b86abd31a654bf296900d6cb14d04ef0811568ff4675494af2d92166b') expect( rawTx === '010000000158EED5DBBB7E2F7D70C79A11B9B61AABEECFA5A7CEC679BEDD00F42C48A4BD45010000006B483045022100AE8BB45498A40E2AC797775C405C108168804CD84E8C09A9D42D280D18EDDB6D022024863BFAAC5FF3C24CA65E2F3677EDA092BC3CC5D2EFABA73264B8FF55CF416B412102094AAF520E14E1C4D68496822800BCC7D3B3B26CA368E004A2CB70B398D82FACFFFFFFFF0203000000000000007421020A624B72B34BC192851C5D8890926BBB70B31BC10FDD4E3BC6534E41B1C81B93AC03010203030405064630440220013B4984F4054C2FBCD2F448AB896CCA5C4E234BF765B0C7FB27EDE572A7F7DA02201A5C8D0D023F94C209046B9A2B96B2882C5E43B72D8115561DF8C07442010EEA6D7592090000000000001976A9146511FCE2F7EF785A2102142FBF381AD1291C918688AC00000000' ) expect(await wocTest.getRawTx('1'.repeat(64))).toBeUndefined() }) test('1 getRawTx mainnet', async () => { const rawTx = await wocMain.getRawTx('d9978ffc6676523208f7b33bebf1b176388bbeace2c7ef67ce35c2eababa1805') expect( rawTx === '0100000001026A66A5F724EB490A55E0E08553286F08AD57E92C4BF34B5C44EA6BC0A49828020000006B483045022100C3D9A5ACA30C1F2E1A54532162E7AFE5AA69150E4C06D760414A16D1EA1BABD602205E0D9191838B0911A1E7328554A2B22EFAA80CF52B15FBA37C3046A0996C7AAD412103FA3CF488CA98D9F2DB91843F36BAF6BE39F6C947976C02394602D09FBC5F4CF4FFFFFFFF0210270000000000001976A91444C04354E88975C4BEF30CFE89D300CC7659F7E588AC96BC0000000000001976A9149A53E5CF5F1876924D98A8B35CA0BC693618682488AC00000000' ) expect(await wocMain.getRawTx('1'.repeat(64))).toBeUndefined() }) test('2 getMerklePath testnet', async () => { const services = new Services(envTest.chain) { const r = await wocTest.getMerklePath( '7e5b797b86abd31a654bf296900d6cb14d04ef0811568ff4675494af2d92166b', services ) const s = JSON.stringify(r) expect(s).toBe( '{"name":"WoCTsc","notes":[{"what":"getMerklePathSuccess","name":"WoCTsc","status":200,"statusText":"OK"}],"merklePath":{"blockHeight":1661398,"path":[[{"offset":6,"hash":"7e5b797b86abd31a654bf296900d6cb14d04ef0811568ff4675494af2d92166b","txid":true},{"offset":7,"hash":"97dd9d9080394d52338588732d9f84e1debca93f171f674ac3beac1e75495568"}],[{"offset":2,"hash":"81beedcd219d9e03255bde2ee479db34b9fed04d30373ba8bc264a64af2515b9"}],[{"offset":0,"hash":"9965f9aaeea33f6878335e6f7e6bdb544c3a8550c84e2f0daca54e9cd912111c"}]]},"header":{"version":536870912,"previousHash":"000000000688340a14b77e49bb0fca5ac7b624f7f79a5517583d1aae61c4e658","merkleRoot":"edbc07082ca0a31d5ec89d1f503a9cd41112c0d8f3221a96acfb8a9d16f8e82b","time":1739624725,"bits":486604799,"nonce":1437884974,"height":1661398,"hash":"00000000d8a73bf9a37272a71886ea92a25376bed1c1916f2b5cfbec4d6f6a25"}}' ) } { const r = await wocTest.getMerklePath('1'.repeat(64), services) const s = JSON.stringify(r) expect(s).toBe( '{"name":"WoCTsc","notes":[{"what":"getMerklePathNoData","name":"WoCTsc","status":200,"statusText":"OK"}]}' ) } }) test('3 getMerklePath mainnet', async () => { const services = new Services(envMain.chain) { const r = await wocMain.getMerklePath( 'd9978ffc6676523208f7b33bebf1b176388bbeace2c7ef67ce35c2eababa1805', services ) const s = JSON.stringify(r) expect(s).toBe( '{"name":"WoCTsc","notes":[{"what":"getMerklePathSuccess","name":"WoCTsc","status":200,"statusText":"OK"}],"merklePath":{"blockHeight":883637,"path":[[{"offset":46,"hash":"d9978ffc6676523208f7b33bebf1b176388bbeace2c7ef67ce35c2eababa1805","txid":true},{"offset":47,"hash":"066f6fa6fa988f2e3a9d6fe35fa0d3666c652dac35cabaeebff3738a4e67f68f"}],[{"offset":22,"hash":"232089a6f77c566151bc4701fda394b5cc5bf17073140d46a73c4c3ed0a7b911"}],[{"offset":10,"hash":"c639b3a6ce127f67dbd01c7331a6fca62a4b429830387bd68ac6ac05e162116d"}],[{"offset":4,"hash":"730cec44be97881530947d782bb328d25f1122fdae206296937fffb03e936d48"}],[{"offset":3,"hash":"28b681f8ab8db0fa4d5d20cb1532b95184a155346b0b8447bde580b2406d51e6"}],[{"offset":0,"hash":"c49a18028e230dd1439b26794c08c339506f24a450f067c4facd4e0d5a346490"}],[{"offset":1,"hash":"0ba57d1b1fad6874de3640c01088e3dedad3507e5b3a3102b9a8a8055f3df88b"}],[{"offset":1,"hash":"c830edebe5565c19ba584ec73d49129344d17539f322509b7c314ae641c2fcdb"}],[{"offset":1,"hash":"ff62d5ed2a94eb93a2b7d084b8f15b12083573896b6a58cf871507e3352c75f5"}]]},"header":{"version":1040187392,"previousHash":"00000000000000000d9f6889dd6743500adee204ea25d8a57225ecd48b111769","merkleRoot":"59c1efd79fae0d9c29dd8da63f8eeec0aadde048f4491c6bfa324fcfd537156d","time":1739329877,"bits":403818359,"nonce":596827153,"height":883637,"hash":"0000000000000000060ac8d63b78d41f58c9aba0b09f81db7d51fa4905a47263"}}' ) } { const r = await wocMain.getMerklePath('1'.repeat(64), services) const s = JSON.stringify(r) expect(s).toBe( '{"name":"WoCTsc","notes":[{"what":"getMerklePathNoData","name":"WoCTsc","status":200,"statusText":"OK"}]}' ) } }) test('4 updateBsvExchangeRate', async () => { { const r = await wocMain.updateBsvExchangeRate() expect(r.base).toBe('USD') expect(r.rate).toBeGreaterThan(0) expect(r.timestamp).toBeTruthy() } }) test('5 getTxPropagation testnet', async () => { return // throwing internal server error 500 when tested. const count = await wocTest.getTxPropagation('7e5b797b86abd31a654bf296900d6cb14d04ef0811568ff4675494af2d92166b') expect(count > 0) expect((await wocTest.getTxPropagation('1'.repeat(64))) === 0) }) test('6 getTxPropagation mainnet', async () => {}) test.skip('7 postRawTx testnet', async () => { if (Setup.noEnv('test')) return const woc = wocTest const c = await _tu.createNoSendTxPair('test') const rawTxDo = c.beef.findTxid(c.txidDo)!.tx!.toHex() const rawTxUndo = c.beef.findTxid(c.txidUndo)!.tx!.toHex() const txidDo = await woc.postRawTx(rawTxDo) expect(txidDo).toBe(c.txidDo) await wait(1000) const txidUndo = await woc.postRawTx(rawTxUndo) expect(txidUndo).toBe(c.txidUndo) }) test.skip('7a nosend cleanup testnet', async () => { const c = await _tu.createWalletSetupEnv('test') const actions = await c.wallet.listActions({ labels: [], limit: 1000 }) const nosends = actions.actions.filter(a => a.status === 'nosend') const refs = ['yUfgNVaFcBNyP2Xv'] for (const ref of refs) { try { await c.wallet.abortAction({ reference: ref }) } catch (eu: unknown) { const e = sdk.WalletError.fromUnknown(eu) } } }) test.skip('8 postRawTx mainnet', async () => { if (Setup.noEnv('main')) return const woc = wocMain const c = await _tu.createNoSendTxPair('main') const rawTxDo = c.beef.findTxid(c.txidDo)!.tx!.toHex() const rawTxUndo = c.beef.findTxid(c.txidUndo)!.tx!.toHex() const txidDo = await woc.postRawTx(rawTxDo) expect(txidDo).toBe(c.txidDo) /* try { // This method is broken as of 2025-02-16 const count = await woc.getTxPropagation(txidDo) } catch {} // getRawTx returns undefined for unmined transactions, sometimes. let rawTx = await woc.getRawTx(txidDo) let i = 0 while (!rawTx) { console.log(`${i++} waiting for WhatsOnChain to acknowledge new transaction exists.`) await wait(5000) rawTx = await woc.getRawTx(txidDo) } expect(rawTx).toBe(rawTxDo) */ // allow for propagation... await wait(1000) const txidUndo = await woc.postRawTx(rawTxUndo) expect(txidUndo).toBe(c.txidUndo) await wait(1000) // Confirm double spend detection. // 'The rawTx parameter must be valid. unexpected response code 500: 258: txn-mempool-conflict' // 'The rawTx parameter must be valid. unexpected response code 500: Missing inputs' try { await woc.postRawTx(c.doubleSpendTx.toHex()) expect(false) } catch (eu: unknown) { const e = sdk.WalletError.fromUnknown(eu) expect( e.message === 'The rawTx parameter must be valid. unexpected response code 500: 258: txn-mempool-conflict' || 'The rawTx parameter must be valid. unexpected response code 500: Missing inputs' ) } }) test.skip('8a nosend cleanup mainnet', async () => { const c = await _tu.createWalletSetupEnv('main') const actions = await c.wallet.listActions({ labels: [], limit: 1000 }) const nosends = actions.actions.filter(a => a.status === 'nosend') // No way to get from actions to reference string values for use with abortAction... if (c['activeStorage']) { const s = c['activeStorage'] as StorageKnex const userId = c['userId'] as number const txs = await s.findTransactions({ partial: { userId, status: 'nosend' } }) const refs = txs.map(tx => tx.reference) for (const ref of refs) { try { await c.wallet.abortAction({ reference: ref }) } catch (eu: unknown) { const e = sdk.WalletError.fromUnknown(eu) } } } await c.wallet.destroy() }) test.skip('8b run monitor mainnet', async () => { if (Setup.noEnv('main')) return if (!Setup.getEnv('main').filePath) return // Only run if `Setup` style .env is present with a sqlite filePath... const c = await _tu.createWalletSetupEnv('main') await c.monitor.runOnce() await c.wallet.destroy() }) test.skip('8c backup to cloud', async () => { if (Setup.noEnv('main')) return if (!Setup.getEnv('main').filePath) return const c = await _tu.createWalletSetupEnv('main') const client = new StorageClient(c.wallet, 'https://storage.babbage.systems') await c.storage.addWalletStorageProvider(client) await c.storage.updateBackups() await c.wallet.destroy() }) })