Amoveo’s Smart Contracts

Tallak Tveide
6 min readOct 29, 2018

--

By Cryteria — Own work, CC BY 3.0, https://commons.wikimedia.org/w/index.php?curid=11651154

Amoveo is a new blockchain project featuring programmable state channels, on-chain oracles, financial derivatives and more. In this post I will look at the way smart contracts in channels are implemented, which is quite different. So start by forgetting everything you know about programming smart contracts for other blockchains.

This article attempts to describe Amoveo state channel smart constracts in broad terms. We will not discuss why you would want to use state channels. We will also not discuss the Amoveo smart contract language called Chalang, a functional language without the goto opcode in the VM, making it easier to analyze. As you will see later, Amoveo contracts, in their nature, are easy to reason about, because they have no state outside the code.

As the state channels in Amoveo are cryptoeconomically secure, it is worthwhile for both participants to cooperate. Both sign the transactions [TX] to put money into and later extract it from of the channel. Being cryptoeconomically secure means that both parties must put money in the channel that is only redeemable by cooperating. When the parties are cooperating, no code is stored on-chain. Instead both parties attest that the money in the channel is divided in a certain way upon closing the channel. This involves a channel_new TX, where participants insert money into the channel, and the channel_team_close TX that divides the channel balance among the participants. Both of these TX are signed by both participants. This is the simple scenario and probably will be the most common scenario, and no code ever goes on-chain.

If the parties cannot agree upon a funds split, we are left with a scenario where the channel_new TX still exists, but we need a channel_solo_close TX to initiate a close by only one party. Following this TX, additional channel_slash TX may be added providing a newer code for the state channel. There will be a period where the channel funds are frozen to allow the other participant to react. The channel may be closed with a channel_timeout TX, after which funds are transferred from the channel into the two participant’s accounts. In this scenario, the channel_solo_close and channel_slash will contain the latest agreed upon code from the channel. All Amoveo servers may independently validate the outcome of the code as part of processing the blockchain.

This is the mechanism of state channel interaction with the blockchain. Now lets look at how the code is actually executed and instanciated in the state channel, and how state is maintained in the channel.

Using pseudocode, I’ll make a simple contract to make a bet on the outcome of an on-chain oracle. Note that this grossly simplified code will not work, but is meant to illustrate how these contracts operate. The contract runs without any inputs and returns three values: the delay for a single sided closing, a nonce and the movement of funds from one participant to the other (the participants being the better and the server, no market is assumed here).

# contract for betting on an oracle result
# returns {<delay period>, <nonce>, <amount to transfer>}
oracle = “jjFZnjADflb4FzocON+Kboh5T+UHHfiw”case oracle_result(oracle) do
“unfinished” ->
nonce = 1
return {1 year, nonce, 0}
“bad question” ->
nonce = 1
return {0 days, nonce, 0}
“statement true” ->
nonce = 2
return {0 days, nonce, 1.0 VEO}
“statement false” ->
nonce = 2
return {0 days, nonce, -2.0 VEO}
end

First, notice that there is only code in the channel, and no state (which I find funny as they are called state channels). For this particular contract, there are three items that separate this code from a generic code: the oracle id, the amount of VEO to transfer if the oracle is true, and an amount for false (the last two defining the odds of the bet). The generic code could look something like:

# contract for betting on an oracle result
# returns {<delay period>, <nonce>, <amount to transfer>}
oracle = <oracle-id>case oracle_result(oracle) do
“unfinished” ->
nonce = 1
return {1 year, nonce, 0}
“bad question” ->
nonce = 2
return {0 days, nonce, 0}
“statement true” ->
nonce = 2
return {0 days, nonce, <amount-if-true> VEO}
“statement false” ->
nonce = 2
return {0 days, nonce, -<amount-if-false> VEO}
end

How do the two parties agree upon which code to sign? They both have to be able to come up with the exact same code, so that they may both sign the hash of the contract. This means that once the two parties agree upon <oracle_id>, <amount-if-true> and <amount-if-false>, they have to both have access to the generic contract and generate a specific contract to sign.

If one party is the Amoveo node hosting the bet, and the other is the user using the web wallet, the use case would play out like this:

  • The user enters the oracle id and the two amounts in a form
  • The web wallet puts the values of the form into the generic code and signs it (providing a signature and a hash of the code)
  • The web wallet submits the values and the signed code to the server
  • The server uses the values and it’s own generic code and verifies that the hash matches
  • The server signs the code also, and returns the signature to the web wallet

Because no party should trust the other to produce the correct code for the channel smart contract, both the server and the web wallet must contain the generic contract and a way to replace parameter values.

So if the state channel does not contain state, could it even be very useful?

I’d like to make another example code that could support micropayments. The objective here is to have a user put money in a channel to get access to a service, eg. playing a game. VEO is charged per second of use, but you would not like to put all those TX on the blockchain. It is possible by injecting the state (the amount of seconds played) into the contract like this:

# contract for micropayments
# returns {<delay period>, <nonce>, <amount to transfer>}
nonce = 1
usage = 100
return {0 days, nonce, usage}

The game server and the game client would generate a new code every few seconds, containing the new accumulated usage. Both the server and client would sign these as time went by. The game player controls and trusts his game client software. The game server could never take any money that was not signed for by the player. The concrete code inserted into the channel would look like:

# contract for micropayments, at t = 10:00:00
# returns {<delay period>, <nonce>, <amount to transfer>}
nonce = 1
usage = 0
return {0 days, nonce, usage}
# contract for micropayments, at t = 10:00:10
# returns {<delay period>, <nonce>, <amount to transfer>}
nonce = 2
usage = 100
return {0 days, nonce, usage}
# contract for micropayments, at t = 10:00:20
# returns {<delay period>, <nonce>, <amount to transfer>}
nonce = 3
usage = 200
return {0 days, nonce, usage}

And so on. Only the latest code needs to be stored, as only the code with the highest nonce will be used to close the channel. Once the gamer is done playing, the channel may be closed and the funds distributed, resulting in a total of two transactions on-chain, none of them containing any code.

--

--