Data Storage


Performing CRUD operations against EOS smart contracts is achieved with the eosio::multi_index interface, which brings functionality which can be compared to a traditional database

To Do Smart Contract

In this article we will be creating a simple To Do list smart contract which enables the user to add a todo element e.g. “feed the cat” and mark it as complete.

In the contracts directory, create a new folder “todo_contract” and a new file CPP file of the same name.

mkdir todo_contract
cd todo_contract
touch todo_contract.cpp
vim todo_contract.cpp

Alternatively you can use eosiocpp to generate a boiler plate for the project including the project folder. From your top-level project folder, execute the following:

eosiocpp -n todo_contract

This will give you the following folder structure:

├── todo_contract.cpp
└── todo_contract.hpp

0 directories, 2 files

We will be demonstrating Create, Update & Delete functionality with our ABI actions - create(author, id, description) - destroy(author, id) - complete(author, id)

Our todo elements have 3 simple properties.


which as a struct looks like

// @abi table todos i64
struct todo {
	uint64_t id;
	std::string description;
	uint64_t completed;

	uint64_t primary_key() const { return id; }
	EOSLIB_SERIALIZE(todo, (id)(description)(completed))

Create function

The create function creates a new todo element using the emplace method. The first parameter is the payer, a valid account that authorized the current action (and thus allowed to be billed for storage usage)

// @abi action
void create(account_name author, const uint32_t id, const std::string& description) {
	todos.emplace(author, [&](auto& new_todo) {  = id;
		new_todo.description = description;
		new_todo.completed = 0;

Destroy function

The erase method will remove the object from the table and refund the existing payer for storage of it.

// @abi action
void destroy(account_name author, const uint32_t id) {
	auto todo_lookup = todos.find(id);

	eosio::print("todo#", id, " destroyed");

Complete function

We complete our todo by simply changing the completed property from 0 to 1 with the modify method.

The 2nd parameter used in the modify method is the payer (account_name)

Passing 0 indicates the payer of the newly modified row is the same as the original.

If the new payer is the same as the old, he only pays the difference between the old and new object.

If the new payer is not the old, the old is refunded for the storage usage of the existing object and the new payer is liable.

    // @abi action
    void complete(account_name author, const uint32_t id) {
      auto todo_lookup = todos.find(id);
      eosio_assert(todo_lookup != todos.end(), "Todo does not exist");

      todos.modify(todo_lookup, author, [&](auto& modifiable_todo) {
        modifiable_todo.completed = 1;

      eosio::print("todo#", id, " marked as complete");

Table Set up

We will now set up the container, think of it as the table.

typedef eosio::multi_index<N(todos), todo> todo_table;
todo_table todos;


Full code available from EOS Asia here

eosiocpp -o todo_contract.wast todo_contract.cpp
eosiocpp -g todo_contract.abi todo_contract.cpp
cleos --wallet-url http://wallet:5555 -u http://server:7777 set contract mynewaccount /eos/contracts/todo_contract -p mynewaccount



cleos --wallet-url http://wallet:5555 -u http://server:7777 get table mynewaccount todo todos


cleos --wallet-url http://wallet:5555 -u http://server:7777 push action mynewaccount create '["mynewaccount", 1, "feed cat"]' -p mynewaccount


cleos --wallet-url http://wallet:5555 -u http://server:7777 push action mynewaccount complete '["mynewaccount", 1]' -p mynewaccount


cleos --wallet-url http://wallet:5555 -u http://server:7777 push action mynewaccount destroy '["mynewaccount", 1]' -p mynewaccount

More storage resources