210 lines
10 KiB
Markdown
210 lines
10 KiB
Markdown
# DeepDive into Liquid: Part II - Asset Creation and Configuration
|
|
|
|
This is a multipart DeepDive that will focus on the Liquid Sidechain. It will be released in 3 Parts:
|
|
|
|
* [Part I](https://stacker.news/items/399400): Overview, Installation, and first Peg-In
|
|
* Part II (this): Asset Creation and Configuration
|
|
* Part III: Advanced Topics and Peg-out
|
|
|
|
## Assets
|
|
|
|
In Part I, we succesfully Pegged-In our BTC and received L-BTC, now lets use that L-BTC to do some interesting things with Asset Issuance:
|
|
|
|
* Let's begin by checking out these 2 commands[^1]:
|
|
- `$ sudo ./scripts/app compose elements exec node elements-cli -rpcuser=$E_RPCUSER -rpcpassword=$E_RPCPASS getwalletinfo`
|
|
|
|
"balance": {"bitcoin": 0.00149155}
|
|
|
|
- `$ sudo ./scripts/app compose elements exec node elements-cli -rpcuser=$E_RPCUSER -rpcpassword=$E_RPCPASS dumpassetlabels`
|
|
|
|
{"bitcoin": "6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d"}
|
|
|
|
This is telling us that `bitcoin` is a label for an asset that has the UUID of `6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d`. Everything in Liquid is an 'Asset' (including L-BTC) and each of these Assets can have different features.
|
|
|
|
Looking up this value on [https://blockstream.info/liquid/assets](https://blockstream.info/liquid/asset/6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d) we can see some info about it:
|
|
|
|

|
|
|
|
This shows us the total amount of L-BTC in circulation, additionally we can see how much was Pegged-In and Out. Most notably,
|
|
|
|
### Issuing our own Asset
|
|
|
|
Issuing assets is pretty straight forward, it can be roughly broken down into 3 main steps[^3]:
|
|
|
|
1. Generate a Legacy Address[^4] and PUBKEY for that address
|
|
2. Generate a Contract Hash
|
|
3. Issue the Asset
|
|
|
|
* STEP 1a: Let's generate our legacy address and set the output to a variable
|
|
`$ LEG_ADDRESS=$(sudo ./scripts/app compose elements exec node elements-cli -rpcuser=$E_RPCUSER -rpcpassword=$E_RPCPASS getnewaddress "" legacy`)
|
|
|
|
lq1qq2s92z0uq78kd4gfepua6qvfwx40g4lqqer9e3tzrr0j04ugyzsed39mnh9wvuhw0hmaqy5mxs9egqrr7j3rx8j2sdyun9m90
|
|
|
|
* STEP 1b: Set this address to a variable for use later and generate the public key.
|
|
- `$ export LEG_ADDRESS="lq1qq2s92....."`
|
|
- `$ sudo ./scripts/app compose elements exec node elements-cli -rpcuser=$E_RPCUSER -rpcpassword=$E_RPCPASS getaddressinfo $LEG_ADDRESS | jq '.pubkey'`
|
|
|
|
025aa49d444a150c99c904c8e779e5317aff4aee15ee9171f450e14af9dd8b8780
|
|
|
|
- `$ export PUBKEY="025aa49d444a150c99c904c8e779e5317aff4aee15ee9171f450e14af9dd8b8780"`
|
|
|
|
* STEP 2: In order to generate the contract hash, it requires a few steps - so I've simplified it by making a bash script. Copy this into a file named `gen_asset_contract.sh` and mark as executable
|
|
|
|
```
|
|
#!/bin/bash
|
|
#set -x
|
|
|
|
shopt -s expand_aliases
|
|
|
|
### FILENAME: gen_asset_contract.sh
|
|
### USAGE: ./gen_asset_contract.sh PUBKEY
|
|
|
|
if [ -z "$1" ]
|
|
then
|
|
echo "Please supply PUBKEY before running"
|
|
exit 1
|
|
fi
|
|
|
|
PUBKEY=$1
|
|
|
|
###EDIT THESE VALUES###
|
|
|
|
DOMAIN="nulldata.org"
|
|
NAME="StackerNews-Demo1"
|
|
PRECISION=8
|
|
TICKER="SND-1"
|
|
CONTRACT='{"entity":{"domain":"'$DOMAIN'"},"issuer_pubkey":"'$PUBKEY'","name":"'$NAME'","precision":'$PRECISION',"ticker":"'$TICKER'","version":'0'}'
|
|
CONTRACT_HASH=$(echo -n "${CONTRACT}" | sha256sum | sha256sum | sed 's/ .*//g')
|
|
|
|
#Generate a byte-aligned reveresed CONTRACT_HASH for use in asset Creation
|
|
TEMP=$CONTRACT_HASH
|
|
LEN=${#TEMP}
|
|
until [ $LEN -eq "0" ]; do
|
|
END=${TEMP:(-2)}
|
|
CONTRACT_HASH_REV="$CONTRACT_HASH_REV$END"
|
|
TEMP=${TEMP::$((${#TEMP} - 2))}
|
|
LEN=$((LEN-2))
|
|
done
|
|
|
|
### END EDITING HERE ###
|
|
echo CONTRACT=$CONTRACT
|
|
echo CONTRACT_HASH=$CONTRACT_HASH
|
|
echo CONTRACT_HASH_REV=$CONTRACT_HASH_REVT_HASH_REV=$CONTRACT_HASH_REV
|
|
```
|
|
|
|
* STEP 2: Now we can use the script we saved before to generate the contract:
|
|
|
|
- `$ ./gen_asset_contract.sh $PUBKEY`
|
|
|
|
CONTRACT={"entity":{"domain":"nulldata.org"},"issuer_pubkey":"025aa49d444a150c99c904c8e779e5317aff4aee15ee9171f450e14af9dd8b8780","name":"StackerNews-Demo1","precision":8,"ticker":"SND-1","version":0}
|
|
|
|
CONTRACT_HASH=df4bd5aec71f808f78b752cbaac783019fa20268265f66baa406e4202b77e4a1
|
|
|
|
CONTRACT_HASH_REV=a1e4772b20e406a4ba665f266802a29f0183c7aacb52b7788f801fc7aed54bdf
|
|
|
|
|
|
* STEP 2: Finally export those variables via bash to use later:
|
|
|
|
```
|
|
export CONTRACT={"entity":{"domain":"nulldata.org"},"issuer_pubkey":"025aa49d444a150c99c904c8e779e5317aff4aee15ee9171f450e14af9dd8b8780","name":"StackerNews-Demo1","precision":8,"ticker":"SND-1","version":1}
|
|
|
|
export CONTRACT_HASH=7d6bf3e3228fd00e9591c4c6bd1163d088a387e95d29fdfcf2e4e5035a137a94
|
|
|
|
export CONTRACT_HASH_REV=947a135a03e5e4f2fcfd295de987a388d06311bdc6c491950ed08f22e3f36b7d
|
|
```
|
|
|
|
* STEP 3: Now Issuing our own asset is straight-forward, as its a single line command in the client. Let's issue 10 new tokens and set the supply to be fixed (no re-issuance)
|
|
- `$ sudo ./scripts/app compose elements exec node elements-cli -rpcuser=$E_RPCUSER -rpcpassword=$E_RPCPASS issueasset 10 0 true $CONTRACT_HASH_REV`
|
|
|
|
{
|
|
"txid": dd3983619f67e7a743ccfd32e48bbdb591c1d44b86a71d442be95a2453c0479a,
|
|
"vin": 0,
|
|
"entropy": cd3d7319525b28b6500d0a0b4688d91392ba8192be9bc264ec9637a001907322,
|
|
"asset": 1e69f87952c26b8dfc80dda0427041a0279a0723ea12086b88b75752545e0d22,
|
|
"token": 2dc5fb795fd42e08adb9dd29b5ff14f4326ecd8443e1cdc31dc6666d7576ff89
|
|
}
|
|
|
|
* Checking out our wallet we see:
|
|
- `$ sudo ./scripts/app compose elements exec node elements-cli -rpcuser=$E_RPCUSER -rpcpassword=$E_RPCPASS getwalletinfo`
|
|
|
|
"balance": {"1e69f87952c26b8dfc80dda0427041a0279a0723ea12086b88b75752545e0d22": 10.00000000,"bitcoin": 0.00148701}
|
|
|
|
* We can see our wallet has 10 of our assets[^2], lets checkout what the [Liquid network knows about it](https://blockstream.info/liquid/asset/1e69f87952c26b8dfc80dda0427041a0279a0723ea12086b88b75752545e0d22):
|
|
|
|

|
|
|
|
* So publiclly we know the following about our new asset:
|
|
- It cannot be re-issued
|
|
- It has only been issued once
|
|
- However both the issued amount and the circulating supply has been hidden from us.
|
|
|
|
### Issuing a Non-Confidential Asset
|
|
|
|
* Let's create another asset and this time choose a different option (specifically, lets create this asset unblinded):
|
|
- `$ sudo ./scripts/app compose elements exec node elements-cli -rpcuser=$E_RPCUSER -rpcpassword=$E_RPCPASS issueasset 10 0 false`
|
|
|
|
{"txid": "1dfdf2f3a393a7a7be9f1f58c8651565a29486851268027794e1b69f5227864f",
|
|
"vin": 0,
|
|
"entropy": "5a32df406eb3f8c4f9b59c669d411e3a5ed0fd75058c2483e5732ccc6b482722",
|
|
"asset": "03d63d6c373979954a4dda2afdd941a0de96a0739da455af1cdb1a2e2a63a9a5",
|
|
"token": "ac860f370aabb829b70283c05e13a327cccec8ad0eea5493980cca53dd6631f9"}
|
|
|
|
...and checking again what [the Liquid network knows about it](https://blockstream.info/liquid/asset/03d63d6c373979954a4dda2afdd941a0de96a0739da455af1cdb1a2e2a63a9a5)
|
|
|
|

|
|
|
|
* Now we can see the total issued amount / supply[^2]
|
|
|
|
* Let's try sending this new unblinded asset to another wallet (my Blockstream Green mobile wallet) and see what is visible on the network.
|
|
- `$sudo ./scripts/app compose elements exec node elements-cli -named -rpcuser=$E_RPCUSER -rpcpassword=$E_RPCPASS sendtoaddress address="VJL6Thq......" amount=1.0 fee_rate=1 assetlabel="03d63d6c...."`
|
|
|
|
edf087368703bbb99054b4c5d7d1a85a9fbc4ad1ba9eac97c71463eb822dea3b
|
|
|
|
* Looking up this transaction on the [block explorer, we see](https://blockstream.info/liquid/tx/edf087368703bbb99054b4c5d7d1a85a9fbc4ad1ba9eac97c71463eb822dea3b):
|
|
|
|

|
|
|
|
This is interesting: So although the transaction is visible, we can't see what was actually transferred (even though the details of the asset are visible, *it is still hidden inside the transaction*). Further, where is my Green Wallet address (ie. VJL6Th...)? We can see 3 output addresses, presumably these are: Change, Fee, and Receipiant...but which is my Green Wallet?
|
|
|
|
* Let's look up my [Green Wallet address directly in the explorer](https://blockstream.info/liquid/address/VJL6ThqfHJdJXu4oqbsyZCDZuEupptqfRciySLdRLfRqSjLLKCPrt12Ki7a82XNZZMCf5gRfQ8b5rRdu):
|
|
|
|

|
|
|
|
So now this shows us that the *Confidential Address: VJL6Thq....* corresponds to the *Unconfidential Address: GprWqLK....* Through the magic of one-way hashes, if we know the "Confidential" address we can then dervive its public address....however just by looking at the public blockchain, there is no way to reverse that hash.
|
|
|
|
Now, lets look at how things look on the Green mobile wallet:
|
|
|
|

|
|
|
|
We can see that we've received 100,000,000 'sats' of our custom asset. However, notice how there is no labels. The elements for L-BTC, USDT, etc show with ticker symbols...whereas ours is showing just the contract address....not very user friendly. Let's see if we can remedy.
|
|
|
|
# Registering our Asset
|
|
|
|
The publication of asset metadata info on Liquid works on a `.well-known` system where specific files are published on a webserver that you control. There are a few different steps to accomplish this, so lets begin
|
|
|
|
* The first step is we need to generate a `legacy` address in case we ever want to delete the asset from the registry later[^3]
|
|
- `$ sudo ./scripts/app compose elements exec node elements-cli -rpcuser=$E_RPCUSER -rpcpassword=$E_RPCPASS getnewaddress "" legacy`
|
|
|
|
lq1qq2s92.....
|
|
|
|
* Set this address to a variable for use later and generate the public key.
|
|
- `$ export DELETE_ADDRESS="lq1qq2s92....."`
|
|
- `$ sudo ./scripts/app compose elements exec node elements-cli -rpcuser=$E_RPCUSER -rpcpassword=$E_RPCPASS getaddressinfo $DELETE_ADDRESS | jq '.pubkey'`
|
|
|
|
025aa49d444a150c99c904c8e779e5317aff4aee15ee9171f450e14af9dd8b8780
|
|
|
|
- `$ export PUBKEY="025aa49d444a150c99c904c8e779e5317aff4aee15ee9171f450e14af9dd8b8780"`
|
|
|
|
* We need to set some variable and then generate a json 'contract' file
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[^1]: The values E_RPCUSER and E_RPCPASS, where environmental variables we set in Part I
|
|
[^2]: Like in bitcoin, 1 integer unit is 100,000,000 base units (not sats, but equivalent concept)
|
|
[^3]: Technically just running `elements-cli issueasset 10 0` is enough to issue an asset, however there will be limitations later on when trying to register the asset, burn, remove, etc.
|
|
[^4]: Using a legacy address for this task imposes no real implications to your security since its only used to remove assets from the registry. Its possible to do this with a non-legacy address, but more steps are involved and we will need to use other tools rather than what's already built-in to Elements node, so we will just use a legacy address for this. |