This post explains the process of encoding and decoding Counterparty transactions
#Encode
You can use one of these methods:
- Use Counterparty API (e.g.
create_send
) to create a raw Bitcoin transaction with embedded Counterparty payload. This approach is easier, but requires access to a Counterparty server or API endpoint. - Use any programming language to compose such a transaction manually. This is harder, but does not require a Counterparty server or Counterparty API access.
The API (create_send
) returns a raw bitcoin transaction, i.e. there’s no need to encode anything manually.
###Counterparty Transaction Encoding
The best source of such information are Counterparty repositories on Github (for example, counterparty-lib
). You can also reference this page (and other content in this repository): https://github.com/tokenly/counterparty-spec/blob/master/spec/03-encoding.md.
###Example
Go to a Counterparty block explorer, get a transaction ID and then use a Bitcoin explorer to see how such transaction looks from that side.
It’s probably easiest to create a transaction yourself using Counterwallet and then - having the address and private key - try to get the same transaction output using whatever coding approach you choose.
A working example of a Counterparty encoder written in JavaScript can be found here.
A Counterparty payload example from testnet used in this post: 0000000015056c5dd87f00000000000000000001
#Decode
Use the reverse process to decode a Counterparty transaction.
You can use a bitcoin transaction decoder such as (testnet example): https://live.blockcypher.com/btc-testnet/decodetx/ and then proceed to decode the Counterparty payload within the transaction.
###Counterparty Transaction Decoding
Implementations and code examples can be found in Counterparty repositories such as counterparty-lib
and open source Counterparty projects that don’t use the Counterparty API.
There’s also a helpful page on decoding Counterparty transactions created by Tokenly:
###Example
Raw testnet transaction created by Counterparty (returned by create_send
, for example):
0100000001a551b593f03e948d3a91770d1fe6dc78d92c960387cdf0c79bd3970fc2c7f845020000001976a914f8eb547223b286af4c069845bab650951de0ba8988acffffffff0335150000000000001976a914dd1262b79cba636a0366790369d8442f2b7fba0688ac00000000000000001e6a1c8e180488b758e3c22003bcd9cea28c633dc9a5d110a791c889910840a2fb3200000000001976a914f8eb547223b286af4c069845bab650951de0ba8988ac00000000
Signed testnet transaction (that was broadcast on the bitcoin network):
0100000001a551b593f03e948d3a91770d1fe6dc78d92c960387cdf0c79bd3970fc2c7f845020000006a473044022064355db66650c3a9b51ed4b4bae383f914486f61750db83164cc9f75dbf9bb0502204812af330d83655a4724b92caaf0634e9cc34b04cdbf16766c27d3a19f53403901210265f9763ea8f857571a003a9c7abddc9875a3dd921dbdb15c1659944869f945cdffffffff0335150000000000001976a914dd1262b79cba636a0366790369d8442f2b7fba0688ac00000000000000001e6a1c8e180488b758e3c22003bcd9cea28c633dc9a5d110a791c889910840a2fb3200000000001976a914f8eb547223b286af4c069845bab650951de0ba8988ac00000000
The same transaction can be decoded with a decoder such as https://live.blockcypher.com/btc-testnet/decodetx/ (for testnet):
{
"addresses": [
"n4D7ndiC4yLZxhAf726uMHXC914sEuUAcg",
"n1fseuMLWaKDnDkpXiz8PpwV8RqYna9Mbf"
],
"block_height": -1,
"block_index": -1,
"confirmations": 0,
"data_protocol": "unknown",
"double_spend": false,
"fees": 7875,
"hash": "afd90be0ffea165e7d4fe479920cdcea4c0efd11a1d14cc43bb0176f1e0bc4da",
"inputs": [
{
"addresses": [
"n4D7ndiC4yLZxhAf726uMHXC914sEuUAcg"
],
"output_index": 2,
"output_value": 3354522,
"prev_hash": "45f8c7c20f97d39bc7f0cd8703962cd978dce61f0d77913a8d943ef093b551a5",
"script": "473044022064355db66650c3a9b51ed4b4bae383f914486f61750db83164cc9f75dbf9bb0502204812af330d83655a4724b92caaf0634e9cc34b04cdbf16766c27d3a19f53403901210265f9763ea8f857571a003a9c7abddc9875a3dd921dbdb15c1659944869f945cd",
"script_type": "pay-to-pubkey-hash",
"sequence": 4294967295
}
],
"lock_time": 0,
"outputs": [
{
"addresses": [
"n1fseuMLWaKDnDkpXiz8PpwV8RqYna9Mbf"
],
"script": "76a914dd1262b79cba636a0366790369d8442f2b7fba0688ac",
"script_type": "pay-to-pubkey-hash",
"value": 5429
},
{
"addresses": null,
"data_hex": "8e180488b758e3c22003bcd9cea28c633dc9a5d110a791c889910840",
"script": "6a1c8e180488b758e3c22003bcd9cea28c633dc9a5d110a791c889910840",
"script_type": "null-data",
"value": 0
},
{
"addresses": [
"n4D7ndiC4yLZxhAf726uMHXC914sEuUAcg"
],
"script": "76a914f8eb547223b286af4c069845bab650951de0ba8988ac",
"script_type": "pay-to-pubkey-hash",
"value": 3341218
}
],
"preference": "medium",
"received": "2016-10-27T07:00:31.93228414Z",
"relayed_by": "54.158.61.129",
"size": 264,
"total": 3346647,
"ver": 1,
"vin_sz": 1,
"vout_sz": 3
}
From here you’d have to decode the transaction using the same approach that counterparty-lib
uses (or leverage the API).
With the Counterparty API you can use get_tx_info
(see http://counterparty.io/docs/api/#get_tx_info). For input we use the raw unsigned transaction (hexadecimal serialization of the transaction, not its hash). Put another way, tx_hex
is what the API or client returns before you sign and broadcast (or send, in Bitcoin Core language) the transaction. The Counterparty API (server) sometimes confusingly returns a weird message (‘Asked to read 32 bytes, but only got 27’) if you pass it the hash (which is actually 64 bytes!) of a signed & sent transaction.
{
"method": "get_tx_info",
"params": {"tx_hex": "0100000001a551b593f03e948d3a91770d1fe6dc78d92c960387cdf0c79bd3970fc2c7f845020000001976a914f8eb547223b286af4c069845bab650951de0ba8988acffffffff0335150000000000001976a914dd1262b79cba636a0366790369d8442f2b7fba0688ac00000000000000001e6a1c8e180488b758e3c22003bcd9cea28c633dc9a5d110a791c889910840a2fb3200000000001976a914f8eb547223b286af4c069845bab650951de0ba8988ac00000000"},
"jsonrpc": "2.0",
"id": 1
}
Response:
{
"result": [
"n4D7ndiC4yLZxhAf726uMHXC914sEuUAcg",
"n1fseuMLWaKDnDkpXiz8PpwV8RqYna9Mbf",
5429,
7875,
"0000000015056c5dd87f00000000000000000001"
],
"id": 1,
"jsonrpc": "2.0"
}
As you can probably guess, here’s what the list means:
- source
- destination
- btc_amount (in satoshi)
- tx_fee (to bitcoin miners)
- data (Counterparty payload)
Now we need to decode the payload (0000000015056c5dd87f00000000000000000001
) . Refer to Tokenly’s decoder or counterparty-lib
or examples such as this JavaScript decoder.
Here we’ll use another Counterparty API, unpack
, and pass the Counetrparty payload from the previous call:
{
"method": "unpack",
"params": {"data_hex": "0000000015056c5dd87f00000000000000000001"},
"jsonrpc": "2.0",
"id": 1
}
Finally, we get the result:
{
"result": [
0,
{
"quantity": 1,
"asset": "A1514736000000000000"
}
],
"id": 1,
"jsonrpc": "2.0"
}
#Send Transaction Used in This Post
This was the original transaction (again, on testnet):
send --source n4D7ndiC4yLZxhAf726uMHXC914sEuUAcg --destination n1fseuMLWaKDnDkpXiz8PpwV8RqYna9Mbf --asset A1514736000000000000 --quantity 1