While we’re in process of final testing and preparations for the first mainnet release for smart accounts, let’s discuss further developments and how if can fit current waves model.
As per now, waves smart accounts are stateless predicates: they consume data from blockchain and either allow or deny outgoing transactions from an account. While powerful enough for basic needs like atomic swaps and multisigs, a general custom application(decentralized or not) needs to have state. Waves does allow accounts to have state via data transactions, and those data fields can be read from smart account, but up until this point, smart accounts can’t write any state.
Currently, smart account has 1 function that returns boolean. Let’s generalize this a little:
- Let’s allow an account to have multiple named functions.
- Let’s make this functions return special constructs which represent inner transactions, that will be issued upon function invocation
- Add a new type of transaction : ContractInvocationTransaction(accountAddress, functionName, functionArgs…)
So, contract code could look like:
contract {
def init() : List[Transaction] = {
List(DataTransaction("x", 0))
}
def add(x: int) : List[Transaction] = {
let oldValue = readInteger("x")
let newValue = state + x
List(DataTransaction("x", newValue))
}
def dec() : List[Tranaction] = {
let oldValue = readInteger("x")
if (oldValue == 0)
throw("can't make x < 0")
else
List(DataTransaction("x", oldValue - 1))
}
It this small example, we wrote a DApp that can modify contract state and rely on it in further calls(dec()
)
But why limit to DataTransactions? Let’s allow contract issue TransferTransaction
as well:
contract {
...
def withdrawAlice(amount: Int) : List[Transaction] = {
let aliceTotal= readInteger("alice")
if (aliceTotal >= amount)
List(
DataTransaction("alice", aliceTotal - amount),
TransferTransaction(..., amount, ...))
else throw("alice is eligible for less than $aliceTotal only")
}
def ....
def ....
}
Upon calling the contact, only ContractInvocationTransaction will be put to blockchain. The inner Datas,Transafers and what not will be generated in-place implicitly, hence won’t consume any space in blockchain. The emitted transactions will be processed as usual ones, but atomically: if Transfer
from the example is not allowed because contract has less than required, data change won’t happen either.
With this, we’ll onboard things like
- dapp state
- atomic transaction containers
-
payable
methods
While preserving the following
- no gas, predictable cost
- no major changes to compiler and executor engine
- functional approach within RIDE
What do you think?