How To Develop and Deploy Contracts

Edit contract

You can write contracts based on any editor that supports solidity. The following will be based on Remix online editor as an example for explanation. Check here for Remix’s documentation.

For convenience of description, we use the following simple contract example:

pragma solidity >=0.4.24 <=0.7.6 ;

contract SimpleStorage {
    uint storedData;

    function set(uint x) public {
        storedData = x;
    }

    function get() public view returns (uint) {
        return storedData;
    }
}

Note: Since the SCDO mainnet is compatible with the Istanbul version of EVM, it's recommended to use the solidity version no later than 0.7.6 to develop your contracts. The features in the Berlin version of EVM is not available on the SCDO virtual machine.

The following screenshot is an illustration for Remix IDE:

Compile contract

After the contract is written and saved to a file, you can use the compile function of Remix to compile the contract and check for possible syntax errors. As shown in the screenshot, click the "Compile" button to compile the example contract. If there is an error, the compiler will point to where the possible error(s) takes place.

Deploy contract

Local test environment

After compiling the contract successfully, we can deploy the contract and test it. The best practice that we recommend is to set up a SCDO private chain node. Then, deploy the contract and call it on the private chain. If you're satisfied with the test results, you can deploy the contract to the SCDO mainnet. Our test node is set up in Ubuntu.

Get the contract's bytecode

As shown in Remix IDE, after the contract is complied successfully, click the "Deploy" icon on the left panel of Remix IDE:

Click "Deploy". If there is no error, then you will see the following:

Then click the green check icon.

You will see the following:

The value in the "input" field is the bytecode of the contract. Click the copy icon next to the bytecode string to copy it to the clipboard. Then save the copy to a safe place. The bytcode is as follows:

0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a723058209e18a0a3a2dc0fa6b26ca8a3b915b69344f7a214ce5510d0bc21f948fb0ff0750029

Deploy the contract through the client tool

  • Prepare a SCDO account and ensure that there is enough balance to deploy the contract. Here we use account 1S010a3fe1668c7cab5923fe0f77cb25ec21f644f1 of shard 1 and save the account keystore file.

  • You can download SCDO release Mac/Windows/Linux node and client tools.

Note: keystore file is generated by the following command

./client savekey --privatekey "the private key paired with 1S010a3fe1668c7cab5923fe0f77cb25ec21f644f1" --file 1S010a3fe1668c7cab5923fe0f77cb25ec21f644f1.keystore --shard 1
  • Start a private chain node (in our example, the node is in shard 1).

  • Deploy the contract using the sendtx command.

 ./client sendtx --amount 0  --address 0.0.0.0:8027 --payload 0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a723058209e18a0a3a2dc0fa6b26ca8a3b915b69344f7a214ce5510d0bc21f948fb0ff0750029 --from 1S010a3fe1668c7cab5923fe0f77cb25ec21f644f1.keystore

The sendtx parameter address is the node ip address; "amount" is the transaction amount (in Wen), which can usually be set to 0 for contract deployment; from is the keystore file corresponding to the sending transaction account keyfile; payload is the contract bytecode; gas is the minimum gas value required for the transaction (the default is 20000).

The return result of the above command is as follows:

transaction sent successfully
{
    "Data": {
        "AccountNonce": 12,
        "Amount": 0,
        "From": "1S010a3fe1668c7cab5923fe0f77cb25ec21f644f1",
        "GasLimit": 200000,
        "GasPrice": 10,
        "Payload": "0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a723058209e18a0a3a2dc0fa6b26ca8a3b915b69344f7a214ce5510d0bc21f948fb0ff0750029",
        "Timestamp": 0,
        "To": "0S0000000000000000000000000000000000000000",
        "Type": 0
    },
    "Hash": "0x08c45b71dd7c151071f222fb6d1216248425e977255d5923dbade76c32abd1b0",
    "Signature": {
        "Sig": "9IawOq9cHp6Cmmj7i7YD7oxMNB+Zc28YmJuUzpA7S9INLiGP6ysdYK/AC9jZH3CF+kUJYvBWsIwXEWx2s/s/aQA="
    }
}

You can view the contract deployment result according to the transaction Hash as the following:

./client getreceipt --address 0.0.0.0:8027 --hash 0x08c45b71dd7c151071f222fb6d1216248425e977255d5923dbade76c32abd1b0

Return result:

{
    "contract": "1S01f671dfc64128d285e178c1f6e7bf640d420002",
    "failed": false,
    "poststate": "0x3c7e3c77abf149d2d59e2d94d134611314751e22b940a2f22be9b2e2c74fb9b6",
    "result": "0x6080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a723058209e18a0a3a2dc0fa6b26ca8a3b915b69344f7a214ce5510d0bc21f948fb0ff0750029",
    "totalFee": 802130,
    "txhash": "0x08c45b71dd7c151071f222fb6d1216248425e977255d5923dbade76c32abd1b0",
    "usedGas": 80213
}

The value of the "failed" field as false in the result indicates that the contract is successfully deployed, and the value of "contract" is the contract address.

Call contract

Use Remix to get the bytecode of the method call

To use the client sendtx command to call a contract, you need to provide the payload information (bytecode) of the method of the contract to be called. This bytecode can be obtained through Remix. Below the "Deploy" button of the left side panel of Remix IDE, you can see the set and get methods. Fill in the parameter value ​​on the right side of the set method (here it is 22) and click "set" to implement the method call.

You can see the result of the call in the log widget on the right side panel.

Click the green check icon to view the call details, where the value of "input" is the bytecode of the set method call. Here the set method call sets the variable value to 22, as shown in the above figure.

The bytecode of the set method call is:

0x60fe47b10000000000000000000000000000000000000000000000000000000000000016

Use sendtx to call the contract

The following command calls the set method in the above contract and sets the variable value to 22. The payload is the bytecode obtained from Remix. "From" is the account that initiated the transaction, and "to" is the contract address as shown in the return of "./client getreceipt ..." above.

./client sendtx --amount 0   --payload  --address 0.0.0.0:8027 --payload 0x60fe47b10000000000000000000000000000000000000000000000000000000000000016 --from 1S017f6215c30f1505e0d42769c5472b410d6bf961.keystore --to 1S01f671dfc64128d285e178c1f6e7bf640d420002

Result:

transaction sent successfully
{
    "Data": {
        "AccountNonce": 13,
        "Amount": 0,
        "From": "1S010a3fe1668c7cab5923fe0f77cb25ec21f644f1",
        "GasLimit": 200000,
        "GasPrice": 10,
        "Payload": "0x60fe47b10000000000000000000000000000000000000000000000000000000000000016",
        "Timestamp": 0,
        "To": "1S0126ba0710ad416638a7f0e5a113e9b6be4b0002",
        "Type": 0
    },
    "Hash": "0xb26dae6efc9942c6655a6e5baa372f6d3388b62ac50011466a7b6c105ee6e01e",
    "Signature": {
        "Sig": "bt/Nh0UyKrCxTxoP/gyeTgE8mHVmVmZHCQHJ14pGePJHblZrS1vI/6aE2d2WXUSqLYGnSqFWoaXkxbOa7hco+wA="
    }
}

By querying the receipt information, the result of the contract call can be obtained:

./client getreceipt --hash 0xb26dae6efc9942c6655a6e5baa372f6d3388b62ac50011466a7b6c105ee6e01e

Return result:

{
    "contract": "0x",
    "failed": false,
    "poststate": "0x328868cd36c074185bd1ccf4e905728b0f36de9fd06743e93b87483ae3872bd1",
    "result": "0x",
    "totalFee": 266690,
    "txhash": "0xb26dae6efc9942c6655a6e5baa372f6d3388b62ac50011466a7b6c105ee6e01e",
    "usedGas": 26669
}

Note: The account calling the contract must be in the same shard as the contract address. SCDO currently does not support cross-shard contract calls.

Use the command "call" to call contract methods

For methods that only get the value of a variable without changing the state of the contract, you can call the method through command "call". As in our example, obtaining the bytecode for "get" method, similar to the above-mentioned "set" method (the bytecode is 0x6d4ce63c here). To call the "get" method, it will look like:

./client call -payload 0x6d4ce63c --to 1S0126ba0710ad416638a7f0e5a113e9b6be4b0002

The return result is:

{
    "contract": "0x",
    "failed": false,
    "poststate": "0x2673977b8565ad747d1dff04dccaa424afcb1e81c3e07e994eeef538d25a1a06",
    "result": "0x0000000000000000000000000000000000000000000000000000000000000016",
    "totalFee": 21696,
    "txhash": "0x169ac2e722ddfc99a2368aecd4462cbf92a43320c2cf5e18341492bfb00fd4ec",
    "usedGas": 21696
}

As you can see, the variable value displayed by the result is 22 in hex format, which was previously set by the set method.

Deploy to SCDO mainnet

After the contract is fully tested as shown in the previous sections, you can deploy it to the SCDO mainnet by following the same steps as deploying it to a private net.

Last updated