-
Notifications
You must be signed in to change notification settings - Fork 36
UDT (sudt) Operations Tutorial
Simple UDT(SUDT) script is a type script, as the RFC25 says UDT only support two operations issue
and transfer
. SUDT can work with any lock script, but in practice SUDT mostly work with anyone-can-pay
and cheque
lock script. The anyone-can-pay
lock let user transfer to a cell with some amount of SUDT without require to unlock the cell. The cheque
lock let user issue or transfer to some address that unneeded to provide the required CKB capacity. More details please see the rfcs of two lock scripts.
In this tutorial we will demonstrate several scenarios:
- Issue some SUDT to a cheque address
- Create a cell with SUDT type script and anyone-can-pay lock script for receiving the SUDT (
empty-sudt-acp
cell) - Claim the SUDT to the new created anyone-can-pay cell
- Create another
empty-sudt-acp
cell with different address - Transfer a part of the claimed SUDT to the new created
empty-sudt-acp
cell
- Create a cell with SUDT type script and anyone-can-pay lock script for receiving the SUDT (
- Issue some SUDT to an anyone-can-pay address
- Transfer some SUDT to a cheque address (for claim)
- Claim the SUDT to an anyone-can-pay address
- Iransfer some SUDT to a cheque address (for withdraw)
- Withdraw the SUDT to an anyone-can-pay address
First we build the contract binaries.
This will build simple_udt and anyone_can_pay:
git clone https://github.com/nervosnetwork/ckb-production-scripts
cd ckb-production-scripts
git checkout e570c11aff3eca12a47237c21598429088c610d5
git submodule update --init --recursive
make all-via-docker
And the binaries are located in build/simple_udt
and build/anyone_can_pay
.
This will build cheque:
cargo install ckb-capsule --version=0.4.3
git clone https://github.com/nervosnetwork/ckb-cheque-script.git
cd ckb-cheque-script
git checkout 4ca3e62ae39c32cfcc061905515a2856cad03fd8
git submodule update --init --recursive
cd contracts/ckb-cheque-script/ckb-lib-secp256k1/ckb-production-scripts
git submodule update --init --recursive
cd .. && make all-via-docker
cd ../../..
capsule build
And the binary is located in build/release/ckb-cheque-script
We will use ckb-cli deploy
subcommand to deploy the contract binaries
# Since the implementation of the subcomand PR is not merged, we will build it from source
git clone -b add-deploy-subcommand https://github.com/TheWaWaR/ckb-cli.git
cd ckb-cli
make prod
ln -s $PWD/target/release/ckb-cli $HOME/.cargo/bin/ckb-cli-deploy
Then we copy the binaries to a direcotry and create a deployment config file.
mkdir -p deploy-files/{contracts,migrations}
cd deploy-files
cp ckb-production-scripts/build/simple_udt ckb-production-scripts/build/anyone_can_pay ckb-cheque-script/build/release/ckb-cheque-script contracts
touch deployment.toml
And the deployment.toml
will be like this:
[[cells]]
name = "cheque_lock"
enable_type_id = true
location = { file = "contracts/ckb-cheque-script" }
[[cells]]
name = "acp_lock"
enable_type_id = true
location = { file = "contracts/anyone_can_pay" }
[[cells]]
name = "simple_udt"
enable_type_id = true
location = { file = "contracts/simple_udt" }
# reference to on-chain cells, this config is referenced by dep_groups.cells
[[cells]]
name = "secp256k1_data"
enable_type_id = false
location = { tx_hash = "<genesis-cellbase-tx-hash>", index = 3 }
# Dep group cells
[[dep_groups]]
name = "cheque_lock_dep"
cells = [
"secp256k1_data",
"cheque_lock"
]
[[dep_groups]]
name = "acp_lock_dep"
cells = [
"secp256k1_data",
"acp_lock"
]
# Replace with your own lock if you want to unlock deployed cells.
# For example the secp256k1 lock
[lock]
code_hash = "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8"
args = "<sighash-address-lock-args>"
hash_type = "type"
# For unlocking inputs with multisig lock script
[multisig_config]
sighash_addresses = [
# "ckt1qyq111111111111111111111111111111111111111",
# "ckt1qyq222222222222222222222222222222222222222",
# "ckt1qyq333333333333333333333333333333333333333",
]
require_first_n = 1
threshold = 2
The genesis-cellbase-tx-hash
can get from ckb-cli util genesis-scripts
in the output's secp256k1_data
field.
The sighash-address-lock-args
the your ckb-cli account id.
Then we run follow command to deploy the binaries:
ckb-cli-deploy deploy gen-txs \
--deployment-config ./deployment.toml \
--migration-dir ./migrations \
--from-address <your-account> \
--info-file ./info.json \
--sign-now
ckb-cli-deploy deploy apply-txs --migration-dir ./migrations --info-file ./info.json
The cell_deps.json
is a config file to tell ckb-cli the script id (code_hash + hash_type) of a type of script so we can build the script by given args, and also the cell_dep
information of the script id. Currently there are only 3 kind of cell_dep are allowed:
-
acp
for anyone-can-pay lock script -
cheque
for cheque lock script -
sudt
for simple udt type script
Below is an example content:
{
"items": {
"cheque": {
"script_id": {
"hash_type": "type",
"code_hash": "0xb62470c53fe232c8120f81bd65d27d7d88f1e2bfd5e493d0219a5afd5be3b962"
},
"cell_dep": {
"out_point": {
"tx_hash": "0x7c444551da09140abf7c8bbb956cea7d3d3feeb9676c29281bb66e505be48e99",
"index": "0x0"
},
"dep_type": "dep_group"
}
},
"acp": {
"script_id": {
"hash_type": "type",
"code_hash": "0x23c28bc9918408180105fdeb173933e8b6bbf200f8e1c286af994e38ba8d3d3e"
},
"cell_dep": {
"out_point": {
"tx_hash": "0x7c444551da09140abf7c8bbb956cea7d3d3feeb9676c29281bb66e505be48e99",
"index": "0x1"
},
"dep_type": "dep_group"
}
},
"sudt": {
"script_id": {
"hash_type": "type",
"code_hash": "0x662e860980e557e3f3b1fb25cf19729bb86fcbb4344f80746843c6712439c5f0"
},
"cell_dep": {
"out_point": {
"tx_hash": "0x0cd76992bbc022a7fd37dc8a1765b106b4b42551bd37c242897bdc2e02350fed",
"index": "0x2"
},
"dep_type": "code"
}
}
}
}
The actual field value should be from deploy-files/migrations/yyyy-mm-dd-xxxx.json
Here we need 3 accounts, one is for SUDT owner
, and the other two is for normal SDUT account.
mkdir /tmp/tmp-ckb-cli-home
export CKB_CLI_HOME=/tmp/tmp-ckb-cli-home
# account owner
ckb-cli account new
address:
testnet: ckt1qyq86vaa6e8tsruv5ngcd5tp7lcvcewxy7cquuksvj
# account 1
ckb-cli account new
address:
testnet: ckt1qyqfjslcvyaay029vvfxtn80rxnwmlma43xscrqn85
# account 2
ckb-cli account new
address:
testnet: ckt1qyq9qaekmruccau7u3eff4wsv8v74gxmlptqj2lcte
Then we transfer some CKB to those addresses.
ckb-cli wallet transfer --from-account <miner-address> --to-address ckt1qyq86vaa6e8tsruv5ngcd5tp7lcvcewxy7cquuksvj --capacity 10000.0
ckb-cli wallet transfer --from-account <miner-address> --to-address ckt1qyqfjslcvyaay029vvfxtn80rxnwmlma43xscrqn85 --capacity 10000.0
ckb-cli wallet transfer --from-account <miner-address> --to-address ckt1qyq9qaekmruccau7u3eff4wsv8v74gxmlptqj2lcte --capacity 10000.0
Issue 2000 SUDT to a cheque address which the sender is the sudt owner and the receiver is account 1.
ckb-cli sudt issue \
--owner ckt1qyq86vaa6e8tsruv5ngcd5tp7lcvcewxy7cquuksvj \
--udt-to ckt1qyqfjslcvyaay029vvfxtn80rxnwmlma43xscrqn85:2000 \
--to-cheque-address \
--cell-deps ./cell_deps.json
The output:
receivers:
- address: ckt1qzmzgux98l3r9jqjp7qm6ewj047c3u0zhl27fy7syxd94l2muwukyqfydu2yhskr8feutg9wdvltwqtf3vey5uy2s8u8hdcakd5me8tesxl5c22f0h37sxs5xgzjg
amount: "2000"
transaction-hash: 0xefe513ae065293c0cce8a962f9c7a0386eaa1d1495e91d93611183dbb1119562
The address is the cheque address. We can use this address to query the amount.
ckb-cli sudt get-amount \
--owner ckt1qyq86vaa6e8tsruv5ngcd5tp7lcvcewxy7cquuksvj \
--address ckt1qzmzgux98l3r9jqjp7qm6ewj047c3u0zhl27fy7syxd94l2muwukyqfydu2yhskr8feutg9wdvltwqtf3vey5uy2s8u8hdcakd5me8tesxl5c22f0h37sxs5xgzjg \
--cell-deps ./cell_deps.json
The output:
cell_count: 1
cells:
- amount: "2000"
out_point:
index: 0x0
tx_hash: 0xefe513ae065293c0cce8a962f9c7a0386eaa1d1495e91d93611183dbb1119562
total_amount: "2000"
Then we create a cell with SUDT type script and anyone-can-pay lock script (account 1) for receiving the SUDT.
ckb-cli sudt new-empty-acp \
--owner ckt1qyq86vaa6e8tsruv5ngcd5tp7lcvcewxy7cquuksvj \
--to ckt1qyqfjslcvyaay029vvfxtn80rxnwmlma43xscrqn85 \
--cell-deps ./cell_deps.json
The output:
acp-address: ckt1qq3u9z7fjxzqsxqpqh77k9eex05tdwljqruwrs5x47v5uw96357nuqveg0uxzw7j84zkxyn9enh3nfhdla76cngw3fvxw
transaction-hash: 0xf6f37d3b777a318326d92b5496f28f6d3a4477554de09885172ff45e9a33ecbc
Query the amount of the new created anyone-can-pay cell.
ckb-cli sudt get-amount \
--owner ckt1qyq86vaa6e8tsruv5ngcd5tp7lcvcewxy7cquuksvj \
--address ckt1qq3u9z7fjxzqsxqpqh77k9eex05tdwljqruwrs5x47v5uw96357nuqveg0uxzw7j84zkxyn9enh3nfhdla76cngw3fvxw \
--cell-deps ./cell_deps.json
The output:
cell_count: 1
cells:
- amount: "0"
out_point:
index: 0x0
tx_hash: 0xf6f37d3b777a318326d92b5496f28f6d3a4477554de09885172ff45e9a33ecbc
total_amount: "0"
Claim the SUDT to the new created anyone-can-pay-cell
ckb-cli sudt cheque-claim \
--owner ckt1qyq86vaa6e8tsruv5ngcd5tp7lcvcewxy7cquuksvj \
--sender ckt1qyq86vaa6e8tsruv5ngcd5tp7lcvcewxy7cquuksvj \
--receiver ckt1qyqfjslcvyaay029vvfxtn80rxnwmlma43xscrqn85 \
--cell-deps ./cell_deps.json
Query the SUDT amount of account 1.
ckb-cli sudt get-amount \
--owner ckt1qyq86vaa6e8tsruv5ngcd5tp7lcvcewxy7cquuksvj \
--address ckt1qq3u9z7fjxzqsxqpqh77k9eex05tdwljqruwrs5x47v5uw96357nuqveg0uxzw7j84zkxyn9enh3nfhdla76cngw3fvxw \
--cell-deps ./cell_deps.json
The output:
cell_count: 1
cells:
- amount: "2000"
out_point:
index: 0x0
tx_hash: 0xf29806ea07769381e20479319611a9717c00a09e1cc3a02cf27a25073efa86f9
total_amount: "2000"
Then we create another anyone-can-pay cell (account 2), the output:
acp-address: ckt1qq3u9z7fjxzqsxqpqh77k9eex05tdwljqruwrs5x47v5uw96357nuq2swumd37vvw70wgu556hgxrk025rdls4sn8j5qk
transaction-hash: 0x11a370d042e79f7b48ce2f25d1306a4af91dc15722568873ce7a4efac8ff604b
Transfer a part of the claimd SUDT to new cell.
ckb-cli sudt transfer \
--owner ckt1qyq86vaa6e8tsruv5ngcd5tp7lcvcewxy7cquuksvj \
--sender ckt1qq3u9z7fjxzqsxqpqh77k9eex05tdwljqruwrs5x47v5uw96357nuqveg0uxzw7j84zkxyn9enh3nfhdla76cngw3fvxw \
--udt-to ckt1qq3u9z7fjxzqsxqpqh77k9eex05tdwljqruwrs5x47v5uw96357nuq2swumd37vvw70wgu556hgxrk025rdls4sn8j5qk:600 \
--to-acp-address \
--cell-deps ./cell_deps.json
Then if we query the two above anyone-can-pay address the amount will be:
- account 1: 1400
- account 2: 600
Issue 300 SUDT to account 1's anyone-can-pay address
ckb-cli sudt issue \
--owner ckt1qyq86vaa6e8tsruv5ngcd5tp7lcvcewxy7cquuksvj \
--udt-to ckt1qq3u9z7fjxzqsxqpqh77k9eex05tdwljqruwrs5x47v5uw96357nuqveg0uxzw7j84zkxyn9enh3nfhdla76cngw3fvxw:300 \
--to-acp-address \
--cell-deps ./cell_deps.json
Then if we query the account 1's amount, it become 1700.
Transfer 500 SUDT from account 1 anyone-can-pay address to account 2 cheque address:
ckb-cli sudt transfer \
--owner ckt1qyq86vaa6e8tsruv5ngcd5tp7lcvcewxy7cquuksvj \
--sender ckt1qq3u9z7fjxzqsxqpqh77k9eex05tdwljqruwrs5x47v5uw96357nuqveg0uxzw7j84zkxyn9enh3nfhdla76cngw3fvxw \
--udt-to ckt1qyq9qaekmruccau7u3eff4wsv8v74gxmlptqj2lcte:500 \
--to-cheque-address \
--cell-deps ./cell_deps.json
Then if we query the two above anyone-can-pay address the amount will be:
- account 1: 1200
- account 2: 600
Claim the SUDT to account 2:
ckb-cli sudt cheque-claim \
--owner ckt1qyq86vaa6e8tsruv5ngcd5tp7lcvcewxy7cquuksvj \
--sender ckt1qyqfjslcvyaay029vvfxtn80rxnwmlma43xscrqn85 \
--receiver ckt1qyq9qaekmruccau7u3eff4wsv8v74gxmlptqj2lcte \
--cell-deps ./cell_deps.json
Query two account's amounts again:
- account 1: 1200
- account 2: 1100
Transfer 500 SUDT from account 1 anyone-can-pay address to account 2 cheque address:
ckb-cli sudt transfer \
--owner ckt1qyq86vaa6e8tsruv5ngcd5tp7lcvcewxy7cquuksvj \
--sender ckt1qq3u9z7fjxzqsxqpqh77k9eex05tdwljqruwrs5x47v5uw96357nuqveg0uxzw7j84zkxyn9enh3nfhdla76cngw3fvxw \
--udt-to ckt1qyq9qaekmruccau7u3eff4wsv8v74gxmlptqj2lcte:500 \
--to-cheque-address \
--cell-deps ./cell_deps.json
Query two account's amounts:
- account 1: 700
- account 2: 1100
Then we will withdraw after 6 epochs (10800 blocks):
# First change ckb-miner.toml miner.workers.value = 1
ckb miner -l 10800
Withdraw the SUDT amount:
ckb-cli sudt cheque-withdraw \
--owner ckt1qyq86vaa6e8tsruv5ngcd5tp7lcvcewxy7cquuksvj \
--sender ckt1qyqfjslcvyaay029vvfxtn80rxnwmlma43xscrqn85 \
--receiver ckt1qyq9qaekmruccau7u3eff4wsv8v74gxmlptqj2lcte \
--to-acp-address \
--cell-deps ./cell_deps.json
Query two account's amounts:
- account 1: 1200
- account 2: 1100