|
1 | 1 | import { |
| 2 | + buildBtdAssetPackExchangeSettlement, |
2 | 3 | buildBtdMintDraft, |
3 | 4 | buildBtdReadAccessDecision, |
| 5 | + buildBtdReadReceiptBoundarySettlement, |
4 | 6 | buildBtdRegistrySnapshot, |
5 | 7 | createBtdMeasureMintState, |
6 | 8 | parseBtdOptionalBigInt, |
@@ -38,10 +40,26 @@ describe('BTD API boundaries', () => { |
38 | 40 | exchangeSequence: 1n, |
39 | 41 | actorId: 'actor-boundary-1', |
40 | 42 | issuedAt, |
| 43 | + depositorWalletId: 'wallet-depositor-boundary', |
| 44 | + sourceSafePreviewRoot: 'source-safe-preview-root-boundary', |
| 45 | + findingFitsResultRoot: 'finding-fits-root-boundary', |
| 46 | + settlementConservationRoot: 'settlement-conservation-root-boundary', |
| 47 | + ledgerProjectionRoot: 'ledger-projection-root-boundary', |
41 | 48 | }); |
42 | 49 |
|
43 | 50 | expect(draft.kind).toBe('btd_mint_draft'); |
44 | 51 | expect(draft.measureMint.tokenCount).toBe(10_500_000); |
| 52 | + expect(draft.assetPackMintReceipt).toMatchObject({ |
| 53 | + kind: 'btd.asset_pack_mint_receipt', |
| 54 | + depositorWalletId: 'wallet-depositor-boundary', |
| 55 | + sourceSafePreviewRoot: 'source-safe-preview-root-boundary', |
| 56 | + findingFitsResultRoot: 'finding-fits-root-boundary', |
| 57 | + ledgerProjectionRoot: 'ledger-projection-root-boundary', |
| 58 | + protectedSourceVisible: false, |
| 59 | + }); |
| 60 | + expect(draft.terminalJournalEntry.receiptRoots).toContain( |
| 61 | + draft.assetPackMintReceipt?.receiptRoot, |
| 62 | + ); |
45 | 63 | expect(draft.terminalJournalEntry.transactionKind).toBe('asset_pack_mint'); |
46 | 64 | expect(draft.terminalJournalEntry.actorId).toBe('actor-boundary-1'); |
47 | 65 | }); |
@@ -119,4 +137,124 @@ describe('BTD API boundaries', () => { |
119 | 137 | expect(decision.decision.decision).toBe('licensed_read'); |
120 | 138 | expect(decision.policyDisclosure.accessPolicyHash).toBe('policy-boundary-hash'); |
121 | 139 | }); |
| 140 | + |
| 141 | + it('binds source-safe read receipts and paid rights-transfer receipts at package boundaries', () => { |
| 142 | + const preview = buildBtdReadReceiptBoundarySettlement({ |
| 143 | + actorId: 'actor-boundary-1', |
| 144 | + assetPackId: 'asset-pack-boundary-1', |
| 145 | + readId: 'read-boundary-1', |
| 146 | + readRequestId: 'read-request-boundary-1', |
| 147 | + acceptedNeedRoot: 'accepted-need-root-boundary', |
| 148 | + findingFitsResultRoot: 'finding-fits-root-boundary', |
| 149 | + readerWalletId: 'wallet-reader-boundary', |
| 150 | + depositorWalletId: 'wallet-depositor-boundary', |
| 151 | + rangeStart: 0, |
| 152 | + rangeEndExclusive: 10, |
| 153 | + sourceManifestRoot: 'source-root-boundary', |
| 154 | + sourceSafePreviewRoot: 'source-safe-preview-root-boundary', |
| 155 | + accessPolicyHash: 'policy-boundary-hash', |
| 156 | + disclosureState: 'source_safe_preview', |
| 157 | + readRightState: 'none', |
| 158 | + deliveryAdmissionState: 'blocked', |
| 159 | + ledgerProjectionRoot: 'ledger-projection-root-boundary', |
| 160 | + exchangeSequence: 4n, |
| 161 | + issuedAt, |
| 162 | + }); |
| 163 | + |
| 164 | + expect(preview.readReceipt).toMatchObject({ |
| 165 | + kind: 'btd.read_receipt', |
| 166 | + disclosureState: 'source_safe_preview', |
| 167 | + deliveryAdmissionState: 'blocked', |
| 168 | + protectedSourceVisible: false, |
| 169 | + paidUnlockRoot: null, |
| 170 | + }); |
| 171 | + expect(preview.terminalJournalEntry.transactionKind).toBe('read_submission'); |
| 172 | + expect(preview.terminalJournalEntry.receiptRoots).toContain(preview.readReceipt.receiptRoot); |
| 173 | + |
| 174 | + expect(() => |
| 175 | + buildBtdReadReceiptBoundarySettlement({ |
| 176 | + ...preview.readReceipt, |
| 177 | + actorId: 'actor-boundary-1', |
| 178 | + exchangeSequence: 5n, |
| 179 | + protectedSourceVisible: true, |
| 180 | + }), |
| 181 | + ).toThrow('Protected source cannot be visible before paid unlock.'); |
| 182 | + |
| 183 | + const created = buildBtdAssetPackExchangeSettlement({ |
| 184 | + action: 'create_order', |
| 185 | + orderId: 'order-boundary-1', |
| 186 | + orderKind: 'sell', |
| 187 | + assetPackId: 'asset-pack-boundary-1', |
| 188 | + rangeStart: 0, |
| 189 | + rangeEndExclusive: 10, |
| 190 | + makerWalletId: 'wallet-depositor-boundary', |
| 191 | + priceSats: '1200', |
| 192 | + accessPolicyHash: 'policy-boundary-hash', |
| 193 | + createdAtExchangeSequence: 6n, |
| 194 | + actorId: 'actor-boundary-1', |
| 195 | + issuedAt, |
| 196 | + }); |
| 197 | + const accepted = buildBtdAssetPackExchangeSettlement({ |
| 198 | + action: 'accept_order', |
| 199 | + previousOrder: created.order, |
| 200 | + takerWalletId: 'wallet-reader-boundary', |
| 201 | + actorId: 'actor-boundary-1', |
| 202 | + issuedAt, |
| 203 | + }); |
| 204 | + const settled = buildBtdAssetPackExchangeSettlement({ |
| 205 | + action: 'settle_order', |
| 206 | + previousOrder: accepted.order, |
| 207 | + settledAtExchangeSequence: 7n, |
| 208 | + ledgerAnchorId: 'ledger-anchor-boundary-1', |
| 209 | + actorId: 'actor-boundary-1', |
| 210 | + issuedAt, |
| 211 | + }); |
| 212 | + const transferred = buildBtdAssetPackExchangeSettlement({ |
| 213 | + action: 'transfer_rights', |
| 214 | + previousOrder: settled.order, |
| 215 | + receiptId: 'legacy-transfer-boundary-1', |
| 216 | + fromWalletId: 'wallet-depositor-boundary', |
| 217 | + toWalletId: 'wallet-reader-boundary', |
| 218 | + btcFeeReceiptId: 'btc-fee-boundary-1', |
| 219 | + btcFeeFinalityState: 'confirmed', |
| 220 | + readLicenseId: 'read-license-boundary-1', |
| 221 | + sourceSafePreviewRoot: 'source-safe-preview-root-boundary', |
| 222 | + paidUnlockRoot: 'paid-unlock-root-boundary', |
| 223 | + deliveryAdmissionRoot: 'delivery-admission-root-boundary', |
| 224 | + ledgerProjectionRoot: 'ledger-projection-root-boundary', |
| 225 | + actorId: 'actor-boundary-1', |
| 226 | + issuedAt, |
| 227 | + }); |
| 228 | + |
| 229 | + expect(transferred.btdRightsTransferReceipt).toMatchObject({ |
| 230 | + kind: 'btd.rights_transfer_receipt', |
| 231 | + readerWalletId: 'wallet-reader-boundary', |
| 232 | + depositorWalletId: 'wallet-depositor-boundary', |
| 233 | + btcFeeFinalityState: 'confirmed', |
| 234 | + deliveryAdmissionState: 'admitted', |
| 235 | + protectedSourceVisible: true, |
| 236 | + }); |
| 237 | + expect(transferred.terminalJournalEntry.receiptRoots).toContain( |
| 238 | + transferred.btdRightsTransferReceipt?.receiptRoot, |
| 239 | + ); |
| 240 | + |
| 241 | + expect(() => |
| 242 | + buildBtdAssetPackExchangeSettlement({ |
| 243 | + action: 'transfer_rights', |
| 244 | + previousOrder: settled.order, |
| 245 | + receiptId: 'legacy-transfer-boundary-2', |
| 246 | + fromWalletId: 'wallet-depositor-boundary', |
| 247 | + toWalletId: 'wallet-reader-boundary', |
| 248 | + btcFeeReceiptId: 'btc-fee-boundary-2', |
| 249 | + btcFeeFinalityState: 'broadcast', |
| 250 | + readLicenseId: 'read-license-boundary-2', |
| 251 | + sourceSafePreviewRoot: 'source-safe-preview-root-boundary', |
| 252 | + paidUnlockRoot: 'paid-unlock-root-boundary', |
| 253 | + deliveryAdmissionRoot: 'delivery-admission-root-boundary', |
| 254 | + ledgerProjectionRoot: 'ledger-projection-root-boundary', |
| 255 | + actorId: 'actor-boundary-1', |
| 256 | + issuedAt, |
| 257 | + }), |
| 258 | + ).toThrow('Rights transfer receipt requires confirmed BTC fee finality.'); |
| 259 | + }); |
122 | 260 | }); |
0 commit comments