This is the 2nd article in our series on integrating payment channels on Telegram Open up Network. In the starting time part, we introduced the network, detailed our experience of the competition, and explained how synchronous and asynchronous smart contracts piece of work. Every bit the next improver to the series, this commodity details how we built a synchronous payment channel on the network during TON'south contest dorsum in September. Hither, nosotros volition be talking but about Fift (TON's full general-purpose programming linguistic communication) and FunC (TON's programming language for writing smart contracts).

The TON white newspaper provides more in-depth information about payment channels, but we will briefly explain them again.

Related: Behind the Scenes of TON: Lessons Learned on Deploying Smart Contracts, Part ane

A synchronous payment channel allows sending transactions between two users off-chain using on-chain assets. In our case — GRAMs. It is impossible for ane party to cheat the other off-concatenation, and transactions are made much faster than executing layer-one blockchain transactions, equally only user devices are used to complete them without having to write to the blockchain. At that place are 2 basic operations: eolith and withdraw. The withdrawal is the nigh challenging one to implement.

To make a correct withdrawal, users need to provide the latest information well-nigh the state of their channel. The state consists of the steps and digital signatures of each participant, which ways it's not possible to provide a correct state with data that has not been approved by both parties.

To deploy a smart contract, you need to write a deploy script in Fift and compile it to a .boc (purse of cells) file. Doing this makes multiple cells that will be linked to each other. GRAMs then need to be sent to the address that was received during deploy script execution. Once GRAMs are on the address, send the .boc file to the network and the contract will be deployed.

To make a function call, write a script that volition send an external bulletin to the deployed smart contract.

Basically, anything on TON is a cell with some references. A bag of cells is a data construction that was designed by the Telegram team. It is an thespian model. More details are at TON whitepaper: "everything is a bag of cells." You are building a cell that volition interact with another prison cell when information technology is deployed.

Each peer-to-peer payment channel is a unmarried smart contract. Let'due south accept a expect at the segments of a smart contract.

Related: What to Expect From the Telegram Open Network: A Developer's Perspective

Deployment part

A serialized Fift script is used to deploy a contract. It is saved to a .boc file and sent to the network via TON Cli, the network's low-cal customer.

The latest cell on the stack is the result of executing the in a higher place Fift script.

The usual segments of a Fift deploy script include (but are non limited to):

  1. Lawmaking of the smart contract equally a single cell (unremarkably written in FunC, so compiled into Fift ASM code and included in the principal .fif file using path-to-compiled-asm.fif).
  2. Initial storage of the smart contract (see beneath).
  3. New smart contract address (the hash from the initial state of the smart contract that also includes the smart contract code cell and the initial storage jail cell).
  4. Arguments of the outset call of the recv_external function (the amount of arguments and type depends on the contract).
  5. An external message cell for initialization, which will exist serialized into bytes and packed to the .boc file, which consists of all the information from points 1–iv and some additional ones that are nevertheless lacking documentation.

When the .boc is compiled, a specific amount of GRAMs demand to be sent to the smart contract address. The .boc file must be sent to the network to initialize the smart contract. The corporeality of GRAMs depends on the size and volume of calculations of the deployed smart contract's external message cell (not just the code of it). Gas × gas price is taken from the deployed smart contract residual. This amount is the minimum needed to pay for gas during the deployment.

A representation of the storage:

  1. seqno 32 bits
  2. contract_status four bits
  3. first_user_pubkey. The first party's public key 256 bits
  4. second_user_pubkey. The 2d party's public key 256 bits
  5. time_to_send. Time to ship after the first actual country being submitted 32 bits (valid until 2038)
  6. depositSum. The deposited sum of two participants upwardly to 121 bits
  7. state_num 64 bits. The current amount of states that occurred

A cell contains up to 1023 bits and four references to other cells. We were able to fit the unabridged storage onto i cell without a unmarried reference. Our storage can have upwardly a maximum of 765 bits.

All smart contract states

0x0 — Deployment state

0x1 — Channel opened and set up for deposit

0x2 — Deposit by user i

0x3 — Deposit by user 2

0x4 — The eolith is blocked. Information technology is possible to provide a state to the smart contract

0x5 — User 1 has provided the country

0x6 — User two has provided the land

0x7 — The channel is closed

Depositing

The deposit function receives a bulletin from a simple wallet (transfer) with an boosted body payload.

Depositing GRAMs to the channel:

  1. The user generates an additional body payload that includes a message (for case, ane fleck) and its signature in a separate .fif file.
  2. Body payload is compiled to a .boc file.
  3. Trunk payload is loaded from this .boc file into a .fif file as a body-jail cell "transferring" reference (the .fif is responsible for transferring GRAMs from the wallet).
  4. The recv_external office is chosen with arguments (the deposit amount and the destination accost of the channel) when the compiled .fif file is sent to the network.
  5. The send_raw_message function is executed. Deposited GRAMs and boosted body payload is sent to a P2P channel smart contract destination accost.
  6. The recv_internal part of the P2P channel smart contract is called. GRAMs are received past channel contracts.

The eolith function can be called if the state of the P2P channel smart contract is 0x1 or 0x2 or 0x3.

FunC code that checks the state:

1

Only the owners of the public keys (written in the initial storage) are allowed to brand a deposit. The smart contract checks the signature of each internal message that will exist received through the recv_internal part. If the message is signed by one of the public key owners, the contract status changes to 0x2 or 0x3 (0x2 if it is public fundamental 1 and 0x3 if it is public primal 2). If all users take fabricated a deposit, the contract status changes to 0x4 on the same office call.

The FunC code responsible for irresolute contract status:

2

Refund

Funds tin can be returned if a counterparty has non made a eolith on fourth dimension.

To practise that, a user needs to provide their address and signature via external message. The funds will be refunded if the provided signature belongs to public key 1 or public key 2 (persons who made a deposit) and the contract condition is 0x2 or 0x3.

FunC lawmaking that is responsible for verifying the refund application:

3

Withdrawal

Each person should provide an get out state, the signature of this state, and signature of the body message.

Country details:

  1. Smart contract address (to exclude the possibility of entering the correct country from the previous P2P channel with the aforementioned participants).
  2. The final balance of the first participant.
  3. The terminal residuum of the second participant.
  4. State number.

The body message signature is stored in the main slice, the state is stored in a separate reference, and land signatures are stored as references to a "signatures" reference to avert cell overflow.

Withdrawal steps:

  1. Cheque the trunk message signature and determine the participant.

4

  1. Check that it is the turn of the participant or 24 hours accept passed since the last entered state. Write the plough of the current participant (0x5 or 0x6) to the contract condition.

An example of a right signature of the body message for the owner of first_user_pubkey:

5

Nosotros then need to verify that the smart contract accost written to the land is the actual contract address:

6

Next, we need to verify signatures nether the state:

7

After that, at that place are 2 assertions:

  1. The deposited corporeality from the storage should be equal to the sum of the total balances of the participants.
  2. The new entered state number must be greater than or equal to the previous one.

8

In case of new_state_num > state_num we need to store new_state_num with the new time_to_send equaling to now() + 86401 (24 hours from the current fourth dimension), and too write the actual contract status (0x5 if first participant made a phone call, otherwise 0x6).

In another case, if new_state_num == state_num we demand to put an boosted two references to the "signatures" reference with addresses of each participant and signatures under their addresses.

If the signatures are correct, GRAMs are withdrawn from one accost and put into the owner'south address.

9

Each fourth dimension a successful call happens, we need to store all storage data fifty-fifty if it doesn't change.

Unsolved issues

The assumption is that the showtime user deployed the contract and the participants agreed on commissions. The agreement on commissions in our example is reaching off-chain.

We have non yet figured out how to summate the total commission, taking into account the fact that players can write an irrelevant land and record actual states after that. Keep in mind that we need to pay fees from the P2P channel smart contract each time we successfully call recv_internal or recv_external functions.

As mentioned earlier, nosotros need to add some amount of GRAMs to a non-bounceable future smart contract accost in order to initialize it.

On the terminal day of the competition, TON's developers made a commit to the stdlib.fc library with a new office that allows getting the actual smart contract balance.

10

Suggestions for possible solutions to this problem are welcome!

Determination

FunC and Fift allow any developer admission to the low-level world of software technology, opening new opportunities and features for blockchain developers who have already gotten used to Ethereum or any other smart contract platform. It is important that TON is a sharded blockchain, and then implementing smart contracts on it is more challenging. For example, Ethereum'southward contracts run synchronously and practice non require handling situations such as waiting for an respond from another contract.

The asynchronous fashion of smart contract communication is the only option to make it scalable, and TON has these options. Our solution concluded up existence more hard to implement than Solidity, but at that place is always a trade-off. It is definitely possible to build an avant-garde smart contract on TON, and the way that TON'southward team handled it is very impressive. Nosotros are looking forward to seeing more libraries and tools that will help to deploy and build FunC contracts.

We thoroughly enjoyed all the tasks and wish that we'd had more time to implement all of them. Still, we won two prizes at TON Competition: beginning place for all-time synchronous payment channel as well as 3rd place for all-time asynchronous payment aqueduct.

Nosotros volition share our own personal feedback in part three.

The views, thoughts and opinions expressed here are the authors' alone and do not necessarily reflect or stand for the views and opinions of Cointelegraph.

This commodity was co-authored by Nick Kozlov and Kirill Kuznetsov.

Nick Kozlov is the CTO and co-founder of Button Wallet, a software developer and researcher, also every bit one of the winners of the TON competition.

Kirill Kuznetsov is the co-founder of Push Wallet, as well as i of the winners of the TON contest.