Interacting with the wCCD token protocol#

Note

Before you start with part 2 of this tutorial, make sure you have:

  • access to a testnet node

  • the concordium-client version 5.0.1 or greater installed

  • an account created in the wallet that is funded with some CCD

  • the keys from the wallet imported into the concordium-client configuration

If you haven’t completed any of the above steps, Setup the development environment will guide you through these setup steps. If you haven’t completed any of the above steps, you can continue with part 3 of this tutorial. However, it is recommended to complete every part of this tutorial in the given order. You need an up-to-date concordium-client version because the wCCD smart contract uses the newest schema_V3.

Query (non-state-mutative) functions#

The protocol has four query functions (balanceOf, operatorOf, tokenMetadata, and supports) that you can invoke on the wCCD contract. Because the schema is already embedded, the input parameters can be provided with the --parameter-json flag.

Note

The wCCD smart contract has its schemas embedded and you will not have to provide any schemas with the --schema flag. You can read more about schemas in this section.

Getting the CCD balance of an address#

Checking the CCD balance of an account (click here)

You can check the CCD balance of an account on CCDScan.

../../_images/wCCD_tutorial_1.png

You can check the CCD balance of an account with this command:

$ concordium-client account show ACCOUNT --grpc-port 20001
../../_images/wCCD_tutorial_10.png
Checking the CCD balance of a smart contract (click here)

You can check the CCD balance of a smart contract with this command:

$ concordium-client contract show INDEX --grpc-port 20001
../../_images/wCCD_tutorial_3.png

Note

The smallest unit of CCD is 1 micro CCD and equals 10−6 (one millionth) of a CCD. CCD has 6 decimal places. 1 CCD is represented by the balance value of 1,000,000 micro CCD on the blockchain and is worth the equivalent of a balance value of 1,000,000 micro wCCD.

The balanceOf function#

Input parameters for the balanceOf function (click here)

Create a balanceOf.json file and insert the following JSON array.

[
    {
        "address": {
            "Enum": [
                {
                    "Account": [
                        ACCOUNT_ADDRESS
                    ]
                },
                {
                    "Contract": [
                        {
                            "index": INDEX,
                            "subindex": SUBINDEX
                        }
                    ]
                }
            ]
        },
        "token_id": TOKEN_ID
    }
]

Note

You can query the balance of several addresses in the above array.

If you insert an account address correctly, the JSON array should look similar to the below JSON array.

[
    {
        "address": {
            "Account": [
                "4phD1qaS3U1nLrzJcgYyiPq1k8aV1wAjTjYVPE3JaqovViXS4j"
            ]
        },
        "token_id": ""
    }
]

If you insert a smart contract address correctly, the JSON array should look similar to the below JSON array.

[
    {
        "address": {
            "Contract": [
                {
                    "index": 844,
                    "subindex": 0
                }
            ]
        },
        "token_id": ""
    }
]

You are ready now to invoke the balanceOf function with the following command.

$ concordium-client contract invoke WCCD_CONTRACT_INDEX --entrypoint balanceOf --parameter-json balanceOf.json --grpc-port 20001
../../_images/wCCD_tutorial_4.png

The operatorOf function#

Input parameters for the operatorOf function (click here)

Create an operatorOf.json file and insert the following JSON array.

[
    {
        "address": {
            "Enum": [
                {
                    "Account": [
                        ACCOUNT_ADDRESS
                    ]
                },
                {
                    "Contract": [
                        {
                            "index": INDEX,
                            "subindex": SUBINDEX
                        }
                    ]
                }
            ]
        },
        "owner": {
            "Enum": [
                {
                    "Account": [
                        ACCOUNT_ADDRESS
                    ]
                },
                {
                    "Contract": [
                        {
                            "index": INDEX,
                            "subindex": SUBINDEX
                        }
                    ]
                }
            ]
        }
    }
]

Note

You can query several sets of addresses in the above array.

If you insert everything correctly, the JSON array should look similar to the below JSON array.

[
    {
        "address": {
            "Account": [
                "4DH219BXocxeVByKpZAGKNAJx7s2w1HFpwaNu1Ljd1mXFXig22"
            ]
        },
        "owner": {
            "Account": [
                "4phD1qaS3U1nLrzJcgYyiPq1k8aV1wAjTjYVPE3JaqovViXS4j"
            ]
        }
    }
]

You are ready now to invoke the operatorOf function with the following command.

$ concordium-client contract invoke WCCD_CONTRACT_INDEX --entrypoint operatorOf --parameter-json operatorOf.json --grpc-port 20001
../../_images/wCCD_tutorial_7.png

The tokenMetadata function#

Input parameters for the tokenMetadata function (click here)

Create a tokenMetadata.json file and insert the following JSON array.

[""]

Note

This empty string is required because of the CIS-2 token standard. The tokenId of the wCCD token is the smallest unit possible (an empty string).

You are ready now to invoke the tokenMetadata function with the following command.

$ concordium-client contract invoke WCCD_CONTRACT_INDEX --entrypoint tokenMetadata --parameter-json tokenMetadata.json --grpc-port 20001
../../_images/wCCD_tutorial_8.png

The supports function#

Input parameters for the supports function (click here)

Create a supports.json file and insert the following example JSON array. It will query if the two token standards (CIS-0 and CIS-2) are supported by the wCCD token.

["CIS-0","CIS-2"]

Note

You can find more information about the CIS-0 standard and the CIS-2 standard.

You are ready now to invoke the supports function with the following command.

$ concordium-client contract invoke WCCD_CONTRACT_INDEX --entrypoint supports --parameter-json supports.json --grpc-port 20001

The below screenshot shows the response of querying if the wCCD token contract supports the following standards ["12345","CIS-0","CIS-2"]. Its response is that it does not support the standard 12345 but it supports the CIS-0 and the CIS-1 standards.

../../_images/wCCD_tutorial_9.png

State-mutative functions#

The protocol has four state-mutative functions (wrap, unwrap, transfer, and updateOperator) that you can invoke on the wCCD smart contract. Because the schema is already embedded, the input parameters can be provided with the --parameter-json flag.

Note

The wCCD smart contract has its schemas embedded and you will not have to provide any schemas with the --schema flag. You can read more about schemas in this section.

The wrap function#

Wrapping CCD refers to the process of converting the native currency CCD into a CIS-2 compliant token (wCCD) at a 1:1 ratio by sending CCD to the wCCD smart contract and getting wCCD in return. You can specify with the --amount flag how much CCD you want to wrap.

Create a wrap.json file and insert the JSON object from option 1 (Receiver is an account) or option 2 (Receiver is a smart contract).

Option 1 (Receiver is an account) (click here)
{
    "data": DATA_STRING,
    "to": {
        "Account": [
            ACCOUNT_ADDRESS
        ]
    }
}

The DATA_STRING is only relevant if wCCD is sent to a smart contract as described in option 2. You can use your account address if you want to credit the wCCD to your own account. If you insert your account address correctly, the JSON object should look similar to the below JSON object.

{
    "data": "",
    "to": {
        "Account": [
            "4phD1qaS3U1nLrzJcgYyiPq1k8aV1wAjTjYVPE3JaqovViXS4j"
        ]
    }
}
Option 2 (Receiver is a smart contract) (click here)
{
    "data": DATA_STRING,
    "to": {
        "Contract": [
            {
                "index": INDEX,
                "subindex": SUBINDEX
            },
            ENTRYPOINT_NAME
        ]
    }
}

Some additional bytes (encoded as a lowercase hex string called DATA_STRING) are used in the OnReceivingCis2 hook. This hook is executed only if the to address is a contract and the to address is not the invoker of the wrap function. The OnReceivingCis2 hook invokes the ENTRYPOINT_NAME on the smart contract INDEX with the OnReceivingCis2Params parameters which include the above DATA_STRING. This action allows the receiving smart contract to react to the credited wCCD amount. You can keep the data field empty if you don’t want to send any additional data to the receiving smart contract.

Note

In programming, a hook is an interface provided in packaged code that allows a programmer to insert customized programming code to either provide a different behavior or to react when something happens. The OnReceivingCis2 hook allows a smart contract developer to code a smart contract A that taps into the transfer or wrap functions of the wCCD smart contract. Smart contract A can insert some custom logic/behavior if the transfer or wrap functions are invoked and would result in the smart contract A getting credited some wCCD.

The ENTRYPOINT_NAME is an attribute that is added above each function in the smart contract code as shown below using the example entrypoint name receiveToken.

#[receive(contract = "contractName", name = "receiveToken")]
fn contract_receive_token( ... ) ... { ... }

You can use the smart contract deployed at index 844 on testnet and its function entry point name receiveToken for testing.

{
    "data": "",
    "to": {
        "Contract": [
            {
                "index": 844,
                "subindex": 0
            },
            "receiveToken"
        ]
    }
}

Before you execute the wrap function, check the CCD balance of your SENDER_ACCOUNT (the account that initiates the transaction) and the wCCD smart contract as described here. The wrap function will send some CCD from your SENDER_ACCOUNT account to the wCCD smart contract contract.

Note

This tutorial is also used by other people and they might at the same time interact with the smart contracts and change their CCD or wCCD balances.

Before you execute the wrap function, check the wCCD balance of the to address with the balanceOf function. The to address will receive some wCCD because the wrap function will credit some wCCD to the to address.

You are ready now to wrap your CCD into wCCD with the following command. The --energy flag specifies the maximum amount of NRG to be spent on the transaction and can be used to set an upper limit of the transaction fee that you are willing to spend when interacting with the blockchain.

$ concordium-client contract update WCCD_CONTRACT_INDEX --entrypoint wrap --parameter-json wrap.json --amount AMOUNT --sender SENDER_ACCOUNT --energy 25000 --grpc-port 20001

The below screenshot shows the wrapping of 1 CCD (1,000,000 micro CCDs) into 1,000,000 micro wCCD.

../../_images/wCCD_tutorial_2.png

Confirm that the CCD balance of the SENDER_ACCOUNT was decreased by AMOUNT and that the CCD balance of the wCCD smart contract contract was increased by AMOUNT.

Note

Keep in mind that the SENDER_ACCOUNT also paid some CCD as transaction fees. The amount of transaction fees can be seen as shown in the above screenshot.

Confirm that the wCCD balance of the to address increased by AMOUNT.

The unwrap function#

Unwrapping CCD refers to the opposite process of converting the CIS-2 compliant wCCD token at a 1:1 ratio back to the native currency CCD by burning the wCCD token in the wCCD smart contract and getting CCD in return.

Input parameters for the unwrap function (click here)

Create an unwrap.json file and insert the below JSON object.

{
    "amount": AMOUNT,
    "data": DATA_STRING,
    "owner": {
        "Enum": [
            {
                "Account": [
                    ACCOUNT_ADDRESS
                ]
            },
            {
                "Contract": [
                    {
                        "index": INDEX,
                        "subindex": SUBINDEX
                    }
                ]
            }
        ]
    },
    "receiver": {
        "Enum": [
            {
                "Account": [
                    ACCOUNT_ADDRESS
                ]
            },
            {
                "Contract": [
                    {
                        "index": INDEX,
                        "subindex": SUBINDEX
                    },
                    ENTRYPOINT_NAME
                ]
            }
        ]
    }
}

If you insert everything correctly, the JSON object should look similar to the below JSON object that will unwrap 1,000,000 micro wCDD from an account and send the received CCDs back to the same account.

{
    "amount": "1000000",
    "data": "",
    "owner": {
        "Account": [
            "4phD1qaS3U1nLrzJcgYyiPq1k8aV1wAjTjYVPE3JaqovViXS4j"
        ]
    },
    "receiver": {
        "Account": [
            "4phD1qaS3U1nLrzJcgYyiPq1k8aV1wAjTjYVPE3JaqovViXS4j"
        ]
    }
}

Before you execute the unwrap function, check the CCD balance of the receiver address and the wCCD smart contract as described here. The unwrap function will send some CCD from the wCCD smart contract to the receiver address.

Before you execute the unwrap function, check the wCCD balance of the owner address with the balanceOf function. The owner address will get its wCCD balance reduced because the unwrap function will burn some wCCD from the owner address.

The owner has to have at least a balance of AMOUNT in wCCD tokens and the SENDER_ACCOUNT has to be the owner address or be an operator of the owner address. You are ready now to unwrap your wCCD into CCD with the following command.

$ concordium-client contract update WCCD_CONTRACT_INDEX --entrypoint unwrap --parameter-json unwrap.json --sender SENDER_ACCOUNT --energy 25000 --grpc-port 20001

The below screenshot shows the execution of the unwrap function.

../../_images/wCCD_tutorial_11.png

Confirm that the CCD balance of the receiver was increased by AMOUNT (specified in the unwrap.json file) and that the CCD balance of the wCCD smart contract was decreased by AMOUNT.

Confirm that the wCCD balance of the owner address decreased by AMOUNT specified in the unwrap.json file.

The transfer function#

You can transfer the wCCD tokens from one address to another address.

Input parameters for the transfer function (click here)

Create a transfer.json file and insert the below JSON array.

[
    {
        "amount": AMOUNT,
        "data": DATA_STRING,
        "from": {
            "Enum": [
                {
                    "Account": [
                        ACCOUNT_ADDRESS
                    ]
                },
                {
                    "Contract": [
                        {
                            "index": INDEX,
                            "subindex": SUBINDEX
                        }
                    ]
                }
            ]
        },
        "to": {
            "Enum": [
                {
                    "Account": [
                        ACCOUNT_ADDRESS
                    ]
                },
                {
                    "Contract": [
                        {
                            "index": INDEX,
                            "subindex": SUBINDEX
                        },
                        ENTRYPOINT_NAME
                    ]
                }
            ]
        },
        "token_id": TOKEN_ID
    }
]

Note

You can execute several transfers in the above array.

If you insert everything correctly, the JSON array should look similar to the below JSON array that will transfer 1 micro wCCD from an account address to another account address.

[
    {
        "amount": "1",
        "data": "",
        "from": {
            "Account": [
                "4phD1qaS3U1nLrzJcgYyiPq1k8aV1wAjTjYVPE3JaqovViXS4j"
            ]
        },
        "to": {
            "Account": [
                "4DH219BXocxeVByKpZAGKNAJx7s2w1HFpwaNu1Ljd1mXFXig22"
            ]
        },
        "token_id": ""
    }
]

Before you execute the transfer function, check the wCCD balance of the from address and the to address with the balanceOf function. The transfer function will send some wCCD from the from address to the to address.

The from address has to have at least a balance of AMOUNT in wCCD tokens and the SENDER_ACCOUNT has to be the from address or be an operator of the from address. You are ready now to transfer your wCCD to another address with the following command.

$ concordium-client contract update WCCD_CONTRACT_INDEX --entrypoint transfer --parameter-json transfer.json --sender SENDER_ACCOUNT --energy 25000 --grpc-port 20001

The below screenshot shows the execution of the transfer function.

../../_images/wCCD_tutorial_5.png

Confirm that the wCCD balance of the to address was increased by AMOUNT (specified in the transfer.json file) and that the wCCD balance of the from address was decreased by AMOUNT.

The updateOperator function#

You can add one or more operator addresses to an address that you control. These operators have access to your wCCD tokens at that address and can transfer or unwrap them on your behalf. You should only add operator addresses that you trust. The updateOperator function allows you to add and remove operators. For example, a smart contract address is often added as an operator so it can access your tokens to perform some smart contract operations without you having to interact with the smart contract again.

Input parameters for the updateOperator function (click here)

Create an updateOperator.json file and insert the below JSON array.

[
    {
        "operator": {
            "Enum": [
                {
                    "Account": [
                        ACCOUNT_ADDRESS
                    ]
                },
                {
                    "Contract": [
                        {
                            "index": INDEX,
                            "subindex": SUBINDEX
                        }
                    ]
                }
            ]
        },
        "update": {
            "Enum": [
                {
                    "Remove": []
                },
                {
                    "Add": []
                }
            ]
        }
    }
]

Note

You can add/remove several operator addresses in the above array.

If you insert everything correctly, the JSON array should look similar to the below JSON array that will add the account address 4DH219B… as an operator to the SENDER_ACCOUNT.

[
    {
        "operator": {
            "Account": [
                "4DH219BXocxeVByKpZAGKNAJx7s2w1HFpwaNu1Ljd1mXFXig22"
            ]
        },
        "update":
        {
            "Add": []
        }
    }
]

Before you execute the updateOperator function, check the state of the smart contract with the operatorOf function.

You are ready now to update the operator on your SENDER_ACCOUNT address with the following command.

$ concordium-client contract update WCCD_CONTRACT_INDEX --entrypoint updateOperator --parameter-json updateOperator.json --sender SENDER_ACCOUNT --energy 25000 --grpc-port 20001

The below screenshot shows the execution of the updateOperator function.

../../_images/wCCD_tutorial_6.png

Confirm that the updateOperator function has added/removed operator addresses by checking with the operatorOf function the state of the smart contract again.

To continue with the tutorial click here.

Was this article helpful?