Proof of Issuance - Blockstream’s Liquid Asset Registry¶
This example shows how to use Blockstream’s Liquid Asset Registry. The asset registry allows you to register an asset and prove ownership against a domain name.
The code below creates an asset, an associated token, and outputs two files:
A
liquid-asset-proof-<asset-id>
file that must be placed on the server of the registered domain over the entire lifecycle of the asset.A
register_asset.sh
file that, when run, will post the asset registration data to Blockstream’s Liquid Asset Registry.
The use of the output files will be explained later.
There are six fields that need setting within the script:
NAME
The name of the asset as it will apear in the registry and applications that use asset registry data, such as the Blockstream Explorer. Length must be 5 to 255 ASCII characters.TICKER
The ticker you would like to assign to the asset. Length must be 3 to 5 characters. Valid characters are:a-z
A-Z
.
and-
. If provided, ticker has to be unique when combined with the domain field.DOMAIN
The domain that will be used to verify the asset. Must be a valid domain name format and only supports (sub)domain names, for example: example.com or sub.example.com. Do not include the http/s or www prefixes. To verify you control the entity domain name, you’ll need to place a file on your webserver. Note that serving the file with https is required, except for .onion hidden services. The file should be made available athttps://<domain>/.well-known/liquid-asset-proof-<asset-id>
, with the following contents (See line 133 of the code example below for an example of file content generation):Authorize linking the domain name <domain> to the Liquid asset <asset-id>
ASSET_AMOUNT
The amount to be issued. It is preferable to consider one satoshi unit as representing one asset. So to issue an amount of 100 of an asset, a value of 0.00000100 should be used. Please note that how this value is displayed within applications that use asset registry data is affected by thePRECISION
field.TOKEN_AMOUNT
The amount of reissuance tokens to be created. It is preferable to consider one satoshi unit as representing one reissuance token, so a value of 0.00000001 will create 0.00000001 reissuance tokens and when viewed from Liquid Core it will also show as 0.00000001. When viewed from an app that uses satoshi sized units, such as the Blockstream Explorer it will show as 1. This field is not affected by thePRECISION
field.PRECISION
The precision used to display the asset amount within applications that use Liquid Asset Registry data, such as the Blockstream Explorer. Represents the number of digits after the decimal point, i.e. 0 for non-divisible assets or 8 for BTC-like divisible assets. See the examples below.
Precision examples:
A PRECISION
value of 0 for an ASSET_AMOUNT
of 0.00000100 will create 0.00000100 when viewed from Liquid Core and 100 when viewed in an app that uses the asset registry data, which shifts the decimal 0 places left from the sats value.
A PRECISION
value of 2 for an ASSET_AMOUNT
of 0.00000100 will create 0.00000100 when viewed from Liquid Core and 1.00 when viewed in an app that uses the asset registry data, which shifts the decimal 2 places left from the sats value.
A PRECISION
value of 8 for an ASSET_AMOUNT
of 0.00000100 will create 0.00000100 when viewed from Liquid Core and 0.00000100 when viewed in an app that uses the asset registry data, which shifts the decimal 8 places left from the sats value. This equates to BTC units.
The default is 0 and the maximum value is 8.
Please note that precision is not taken into account when displaying reissuance token amounts. So if you issue your asset with 1 reissuance token it will always show as 100 000 000 (the amount 1.00 in sats) via Blockstream Explorer and other apps using the registry. In Elements it will show as 1.00000000.
PUBKEY
holds the public key value that goes into theissuer_pubkey
registration data field. The code example derives this from a new address generated by a private key in the node’s wallet.dat file. For safety, this file should be backed up after running the script. Any ECDSA secp256k1 public key could be used in its place, which may be of use when the issuing entity is not the same as the entity running the script. You should ensure that, whatever PUBKEY value you use to set the registration data’s issuer_pubkey field, it is recorded somewhere and that the corresponding private key is backed up for potential future use in authorizing amendments to the registry data. Note that the script sets thePUBKEY
variable’s value by callinggetaddressinfo
with a new address generated by the node’s wallet (line 52). The value of PUBKEY is then used to set the issuer_pubkey registration data field (line 64). The issuer_pubkey data field is used by the Asset Registry to verify ownership when removing or updating registry data in the future.
The code below uses Liquid in live mode. The code can easily be adapted for test use.
Save the code below in a file named issue_and_prepare_register.sh
and take a back up of the script before you run it as you may wish to refer to it in the future to track how you created the registry data.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | #!/bin/bash
set -x
shopt -s expand_aliases
# ASSUMES elementsd IS ALREADY RUNNING
######################################################
# #
# SCRIPT CONFIG - PLEASE REVIEW BEFORE RUNNING #
# #
######################################################
# Amend the following:
NAME="Wintercoin"
TICKER="WTX"
# Do not use a domain prefix in the following:
DOMAIN="wintercooled.github.io"
# Issue 100 assets using the satoshi unit, dependant on PRECISION when viewed from
# applications using Asset Registry data.
ASSET_AMOUNT=0.00000100
# Issue 1 reissuance token using the satoshi unit, unaffected by PRECISION.
TOKEN_AMOUNT=0.00000001
# Amend the following if needed:
PRECISION=0
# Don't change the following:
VERSION=0
# If your Liquid node has not seen enough transactions to calculate
# its own feerate you will need to specify one to prevent a 'feeRate'
# error. We'll assume this is the case:
FEERATE=0.00003000
# Change the following to point to your elements-cli binary and liquid data directory.
alias e1-cli="$HOME/elements-0.17.0.1/bin/elements-cli -datadir=$HOME/.elements"
##############################
# #
# END OF SCRIPT CONFIG #
# #
##############################
# Exit on error
set -o errexit
# We need to get a 'legacy' type (prefix 'CTE') address for this:
NEWADDR=$(e1-cli getnewaddress "" legacy)
VALIDATEADDR=$(e1-cli getaddressinfo $NEWADDR)
PUBKEY=$(echo $VALIDATEADDR | jq '.pubkey' | tr -d '"')
ASSET_ADDR=$NEWADDR
NEWADDR=$(e1-cli getnewaddress "" legacy)
TOKEN_ADDR=$NEWADDR
# Create the contract and calculate the contract hash.
# The contract is formatted for use in the Blockstream Asset Registry
# Do not amend the following!
CONTRACT='{"entity":{"domain":"'$DOMAIN'"},"issuer_pubkey":"'$PUBKEY'","name":"'$NAME'","precision":'$PRECISION',"ticker":"'$TICKER'","version":'$VERSION'}'
# We will hash using openssl, other options are available
CONTRACT_HASH=$(echo -n $CONTRACT | openssl dgst -sha256)
CONTRACT_HASH=$(echo ${CONTRACT_HASH#"(stdin)= "})
# Reverse the hash. This will be calculated from the contract by the asset registry service to
# check validity of the issuance against the registry entry.
TEMP=$CONTRACT_HASH
LEN=${#TEMP}
until [ $LEN -eq "0" ]; do
END=${TEMP:(-2)}
CONTRACT_HASH_REV="$CONTRACT_HASH_REV$END"
TEMP=${TEMP::-2}
LEN=$((LEN-2))
done
RAWTX=$(e1-cli createrawtransaction '''[]''' '''{"''data''":"''00''"}''')
# If your Liquid node has seen enough transactions to calculate its
# own feeRate then you can switch the two lines below. We'll default
# to specifying a fee rate:
#FRT=$(e1-cli fundrawtransaction $RAWTX)
FRT=$(e1-cli fundrawtransaction $RAWTX '''{"''feeRate''":'$FEERATE'}''')
HEXFRT=$(echo $FRT | jq '.hex' | tr -d '"')
RIA=$(e1-cli rawissueasset $HEXFRT '''[{"''asset_amount''":'$ASSET_AMOUNT', "''asset_address''":"'''$ASSET_ADDR'''", "''token_amount''":'$TOKEN_AMOUNT', "''token_address''":"'''$TOKEN_ADDR'''", "''blind''":false, "''contract_hash''":"'''$CONTRACT_HASH_REV'''"}]''')
# Details of the issuance...
HEXRIA=$(echo $RIA | jq '.[0].hex' | tr -d '"')
ASSET=$(echo $RIA | jq '.[0].asset' | tr -d '"')
ENTROPY=$(echo $RIA | jq '.[0].entropy' | tr -d '"')
TOKEN=$(echo $RIA | jq '.[0].token' | tr -d '"')
# Blind, sign and send the issuance transaction...
BRT=$(e1-cli blindrawtransaction $HEXRIA true '''[]''' false)
SRT=$(e1-cli signrawtransactionwithwallet $BRT)
HEXSRT=$(echo $SRT | jq '.hex' | tr -d '"')
# Test the transaction's acceptance into the mempool
TEST=$(e1-cli testmempoolaccept '''["'$HEXSRT'"]''')
ALLOWED=$(echo $TEST | jq '.[0].allowed' | tr -d '"')
# If the transaction is valid
if [ "true" = $ALLOWED ] ; then
# Broadcast the transaction
ISSUETX=$(e1-cli sendrawtransaction $HEXSRT)
else
echo "ERROR SENDING TRANSACTION!"
fi
#####################################
# #
# ASSET REGISTRY FILE OUTPUTS #
# #
#####################################
# Blockstream's Liquid Asset Registry (https://assets.blockstream.info/) can be used to register an asset to an issuer.
# We already have the required data and have formatted the contract plain text into a format that we can use for this.
# Write the domain and asset ownership proof to a file. The file should then be placed over the entire lifecycle of
# the asset in a directory within the root of your domain named ".well-known"
# The file should have no extension and just copied as it is created.
echo "Authorize linking the domain name $DOMAIN to the Liquid asset $ASSET" > liquid-asset-proof-$ASSET
# After you have placed the above file without your domain you can run the register_asset.sh script created below to post the asset data to the registry.
echo "curl https://assets.blockstream.info/ --data-raw '{\"asset_id\":\"$ASSET\",\"contract\":$CONTRACT}'" > register_asset.sh
# For reference, write some asset details. These are not needed by the asset registry.
echo "ISSUETX:$ISSUETX ASSET:$ASSET ENTROPY:$ENTROPY TOKEN:$TOKEN ASSET_AMOUNT:$ASSET_AMOUNT TOKEN_AMOUNT:$TOKEN_AMOUNT ASSET_ADDR:$ASSET_ADDR TOKEN_ADDR:$TOKEN_ADDR CONTRACT_HASH_REV:$CONTRACT_HASH_REV" > liquid-asset-ref-$ASSET
##################################################################
echo "Completed without error"
|
When you have saved the above to the file, edit the variables at the top and of the file and start elements-qt or elementsd using an argument of -server=1
to allow the Liquid client to communicate with it. Execute the script from the directory you created it in by opening a Terminal session and running:
bash issue_and_prepare_register.sh
In order to register the asset just created:
Wait a couple of minutes for the issuance transaction to confirm.
Place the
liquid-asset-proof-<asset-id>
file in a folder named.well-known
in the root of your domain. This proof should be stored there over the entire lifecycle of the asset.Run the
register_asset.sh
script.
For example, if your domain was www.your-example-domain-here.com
and the asset id generated was 123abc (it will of course be much longer) then the file generated would be named:
liquid-asset-proof-123abc
The domain variable in the code above would be set to:
your-example-domain-here.com
So the path used to check asset to domain registry would end up being:
www.your-example-domain-here.com/.well-known/liquid-asset-proof-123abc
Once that file is accessible you can then run the register_asset.sh
script and, when the required checks against the domain and issuance transaction have been made, the registration will be found on Blockstream’s Liquid Asset Registry.
Deleting Asset Registration Data¶
Deleting an asset from the Blockstream Asset Registry only removes its metadata from the registry. It does not, and cannot, delete the asset itself from the Liquid Blockchain.
To delete an asset from the Blockstream Asset Registry, sign the following message using the issuer_pubkey
used when registering the asset:
remove <asset-id> from registry
Then submit the deletion request with the base64-encoded signature:
$ curl -X DELETE https://assets.blockstream.info/<asset-id> -H 'Content-Type: application/json' \
-d '{"signature":"<base64-encoded-signature>"}'