Advanced

 

How to Create and deploy Smart-Contracts on VeChain.

Setup Project

The project consists of a nodejs-project using truffle suite for the contract handling.

These are the commands to setup the project:

yarn init          # init package.json and project description
yarn add truffle   # add truffle 
npx truffle init   # init truffle project

truffle will setup the following directory structure:

drwxr-xr-x    3 favo  staff    96B 29 Dez 16:26 contracts
drwxr-xr-x    3 favo  staff    96B 29 Dez 16:26 migrations
drwxr-xr-x  118 favo  staff   3,7K 29 Dez 16:25 node_modules
-rw-r--r--    1 favo  staff   145B 29 Dez 16:25 package.json
drwxr-xr-x    4 favo  staff   128B 29 Dez 16:29 test
-rw-r--r--    1 favo  staff   4,1K 29 Dez 16:26 truffle-config.js
-rw-r--r--    1 favo  staff    39K 29 Dez 16:25 yarn.lock

 

Writing Tests & Contract

Create test/Contract.jswith our first test:

const Contract = artifacts.require('Contract')

contract('Contract', accounts => {
  const [firstAccount] = accounts

  it('has a contract length <24kb', async () => {
    const contractInstance = await Contract.new()
    expect(contractInstance.constructor._json.deployedBytecode.length).to.be.lessThan(24000)
  })

  it('sets the creator as owner', async () => {
    const contractInstance = await Contract.new()
    const owner = await contractInstance.owner.call()
    expect(owner).to.equal(firstAccount)
  })
})

It will test if the contract sets an owner attribute with the account that created the contract.

Running the test will fail because nothing is written yet:

$ npx truffle testCompiling your contracts...
===========================
> Compiling ./contracts/Migrations.sol
> Artifacts written to /var/folders/nw/hymkww096w943gbmh256534h0000gn/T/test--47718-RIGRzjk6f2l2
> Compiled successfully using:
   - solc: 0.5.16+commit.9c3226ce.Emscripten.clangError: Could not find artifacts for Contract from any sources

Create contract/Contract.sol with our first contract definition:

pragma solidity >=0.4.22 <0.6.0;

contract Contract {
    address public owner;

    constructor() public {
        owner = msg.sender;
    }
}

It will remember the sender of the transaction that creates the contract as owner

Running the test will be successful now:

$ npx truffle test
Compiling your contracts...
===========================
> Compiling ./contracts/Contract.sol
> Compiling ./contracts/Migrations.sol
> Artifacts written to /var/folders/nw/hymkww096w943gbmh256534h0000gn/T/test--48154-PBoTcbjV1izF
> Compiled successfully using:
   - solc: 0.5.16+commit.9c3226ce.Emscripten.clang
Contract: Contract
    ✓ has a contract length <24kb (49ms)
    ✓ sets the creator as owner (81ms)
2 passing (156ms)

Add an echo-Function

Call a new function echo and expect what we send as result:

it('echoes what we send', async () => {
  const randomValue = String(Math.random())
  const contractInstance = await Contract.new()
  const echo = await contractInstance.echo(randomValue)
  expect(echo).to.equal(randomValue)
})

The contract will be modified to return the input:

pragma solidity >=0.4.22 <0.6.0;

contract Contract {
    address public owner;

    constructor() public {
        owner = msg.sender;
    }

    function echo(string memory input) public view returns (string memory) {
        string memory output = input;
        return output;
    }
}

Simplifying the test driven approach

With nodemon it is possible to watch for file changes and run the same command when something changes. Install viayarn add --dev nodemon and modify the package.json:

{
  "name": "smart-contract",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "dependencies": {
    "truffle": "^5.1.59"
  },
  "devDependencies": {
    "nodemon": "^2.0.6"
  },
  "scripts":{
    "test": "npx truffle test",
    "develop": "nodemon -e js,sol --exec 'npx truffle test'"
  }
}

A new shortcut will be available yarn develop that executes tests when a contract or testfile changes. yarn test will make it easier for other developers to find into the project.

Deploy Contract on the VeChain-Testnet

Prepare Test-Account and Toolchain

VeChains web3-gear will bridge the truffle suite to the VeChain-APIs. Install it using pip3 install web3-gear

Find more about it at

To connect it directly to the Testnet without running a local node a valid keystore is required. Open the Sync Browser ( ) and create a new account on the Testnet.

  1. Switch to the Testnet in the Toolbar

  2. Create a new Account

  3. Visit to claim some free VTHO

  4. Backup the Account and save the keystore in the file keystore

{
  "address": "3df37993f2a9508d73bc35d89b422445cddfcafe",
  "crypto": {
    "cipher": "aes-128-ctr",
    "ciphertext": "06c01f5ffe81519827fea805c6a745b85a24ee70a9d257030b5622a2a9ed0c62",
    "cipherparams": {
      "iv": "b087474bc99129d3a0d507a192ca8fb2"
    },
    "mac": "681fb93b50f9d529dc9199682bad02d3890bf3572a2cba8538f6c0f36228ffec",
    "kdf": "scrypt",
    "kdfparams": {
      "dklen": 32,
      "n": 262144,
      "r": 8,
      "p": 1,
      "salt": "e476a53fb7518df58dcf6e66cc64a145bce27d3dbf488b3330a17c790556f4c4"
    }
  },
  "id": "d4c9aa59-d8f0-4a17-a5b4-83004e0af465",
  "version": 3
}

Open a second terminal and run web3-gear to start a local RESTful API that the truffle suite can use to deploy the contract using the test account:

$ web3-gear --host 127.0.0.1 --port 8545 --endpoint https://sync-testnet.vechain.org --keystore ./keystore --passcode contract-test
Web3-Gear/2.0.2/darwin/python3.8.5
Listening on 127.0.0.1:8545
======== Running on http://127.0.0.1:8545 ========
(Press CTRL+C to quit)

Enable a network configuration in truffle-config.js

module.exports = {
  networks: {
    testnet: {
      host: '127.0.0.1', // Localhost (default: none)
      port: 8545, // Standard Ethereum port (default: none)
      network_id: '*', // Any network (default: none)
      skipDryRun: true,
      production: true
    }
  },

  // Set default mocha options here, use special reporters etc.
  mocha: {
    // timeout: 100000
  },

  // Configure your compilers
  compilers: {
    solc: {
      // version: "0.5.1",    // Fetch exact version from solc-bin (default: truffle's version)
      // docker: true,        // Use "0.5.1" you've installed locally with docker (default: false)
      // settings: {          // See the solidity docs for advice about optimization and evmVersion
      //  optimizer: {
      //    enabled: false,
      //    runs: 200
      //  },
      //  evmVersion: "byzantium"
      // }
    }
  }
};

Deploy contract

$ npx truffle migrate --network testnet
Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.
Starting migrations...
======================
> Network name:    'testnet'
> Network id:      5777
> Block gas limit: 16777216 (0x1000000)
1_initial_migration.js
======================
Deploying 'Migrations'
   ----------------------
   > transaction hash:    0x8e9cc44151ccfdee4c079ade5a8e1fa4d15a3145990532ac868e62faf25886a7
   > Blocks: 1            Seconds: 10
   > contract address:    0x220BC18B32bc66F8FDB4704376AA104CE92bf307
   > block number:        7922860
   > block timestamp:     1609259770
   > account:             0x64fFb7a9bEC36bd37F239A7deA1190aEb8Abd1d3
   > balance:             4000
   > gas used:            221555 (0x36173)
   > gas price:           0.000000001 gwei
   > value sent:          0 ETH
   > total cost:          0.000000000000221555 ETH
> Saving migration to chain.
   > Saving artifacts
   -------------------------------------
   > Total cost:     0.000000000000221555 ETH
Summary
=======
> Total deployments:   1
> Final cost:          0.000000000000221555 ETH

This contract was published to https://explore-testnet.vechain.org/accounts/0x220BC18B32bc66F8FDB4704376AA104CE92bf307

Summary

In this article we did all what was necessary to write a smart contract and deploy it on the VeChain-Testnet:

  • Setup a new Project using the truffle suite

  • Using a test-driven-approach to write a contract

  • Creating an account where we can publish the contract

  • Deploying the contract on the Testnet

The handling of the Testnet can be duplicated for the Mainnet.

By this, you complete this workshop successfully!!