Skip to content

Issuance of liquid assets with multisig and registry support

Notifications You must be signed in to change notification settings

Blockstream/liquid_multisig_issuance

Repository files navigation

Liquid assets on multisig addresses

In this example, we will show how to:

  • create Liquid 2-of-2 multisig addresses
  • issue Liquid assets and reissuance tokens directly on such addresses,
  • register assets on the asset registry
  • send asset from the multisig output
  • reissue the asset

Install Elements

Download Elements from the GitHub Releases page, the following scripts use Elements version 0.18.1.9.

Create wallets and configure

In order to configure your Elements regtest and create the wallets you need to write a configuration file for the Elements instance.

chain=elementsregtest
daemon=1
listen=1
validatepegin=0

initialfreecoins=2100000000000000

rpcuser=username
rpcpassword=password
elementsregtest.rpcallowip=0.0.0.0/0
elementsregtest.rpcport=18891
elementsregtest.port=18893

txindex=1

elementsregtest.wallet=wallet.dat
elementsregtest.wallet=wallet_1.dat
elementsregtest.wallet=wallet_2.dat
elementsregtest.wallet=wallet_3.dat

Save this file in the configuration folder (e.g. ~/.elements/elements.conf) and run the elementsd executable.

Configure the file liquid_utils.py with the correct username, password and IP address for each wallet involved (which might need to be created and loaded).

If you start with a fresh regtest you will need to move some funds from your wallet to your wallet_1. You can use the command elements-cli -rpcwallet=wallet.dat sendtoaddress $(elements-cli -rpcwallet=wallet_1.dat getnewaddress) 1000 then you can generate a block elements-cli -rpcwallet=wallet.dat generate 1 and finally check balance of your wallet_1 elements-cli -rpcwallet=wallet_1.dat getbalance "*" 0 true.

If your regtest wallet has funds or you are using mainnet you don't need to execute the previous commands.

We will use 4 wallets in this way:

  • wallet to generate blocks and move funds (the "miner")
  • wallet_1 and wallet_2 to create the multisig for assets and tokens (the "cosigners")
  • wallet_3 for receive assets (the "receiver")

Create the environment

Create and activate a virtual environment for python 3.

virtualenv -p python3 venv3
source venv3/bin/activate
pip install -r requirements.txt

Remember to call this scripts from the virtualenv.

Issue assets

The first step is issuing an asset compatible with the asset registry requirements. The assets and the reissuance tokens will be sent to two 2 of 2 multisig wallet (between wallet_1 and wallet_2).

Configure

he parameters needed to make the issuance compatible with the asset registry can be found in the file issue.py. You will need to specify:

  • a pubkey (in hexadecimal format) corresponding to a privkey controlled by the issuer; this key will be used to sign update messages for the asset registry (allowing future updates to the asset registry)

  • a name for your asset (<255 ASCII chars)

  • a ticker (3 or 4 ASCII chars)

  • the precision, corresponding to the position shift of the point with respect to satoshis (in other words the digits after the decimal separator when you represent values in satoshi). E.g. Asset amount 0.00000020 == 20 satoshi with precision 0 -> 20 assets Asset amount 0.00000315 == 315 satoshi with precision 2 -> 3,15 assets Asset amount 1.00000000 == 100000000 satoshi with precision 8 -> 1 assets

  • the domain connected with the issuance (you will need to publish a file in the folder .well-known of this server)

Modify the variables in the file issue.py before calling the scripts.

...
# FIXME: contract information (all required for asset registry)
issuer_pubkey = ''
name = 'asset name'
ticker = 'XYZ'
precision = 0
domain = 'domain.com'
version = 0 # don't change
...

Exec the script

After configuration, you can call the script passing all the arguments needed.

Usage: python issue.py ASSET_AMOUNT ASSET_ADDRESS REISSUANCE_TOKEN_AMOUNT REISSUANCE_TOKEN_ADDRESS

The script create_multisig.py helps creating multisig addresses between wallet_1 and wallet_2 and can be used called in a simple shell script like the following.

echo "Create multisig issuance"
ASSET_AMOUNT="0.00000020"
REISSUANCE_TOKEN_AMOUNT="0.00000005"
echo "   Create multisig address for the asset"
MULTISIG_ASSET=$(python create_multisig.py asset)
MULTISIG_ASSET_ADDRESS=$(echo $MULTISIG_ASSET | jq -r .multisig)
echo "   Create multisig address for the reissuance token"
MULTISIG_REISSUANCE=$(python create_multisig.py reissuance)
MULTISIG_REISSUANCE_ADDRESS=$(echo $MULTISIG_REISSUANCE | jq -r .multisig)
echo "   Create the issuance transaction (information available in the file TX_ISSUANCE.txt)"
TX_ISSUANCE=$(python issue.py $ASSET_AMOUNT $MULTISIG_ASSET_ADDRESS $REISSUANCE_TOKEN_AMOUNT $MULTISIG_REISSUANCE_ADDRESS)
echo $TX_ISSUANCE > TX_ISSUANCE.txt

In this example are generated 20 asset tokens and 5 reissuance tokens (consider precision = 0), you can check balance of wallet_1 using the command elements-cli -rpcwallet=wallet_1.dat getbalance "*" 0 true.

In the file TX_ISSUANCE.txt you can read all the information about the issuance and you can find the contract JSON code fragment, we will use this code for the asset registry request.

The issuance transaction is built on the basis of a simple transaction, in our case a simple transaction with op_return, on which the fees are calculated. Obviously, the fees must be increased (acting on the used feerate on the fundrawtransaction call) in order to cover the weight of the final transaction.

If the fees are too low, they can be increased by changing the value of the variable feerate on the script issue.py.

Register the asset on asset registry

After the issuance, you can register the token in the asset registry following these steps.

CONTRACT=$(echo $TX_ISSUANCE  | jq -r .contract)
ASSET=$(echo $TX_ISSUANCE | jq -r .asset_id)
TXID=$(echo $TX_ISSUANCE | jq -r .txid)
ISSUANCE_TX=$(echo $TX_ISSUANCE | jq -r .txid)
DOMAIN=$(echo $TX_ISSUANCE | jq -r .contract |jq -r .entity.domain)

echo "curl https://assets.blockstream.info/ --data-raw '{\"asset_id\":\"$ASSET\",\"contract\":$CONTRACT,\"issuance_txin\":{\"txid\":\"$ISSUANCE_TX\",\"vin\":0}}'" > register_asset.sh
echo "Authorize linking the domain name $DOMAIN to the Liquid asset $ASSET" > liquid-asset-proof-$ASSET

Copy the generated file liquid-asset-proof-... in the folder .well-known of the same server specified in the contract.

Execute the script register_asset.sh or perform a simple curl call to inform the registry about the new issuance.

The asset registry will check all information about the issuance and will search for the liquid asset proof file in the specified domain.

Move asset from the multisig address

The script send_assets.py shows how we can send a certain amount of assets to another address (multisig or not), sending the change back to another multisig.

Usage: python send_assets.py ASSET ASSET_ADDRESS ASSET_AMOUNT ASSET_CHANGE_ADDRESS

All the information needed can be obtained using the following script.

echo "Send some tokens to a singlesig address"
ASSET=$(echo $TX_ISSUANCE | jq -r .asset_id)
AMOUNT="0.00000001"
echo "   Get a receiving address (on wallet_3)"
RECEIVING_ADDRESS=$(python get_address.py receiver | jq -r .address)
echo "   Create a multisig change address"
MULTISIG_ASSET_CHANGE=$(python create_multisig.py change)
MULTISIG_ASSET_CHANGE_ADDRESS=$(echo $MULTISIG_ASSET_CHANGE | jq -r .multisig)
echo "   Create the transaction (information available in the file TX_SEND.txt)"
TX_SEND=$(python send_assets.py $ASSET $RECEIVING_ADDRESS $AMOUNT $MULTISIG_ASSET_CHANGE_ADDRESS)
echo $TX_SEND > TX_SEND.txt

In this case I'm moving 1 asset token from my multisig (wallet_1 and wallet_2) to a singlesig address controlled by wallet_3. The remaining assets are moved to a new multisig address. The asset id is found from the data saved from the previous step.

You can check the balance of wallet_3 using elements-cli -rpcwallet=wallet_3.dat getbalance.

Reissuance assets from a multisig address

If we want to issue more assets we can use the reissuance token, the reissuance.py script shows how we can reissue assets using tokens held in a multisig wallet.

Usage: python reissuance.py AMOUNT ASSET_ADDRESS ENTROPY REISSUANCE_TOKEN REISSUANCE_TOKEN_ADDRESS REISSUANCE_TOKEN_CHANGE_ADDRESS

Like before we can use some scripts in order to calculate new multisig addresses for change outputs and new assets.

echo "Reissue and asset using a reissunce token present in a multisig wallet"
AMOUNT="0.00000300"
echo "   Create a multisig address for the asset"
MULTISIG_ASSET_REISSUANCE=$(python create_multisig.py "asset reissuance")
MULTISIG_ASSET_REISSUANCE_ADDRESS=$(echo $MULTISIG_ASSET_REISSUANCE | jq -r .multisig)
echo "   Get asset and token information"
ASSET_ENTROPY=$(echo $TX_ISSUANCE | jq -r .decoded_raw_transaction.vin[0].issuance.assetEntropy)
REISSUANCE_TOKEN=$(echo $TX_ISSUANCE | jq -r .decoded_raw_transaction.vin[0].issuance.token)
echo "   Create a multisig address for the reissuance token"
REISSUANCE_TOKEN_MULTISIG=$(python create_multisig.py "token reissuance")
REISSUANCE_TOKEN_ADDRESS=$(echo $REISSUANCE_TOKEN_MULTISIG | jq -r .multisig)
echo "   Create a multisig change address for the reissuance token"
REISSUANCE_TOKEN_CHANGE=$(python create_multisig.py "token reissuance change")
REISSUANCE_TOKEN_CHANGE_ADDRESS=$(echo $REISSUANCE_TOKEN_CHANGE | jq -r .multisig)
echo "   Create the reissuance transaction (information available in the file TX_REISSUANCE.txt)"
TX_REISSUANCE=$(python reissuance.py $AMOUNT $MULTISIG_ASSET_REISSUANCE_ADDRESS $ASSET_ENTROPY $REISSUANCE_TOKEN $REISSUANCE_TOKEN_ADDRESS $REISSUANCE_TOKEN_CHANGE_ADDRESS)
echo $TX_REISSUANCE > TX_REISSUANCE.txt

In this case we are creating 300 new assets, the reissuance token will be moved in a new multisig address.

As already discussed in the case of the issue.py script, if the fees are too low, the value of the variable feerate in the reissuance.py script can be increased.

About

Issuance of liquid assets with multisig and registry support

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages