RGB Protocol でアセットを発行し転送する

Hiroki Gondo
Nayuta エンジニアブログ
35 min readJan 15, 2024
Photo by Shubham Dhage on Unsplash

この記事では RGB Protocol(以下 RGB と略す)で任意のアセット(代替可能トークン)を発行しそれを転送する手順を説明する。実装は rgb-sandbox を用いる。

rgb-sandbox では自動デモと手動デモを試すことができるが、ここでは各手順の説明のため手動デモで行う。

いずれのデモも、macOS では一部の shell スクリプトが存在しない、オプションが異なる等の理由でデモが失敗する。修正版を作ったのそれで確認することができる。

環境構築

rgb-sandbox リポジトリのクローンを行う。

$ git clone https://github.com/RGB-Tools/rgb-sandbox - recurse-submodules - shallow-submodules
$ cd rgb-sandbox

ワーキングディレクトリを作成し、Docker コンテナで必要なサービスを開始する。2つのサービスが確認できる。

$ mkdir data{0,1,core,index}
$ docker compose up -d
$ docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
rgb-sandbox-bitcoind-1 registry.gitlab.com/hashbeam/docker/bitcoind:25.0 "/usr/local/bin/star…" bitcoind 5 minutes ago Up 5 minutes 8332–8333/tcp, 18332–18333/tcp, 18443–18444/tcp, 28332–28333/tcp
rgb-sandbox-electrs-1 registry.gitlab.com/hashbeam/docker/electrs:0.9.14 "/usr/local/bin/star…" electrs 5 minutes ago Up 5 minutes 24224/tcp, 0.0.0.0:50001->50001/tcp

ひとつは bitcoind でこれから作成するテストネットワーク(regtest)を管理する。electrs は Electrum Server というもので、アプリケーションが bitcoind にアクセスするのを便利にする。

2つの CLI ツールをインストールする。

$ cargo install bdk-cli - version "0.27.1" - root "./bdk-cli" - features electrum - locked
$ cargo install rgb-contracts - version "0.10.0-rc.5" - root "./rgb-contracts" - all-features - locked

bdk-cli で BDK を使ってBitcoin ウォレットを操作し、rgb-contracts で RGB 機能を操作する。

初期設定

CLI 呼び出しを容易にするためにエイリアスを設定する。

$ alias bcli="docker compose exec -u blits bitcoind bitcoin-cli -regtest"
$ alias bdk="bdk-cli/bin/bdk-cli"
$ alias rgb0="rgb-contracts/bin/rgb -n regtest -d data0"
$ alias rgb1="rgb-contracts/bin/rgb -n regtest -d data1"

それぞれ、以下を行うためのエイリアスである。

  • bcli: bitcoind を操作
  • bdk: bdk-cli で BDK を操作
  • rgb0: アセットの issuer/sender が、rgb を操作
  • rgb1: アセットの receiver が、rgb を操作

いくつかの環境変数を設定する。

$ CLOSING_METHOD="opret1st"
$ DERIVE_PATH="m/86'/1'/0'/9"
$ DESC_TYPE="wpkh"
$ ELECTRUM="localhost:50001"
$ ELECTRUM_DOCKER="electrs:50001"
$ CONSIGNMENT="consignment.rgb"
$ PSBT="tx.psbt"
$ IFACE="RGB20"

Bitcoin ウォレットの準備

まず Bitcoin のマイナー用の Bitcoin ウォレットを bitcond に用意し、ブロックを生成して残高を増やしておく。

$ bcli createwallet miner
bcli -generate 103{
"name": "miner"
}
$ bcli -generate 103
{
"address": "bcrt1qt8z7y9sycmzwp3w8fv4jrqhw8gytamd35yak6r",
"blocks": [
"342d3a9a092ea9a6db7d36428259442e53a58b12dd307a3fb44abb86fac3bfdc",
"1b8376f0e7fe18b55401901a51f938b8b1e92a840b578f6137a660e95dee8bd4",
"580e76c9015bbc59382f6b403c07677a1266ff62d2c6b732fa794a43fa9e2f3d",

"4162515dd5e9d225785d0f4cc1b97e9aabb4d0fc17efc2518a677479e93a4821"
]
}

次に BDK を使用して、アセットの issuer/sender(同一である)および receiver 用に Bitcoin ウォレットを生成する。それぞれ以下を生成する

  • マスター鍵ペア
  • マスター鍵から派生した鍵ペア(派生パスは DERIVE_PATH で定義)
  • 派生した鍵ペアから生成した Bitcoin アドレス

BDK のデフォルトのワーキングディレクトリを削除しておく必要がある。

$ rm -fr ~/.bdk-bitcoin/{issuer,receiver}

issuer/sender 用のマスター鍵ペア、マスター鍵から派生した鍵ペアの生成。

$ bdk key generate
{
"fingerprint": "f0691809",
"mnemonic": "picnic mirror short notice engage minor lizard task noble behind history thrive coconut stable dismiss text layer ski frown fog chaos regular beef convince",
"xprv": "tprv8ZgxMBicQKsPdEdsR3deDJyGA1Pc34zMu9HRCfWuY42ooQCiYn24H1jJCk7wsxgxW6nDPVmfFmTw6DU4BdFXpLcnUaZ4x4GiipXbMzCCCDJ"
}
$ xprv_0="tprv8ZgxMBicQKsPdEdsR3deDJyGA1Pc34zMu9HRCfWuY42ooQCiYn24H1jJCk7wsxgxW6nDPVmfFmTw6DU4BdFXpLcnUaZ4x4GiipXbMzCCCDJ"
$ bdk key derive -p "$DERIVE_PATH" -x "$xprv_0"
{
"xprv": "[f0691809/86'/1'/0'/9]tprv8hmhsMtPRFTzCcA9qxqKzHrVFxjC64daRL2ThdUhgEo6UQatVSeBuEnoNqqRAB7JZYj4S5qcUnUf1S1o26nrvQeevRPQ1Dqm255T9pTMXzi/*",
"xpub": "[f0691809/86'/1'/0'/9]tpubDETk1mvdZd9f65BwjcVvPhWbpzF8FPpUzddEz9X16WbVJtqf7qTn5jQfYyUGCQUD7u1cUpwXqpX4bADA5NLvk7xBzjyRVBsNUbYmtJZaDfK/*"
}
$ xprv_der_0="[f0691809/86'/1'/0'/9]tprv8hmhsMtPRFTzCcA9qxqKzHrVFxjC64daRL2ThdUhgEo6UQatVSeBuEnoNqqRAB7JZYj4S5qcUnUf1S1o26nrvQeevRPQ1Dqm255T9pTMXzi/*"
$ xpub_der_0="[f0691809/86'/1'/0'/9]tpubDETk1mvdZd9f65BwjcVvPhWbpzF8FPpUzddEz9X16WbVJtqf7qTn5jQfYyUGCQUD7u1cUpwXqpX4bADA5NLvk7xBzjyRVBsNUbYmtJZaDfK/*"

同様に、receiver 用のマスター鍵ペア、マスター鍵から派生した鍵ペアの生成。

$ bdk key generate
{
"fingerprint": "0dd6a3dc",
"mnemonic": "sorry express prevent need result cruel fine coconut half hollow service good work aunt suit honey blur buddy danger scrap way crystal wall riot",
"xprv": "tprv8ZgxMBicQKsPd3Hz9Phd6ixMxWa1jWfpmPGPWx2YmvZAgn8at2UJiLzLwHf73ps7TUHcUQcfBMNvxUp5bEMfSMC8zN6MRKGTsAJxrhLFzcn"
}
$ xprv_1="tprv8ZgxMBicQKsPd3Hz9Phd6ixMxWa1jWfpmPGPWx2YmvZAgn8at2UJiLzLwHf73ps7TUHcUQcfBMNvxUp5bEMfSMC8zN6MRKGTsAJxrhLFzcn"
$ bdk key derive -p "$DERIVE_PATH" -x "$xprv_1"
{
"xprv": "[0dd6a3dc/86'/1'/0'/9]tprv8iHVDsqD9jD6TRePGGB8VFC9vHMp2Q1WYApj8NzgZb2tGRSrzqBjE241WvkKti9YT5fwt5LZZ6f4df5f4LdNnbzLfbYhEEn8VSaQ7rJoeb1/*",
"xpub": "[0dd6a3dc/86'/1'/0'/9]tpubDEyXNHsTJ6tmLtgB9uqiterGVJskBjCR7URWQu2yyrqH6uhddE1KQWfsh4gYG2f5LP51LopLsaEyZ5e44UAtmMBTo3gioQjtRRqA5w3HVZN/*"
}
$ xprv_der_1="[0dd6a3dc/86'/1'/0'/9]tprv8iHVDsqD9jD6TRePGGB8VFC9vHMp2Q1WYApj8NzgZb2tGRSrzqBjE241WvkKti9YT5fwt5LZZ6f4df5f4LdNnbzLfbYhEEn8VSaQ7rJoeb1/*"
$ xpub_der_1="[0dd6a3dc/86'/1'/0'/9]tpubDEyXNHsTJ6tmLtgB9uqiterGVJskBjCR7URWQu2yyrqH6uhddE1KQWfsh4gYG2f5LP51LopLsaEyZ5e44UAtmMBTo3gioQjtRRqA5w3HVZN/*"

issuer/sender 用のウォレットにアセット発行用、およびアセットのお釣り受信用のための Bitcoin アドレスをそれぞれ生成する。

$ bdk -n regtest wallet -w issuer -d "$DESC_TYPE($xpub_der_0)" get_new_address
{
"address": "bcrt1q4sfcr4llr9rrxsx53czx8kn7tsqs2lp85rmjj6"
}
$ addr_issue="bcrt1q4sfcr4llr9rrxsx53czx8kn7tsqs2lp85rmjj6"
$ bdk -n regtest wallet -w issuer -d "$DESC_TYPE($xpub_der_0)" get_new_address
{
"address": "bcrt1qndrr80z5d7v0p490nstszz7fxc0dlrx6yw6tvk"
}
$ addr_change="bcrt1qndrr80z5d7v0p490nstszz7fxc0dlrx6yw6tvk"

receiver 用のウォレットにアセット受信用のための Bitcoin アドレスを生成する。

$ bdk -n regtest wallet -w receiver -d "$DESC_TYPE($xpub_der_1)" get_new_address
{
"address": "bcrt1qstx6x794yxc9uny75hawjf5yflplgc6nyaslv5"
}
$ addr_receive="bcrt1qstx6x794yxc9uny75hawjf5yflplgc6nyaslv5"

Bitcoin ウォレットに Bitcoin を入金する

issuer/sender のアセット発行用アドレス(addr_issue)と、receiver のアセット受信用アドレス(addr_receive)にマイナーから 1 BTC 送信しておく。送信を確定するために1ブロック生成する。

$ bcli -rpcwallet=miner sendtoaddress "$addr_issue" 1
a03cc554e75471a10c31036136a2457d6f1678eddf0fd8d83cd6a81621bd958b
$ bcli -rpcwallet=miner sendtoaddress "$addr_receive" 1
9bab29bcb95fb96ecd56126f04d1ae2b0af120c3fbcc937c463fc7e0e544aa81
$ bcli -rpcwallet=miner -generate 1
{
"address": "bcrt1qgkdws864e4h92exkccyj083pm2fe03ecz888a0",
"blocks": [
"392bda99afb0c7de1c6934359743960fb1c555fc835f1f84608c352f30494f79"
]
}

それぞれのウォレットの状態をブロックチェーン(bitcoind)と同期する。

$ bdk -n regtest wallet -w issuer -d "$DESC_TYPE($xpub_der_0)" -s "$ELECTRUM" sync
{}
$ bdk -n regtest wallet -w receiver -d "$DESC_TYPE($xpub_der_1)" -s "$ELECTRUM" sync
{}

それぞれのトランザクションの新たな UTXO(outpoint)を環境変数に設定しておく。

$ bdk -n regtest wallet -w issuer -d "$DESC_TYPE($xpub_der_0)" list_unspent
[
{
"is_spent": false,
"keychain": "External",
"outpoint": "a03cc554e75471a10c31036136a2457d6f1678eddf0fd8d83cd6a81621bd958b:0",
"txout": {
"script_pubkey": "0014ac1381d7ff19463340d48e0463da7e5c01057c27",
"value": 100000000
}
}
]
$ outpoint_issue="0014ac1381d7ff19463340d48e0463da7e5c01057c27"
$ bdk -n regtest wallet -w receiver -d "$DESC_TYPE($xpub_der_1)" list_unspent
[
{
"is_spent": false,
"keychain": "External",
"outpoint": "9bab29bcb95fb96ecd56126f04d1ae2b0af120c3fbcc937c463fc7e0e544aa81:0",
"txout": {
"script_pubkey": "001482cda378b521b05e4c9ea5fae926844fc3f46353",
"value": 100000000
}
}
]
$ outpoint_receive="9bab29bcb95fb96ecd56126f04d1ae2b0af120c3fbcc937c463fc7e0e544aa81:0"

なぜアセットの受信側に Bitcoin が必要か?

なぜ事前に各アドレスに Bitcoin を入金したのか?

アセットの発行、送信を行う側(issuer/sender)は、その状態をブロックに書き込むためにBitcoin トランザクションを生成する必要があり、Bitcoin を持っておく必要があるのは理解できるであろう。それではアセットの受信側(receiver)はなぜ事前に Bitcoin を持っておく必要があるのか?

RGB の従う Single-use seals のコンセプトでは、アセットを送信する場合、受信側の Bitcoin UTXO が指定される必要がある。実際にはこの UTXO はプライバシーのため送信側には暗号学的に隠蔽されて渡されるが。この UTXO を消費することができる主体のみが受信したアセットを再送信できる。

RGB クライアントの設定

RGB クライアントをセットアップし、RGB20 のスキーマをインポートする。

issuer/sender 側。

$ rgb0 import rgb-schemata/schemata/NonInflatableAssets.rgb
Stock file not found, creating default stock
Wallet file not found, creating new wallet list
Schema urn:lnp-bp:sc:BEiLYE-am9WhTW1-oK8cpvw4-FEMtzMrf-mKocuGZn-qWK6YF#ginger-parking-nirvana imported to the stash
$ rgb0 import rgb-schemata/schemata/NonInflatableAssets-RGB20.rgb
Implementation urn:lnp-bp:im:9EUGHC-wpuiyrQE-NdPBVyiv-VX4sVRBs-9yKfteug-HtqnGb#titanic-easy-citizen of interface urn:lnp-bp:if:48hc4i-m9JRcYQA-uUSzwFCK-VNEa9eZf-nhepU8QJ-pqosXS#laptop-domingo-cool for schema urn:lnp-bp:sc:BEiLYE-am9WhTW1-oK8cpvw4-FEMtzMrf-mKocuGZn-qWK6YF#ginger-parking-nirvana imported to the stash

receiver 側。

$ rgb1 import rgb-schemata/schemata/NonInflatableAssets.rgb
Stock file not found, creating default stock
Wallet file not found, creating new wallet list
Schema urn:lnp-bp:sc:BEiLYE-am9WhTW1-oK8cpvw4-FEMtzMrf-mKocuGZn-qWK6YF#ginger-parking-nirvana imported to the stash
$ rgb1 import rgb-schemata/schemata/NonInflatableAssets-RGB20.rgb
Implementation urn:lnp-bp:im:9EUGHC-wpuiyrQE-NdPBVyiv-VX4sVRBs-9yKfteug-HtqnGb#titanic-easy-citizen of interface urn:lnp-bp:if:48hc4i-m9JRcYQA-uUSzwFCK-VNEa9eZf-nhepU8QJ-pqosXS#laptop-domingo-cool for schema urn:lnp-bp:sc:BEiLYE-am9WhTW1-oK8cpvw4-FEMtzMrf-mKocuGZn-qWK6YF#ginger-parking-nirvana imported to the stash

スキーマ ID を取得し、それを環境変数に設定しておく。

$ rgb0 schemata
urn:lnp-bp:sc:BEiLYE-am9WhTW1-oK8cpvw4-FEMtzMrf-mKocuGZn-qWK6YF#ginger-parking-nirvana RGB20
$ schema="urn:lnp-bp:sc:BEiLYE-am9WhTW1-oK8cpvw4-FEMtzMrf-mKocuGZn-qWK6YF#ginger-parking-nirvana"

アセットの発行

まずコントラクト定義ファイルを用意する。

sed \
-e "s/issued_supply/1000/" \
-e "s/created_timestamp/$(date +%s)/" \
-e "s/closing_method/$CLOSING_METHOD/" \
-e "s/txid:vout/$outpoint_issue/" \
contracts/usdt.yaml.template > contracts/usdt.yaml

アセットを 1000 発行し、コントラクト ID を環境変数に設定しておく。

$ rgb0 issue "$schema" "$IFACE" contracts/usdt.yaml
A new contract rgb:BLtBXAT-QEwWBdT3y-EFDfYYgfc-jiGCaNXPS-YnoEtZduq-iYfgVa is issued and added to the stash.
Use `export` command to export the contract.
$ contract_id="rgb:BLtBXAT-QEwWBdT3y-EFDfYYgfc-jiGCaNXPS-YnoEtZduq-iYfgVa"
$ rgb0 contracts
rgb:BLtBXAT-QEwWBdT3y-EFDfYYgfc-jiGCaNXPS-YnoEtZduq-iYfgVa
$ rgb0 state "$contract_id" "$IFACE"
Global:
spec := (naming=(ticker=("USDT"), name=("USD Tether"), details=~), precision=0)
data := (terms=("demo RGB20 asset"), media=~)
issuedSupply := (1000)
created := (1705040430)
Owned:
assetOwner:
amount=1000, utxo=a03cc554e75471a10c31036136a2457d6f1678eddf0fd8d83cd6a81621bd958b:0, witness=~ # owner unknown

アセットの転送

receiver がアセット 100 を受信するための請求書を生成する。請求書にはアセットを受信するための Bitcoin UTXO(outpoint_receive)が含まれていることに注意(ただし隠蔽されている)。

$ rgb1 invoice "$contract_id" "$IFACE" 100 "$CLOSING_METHOD:$outpoint_receive"
rgb:BLtBXAT-QEwWBdT3y-EFDfYYgfc-jiGCaNXPS-YnoEtZduq-iYfgVa/RGB20/100+utxob:7QQCWe4-J4byQq6Yy-PMiKCESi8–36CvYt2Vw-XAyzPZdc8-dACwRz
$ invoice="rgb:BLtBXAT-QEwWBdT3y-EFDfYYgfc-jiGCaNXPS-YnoEtZduq-iYfgVa/RGB20/100+utxob:7QQCWe4-J4byQq6Yy-PMiKCESi8–36CvYt2Vw-XAyzPZdc8-dACwRz"

sender はアセットの転送を行う PSBT(Partially Signed Bitcoin Transaction)を作成し data0/$PSBT に保存する。PSBT はまだ完全な Bitcoin トランザクションではない。

$ bdk -n regtest wallet -w issuer -d "$DESC_TYPE($xpub_der_0)" create_tx -f 5 - send_all - utxos "$outpoint_issue" - to "$addr_change:0" - add_string opret
{
"details": {
"confirmation_time": null,
"fee": 630,
"received": 99999370,
"sent": 100000000,
"transaction": null,
"txid": "fccb8d0ff55ad4850c980a00617b914c50c9230edd8ffa031baa7b10e7127dcc"
},
"psbt": "cHNidP8BAGIBAAAAAYuVvSEWqNY82NgP3+14Fm99RaI2YQMxDKFxVOdUxTygAAAAAAD+////Aore9QUAAAAAFgAUm0YzvFRvmPDUr5wXAQvJNh7fjNoAAAAAAAAAAAdqBW9wcmV0aAAAAAABAN4CAAAAAAEBP82Zr/19Ae91dSZlsI4+QmPeX/PLOvlg1NIXPM/wjokAAAAAAP3///8CAOH1BQAAAAAWABSsE4HX/xlGM0DUjgRj2n5cAQV8J/wFECQBAAAAFgAUUmfLAke6lA9OeaITZGmmhJ8Le5cCRzBEAiBiqTAAwx0ssyWoca309OWG+uEIJzqHg38px59i+WArrQIgJcOFRmP5SFJMSexsh6PslUfCL56pK+rIE3YIXk9VyJsBIQI4cABOZChQYxszk5BYK0Wayn7TN7DcXytnijUxS9y/aGcAAAABAR8A4fUFAAAAABYAFKwTgdf/GUYzQNSOBGPaflwBBXwnIgYCZU5FdajH25AGZTP1cVeKu0VOfS2xeprkIl5D2LtihBEY8GkYCVYAAIABAACAAAAAgAkAAAAAAAAAACICA42LVQtVBvyt6mGCYi0bOfr6U4DAud5imvgvraYGI8I1GPBpGAlWAACAAQAAgAAAAIAJAAAAAQAAAAAA"
}
$ echo "cHNidP8BAGIBAAAAAYuVvSEWqNY82NgP3+14Fm99RaI2YQMxDKFxVOdUxTygAAAAAAD+////Aore9QUAAAAAFgAUm0YzvFRvmPDUr5wXAQvJNh7fjNoAAAAAAAAAAAdqBW9wcmV0aAAAAAABAN4CAAAAAAEBP82Zr/19Ae91dSZlsI4+QmPeX/PLOvlg1NIXPM/wjokAAAAAAP3///8CAOH1BQAAAAAWABSsE4HX/xlGM0DUjgRj2n5cAQV8J/wFECQBAAAAFgAUUmfLAke6lA9OeaITZGmmhJ8Le5cCRzBEAiBiqTAAwx0ssyWoca309OWG+uEIJzqHg38px59i+WArrQIgJcOFRmP5SFJMSexsh6PslUfCL56pK+rIE3YIXk9VyJsBIQI4cABOZChQYxszk5BYK0Wayn7TN7DcXytnijUxS9y/aGcAAAABAR8A4fUFAAAAABYAFKwTgdf/GUYzQNSOBGPaflwBBXwnIgYCZU5FdajH25AGZTP1cVeKu0VOfS2xeprkIl5D2LtihBEY8GkYCVYAAIABAACAAAAAgAkAAAAAAAAAACICA42LVQtVBvyt6mGCYi0bOfr6U4DAud5imvgvraYGI8I1GPBpGAlWAACAAQAAgAAAAIAJAAAAAQAAAAAA" | base64 -d > "data0/$PSBT"

PSBT に commitment host (OP_RETURN commitment)を設定する。commitment host は RGB のデータが Bitcoin トランザクション出力にどのように埋め込まれているかを示す。

$ rgb0 set-host - method "$CLOSING_METHOD" "data0/$PSBT"
PSBT file 'data0/tx.psbt' is updated with opret1st host now set.

PSBT と請求書を提供して転送を作成する(まだトランザクションはブロードキャストされていない)。これにより、consignment が生成される。Bitcoin トランザクション出力には RGB の状態遷移を表現する完全なデータが含まれるのではなく、その暗号学的ハッシュ値のみが含まれる。状態遷移を検証するためには別途 consignment が必要になる。以下の consignment.inspect をエディタで開くと consignment の内容を確認することができる。

​​$ rgb0 transfer - method "$CLOSING_METHOD" "data0/$PSBT" "$invoice" "data0/$CONSIGNMENT"
Transfer is created and saved into 'data0/consignment.rgb'.
PSBT file 'data0/tx.psbt' is updated with all required commitments and ready to be signed.
Stash data are updated.
$ rgb0 inspect "data0/$CONSIGNMENT" > consignment.inspect

ピア間(sender、receiver)の consignment 受け渡しはここでは単純にファイルをコピーすることによって行うが実際のシナリオでは RGB proxy server などを介して行う必要がある。

​​$ cp data{0,1}/"$CONSIGNMENT"

receiver は転送を検証することができる。しかしまだトランザクションはブロードキャストされていないのでマイニングされていない。

$ rgb1 validate "data1/$CONSIGNMENT"
Consignment has non-mined terminal(s)
Non-mined terminals:
- dd16026a59d0158df88ff787c958df543ffb77661b2106c0fa09f5f645fd821d
Validation warnings:
- terminal witness transaction dd16026a59d0158df88ff787c958df543ffb77661b2106c0fa09f5f645fd821d is not yet mined.

sender がトランザクションに署名してブロードキャストする。macOS では base64 コマンドがエラーになるのでオプションを -w0 から -i に変更する。

$ bdk -n regtest wallet -w issuer -d "$DESC_TYPE($xprv_der_0)" sign - psbt $(base64 -w0 "data0/$PSBT")
base64: invalid option - w
Usage: base64 [-Ddh] [-b num] [-i in_file] [-o out_file]
-b, - break break encoded string into num character lines
-Dd, - decode decodes input
-h, - help display this message
-i, - input input file (default: "-" for stdin)
-o, - output output file (default: "-" for stdout)
error: The argument ' - psbt <BASE64_PSBT>' requires a value but none was supplied
For more information try - help
$ bdk -n regtest wallet -w issuer -d "$DESC_TYPE($xprv_der_0)" sign - psbt $(base64 -i "data0/$PSBT")
{
"is_finalized": true,
"psbt": "cHNidP8BAH0BAAAAAYuVvSEWqNY82NgP3+14Fm99RaI2YQMxDKFxVOdUxTygAAAAAAD+////Aore9QUAAAAAFgAUm0YzvFRvmPDUr5wXAQvJNh7fjNoAAAAAAAAAACJqIBbkFFUkewef0u8EFClQ6rW7x2KvBZ+I7r9yimSjG1lYaAAAACb8A1JHQgH9hiGkYJbzXZOwdqfwoeVDLjMlktZPn4FT3XalLitqYtYAABd8DlyFdl5XyeYyb3/Z725gn/sdxVvjUn1WP/tfWZfKECcAAAABF3wOXIV2XlfJ5jJvf9nvbmCf+x3FW+NSfVY/+19Zl8qgDwAAAAGgDwECAAIOijEYSJZt8SpkRhvsyXq7cITYkbMyHlkE8lnnVPNpCQhkAAAAAAAAAHPkFH6fJr0MzfiF4p7PcakvAveqkJhkC+iYeGrWVdeDAwAAAAAAAK2pAAtm3jBECIQDAAAAAAAAKOcnvKZoDro7JdraMQ9404QY+DJ868Ed9QRAHcpRi/YAAAEA3gIAAAAAAQE/zZmv/X0B73V1JmWwjj5CY95f88s6+WDU0hc8z/COiQAAAAAA/f///wIA4fUFAAAAABYAFKwTgdf/GUYzQNSOBGPaflwBBXwn/AUQJAEAAAAWABRSZ8sCR7qUD055ohNkaaaEnwt7lwJHMEQCIGKpMADDHSyzJahxrfT05Yb64QgnOoeDfynHn2L5YCutAiAlw4VGY/lIUkxJ7GyHo+yVR8Ivnqkr6sgTdgheT1XImwEhAjhwAE5kKFBjGzOTkFgrRZrKftM3sNxfK2eKNTFL3L9oZwAAAAEBHwDh9QUAAAAAFgAUrBOB1/8ZRjNA1I4EY9p+XAEFfCciBgJlTkV1qMfbkAZlM/VxV4q7RU59LbF6muQiXkPYu2KEERjwaRgJVgAAgAEAAIAAAACACQAAAAAAAAABBwABCGsCRzBEAiBPdeodx3IyxL/+3e8gKq+RwNXdyuGskHDwA7iMJ77zXgIgINpS4zVEc4IoH8WcnBCrQ5bS1l+qlRUjFKdYTPUPh6MBIQJlTkV1qMfbkAZlM/VxV4q7RU59LbF6muQiXkPYu2KEESb8A1JHQgMXfA5chXZeV8nmMm9/2e9uYJ/7HcVb41J9Vj/7X1mXyiD9hiGkYJbzXZOwdqfwoeVDLjMlktZPn4FT3XalLitqYgAiAgONi1ULVQb8rephgmItGzn6+lOAwLneYpr4L62mBiPCNRjwaRgJVgAAgAEAAIAAAACACQAAAAEAAAAAKfwGTE5QQlA0ABd8DlyFdl5XyeYyb3/Z725gn/sdxVvjUn1WP/tfWZfKIHBmA1AJa7+EzOGnG+0HCNHq/8KWSaZfdDC01tbFliplCfwGTE5QQlA0AQhrIAx8E2G5BAj8BU9QUkVUAAAI/AVPUFJFVAEgFuQUVSR7B5/S7wQUKVDqtbvHYq8Fn4juv3KKZKMbWVgA"
}
$ bdk -n regtest wallet -w issuer -d "$DESC_TYPE($xpub_der_0)" -s "$ELECTRUM" broadcast - psbt "$psbt_signed"
{
"txid": "dd16026a59d0158df88ff787c958df543ffb77661b2106c0fa09f5f645fd821d"
}

アセット転送の確認

トランザクションを確定させるため1ブロック生成する。

$ bcli -rpcwallet=miner -generate 1
{
"address": "bcrt1qywmx098pamjvl2wupl3ltyqnwglytsw9aw84q4",
"blocks": [
"33091aa9354eefe834a56b9bb0aaacee31f6b0f524818bb2423b5cf6228a43ec"
]
}

receiver はアセットの転送を受け入れる。consignment が検証され、receiver のoutpoint_receive(”9bab29bcb95fb96ecd56126f04d1ae2b0af120c3fbcc937c463fc7e0e544aa81:0")にアセットが 100 含まれることが確認できる。

$ rgb1 accept "data1/$CONSIGNMENT"
Consignment is valid
Transfer accepted into the stash
$ rgb1 state "$contract_id" "$IFACE"
Global:
spec := (naming=(ticker=("USDT"), name=("USD Tether"), details=~), precision=0)
data := (terms=("demo RGB20 asset"), media=~)
issuedSupply := (1000)
created := (1705040430)
Owned:
assetOwner:
amount=1000, utxo=a03cc554e75471a10c31036136a2457d6f1678eddf0fd8d83cd6a81621bd958b:0, witness=~ # owner unknown
amount=100, utxo=9bab29bcb95fb96ecd56126f04d1ae2b0af120c3fbcc937c463fc7e0e544aa81:0, witness=dd16026a59d0158df88ff787c958df543ffb77661b2106c0fa09f5f645fd821d # owner unknown
amount=900, utxo=dd16026a59d0158df88ff787c958df543ffb77661b2106c0fa09f5f645fd821d:0, witness=dd16026a59d0158df88ff787c958df543ffb77661b2106c0fa09f5f645fd821d # owner unknown

sender 側では転送トランザクションの新しい出力(”dd16026a59d0158df88ff787c958df543ffb77661b2106c0fa09f5f645fd821d:0”)にお釣りのアセットが 900 含まれることがわかる。sender 側の表示では送信した 100 は含まれない。receiver 側の outpoint_receive は隠蔽されて渡されるため、sender は送信先の情報を見ることができない。

$ rgb0 state "$contract_id" "$IFACE"
Global:
spec := (naming=(ticker=("USDT"), name=("USD Tether"), details=~), precision=0)
data := (terms=("demo RGB20 asset"), media=~)
issuedSupply := (1000)
created := (1705040430)
Owned:
assetOwner:
amount=1000, utxo=a03cc554e75471a10c31036136a2457d6f1678eddf0fd8d83cd6a81621bd958b:0, witness=~ # owner unknown
amount=900, utxo=dd16026a59d0158df88ff787c958df543ffb77661b2106c0fa09f5f645fd821d:0, witness=dd16026a59d0158df88ff787c958df543ffb77661b2106c0fa09f5f645fd821d # owner unknown

環境の削除

最後に、サービスを終了しワーキングディレクトリを削除する。

$ docker compose down
$ rm -fr data{0,1,core,index}

--

--