Protocol

← Bitmarkets
Steve Dekorte

The message types and transaction flow behind the Bitmarkets marketplace.

Overview

Bitmarkets is a protocol and example client for a decentralized marketplace which uses Bitcoin as its currency and Bitmessage as its transport. Mutual security deposits between buyer and seller are used to align incentives for completing transactions without the need for either reputation systems or trusted third parties.

This page describes the wire protocol: the message format, the message types, and the order in which they are exchanged over the course of a transaction. For a non-technical overview, see the White Paper.

Message Format

Each message is a JSON dictionary. Every dictionary contains a _type field naming the message type, plus additional fields that depend on that type.

  • Text strings are UTF-8 encoded.
  • Strings carrying binary data are Base64 encoded.
  • Date fields use Unix time (seconds since 1970 UTC).

In the examples below, long field values are abbreviated to their first few characters followed by ... for readability.

Transaction Flow

A complete sale moves through four phases — posting, escrow lock, delivery, and either payment or refund. Each cell below shows one message and the direction it travels.

Stepseller → channelseller → buyerbuyer → seller→ bitcoin
1post
2bid
3close postaccept bid
4lock escrow 1
5lock escrow 2
6lock escrow 3 (seller)
7delivery info
8unlock escrow 1
9unlock escrow 2
10unlock escrow 3 (buyer)

The three "lock escrow" steps build a single Bitcoin multi-signature transaction holding both deposits plus the payment: the seller sends a partial transaction with their deposit (SellLockEscrowMsg), the buyer adds their deposit and the payment, signs, and returns it (BuyLockEscrowMsg), then the seller signs and broadcasts it. The three "unlock escrow" steps build and broadcast the release transaction the same way but reversed: the buyer initiates (BuyPaymentMsg), the seller signs and returns it (SellAcceptPaymentMsg), then the buyer broadcasts. The refund path mirrors payment, returning the deposits to each party and the payment to the buyer.

Message Types

Posting

Sellers post sales to a particular Bitmessage channel (a publicly known address) where they are picked up and browsed by other clients. This channel model also enables private markets: a hard-to-guess channel name (e.g. a large random number) lets only those who know the secret name send or receive messages.

PostMsg

Sent from seller to channel to post a sale.

{
    "_type": "PostMsg",
    "postUuid": "B160...",
    "sellerAddress": "BM-2cVr...",
    "dateNumber": 1409004883,
    "payload": {
        "postUuid": "B160...",
        "regionPath": ["North America", "US"],
        "categoryPath": ["Electronics", "Laptops"],
        "title": "Macbook Air 13\" 128GB",
        "priceInSatoshi": 100000,
        "sellerAddress": "BM-2cVr...",
        "description": "Test",
        "attachments": []
    }
}

BidMsg

Sent from buyer to seller in response to a sale post.

{
    "_type": "BidMsg",
    "postUuid": "B160...",
    "sellerAddress": "BM-2cVr...",
    "buyerAddress": "BM-2cVr...",
    "dateNumber": 1409004919
}

ClosePostMsg

Sent from seller to channel after accepting a bid or cancelling the sale, in order to remove the post.

{
    "_type": "ClosePostMsg",
    "postUuid": "B160...",
    "sellerAddress": "BM-2cVr...",
    "dateNumber": 1409004929
}

AcceptBidMsg

Sent from seller to buyer to accept a bid.

{
    "_type": "AcceptBidMsg",
    "postUuid": "B160...",
    "sellerAddress": "BM-2cVr...",
    "buyerAddress": "BM-2cVr...",
    "dateNumber": 1409004929
}

RejectBidMsg

Sent from seller to every potential buyer other than the one accepted, after accepting a bid.

{
    "_type": "RejectBidMsg",
    "postUuid": "B160...",
    "sellerAddress": "BM-2cVr...",
    "buyerAddress": "BM-2cVr...",
    "dateNumber": 1409004929
}

Escrow Lock

If the seller accepts a purchase request, buyer and seller together construct a Bitcoin escrow lock transaction in which each adds a security deposit and the buyer adds the payment amount. The transaction is built so the funds are unspendable by either party until both sign another transaction to release them.

SellLockEscrowMsg

Sent from seller to buyer. Contains an incomplete multi-signature transaction with the seller's unspent inputs for their security deposit.

{
    "_type": "SellLockEscrowMsg",
    "postUuid": "B160...",
    "sellerAddress": "BM-2cVr...",
    "buyerAddress": "BM-2cVr...",
    "dateNumber": 1409005057,
    "payload": {
        "type": "BNTx",
        "txHash": null,
        "inputs": [
            {
                "type": "BNTxIn",
                "previousTxHash": "0851...",
                "previousOutIndex": 0,
                "previousTxSerializedHex": "0100...",
                "scriptSig": null
            }
        ],
        "outputs": [
            {
                "type": "BNTxOut",
                "value": 110000,
                "scriptPubKey": {
                    "type": "BNMultisigScriptPubKey",
                    "pubKeys": ["0389...", "0389..."]
                }
            }
        ],
        "updateTime": null,
        "fee": null,
        "confirmations": null,
        "error": null
    }
}

BuyLockEscrowMsg

Sent from buyer to seller. Contains the multi-signature transaction including the buyer's inputs (for their security deposit and the payment) and the buyer's signature. On receipt the seller adds their signature and broadcasts the transaction to the Bitcoin network. Both parties watch the network to confirm the escrow transaction.

{
    "_type": "BuyLockEscrowMsg",
    "postUuid": "B160...",
    "sellerAddress": "BM-2cVr...",
    "buyerAddress": "BM-2cVr...",
    "dateNumber": 1409005067,
    "payload": {
        "type": "BNTx",
        "txHash": "c0b1...",
        "inputs": [
            {
                "type": "BNTxIn",
                "previousTxHash": "0851...",
                "previousOutIndex": 0,
                "previousTxSerializedHex": "0100...",
                "scriptSig": null
            },
            {
                "type": "BNTxIn",
                "previousTxHash": "19e4...",
                "previousOutIndex": 0,
                "previousTxSerializedHex": "0100...",
                "scriptSig": {
                    "type": "BNScriptSig",
                    "programHexBytes": "4730...",
                    "isMultisig": false
                }
            }
        ],
        "outputs": [
            {
                "type": "BNTxOut",
                "value": 310000,
                "scriptPubKey": {
                    "type": "BNMultisigScriptPubKey",
                    "pubKeys": ["0389...", "02ff..."]
                }
            }
        ],
        "updateTime": 0,
        "netValue": -320000,
        "serializedHex": "0100...",
        "fee": 10000,
        "confirmations": 0,
        "error": null
    }
}

Cancellation. The client supports cancelling the lock on either side by broadcasting a transaction that sends one's own inputs back to oneself. Cancellation only works if the escrow lock transaction has not already been broadcast to the Bitcoin network.

Delivery

After the buyer's client sees the escrow lock transaction confirmed on the blockchain, it prompts the buyer to send the seller their delivery details.

BuyerAddressMsg

Sent from buyer to seller. Contains the address to which the good or service should be delivered. The seller views this address from their client.

{
    "_type": "BuyerAddressMsg",
    "postUuid": "B160...",
    "sellerAddress": "BM-2cVr...",
    "buyerAddress": "BM-2cVr...",
    "dateNumber": 1409007460,
    "payload": {
        "addressee": "Me",
        "address1": "Here",
        "address2": "SF",
        "country": " "
    }
}

Payment

After the seller provides the good or service, the buyer constructs an escrow release transaction that returns the security deposits to their respective parties and sends the payment to the seller. The seller signs and broadcasts it to accept payment.

BuyPaymentMsg

Sent from buyer to seller. Contains an incomplete multi-signature transaction making payment to the seller and returning the security deposits.

{
    "_type": "BuyPaymentMsg",
    "postUuid": "B160...",
    "sellerAddress": "BM-2cVr...",
    "buyerAddress": "BM-2cVr...",
    "dateNumber": 1409007687,
    "payload": {
        "type": "BNTx",
        "txHash": null,
        "inputs": [
            {
                "type": "BNTxIn",
                "previousTxHash": "f9b2...",
                "previousOutIndex": 0,
                "previousTxSerializedHex": "0100...",
                "scriptSig": null
            }
        ],
        "outputs": [
            {
                "type": "BNTxOut",
                "value": 103333,
                "scriptPubKey": {
                    "type": "BNPayToAddressScriptPubKey",
                    "address": "1MLps..."
                }
            }
        ],
        "updateTime": null,
        "fee": null,
        "confirmations": null,
        "error": null
    }
}

SellAcceptPaymentMsg

Sent from seller to buyer with the completed payment transaction. The buyer broadcasts it on the Bitcoin network.

{
    "_type": "SellAcceptPaymentMsg",
    "postUuid": "B160...",
    "sellerAddress": "BM-2cVr...",
    "buyerAddress": "BM-2cVr...",
    "dateNumber": 1409007722,
    "payload": {
        "type": "BNTx",
        "txHash": "3178...",
        "inputs": [
            {
                "type": "BNTxIn",
                "previousTxHash": "f9b2...",
                "previousOutIndex": 0,
                "previousTxSerializedHex": "0100...",
                "scriptSig": {
                    "type": "BNScriptSig",
                    "programHexBytes": "0047...",
                    "isMultisig": true
                }
            }
        ],
        "outputs": [
            {
                "type": "BNTxOut",
                "value": 103333,
                "scriptPubKey": {
                    "type": "BNPayToAddressScriptPubKey",
                    "address": "1MLps..."
                }
            },
            {
                "type": "BNTxOut",
                "value": 196666,
                "scriptPubKey": {
                    "type": "BNPayToAddressScriptPubKey",
                    "address": "1AiRT..."
                }
            }
        ],
        "updateTime": 0,
        "netValue": 299999,
        "serializedHex": "0100...",
        "fee": 10000,
        "confirmations": 0,
        "error": null
    }
}

Refund

If the good or service is not provided, the buyer can request a refund: a transaction that returns the security deposits to their respective parties and returns the payment to the buyer. If the seller agrees, they sign and broadcast it.

BuyRefundRequestMsg

Sent from buyer to seller with the first half of the refund transaction.

{
    "_type": "BuyRefundRequestMsg",
    "postUuid": "1F343...",
    "sellerAddress": "BM-2cTEk...",
    "buyerAddress": "BM-2cTEk...",
    "dateNumber": 1410879639,
    "payload": {
        "type": "BNTx",
        "txHash": null,
        "inputs": [
            {
                "type": "BNTxIn",
                "previousTxHash": "9749d...",
                "previousOutIndex": 0,
                "previousTxSerializedHex": "0100...",
                "scriptSig": null
            }
        ],
        "outputs": [
            {
                "type": "BNTxOut",
                "value": 306666,
                "scriptPubKey": {
                    "type": "BNPayToAddressScriptPubKey",
                    "address": "1JUFU..."
                }
            }
        ],
        "updateTime": null,
        "fee": null,
        "confirmations": null,
        "error": null
    }
}

SellAcceptRefundRequestMsg

Sent from seller to buyer with the completed refund transaction. The buyer broadcasts it on the Bitcoin network.

{
    "_type": "SellAcceptRefundRequestMsg",
    "postUuid": "1F3439...",
    "sellerAddress": "BM-2cTEk...",
    "buyerAddress": "BM-2cTEk...",
    "dateNumber": 1410880002,
    "payload": {
        "type": "BNTx",
        "txHash": "5a9f4...",
        "inputs": [
            {
                "type": "BNTxIn",
                "previousTxHash": "9749d...",
                "previousOutIndex": 0,
                "previousTxSerializedHex": "0100...",
                "scriptSig": {
                    "type": "BNScriptSig",
                    "programHexBytes": "0047...",
                    "isMultisig": true
                }
            }
        ],
        "outputs": [
            {
                "type": "BNTxOut",
                "value": 306666,
                "scriptPubKey": {
                    "type": "BNPayToAddressScriptPubKey",
                    "address": "1JUFU..."
                }
            },
            {
                "type": "BNTxOut",
                "value": 143333,
                "scriptPubKey": {
                    "type": "BNPayToAddressScriptPubKey",
                    "address": "12875..."
                }
            }
        ],
        "updateTime": 0,
        "netValue": 449999,
        "serializedHex": "0100...",
        "fee": 10000,
        "confirmations": 0,
        "error": null
    }
}

This content is in the public domain.