Skip to content

Inline Actions

In smart contracts, it is also possible to initiate an action, which is called an inline action. Note that actions are asynchronous, meaning that the contract code corresponding to the inline action is only called after the entire code has been executed. If the called contract has not defined the relevant action or if there is no deployed contract in the account, the call will have no effect, but no exceptions will be thrown. Even empty inline actions are not without any purpose, for they can be used as on-chain logs for application programs to query.

Here is the complete code for the Action class in action.codon:

@packer
class Action(object):
    account: Name
    name: Name
    authorization: List[PermissionLevel]
    data: bytes

    def __init__(self, account: Name, name: Name, data: bytes=bytes()):
        self.account = account
        self.name = name
        self.authorization = [PermissionLevel(account, n'active')]
        self.data = data

    def __init__(self, account: Name, name: Name, permission_account: Name, data: bytes=bytes()):
        self.account = account
        self.name = name
        self.authorization = [PermissionLevel(permission_account, n'active')]
        self.data = data

    def __init__(self, account: Name, name: Name, permission_account: Name, permission_name: Name, data: bytes=bytes()):
        self.account = account
        self.name = name
        self.authorization = [PermissionLevel(permission_account, permission_name)]
        self.data = data

    def __init__(self, account: Name, name: Name, authorization: List[PermissionLevel], data: bytes=bytes()):
        self.account = account
        self.name = name
        self.authorization = authorization
        self.data = data

    def send(self):
        raw = pack(self)
        send_inline(raw.ptr, u32(raw.len))

    def send(self, data: T, T: type):
        self.data = pack(data)
        raw = pack(self)
        send_inline(raw.ptr, u32(raw.len))

This class has three __init__ functions, which should be used according to needs. The following initialization function should be the most commonly used:

def __init__(self, account: Name, name: Name, data: bytes=bytes())

This function uses active authorization by default.

The following initialization function specifies which account's authorization to use, and also uses the active authorization of the account by default:

def __init__(self, account: Name, name: Name, permission_account: Name, data: bytes=bytes())

If a contract uses other authorizations, the following initialization function can be used:

def __init__(self, account: Name, name: Name, permission_account: Name, permission_name: Name, data: bytes=bytes()):

If an account has multiple authorizations, the following initialization function can be used:

def __init__(self, account: Name, name: Name, authorization: List[PermissionLevel], data: bytes=bytes()):

Example:

# action_example.codon
from packer import pack
from chain.action import Action, PermissionLevel
from chain.contract import Contract

@packer
class Person:
    name: str
    height: u64
    def __init__(self, name: str, height: u64):
        self.name = name
        self.height = height

@contract(main=True)
class MyContract(Contract):

    def __init__(self):
        super().__init__()

    @action('test')
    def test(self):
        a = Action(n'hello', n'test2')
        print('++++send test2 action')
        a.send("1 alice")

        a = Action(n'hello', n'test2', n'hello')
        print('++++send test2 action')
        a.send("2 alice")

        a = Action(n'hello', n'test2', n'hello', n'active')
        print('++++send test2 action')
        a.send("3 alice")

        a = Action(n'hello', n'test2', [PermissionLevel(n"hello", n"active")])
        print('++++send test2 action')
        a.send("4 alice")

        a = Action(n'hello', n'test3')
        print('++++send test3 action')
        a.send(Person("alice", 175u64))
        return

    @action('test2')
    def test2(self, name: str):
        print('++++=name:', name)

    @action('test3')
    def test3(self, name: str, height: u64):
        print('++++=name:', name, 'height:', height)

Please note that in order to call inline actions in the contract, the virtual permission eosio.code must be added to the active permission of the account, and in the test code, the following function is used to add this virtual permission to the active permission.

def update_auth(chain, account):
    a = {
        "account": account,
        "permission": "active",
        "parent": "owner",
        "auth": {
            "threshold": 1,
            "keys": [
                {
                    "key": 'EOS6AjF6hvF7GSuSd4sCgfPKq5uWaXvGM2aQtEUCwmEHygQaqxBSV',
                    "weight": 1
                }
            ],
            "accounts": [{"permission":{"actor":account,"permission": 'eosio.code'}, "weight":1}],
            "waits": []
        }
    }
    chain.push_action('eosio', 'updateauth', a, {account:'active'})