Created
July 21, 2025 21:42
-
-
Save ac12644/5293c427e2f44f61cac7e2339b4d1d36 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import * as bitcoin from "bitcoinjs-lib"; | |
| import * as ECPairFactory from "ecpair"; | |
| import tinysecp from "tiny-secp256k1"; | |
| // Initialize ECPair for signing | |
| const ECPair = ECPairFactory.ECPairFactory(tinysecp); | |
| // Configuration (replace these with your real values or import from config) | |
| const NETWORK = bitcoin.networks.testnet; // or bitcoin.networks.bitcoin for mainnet | |
| const PLATFORM_KEY_WIF = "<YOUR_PLATFORM_WIF>"; // WIF of your platform's private key | |
| const FEE_WALLET = "tb1q..."; // platform fee recipient | |
| const FEE_BPS = 200; // 2% | |
| interface Utxo { | |
| tx_hash: string; | |
| tx_pos: number; | |
| value: number; // in satoshis | |
| address: string; | |
| } | |
| /** | |
| * Build, sign, and finalize a PSBT for a sticker purchase: | |
| * - Input: buyer UTXO (paid to pool address) | |
| * - Output1: platform fee | |
| * - Output2: seller payout | |
| * - Output3: OP_RETURN(metadata) | |
| */ | |
| export function createStickerPurchasePsbt( | |
| utxo: Utxo, | |
| sellerAddress: string, | |
| productId: string, | |
| productName: string | |
| ): string { | |
| const platformKey = ECPair.fromWIF(PLATFORM_KEY_WIF, NETWORK); | |
| // 1. Calculate sats | |
| const grossSat = utxo.value; | |
| const feeSat = Math.floor((grossSat * FEE_BPS) / 10000); | |
| const netSat = grossSat - feeSat; | |
| // 2. Create PSBT | |
| const psbt = new bitcoin.Psbt({ network: NETWORK }); | |
| // 2a. Add input | |
| psbt.addInput({ | |
| hash: utxo.tx_hash, | |
| index: utxo.tx_pos, | |
| witnessUtxo: { | |
| script: bitcoin.address.toOutputScript(utxo.address, NETWORK), | |
| value: utxo.value, | |
| }, | |
| }); | |
| // 2b. Add fee output | |
| psbt.addOutput({ address: FEE_WALLET, value: feeSat }); | |
| // 2c. Add seller payout | |
| psbt.addOutput({ address: sellerAddress, value: netSat }); | |
| // 2d. Embed metadata via OP_RETURN (up to 80 bytes) | |
| const metadata = `${productId}|${productName}`; | |
| const data = Buffer.from(metadata, 'utf8'); | |
| if (data.length > 80) throw new Error('Metadata too long'); | |
| const embed = bitcoin.payments.embed({ data: [data] }); | |
| if (embed.output) psbt.addOutput({ script: embed.output, value: 0 }); | |
| // 3. Sign input with platform key | |
| psbt.signInput(0, platformKey); | |
| // 4. Finalize and extract transaction hex | |
| psbt.finalizeAllInputs(); | |
| const tx = psbt.extractTransaction(); | |
| return tx.toHex(); | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
PSBT example
This utility builds and signs a PSBT for a sticker purchase, automatically splitting a buyer’s payment into:
productId|productName(up to 80 bytes)Example Usage
How It Works
Perfect for on‑chain marketplaces, tip bots, and any BTC‑priced digital store!