import { describe, expect, it } from "vitest"; import type { XOInvitation } from "@xo-cash/types"; import { vendingMachineTemplate } from "../../src/templates/vending-machine.js"; import { resolveCommitReferences } from "../../src/utils/resolve-invitation-data.js"; const MERCHANT_ENTITY = "xpub6EUk69HMQk83Ay3QEFWhYgvqLvT6tGTnzWK33fao2fvnDyzhbBeoSc6JbQkvnKq33bH7HjqQmZ9H29hsesC53ZgxQfGBadBZL5jmSa7kbTD"; const CUSTOMER_ENTITY = "xpub6FHRsCb1ma6VFGZpRYZL8A3X1Gwwc8JjRcaDJR2vgirrttmdvJX5VNYceA84RDVjy1c2a2oYEwuayLDZ9gssDgU52UXDGFTDa19z5ceXfFh"; /** * Minimal reproduction of OriginalInvitation.json for the vending machine flow. */ const originalInvitation: XOInvitation = { invitationIdentifier: "c57b1f8f8534df28b359e323c5fbd5ba", createdAtTimestamp: 1779488689379, templateIdentifier: "feadd05c6566c5eded68f321efe7150cb765fda070d027c89f285e5b42a00652", actionIdentifier: "purchaseItems", commits: [ { commitIdentifier: "76b935a35ca45f1065f9c66769d1a957", previousCommitIdentifier: undefined, entityIdentifier: MERCHANT_ENTITY, data: {}, signature: "5f487c045657f3939ecfeaaacf239a7cfd44b485c2be591f5280bf0cc3a6e5fe304e8ea23311d82b2afa4f0ad7e0a6d07ec1e0b1aaee9c44097613694390966b", expiresAtTimestamp: 1779506689379, }, { commitIdentifier: "cbf2d6242144f6761d0efc3bbbbf6660", previousCommitIdentifier: "76b935a35ca45f1065f9c66769d1a957", entityIdentifier: MERCHANT_ENTITY, data: { variables: [ { variableIdentifier: "totalSatoshis", roleIdentifier: "merchant", value: 3000, }, { variableIdentifier: "orderId", roleIdentifier: "merchant", value: "eb5a30b3-ec8c-4b81-89dd-c53371f55a0e", }, { variableIdentifier: "merchantName", roleIdentifier: "merchant", value: "XO Snack Machine", }, { variableIdentifier: "receiptSummary", roleIdentifier: "merchant", value: "2× Chips", }, { variableIdentifier: "lineItemsJson", roleIdentifier: "merchant", value: '[{"id":"225e37f4-14f2-4b33-86fd-763018bbfd7c","name":"Chips","quantity":2,"price":1500}]', }, ], }, signature: "7cfc53860ec81403a79a03521a7674ee8d2a11365ee031e4f7f2e36a045bd6e2999510264b29045582a74e1190f0176950a855361f02bc67ff7877fabcf794f4", expiresAtTimestamp: 1779506689390, }, { commitIdentifier: "583208aa304c0aa9841d1400efe6b6aa", previousCommitIdentifier: "cbf2d6242144f6761d0efc3bbbbf6660", entityIdentifier: MERCHANT_ENTITY, data: { outputs: [ { outputIdentifier: "purchaseOutput", lockingBytecode: "76a9146a4715fe1cc1ce228336502f1711b06045ef361088ac", }, ], }, signature: "d9bdd3b24fef6afd13f12da92e832672c6c1b83fb372506faeb7fa4ea0e39e3a32ad74493fbe7a393aed58bc18226431dabae09948ce371ad3f77b0219cb3831", expiresAtTimestamp: 1779506689412, }, { commitIdentifier: "4f3f9a3361c8070ab589cc44248a6a80", previousCommitIdentifier: "583208aa304c0aa9841d1400efe6b6aa", entityIdentifier: CUSTOMER_ENTITY, data: {}, signature: "63be8af81622da4fccc7eb6b81c6174879fe6aa113b8dae794bd42d4d5c87ae550a18be1e6cb5edf231e774bdc7883eb5a78bd02188579dce58da0d449c43865", expiresAtTimestamp: 1779506979194, }, { commitIdentifier: "d18b9a0caa638eaa1d0711f333e9c114", previousCommitIdentifier: "4f3f9a3361c8070ab589cc44248a6a80", entityIdentifier: CUSTOMER_ENTITY, data: { inputs: [ { outpointTransactionHash: "b1e8f77cdc60efac19f668fc5c7177ace42a46e2532f230979559c7190c3c80a", outpointIndex: 1, }, ], }, signature: "e36942eb5f147e620659d20b7059630da871944e74fe5ffb3c4ff0298a5aedb101bc7468b19750114cbcfa56b99bd4a080453a31084f18173adcd9442fca4303", expiresAtTimestamp: 1779507006272, }, { commitIdentifier: "7823f7ae7a365f87f6acdfee8896f508", previousCommitIdentifier: "d18b9a0caa638eaa1d0711f333e9c114", entityIdentifier: CUSTOMER_ENTITY, data: { outputs: [ { valueSatoshis: 74881n, lockingBytecode: "76a9141730ca066d4b9c8d542f8c9bdce645f77697d46088ac", }, ], }, signature: "2c1d1ed1259a2e4b1bc7187b93029e99e590a4e92ff9c39031319766b7fbcdabab9c3dc20b3d27d05eee198cbc717b9aedfbef92bd3e519c62c60e4731bd936a", expiresAtTimestamp: 1779507008169, }, ], }; describe("resolveCommitReferences", () => { it("flattens commits and enriches items with template metadata", () => { const resolved = resolveCommitReferences( originalInvitation, vendingMachineTemplate, ); expect(resolved).toEqual({ invitationIdentifier: "c57b1f8f8534df28b359e323c5fbd5ba", templateIdentifier: "feadd05c6566c5eded68f321efe7150cb765fda070d027c89f285e5b42a00652", actionIdentifier: "purchaseItems", variables: [ { entityIdentifier: MERCHANT_ENTITY, name: "Total Price", description: "Total purchase price in satoshis", type: "integer", hint: "satoshis", variableIdentifier: "totalSatoshis", roleIdentifier: "merchant", value: 3000, }, { entityIdentifier: MERCHANT_ENTITY, name: "Order ID", description: "Unique order identifier", type: "string", variableIdentifier: "orderId", roleIdentifier: "merchant", value: "eb5a30b3-ec8c-4b81-89dd-c53371f55a0e", }, { entityIdentifier: MERCHANT_ENTITY, name: "Merchant Name", description: "Display name of the vending machine", type: "string", variableIdentifier: "merchantName", roleIdentifier: "merchant", value: "XO Snack Machine", }, { entityIdentifier: MERCHANT_ENTITY, name: "Receipt Summary", description: "Human-readable list of purchased items", type: "string", variableIdentifier: "receiptSummary", roleIdentifier: "merchant", value: "2× Chips", }, { entityIdentifier: MERCHANT_ENTITY, name: "Line Items", description: "JSON-encoded line items for the purchase", type: "string", variableIdentifier: "lineItemsJson", roleIdentifier: "merchant", value: '[{"id":"225e37f4-14f2-4b33-86fd-763018bbfd7c","name":"Chips","quantity":2,"price":1500}]', }, ], inputs: [ { entityIdentifier: CUSTOMER_ENTITY, outpointTransactionHash: "b1e8f77cdc60efac19f668fc5c7177ace42a46e2532f230979559c7190c3c80a", outpointIndex: 1, }, ], outputs: [ { entityIdentifier: MERCHANT_ENTITY, outputIdentifier: "purchaseOutput", lockingBytecode: "76a9146a4715fe1cc1ce228336502f1711b06045ef361088ac", name: "Purchase Payment", description: "$() sats to $()", icon: "request", roles: { merchant: { name: "Payment Received", description: "Received $() sats for $()", }, customer: { name: "Payment Sent", description: "Sent $() sats for $()", }, }, lockingScript: "merchantReceivingLockingScript", valueSatoshis: "$()", token: null, }, { entityIdentifier: CUSTOMER_ENTITY, valueSatoshis: 74881n, lockingBytecode: "76a9141730ca066d4b9c8d542f8c9bdce645f77697d46088ac", }, ], }); }); it("leaves unidentified inputs and outputs without template metadata", () => { const resolved = resolveCommitReferences( originalInvitation, vendingMachineTemplate, ); expect(resolved.inputs[0]).not.toHaveProperty("name"); expect(resolved.outputs[1]).not.toHaveProperty("name"); expect(resolved.outputs[1]).not.toHaveProperty("outputIdentifier"); }); });