Time-Locked Bitcoin Transactions

Abhishek Chauhan
Coinmonks
3 min readSep 13, 2023

--

A time-locked transaction includes a parameter specifying a time before which the transaction cannot be added to the blockchain. This means that even if the transaction is broadcasted to the network, it will remain in a ‘pending’ state until the time lock has expired.

timelock btc transaction

Use Cases:

  1. Savings or Trust Funds ₿: Individuals can time-lock funds meant for future purposes such as children’s education or a significant planned purchase 🛍. This ensures that the funds aren’t accessible until a predetermined future date 📅.
  2. Escrow Services 🤝: Time-locked transactions can be used in escrow arrangements. Funds can be locked until both parties fulfill agreed-upon conditions.
  3. Payment Plans or Subscriptions ₿: Businesses can create recurring payment plans where funds are automatically released from a user’s account at specific intervals 📆.
  4. Atomic Swaps 🔁: In cross-chain trading, a time-lock ensures one party doesn’t abscond with funds by requiring both parties in the trade to deposit their funds. If the trade isn’t complete by a specified time, the funds are returned 🔙.
  5. Multi-signature Wallets with Delays 🛡: In high-security applications, a multi-signature wallet can be combined with a time-lock, ensuring that funds can’t be quickly moved without multiple approvals and a waiting period.
  6. Incentive Plans 🎁: Companies can time-lock bonus payments or shares for employees, ensuring they’re released only after the employee has been with the company for a certain period 📈.

How Does It Work 🖥?

The provided code snippet is a function that creates a time-locked transaction. Here’s a step-by-step breakdown:

// Importing required libraries
require("dotenv").config();
const bitcore = require("bitcore-lib");
const axios = require("axios");

// The function to create a time-locked Bitcoin transaction
exports.createTimeLockTransaction = async (req, res) => {
try {
const { recipientAddress, amountInBTC, timestamp } = req.body;

// Check for necessary parameters
if (!recipientAddress || !amountInBTC || !timestamp) {
return res.status(400).json({ error: "Parameters are missing!" });
}

// Ensure provided timestamp isn't in the past
const currentTimestamp = Math.floor(Date.now() / 1000);
if (timestamp <= currentTimestamp) {
throw new Error(
"Provided timestamp is in the past. Please provide a future timestamp."
);
}

// Initializing Bitcoin testnet
const testnet = bitcore.Networks.testnet;
const privateKey = new bitcore.PrivateKey.fromWIF(process.env.BITCOIN_PRIVATE_KEY, testnet);
const address = privateKey.toAddress(testnet);

// Fetching UTXOs related to the derived Bitcoin address
const { data: utxos } = await axios.get(`https://blockstream.info/testnet/api/address/${address}/utxo`);

if (utxos.length === 0) {
throw new Error("No UTXOs found for this address.");
}

let totalAmountAvailable = 0;
const transaction = new bitcore.Transaction();

const publicKey = bitcore.PublicKey.fromPrivateKey(privateKey);
const scriptPubKey = bitcore.Script.buildPublicKeyHashOut(publicKey).toString();

// Building the transaction using available UTXOs
utxos.forEach((utxo) => {
transaction.from({
txId: utxo.txid,
outputIndex: utxo.vout,
script: scriptPubKey,
satoshis: utxo.value,
});
totalAmountAvailable += utxo.value;
});

const satoshisToSend = bitcore.Unit.fromBTC(amountInBTC).toSatoshis();
const fee = 50000; // Transaction fee
const remaining = totalAmountAvailable - satoshisToSend - fee;

if (remaining < 0) {
throw new Error("Insufficient balance.");
}

// Setting the lock time for the transaction
transaction.to(recipientAddress, satoshisToSend);
transaction.change(address);
transaction.fee(fee);
transaction.lockUntilDate(new Date(timestamp * 1000));
transaction.sign(privateKey);

return transaction.serialize();
} catch (error) {
console.error("Error creating time-locked transaction:", error);
throw error;
}
};

Key Components and Functionality:

  • Required Libraries 📚: The code begins by importing necessary libraries: bitcore-lib for Bitcoin functions, axios for API calls, and dotenv to manage environment variables.
  • Parameters Validation ✔: The function checks if all required parameters (recipientAddress, amountInBTC, and timestamp) are provided and ensures the timestamp is not in the past.
  • Initialization 🚀: It initializes the Bitcoin testnet and derives the associated Bitcoin address from a provided private key.
  • Fetching UTXOs 💰: UTXOs (Unspent Transaction Outputs) associated with the derived Bitcoin address are retrieved to fund the transaction.
  • Transaction Building 🏗: For each available UTXO, it is added as an input to the transaction. It then calculates the total transaction fee and checks for a sufficient balance.
  • Setting Lock Time 🔐: This is the crux. The transaction’s lock time is established using the provided timestamp. This ensures the transaction isn’t confirmed until the stipulated time.
  • Error Handling ⚠: Comprehensive error handling ensures smooth execution, gracefully managing scenarios like past timestamps or insufficient funds.

Conclusion 🌠

Time-locked transactions on the Bitcoin network introduce a layer of control over the transfer of funds, paving the way for many innovative solutions in finance, contractual agreements, and more. The provided code example combined with the real-world applications paints a vivid picture of the potential and flexibility of blockchain technology.

--

--

Abhishek Chauhan
Coinmonks

👨‍💻 Blockchain dev sharing insights on innovative solutions. Follow me on LinkedIn: https://www.linkedin.com/in/ac12644 🤝 GitHub: https://github.com/ac12644