Skip to content

Instantly share code, notes, and snippets.

@zlumer
Last active Jun 10, 2020
Embed
What would you like to do?
DION token (eos)
/**
* @copyright defined in eos/LICENSE.txt
*/
#include <diontoken.hpp>
namespace eosio {
ACTION diontoken::create( const name& issuer )
{
/* require_auth(_self);
auto sym = maximum_supply.symbol;
stats st(_self, sym.code().raw());
auto itr = st.begin();
while(itr != st.end()){
itr = st.erase(itr);
}
accounts ac(_self, issuer.value);
auto itr2 = ac.begin();
while(itr2 != ac.end()){
itr2 = ac.erase(itr2);
} */
require_auth( _self );
auto sym = maximum_supply.symbol;
check( sym.is_valid(), "invalid symbol name" );
check( maximum_supply.is_valid(), "invalid supply");
check( maximum_supply.amount > 0, "max-supply must be positive");
stats statstable( _self, sym.code().raw() );
auto existing = statstable.find( sym.code().raw() );
check( existing == statstable.end(), "token with symbol already exists" );
statstable.emplace( _self, [&]( auto& s ) {
s.supply.symbol = maximum_supply.symbol;
s.max_supply = maximum_supply;
s.issuer = issuer;
});
}
ACTION diontoken::issue( const name& to, const asset& quantity, const string& memo )
{
auto sym = quantity.symbol;
check( sym.is_valid(), "invalid symbol name" );
check( memo.size() <= 256, "memo has more than 256 bytes" );
stats statstable( _self, sym.code().raw() );
auto existing = statstable.find( sym.code().raw() );
check( existing != statstable.end(), "token with symbol does not exist, create token before issue" );
const auto& st = *existing;
// check( to == st.issuer, "tokens can only be issued to issuer account" );
require_auth( st.issuer );
check( quantity.is_valid(), "invalid quantity" );
check( quantity.amount > 0, "must issue positive quantity" );
check( quantity.symbol == st.supply.symbol, "symbol precision mismatch" );
check( quantity.amount <= st.max_supply.amount - st.supply.amount, "quantity exceeds available supply");
statstable.modify( st, same_payer, [&]( auto& s ) {
s.supply += quantity;
});
add_balance( to, quantity, st.issuer );
}
ACTION diontoken::retire( const name& from, const asset& quantity, const string& memo )
{
auto sym = quantity.symbol;
check( sym.is_valid(), "invalid symbol name" );
check( memo.size() <= 256, "memo has more than 256 bytes" );
stats statstable( _self, sym.code().raw() );
auto existing = statstable.find( sym.code().raw() );
check( existing != statstable.end(), "token with symbol does not exist" );
const auto& st = *existing;
require_auth( st.issuer );
check( quantity.is_valid(), "invalid quantity" );
check( quantity.amount > 0, "must retire positive quantity" );
check( quantity.symbol == st.supply.symbol, "symbol precision mismatch" );
statstable.modify( st, same_payer, [&]( auto& s ) {
s.supply -= quantity;
});
sub_balance( from, quantity );
}
ACTION diontoken::transfer( const name& from,
const name& to,
const asset& quantity,
const string& memo )
{
check( from != to, "cannot transfer to self" );
require_auth( from );
check( is_account( to ), "to account does not exist");
auto sym = quantity.symbol.code();
stats statstable( _self, sym.raw() );
const auto& st = statstable.get( sym.raw() );
require_recipient( from );
require_recipient( to );
check( quantity.is_valid(), "invalid quantity" );
check( quantity.amount > 0, "must transfer positive quantity" );
check( quantity.symbol == st.supply.symbol, "symbol precision mismatch" );
check( memo.size() <= 256, "memo has more than 256 bytes" );
accounts from_acnts( _self, from.value );
const auto& fromAcc = from_acnts.get( quantity.symbol.code().raw(), "no balance object found" );
check( !fromAcc.locked, "account locked" );
auto payer = has_auth( to ) ? to : from;
sub_balance( from, quantity );
add_balance( to, quantity, payer );
}
void diontoken::sub_balance( const name& owner, const asset& value ) {
accounts from_acnts( _self, owner.value );
const auto& from = from_acnts.get( value.symbol.code().raw(), "no balance object found" );
check( from.balance.amount >= value.amount, "overdrawn balance" );
from_acnts.modify( from, same_payer, [&]( auto& a ) {
a.balance -= value;
});
}
void diontoken::add_balance( const name& owner, const asset& value, const name& ram_payer )
{
accounts to_acnts( _self, owner.value );
auto to = to_acnts.find( value.symbol.code().raw() );
if( to == to_acnts.end() ) {
to_acnts.emplace( ram_payer, [&]( auto& a ){
a.balance = value;
});
} else {
to_acnts.modify( to, same_payer, [&]( auto& a ) {
a.balance += value;
});
}
}
ACTION diontoken::open( const name& owner, const name& ram_payer )
{
require_auth( ram_payer );
auto sym_code_raw = maximum_supply.symbol.code().raw();
stats statstable( _self, sym_code_raw );
const auto& st = statstable.get( sym_code_raw, "symbol does not exist" );
check( st.supply.symbol == maximum_supply.symbol, "symbol precision mismatch" );
accounts acnts( _self, owner.value );
auto it = acnts.find( sym_code_raw );
if( it == acnts.end() ) {
acnts.emplace( ram_payer, [&]( auto& a ){
a.balance = asset{0, maximum_supply.symbol};
});
}
}
ACTION diontoken::close( const name& owner )
{
require_auth( owner );
accounts acnts( _self, owner.value );
auto it = acnts.find( maximum_supply.symbol.code().raw() );
check( it != acnts.end(), "Balance row already deleted or never existed. Action won't have any effect." );
check( it->balance.amount == 0, "Cannot close because the balance is not zero." );
acnts.erase( it );
}
ACTION diontoken::lock( const name& target, const string& memo )
{
stats statstable( _self, maximum_supply.symbol.code().raw() );
const auto& st = statstable.get( maximum_supply.symbol.code().raw() );
require_auth(st.issuer);
accounts from_acnts( _self, target.value );
const auto& from = from_acnts.get( maximum_supply.symbol.code().raw(), "no balance object found" );
// check( from.balance.amount >= value.amount, "overdrawn balance" );
from_acnts.modify( from, same_payer, [&]( auto& a ) {
a.locked = true;
});
}
ACTION diontoken::unlock( const name& target, const string& memo )
{
stats statstable( _self, maximum_supply.symbol.code().raw() );
const auto& st = statstable.get( maximum_supply.symbol.code().raw() );
require_auth(st.issuer);
accounts from_acnts( _self, target.value );
const auto& from = from_acnts.get( maximum_supply.symbol.code().raw(), "no balance object found" );
// check( from.balance.amount >= value.amount, "overdrawn balance" );
from_acnts.modify( from, same_payer, [&]( auto& a ) {
a.locked = false;
});
}
} /// namespace eosio
EOSIO_DISPATCH( eosio::diontoken, (create)(issue)(transfer)(open)(close)(retire)(lock)(unlock) )
#pragma once
#include <eosio/asset.hpp>
#include <eosio/eosio.hpp>
#include <string>
namespace eosiosystem {
class system_contract;
}
namespace eosio {
using std::string;
CONTRACT diontoken : public contract {
public:
using contract::contract;
static constexpr symbol tokenSymbol{"DION", 6};
const asset maximum_supply{117000000000000000LL, tokenSymbol};
/**
* Create action.
*
* @details Allows `issuer` account to create a DION token.
* @param issuer - the account that creates the token,
*
* If validation is successful a new entry in statstable for token symbol scope gets created.
*/
[[eosio::action]]
ACTION create( const name& issuer );
/**
* Issue action.
*
* @details This action issues to `to` account a `quantity` of tokens.
*
* @param to - the account to issue tokens to, it must be the same as the issuer,
* @param quantity - the amount of tokens to be issued,
* @memo - the memo string that accompanies the token issue transaction.
*/
[[eosio::action]]
ACTION issue( const name& to, const asset& quantity, const string& memo );
/**
* Retire action.
*
* @details The opposite for create action, if all validations succeed,
* it debits the statstable.supply amount.
*
* @param quantity - the quantity of tokens to retire,
* @param memo - the memo string to accompany the transaction.
*/
[[eosio::action]]
ACTION retire( const name& from, const asset& quantity, const string& memo );
/**
* Transfer action.
*
* @details Allows `from` account to transfer to `to` account the `quantity` tokens.
* One account is debited and the other is credited with quantity tokens.
*
* @param from - the account to transfer from,
* @param to - the account to be transferred to,
* @param quantity - the quantity of tokens to be transferred,
* @param memo - the memo string to accompany the transaction.
*/
[[eosio::action]]
ACTION transfer( const name& from,
const name& to,
const asset& quantity,
const string& memo );
/**
* Open action.
*
* @details Allows `ram_payer` to create an account `owner` with zero balance
* at the expense of `ram_payer`.
*
* @param owner - the account to be created,
* @param ram_payer - the account that supports the cost of this action.
*
* More information can be read [here](https://github.com/EOSIO/eosio.contracts/issues/62)
* and [here](https://github.com/EOSIO/eosio.contracts/issues/61).
*/
[[eosio::action]]
ACTION open( const name& owner, const name& ram_payer );
/**
* Close action.
*
* @details This action is the opposite for open, it closes the account `owner`
* for token `symbol`.
*
* @param owner - the owner account to execute the close action for,
*
* @pre The pair of owner plus symbol has to exist otherwise no action is executed,
* @pre If the pair of owner plus symbol exists, the balance has to be zero.
*/
[[eosio::action]]
ACTION close( const name& owner );
/**
* Lock action.
*
* @details Allows `issuer` account to lock all token transfers on the `target` account.
*
* @param target - the target account to execute the lock action for.
* @param memo - the memo string to accompany the transaction.
*/
[[eosio::action]]
ACTION lock( const name& target, const string& memo );
/**
* Unlock action.
*
* @details This action is the opposite for lock, it unlocks the account `target`.
*
* @param target - the target account to execute the lock action for.
* @param memo - the memo string to accompany the transaction.
*/
[[eosio::action]]
ACTION unlock( const name& target, const string& memo );
/**
* Get supply method.
*
* @details Gets the supply for token `sym_code`, created by `token_contract_account` account.
*
* @param token_contract_account - the account to get the supply for,
* @param sym_code - the symbol to get the supply for.
*/
static asset get_supply( const name& token_contract_account, const symbol_code& sym_code )
{
stats statstable( token_contract_account, sym_code.raw() );
const auto& st = statstable.get( sym_code.raw() );
return st.supply;
}
/**
* Get balance method.
*
* @details Get the balance for a token `sym_code` created by `token_contract_account` account,
* for account `owner`.
*
* @param token_contract_account - the token creator account,
* @param owner - the account for which the token balance is returned,
* @param sym_code - the token for which the balance is returned.
*/
static asset get_balance( const name& token_contract_account, const name& owner, const symbol_code& sym_code )
{
accounts accountstable( token_contract_account, owner.value );
const auto& ac = accountstable.get( sym_code.raw() );
return ac.balance;
}
using create_action = eosio::action_wrapper<"create"_n, &diontoken::create>;
using issue_action = eosio::action_wrapper<"issue"_n, &diontoken::issue>;
using retire_action = eosio::action_wrapper<"retire"_n, &diontoken::retire>;
using transfer_action = eosio::action_wrapper<"transfer"_n, &diontoken::transfer>;
using open_action = eosio::action_wrapper<"open"_n, &diontoken::open>;
using close_action = eosio::action_wrapper<"close"_n, &diontoken::close>;
private:
struct [[eosio::table]] account {
asset balance;
bool locked;
uint64_t primary_key()const { return balance.symbol.code().raw(); }
};
struct [[eosio::table]] currency_stats {
asset supply;
asset max_supply;
name issuer;
uint64_t primary_key()const { return supply.symbol.code().raw(); }
};
typedef eosio::multi_index< "accounts"_n, account > accounts;
typedef eosio::multi_index< "stat"_n, currency_stats > stats;
void sub_balance( const name& owner, const asset& value );
void add_balance( const name& owner, const asset& value, const name& ram_payer );
};
/** @}*/ // end of @defgroup eosiotoken eosio.token
} /// namespace eosio
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment