Reference

Overview

aergo smart contract uses Lua, a lightweight scripting language, as a smart contract language. The following is an example of a simple coin stack smart contract written in Lua that stores key-value values ​​in a block-chain state store and reads the values.

-- Storing key-values ​​in the state store
function set(key, value)
    system.setItem(key, value);
end

-- Returns the value corresponding to the key in the state store
function get(key)
    return system.getItem(key);
end
​
-- Output the hash value of the previous block. The output is printed on the server log.
function printPrevBlock()
    system.print(system.getPrevBlockHash());
end

-- Functions to be called for contract declare as abi
abi.register(set, get, printBlock)

To read and write data on a block chain within a contract, you must use a system package. In the above example, smart contract provides the function to access the key-value repository through the setItem and getItem functions of the system package and store the data permanently. In addition, a simple debug message can be output to the log file of the node via the print function.

system package

This packages provides blockchain information and store/get state

getSender()

This function returns caller address of current contract

getBlockheight()

This function returns the block number that contains the current contract transaction.

getTxhash()

This function returns the id of the current contract transaction.

getTimestamp()

This function returns the creation start time of the block that contains current contract transaction.

getContractID()

This function returns the current contract address.

setItem(key, value)

This function sets the value corresponding to key to the storage belonging to current contract

  • restriction
    • key type string only (number type is implicitly converted to string)
    • value type available : number, string, table

getItem(key)

This function returns the value corresponding to key in storage belonging to current contract

  • If there is no value corresponding to key, it returns nil.

getAmount()

This function returns number of AER sent with contract call. Return type is string.

getCreator()

This function returns creator address of current contract

getOrigin()

This function returns sender address of current transaction

getPrevBlockHash()

This function returns the hash of the previous block

isContract(address)

This function return if address is contract then true else false. when address is invalid then raise error

contract package

This packages provides contract operation

send(address, amount)

This function transfers the coins in this contract by address and amount(in AER units). Amount form can be string, number, bignum.

contract.send("Amh4S9pZgoJpxdCoMGg6SXEpAstTaTQNfQdZFsE26NpkqPwmaWod", 1)
contract.send("Amh4S9pZgoJpxdCoMGg6SXEpAstTaTQNfQdZFsE26NpkqPwmaWod", "1 aergo 10 gaer")
contract.send("Amh4S9pZgoJpxdCoMGg6SXEpAstTaTQNfQdZFsE26NpkqPwmaWod", bignum.number("999999999999999"))

deploy(code, args…)

The deploy function creates a contract account using code and args, and returns the corresponding address and the return of the constructor function

  • If you use an existing address instead of code, deploy it with the code of the address.
  • In addition, can call the value function to send a coin. Value function can get string, number, bignum argument like send function.
    src = [[
        function hello(say)
            return "Hello " .. say .. system.getItem("made")
        end
        function constructor(check)
            system.setItem("made", check)
        end
        abi.register(hello)
        abi.payable(constructor)
    ]]
    addr = contract.deploy.value("1 aergo")(src, system.getContractID())

call(address, function_name, args…)

The call function returns the result of the function of the contract being executed in the state of the corresponding address.

  • In addition, can call the value function to send a coin. Value function can get string, number, bignum argument like send function.
contract.call("Amh4S9pZgoJpxdCoMGg6SXEpAstTaTQNfQdZFsE26NpkqPwmaWod", "inc", 1)
contract.call.value(10)("Amh4S9pZgoJpxdCoMGg6SXEpAstTaTQNfQdZFsE26NpkqPwmaWod", "inc", 2)

Restrictions

Before the fee system for smart contract is applied to mainnet, there are the following restrictions

  • limit the call depth of call or delegatecall in one transaction to 5

delegatecall(address, function_name, args…)

The delegatecall function returns the result of the function of the calling process, executed in the state in the current address.

contract.delegatecall("Amh4S9pZgoJpxdCoMGg6SXEpAstTaTQNfQdZFsE26NpkqPwmaWod", "inc", 1)

Restrictions

Before the fee system for smart contract is applied to mainnet, there are the following restrictions

  • limit the call depth of call or delegatecall in one transaction to 5

pcall(fn, args…)

It is an error handling function that works just like pcall in lua. The difference is that when the error occurs, the modified state,table or balance of the function executed rollback

success = contract.pcall(contract.send, "Amh4S9pZgoJpxdCoMGg6SXEpAstTaTQNfQdZFsE26NpkqPwmaWod", "1 AERGO")
if success == false then
    return 0
end
return 1

balance(address)

This function return balance of the address(argument) in AER. return type is string. If address is nil then return balance of current address.

contract.balance() --get balance of current contract address 
contract.balance("Amh4S9pZgoJpxdCoMGg6SXEpAstTaTQNfQdZFsE26NpkqPwmaWod")

event(eventName, args…)

This function causes eventName and args to remain in the contract result receipt. The user can search for event and receive notification the event with rpc when the receipt is added to the blockchain.

contract.event("send", 1, "toaddress") 

Restrictions

Before the fee system for smart contract is applied to mainnet, there are the following restrictions

  • limit length of event name to 64
  • limit size of event argument to 4k
  • limit the number of events in one transaction to 50

Search event and receive notification with aergocli

you can search for events with event name “send” in the contract address(AmhbdCEg4TUFm6Hpdoz8d81eSdzRncsekBLN3mYgLCbAVdPnu1MZ)

./aergocli event list --address AmhbdCEg4TUFm6Hpdoz8d81eSdzRncsekBLN3mYgLCbAVdPnu1MZ --event send

you can search for events with event argument 0 is 1 and argument 1 is “toaddress” in the contract address(AmhbdCEg4TUFm6Hpdoz8d81eSdzRncsekBLN3mYgLCbAVdPnu1MZ)

./aergocli event list --address AmhbdCEg4TUFm6Hpdoz8d81eSdzRncsekBLN3mYgLCbAVdPnu1MZ --argfilter '{"0":1, "1":"toaddress"}'

you can get notified for events with event name “send” for contract(AmhbdCEg4TUFm6Hpdoz8d81eSdzRncsekBLN3mYgLCbAVdPnu1MZ)

./aergocli event stream --address AmhbdCEg4TUFm6Hpdoz8d81eSdzRncsekBLN3mYgLCbAVdPnu1MZ --event send

stake(amount), unstake(amount), vote([bps,…])

you can do governance(stake, unstake, vote) in contract with contract address

contract.stake("1 aergo") 
contract.vote(["<bp1 address>", "<bp2 address>"....)
contract.unstake("1 aergo")

Built-in Functions

Lua provides the language itself as a useful function and basic package. It provides useful functions such as string management functions, so you can easily create smart contracts using these functions. Please refer to the Lua Reference Manual for detailed syntax, explanation, basic built-in functions and packages.

Since Lua Smart Contract is performed in Blockchain, OS related functions including input / output are not provided for stability and security.

Here is a list of the main functions that are not available.

print, loadstring, dofile, loadfile and module

Here is a list of the default packages that are not available.

coroutine, io, os and debug

The string, math, and table packages are available. However, you can not use the random, randomseed functions in the math package.

DB package

If the smart contract is handling simple types of data, it would not be difficult to implement using only the basic APIs (getItem (), setItem ()). However, complex data structures, data association, scope queries, filtering, sorting, and other features require the complexity and size of the data logic so developers can not focus on critical business logic. To solve this problem, Aergo supports SQL. This section details the types and usage of SQL APIs available in smart contracts

Note: The db package is only available on private networks(SQL TestNet).

exec(sql)

This function perform DDL or DML statements

query(sql)

This function perform SELECT statements and return result set object

prepare(sql)

This function create prepared statement and return statement object

-- create customer table 
function createTable()
  db.exec([[create table if not exists customer(
        id text,
        passwd text,
        name text,
        birth text,
        mobile text
    )]])
end

function insert(id, passwd, name, birth, mobile)
  db.exec("insert into customer values (?, ?, ?, ?, ?)",
      id, passwd, name, birth, mobile)
end

functions of result set object

Object functions must be called with the: operator

get

This function return result row

function query(id)
  local rt = {}
  local rs = db.query("select * from customer where id like '%' || ? || '%'", id)
  while rs:next() do 
    local col1, col2, col3, col4, col5 = rs:get()
    local item = {
        id = col1,
        passwd = col2,
        name = col3,
        birth = col4,
        mobile = col5
    }
    table.insert(rt, item)
  end
  return rt
end

functions of prepared statement object

equivalent to the prepareStatement object in JDBC. You can use the parameters in SELECT or DML to view, add, modify, or delete information.

query(bind1 , bind2, ….)

This function execute SELECT statement by specifying argument value corresponding to bind parameter and return result set object

exec(bind1, bind2, ….)

This function execute DML statement by specifying argument value corresponding to bind parameter

SQL Restrictions

Smart Contract’s SQL processing engine is built on SQLite. Therefore, detailed SQL usage grammar can be found at https://sqlite.org/lang.html and https://sqlite.org/lang_corefunc.html. However, because of the stability and security of the Aergo, not all SQL is allowed.

types

Allow only SQL datatypes corresponding to Lua strings and numbers (int, float).

  • text
  • integer
  • real
  • null
  • date, datetime

SQL statement

The allowed SQL statements are listed below. However, DDL and DML are only allowed in smart contract transactions.

  • DDL
    • TABLE: ALTER, CREATE, DROP
    • VIEW: CREATE, DROP
    • INDEX: CREATE, DROP
  • DML
    • INSERT, UPDATE, DELETE, REPLACE
  • Query
    • SELECT

Function

The following is an unavailable list

  • Data and time related functions can be used except ‘now’ timestring and ‘localtime’ modifier
  • load_XXX function
  • random function
  • sqlite_XXX function

For a list of other functions and descriptions, please refer to the links below.

Constraint

The following constraints can be used.

  • NOT NULL
  • DEFAULT
  • UNIQUE
  • PRIMARY KEY(FOREIGN KEY)
  • CHECK
function init_database()
    db.exec("drop table if exists customer")
    db.exec("create table if not exists customer (cid integer PRIMARY KEY ASC AUTOINCREMENT , passwd text , cname text, birthdate date, rgdate date)")
    db.exec("insert into customer (cid, passwd, cname, birthdate, rgdate) values (100 ,'passwd1','홍길동', date('1988-01-03'),date('2018-05-30'))")
    db.exec("insert into customer (passwd, cname, birthdate, rgdate) values ('passwd2','김철수', date('1978-11-03'),date('2018-05-30'))")
    db.exec("insert into customer (passwd, cname, birthdate, rgdate) values ('passwd3','이영미', date('1938-04-23'),date('2018-05-30'))")

    db.exec("drop table if exists product")
    db.exec("create table if not exists product (pid integer PRIMARY KEY ASC AUTOINCREMENT, pname text, price real, rgdate date)")
    db.exec("insert into product (pid, pname, price, rgdate) values (1000 ,'사과',1000, date('2018-05-30'))")
    db.exec("insert into product (pname, price, rgdate) values ('수박',10000, date('2018-05-30'))")
    db.exec("insert into product (pname, price, rgdate) values ('포도',3500, date('2018-05-30'))")

    db.exec("drop table if exists order_hist")
    db.exec("create table order_hist (oid integer PRIMARY KEY ASC AUTOINCREMENT, cid integer, pid integer, p_cnt integer, total_price real, rgtime datetime, FOREIGN KEY(cid) REFERENCES customer(cid), FOREIGN KEY(pid) REFERENCES product(pid) )")
    db.exec("insert into order_hist(oid, cid, pid,  p_cnt, total_price,rgtime) values(10000,100,1000,3,3000, datetime('2018-05-30 16:00:00'))")
    db.exec("insert into order_hist(cid, pid, p_cnt, total_price, rgtime) values(100,1000,3,3000, datetime('2018-05-30 17:00:00'))")
    db.exec("insert into order_hist(cid, pid, p_cnt, total_price, rgtime) values(100,1000,3,3000, datetime('2018-05-30 18:00:00'))")
end

json package

Json package is provided for user convenience in input and output. This package allows automatic conversion between Json format strings and Lua Table structures.

encode(arg)

This function returns a JSON-formatted string with the given lua value.

decode(string)

This function converts a string in JSON format to the corresponding Lua structure and returns it

crypto package

sha256(arg)

This function compute the SHA-256 hash of the argument.

ecverify(message, signature, address)

This function verify the address associated with the public key from elliptic curve signature.

function validate_sig(data, signature, address)
    msg = crypto.sha256(data)
    return crypto.ecverify(msg, signature, address)
end

bignum package

Since the lua number type has a limit on the range that can be represented by an integer (less than 2 ^ 53), the bignum module is used to provide an exact operation for larger numbers.

  • Notice
    • == Operations on bignum and other types always return false.
    • Bignum does not allow a decimal point.
    • Bignum value range : -(2^256 - 1) ~ (2^256 -1)

number(x)

This function make bignum object with argument x(string or number)

isneg(x)

Check bignum x if negative than return true else false

iszero(x)

Check bignum x if zero than return true else false

tonumber(x)

Convert bignum x to lua number

tostring(x) (bignum.tostring(x) same as tostring(x))

Convert bignum x to lua string

neg(x) (same as -x)

Negate bignum x and return as bignum

sqrt(x)

Returns the square root of a positive number as bignum. not permitted negative value to x

compare(x, y)

Compare two big numbers. Return value is 0 if equal, -1 if x is less than y and +1 if x is greater than y.

add(x, y) (same as x + y)

Add two big numbers and return bignum

sub(x, y) (same as x - y)

Subtract two big numbers and return bignum

mul(x, y) (same as x * y)

Multiply two big numbers and return bignum

mod(x, y) (same as x % y)

Returns the bignum remainder after bignum x is divided by bignum y

div(x, y) (same as x / y)

Divide two big numbers and return bignum

pow(x, y) (same as x ^ y)

Power of two big numbers and return bignum. not permitted negative value to y

divmod(x, y)

Returns a pair of big numbers consisting of their quotient and remainder

powmod(x, y, m)

Return the bignum remainder after pow(bignum x,bignum y) is divided by bignum m. not permitted negative value to y

isbignum(x)

Return true if x is bignum else false

tobyte(x)

Return byte string of bignum x. not permitted negative value to x

frombyte(x)

Return bignum from byte string x

function factorial(n,f)
 for i=2,n do f=f*i end
 return f
end
for i=1,30 do
  local b=factorial(i,bignum.number(1))
  return bignum.mod(b, 10)
end