You can create your own CF-20 token in the Cellframe network.
If you want to create token in your own network on Cellframe platfrom, see this manual.
Actions:
This manual will show the process of token creation from declaration to emission.
Declaration
Every token in the Cellframe ecosystem must be declared before emission.
Use Node Command - TOKEN DECL to declare your token.
Command has such parameters:
net
- name of the Cellframe Network
chain
- name of the chain where token was declared
token
- ticker (name) of the token
total_supply
- maximum sum of all token emissions in datoshi
signs_total
- quantity of authorized token signatures
signs_emission
- quantity of authorized token signatures required for its emission, must be lower than signs_emission
value
decimals
- number accuration after comma (18
by default)
certs
- certificates which is used to sign token (you can use any certificate)
Note
In this example, we will use bridge certificates.
Let’s declare the token CRINGE:
Command:
cellframe-node-cli token_decl -net riemann -chain zerochain -token CRINGE -type CF20 -total_supply 10000 -signs_total 2 -signs_emission 2 -decimals 18 -certs riemann.bridge.pvt.0
total_supply 10000
means 10000
datoshi or 0.00000000000001
coin, so usually you have to specify 10000.0e+18
in case you want 10000
coins to be declared.
Despite specifying more than one cert in signs_total
parameter, use just one certificate in this command, you will be able to add remaining certificates using Node Command - TOKEN DECL SIGN.
Response:
code: 0
message: Datum 0x80F32668F798B9A59257344010D08E9D5DF4BBA6FD4855303D27B27D2B754B5E with token CRINGE is placed in datum pool
Sign it with additional cert riemann.bridge.pvt.1
:
Command:
cellframe-node-cli token_decl_sign -net riemann -chain zerochain -datum 0x80F32668F798B9A59257344010D08E9D5DF4BBA6FD4855303D27B27D2B754B5E -certs riemann.bridge.pvt.1
After signing, the hash of the datum will change.
Response:
code: 0
message: Datum was replaced in datum pool:
Old: 0x80F32668F798B9A59257344010D08E9D5DF4BBA6FD4855303D27B27D2B754B5E
New: 0xB2B3D91D0DEA507FE892103140068B6E866EF607D0996814FFC36443FBA909AE
And finally, sign it with remaining cert riemann.bridge.pvt.2
:
Command:
cellframe-node-cli token_decl_sign -net riemann -chain zerochain -datum 0xB2B3D91D0DEA507FE892103140068B6E866EF607D0996814FFC36443FBA909AE -certs riemann.bridge.pvt.2
The hash of the datum has changed again.
Response:
code: 0
message: Datum was replaced in datum pool:
Old: 0xB2B3D91D0DEA507FE892103140068B6E866EF607D0996814FFC36443FBA909AE
New: 0x8C21984193F7BF0746063B3B186F5C1BBB0676282713BC0C5B8D92B2488B8FF4
Now, our datum with token declaration is in the mempool. We have to process it.
Use Node Command - MEMPOOL PROC and the last datum hash as a datum
parameter. In this case - 0x8C21984193F7BF0746063B3B186F5C1BBB0676282713BC0C5B8D92B2488B8FF4
.
Command:
cellframe-node-cli mempool_proc -net riemann -chain zerochain -datum 0x8C21984193F7BF0746063B3B186F5C1BBB0676282713BC0C5B8D92B2488B8FF4
Response:
datum:
hash: 0x8C21984193F7BF0746063B3B186F5C1BBB0676282713BC0C5B8D92B2488B8FF4
type: DATUM_TOKEN
ts_created:
time_stamp: 1743058177
str: Thu, 27 Mar 2025 06:49:37 +0000
data_size: 10226
verify:
isProcessed: true
notice: Removed datum from mempool.
Here is the important info:
verify:
isProcessed: true
notice: Removed datum from mempool.
We have processed the datum, in the next few minutes it will be in the zerochain.
We can now get some information about our newly created token using Node Command - TOKEN INFO.
Command:
cellframe-node-cli token info -net riemann -name CRINGE
Response:
TOKENS:
CRINGE:
current state:
-->Token name: CRINGE
type: CF20
flags: NONE
description: The token description is not set
Supply current: 10000
Supply total: 10000
Decimals: 18
Auth signs valid: 2
Auth signs total: 3
Signatures public keys:
line: 0
hash: 0xE7D0E94E6792FE145A9691ECDFECA151BC1C7477C3E11979DA48E5752C14A2E1
pkey_type: DAP_PKEY_TYPE_SIGN_DILITHIUM
bytes: 1196
line: 1
hash: 0x0A57D6D1F3E72E9F2D1DDA6E6089AFEB0AADB953FB347E08C7B6575D65FA6D56
pkey_type: DAP_PKEY_TYPE_SIGN_DILITHIUM
bytes: 1196
line: 2
hash: 0x18A38ACF46876226F9AC130427870814503C19B00185A85F034DDC2058D699C1
pkey_type: DAP_PKEY_TYPE_SIGN_DILITHIUM
bytes: 1196
Total emissions: 0
declarations:
status: ACCEPTED
Ledger return code: 0
Datum:
=== Datum Token Declaration ===:
hash: 0x8C21984193F7BF0746063B3B186F5C1BBB0676282713BC0C5B8D92B2488B8FF4
ticker: CRINGE
size: 10226
version: 2
type: DECL
subtype: CF20
decimals: 18
auth signs valid: 2
auth signs total: 3
total_supply: 10000
flags: NONE
Signatures:
status:
line: 1
hash: 0xE7D0E94E6792FE145A9691ECDFECA151BC1C7477C3E11979DA48E5752C14A2E1
sign_type: sig_dil
bytes: 2096
line: 2
hash: 0x0A57D6D1F3E72E9F2D1DDA6E6089AFEB0AADB953FB347E08C7B6575D65FA6D56
sign_type: sig_dil
bytes: 2096
line: 3
hash: 0x18A38ACF46876226F9AC130427870814503C19B00185A85F034DDC2058D699C1
sign_type: sig_dil
bytes: 2096
updates:
On the top of the dump is current state description, below goes declarations and then updates, for now updates are empty.
You can emit your token after declaration, but in case you want to change something about it, improve safety, increase total supply, add description, etc, you must update your token.
But in case you want to emit your token immediately, go here.
Updating
Token updating allows the user to fine tune the token.
It is provided by Node Command - TOKEN UPDATE.
Command parameters:
-net - name of the Cellframe Network. The list of networks can be found in the <Config_dir> \ etc \ network folder or received by The Cellframe-Node-CLI using command - net list
-chain - name of the chain where token was declared (optional)
-token - ticker (name) of the token
-type - type of the token (CF20 or private, CF20 by default)
-total_supply_change - changes total supply, specify “INF” to set unlimited total supply (optional)
-certs - list of certificates which were used to sign token
-flag_set - list of flags are being set (optional)
-flag_unset - list of flags are being unset (optional)
-total_signs_valid - sets the minimum amount of valid signatures (optional)
-description - token description written in " " (optional)
-tx_receiver_allowed - adds specified wallet address to the list of allowed receivers (optional)
-tx_receiver_blocked - adds specified wallet address to the list of blocked receivers (optional)
-tx_sender_allowed - adds specified wallet address to the list of allowed senders (optional)
-tx_sender_blocked - adds specified wallet address to the list of blocked senders (optional)
-add_cert - adds certificates to the certificates list of the token (optional)
-remove_certs - removes certificates from the certificates list using theirs public key hash (optional)
Available flags:
ALL_BLOCKED: Blocks all permissions.
ALL_ALLOWED: Allows all permissions unless they are blocked. Be careful with this mode.
ALL_FROZEN: Temporarily freezes all permissions
ALL_UNFROZEN: Unfreezes all frozen permissions
STATIC_ALL: Blocks manipulations with a token after declaration. Tokens are declared statically.
STATIC_FLAGS: Blocks manipulations with token flags after declaration.
STATIC_PERMISSIONS_ALL: Blocks all manipulations with permissions list after declaration.
STATIC_PERMISSIONS_DATUM_TYPE: Blocks all manipulations with datum permissions list after declaration.
STATIC_PERMISSIONS_TX_SENDER: Blocks all manipulations with transaction senders permissions list after declaration.
STATIC_PERMISSIONS_TX_RECEIVER: Blocks all manipulations with transaction receivers permissions list after declaration.
What do we want to modify?
Example
For example, we need to increase
total_supply
by5000
and restrict all actions withflags
using flagSTATIC_FLAGS
, after that, we can inform users about this update by changing tokendescription
.
Paste all these parameters in the command.
Command:
cellframe-node-cli token_update -net riemann -chain zerochain -token CRINGE -type CF20 -total_supply_change 15000 -certs riemann.bridge.pvt.0 -flag_set STATIC_FLAGS -description "Updated: total supply increased on 5000 and the flags were set as STATIC"
Response:
code: 0
message: Datum 0xF48B60D3C829D1F6280781862B9EB87ED36729E6AD75D35604053A3D0D81A4AB with token update for ticker CRINGE is placed in datum pool
This message indicates that the CRINGE was successfully updated.
Now let’s sign it with 2 more signatures.
Command:
cellframe-node-cli token_update_sign -net riemann -chain zerochain -datum 0xF48B60D3C829D1F6280781862B9EB87ED36729E6AD75D35604053A3D0D81A4AB -certs riemann.bridge.pvt.1
First one.
Response:
code: 0
message: Datum was replaced in datum pool:
Old: 0xF48B60D3C829D1F6280781862B9EB87ED36729E6AD75D35604053A3D0D81A4AB
New: 0x549730A5830CFE1EDA983B36CDA935D84B64A9977BB649F20E27938F48BA2432
Command:
cellframe-node-cli token_update_sign -net riemann -chain zerochain -datum 0x549730A5830CFE1EDA983B36CDA935D84B64A9977BB649F20E27938F48BA243 -certs riemann.bridge.pvt.2
And the second one.
Response:
code: 0
message: Datum was replaced in datum pool:
Old: 0x549730A5830CFE1EDA983B36CDA935D84B64A9977BB649F20E27938F48BA2432
New: 0x562FB0177E71EE299532467A937E181CB409714864FBC8620590CF0E62CA22C0
As it was with the declaration datum, we have to proccess updating datum too.
Command:
cellframe-node-cli mempool_proc -net riemann -chain zerochain -datum 0xD6B95071CFC459965DA8E0B35423D85A3D78B01B41C897B1E1F3F115406C8CDD
Response:
datum:
hash: 0xD6B95071CFC459965DA8E0B35423D85A3D78B01B41C897B1E1F3F115406C8CDD
type: DATUM_TOKEN
ts_created:
time_stamp: 1743069545
str: Thu, 27 Mar 2025 09:59:05 +0000
data_size: 10287
verify:
isProcessed: true
notice: Removed datum from mempool.
The datum was processed.
How token looks now:
Command:
cellframe-node-cli token info -net riemann -name CRINGE
Now the token dump contains information about declaration and all updates which led to its current state which is shown on the top.
Response:
TOKENS:
CRINGE:
current state:
-->Token name: CRINGE
type: CF20
flags:
STATIC_FLAGS
description: Updated: total supply increased on 5000 and the flags were set as STATIC
Supply current: 15000
Supply total: 15000
Decimals: 18
Auth signs valid: 2
Auth signs total: 3
Signatures public keys:
line: 0
hash: 0xE7D0E94E6792FE145A9691ECDFECA151BC1C7477C3E11979DA48E5752C14A2E1
pkey_type: DAP_PKEY_TYPE_SIGN_DILITHIUM
bytes: 1196
line: 1
hash: 0x0A57D6D1F3E72E9F2D1DDA6E6089AFEB0AADB953FB347E08C7B6575D65FA6D56
pkey_type: DAP_PKEY_TYPE_SIGN_DILITHIUM
bytes: 1196
line: 2
hash: 0x18A38ACF46876226F9AC130427870814503C19B00185A85F034DDC2058D699C1
pkey_type: DAP_PKEY_TYPE_SIGN_DILITHIUM
bytes: 1196
Total emissions: 0
declarations:
status: ACCEPTED
Ledger return code: 0
Datum:
=== Datum Token Declaration ===:
hash: 0x8C21984193F7BF0746063B3B186F5C1BBB0676282713BC0C5B8D92B2488B8FF4
ticker: CRINGE
size: 10226
version: 2
type: DECL
subtype: CF20
decimals: 18
auth signs valid: 2
auth signs total: 3
total_supply: 10000
flags: NONE
Signatures:
status:
line: 1
hash: 0xE7D0E94E6792FE145A9691ECDFECA151BC1C7477C3E11979DA48E5752C14A2E1
sign_type: sig_dil
bytes: 2096
line: 2
hash: 0x0A57D6D1F3E72E9F2D1DDA6E6089AFEB0AADB953FB347E08C7B6575D65FA6D56
sign_type: sig_dil
bytes: 2096
line: 3
hash: 0x18A38ACF46876226F9AC130427870814503C19B00185A85F034DDC2058D699C1
sign_type: sig_dil
bytes: 2096
updates:
status: ACCEPTED
Ledger return code: 0
Datum:
=== Datum Token Declaration ===:
hash: 0x562FB0177E71EE299532467A937E181CB409714864FBC8620590CF0E62CA22C0
size: 10305
version: 2
total_sign: 3
description: Updated: total supply increased on 5000 and the flags were set as STATIC
Signatures:
status:
line: 1
hash: 0xE7D0E94E6792FE145A9691ECDFECA151BC1C7477C3E11979DA48E5752C14A2E1
sign_type: sig_dil
bytes: 2096
line: 2
hash: 0x0A57D6D1F3E72E9F2D1DDA6E6089AFEB0AADB953FB347E08C7B6575D65FA6D56
sign_type: sig_dil
bytes: 2096
line: 3
hash: 0x18A38ACF46876226F9AC130427870814503C19B00185A85F034DDC2058D699C1
sign_type: sig_dil
bytes: 2096
Finally, it’s time to execute emission.
Emission
To provide token emission, we must have a wallet in the corresponding network.
How to create a wallet - via the Cellframe Wallet or via the CLI request.
Let’s emit 10000
datoshi from our 15000
total supply.
cellframe-node-cli token_emit -token CRINGE -emission_value 10000 -addr o9z3wUTSTicckJuoznovQRfNbRKv2viuHsUtmmJFockaWLtuCx2BTU7SBMfJRCFwpLo7UnkMkdpX5VsTFBHoRFQzfQpow2S6Ddc713aE -chain_emission zerochain -net riemann -certs riemann.bridge.pvt.0
Important
Emission must be performed in the zerochain.
Datum 0xF7D26F9667EFC236EECD1001394445E9A300858CFB3CCA853ED846B6E56A9E27 with 256bit emission is placed in datum pool
Sign datum using Node Command - TOKEN EMIT SIGN, and for now, we need only 2
signatures as we specified during token declaration.
cellframe-node-cli token_emit sign -emission 0xF7D26F9667EFC236EECD1001394445E9A300858CFB3CCA853ED846B6E56A9E27 -chain zerochain -net riemann -certs riemann.bridge.pvt.1
Datum was successfully signed.
result: Datum 0x1FF3A2565F9F523CA59C485F49F675693119F5D420FB90433890D1CAF723B58F with 256bit emission is placed in datum pool
We also must process this datum.
In case when emission datums autoprocessing mempool_auto_types=[emission]
is enabled in the network config, we don’t have to process it manually, so the datum automatically gets in chain.
But if an autoprocessing is disabled, use this command.
cellframe-node-cli mempool_proc -net riemann -datum 0x1FF3A2565F9F523CA59C485F49F675693119F5D420FB90433890D1CAF723B58F
Now, we have to create a transaction which will transfer funds from the emission to the specified wallet.
cellframe-node-cli tx_create -net riemann -chain main -from_emission 0x1FF3A2565F9F523CA59C485F49F675693119F5D420FB90433890D1CAF723B58F -cert riemann.root.pvt.0
Transaction is created.
emission: Ok
hash: 0xE17EE5A89343DAA2E2D9A3CD85CE85B398C17361908D553B66A70045762A0B3D
Let’s check the wallet balance using Node Command - WALLET INFO.
cellframe-node-cli wallet info -addr o9z3wUTSTicckJuoznovQRfNbRKv2viuHsUtmmJFockaWLtuCx2BTU7SBMfJRCFwpLo7UnkMkdpX5VsTFBHoRFQzfQpow2S6Ddc713aE -net riemann
So we have 10000
CRINGE datoshi on our wallet or just 0.00000000000001
coin.
addr: o9z3wUTSTicckJuoznovQRfNbRKv2viuHsUtmmJFockaWLtuCx2BTU7SBMfJRCFwpLo7UnkMkdpX5VsTFBHoRFQzfQpow2S6Ddc713aE
network: riemann
signs: sig_dil
tokens:
balance:
coins: 0.00000000000001
datoshi: 10000
token:
ticker: CRINGE
description: Updated: total supply increased on 5000 and the flags were set as STATIC