You can create your own **[[CF-20 Standard|CF-20 token]]** in the Cellframe network.
If you want to create token in your own network on Cellframe platfrom, see **[[Custom Network Setup|this manual]]**.
Actions:
- **[[How to Create and Manage the Token#Declaration|DECLARE]]**
- **[[How to Create and Manage the Token#Updating|UPDATE]]**
- **[[How to Create and Manage the Token#Emission|EMIT]]**
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)
> [!HINT] Note
> In this example, we will use bridge certificates.
Let's declare the token **CRINGE**:
`Command:`
```actionscript
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:`
```actionscript
code: 0
message: Datum 0x80F32668F798B9A59257344010D08E9D5DF4BBA6FD4855303D27B27D2B754B5E with token CRINGE is placed in datum pool
```
Sign it with additional cert `riemann.bridge.pvt.1`:
`Command:`
```actionscript
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:`
```actionscript
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:`
```actionscript
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:`
```actionscript
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:`
```actionscript
cellframe-node-cli mempool_proc -net riemann -chain zerochain -datum 0x8C21984193F7BF0746063B3B186F5C1BBB0676282713BC0C5B8D92B2488B8FF4
```
`Response:`
```actionscript
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:
```actionscript
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:`
```actionscript
cellframe-node-cli token info -net riemann -name CRINGE
```
`Response:`
```actionscript
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 **[[How to Create and Manage the Token#Emission|here]]**.
## Updating
Token updating allows the user to fine tune the token.
It is provided by [[Node Command - TOKEN UPDATE]].
Command parameters:
```actionscript
-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:`
```actionscript
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] Example
> For example, we need to increase **`total_supply`** by `5000` and restrict all actions with **`flags`** using flag `STATIC_FLAGS`, after that, we can inform users about this update by changing token **`description`**.
Paste all these parameters in the command.
`Command:`
```actionscript
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:`
```actionscript
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:`
```actionscript
cellframe-node-cli token_update_sign -net riemann -chain zerochain -datum 0xF48B60D3C829D1F6280781862B9EB87ED36729E6AD75D35604053A3D0D81A4AB -certs riemann.bridge.pvt.1
```
First one.
`Response:`
```actionscript
code: 0
message: Datum was replaced in datum pool:
Old: 0xF48B60D3C829D1F6280781862B9EB87ED36729E6AD75D35604053A3D0D81A4AB
New: 0x549730A5830CFE1EDA983B36CDA935D84B64A9977BB649F20E27938F48BA2432
```
`Command:`
```actionscript
cellframe-node-cli token_update_sign -net riemann -chain zerochain -datum 0x549730A5830CFE1EDA983B36CDA935D84B64A9977BB649F20E27938F48BA243 -certs riemann.bridge.pvt.2
```
And the second one.
`Response:`
```actionscript
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:`
```actionscript
cellframe-node-cli mempool_proc -net riemann -chain zerochain -datum 0xD6B95071CFC459965DA8E0B35423D85A3D78B01B41C897B1E1F3F115406C8CDD
```
`Response:`
```actionscript
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:`
```actionscript
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:`
```actionscript
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 [[Crypto Wallet|Cellframe Wallet]] or [[Node Command - WALLET NEW|via the CLI request]].
Let's emit `10000` datoshi from our `15000` total supply.
```actionscript
cellframe-node-cli token_emit -token CRINGE -emission_value 10000 -addr o9z3wUTSTicckJuoznovQRfNbRKv2viuHsUtmmJFockaWLtuCx2BTU7SBMfJRCFwpLo7UnkMkdpX5VsTFBHoRFQzfQpow2S6Ddc713aE -chain_emission zerochain -net riemann -certs riemann.bridge.pvt.0
```
```actionscript
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.
```actionscript
cellframe-node-cli token_emit sign -emission 0xF7D26F9667EFC236EECD1001394445E9A300858CFB3CCA853ED846B6E56A9E27 -chain zerochain -net riemann -certs riemann.bridge.pvt.1
```
Datum was successfully signed.
```actionscript
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.
```actionscript
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.
```actionscript
cellframe-node-cli tx_create -net riemann -chain main -from_emission 0x1FF3A2565F9F523CA59C485F49F675693119F5D420FB90433890D1CAF723B58F -cert riemann.root.pvt.0
```
Transaction is created.
```actionscript
emission: Ok
hash: 0xE17EE5A89343DAA2E2D9A3CD85CE85B398C17361908D553B66A70045762A0B3D
```
Let's check the wallet balance using [[Node Command - WALLET INFO]].
```actionscript
cellframe-node-cli wallet info -addr o9z3wUTSTicckJuoznovQRfNbRKv2viuHsUtmmJFockaWLtuCx2BTU7SBMfJRCFwpLo7UnkMkdpX5VsTFBHoRFQzfQpow2S6Ddc713aE -net riemann
```
So we have `10000` **CRINGE** datoshi on our wallet or just `0.00000000000001` coin.
```actionscript
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
```