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.js
with 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 (Connex Environment ) and create a new account on the Testnet.
-
Switch to the Testnet in the Toolbar
-
Create a new Account
-
Visit to claim some free VTHO
-
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.