Edit me

English / 中文

Deploy & invoke smart contract

Version 0.7.0

1. Deploy smart contract

This process needs to construct related transaction and send it to the blockchain.

Users should offer the contract’s content in hex string and some configuration parameters to construct the transaction.

Normally, contracts are stored in .avm files (for NEO VM) and .wasm files (for WASM VM).

The configuration parameters are as follow:

code contract’s content,hexadecimal string。

vmType type of virtual machine。Now we supports these types:

export enum VmType {
    NativeVM = 0xFF,
    NEOVM    = 0x80,
    WASMVM   = 0x90
}

name name of the contract, optional string value.

codeVersion version of the contract, optional string value.

author author of the contract, optional string value.

email email of the contract’s author, optional string value.

desp description of the contract, optional string value.

needStorage the contract needs storage or not. Default as true.

import * as core from '../src/core'

//get the content of the contract
var fs = require('fs')
var path = require('path')
let idContractAvm = fs.readFileSync(path.join(__dirname, '../src/smartcontract/data/IdContract.avm'))
var idContractAvmCode = ab2hexstring(idContractAvm)
var name = 'test',
	codeVersion = '1.0',
	author = 'alice',
	email = '',
	desp = '',
	needStorage = true;
//construct the transaction
var tx = core.makeDeployCodeTransaction(idContractAvmCode, VmType.NEOVm, name, codeVersion, author, email, desp, needStorage)
//send the transaction
var param = buildRestfulParam(tx)
var url = TEST_ONT_URL.sendRawTxByRestful
axios.post(url, param).then((res:any)=> {
	console.log('deploy res: '+ JSON.stringify(res.data))
	//check the result of deploying contract in 6 seconds
    setTimeout(function () {
    	getContract(code, vmType)
    }, 6000)
    }).catch(err => {
   	   console.log('err: '+ err)
})

//query the contract from blockchain.
const getContract = (avmCode, vmType=VmType.NEOVM) => {
    const codeHash = getContractHash(avmCode,vmType)
    let url = `${TEST_ONT_URL.REST_URL}/api/v1/contract/${codeHash}`
    console.log('url : '+ url)
    axios.get(url).then((res)=>{
        console.log(res.data)
    }).catch(err => {
        console.log(err)
    })
}

2. Invoke smart contract

You can not invoke smart contract before deploying it. Invoking contract needs to construct related transaction and send it to the blockchain.

2.1 Construct transaction with abi file

.abifile is in JSON format that describes the methods and parameters of the smart contract. We can construct the transaction to invoke contract easily with abi files. Some transactions may need to be signed with user’s privatekey.

There are some class related to abi in TS SDK.

class AbiInfo {
    hash : string
    entrypoint : string
    functions : Array<AbiFunction>
}

hash hash value of the contract. Also called contract address. It can be used to distinguish each contract.

entrypoint the entry function name of the contract.

functions the set of functions that the contract contains.

class AbiFunction {
    name : string
    returntype : string
    parameters : Array<Parameter>
}

name name of the function.

returntype the return type of the function.

parameters the parameters of the function.

class Parameter {
    name : string
    type : ParameterType
    value : any
}

name name of the parameter.

type type of the parameter.

value value of the parameter.

The function that constructs transaction to invoke contract needs parameters as follow:

function makeInvokeTransaction(funcName : string, parameters : Array<Parameter>, contractHash : string, vmType : VmType = VmType.NEOVM, fees : Array<Fee> = [])

funcName the function to be called in the contract.

parameters the parameters of the function.

contractHash the hash of the contract.

vmType the virtual machine type.

fees the fees required to send transaction.

Here is a example about invoking ONT ID smart contract to register ONT ID.

//read abi file. Here the file exports a JSON object.
import abiJson from '../smartcontract/data/idContract.abi'

//parse the abi content
const abiInfo = AbiInfo.parseJson(JSON.stringify(abiJson))

//get the AbiFunction
const abiFunction = abiInfo.getFunction('RegIdWithPublicKey')

const privateKey = '7c47df9664e7db85c1308c080f398400cb24283f5d922e76b478b5429e821b95'
const publicKey = '1202037fa2bbad721197da4f2882e4f8e4ef6a77dbc7cfbd72267cdd72dd60ac30b41e'
const ontid = '6469643a6f6e743a544d7876617353794747486e7574674d67657158443556713265706b6a476f737951'

//construct parameters. Notice that all the parameters are hex string here.
let p1 = new Parameter(f.parameters[0].getName(), ParameterType.ByteArray, ontid)
let p2 = new Parameter(f.parameters[1].getName(), ParameterType.ByteArray, publicKey)

//set parameters
abiFunction.setParasValue(p1, p2)

//construct transaction
let fees = []
let vmType = VmType.NEOVM
let tx = makeInvokeTransaction(abiFunction.name, abiFunction.parameters, abiInfo.hash, vmType, fees)

//sign the transaction.
signTransaction(tx, privateKey)

2.2 Construct transactions based on WASM vm

This process is mostly the same as above. Though we do not have abi files. We can use the same method as long as we can offer the exact function name and parameters.

const codeHash = '9007be541a1aef3d566aa219a74ef16e71644715'
const params = [
		new Parameter('p1', ParameterType.Int, 20), 
		new Parameter('p2', ParameterType.Int, 30)
	]
const funcName = 'add'
let tx = makeInvokeTransaction(funcName, params, codeHash, VmType.WASMVM)

2.3 Send transactions

There are multiple ways to send transactions.

2.3.1 Restful

//use the wrapped class
let restClient = new RestClient()
//use the transaction created before to build parameters
restClient.sendRawTransaction(tx.serialize()).then(res => {
    console.log(res)
})

The response of the request contains the hash of the transaction. We need to query the execution result of invoking the contract with the hash. A simple way is to query the result on Ontology’s blockchain browser.

2.3.2 Rpc

let rpcClient = new RpcClient()
rpcClient.sendRawTransaction(tx.serialize()).then(res => {
    console.log(res)
})

Rpc request is similar to Restful request. The response is also the transaction hash.

2.3.3 Websocket

We can use websocket to send transactions and listen to the messages. Notifications will be sent back if there are event push definitions in the contract.

let param = buildTxParam(tx)
let txSender = new TxSender(TEST_ONT_URL.SOCKET_URL)
//define the callback
//@param err : error result
//@param res : messages pushed from blockchain
//@param socket websocket object
const callback = (err, res, socket) => {
    if(err) {
        console.log(err)
        socket.close()
        return;
    }
    if(res.Action === 'Notify') {
        console.log('Notify: '+ JSON.stringify(res))
        socket.close()
    }
}
txSender.sendTxWithSocket(param, callback)