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 ```