Every rule, proven. This page is generated by the tests passing.

This is the engine's verification record. It is not written by hand. The engine's test suite runs with a recorder attached, and the record below is captured from the tests actually executing, written only when every one of them passes. The engine's build aborts if a single law test fails, which means one sentence is literally true by construction: this page cannot exist unless every proof passes.

29 rules, 111 assertions, all green. Captured 2026-08-23 10:01 UTC, engine build 2026-08-23 10:01 UTC. Where a rule follows statute, the sections are linked. Where it follows an HMRC worked example, the manual page is linked so you can check our arithmetic against theirs. Where the engine cites no statute, this page claims none, figures like rates and allowances are verified against GOV.UK published values instead, and they appear under behaviour, not law.

The law rules, 13 of them, cited and tested

HMRC CRYPTO22251, Victoria, section 104 pool

TCGA 1992 section 104 , worked example CRYPTO22251

The scenario the test runs

1 Jan 2024 buy 100 TOKENA for £1,000; 18 Sept 2024 buy 50 TOKENA for £125,000; 1 Dec 2024 sell 50 TOKENA for £300,000. The engine must produce gain = 258,000, pool cost left = 84,000, pool qty left = 100.

What the test proves: The suite asserts 3 facts about this scenario and every one must hold for this file to exist. (3 assertions)

HMRC CRYPTO22255, Melanie, 30 day rule

TCGA 1992 section 106A , worked example CRYPTO22255

The scenario the test runs

1 Jan 2024 buy 14000 TOKENE for £200,000; 30 Aug 2024 sell 4000 TOKENE for £160,000; 11 Sept 2024 buy 500 TOKENE for £17,500. The engine must produce gain = 92,500, pool qty = 10,500, pool cost = 150,000.

What the test proves: The suite asserts 3 facts about this scenario and every one must hold for this file to exist. (3 assertions)

matching order, same day beats 30 day beats pool

TCGA 1992 section 106A, TCGA 1992 section 105, TCGA 1992 section 104

The scenario the test runs

1 Jan 2024 buy 10 X for £1,000; 1 Jun 2024 sell 5 X for £2,000; 1 Jun 2024 buy 2 X for £600; 10 Jun 2024 buy 1 X for £400. The engine must produce cost = 1,200, rules used in order = "same,thirty,pool", pool left = 8.

What the test proves: The suite asserts 3 facts about this scenario and every one must hold for this file to exist. (3 assertions)

30 day window is forward only

TCGA 1992 section 106A

The scenario the test runs

1 Jan 2024 buy 10 X for £1,000; 1 Jun 2024 sell 10 X for £5,000; 2 Jul 2024 buy 10 X for £9,000. The engine must produce day 31 stays in pool = 4,000.

What the test proves: The suite asserts 1 fact about this scenario and every one must hold for this file to exist. (1 assertion)

crypto to crypto trade is a disposal, CRYPTO22100

, worked example CRYPTO22100

The scenario the test runs

1 Jan 2024 buy 1 BTC for £20,000; 1 Jun 2024 trade 1 BTC for £30,000 into 10 ETH. The engine must produce BTC gain on the swap = 10,000, ETH enters the pool at the swap value = 30,000, ETH pool qty = 10.

What the test proves: The suite asserts 3 facts about this scenario and every one must hold for this file to exist. (3 assertions)

income, s37 TCGA, taxed at receipt then base cost

TCGA 1992 section 37

The scenario the test runs

1 May 2024 income 2 ETH for £4,000; 1 Nov 2024 sell 2 ETH for £5,200. The engine must produce income total = 4,000, gain is only the uplift after receipt = 1,200.

What the test proves: The suite asserts 2 facts about this scenario and every one must hold for this file to exist. (2 assertions)

allowable costs, s38, fees both sides

TCGA 1992 section 38

The scenario the test runs

1 Jan 2024 buy 10 X for £1,000 with a £100 fee; 1 Jun 2024 sell 10 X for £2,000 with a £50 fee. The engine must produce gain net of both fees = 850.

What the test proves: The suite asserts 1 fact about this scenario and every one must hold for this file to exist. (1 assertion)

NFTs are not pooled and no matching rules apply, CRYPTO22200

, worked example CRYPTO22200

The scenario the test runs

1 Jan 2024 buy 1 PUNK123 for £5,000; 1 Jun 2024 sell 1 PUNK123 for £9,000; 10 Jun 2024 buy 1 PUNK123 for £40,000. The engine must produce NFT gain uses its own cost, not the 30 day buy = 4,000, no matching rules recorded = "pool".

What the test proves: The suite asserts 2 facts about this scenario and every one must hold for this file to exist. (2 assertions)

spouse transfer is no gain no loss, s58

TCGA 1992 section 58

The scenario the test runs

1 Jan 2024 buy 10 X for £1,000; 1 Jun 2024 gift-spouse 5 X for £9,999. The engine must produce no disposal recorded = 0, no gain = 0, half the cost leaves the pool with the units = 500, flags the spouse rule, the SPOUSE_NGNL finding is raised.

What the test proves: The suite asserts 4 facts about this scenario and every one must hold for this file to exist. (4 assertions)

gift to charity is no gain no loss, s257

TCGA 1992 section 257

The scenario the test runs

1 Jan 2024 buy 10 X for £1,000; 1 Jun 2024 gift-charity 10 X for £50,000. The engine must produce no taxable gain on the donation = 0, pool emptied = 0.

What the test proves: The suite asserts 2 facts about this scenario and every one must hold for this file to exist. (2 assertions)

gift to anyone else is a disposal at market value, s17

TCGA 1992 section 17

The scenario the test runs

1 Jan 2024 buy 10 X for £1,000; 1 Jun 2024 gift-out 10 X for £8,000. The engine must produce taxed on market value = 7,000.

What the test proves: The suite asserts 1 fact about this scenario and every one must hold for this file to exist. (1 assertion)

losing a key is not a disposal, CRYPTO22400

TCGA 1992 section 24 , worked example CRYPTO22400

The scenario the test runs

1 Jan 2024 buy 10 X for £1,000; 1 Jun 2024 lost 10 X for £0. The engine must produce no disposal = 0, no loss allowed automatically = 0, units stay in the pool = 10, explains the negligible value route, the LOST_NOT_DISPOSAL finding is raised.

What the test proves: The suite asserts 4 facts about this scenario and every one must hold for this file to exist. (4 assertions)

fork gets its own pool, CRYPTO22300

TCGA 1992 section 52(4) , worked example CRYPTO22300

The scenario the test runs

1 Jan 2024 buy 1 BTC for £20,000; 1 Aug 2024 fork 1 BCH for £0; 1 Sept 2024 sell 1 BCH for £300. The engine must produce forked asset has its own pool = true, BTC pool untouched = 1, dust arrivals are informational = 40, dust costs no confidence = 0, real unpaired arrivals still warn = 25, with 2 further checks.

What the test proves: The suite asserts 7 facts about this scenario and every one must hold for this file to exist. (7 assertions)

The behaviour rules, 16 of them

Everything below is engine behaviour rather than statute, reconciliation, transfer linking, the confidence score, and the published figures the engine checks against GOV.UK rather than deriving from an act.

transfers between your own wallets are not disposals

The scenario the test runs

1 Jan 2024 buy 1 BTC for £20,000; 1 Mar 2024 transfer-out 1 BTC for £0; 1 Mar 2024 transfer-in 1 BTC for £0; 1 Sept 2024 sell 1 BTC for £26,000. The engine must produce gain unaffected by the move = 6,000, paired transfer raises nothing, the UNPAIRED_OUT finding is not raised, paired transfer raises nothing in, the UNPAIRED_IN finding is not raised.

What the test proves: The suite asserts 3 facts about this scenario and every one must hold for this file to exist. (3 assertions)

transfer linking, fee aware, cross wallet, best match first

The scenario the test runs

1 Jan 2024 buy 1 BTC for £20,000; 1 Mar 2024 transfer-out 0.5 BTC for £0; 2 Mar 2024 transfer-in 0.4996 BTC for £0. The engine must produce fee delta pair links silently = 1, network fee measured = 0, link carries both rows = "2>3", no unpaired out, the UNPAIRED_OUT finding is not raised, no unpaired in, the UNPAIRED_IN finding is not raised, with 5 further checks.

What the test proves: The suite asserts 10 facts about this scenario and every one must hold for this file to exist. (10 assertions)

an unpaired transfer is flagged, the classic inflated gain

The scenario the test runs

1 Jan 2024 buy 1 BTC for £20,000; 1 Mar 2024 transfer-out 1 BTC for £0. The engine must produce unpaired out flagged, the UNPAIRED_OUT finding is raised.

What the test proves: The suite asserts 1 fact about this scenario and every one must hold for this file to exist. (1 assertion)

disposal with no acquisition history

The scenario the test runs

1 Jun 2024 sell 1000 DOGE for £900. The engine must produce nil cost, whole proceeds are gain = 900, shortfall recorded = 1,000, missing cost basis flagged, the NO_COST_BASIS finding is raised.

What the test proves: The suite asserts 3 facts about this scenario and every one must hold for this file to exist. (3 assertions)

diagnostics catch bad rows

The scenario the test runs

buy 1 X for £100; 1 Jan 2024 wat 1 X for £100; 1 Jan 2024 buy 1 for £100; 1 Jan 2024 buy 0 X for £100; 1 Jan 2024 income 1 X for £0; 1 Jan 2024 gift-out 1 X for £0; and 2 further rows. The engine must produce bad date, the BAD_DATE finding is raised, bad type, the BAD_TYPE finding is raised, no asset, the NO_ASSET finding is raised, no qty, the NO_QTY finding is raised, income with no value, the NO_VALUE finding is raised, with 3 further checks.

What the test proves: The suite asserts 8 facts about this scenario and every one must hold for this file to exist. (8 assertions)

tax computation, bands and losses

The scenario the test runs

The engine must produce at 18 = 8,270, at 24 = 4,795, due = 2,639.4, all in basic band when no income = 0, brought forward losses applied before the allowance = 3,000, with 1 further checks.

What the test proves: The suite asserts 6 facts about this scenario and every one must hold for this file to exist. (6 assertions)

tax year assignment, 6 April boundary

The scenario the test runs

The engine must produce 5 April is the old year = "2024-25", 6 April starts the new year = "2025-26", early January belongs to the year that began the previous April = "2023-24".

What the test proves: The suite asserts 3 facts about this scenario and every one must hold for this file to exist. (3 assertions)

multi year split, one figure per tax year

The scenario the test runs

1 May 2021 buy 4 BTC for £40,000; 10 Jan 2023 sell 1 BTC for £30,000; 10 Jun 2023 sell 1 BTC for £4,000; 10 Jun 2025 sell 1 BTC for £26,000. The engine must produce three years produced = 3, years in order = "2022-23,2023-24,2025-26", 2022-23 uses the £12,300 allowance = 12,300, 2022-23 taxable = 7,700, 2022-23 taxed at the old 10 per cent rate = 10, with 8 further checks.

What the test proves: The suite asserts 13 facts about this scenario and every one must hold for this file to exist. (13 assertions)

brought forward losses never waste the exempt amount

The scenario the test runs

1 May 2025 buy 10 X for £0; 1 Jun 2025 sell 10 X for £10,000. The engine must produce only enough losses used to reach the allowance = 7,000, taxable nil = 0, the rest carries on = 93,000.

What the test proves: The suite asserts 3 facts about this scenario and every one must hold for this file to exist. (3 assertions)

current year losses are used in full even where that wastes allowance

The scenario the test runs

1 May 2025 buy 1 A for £1,000; 1 Jun 2025 sell 1 A for £6,000; 1 May 2025 buy 1 B for £9,000; 1 Jul 2025 sell 1 B for £5,000. The engine must produce net after mandatory loss offset = 1,000, nothing taxable = 0, no loss survives to carry forward = 0.

What the test proves: The suite asserts 3 facts about this scenario and every one must hold for this file to exist. (3 assertions)

2024-25 split year, 30 October rate change, beneficial allocation

The scenario the test runs

1 May 2023 buy 100 X for £1,000; 1 Jun 2024 sell 50 X for £20,000; 1 Dec 2024 sell 50 X for £30,000. The engine must produce one tax year = 1, year is 2024-25 = "2024-25", taxable after £3,000 allowance = 46,000, band count = 3, 10 per cent slice = 8,270, with 3 further checks.

What the test proves: The suite asserts 8 facts about this scenario and every one must hold for this file to exist. (8 assertions)

years before 2021-22 are computed but not estimated

The scenario the test runs

1 Jan 2019 buy 1 X for £1,000; 1 Jun 2019 sell 1 X for £5,000. The engine must produce gain still computed = 4,000, no tax estimate for the year = null, unsupported year flagged, the YEAR_UNSUPPORTED finding is raised.

What the test proves: The suite asserts 3 facts about this scenario and every one must hold for this file to exist. (3 assertions)

the pool ledger knows which row moved it

The scenario the test runs

1 Jan 2024 buy 1 BTC for £20,000; 1 Jun 2024 sell 0.4 BTC for £12,000. The engine must produce acquisition entry carries its row = 1, disposal entry carries its row = 2.

What the test proves: The suite asserts 2 facts about this scenario and every one must hold for this file to exist. (2 assertions)

reconciliation confidence score

The scenario the test runs

1 May 2025 buy 1 X for £1,000; 1 Jun 2025 sell 1 X for £2,000. The engine must produce clean data scores 100 = 100, missing cost basis costs 20 = 80, an unpaired transfer costs 6 = 94, each finding carries its own deduction = 6, heavy errors carry 20 = 20.

What the test proves: The suite asserts 5 facts about this scenario and every one must hold for this file to exist. (5 assertions)

wallet labels survive expansion, the UI attributes findings by them

The scenario the test runs

The engine must produce wallet carried through = "Kraken".

What the test proves: The suite asserts 1 fact about this scenario and every one must hold for this file to exist. (1 assertion)

a trade with no received side is flagged, not silently ignored

The scenario the test runs

1 Jan 2024 buy 1 BTC for £20,000; 1 Jun 2024 trade 0.5 BTC for £15,000. The engine must produce inert trade flagged, the TRADE_NO_COUNTER finding is raised, pool untouched by the inert row = 1, complete trades are not flagged, the TRADE_NO_COUNTER finding is not raised.

What the test proves: The suite asserts 3 facts about this scenario and every one must hold for this file to exist. (3 assertions)

Run any of these yourself. Open the app, enter the scenario rows from a worked example, and compare the figures against HMRC's own page. The engine's answer and the manual's answer are the same numbers, that is the test.