Smart Contract Examples
Blockmatic Contract List provides a ton of example links to various smart contracts that are available.
However, you might be just looking for a quick way to perform basic functionality inside of your smart contract.
Require Authorization Action
Requires permission from the name passed from the client to transact.
Code
ACTION hi(name user) {
require_auth(user);
}
Actions with More Parameters
When you need to add more parameters to your action.
Code
ACTION hi(name user, string message) {
print("Hello, your message was: ", message);
}
CRUD Operations
When you want to create a data entry, store it, update it, and delete that entry from a table.
The code below is a simple 'set your status' contract.
Code
#include <eosio/eosio.hpp>
#include <eosio/print.hpp>
using namespace std;
using namespace eosio;
CONTRACT status : public eosio::contract {
using eosio::contract::contract;
public:
ACTION setstatus(name& user, string& status) {
require_auth(user);
auto info_itr = info.find(user.value);
if (info_itr == info.end()) {
// This creates an entry in the table for the user
info.emplace(user, [&](status_struct &_info) {
_info.user = user.value;
_info.status = status;
});
} else {
// This modifies an existing entry, and sets existing data.
info.modify(info_itr, same_payer, [&](status_struct &_info) {
_info.status = status;
});
}
print(user.to_string(), " has set their status to: ", status);
}
ACTION rmvstatus(name& user) {
require_auth(user);
// This requires an entry to exist; before proceeding any further
auto info_itr = info.require_find(user.value, "user does not have any entries");
// This empties the table entry for the specified user
info.erase(info_itr);
print(user.to_string(), " removed table entry");
}
private:
TABLE status_struct {
uint64_t user;
string status;
uint64_t primary_key() const {
return user;
}
};
typedef multi_index<name("status"), status_struct> status_t;
status_t info = status_t(get_self(), get_self().value);
};
// Trevor Wessel - 2023
Scoped CRUD Operations
When you want to create a data entry, store it, update it, and delete that entry from a table owned by a user.
This means that table entries are owned by the user for their specific table. Only they can modify their entries.
The code below is the equivalent of a Twitter clone.
Code
#include <eosio/eosio.hpp>
#include <eosio/print.hpp>
#include <eosio/system.hpp>
using namespace std;
using namespace eosio;
CONTRACT journal : public eosio::contract {
using eosio::contract::contract;
public:
ACTION add(name& user, string& message) {
require_auth(user);
check(message.size() <= 256, "Message cannot exceed 256 bytes");
auto current_time = get_current_time();
// This makes it so that multiple users can have a 'journal'
// They have their own tables which are scoped to their name
// They can only add entries to the table which they own
journal_t scoped_journal = journal_t(get_self(), user.value);
auto journal_itr = scoped_journal.find(current_time);
check(journal_itr == scoped_journal.end(), "Entry already exists for this timepoint");
scoped_journal.emplace(user, [&](journal_struct &_entry) {
_entry.date = user.value;
_entry.message = message;
});
print(user.to_string(), " added a new entry at ", current_time);
}
ACTION edit(name& user, uint32_t& timepoint, string& message) {
require_auth(user);
journal_t scoped_journal = journal_t(get_self(), user.value);
auto journal_itr = scoped_journal.require_find(timepoint, "entry was not found");
scoped_journal.modify(journal_itr, user, [&](journal_struct &_entry) {
_entry.message = message;
});
print(user.to_string(), " updated entry at ", timepoint);
}
ACTION remove(name& user, uint32_t& timepoint) {
require_auth(user);
journal_t scoped_journal = journal_t(get_self(), user.value);
auto journal_itr = scoped_journal.require_find(timepoint, "entry was not found");
scoped_journal.erase(journal_itr);
print(user.to_string(), " removed journal entry at ", timepoint);
}
private:
// table: journal, scope: name
TABLE journal_struct {
uint32_t date;
string message;
uint32_t primary_key() const {
return date;
}
};
typedef multi_index<name("journal"), journal_struct> journal_t;
uint32_t get_current_time() {
return eosio::current_block_time().to_time_point().sec_since_epoch();
}
};
// Trevor Wessel - 2023
Reading Data from Table Iterators
In some cases, you may need to read directly from a table in a contract.
You can use the iterator to directly access the data.
The code below is based on the Scoped CRUD Operations
Code
journal_t scoped_journal = journal_t(get_self(), user.value);
auto journal_itr = scoped_journal.require_find(timepoint, "entry was not found");
print("Message at ", timepoint, " is ", journal_itr->message);
Listening for Token Transfers
The code below allows only the default UOS
token with a precision of 8
.
You must add the eosio.code
permission to your account to use this.
Code
#include <eosio/eosio.hpp>
#include <eosio/print.hpp>
#include <eosio/asset.hpp>
#include <eosio/symbol.hpp>
#include <eosio/system.hpp>
using namespace std;
using namespace eosio;
CONTRACT hello : public eosio::contract {
using eosio::contract::contract;
public:
[[eosio::on_notify("eosio.token::transfer")]] void deposit(name from, name to, eosio::asset amount, std::string memo) {
check(amount.amount > 0, "deposit amount should be positive");
// We want to ignore any transfers not going to us
// We want to make sure we are ignoring transfers out from ourselves
if (to != get_self() || from == get_self()) {
return;
}
check(memo.size() >= 1);
check(amount.symbol == eosio::symbol('UOS', 8), "Not the token we need. Bye.");
// You can check a memo here after an 'order' is created
// An order can be given a string value
// The memo can then be used to find a table entry
}
};
Listening for Uniq Transfers
If you want to listen for transfers from eosio.nft.ft
see onIssue Example.