Telegram Open Network Node SE Setup using Docker with Contract Deployment
By: Sunil Hirole
Tags: Blockchain, Telegram Open Network, Smart Contracts, Telegram, Solidity

After completing the above setup, now we can deploy, run and query smart contracts using TON client.

Contract Deployment

In order to deploy the smart contract on TON Blockchain, first we need to create and compile the smart contract. The necessary elements are a compatible TVM code and an ABI structure. Both elements were obtained at the compilation stage.

Now let's create a folder called contracts and inside contracts folder create a file hello.sol for our smart contract and paste the below code in it.

pragma solidity ^0.5.4; contract HelloTON {

uint32 timestamp; // Modifier that allows public function to accept all external calls.

modifier alwaysAccept {

tvm_accept();

_;

}

// Runtime function that allows contract to process inbound messages spending

// it's own resources (it's necessary if contract should process all inbound messages,

// not only those that carry value with them).

function tvm_accept() private pure {} constructor() public {

timestamp = uint32(now);

}

//Function setting set value to state variable timestamp

function touch() external alwaysAccept {

timestamp = uint32(now);

}

//Function returns value of state variable timestamp

function sayHello() external view returns (uint32) {

return timestamp;

}

}

Next, we need to compile our smart contract. Run TON labs Sol2TVM compiler.

tondev sol hello -l js -L deploy

Sol2TVM compiler compiles smart contracts written in Solidity to TVM assembly

-l js option is used to generate JavaScript client helper code for the compiled contract.

-L deploy is used to include an imageBase64 field into the generated JavaScript contract client code.

L deploy with js flag generates a Javascript file helloPackage.js with a contract wrapper class. This wrapper contains methods for deploying and calling the contract functions. It contains a deploy method that is used to deploy the contract. The class contains two methods for each contract function, one is named as the function itself, the other as function_nameLocal . The use of these two function will be explained in the next section. The class has the package static variable that stores two fields: abi and imageBase64 .

Need to generate key pair when a contract is deployed. You can also use an existing key pair to deploy the contract.

Save the keys post generation. It is required to call contract functions.

Now our contract is ready to deploy. In TON Blockchain you must deposit tokens to the address of the deployed contract before the actual deploy. Otherwise deploy will fail.

We can either deploy our own giver or use local giver provided by TON local node. For now, we are using local giver provided by TON local node.

In order to use Node SE pre-deployed giver, we need to use the below address and ABI in our project.

const giverAddress = '0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94';

const giverAbi =

{

"ABI version": 1,

"functions": [

{

"name": "constructor",

"inputs": [],

"outputs": []

},

{

"name": "sendGrams",

"inputs": [

{"name":"dest","type":"address"},

{"name":"amount","type":"uint64"}

],

"outputs": []

}

],

"events": [],

"data": []

};

Update the index.js file that we created previously with the below code. The get_grams_from_giver function is used to get test grams from giver to deploy the smart contract.

const { TONClient } = require('ton-client-node-js');

// ABI and imageBase64 of a binary Hello contract

const HelloContract = require('./HelloContract.js');



//address of giver on NodeSE

const giverAddress = '0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94';

//giver ABI on NodeSE

const giverAbi =

{

'ABI version': 1,

'functions': [

{

'name': 'constructor',

'inputs': [],

'outputs': []

},

{

'name': 'sendGrams',

'inputs': [

{'name': 'dest', 'type': 'address'},

{'name': 'amount', 'type': 'uint64'}

],

'outputs': []

}

],

'events': [],

'data': []

};



//Requesting 1000000000 local test nanograms from Node SE giver

async function get_grams_from_giver(client, account) {

//console.log(account);

const {contracts, queries} = client;

await contracts.run({

address: giverAddress,

functionName: 'sendGrams',

abi: giverAbi,

input: {

dest: account,

amount: 1000000000

},

keyPair: null,

});

} async function main(client) {

}

try {

const client = new TONClient();

client.config.setData({

servers: ['

});

await client.setup();

await main(client);

console.log('TON client connected to local node');

process.exit(0);

} catch (error) {

console.error(error);

}

})(); (async () => {try {const client = new TONClient();client.config.setData({servers: [' http://0.0.0.0' });await client.setup();await main(client);console.log('TON client connected to local node');process.exit(0);} catch (error) {console.error(error);})();

In next step we need to generate the future address of contract where it gets deployed. To generate future address add the below code in main function of index.js file.

async function main(client) {

//Generating public and secret key pairs

let helloKeys = await client.crypto.ed25519Keypair();

//Receiving future Hello contract address

const futureAddress = (await client.contracts.createDeployMessage({

package: HelloContract.package,

constructorParams: {},

keyPair: helloKeys,

})).address;



console.log(`Future address of the contract will be: ${futureAddress}`); }

After generating the future address of the contract, we need to send some test grams to that address for contract deployment. Update the main function with the below code.

async function main(client) {

//Generating public and secret key pairs

let helloKeys = await client.crypto.ed25519Keypair();

//Receiving future Hello contract address

const futureAddress = (await client.contracts.createDeployMessage({

package: HelloContract.package,

constructorParams: {},

keyPair: helloKeys,

})).address;



console.log(`Future address of the contract will be: ${futureAddress}`);



//Requesting contract deployment funds form a local NodeSE giver

await get_grams_from_giver(client, futureAddress);

console.log(`Grams were transfered from giver to ${futureAddress}`); }

In TON Blockchain we need to deposit tokens to the address of the deployed contract before the actual deploy.

Now our contract is ready for deployment. Simply update the below code in main function to deploy the contract.

async function main(client) {

//Generating public and secret key pairs

let helloKeys = await client.crypto.ed25519Keypair();

//Receiving future Hello contract address

const futureAddress = (await client.contracts.createDeployMessage({

package: HelloContract.package,

constructorParams: {},

keyPair: helloKeys,

})).address;



console.log(`Future address of the contract will be: ${futureAddress}`);



//Requesting contract deployment funds form a local NodeSE giver

await get_grams_from_giver(client, futureAddress);

console.log(`Grams were transfered from giver to ${futureAddress}`);

//Deploy requires a fee to be paid

const helloAddress = (await client.contracts.deploy({

package: HelloContract.package,

constructorParams: {},

keyPair: helloKeys,

})).address;

console.log(`Hello contract was deployed at address: ${helloAddress}`); }

To deploy the contract simply run the node application and check the result.

node index.js

Hello contract was deployed at address: 516c7a2bc72c5728526eb73064da07a2876d964c3da5ed2488e1aba3da20be3f

Running a contract

Calling the contract functions is quite simple using TON client

async function main(client) {

//Generating public and secret key pairs

let helloKeys = await client.crypto.ed25519Keypair();

//Receiving future Hello contract address

const futureAddress = (await client.contracts.createDeployMessage({

package: HelloContract.package,

constructorParams: {},

keyPair: helloKeys,

})).address;



console.log(`Future address of the contract will be: ${futureAddress}`);



//Requesting contract deployment funds form a local NodeSE giver

await get_grams_from_giver(client, futureAddress);

console.log(`Grams were transfered from giver to ${futureAddress}`); //Deploy requires a fee to be paid

const helloAddress = (await client.contracts.deploy({

package: HelloContract.package,

constructorParams: {},

keyPair: helloKeys,

})).address;

console.log(`Hello contract was deployed at address: ${helloAddress}`);



const response = await client.contracts.run({

address: helloAddress,

abi: HelloContract.package.abi,

functionName: 'touch',

input: {},

keyPair: helloKeys,

});

console.log('Hello contract was responded to touch:', response.transaction.id);



const localResponse = await client.contracts.runLocal({

address: helloAddress,

abi: HelloContract.package.abi,

functionName: 'sayHello',

input: {},

keyPair: helloKeys,

});

console.log('Hello contract was ran on a client TVM and also responded to sayHello:', localResponse);

}

Note that sayHello is the getter function and it should be called via runLocal or sayHelloLocal , so as not to waste gas. But if you want to call the function via run, add tvm_accept() to the beginning of the sayHello function.

Thanks for reading. Hopefully, this guide has been useful to you and will help you to understand TON Blockchain network setup and contract deployment.