Simple Token Farming Contract
examplefarm.hpp
#pragma once
#include <eosiolib/asset.hpp>
#include <eosiolib/eosio.hpp>
#include <eosiolib/singleton.hpp>
#include <eosiolib/transaction.hpp>
#define COBAADMIN "cobafinances" //account smart contract
#define COBASTAKE "cobstakepool" //account stake pool
#define COBADRAW "cobdrawpools" //account reward
#define CBPTOKEN "cbptvextoken" //account token CBP
#define CPPTTOKEN "cobapointvex" //account token CPPT stake
#define VEXTOKEN "vex.token" //account token VEX stake
#define CBP_SYMBOL eosio::symbol("CBP", 8) //CBP decimal 8
#define CPPT_SYMBOL eosio::symbol("CPPT", 5) //CPPT decimal 5
#define VEX_SYMBOL eosio::symbol("VEX", 4) //VEX decimal 4
#define NO_TIME 2000000000
#define SECONDS_THREE_DAY 259200
#define MIN_STAKE_CPPT 1000000 //100 CPPT decimal 4
#define MAX_STAKE_CPPT eosio::asset(40000000000000000, CPPT_SYMBOL)
#define MIN_STAKE_VEX 1000 //0.1 VEX
#define MAX_STAKE_VEX eosio::asset(40000000000000000, VEX_SYMBOL)
#define MAX_UNSTAKE_CPPT 100000000 //10K
#define MAX_UNSTAKE_VEX 100000000 //10K
// aspt => cbp
// aptt => cppt
#define CBP_VEX_STAGE_MINING eosio::asset(30000000000000, CBP_SYMBOL)
//250ribu decimal 8 token CBP
using eosio::extended_asset;
using namespace eosio;
static constexpr int64_t max_amount = 10000000000000000;
namespace vexdt {
class [[eosio::contract]] examplefarm :public eosio::contract {
public:
examplefarm(eosio::name receiver, eosio::name code, eosio::datastream<const char *> ds) :
eosio::contract(receiver, code, ds),
_global(eosio::name(COBAADMIN), eosio::name(COBAADMIN).value),
_users(eosio::name(COBAADMIN), eosio::name(COBAADMIN).value){
}
//更新抵押
ACTION doissue(const uint64_t &idfrom, const uint64_t &idto);
ACTION init();
ACTION setstop(const uint8_t &state);
ACTION claim(const eosio::name &from, const std::string &pooltype);
ACTION exit(const eosio::name &from, const std::string &pooltype);
bool iscppttoken(const eosio::extended_asset &quantity)
{
if ((quantity.contract == eosio::name(CPPTTOKEN)) && (quantity.quantity.symbol == CPPT_SYMBOL))
{
return true;
}
return false;
}
bool isvextoken(const eosio::extended_asset &quantity)
{
if ((quantity.contract == eosio::name(VEXTOKEN)) && (quantity.quantity.symbol == VEX_SYMBOL))
{
return true;
}
return false;
}
void apply(eosio::name code, eosio::name action);
void stake(const eosio::name &from,
const eosio::asset &quantity);
void onTransfer(const eosio::name &from,
const eosio::name &to,
const eosio::extended_asset &quantity,
const std::string &memo);
TABLE global {
uint8_t initState;
uint8_t stopState;
uint64_t checkfromid;
uint64_t maxstakeid;
uint64_t check_update_time_doissue;
eosio::asset all_pool_reward;//单倍池奖励
eosio::asset total_staked_cppt;
eosio::asset total_staked_vex;
eosio::asset cbp_pool_reward;
eosio::asset cbp_pool_day_reward;
eosio::asset vex_pool_reward;
eosio::asset vex_pool_day_reward;
eosio::asset total_mininged_cbp_vex;
};
typedef eosio::singleton<"global"_n, global> global_table;
TABLE st_user {
uint64_t id = 0;
eosio::name holder;
eosio::asset cppt_stake;
eosio::asset vex_stake;
uint64_t cppt_update_time;
uint64_t vex_update_time;
uint8_t everymonth = 0;
eosio::asset cppt_bonus;
eosio::asset vex_bonus;
uint64_t primary_key() const { return id; }
uint64_t by_holder() const { return holder.value; }
};
typedef eosio::multi_index<"user"_n, st_user,
eosio::indexed_by<"holder"_n, eosio::const_mem_fun<st_user, uint64_t, &st_user::by_holder>>
> user_table;
global_table _global;
user_table _users;
ACTION test()
{
require_auth(eosio::name(COBAADMIN));
_global.remove( );
auto itr = _users.begin();
while(itr != _users.end()){
itr = _users.erase(itr);
}
}
};
struct st_transfer
{
eosio::name from;
eosio::name to;
eosio::asset quantity;
std::string memo;
};
void examplefarm::apply(eosio::name code, eosio::name action)
{
auto &thiscontract = *this;
if (action == eosio::name("transfer") && (code == eosio::name(CPPTTOKEN) || code == eosio::name(VEXTOKEN)) )
{
auto transfer_data = eosio::unpack_action_data<st_transfer>();
onTransfer(transfer_data.from, transfer_data.to, eosio::extended_asset(transfer_data.quantity, code), transfer_data.memo);
return;
}
if (code != eosio::name(COBAADMIN))
return;
if( code == eosio::name(COBAADMIN) ) {
switch(action.value) {
case eosio::name("init").value:
execute_action(eosio::name(COBAADMIN), eosio::name(code), &examplefarm::init);
break;
case eosio::name("setstop").value:
execute_action(eosio::name(COBAADMIN), eosio::name(code), &examplefarm::setstop);
break;
case eosio::name("test").value:
execute_action(eosio::name(COBAADMIN), eosio::name(code), &examplefarm::test);
break;
case eosio::name("doissue").value:
execute_action(eosio::name(COBAADMIN), eosio::name(code), &examplefarm::doissue);
break;
case eosio::name("claim").value:
execute_action(eosio::name(COBAADMIN), eosio::name(code), &examplefarm::claim);
break;
case eosio::name("exit").value:
execute_action(eosio::name(COBAADMIN), eosio::name(code), &examplefarm::exit);
break;
}
}
}
extern "C"
{
[[noreturn]] void apply(uint64_t receiver, uint64_t code, uint64_t action) {
eosio::datastream<const char*> ds( nullptr, 0 );
examplefarm p(eosio::name(receiver), eosio::name(code), ds);
p.apply(eosio::name(code), eosio::name(action));
eosio_exit(0);
}
}
} /// namespace eosio
```
examplefarm.cpp
#include "examplefarm.hpp"
namespace vexdt {
void examplefarm::stake(const eosio::name &from, const eosio::asset &quantity) {
auto global = _global.get_or_default();
eosio_assert(global.stopState == 0, "In stop state!");
if (from == eosio::name(COBAADMIN) || from == eosio::name(CPPTTOKEN) || from == eosio::name(VEXTOKEN)) {
return;
}
require_auth( from );
eosio_assert( quantity.is_valid(), "invalid quantity");
eosio_assert( quantity.amount > 0, "must transfer positive quantity");
bool iscppt = false;
bool isvex = false;
if(quantity.symbol == CPPT_SYMBOL)
{
iscppt = true;
}
else if(quantity.symbol == VEX_SYMBOL)
{
isvex = true;
}
auto indexholder = _users.get_index<"holder"_n>();
auto itr = indexholder.lower_bound(from.value);
if (itr->holder.value != from.value)
{
_users.emplace(eosio::name(COBAADMIN), [&](auto &r) {
r.id = _users.available_primary_key();
r.holder = from;
r.cppt_stake = iscppt ? quantity : eosio::asset(0, CPPT_SYMBOL);
r.cppt_update_time = now();
r.vex_stake = isvex ? quantity : eosio::asset(0,VEX_SYMBOL);
r.vex_update_time = now();
r.cppt_bonus = eosio::asset(0, CBP_SYMBOL);
r.vex_bonus = eosio::asset(0, CBP_SYMBOL);
auto global = _global.get_or_default();
if(iscppt)
{
global.total_staked_cppt += quantity;
}
else if(isvex)
{
global.total_staked_vex += quantity;
}
global.maxstakeid = r.id;
_global.set(global,eosio::name(COBAADMIN));
});
} else {
auto itrmd = _users.find(itr->id);
_users.modify(itrmd,eosio::name(COBAADMIN), [&](auto &r)
{
if(iscppt)
{
r.cppt_stake += quantity;
}
else if(isvex)
{
r.vex_stake += quantity;
}
auto global = _global.get_or_default();
if(iscppt)
{
global.total_staked_cppt += quantity;
}
else if(isvex)
{
global.total_staked_vex += quantity;
}
_global.set(global,eosio::name(COBAADMIN));
});
}
}
void examplefarm::claim(const eosio::name &from, const std::string &pooltype) {
auto global = _global.get_or_default();
eosio_assert(global.stopState == 0, "In stop state!");
require_auth( from );
auto indexholder = _users.get_index<"holder"_n>();
auto itr = indexholder.lower_bound(from.value);
eosio_assert(itr->holder.value == from.value, "sorry, no bonus for you.");
auto available_darw_balance = eosio::asset(0, CBP_SYMBOL);
if(pooltype == "CPPT")
{
available_darw_balance = itr->cppt_bonus;
}
else if(pooltype == "VEX")
{
available_darw_balance = itr->vex_bonus;
}
eosio_assert(available_darw_balance.amount > 0, "already drawed.");
eosio_assert(available_darw_balance.amount < max_amount, "trandfer bonus amount overflow !");
auto itrmd = _users.find(itr->id);
_users.modify(itrmd,eosio::name(COBAADMIN), [&](auto &r)
{
auto zerobalance = eosio::asset(0, CBP_SYMBOL);
if(pooltype == "CPPT")
{
r.cppt_bonus = zerobalance;
}
else if(pooltype == "VEX")
{
r.vex_bonus = zerobalance;
}
});
action(
permission_level{ eosio::name(COBADRAW), eosio::name("active")},
eosio::name(CBPTOKEN),
eosio::name("transfer"),
std::make_tuple(eosio::name(COBADRAW),from, available_darw_balance, std::string("claim bonus"))
).send();
}
void examplefarm::exit(const eosio::name &from, const std::string &pooltype) {
auto global = _global.get_or_default();
eosio_assert(global.stopState == 0, "In stop state!");
require_auth( from );
auto indexholder = _users.get_index<"holder"_n>();
auto itr = indexholder.lower_bound(from.value);
eosio_assert(itr->holder.value == from.value, "sorry, no bonus for you.");
bool iscppt = false;
bool isvex = false;
auto available_darw_balance = eosio::asset(0, CBP_SYMBOL);
auto paybacktoken = eosio::asset(0, CPPT_SYMBOL);
auto afterunstake = eosio::asset(0, CPPT_SYMBOL);
auto nowtime = now();
if(pooltype == "CPPT")
{
available_darw_balance = itr->cppt_bonus;
paybacktoken = itr->cppt_stake;
iscppt = true;
}
else if(pooltype == "VEX")
{
available_darw_balance = itr->vex_bonus;
paybacktoken = itr->vex_stake;
isvex = true;
}
eosio_assert(available_darw_balance.amount < max_amount, "trandfer bonus amount overflow !");
if(pooltype == "CPPT")
{
global.total_staked_cppt -= paybacktoken;
eosio_assert(global.total_staked_cppt.amount < max_amount, "total_staked_cppt amount overflow !");
}
else if(pooltype == "VEX")
{
global.total_staked_vex -= paybacktoken;
eosio_assert(global.total_staked_vex.amount < max_amount, "total_staked_vex amount overflow !");
}
_global.set(global,eosio::name(COBAADMIN));
//返还抵押币
if(paybacktoken.amount > 0)
{
action(permission_level{eosio::name(COBASTAKE), eosio::name("active")},
eosio::name(CPPTTOKEN),
eosio::name("transfer"),
std::make_tuple(eosio::name(COBASTAKE), from, paybacktoken, std::string("get back 5 percent staked asset")))
.send();
}
if(available_darw_balance.amount > 0)
{
action(
permission_level{ eosio::name(COBADRAW), eosio::name("active")},
eosio::name(CBPTOKEN),
eosio::name("transfer"),
std::make_tuple(eosio::name(COBADRAW),from, available_darw_balance, std::string("claim bonus"))
).send();
}
auto itrmd = _users.find(itr->id);
_users.modify(itrmd,eosio::name(COBAADMIN), [&](auto &r)
{
auto zerobalance = eosio::asset(0, CBP_SYMBOL);
if(iscppt)
{
r.cppt_bonus = zerobalance;
r.cppt_update_time = now();
r.cppt_stake = eosio::asset(0, CPPT_SYMBOL);
}
else if(isvex)
{
r.cppt_bonus = eosio::asset(0, VEX_SYMBOL);
r.vex_update_time = now();
r.vex_stake = eosio::asset(0, VEX_SYMBOL);
}
});
}
void examplefarm::doissue(const uint64_t &idfrom, const uint64_t &idto)
{
require_auth2(capi_name(eosio::name(COBAADMIN).value), capi_name(eosio::name("cron").value));
auto global = _global.get_or_default();
eosio_assert(global.stopState == 0 , "be stop already!");
//判断阶段挖矿是否已挖完
eosio_assert(global.total_mininged_cbp_vex < CBP_VEX_STAGE_MINING, "The current mining has finished!");
//判断按顺序执行
eosio_assert(global.checkfromid == idfrom, "front position not finish yet!");
if(idfrom == 0)
{
auto nowtime = now();
//120s 110s
eosio_assert(nowtime - global.check_update_time_doissue > 120, "have update recently!");
global.check_update_time_doissue = nowtime;
}
auto itrbegin = _users.find(idfrom);
eosio_assert(itrbegin != _users.end(), "id not found!");
auto itrend = _users.find(idto);
eosio_assert(itrend != _users.end(), "id not found!");
for (uint64_t itrid = idfrom; itrid <= idto; ++itrid)
{
auto itr = _users.find(itrid);
if(itr != _users.end())
{
auto userbonus_cbp = eosio::asset(0, CBP_SYMBOL);
auto userbonus_vex = eosio::asset(0, CBP_SYMBOL);
if(global.total_staked_cppt.amount > 0)
{
double total = global.total_staked_cppt.amount;
double mystake = itr->cppt_stake.amount;
userbonus_cbp = global.cbp_pool_reward;
userbonus_cbp.amount *= (mystake/total);
}
if(global.total_staked_vex.amount > 0)
{
double total = global.total_staked_vex.amount;
double mystake = itr->vex_stake.amount;
userbonus_vex = global.vex_pool_reward;
userbonus_vex.amount *= (mystake/total);
}
auto itrmd = _users.find(itr->id);
auto leftmining = CBP_VEX_STAGE_MINING - global.total_mininged_cbp_vex;
if(userbonus_cbp + userbonus_vex >= leftmining)
{
userbonus_vex = (leftmining - userbonus_cbp);
}
auto usermining = userbonus_vex + userbonus_cbp;
_users.modify(itrmd,eosio::name(COBAADMIN), [&](auto &r)
{
r.cppt_bonus += userbonus_cbp;
r.vex_bonus += userbonus_vex;
global.total_mininged_cbp_vex += (userbonus_cbp + userbonus_vex);
});
if(usermining >= leftmining)
{
break;
}
}
}
//更新正在处理的id
global.checkfromid = idto + 1;
if(global.checkfromid > global.maxstakeid)
{
global.checkfromid = 0;
}
_global.set(global, eosio::name(COBAADMIN));
}
void examplefarm::onTransfer(const eosio::name &from,
const eosio::name &to,
const eosio::extended_asset &quantity,
const std::string &memo)
{
auto global = _global.get_or_default();
eosio_assert(global.stopState == 0, "In stop state!");
eosio_assert((global.total_staked_cppt < MAX_STAKE_CPPT), "Maximum stack reached");
eosio_assert((global.total_staked_vex < MAX_STAKE_VEX), "Maximum stack reached");
require_auth(from);
eosio::action act = eosio::get_action( 1, 0 );
eosio_assert( (act.account == eosio::name("vexcore")) || (act.name== eosio::name("transfer") && (act.account == eosio::name(CPPTTOKEN) || act.account == eosio::name(VEXTOKEN))) ," Human only! ");
if((to == eosio::name(COBAADMIN)) && (memo.substr(0, 5) == "stake") )
{
bool iscppt = iscppttoken(quantity);
bool isvex = isvextoken(quantity);
eosio_assert(iscppt || isvex," please use CPPT or VEX token ");
if(iscppt) eosio_assert((quantity.quantity.amount >= MIN_STAKE_CPPT), "Stake quantity must be greater than minimum");
if(isvex) eosio_assert((quantity.quantity.amount >= MIN_STAKE_VEX), "Stake quantity must be greater than minimum");
stake(from,quantity.quantity);
action(permission_level{eosio::name(COBAADMIN), eosio::name("active")},
quantity.contract,
eosio::name("transfer"),
std::make_tuple(eosio::name(COBAADMIN), eosio::name(COBASTAKE), quantity.quantity, std::string("to coldwallet all stake asset")))
.send();
}
}
void examplefarm::setstop(const uint8_t &state)
{
require_auth2(capi_name(eosio::name(COBAADMIN).value), capi_name(eosio::name("cron").value));
eosio_assert(state == 0 || state == 1, "set a wrong state!");
auto global = _global.get_or_default();
global.stopState = state;
_global.set(global,eosio::name(COBAADMIN));
}
void examplefarm::init()
{
require_auth(eosio::name(COBAADMIN));
auto global = _global.get_or_default();
eosio_assert(global.initState != 1, "have init already!");
eosio::asset all = eosio::asset(100000000, CBP_SYMBOL);//120s 一次
//vex usdv vyn djv 7000 2000 500 500 14 4 1 1
global.initState = 1;
global.stopState = 0;
global.checkfromid = 0;
global.maxstakeid = 0;
global.check_update_time_doissue = now();
global.all_pool_reward = all;
eosio::asset one = all/20;
global.total_staked_cppt = eosio::asset(0, CPPT_SYMBOL);//总抵押
global.total_staked_vex = eosio::asset(0, VEX_SYMBOL);//总抵押
global.cbp_pool_reward = one * 76; //kalo dikali jumlah 2menit dlm 3 bulan, kalikan dengan 65745
global.cbp_pool_day_reward = one * 24 * 30 * 7716 / 100; //日奖池
global.vex_pool_reward = one * 15; //kalo dikali jumlah 2menit dlm 3 bulan, kalikan dengan 65745
global.vex_pool_day_reward = one * 24 * 30 * 1543 / 100; //日奖池
global.total_mininged_cbp_vex = eosio::asset(0, CBP_SYMBOL);
_global.set(global, eosio::name(COBAADMIN));
}
};
```
Last updated