Versie 0.2.0
This commit is contained in:
commit
e77d8fd373
495 files changed
+81026
No files matched your search
@@ -0,0 +1,429 @@
|
||||
// Generated, do not edit. sha256:5ad4e9e80b4d00212b534f31292a4fbb321ddf002172941e8c0d4d2648e0cfdc
|
||||
import { describe, it, beforeEach, mock } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
|
||||
import { createDbHarness } from '../helpers/db-node.mjs';
|
||||
|
||||
const harness = createDbHarness();
|
||||
mock.module('../../server/db.js', { namedExports: harness.exports });
|
||||
|
||||
const { listSourceTxs, setTxLabels, upsertWalletTxs, labelChannelTxs } = await import('../../server/data/wallet-txs.js');
|
||||
|
||||
let ctx;
|
||||
beforeEach(() => {
|
||||
harness.recreate();
|
||||
harness.exports.run(
|
||||
`INSERT INTO Account (name, searchName, kind, isOwnCustody, scanEnabled, isActive, closedAt) VALUES ('Kluis','kluis','wallet',1,1,1,NULL)`);
|
||||
const account = harness.exports.lastId();
|
||||
harness.exports.run(
|
||||
`INSERT INTO WalletSource (accountId, kind, value, name, createdAt)
|
||||
VALUES (?, 'xpub', 'zpub-test', 'Ledger', '2024-01-01T00:00:00')`, [account]);
|
||||
const bron = harness.exports.lastId();
|
||||
harness.exports.run(
|
||||
`INSERT INTO WalletSource (accountId, kind, value, name, createdAt)
|
||||
VALUES (?, 'address', 'bc1qlos', 'Los adres', '2024-01-01T00:00:00')`, [account]);
|
||||
ctx = { account, bron, bron2: harness.exports.lastId() };
|
||||
});
|
||||
|
||||
const beweging = (extra = {}) => ({
|
||||
accountId: ctx.account, sourceId: ctx.bron, txid: 'tx-1', direction: 'in',
|
||||
valueSats: 100_000, ...extra,
|
||||
});
|
||||
const rij = (txid = 'tx-1') => harness.exports.one(
|
||||
`SELECT * FROM WalletTransaction WHERE accountId = ? AND txid = ?`, [ctx.account, txid]);
|
||||
const aantal = () => harness.exports.one(`SELECT COUNT(*) AS n FROM WalletTransaction`).n;
|
||||
|
||||
describe('upsertWalletTxs: nieuwe bewegingen', () => {
|
||||
it('bewaart alle velden en zet createdAt zelf', async () => {
|
||||
await upsertWalletTxs([beweging({
|
||||
feeSats: 250, blockHeight: 840_000, blockTime: '2024-05-01T12:00:00', address: 'bc1qontvangst',
|
||||
})]);
|
||||
const t = rij();
|
||||
assert.equal(t.sourceId, ctx.bron);
|
||||
assert.equal(t.direction, 'in');
|
||||
assert.equal(t.valueSats, 100_000);
|
||||
assert.equal(t.feeSats, 250);
|
||||
assert.equal(t.blockHeight, 840_000);
|
||||
assert.equal(t.blockTime, '2024-05-01T12:00:00');
|
||||
assert.equal(t.address, 'bc1qontvangst');
|
||||
assert.ok(t.createdAt, 'het tijdstip komt uit de datalaag, niet van de scanner');
|
||||
});
|
||||
|
||||
it('accepteert een beweging zonder blok- en fee-gegevens', async () => {
|
||||
await upsertWalletTxs([beweging()]);
|
||||
const t = rij();
|
||||
assert.equal(t.feeSats, null);
|
||||
assert.equal(t.blockHeight, null);
|
||||
assert.equal(t.blockTime, null);
|
||||
assert.equal(t.address, null);
|
||||
});
|
||||
|
||||
it('schrijft een hele lijst in één keer weg en persisteert één keer', async () => {
|
||||
const voor = harness.calls.persist;
|
||||
await upsertWalletTxs([
|
||||
beweging({ txid: 'tx-1' }), beweging({ txid: 'tx-2' }), beweging({ txid: 'tx-3' }),
|
||||
]);
|
||||
assert.equal(aantal(), 3);
|
||||
assert.equal(harness.calls.persist, voor + 1, 'één persist voor de hele batch');
|
||||
});
|
||||
|
||||
it('persisteert ook bij een lege lijst zonder te struikelen', async () => {
|
||||
await upsertWalletTxs([]);
|
||||
assert.equal(aantal(), 0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('upsertWalletTxs: dezelfde beweging opnieuw (de herscan)', () => {
|
||||
it('werkt de bestaande rij bij in plaats van een tweede te maken', async () => {
|
||||
await upsertWalletTxs([beweging()]);
|
||||
const eersteId = rij().id;
|
||||
|
||||
await upsertWalletTxs([beweging({ blockHeight: 840_123, blockTime: '2024-05-02T09:00:00', feeSats: 300 })]);
|
||||
assert.equal(aantal(), 1, 'geen dubbele rij: (account, txid) is uniek');
|
||||
const t = rij();
|
||||
assert.equal(t.id, eersteId, 'dezelfde rij, dus koppelingen naar dit id blijven geldig');
|
||||
assert.equal(t.blockHeight, 840_123, 'de bevestiging komt erbij');
|
||||
assert.equal(t.feeSats, 300);
|
||||
});
|
||||
|
||||
it('laat het label van de gebruiker staan', async () => {
|
||||
await upsertWalletTxs([beweging()]);
|
||||
harness.exports.run(`INSERT INTO Label (name, searchName) VALUES ('Salaris','salaris')`);
|
||||
const label = harness.exports.lastId();
|
||||
await setTxLabels([rij().id], label);
|
||||
|
||||
await upsertWalletTxs([beweging({ blockHeight: 840_123, blockTime: '2024-05-02T09:00:00Z' })]);
|
||||
assert.equal(rij().labelId, label, 'een herscan raakt het label niet');
|
||||
});
|
||||
|
||||
it('laat createdAt op het eerste moment staan', async () => {
|
||||
await upsertWalletTxs([beweging()]);
|
||||
harness.exports.run(
|
||||
`UPDATE WalletTransaction SET createdAt = '2020-01-01T00:00:00.000Z' WHERE txid = 'tx-1'`);
|
||||
|
||||
await upsertWalletTxs([beweging({ valueSats: 999 })]);
|
||||
assert.equal(rij().createdAt, '2020-01-01T00:00:00.000Z',
|
||||
'createdAt is wanneer wij de beweging voor het eerst zagen, niet wanneer we hem laatst zagen');
|
||||
assert.equal(rij().valueSats, 999, 'de rest van de rij is wél bijgewerkt');
|
||||
});
|
||||
|
||||
it('houdt dezelfde txid op een ánder account apart', async () => {
|
||||
harness.exports.run(
|
||||
`INSERT INTO Account (name, searchName, kind, isOwnCustody, scanEnabled, isActive, closedAt) VALUES ('Tweede','tweede','wallet',1,1,1,NULL)`);
|
||||
const tweede = harness.exports.lastId();
|
||||
await upsertWalletTxs([beweging(), { ...beweging(), accountId: tweede, sourceId: null }]);
|
||||
assert.equal(aantal(), 2);
|
||||
});
|
||||
|
||||
it('verplaatst een beweging naar een andere bron als de scan dat zegt', async () => {
|
||||
await upsertWalletTxs([beweging()]);
|
||||
await upsertWalletTxs([beweging({ sourceId: ctx.bron2 })]);
|
||||
assert.equal(rij().sourceId, ctx.bron2, 'sourceId staat wél in de UPDATE-lijst');
|
||||
});
|
||||
});
|
||||
|
||||
describe('listSourceTxs', () => {
|
||||
it('geeft alleen de bewegingen van die bron', async () => {
|
||||
await upsertWalletTxs([
|
||||
beweging({ txid: 'a' }),
|
||||
beweging({ txid: 'b', sourceId: ctx.bron2 }),
|
||||
]);
|
||||
assert.deepEqual(listSourceTxs(ctx.bron).map(t => t.txid), ['a']);
|
||||
assert.deepEqual(listSourceTxs(ctx.bron2).map(t => t.txid), ['b']);
|
||||
});
|
||||
|
||||
it('zet onbevestigde bewegingen bovenaan, daarna nieuwste blok eerst', async () => {
|
||||
await upsertWalletTxs([
|
||||
beweging({ txid: 'oud', blockHeight: 830_000, blockTime: '2024-01-01T00:00:00' }),
|
||||
beweging({ txid: 'nieuw', blockHeight: 840_000, blockTime: '2024-06-01T00:00:00' }),
|
||||
beweging({ txid: 'mempool' }),
|
||||
]);
|
||||
assert.deepEqual(listSourceTxs(ctx.bron).map(t => t.txid), ['mempool', 'nieuw', 'oud']);
|
||||
});
|
||||
|
||||
it('joint de labelnaam mee en laat een beweging zonder label staan', async () => {
|
||||
await upsertWalletTxs([beweging({ txid: 'met' }), beweging({ txid: 'zonder' })]);
|
||||
harness.exports.run(`INSERT INTO Label (name, searchName) VALUES ('Salaris','salaris')`);
|
||||
const label = harness.exports.lastId();
|
||||
await setTxLabels([rij('met').id], label);
|
||||
|
||||
const perTxid = Object.fromEntries(listSourceTxs(ctx.bron).map(t => [t.txid, t.label_name]));
|
||||
assert.equal(perTxid.met, 'Salaris');
|
||||
assert.equal(perTxid.zonder, null, 'LEFT JOIN: zonder label valt de rij niet weg');
|
||||
});
|
||||
|
||||
it('geeft een lege lijst voor een bron zonder bewegingen', () => {
|
||||
assert.deepEqual(listSourceTxs(ctx.bron), []);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setTxLabels', () => {
|
||||
async function drieBewegingen() {
|
||||
await upsertWalletTxs([beweging({ txid: 'a' }), beweging({ txid: 'b' }), beweging({ txid: 'c' })]);
|
||||
return ['a', 'b', 'c'].map(t => rij(t).id);
|
||||
}
|
||||
|
||||
it('zet één label op meerdere bewegingen tegelijk', async () => {
|
||||
const [a, b, c] = await drieBewegingen();
|
||||
harness.exports.run(`INSERT INTO Label (name, searchName) VALUES ('Salaris','salaris')`);
|
||||
const label = harness.exports.lastId();
|
||||
|
||||
await setTxLabels([a, c], label);
|
||||
assert.equal(rij('a').labelId, label);
|
||||
assert.equal(rij('c').labelId, label);
|
||||
assert.equal(rij('b').labelId, null, 'wat er niet in de lijst staat blijft ongemoeid');
|
||||
});
|
||||
|
||||
it('haalt het label weg met null', async () => {
|
||||
const [a] = await drieBewegingen();
|
||||
harness.exports.run(`INSERT INTO Label (name, searchName) VALUES ('Salaris','salaris')`);
|
||||
await setTxLabels([a], harness.exports.lastId());
|
||||
await setTxLabels([a], null);
|
||||
assert.equal(rij('a').labelId, null);
|
||||
});
|
||||
|
||||
it('weigert een lege lijst in plaats van alles te labelen', async () => {
|
||||
await assert.rejects(() => setTxLabels([], 1), (e) => e.key === 'accounts.labelNoTxs');
|
||||
await assert.rejects(() => setTxLabels(null, 1), (e) => e.key === 'accounts.labelNoTxs');
|
||||
await assert.rejects(() => setTxLabels('niet-een-array', 1), (e) => e.key === 'accounts.labelNoTxs');
|
||||
});
|
||||
|
||||
it('persisteert één keer voor de hele set', async () => {
|
||||
const [a, b] = await drieBewegingen();
|
||||
harness.exports.run(`INSERT INTO Label (name, searchName) VALUES ('Salaris','salaris')`);
|
||||
const label = harness.exports.lastId();
|
||||
const voor = harness.calls.persist;
|
||||
await setTxLabels([a, b], label);
|
||||
assert.equal(harness.calls.persist, voor + 1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('upsertWalletTxs: bron en account mogen niet botsen', () => {
|
||||
it('weigert een bron die bij een ander account hoort', async () => {
|
||||
harness.exports.run(
|
||||
`INSERT INTO Account (name, searchName, kind, isOwnCustody, scanEnabled, isActive, closedAt)
|
||||
VALUES ('Ander','ander','wallet',1,0,1,NULL)`);
|
||||
const ander = harness.exports.lastId();
|
||||
await assert.rejects(() => upsertWalletTxs([beweging({ accountId: ander })]),
|
||||
/source .* belongs to account/);
|
||||
assert.equal(aantal(), 0, 'en er blijft niets half ingevoerd staan');
|
||||
});
|
||||
|
||||
it('weigert een bron die niet bestaat', async () => {
|
||||
await assert.rejects(() => upsertWalletTxs([beweging({ sourceId: 9999 })]), /does not exist/);
|
||||
});
|
||||
|
||||
it('laat een beweging zónder bron door', async () => {
|
||||
await upsertWalletTxs([beweging({ sourceId: null })]);
|
||||
assert.equal(rij().sourceId, null);
|
||||
});
|
||||
|
||||
it('weigert ook bij het bijwerken van een bestaande beweging', async () => {
|
||||
await upsertWalletTxs([beweging()]);
|
||||
harness.exports.run(
|
||||
`INSERT INTO Account (name, searchName, kind, isOwnCustody, scanEnabled, isActive, closedAt)
|
||||
VALUES ('Ander','ander','wallet',1,0,1,NULL)`);
|
||||
const ander = harness.exports.lastId();
|
||||
harness.exports.run(
|
||||
`INSERT INTO WalletSource (accountId, kind, value, name, createdAt)
|
||||
VALUES (?, 'xpub', 'zpub-ander', 'Andere Ledger', '2024-01-01T00:00:00')`, [ander]);
|
||||
const andereBron = harness.exports.lastId();
|
||||
await assert.rejects(() => upsertWalletTxs([beweging({ sourceId: andereBron })]),
|
||||
/belongs to account/);
|
||||
assert.equal(rij().sourceId, ctx.bron, 'de bestaande rij is niet aangeraakt');
|
||||
});
|
||||
});
|
||||
|
||||
describe('randwaardes: een batch van duizend', () => {
|
||||
it('schrijft duizend bewegingen weg met één persist', async () => {
|
||||
const voor = harness.calls.persist;
|
||||
await upsertWalletTxs(Array.from({ length: 1000 }, (_, i) => beweging({ txid: `bulk-${i}` })));
|
||||
assert.equal(aantal(), 1000);
|
||||
assert.equal(harness.calls.persist, voor + 1, 'nog steeds één persist, ook bij duizend rijen');
|
||||
});
|
||||
|
||||
it('houdt bij dezelfde beweging TWEE KEER in één batch de laatste over', async () => {
|
||||
await upsertWalletTxs([
|
||||
beweging({ txid: 'dubbel', valueSats: 111 }),
|
||||
beweging({ txid: 'dubbel', valueSats: 222 }),
|
||||
]);
|
||||
assert.equal(aantal(), 1, 'één rij, geen twee');
|
||||
const rij = harness.exports.one(`SELECT valueSats FROM WalletTransaction WHERE txid = 'dubbel'`);
|
||||
assert.equal(rij.valueSats, 222, 'de laatste uit de batch wint');
|
||||
});
|
||||
});
|
||||
|
||||
describe('upsertWalletTxs: lightning', () => {
|
||||
const betaling = (extra = {}) => ({
|
||||
accountId: ctx.account, sourceId: ctx.bron, layer: 'lightning', txid: 'hash-1', direction: 'out',
|
||||
valueSats: 21, feeSats: 1, blockTime: '2026-10-19T10:00:00Z', ...extra,
|
||||
});
|
||||
const lnRijen = () => harness.exports.all(
|
||||
`SELECT sourceId, layer, valueSats FROM WalletTransaction WHERE layer = 'lightning' ORDER BY sourceId`);
|
||||
|
||||
it('een betaling twee keer is één rij, bijgewerkt', async () => {
|
||||
await upsertWalletTxs([betaling()]);
|
||||
await upsertWalletTxs([betaling({ valueSats: 22 })]);
|
||||
assert.deepEqual(lnRijen(), [{ sourceId: ctx.bron, layer: 'lightning', valueSats: 22 }]);
|
||||
});
|
||||
|
||||
it('dezelfde hash op twee bronnen van één account: twee rijen, en geen die de ander overschrijft', async () => {
|
||||
await upsertWalletTxs([betaling(), betaling({ sourceId: ctx.bron2, valueSats: 99 })]);
|
||||
assert.deepEqual(lnRijen(), [
|
||||
{ sourceId: ctx.bron, layer: 'lightning', valueSats: 21 },
|
||||
{ sourceId: ctx.bron2, layer: 'lightning', valueSats: 99 }]);
|
||||
});
|
||||
|
||||
it('een payment hash die ook als on-chain txid bestaat, botst niet', async () => {
|
||||
await upsertWalletTxs([beweging({ txid: 'hash-1' }), betaling()]);
|
||||
assert.equal(aantal(), 2);
|
||||
});
|
||||
|
||||
it('weigert een lightning-beweging zonder bron, zonder tijd of met een blokhoogte, en een onbekende laag', async () => {
|
||||
await assert.rejects(upsertWalletTxs([betaling({ sourceId: null })]), /needs its source/);
|
||||
await assert.rejects(upsertWalletTxs([betaling({ blockTime: null })]), /moment it settled/);
|
||||
await assert.rejects(upsertWalletTxs([betaling({ blockHeight: 900_000 })]), /no block height/);
|
||||
await assert.rejects(upsertWalletTxs([betaling({ layer: 'bliksem' })]), /Unknown wallet movement layer/);
|
||||
assert.equal(aantal(), 0);
|
||||
});
|
||||
|
||||
it('bewaart de memo compact: van een zap-verzoek alleen wat gelezen wordt', async () => {
|
||||
const zap = { kind: 9734, pubkey: 'c'.repeat(64), content: 'Hoi', tags: [['p', 'd'.repeat(64)], ['relays', 'wss://x']], sig: 'y' };
|
||||
await upsertWalletTxs([betaling({ memo: zap })]);
|
||||
const memo = harness.exports.one(`SELECT memo FROM WalletTransaction WHERE layer = 'lightning'`).memo;
|
||||
assert.deepEqual(JSON.parse(memo), { kind: 9734, pubkey: 'c'.repeat(64), content: 'Hoi', tags: [['p', 'd'.repeat(64)]] });
|
||||
await upsertWalletTxs([betaling({ memo: null })]);
|
||||
assert.equal(harness.exports.one(`SELECT memo FROM WalletTransaction WHERE layer = 'lightning'`).memo, null);
|
||||
});
|
||||
|
||||
it('een betaling aan uzelf houdt zijn soort, en een lightning-rij kan geen kanaal zijn', async () => {
|
||||
await upsertWalletTxs([betaling({ kind: 'self' })]);
|
||||
assert.equal(harness.exports.one(`SELECT kind FROM WalletTransaction WHERE layer = 'lightning'`).kind, 'self');
|
||||
await assert.rejects(upsertWalletTxs([betaling({ txid: 'hash-2', kind: 'channel' })]), /ordinary or 'self'/);
|
||||
});
|
||||
|
||||
it('zonder laag is een beweging on-chain, zoals de scanner hem altijd stuurde', async () => {
|
||||
await upsertWalletTxs([beweging()]);
|
||||
assert.equal(rij().layer, 'onchain');
|
||||
});
|
||||
|
||||
describe('het label van een tweeling', () => {
|
||||
const labelVan = (bron, txid = 'hash-1') => harness.exports.one(
|
||||
`SELECT labelId FROM WalletTransaction WHERE sourceId = ? AND txid = ? AND layer = 'lightning'`, [bron, txid]).labelId;
|
||||
const idVan = bron => harness.exports.one(
|
||||
`SELECT id FROM WalletTransaction WHERE sourceId = ? AND layer = 'lightning'`, [bron]).id;
|
||||
const nieuwLabel = naam => {
|
||||
harness.exports.run(`INSERT INTO Label (name, searchName) VALUES (?, ?)`, [naam, naam.toLowerCase()]);
|
||||
return harness.exports.lastId();
|
||||
};
|
||||
|
||||
it('setTxLabels zet het label ook op de tweeling, en haalt het daar ook weg', async () => {
|
||||
await upsertWalletTxs([betaling(), betaling({ sourceId: ctx.bron2 })]);
|
||||
const zap = nieuwLabel('Zap');
|
||||
await setTxLabels([idVan(ctx.bron2)], zap);
|
||||
assert.equal(labelVan(ctx.bron), zap);
|
||||
await setTxLabels([idVan(ctx.bron)], null);
|
||||
assert.equal(labelVan(ctx.bron2), null);
|
||||
});
|
||||
|
||||
it('raakt geen on-chain beweging met dezelfde txid en geen andere betaling', async () => {
|
||||
await upsertWalletTxs([betaling(), betaling({ sourceId: ctx.bron2 }), beweging({ txid: 'hash-1' }),
|
||||
betaling({ sourceId: ctx.bron2, txid: 'hash-2' })]);
|
||||
await setTxLabels([idVan(ctx.bron)], nieuwLabel('Zap'));
|
||||
assert.equal(harness.exports.one(
|
||||
`SELECT labelId FROM WalletTransaction WHERE layer = 'onchain' AND txid = 'hash-1'`).labelId, null);
|
||||
assert.equal(labelVan(ctx.bron2, 'hash-2'), null);
|
||||
});
|
||||
|
||||
it('een tweeling die later binnenkomt, neemt het label over', async () => {
|
||||
await upsertWalletTxs([betaling()]);
|
||||
const zap = nieuwLabel('Zap');
|
||||
await setTxLabels([idVan(ctx.bron)], zap);
|
||||
await upsertWalletTxs([betaling({ sourceId: ctx.bron2 })]);
|
||||
assert.equal(labelVan(ctx.bron2), zap);
|
||||
});
|
||||
|
||||
it('overschrijft bij het bijwerken nooit een eigen label', async () => {
|
||||
await upsertWalletTxs([betaling(), betaling({ sourceId: ctx.bron2 })]);
|
||||
const zap = nieuwLabel('Zap');
|
||||
const eigen = nieuwLabel('Eigen');
|
||||
harness.exports.run(`UPDATE WalletTransaction SET labelId = ? WHERE sourceId = ?`, [zap, ctx.bron]);
|
||||
harness.exports.run(`UPDATE WalletTransaction SET labelId = ? WHERE sourceId = ?`, [eigen, ctx.bron2]);
|
||||
await upsertWalletTxs([betaling({ sourceId: ctx.bron2, valueSats: 22 })]);
|
||||
assert.equal(labelVan(ctx.bron2), eigen);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('labelChannelTxs', () => {
|
||||
const TX = n => n.repeat(64).slice(0, 64);
|
||||
const labelVan = txid => harness.exports.one(
|
||||
`SELECT l.name FROM WalletTransaction t LEFT JOIN Label l ON l.id = t.labelId WHERE t.txid = ?`, [txid])?.name ?? null;
|
||||
|
||||
it('zet het label op een on-chain beweging zonder label, en maakt het label één keer', async () => {
|
||||
await upsertWalletTxs([beweging({ txid: TX('a') }), beweging({ txid: TX('b') })]);
|
||||
assert.equal(await labelChannelTxs(ctx.account, [TX('a'), TX('c')]), 1);
|
||||
assert.equal(labelVan(TX('a')), 'Lightning-kanaal');
|
||||
assert.equal(labelVan(TX('b')), null);
|
||||
assert.equal(await labelChannelTxs(ctx.account, [TX('b')]), 1);
|
||||
assert.equal(harness.exports.one(`SELECT COUNT(*) AS n FROM Label`).n, 1, 'het label bestaat één keer');
|
||||
});
|
||||
|
||||
it('laat een label van de gebruiker staan', async () => {
|
||||
await upsertWalletTxs([beweging({ txid: TX('a') })]);
|
||||
harness.exports.run(`INSERT INTO Label (name, searchName) VALUES ('Mijn kanaal', 'mijn kanaal')`);
|
||||
const eigen = harness.exports.lastId();
|
||||
await setTxLabels([rij(TX('a')).id], eigen);
|
||||
assert.equal(await labelChannelTxs(ctx.account, [TX('a')]), 0);
|
||||
assert.equal(labelVan(TX('a')), 'Mijn kanaal');
|
||||
});
|
||||
|
||||
it('raakt geen lightning-rij en geen ander account', async () => {
|
||||
harness.exports.run(`INSERT INTO Account (name, searchName, kind, isOwnCustody, scanEnabled, isActive, closedAt) VALUES ('Ander','ander','wallet',1,1,1,NULL)`);
|
||||
const ander = harness.exports.lastId();
|
||||
await upsertWalletTxs([
|
||||
{ accountId: ctx.account, sourceId: ctx.bron, layer: 'lightning', txid: TX('a'), direction: 'out', valueSats: 1, blockTime: '2026-10-19T10:00:00Z' },
|
||||
{ accountId: ander, txid: TX('a'), direction: 'out', valueSats: 1 },
|
||||
]);
|
||||
assert.equal(await labelChannelTxs(ctx.account, [TX('a')]), 0);
|
||||
assert.equal(harness.exports.one(`SELECT COUNT(*) AS n FROM Label`).n, 0, 'geen label voor niets');
|
||||
});
|
||||
|
||||
it('zet de soort kanaal, ook waar de gebruiker een eigen label heeft, en een herscan laat hem staan', async () => {
|
||||
await upsertWalletTxs([beweging({ txid: TX('a') }), beweging({ txid: TX('b') })]);
|
||||
harness.exports.run(`INSERT INTO Label (name, searchName) VALUES ('Mijn kanaal', 'mijn kanaal')`);
|
||||
await setTxLabels([rij(TX('a')).id], harness.exports.lastId());
|
||||
await labelChannelTxs(ctx.account, [TX('a')]);
|
||||
assert.equal(rij(TX('a')).kind, 'channel');
|
||||
assert.equal(rij(TX('b')).kind, null);
|
||||
await upsertWalletTxs([beweging({ txid: TX('a') })]);
|
||||
assert.equal(rij(TX('a')).kind, 'channel');
|
||||
});
|
||||
|
||||
it('neemt het account van een gekoppelde on-chain wallet mee, en geen ongekoppeld account', async () => {
|
||||
harness.exports.run(`INSERT INTO Connection (kind, name, searchName, url, isActive, isSystem, createdAt, updatedAt)
|
||||
VALUES ('lnd', 'Node', 'node', 'https://node.test', 1, 0, '2024-01-01', '2024-01-01')`);
|
||||
const conn = harness.exports.lastId();
|
||||
const nieuwAccount = naam => {
|
||||
harness.exports.run(`INSERT INTO Account (name, searchName, kind, isOwnCustody, scanEnabled, isActive, closedAt) VALUES (?, ?, 'wallet', 1, 1, 1, NULL)`, [naam, naam]);
|
||||
return harness.exports.lastId();
|
||||
};
|
||||
const koud = nieuwAccount('Koud');
|
||||
const los = nieuwAccount('Los');
|
||||
harness.exports.run(`INSERT INTO WalletSource (accountId, connectionId, kind, value, createdAt) VALUES (?, ?, 'lnd', '', '2026-01-01')`, [ctx.account, conn]);
|
||||
harness.exports.run(`INSERT INTO WalletSource (accountId, connectionId, kind, value, scriptType, createdAt) VALUES (?, ?, 'xpub', 'zpub', 'p2wpkh', '2026-01-01')`, [koud, conn]);
|
||||
await upsertWalletTxs([{ accountId: koud, txid: TX('a'), direction: 'out', valueSats: 1 },
|
||||
{ accountId: los, txid: TX('a'), direction: 'out', valueSats: 1 }]);
|
||||
await labelChannelTxs(ctx.account, [TX('a')]);
|
||||
const soort = acc => harness.exports.one(`SELECT kind FROM WalletTransaction WHERE accountId = ?`, [acc]).kind;
|
||||
assert.equal(soort(koud), 'channel');
|
||||
assert.equal(soort(los), null);
|
||||
});
|
||||
|
||||
it('weigert iets anders dan een lijst txids in kleine hex', async () => {
|
||||
await assert.rejects(labelChannelTxs(ctx.account, ['niet-hex']), /lowercase hex/);
|
||||
await assert.rejects(labelChannelTxs(ctx.account, [TX('A')]), /lowercase hex/);
|
||||
await assert.rejects(labelChannelTxs(null, [TX('a')]), /account id/);
|
||||
assert.equal(await labelChannelTxs(ctx.account, []), 0);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user