UNPKG

@bsv/wallet-toolbox

Version:

BRC100 conforming wallet, wallet storage and wallet signer components

488 lines 24.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const sdk_1 = require("@bsv/sdk"); const TestUtilsWalletStorage_1 = require("../../../../test/utils/TestUtilsWalletStorage"); const utilityHelpers_1 = require("../../../utility/utilityHelpers"); const Services_1 = require("../../../services/Services"); const Wallet_1 = require("../../../Wallet"); const Setup_1 = require("../../../Setup"); const StorageKnex_1 = require("../../StorageKnex"); const WalletStorageManager_1 = require("../../WalletStorageManager"); const auth_express_middleware_1 = require("@bsv/auth-express-middleware"); describe('StorageClient to tagged revision manual tests', () => { jest.setTimeout(99999999); test('0 sync createAction signAction', async () => { if (TestUtilsWalletStorage_1._tu.noEnv('main')) return; const env = TestUtilsWalletStorage_1._tu.getEnv('main'); const tag = 'v1-0-149---'; // revision tags must be followed by '---' as a GCR service URL prefix. const endpointUrl = `https://${tag}prod-storage-921101068003.us-west1.run.app`; const s = await TestUtilsWalletStorage_1._tu.createTestWalletWithStorageClient({ rootKeyHex: env.devKeys[env.identityKey], endpointUrl, chain: 'main' }); const testCode = 'xyzzy42'; const k = s.wallet.keyDeriver.derivePrivateKey([0, testCode], '1', 'self'); const address = k.toPublicKey().toAddress(); const p2pkh = new sdk_1.P2PKH(); const lock = p2pkh.lock(address); for (let i = 0; i < 30; i++) { const balance = await s.wallet.balance(); expect(balance).toBeGreaterThan(10000); const outputs = await s.wallet.listOutputs({ basket: testCode, include: 'entire transactions' }); if (outputs.totalOutputs === 0) { // Create an output in the testCode basket if it doesn't exist const car = await s.wallet.createAction({ labels: [testCode], description: `create ${testCode}`, outputs: [ { basket: testCode, lockingScript: lock.toHex(), satoshis: 1, outputDescription: testCode, tags: [testCode] } ], options: { randomizeOutputs: false, acceptDelayedBroadcast: false } }); expect(car.txid).toBeTruthy(); console.log(`Created outpoint: ${car.txid}:0`); } else { const o = outputs.outputs[0]; if (o && o.outpoint && outputs.BEEF) { // Consume the first output found... const unlock = TestUtilsWalletStorage_1._tu.getUnlockP2PKH(k, o.satoshis); const unlockingScriptLength = await unlock.estimateLength(); // Create an output in the testCode basket if it doesn't exist const cas = await s.wallet.createAction({ labels: [testCode], description: `consume ${testCode}`, inputBEEF: outputs.BEEF, inputs: [ { unlockingScriptLength, outpoint: outputs.outputs[0].outpoint, inputDescription: `consume ${testCode}` } ], options: { randomizeOutputs: false, acceptDelayedBroadcast: false } }); expect(cas.signableTransaction).toBeTruthy(); if (cas.signableTransaction) { const st = cas.signableTransaction; expect(st.reference).toBeTruthy(); const atomicBeef = sdk_1.Beef.fromBinary(st.tx); const tx = atomicBeef.txs[atomicBeef.txs.length - 1].tx; tx.inputs[0].unlockingScriptTemplate = unlock; await tx.sign(); const unlockingScript = tx.inputs[0].unlockingScript.toHex(); const signArgs = { reference: st.reference, spends: { 0: { unlockingScript } }, options: { returnTXIDOnly: true, noSend: false, acceptDelayedBroadcast: false } }; const sr = await s.wallet.signAction(signArgs); expect(sr.txid).toBeTruthy(); console.log(`Consumed outpoint: ${o.outpoint} in ${sr.txid}`); } } } } await s.wallet.destroy(); }); test('1 async createAction signAction', async () => { if (TestUtilsWalletStorage_1._tu.noEnv('main')) return; const env = TestUtilsWalletStorage_1._tu.getEnv('main'); const tag = 'v1-0-155---'; // revision tags must be followed by '---' as a GCR service URL prefix. // const endpointUrl = `https://${tag}prod-storage-921101068003.us-west1.run.app` const endpointUrl = `https://storage.babbage.systems`; const s = await TestUtilsWalletStorage_1._tu.createTestWalletWithStorageClient({ rootKeyHex: env.devKeys[env.identityKey], endpointUrl, chain: 'main' }); const testCode = 'xyzzy43'; const k = s.wallet.keyDeriver.derivePrivateKey([0, testCode], '1', 'self'); const address = k.toPublicKey().toAddress(); const p2pkh = new sdk_1.P2PKH(); const lock = p2pkh.lock(address); const count = 8; const acceptDelayedBroadcast = false; const satoshis = 1; let reps = 0; for (;;) { reps++; console.log(`Async createAction/signAction iteration ${reps}`); let outputs = await s.wallet.listOutputs({ basket: testCode, include: 'entire transactions', limit: count }); const missing = count - outputs.totalOutputs; const balance = await s.wallet.balance(); if (balance < missing * 10000) { console.warn(`balance ${balance} is less than needed ${missing * 10000} to run the test, skipping...`); return; } if (missing > 0) { const createPromises = []; for (let i = 0; i < missing; i++) { // Create an output in the testCode basket if it doesn't exist const car = s.wallet.createAction({ labels: [testCode], description: `create ${testCode}`, outputs: [ { basket: testCode, lockingScript: lock.toHex(), satoshis, outputDescription: testCode, tags: [testCode] } ], options: { randomizeOutputs: false, acceptDelayedBroadcast } }); createPromises.push(car); } const createResults = await Promise.all(createPromises); console.log(`${createPromises.length} createPromises resulting in ${createResults.length} createResults`); for (const car of createResults) { expect(car.txid).toBeTruthy(); console.log(`Created outpoint: ${car.txid}:0`); } outputs = await s.wallet.listOutputs({ basket: testCode, include: 'entire transactions', limit: count }); } const consumeCreatePromises = []; const beef = sdk_1.Beef.fromBinary(outputs.BEEF); for (let i = 0; i < count; i++) { const o = outputs.outputs[i]; if (o && o.outpoint && outputs.BEEF) { // Consume the first output found... const unlock = TestUtilsWalletStorage_1._tu.getUnlockP2PKH(k, satoshis); const unlockingScriptLength = await unlock.estimateLength(); // Create an output in the testCode basket if it doesn't exist const po = sdk_1.Validation.parseWalletOutpoint(o.outpoint); // just to verify it parses before we use it const inputBEEF = beef.toBinaryAtomic(po.txid); const cas = s.wallet.createAction({ labels: [testCode], description: `consume ${testCode}`, inputBEEF, inputs: [ { unlockingScriptLength, outpoint: o.outpoint, inputDescription: `consume ${testCode}` } ], options: { randomizeOutputs: false, acceptDelayedBroadcast } }); consumeCreatePromises.push(cas); } } const consumeCreateResults = await Promise.all(consumeCreatePromises); console.log(`${consumeCreatePromises.length} consumeCreatePromises resulting in ${consumeCreateResults.length} consumeCreateResults`); const consumeSignPromises = []; for (const cas of consumeCreateResults) { expect(cas.signableTransaction).toBeTruthy(); if (cas.signableTransaction) { const st = cas.signableTransaction; expect(st.reference).toBeTruthy(); const atomicBeef = sdk_1.Beef.fromBinary(st.tx); const tx = atomicBeef.txs[atomicBeef.txs.length - 1].tx; const unlock = TestUtilsWalletStorage_1._tu.getUnlockP2PKH(k, satoshis); tx.inputs[0].unlockingScriptTemplate = unlock; await tx.sign(); const unlockingScript = tx.inputs[0].unlockingScript.toHex(); const signArgs = { reference: st.reference, spends: { 0: { unlockingScript } }, options: { returnTXIDOnly: true, noSend: false, acceptDelayedBroadcast } }; const sr = s.wallet.signAction(signArgs); consumeSignPromises.push(sr); } } const consumeSignResults = await Promise.all(consumeSignPromises); console.log(`${consumeSignPromises.length} consumeSignPromises resulting in ${consumeSignResults.length} consumeSignResults`); for (const sr of consumeSignResults) { expect(sr.txid).toBeTruthy(); console.log(`Consumed outpoint in ${sr.txid}`); } await (0, utilityHelpers_1.wait)(15000); } await s.wallet.destroy(); }); test('2 makeAvailable', async () => { if (TestUtilsWalletStorage_1._tu.noEnv('main')) return; const env = TestUtilsWalletStorage_1._tu.getEnv('main'); const tag = 'v1-0-154---'; // revision tags must be followed by '---' as a GCR service URL prefix. const endpointUrl = `https://${tag}prod-storage-921101068003.us-west1.run.app`; // const endpointUrl = `https://storage.babbage.systems` const s = await TestUtilsWalletStorage_1._tu.createTestWalletWithStorageClient({ rootKeyHex: env.devKeys[env.identityKey], endpointUrl, chain: 'main' }); await s.storage.makeAvailable(); await s.wallet.destroy(); }); test('3 well-known auth', async () => { if (TestUtilsWalletStorage_1._tu.noEnv('main')) return; const env = TestUtilsWalletStorage_1._tu.getEnv('main'); const services = new Services_1.Services('main'); const rootKey = sdk_1.PrivateKey.fromHex(env.devKeys['02c3bee1dd15c89937899897578b420e253c21d81de76b6365c2f5ad7ca743cf14']); const keyDeriver = new sdk_1.CachedKeyDeriver(rootKey); const knex = Setup_1.Setup.createMySQLKnex(process.env.MAIN_CLOUD_MYSQL_CONNECTION); const activeStorage = new StorageKnex_1.StorageKnex({ chain: env.chain, knex: knex, commissionSatoshis: 0, commissionPubKeyHex: undefined, feeModel: { model: 'sat/kb', value: 1 } }); const settings = await activeStorage.makeAvailable(); const storage = new WalletStorageManager_1.WalletStorageManager(settings.storageIdentityKey, activeStorage); const wallet = new Wallet_1.Wallet({ chain: env.chain, keyDeriver, storage, services }); const options = { wallet }; const auth = (0, auth_express_middleware_1.createAuthMiddleware)(options); // Currently processIntitialRequest in Peer.js must be edited to use a constant sessionNonce so the two requests will share the same session for (const [wellKnownAuth, makeAvailable, nonce] of [ // [wellKnownAuth0, makeAvailable0, "/RrUGlYwjOkxaQEOClkuEZUCQCWAXA9lUKOzxuJvVhfox6AFXeE/jkXUu9AnqHc/"], // [wellKnownAuth1, makeAvailable1, 'zzEWA7yPnnD1dcy689jdQlV6lQD1pu9XhtrzTJw+ndw/6/d6VFOXJbmF4HouaJOA'] [wellKnownAuth2, makeAvailable2, 'qEH+mrEcyA+ZOLy0NQtyybGcRiHjp4eHtHHJQLxzYqosbGsSrcWvTY2kLdaRq9dQ'] ]) { const req = { path: '/.well-known/auth', headers: wellKnownAuth.headers, body: JSON.parse(wellKnownAuth.body), method: 'POST' }; const res = { status: (code) => { console.log(`Response status: ${code}`); return res; }, json: (obj) => { console.log(`Response body: ${JSON.stringify(obj)}`); return res; } }; let authNextCalled = 0; auth(req, res, () => { authNextCalled++; }); await (0, utilityHelpers_1.wait)(1000); // auth is not async, chains via next methods const req2 = { path: '/', headers: makeAvailable.headers, body: JSON.parse(makeAvailable.body), method: 'POST', protocol: 'https', get: (headerName) => { const headerValue = makeAvailable.headers[headerName.toLowerCase()]; console.log(`Request header ${headerName}: ${headerValue}`); return headerValue; } }; auth(req2, res, () => { authNextCalled++; }); await (0, utilityHelpers_1.wait)(1000); // auth is not async, chains via next methods expect(req2.auth.identityKey).toBe(req.body.identityKey); } await wallet.destroy(); }); }); const wellKnownAuth0 = { body: '{"version":"0.1","messageType":"initialRequest","identityKey":"030edf8ae22d7e55fe3de7f9edbeb8b1e59d9a5adae8916fa39dc8142f491bc40d","initialNonce":"0GZ7LeI3HrbeWRLvTYiSp8Z3zpLCY0W/eROUo3x7TY3QRswJYRpwMvmT9OiDIyMD","requestedCertificates":{"certifiers":[],"types":{}}}', bodyJson: { version: '0.1', messageType: 'initialRequest', identityKey: '030edf8ae22d7e55fe3de7f9edbeb8b1e59d9a5adae8916fa39dc8142f491bc40d', initialNonce: '0GZ7LeI3HrbeWRLvTYiSp8Z3zpLCY0W/eROUo3x7TY3QRswJYRpwMvmT9OiDIyMD', requestedCertificates: { certifiers: [], types: {} } }, headers: { 'accept-encoding': 'br, gzip, deflate', 'accept-language': '*', accept: '*/*', connection: 'close', 'content-length': '266', 'content-type': 'application/json', forwarded: 'for="73.114.228.4";proto=https', host: 'v1-0-154---prod-storage-921101068003.us-west1.run.app', 'sec-fetch-mode': 'cors', traceparent: '00-2f8ddd90c1ed5fc87abc205c94c6939c-04929980c02bf805-01', 'user-agent': 'node', 'x-cloud-trace-context': '2f8ddd90c1ed5fc87abc205c94c6939c/329494501010438149;o=1', 'x-forwarded-for': '73.114.228.4, 169.254.169.126', 'x-forwarded-proto': 'https', 'x-nginx-proxy': 'true', 'x-real-ip': '169.254.169.126' } }; const makeAvailable0 = { headers: { 'accept-encoding': 'br, gzip, deflate', 'accept-language': '*', accept: '*/*', connection: 'close', 'content-length': '61', 'content-type': 'application/json', forwarded: 'for="73.114.228.4";proto=https', host: 'v1-0-154---prod-storage-921101068003.us-west1.run.app', 'sec-fetch-mode': 'cors', traceparent: '00-c663bca2e170f0dffb2d4eeeb42e7e06-81a9008de05f0045-00', 'user-agent': 'node', 'x-bsv-auth-identity-key': '030edf8ae22d7e55fe3de7f9edbeb8b1e59d9a5adae8916fa39dc8142f491bc40d', 'x-bsv-auth-nonce': '+ZoZVHfFkK/s9/15We7+WEcrYC+BZeea8VIQa88NQkE=', 'x-bsv-auth-request-id': '7aUXjqq7wUKNlb4IyX+BAww4xXReG/F9AH5+us5EJ08=', 'x-bsv-auth-signature': '304502210087248dbca9270453ba480d7f32f0e0534e58ffddfb72b5f47465c4868c54e05a02203cdf6db286957959b6e3945c2fc51f0239a1056dc6d9709bf44371eeae8ca5aa', 'x-bsv-auth-version': '0.1', 'x-bsv-auth-your-nonce': '/RrUGlYwjOkxaQEOClkuEZUCQCWAXA9lUKOzxuJvVhfox6AFXeE/jkXUu9AnqHc/', // SessionNonce 'x-cloud-trace-context': 'c663bca2e170f0dffb2d4eeeb42e7e06/9342999511311515717', 'x-forwarded-for': '73.114.228.4, 169.254.169.126', 'x-forwarded-proto': 'https', 'x-nginx-proxy': 'true', 'x-real-ip': '169.254.169.126' }, body: '{"jsonrpc":"2.0","method":"makeAvailable","params":[],"id":1}' }; /** * 2026-02-16 13:30:50.573 https://storage.babbage.systems/.well-known/auth */ const wellKnownAuth1 = { body: '{"version":"0.1","messageType":"initialRequest","identityKey":"02e2ae292b4ff4ed51aacc69dc66a235693bbd417d89853f1f8a7bc36fa7fe4132","initialNonce":"lGlQHqNqFSxKhBBtNBPMYqXDJQADlBCbGPapoq+Yuyx7q8in7QRGHbB5s1Gt8tYU","requestedCertificates":{"certifiers":[],"types":{}}}', bodyJson: { version: '0.1', messageType: 'initialRequest', identityKey: '02e2ae292b4ff4ed51aacc69dc66a235693bbd417d89853f1f8a7bc36fa7fe4132', initialNonce: 'lGlQHqNqFSxKhBBtNBPMYqXDJQADlBCbGPapoq+Yuyx7q8in7QRGHbB5s1Gt8tYU', requestedCertificates: { certifiers: [], types: {} } }, headers: { 'accept-encoding': 'br, gzip, deflate', 'accept-language': '*', accept: '*/*', connection: 'close', 'content-length': '266', 'content-type': 'application/json', forwarded: 'for="139.60.24.151";proto=https', host: 'storage.babbage.systems', 'sec-fetch-mode': 'cors', traceparent: '00-e27cb77d84eb5d2b4c143bdde70bb701-93d9e91f12823fc9-01', 'user-agent': 'node', 'x-cloud-trace-context': 'e27cb77d84eb5d2b4c143bdde70bb701/10653802713185402825;o=1', 'x-forwarded-for': '139.60.24.151, 169.254.169.126', 'x-forwarded-proto': 'https', 'x-nginx-proxy': 'true', 'x-real-ip': '169.254.169.126' } }; /** * 2026-02-16 13:30:50.762 https://storage.babbage.systems/ */ const makeAvailable1 = { headers: { 'accept-encoding': 'br, gzip, deflate', 'accept-language': '*', accept: '*/*', connection: 'close', 'content-length': '61', 'content-type': 'application/json', forwarded: 'for="139.60.24.151";proto=https', host: 'storage.babbage.systems', 'sec-fetch-mode': 'cors', traceparent: '00-1bc7b37f69050532c10da101d45e0f2e-5015abad7e20f2b2-00', 'user-agent': 'node', 'x-bsv-auth-identity-key': '02e2ae292b4ff4ed51aacc69dc66a235693bbd417d89853f1f8a7bc36fa7fe4132', 'x-bsv-auth-nonce': 'OJgzWjyWhdBbUC/1Wf0inA0LXi3EEY26NOvn/NFW1u4=', 'x-bsv-auth-request-id': 'xhhmPf62T0XUpFVMIx4cDHqL67Ira7Emch29/EU9AJo=', 'x-bsv-auth-signature': '304402203b868ad7aed3f18086bce5574c7f4a4224186e952c64811481cb8ae6b80758410220769cf00d0d6e2e892353620f28d1061b26a2dfc5053362fcd022908f2f6d35c6', 'x-bsv-auth-version': '0.1', 'x-bsv-auth-your-nonce': 'zzEWA7yPnnD1dcy689jdQlV6lQD1pu9XhtrzTJw+ndw/6/d6VFOXJbmF4HouaJOA', // SessionNonce 'x-cloud-trace-context': '1bc7b37f69050532c10da101d45e0f2e/5770707259178939058', 'x-forwarded-for': '139.60.24.151, 169.254.169.126', 'x-forwarded-proto': 'https', 'x-nginx-proxy': 'true', 'x-real-ip': '169.254.169.126' }, body: '{"jsonrpc":"2.0","method":"makeAvailable","params":[],"id":1}' }; /** * 2026-02-16 13:30:34.530 https://storage.babbage.systems/.well-known/auth */ const wellKnownAuth2 = { headers: { 'accept-encoding': 'br, gzip, deflate', 'accept-language': '*', accept: '*/*', connection: 'close', 'content-length': '266', 'content-type': 'application/json', forwarded: 'for="139.60.24.151";proto=https', host: 'storage.babbage.systems', 'sec-fetch-mode': 'cors', traceparent: '00-f52531a6aa6dec13ba4ec165aa615590-e48b7ddae1ca5217-01', 'user-agent': 'node', 'x-cloud-trace-context': 'f52531a6aa6dec13ba4ec165aa615590/16468394841454826007;o=1', 'x-forwarded-for': '139.60.24.151, 169.254.169.126', 'x-forwarded-proto': 'https', 'x-nginx-proxy': 'true', 'x-real-ip': '169.254.169.126' }, body: '{"version":"0.1","messageType":"initialRequest","identityKey":"03b85662715f2945c0aa26c04177c50a55161c43120caf1a073b7ccc65e152b547","initialNonce":"LPVCEQYXYEr2Y2pjCYZX8FmaZqc1oPPER5chOCtqvFqQxBBAylImSKlR0rPIqgiX","requestedCertificates":{"certifiers":[],"types":{}}}' }; /** * 2026-02-16 13:30:34.769 https://storage.babbage.systems/ */ const makeAvailable2 = { body: '{"jsonrpc":"2.0","method":"makeAvailable","params":[],"id":1}', headers: { 'accept-encoding': 'br, gzip, deflate', 'accept-language': '*', accept: '*/*', connection: 'close', 'content-length': '61', 'content-type': 'application/json', forwarded: 'for="139.60.24.151";proto=https', host: 'storage.babbage.systems', 'sec-fetch-mode': 'cors', traceparent: '00-7d00483fcd60d92106a9dce7c4a39df0-a3027461b3c018f1-00', 'user-agent': 'node', 'x-bsv-auth-identity-key': '03b85662715f2945c0aa26c04177c50a55161c43120caf1a073b7ccc65e152b547', 'x-bsv-auth-nonce': '954FRnp8CoQ6BS6drfYg+F/0vCSpyp3kSMwxckLYRu0=', 'x-bsv-auth-request-id': 'xxXd9Gddq436hRjxkdNoxXTaz8k5VyTGQRdS/Aer1ks=', 'x-bsv-auth-signature': '3045022100e476674b0ab85d362adefd479cf35ebdd547dbf91917d9e82d27aafe7939532e022008f4b2aa6f264d73ce1638e3767d8b4c16d7c92b315b3668c7d7ff97c5dc681d', 'x-bsv-auth-version': '0.1', 'x-bsv-auth-your-nonce': 'qEH+mrEcyA+ZOLy0NQtyybGcRiHjp4eHtHHJQLxzYqosbGsSrcWvTY2kLdaRq9dQ', 'x-cloud-trace-context': '7d00483fcd60d92106a9dce7c4a39df0/11746078741112035569', 'x-forwarded-for': '139.60.24.151, 169.254.169.126', 'x-forwarded-proto': 'https', 'x-nginx-proxy': 'true', 'x-real-ip': '169.254.169.126' } }; //# sourceMappingURL=StorageClient.man.test.js.map