Skip to content

EN EcmaContracts

Andrey Nedobylsky edited this page Oct 10, 2019 · 15 revisions

EcmaContracts implements a smart contract management and execution environment. EcmaContracts monitors the state of running virtual machine instances, resource consumption, and provides contract execution environments with methods and objects necessary for working. Interaction with such objects allows you to create powerful and functional decentralized systems.

EcmaContracts based on isolated-vm module that uses Chrome's V8 JavaScript engine (same as Node.js).

Also EcmaContracts supports plugins for improve smart-contracts. For example, this allows you to add support for additional cryptographic functions to smart contracts or add support for other programming languages using an external virtual machines or environments.

Additional about EcmaContracts

Mocks and supports

  • Replaced method Math.random (). Added support for external seed form blockchain state
  • Date mocked and freezed to support state persistence

Smart contracts writing rules

  • Use synchronous JS style. Async is not supported.
  • The names of all private methods and properties must starts with the “_” character to prevent external access to them
  • Do not use a standard class constructor. To initialize a class, you must use the init and deploy method to handle the first run.
  • To save data between instances, you need to use the saved objects KeyValue, TypedKeyValue, BlockchainArray, BlockchainMap

Recommendations

These recommendations will avoid most of the mistakes in designing and writing a contract. Remember that a running contract cannot be modified or updated in the future!

  • To implement a token, use the TokenRegister data type or inherit a contract from TokenContract
  • To work with numbers (like balances) use the BigNumber class
  • It is recommended to inherit any contract from the Contract class, which implements the basic data protection and processing systems for contracts
  • Check all input data for types, as well as mandatory data conversion to the desired type
  • Perform contract execution environment checks using assert and others
  • Important data, such as the address of the contract holder, should be determined in advance in a constant before the contract class
  • Remember that the data recorded on the blockchain is open and accessible to everyone.

Optimization

  • Minimize reading and writing data to stored objects KeyValue, TypedKeyValue, BlockchainArray, BlockchainMap
  • Minimize or not use loops with iteration of an indefinite or very large number of elements

Creating simple token

The IZZZIO blockchain uses its own standard for describing token contracts, similar to the ERC20 standard of the Ethereum blockchain, but with some differences. The IZ3 Token standard (IZ3T) requires certain methods and properties implemented in the contract. Most of these methods are already implemented in the built-in TokenContract class, from which it is recommended to inherit any token contract.

An example of a simple token that complies with the IZ3T standard and security recommendations:

//Tokens emission amount
const EMISSION = 10000;

//Owner address
const CONTRACT_OWNER = 'SOME_ADDR';

class TestToken extends TokenContract{

    //Inititalization. Note that init is used as a constructor
    init() {
        super.init(EMISSION);
    }

    //Contract data property
    get contract() {
        return {
            name: 'Token name',
            ticker: 'TokenTicker',
            owner: CONTRACT_OWNER,
            emission: EMISSION,
            type: 'token',
        };
    }
}

//Register contract class in virtual environment
global.registerContract(TestToken);

Remind

The contract inherits the basic methods of the IZ3T standard from the TokenContract class. When the contract deployed, tokens will be issued to the address CONTRACT_OWNER. Accounting for the number and movement of tokens is done inside the TokenRegister declared in TokenContract

Contract deploy

Deploy with DApp

One way to deploy a contract using the DApp SDK.

DApp deploy example:

const CONTRACT_CODE = ''; //Deploying contract source

const RESOURCES = 1; //Amount of tokens using for resources rent 

//DApp SDK IZZZIO module
const DApp = require(global.PATH.mainDir + '/app/DApp');

class App extends DApp {
        init() {
            that = this;
            that.contracts.ecmaContract.deployContract(CONTRACT_CODE, RESOURCES, function (deployedContract) {
                    console.log('Contract deployed at address', deployedContract.address);
            });
        };
}

Remind

To start DApp, you need to add the appEntry parameter to config.json and specify the path to the entry point to the application. For example, "appEntry": "./BigNet/startNetwork.js", from the BigNet/configStart.json file in the repository.

After starting DApp, the contract will be deployed to the network, and its address will be displayed on the screen.

Deploy by API

To deploy by API, use the method deployContract

Request:

POST contracts/ecma/deployContract

  • resourceRent - Number (from 0). Amount of tokens using for resources rent
  • source - String. Smart contract source code in JavaScript

Response:

Block object with new deploy contract block

Contract interaction

From DApp

To interact with contracts in the IZZZIO network we recommend to use the ecmaContracts methods from the DApp SDK. For example, to get the total number of existing token contract tokens, you can use the method:

let supply = await that.contracts.ecmaPromise.callMethodRollback(CONTRACT_ADDRESS, 'totalSupply', [], {});

Calling this method calls the totalSupply method from the contract. After completion of execution, the state of the contract is rolled back to the state before calling, and the value returned by the totalSupply method is returned, i.e. total number of existing tokens.

To interact with some standard contract formats there are built-in wrapper classes that make it easier to call methods and get properties. For example for IZ3 Token the wrapper class is TokenContractConnector. You can use it like this:

let token = new TokenContractConnector(that.ecmaContract, CONTRACT_ADDRESS);

//Analog for callMethodRollback(CONTRACT_ADDRESS, 'totalSupply', [], {});
let supply =  await token.totalSupply();

//Creates transaction for 10 tokens
await token.transfer(SOME_ADDRESS,'10');