Christoph Michel

Jun 28, 2019

4 min read

Advanced EOSIO programming concepts

While reviewing EOS smart contracts I noticed that every developer has its own style of programming and that there are many different ways to do the same things, like working with time or sending actions to other contracts. This article is a thought-dump of some EOSIO library functions that I find elegant and are useful to know.

1. eosio::same_payer

Usage:

statstable.modify( st, eosio::same_payer, [&]( auto& s ) {
s.supply += quantity;
});

It’s defined in [multi_index.hpp] and is just a constant expression for the empty name (value: 0) ""_n or name(0) which some developers still use to indicate the same payer.

2. get_first_receiver, get_self()

For example, listening to notifications of the eosio.token's transfer action, get_self() returns the account your contract is deployed to, whereas get_first_receiver() returns the eosio.token account. This is because the action originated by an account sending a transfer action to the eosio.token account that involves your contract account.

Usage:

[[eosio::on_notify("eosio.token::transfer")]] void cryptoship::transfer(name from, name to, const asset &quantity,
string memo) {
print(get_self()); // cryptoship
print(get_first_receiver()); // eosio.token
}

3. action_wrapper

The first argument is the action name and the second one is the method declaration of the action.

Usage

[[eosio::action]]
void create( name issuer,
asset maximum_supply);

[[eosio::action]]
void issue( name to, asset quantity, string memo );

[[eosio::action]]
void retire( asset quantity, string memo );

[[eosio::action]]
void transfer( name from,
name to,
asset quantity,
string memo );

// ...

using create_action = eosio::action_wrapper<"create"_n, &token::create>;
using issue_action = eosio::action_wrapper<"issue"_n, &token::issue>;
using retire_action = eosio::action_wrapper<"retire"_n, &token::retire>;
using transfer_action = eosio::action_wrapper<"transfer"_n, &token::transfer>;
// ...

We can now send inline actions to any eosio.token contract by including this header file.

Important to note is that only this header file with the declarations needs to be included. Meaning, one can easily write action wrappers even for closed-source contracts with unknown implementation details. Only the declaration, the action signature, needs to be written, which one can get from the ABI.

Additional include directories for header files are included using the -I flag of eosio-cpp.

After including the header file, an inline transfer action is sent like this:

#include <eosio_token/include/eosio_token.hpp>

// can specify the contract to send the action to as first argument
token::transfer_action payout("eosio.token"_n, {get_self(), "active"_n});
// transfer arguments are now passed as postional arguments
payout.send(get_self(), to, quantity, memo);

The same works for deferred transactions using the to_action method:

token::transfer_action payout("eosio.token"_n, {get_self(), "active"_n});

transaction t{};
t.actions.emplace_back(payout.to_action(get_self(), to, quantity, memo));
t.delay_sec = 10;
t.send(0 /* sender id */, get_self(), false);

4. EOSIO time classes time_point, time_point_sec, microseconds

To do arithmetic with times, one uses the microseconds class which comes with useful helpers like seconds, minutes or hours.

Usage

eosio::time_point tp = eosio::current_time_point();
eosio::time_point_sec tps = eosio::current_time_point();
eosio::microseconds micros = tp.time_since_epoch();
uint64_t count_micros = micros.count();
uint32_t count_seconds = tps.sec_since_epoch();

// no more 60*60*24*1e6
const auto MICROSECONDS_IN_DAY = hours(24);
count_micros += MICROSECONDS_IN_DAY;
// no more 60*60*24
count_seconds += hours(24).to_seconds();

eosio::time_point_sec lastGame = /* ... */;
check((eosio::time_point_sec)(current_time_point() + minutes(1)) >= lastGame,
"last game not finished");

Using the microseconds class and its helpers allow one to avoid any kind of constants like const auto SECONDS_PER_DAY = 60*60*24, making the code easier to reason about.

If you want to learn more about EOS smart contract programming techniques, check out the Learn EOS Development book.

Learn EOS Development Signup

Originally published at cmichel.io

Medium Clap