import type { XOTemplate } from '@xo-cash/types'; /** * Vending machine payment template. * * Merchant creates a purchaseItems invitation with receipt variables; * customer funds and signs the composable transaction. */ export const vendingMachineTemplate: XOTemplate = { $schema: 'https://libauth.org/schemas/wallet-template-v0.schema.json', name: 'Vending Machine', description: 'Purchase items from a vending machine with an itemized receipt.', icon: 'wallet', version: '1', supported: ['BCH_2023_05', 'BCH_2024_05', 'BCH_2025_05', 'BCH_2026_05'], defaults: { change: { output: 'changeOutput', role: 'merchant', generate: ['merchantKey'], }, }, roles: { merchant: { name: 'Merchant', description: 'The vending machine operator receiving payment.', icon: 'owner', }, customer: { name: 'Customer', description: 'The customer paying for items.', icon: 'sender', }, }, start: [ { action: 'purchaseItems', role: 'merchant', generate: ['merchantKey'], }, ], actions: { purchaseItems: { name: 'Purchase Items', description: 'Purchase: $() for $() sats', icon: 'request', roles: { merchant: { name: 'Sell Items', description: 'Receive payment for $()', icon: 'request', requirements: { secrets: ['merchantKey'], variables: [ 'totalSatoshis', 'orderId', 'merchantName', 'receiptSummary', 'lineItemsJson', ], }, }, customer: { name: 'Pay', description: 'Pay $() sats for $()', icon: 'send', requirements: {}, }, }, requirements: { participants: [ { role: 'merchant', slots: { min: 1, max: 1 } }, { role: 'customer', slots: { min: 1 } }, ], }, transaction: 'purchaseItemsTransaction', }, }, transactions: { purchaseItemsTransaction: { name: 'Vending Purchase', description: 'Order $(): $()', icon: 'request', roles: { merchant: { name: 'Received Payment', description: 'Received $() sats from $() sale', icon: 'receive', }, customer: { name: 'Sent Payment', description: 'Paid $() sats for $()', icon: 'send', }, }, inputs: [], outputs: [{ output: 'purchaseOutput' }], version: 2, locktime: 0, composable: true, }, }, /** No custom input templates — customer UTXOs are selected at funding time. */ inputs: {}, outputs: { changeOutput: { name: 'Change', description: 'Funds returned as change.', icon: 'receive', lockingScript: 'merchantReceivingLockingScript', }, purchaseOutput: { 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, }, }, lockingScripts: { merchantReceivingLockingScript: { name: 'Merchant Receive', description: 'Funds received by the vending machine merchant.', icon: 'address', lockingType: 'p2pkh', lockingBytecode: 'lockMerchantP2PKH', unlockingBytecode: 'unlockMerchantP2PKH', actions: [], state: { variables: [], secrets: [] }, balance: {}, roles: { merchant: { state: { variables: [], secrets: ['merchantKey'], }, actions: [], balance: { satoshis: true, fungibleTokens: true, nonfungibleTokens: true, }, selectable: true, }, }, }, }, scripts: { lockMerchantP2PKH: 'OP_DUP OP_HASH160 <$( OP_HASH160)> OP_EQUALVERIFY OP_CHECKSIG', unlockMerchantP2PKH: ' ', }, constants: { dustLimit: { name: 'Dust Limit', description: 'Minimum satoshis for P2PKH outputs.', type: 'integer', value: 546, }, }, variables: { merchantKey: { name: 'Merchant Private Key', description: 'Private key for the vending machine merchant wallet.', type: 'bytes', hint: 'private_key', }, totalSatoshis: { name: 'Total Price', description: 'Total purchase price in satoshis', type: 'integer', hint: 'satoshis', }, orderId: { name: 'Order ID', description: 'Unique order identifier', type: 'string', }, merchantName: { name: 'Merchant Name', description: 'Display name of the vending machine', type: 'string', }, receiptSummary: { name: 'Receipt Summary', description: 'Human-readable list of purchased items', type: 'string', }, lineItemsJson: { name: 'Line Items', description: 'JSON-encoded line items for the purchase', type: 'string', }, }, icons: [ { name: 'wallet', hash: '0000000000000000000000' }, { name: 'owner', hash: '0000000000000000000000' }, { name: 'sender', hash: '0000000000000000000000' }, { name: 'request', hash: '0000000000000000000000' }, { name: 'receive', hash: '0000000000000000000000' }, { name: 'send', hash: '0000000000000000000000' }, ], scenarios: [ { name: 'purchase items happy path', description: 'Merchant requests payment for vending machine items.', action: 'purchaseItems', roles: [ { role: 'merchant', values: { generated: { merchantKey: 'KyRQa5pEXuzVcDwnXRLpYAascjchQW5DoxVRMbj4DTxS83573mz8', }, variables: { totalSatoshis: 3500, orderId: 'order-demo-1', merchantName: 'XO Snack Machine', receiptSummary: '2× Cola, 1× Chips', lineItemsJson: '[{"name":"Cola","qty":2},{"name":"Chips","qty":1}]', }, secrets: {}, inputs: [], outputs: [ { lockingBytecode: '76a91475c715ecb74178fe87933e57e947e5e92d904b8188ac', valueSatoshis: 3500, }, ], }, }, { role: 'customer', values: { generated: {}, variables: {}, secrets: {}, inputs: [], outputs: [], }, }, ], }, ], };