From 38f9be1e432aebfcc0f43f53020a3d5dfd739f26 Mon Sep 17 00:00:00 2001 From: Nadav Ivgi Date: Mon, 29 May 2023 22:05:16 +0300 Subject: [PATCH 1/2] Update and reorganize documentation - Add registry specification based on https://gist.github.com/shesek/94ae7774906107c2369d3c577a0d70c3 - Move CLI docs to separate document --- README.md | 70 +++----------------------------------- doc/cli.md | 67 ++++++++++++++++++++++++++++++++++++ doc/specs.md | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+), 65 deletions(-) create mode 100644 doc/cli.md create mode 100644 doc/specs.md diff --git a/README.md b/README.md index 014da61..a5af598 100644 --- a/README.md +++ b/README.md @@ -1,71 +1,11 @@ # Liquid Asset Registry -## Running the server +## Documentation: -``` -$ cargo run --features 'cli server' --bin server -- -vv --db-path /path/to/db --addr 127.0.0.1:3000 --esplora-url https://blockstream.info/liquid/api/ -``` - -## Using the CLI -```basg -$ cargo run --bin liquid-asset-registry -- --help - -asset_registry 0.1.0 - -USAGE: - liquid-asset-registry [FLAGS] - -FLAGS: - -h, --help Prints help information - -V, --version Prints version information - -v, --verbose Increase verbosity (up to 3 times) - -SUBCOMMANDS: - contract-json print contract json in canonical serialization (sorted) - help Prints this message or the help of the given subcommand(s) - register-asset Send asset to registry - verify-asset Verify asset associations -``` - -Or build the executable: -``` -$ cargo build --release -$ ./target/release/liquid-asset-registry --help -``` - -### Registering an asset - -Get your contract hash: -``` -$ liquid-asset-registry contract-json --hash '{"version":0,"issuer_pubkey":"","name":"Foo Coin","ticker":"FOO",precision:2,"entity":{"domain":"mydomain.com"}}' -025d983cc774da665f412ccc6ccf51cb017671c2cb0d3c32d10d50ffdf0a57de -``` - -(You may also run `contract-json` without `--hash` to only canonicalize the JSON with lexicographically sorted keys, -then hash it yourself -- as a single SHA-256, but with *its bytes reversed*.) - -Issue the asset on liquid using `rawissueasset` with your hash as the `contract_hash` parameter, -wait for the issuance transaction to confirm, then submit the asset to the registry: - -``` -$ liquid-asset-registry register-asset --asset-id --contract -``` +- [Asset registry specification](doc/specs.md) -### Verifying an asset +- [Using the Rust CLI (`liquid-asset-registry`)](doc/cli.md) -Verifies that the contract json is committed in the issuance transaction, -that that issuance transaction was confirmed, -and the domain ownership proof. - -``` -$ liquid-asset-registry verify-asset '' '' .. -``` - -For example: -``` -$ curl https://assets.blockstream.info/ > asset.json -$ liquid-asset-registry verify-asset "$(cat asset.json)" -``` ## Testing @@ -77,9 +17,9 @@ $ cargo +nightly test --features 'cli server client' -- --test-threads 1 ## Development -You may enable the `dev` feature to have domain proofs checked against +You may enable the `dev` feature to have domain proofs checked against a local server running at `http://127.0.0.1:58712/.well-known/liquid-asset-proof-` -instead of the real server. +instead of the real domain name. Make sure to enable all the features for `cargo check`: diff --git a/doc/cli.md b/doc/cli.md new file mode 100644 index 0000000..8528280 --- /dev/null +++ b/doc/cli.md @@ -0,0 +1,67 @@ +## Asset registry CLI + +```bash +$ cargo run --bin liquid-asset-registry -- --help + +asset_registry 0.1.0 + +USAGE: + liquid-asset-registry [FLAGS] + +FLAGS: + -h, --help Prints help information + -V, --version Prints version information + -v, --verbose Increase verbosity (up to 3 times) + +SUBCOMMANDS: + contract-json print contract json in canonical serialization (sorted) + help Prints this message or the help of the given subcommand(s) + register-asset Send asset to registry + verify-asset Verify asset associations +``` + +Or build the executable: +``` +$ cargo build --release +$ ./target/release/liquid-asset-registry --help +``` + +### Registering an asset + +Get your contract hash: +``` +$ liquid-asset-registry contract-json --hash '{"version":0,"issuer_pubkey":"","name":"Foo Coin","ticker":"FOO",precision:2,"entity":{"domain":"mydomain.com"}}' +025d983cc774da665f412ccc6ccf51cb017671c2cb0d3c32d10d50ffdf0a57de +``` + +(You may also run `contract-json` without `--hash` to only canonicalize the JSON with lexicographically sorted keys, +then hash it yourself -- as a single SHA-256, but with *its bytes reversed*.) + +Issue the asset on liquid using `rawissueasset` with your hash as the `contract_hash` parameter, +wait for the issuance transaction to confirm, then submit the asset to the registry: + +``` +$ liquid-asset-registry register-asset --asset-id --contract +``` + +### Verifying an asset + +Verifies that the contract json is committed in the issuance transaction, +that that issuance transaction was confirmed, +and the domain ownership proof. + +``` +$ liquid-asset-registry verify-asset '' '' .. +``` + +For example: +``` +$ curl https://assets.blockstream.info/ > asset.json +$ liquid-asset-registry verify-asset "$(cat asset.json)" +``` + +## Running the registry server + +``` +$ cargo run --features 'cli server' --bin server -- -vv --db-path /path/to/db --addr 127.0.0.1:3000 --esplora-url https://blockstream.info/liquid/api/ +``` \ No newline at end of file diff --git a/doc/specs.md b/doc/specs.md new file mode 100644 index 0000000..9a56974 --- /dev/null +++ b/doc/specs.md @@ -0,0 +1,95 @@ +## Contract JSON fields + +Required fields: + +- `version`: currently `0` +- `issuer_pubkey`: the hex-encoded public key of the issuer +- `name`: 1-255 ASCII characters +- `entity`: the online entity linked to this asset. currently only supports (sub)domain names in the form of a nested object with `{"domain":"foobar.com"}` + +Optional fields: + +- `ticker`: 3-5 characters consisting of `a-z`, `A-Z`, `.` and `-`. + If provided, has to be unique within the `entity` (domain name) namespace. +- `precision`: number of digits after the decimal point, i.e. 0 for non-divisible assets or 8 for BTC-like. defaults to 0. + +Example: + +```json +{ + "version": 0, + "issuer_pubkey": "037c7db0528e8b7b58e698ac104764f6852d74b5a7335bffcdad0ce799dd7742ec", + "name": "Foo Coin", + "ticker": "FOO", + "entity": { "domain": "foo-coin.com" }, + "precision":8 +} +``` + +## Contract hash + +The contract hash is the (single) sha256 hash of the contract json document, *canonicalized to have its keys sorted lexographically*. + +The canonicalization can be done with Perl like so: `$ perl -e 'use JSON::PP; my $js = JSON::PP->new; $js->canonical(1); print $js->encode($js->decode($ARGV[0]))' '{"version":0,"name":"FOO",...}'` + +Or with Python like so: `$ python -c 'import json,sys; sys.stdout.write(json.dumps(json.loads(sys.argv[1]), sort_keys=True, separators=(",",":")))' '{"version":0,"name":"FOO",...}'` + +Or with JavaScript using the [json-stable-stringify](https://www.npmjs.com/package/json-stable-stringify) library. + +The resulting sha256 hash needs to be reversed to match the format expected by elementsd, similarly to the reverse encoding of txids and blockhashes as originally implemented for bitcoin by satoshi. +This can be done in a unix envirnoment like so: `echo | fold -w2 | tac | tr -d "\n"`. + +All together: + +``` +$ CONTRACT='{"version":0,"ticker":"FOO","name":"Foo Coin"}' +$ CONTRACT_HASH=$(python -c 'import json,sys; sys.stdout.write(json.dumps(json.loads(sys.argv[1]), sort_keys=True, separators=(",",":")))' "$CONTRACT" | sha256sum | head -c64 | fold -w2 | tac | tr -d "\n") +$ echo $CONTRACT_HASH +``` + +This can also be done using the asset registry CLI utility: `$ liquid-asset-registry contract-json --hash ''` + +## Domain ownership proof + +To verify you control the `entity` domain name, you'll need to make a file on your webserver available at `https:///.well-known/liquid-asset-proof-`, with the following contents: + +``` +Authorize linking the domain name to the Liquid asset +``` + +Note that serving the file with `https` is required, except for `.onion` hidden services. + +## Issuing & Registering assets + +Prepare your contract json and get your contract hash. You can verify their validity before issuing the asset using the validation endpoint: + +```bash +$ curl https://assets.blockstream.info/contract/validate -H 'Content-Type: application/json' \ + -d '{"contract": , "contract_hash": ""}' +``` + +If everything seems good, issue the asset using elementsd's `rawissueasset` with your hash as the `contract_hash` parameter and take note of the resulting `asset_id`. Add the domain ownership proof (as described above) and, once the issuance transaction confirms, submit the asset to the registry: + +```bash +$ curl https://assets.blockstream.info/ -H 'Content-Type: application/json' \ + -d '{"asset_id": "", "contract": }' +``` + +This can also be done using the asset registry CLI utility: `$ liquid-asset-registry register-asset --asset-id --contract ` + +## Deleting assets metadata + +Note: deleting an asset only removes its metadata from the registry, not the asset itself. + +To delete an asset, sign the following message using your `issuer_pubkey`: + +``` +remove from registry +``` + +Then submit the deletion request with the base64-encoded signature, like so: + +``` +$ curl -X DELETE https://assets.blockstream.info/ -H 'Content-Type: application/json' \ + -d '{"signature":""}' +``` \ No newline at end of file From cd05b5a8b8f841a59dbb4cf88dd0d4f8c1c0d6e6 Mon Sep 17 00:00:00 2001 From: Nadav Ivgi Date: Mon, 29 May 2023 22:29:10 +0300 Subject: [PATCH 2/2] docs: Update contract fields specification to match latest changes Plus some other small changes and fixups. --- doc/specs.md | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/doc/specs.md b/doc/specs.md index 9a56974..42ed0a0 100644 --- a/doc/specs.md +++ b/doc/specs.md @@ -1,3 +1,7 @@ +# Asset Metadata Registry + +To associate an issued asset with its metadata on the Liquid asset registry, the asset contract JSON must be created in advance and have its hash committed to in the asset issuance transaction. The format for the contract and the issuance process are described below. + ## Contract JSON fields Required fields: @@ -9,9 +13,10 @@ Required fields: Optional fields: -- `ticker`: 3-5 characters consisting of `a-z`, `A-Z`, `.` and `-`. +- `ticker`: 3-24 characters consisting of `a-z`, `A-Z`, `.` and `-`. If provided, has to be unique within the `entity` (domain name) namespace. - `precision`: number of digits after the decimal point, i.e. 0 for non-divisible assets or 8 for BTC-like. defaults to 0. +- `collection`: 1-255 ASCII characters Example: @@ -22,13 +27,13 @@ Example: "name": "Foo Coin", "ticker": "FOO", "entity": { "domain": "foo-coin.com" }, - "precision":8 + "precision": 8 } ``` ## Contract hash -The contract hash is the (single) sha256 hash of the contract json document, *canonicalized to have its keys sorted lexographically*. +The contract hash is the (single) sha256 hash of the contract json document, *canonicalized to have its keys sorted lexicographically*. The canonicalization can be done with Perl like so: `$ perl -e 'use JSON::PP; my $js = JSON::PP->new; $js->canonical(1); print $js->encode($js->decode($ARGV[0]))' '{"version":0,"name":"FOO",...}'` @@ -37,14 +42,15 @@ Or with Python like so: `$ python -c 'import json,sys; sys.stdout.write(json.dum Or with JavaScript using the [json-stable-stringify](https://www.npmjs.com/package/json-stable-stringify) library. The resulting sha256 hash needs to be reversed to match the format expected by elementsd, similarly to the reverse encoding of txids and blockhashes as originally implemented for bitcoin by satoshi. -This can be done in a unix envirnoment like so: `echo | fold -w2 | tac | tr -d "\n"`. +This can be done in a unix environment like so: `echo " | fold -w2 | tac | tr -d "\n"`. All together: ``` $ CONTRACT='{"version":0,"ticker":"FOO","name":"Foo Coin"}' -$ CONTRACT_HASH=$(python -c 'import json,sys; sys.stdout.write(json.dumps(json.loads(sys.argv[1]), sort_keys=True, separators=(",",":")))' "$CONTRACT" | sha256sum | head -c64 | fold -w2 | tac | tr -d "\n") -$ echo $CONTRACT_HASH +$ CONTRACT_HASH=$(python -c 'import json,sys; sys.stdout.write(json.dumps(json.loads(sys.argv[1]), sort_keys=True, separators=(",",":")))' "$CONTRACT" | sha256sum | head -c64) +$ CONTRACT_HASH_REV=$(echo $CONTRACT_HASH | fold -w2 | tac | tr -d "\n") +$ echo $CONTRACT_HASH_REV ``` This can also be done using the asset registry CLI utility: `$ liquid-asset-registry contract-json --hash ''` @@ -68,9 +74,11 @@ $ curl https://assets.blockstream.info/contract/validate -H 'Content-Type: appli -d '{"contract": , "contract_hash": ""}' ``` -If everything seems good, issue the asset using elementsd's `rawissueasset` with your hash as the `contract_hash` parameter and take note of the resulting `asset_id`. Add the domain ownership proof (as described above) and, once the issuance transaction confirms, submit the asset to the registry: +If everything seems good, issue the asset using elementsd's `issueasset` with your hash as the `contract_hash` parameter and take note of the resulting `asset_id`. Add the domain ownership proof (as described above) and, once the issuance transaction confirms, submit the asset to the registry: ```bash +$ elements-cli issueasset 10 0 true $CONTRACT_HASH_REV + $ curl https://assets.blockstream.info/ -H 'Content-Type: application/json' \ -d '{"asset_id": "", "contract": }' ```