From ea59c6190878509a088742d8bdcf357f2f8dec79 Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Mon, 29 Mar 2021 14:48:48 -0600 Subject: [PATCH 01/32] add global staking state, and constants final review of modified FIP, first coding iteration, add global staking state and constants. --- contracts/fio.common/fio.common.hpp | 4 ++++ .../include/fio.system/fio.system.hpp | 24 +++++++++++++++++-- contracts/fio.system/src/fio.system.cpp | 2 ++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/contracts/fio.common/fio.common.hpp b/contracts/fio.common/fio.common.hpp index ae79c516..a7b517f2 100644 --- a/contracts/fio.common/fio.common.hpp +++ b/contracts/fio.common/fio.common.hpp @@ -38,6 +38,10 @@ #define MAXBPS 42 #define MAXACTIVEBPS 21 #define DEFAULTBUNDLEAMT 100 +//staking +#define COMBINEDTOKENPOOLMINIMUM 1000000000000000 // 1M FIO SUFS +#define STAKINGREWARDSRESERVEMAXIMUM 25000000000000000 // 25M FIO SUFS. +#define DAILYSTAKINGMINTTHRESHOLD 25000000000000 //25k FIO threshold for MINTING staking rewards. #define REGISTER_ADDRESS_ENDPOINT "register_fio_address" #define REGISTER_DOMAIN_ENDPOINT "register_fio_domain" diff --git a/contracts/fio.system/include/fio.system/fio.system.hpp b/contracts/fio.system/include/fio.system/fio.system.hpp index e74d2662..4ef13dc0 100755 --- a/contracts/fio.system/include/fio.system/fio.system.hpp +++ b/contracts/fio.system/include/fio.system/fio.system.hpp @@ -282,12 +282,30 @@ indexed_by<"byowner"_n, const_mem_fun voters_table; - -//MAS-522 eliminate producers2 table typedef eosio::multi_index<"producers2"_n, producer_info2> producers_table2; +//FIP-21 FIO staking +//staking info is a global state table used to track information relating to staking within the FIO protocol. +struct [[eosio::table, eosio::contract("fio.system")]] global_staking_state { + uint64_t staked_token_pool = 0; //total FIO tokens staked for all accounts, units sufs. + uint64_t combined_token_pool = 0; //total fio tokens staked for all accounts plus fio rewards all accounts, units SUFs, + // incremented when user stakes, when tokens are earmarked as staking rewards, + // decremented by unstaked amount + reward amount when users unstake + uint64_t rewards_token_pool = 0; //total counter how much has come in from fees AND minting units SUFs + uint64_t global_srp_count = 0; //total SRP for all FIO users, increment when users stake, decrement when users unstake. + uint64_t daily_staking_rewards = 0; //this is used to track the daily staking rewards, + // its used only to determine if the protocol should mint FIO whe rewards are under the + uint64_t staking_rewards_reserves_minted = 0; //the total amount of FIO used in minting rewards tokens, will not exceed STAKINGREWARDSRESERVEMAXIMUM + + EOSLIB_SERIALIZE( global_staking_state,(staked_token_pool) + (combined_token_pool)(rewards_token_pool)(global_srp_count) + (daily_staking_rewards)(staking_rewards_reserves_minted) + ) +}; +//FIP-21 FIO staking typedef eosio::singleton<"global"_n, eosio_global_state> global_state_singleton; typedef eosio::singleton<"global2"_n, eosio_global_state2> global_state2_singleton; typedef eosio::singleton<"global3"_n, eosio_global_state3> global_state3_singleton; +typedef eosio::singleton<"staking"_n, global_staking_state> global_staking_singleton; static constexpr uint32_t seconds_per_day = 24 * 3600; @@ -305,9 +323,11 @@ class [[eosio::contract("fio.system")]] system_contract : public native { global_state_singleton _global; global_state2_singleton _global2; global_state3_singleton _global3; + global_staking_singleton _staking; eosio_global_state _gstate; eosio_global_state2 _gstate2; eosio_global_state3 _gstate3; + global_staking_state _gstaking; fioio::fionames_table _fionames; fioio::domains_table _domains; fioio::fiofee_table _fiofees; diff --git a/contracts/fio.system/src/fio.system.cpp b/contracts/fio.system/src/fio.system.cpp index fa1087ec..8e51bf5a 100755 --- a/contracts/fio.system/src/fio.system.cpp +++ b/contracts/fio.system/src/fio.system.cpp @@ -25,6 +25,7 @@ namespace eosiosystem { _global(_self, _self.value), _global2(_self, _self.value), _global3(_self, _self.value), + _staking(_self, _self.value), _lockedtokens(_self,_self.value), _generallockedtokens(_self, _self.value), _fionames(AddressContract, AddressContract.value), @@ -34,6 +35,7 @@ namespace eosiosystem { _gstate = _global.exists() ? _global.get() : get_default_parameters(); _gstate2 = _global2.exists() ? _global2.get() : eosio_global_state2{}; _gstate3 = _global3.exists() ? _global3.get() : eosio_global_state3{}; + _gstaking = _staking.exists() ? _staking.get() : global_staking_state{}; } eosiosystem::eosio_global_state eosiosystem::system_contract::get_default_parameters() { From 79496359344444e3575fdcf020c8d665d12ce78c Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Mon, 29 Mar 2021 15:11:05 -0600 Subject: [PATCH 02/32] update comment comment --- contracts/fio.system/include/fio.system/fio.system.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/fio.system/include/fio.system/fio.system.hpp b/contracts/fio.system/include/fio.system/fio.system.hpp index 4ef13dc0..9561264e 100755 --- a/contracts/fio.system/include/fio.system/fio.system.hpp +++ b/contracts/fio.system/include/fio.system/fio.system.hpp @@ -292,7 +292,7 @@ struct [[eosio::table, eosio::contract("fio.system")]] global_staking_state { uint64_t rewards_token_pool = 0; //total counter how much has come in from fees AND minting units SUFs uint64_t global_srp_count = 0; //total SRP for all FIO users, increment when users stake, decrement when users unstake. uint64_t daily_staking_rewards = 0; //this is used to track the daily staking rewards, - // its used only to determine if the protocol should mint FIO whe rewards are under the + // its used only to determine if the protocol should mint FIO whe rewards are under the DAILYSTAKINGMINTTHRESHOLD uint64_t staking_rewards_reserves_minted = 0; //the total amount of FIO used in minting rewards tokens, will not exceed STAKINGREWARDSRESERVEMAXIMUM EOSLIB_SERIALIZE( global_staking_state,(staked_token_pool) From 34c5f7c7410cf53906cd80615d8c52389aa406b2 Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Mon, 29 Mar 2021 15:37:59 -0600 Subject: [PATCH 03/32] add table for accountstake add table for accountstake, holding staking info used to compute rewards for each FIO account --- .../include/fio.system/fio.system.hpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/contracts/fio.system/include/fio.system/fio.system.hpp b/contracts/fio.system/include/fio.system/fio.system.hpp index 9561264e..9591d5d2 100755 --- a/contracts/fio.system/include/fio.system/fio.system.hpp +++ b/contracts/fio.system/include/fio.system/fio.system.hpp @@ -300,6 +300,25 @@ struct [[eosio::table, eosio::contract("fio.system")]] global_staking_state { (daily_staking_rewards)(staking_rewards_reserves_minted) ) }; + +//stake account table holds staking info used to compute staking rewards by FIO account +struct [[eosio::table, eosio::contract("fio.system")]] account_staking_info { + uint64_t id = 0; //unique id for ease of maintenance. primary key + name account; //the account name associated with this staking info, secondary key, + uint64_t total_srp = 0; //the staking rewards points awarded to this account, units SUS, incremented on stake, decremented on unstake. + uint64_t total_staked_fio = 0; //total fio staked by this account, units SUFs, incremented on stake, decremented on unstake. + + uint64_t primary_key() const{return id;} + uint64_t by_account() const { return account.value; } + + EOSLIB_SERIALIZE( account_staking_info,(id) + (account)(total_srp)(total_staked_fio) + ) +}; +typedef eosio::multi_index<"accountstake"_n, account_staking_info, +indexed_by<"byaccount"_n, const_mem_fun> +> account_staking_table; + //FIP-21 FIO staking typedef eosio::singleton<"global"_n, eosio_global_state> global_state_singleton; From b96802ac8080351f7b05ed016ef8b8f5a18fb1d6 Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Tue, 30 Mar 2021 11:31:56 -0600 Subject: [PATCH 04/32] fix singleton definition fix singleton definition --- contracts/fio.system/include/fio.system/fio.system.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contracts/fio.system/include/fio.system/fio.system.hpp b/contracts/fio.system/include/fio.system/fio.system.hpp index 9591d5d2..7e03fe64 100755 --- a/contracts/fio.system/include/fio.system/fio.system.hpp +++ b/contracts/fio.system/include/fio.system/fio.system.hpp @@ -284,7 +284,8 @@ indexed_by<"byowner"_n, const_mem_fun Date: Wed, 31 Mar 2021 15:47:56 -0600 Subject: [PATCH 05/32] refactor staking into its own contract refactor staking into its own contract. --- contracts/CMakeLists.txt | 1 + contracts/fio.common/fio.accounts.hpp | 1 + contracts/fio.staking/CMakeLists.txt | 13 ++ contracts/fio.staking/fio.staking.abi | 132 ++++++++++++ contracts/fio.staking/fio.staking.cpp | 197 ++++++++++++++++++ contracts/fio.staking/fio.staking.hpp | 60 ++++++ .../include/fio.system/fio.system.hpp | 43 +--- .../fio.system/include/fio.system/native.hpp | 3 +- contracts/fio.system/src/fio.system.cpp | 4 +- 9 files changed, 408 insertions(+), 46 deletions(-) create mode 100644 contracts/fio.staking/CMakeLists.txt create mode 100644 contracts/fio.staking/fio.staking.abi create mode 100644 contracts/fio.staking/fio.staking.cpp create mode 100644 contracts/fio.staking/fio.staking.hpp diff --git a/contracts/CMakeLists.txt b/contracts/CMakeLists.txt index c00a31f3..18b6b592 100644 --- a/contracts/CMakeLists.txt +++ b/contracts/CMakeLists.txt @@ -15,3 +15,4 @@ add_subdirectory(fio.fee) add_subdirectory(fio.request.obt) add_subdirectory(fio.tpid) add_subdirectory(fio.treasury) +add_subdirectory(fio.staking) diff --git a/contracts/fio.common/fio.accounts.hpp b/contracts/fio.common/fio.accounts.hpp index 32fd4093..63e82e55 100644 --- a/contracts/fio.common/fio.accounts.hpp +++ b/contracts/fio.common/fio.accounts.hpp @@ -35,6 +35,7 @@ namespace fioio { static const name TokenContract = name("fio.token"); static const name FOUNDATIONACCOUNT = name("tw4tjkmo4eyd"); static const name TREASURYACCOUNT = name("fio.treasury"); + static const name STAKINGACCOUNT = name("fio.staking"); static const name FIOSYSTEMACCOUNT= name("fio.system"); static const name FIOACCOUNT = name("fio"); diff --git a/contracts/fio.staking/CMakeLists.txt b/contracts/fio.staking/CMakeLists.txt new file mode 100644 index 00000000..d8b5c9ff --- /dev/null +++ b/contracts/fio.staking/CMakeLists.txt @@ -0,0 +1,13 @@ +add_contract(fio.staking fio.staking ${CMAKE_CURRENT_SOURCE_DIR}/fio.staking.cpp) + +target_include_directories(fio.staking + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../fio.system/include + ${CMAKE_CURRENT_SOURCE_DIR}/../ + ) + + +set_target_properties(fio.staking + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") diff --git a/contracts/fio.staking/fio.staking.abi b/contracts/fio.staking/fio.staking.abi new file mode 100644 index 00000000..e8933940 --- /dev/null +++ b/contracts/fio.staking/fio.staking.abi @@ -0,0 +1,132 @@ +{ + "____comment": "This file was generated with eosio-abigen. DO NOT EDIT Thu Jun 13 20:29:09 2019", + "version": "eosio::abi/1.1", + "structs": [ + + { + "name": "global_staking_state", + "base": "", + "fields": [ + { + "name": "staked_token_pool", + "type": "uint64" + }, + { + "name": "combined_token_pool", + "type": "uint64" + }, + { + "name": "rewards_token_pool", + "type": "uint64" + }, + { + "name": "global_srp_count", + "type": "uint64" + }, + { + "name": "daily_staking_rewards", + "type": "uint64" + }, + { + "name": "staking_rewards_reserves_minted", + "type": "uint64" + } + ] + },{ + "name": "account_staking_info", + "base": "", + "fields": [ + { + "name": "id", + "type": "uint64" + }, + { + "name": "account", + "type": "name" + }, + { + "name": "total_srp", + "type": "uint64" + }, + { + "name": "total_staked_fio", + "type": "uint64" + } + ] + },{ + "name": "stakefio", + "base": "", + "fields": [ + { + "name": "amount", + "type": "int64" + }, + { + "name": "max_fee", + "type": "int64" + }, + { + "name": "tpid", + "type": "string" + }, + { + "name": "actor", + "type": "name" + } + ] + },{ + "name": "unstakefio", + "base": "", + "fields": [ + { + "name": "amount", + "type": "int64" + }, + { + "name": "max_fee", + "type": "int64" + }, + { + "name": "tpid", + "type": "string" + }, + { + "name": "actor", + "type": "name" + } + ] + } + ], + "types": [], + "actions": [ + { + "name": "stakefio", + "type": "stakefio", + "ricardian_contract": "" + }, + { + "name": "unstakefio", + "type": "unstakefio", + "ricardian_contract": "" + } + ], + "tables": [ + { + "name": "staking", + "type": "global_staking_state", + "index_type": "i64", + "key_names": [], + "key_types": [] + }, + { + "name": "accountstake", + "type": "account_staking_info", + "index_type": "i64", + "key_names": [], + "key_types": [] + } + ], + "ricardian_clauses": [], + "variants": [], + "abi_extensions": [] +} diff --git a/contracts/fio.staking/fio.staking.cpp b/contracts/fio.staking/fio.staking.cpp new file mode 100644 index 00000000..cc6a9699 --- /dev/null +++ b/contracts/fio.staking/fio.staking.cpp @@ -0,0 +1,197 @@ +/** FioTPID implementation file + * Description: + * @author Adam Androulidakis, Ed Rotthoff + * @modifedby + * @file fio.tpid.cpp + * @license FIO Foundation ( https://github.com/fioprotocol/fio/blob/master/LICENSE ) Dapix + */ + +#include "fio.staking.hpp" + +namespace fioio { + +class [[eosio::contract("Staking")]] Staking: public eosio::contract { + +private: + + global_staking_singleton staking; + global_staking_state gstaking; + bool debugout = false; + +public: + using contract::contract; + + Staking(name s, name code, datastream ds) : + contract(s, code, ds), + staking(_self, _self.value){ + gstaking = staking.exists() ? staking.get() : global_staking_state{}; + } + + + //FIP-21 actions to update staking state. + + //perfstake performs updates to state required upon staking. + // params + // owner, + // fiostakedsufs, + // srpsawardedsuss + // logic + // call incgstake + // call incacctstake + + //perfunstake performs updates to state required upon unstaking. + // params + // owner, + // fiostakedsufs, + // srpsawardedsuss + // logic + // call decgstake + // call decacctstake + + + //incgstake performs the staking state increments when staking occurs + // params + // fiostakedsufs, this is the amount of fio staked in SUFs + // srpcountsus, this is the number of SRPs computed for this stake, units SUSs + // logic + // increment the combined_token_pool by fiostaked. + // increment the staked_token_pool by fiostaked. + // increment the global_srp_count by srpcount. + + //decgstake performs the staking state decrements when unstaking occurs + // params + // fiounstakedsufs, this is the amount of FIO being unstaked, units SUFs + // fiorewardedsufs, this is the amount of FIO being rewarded for this unstaked, units SUFs + // srpcountsus, this is the number of SRPs being rewarded for this unstake, units SUSs + // logic + // decrement the combined_token_pool by fiostaked+fiorewarded. + // decrement the staked_token_pool by fiostaked. + // decrement the global_srp_count by srpcount. + + //incgrewards performs the staking state increments when rewards are identified during fee collection. + // params + // fioamountsufs, this is the amount of FIO being added to the rewards (from fees or when minted). units SUFs + // logic + // increment rewards_token_pool + // increment daily_staking_rewards + // increment combined_token_pool. + + //clrgdailyrew performs the clearing of the daily rewards. + // params none! + // logic + // set daily_staking_rewards = 0; + + //incgstkmint increments the staking_rewards_reserves_minted + // params + // amountfiosufs, this is the amount of FIO that has been minted, units SUFs + //FIP-21 actions to update staking state. + + //FIP-21 actions to update accountstake table. + //incacctstake this performs the incrementing of account wise info upon staking. + // params + // owner, this is the account that owns the fio being staked (the signer of the stake) + // fiostakesufs, this is the amount of fio being staked, units SUFs + // srpawardedsus, this is the number of SRPs being awarded this stake, units SUSs + // logic + //decacctstake this performs the decrementing of account wise info upon staking. + // params + // owner, this is the account that owns the fio being unstaked (the signer of the unstake) + // fiostakesufs, this is the amount of FIO being unstaked, units SUFs + // srprewardedsus, this is the number of SRPs being rewarded this unstake, units SUSs + // logic + //FIP-21 actions to update accountstake table. + + + [[eosio::action]] + void stakefio(const int64_t &amount, const int64_t &max_fee, + const string &tpid, const name &actor) { + require_auth(actor); + print("EDEDEDEDEDEDEDEDEDEDEDEDED call into stakefio amount ", amount," max_fee ",max_fee," tpid ",tpid," actor ",actor, "\n"); + + /* + * Request is validated per Exception handling. + * + stake_fio_tokens fee is collected. + + RAM of signer is increased. amount of RAM increase will be computed during development and updated in this FIP + + SRPs to Award are computed: amount / Rate of Exchange + + Account Tokens Staked is incremented by amount in account related table. Account Tokens Staked cannot be spent by the user. + Account Staking Reward Point is incremented by SRPs to Award in account related table + (call incacctstake) + + Combined Token Pool count is incremented by amount. + Global SRP count is incremented by SRPs to Award. + staked_token_pool is incremented by amount. + (call incgstake) + + + check for maximum FIO transaction size is applied + + Account not voted or proxied Staker's account has not voted in the last 30 days and is not proxying. 400 "actor" Value sent in, e.g. "aftyershcu22" "Account has not voted in the last 30 days and is not proxying." + Invalid amount value amount format is not valid 400 "amount" Value sent in, e.g. "-100" "Invalid amount value" + Invalid fee value max_fee format is not valid 400 "max_fee" Value sent in, e.g. "-100" "Invalid fee value" + Fee exceeds maximum Actual fee is greater than supplied max_fee 400 "max_fee" Value sent in, e.g. "1000000000" "Fee exceeds supplied maximum" + Insufficient balance Available (unlocked and unstaked) balance in Staker's account is less than chain fee + amount 400 "max_oracle_fee" Value sent in, e.g. "100000000000" "Insufficient balance" + Invalid TPID tpid format is not valid 400 "tpid" Value sent in, e.g. "notvalidfioaddress" "TPID must be empty or valid FIO address" + Signer not actor Signer not actor 403 Type: invalid_signature + */ + + check(is_account(actor),"account must pre exist"); + check(amount > 0,"cannot stake token amount less or equal 0."); + } + + [[eosio::action]] + void unstakefio(const int64_t &amount, const int64_t &max_fee, + const string &tpid, const name &actor) { + require_auth(actor); + print("EDEDEDEDEDEDEDEDEDEDEDEDED call into unstakefio amount ", amount," max_fee ",max_fee," tpid ",tpid," actor ",actor, "\n"); + + /* + * Request is validated per Exception handling. + * + unstake_fio_tokens fee is collected. + + RAM of signer is increased, amount of ram increment will be computed and updated into FIP during development + + SRPs to Claim are computed: Staker's Account SRPs * (Unstaked amount / Total Tokens Staked in Staker's Account) + + Staking Reward Amount is computed: ((SRPs to Claim * Rate of Exchnage) - Unstake amount) * 0.9 + + TPID Reward Amount is computed: ((SRPs to Claim * Rate of Exchnage) - Unstake amount) * 0.1 + + Account Tokens Staked is decremented by amount in account related table. + Account Staking Reward Point is decremented by SRPs to Award in account related table + (call decacctstake) + + Staking Reward Amount is transferred to Staker's Account. + Memo: "Paying Staking Rewards" + + Global SRP count is decremented by SRPs to Claim . + Combined Token Pool count is decremented by amount + Staking Reward Amount. + staked token pool is decremented by amount + (call decgstake) + + If tpid was provided, TPID Reward Amount is awarded to the tpid and decremented from Combined Token Pool. + check for max FIO transaction size exceeded will be applied. + + amount + Staking Reward Amount is locked in Staker's Account for 7 days. + + Invalid amount value amount format is not valid 400 "amount" Value sent in, e.g. "-100" "Invalid amount value" + Ustake exceeds staked amount to unstake is greater than the total staked by account 400 "amount" Value sent in, e.g. "100000000000" "Cannot unstake more than staked." + Invalid fee value max_fee format is not valid 400 "max_fee" Value sent in, e.g. "-100" "Invalid fee value" + Fee exceeds maximum Actual fee is greater than supplied max_fee 400 "max_fee" Value sent in, e.g. "1000000000" "Fee exceeds supplied maximum" + Insufficient balance Available (unlocked and unstaked) balance in Staker's account is less than chain fee + amount 400 "max_oracle_fee" Value sent in, e.g. "100000000000" "Insufficient balance" + Invalid TPID tpid format is not valid 400 "tpid" Value sent in, e.g. "notvalidfioaddress" "TPID must be empty or valid FIO address" + Signer not actor Signer not actor 403 Type: invalid_signature + */ + + check(is_account(actor),"account must pre exist"); + check(amount > 0,"cannot unstake token amount less or equal 0."); + } + +}; //class Staking + +EOSIO_DISPATCH(Staking, (stakefio)(unstakefio) ) +} diff --git a/contracts/fio.staking/fio.staking.hpp b/contracts/fio.staking/fio.staking.hpp new file mode 100644 index 00000000..3f76be1b --- /dev/null +++ b/contracts/fio.staking/fio.staking.hpp @@ -0,0 +1,60 @@ +/** FioTPID implementation file + * Description: + * @author Adam Androulidakis + * @modifedby + * @file fio.tpid.cpp + * @license FIO Foundation ( https://github.com/fioprotocol/fio/blob/master/LICENSE ) Dapix + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace fioio { + using namespace eosio; + + + //staking info is a global state table used to track information relating to staking within the FIO protocol. + struct [[eosio::table("staking"), eosio::contract("fio.staking")]] global_staking_state { + global_staking_state() {} + uint64_t staked_token_pool = 0; //total FIO tokens staked for all accounts, units sufs. + uint64_t combined_token_pool = 0; //total fio tokens staked for all accounts plus fio rewards all accounts, units SUFs, + // incremented by the staked amount when user stakes, when tokens are earmarked as staking rewards, + // decremented by unstaked amount + reward amount when users unstake + uint64_t rewards_token_pool = 0; //total counter how much has come in from fees AND minting units SUFs + uint64_t global_srp_count = 0; //total SRP for all FIO users, increment when users stake, decrement when users unstake. + uint64_t daily_staking_rewards = 0; //this is used to track the daily staking rewards collected from fees, + // its used only to determine if the protocol should mint FIO whe rewards are under the DAILYSTAKINGMINTTHRESHOLD + uint64_t staking_rewards_reserves_minted = 0; //the total amount of FIO used in minting rewards tokens, will not exceed STAKINGREWARDSRESERVEMAXIMUM + + EOSLIB_SERIALIZE( global_staking_state,(staked_token_pool) + (combined_token_pool)(rewards_token_pool)(global_srp_count) + (daily_staking_rewards)(staking_rewards_reserves_minted) + ) + }; + + //stake account table holds staking info used to compute staking rewards by FIO account + struct [[eosio::table, eosio::contract("fio.staking")]] account_staking_info { + uint64_t id = 0; //unique id for ease of maintenance. primary key + name account; //the account name associated with this staking info, secondary key, + uint64_t total_srp = 0; //the staking rewards points awarded to this account, units SUS, incremented on stake, decremented on unstake. + uint64_t total_staked_fio = 0; //total fio staked by this account, units SUFs, incremented on stake, decremented on unstake. + + uint64_t primary_key() const{return id;} + uint64_t by_account() const { return account.value; } + + EOSLIB_SERIALIZE( account_staking_info,(id) + (account)(total_srp)(total_staked_fio) + ) + }; + typedef eosio::multi_index<"accountstake"_n, account_staking_info, + indexed_by<"byaccount"_n, const_mem_fun> + > account_staking_table; + + + typedef eosio::singleton<"staking"_n, global_staking_state> global_staking_singleton; +} diff --git a/contracts/fio.system/include/fio.system/fio.system.hpp b/contracts/fio.system/include/fio.system/fio.system.hpp index 7e03fe64..fc4e3431 100755 --- a/contracts/fio.system/include/fio.system/fio.system.hpp +++ b/contracts/fio.system/include/fio.system/fio.system.hpp @@ -282,50 +282,11 @@ indexed_by<"byowner"_n, const_mem_fun voters_table; -//FIP-21 FIO staking -//staking info is a global state table used to track information relating to staking within the FIO protocol. -struct [[eosio::table("staking"), eosio::contract("fio.system")]] global_staking_state { - global_staking_state() {} - uint64_t staked_token_pool = 0; //total FIO tokens staked for all accounts, units sufs. - uint64_t combined_token_pool = 0; //total fio tokens staked for all accounts plus fio rewards all accounts, units SUFs, - // incremented when user stakes, when tokens are earmarked as staking rewards, - // decremented by unstaked amount + reward amount when users unstake - uint64_t rewards_token_pool = 0; //total counter how much has come in from fees AND minting units SUFs - uint64_t global_srp_count = 0; //total SRP for all FIO users, increment when users stake, decrement when users unstake. - uint64_t daily_staking_rewards = 0; //this is used to track the daily staking rewards, - // its used only to determine if the protocol should mint FIO whe rewards are under the DAILYSTAKINGMINTTHRESHOLD - uint64_t staking_rewards_reserves_minted = 0; //the total amount of FIO used in minting rewards tokens, will not exceed STAKINGREWARDSRESERVEMAXIMUM - - EOSLIB_SERIALIZE( global_staking_state,(staked_token_pool) - (combined_token_pool)(rewards_token_pool)(global_srp_count) - (daily_staking_rewards)(staking_rewards_reserves_minted) - ) -}; - -//stake account table holds staking info used to compute staking rewards by FIO account -struct [[eosio::table, eosio::contract("fio.system")]] account_staking_info { - uint64_t id = 0; //unique id for ease of maintenance. primary key - name account; //the account name associated with this staking info, secondary key, - uint64_t total_srp = 0; //the staking rewards points awarded to this account, units SUS, incremented on stake, decremented on unstake. - uint64_t total_staked_fio = 0; //total fio staked by this account, units SUFs, incremented on stake, decremented on unstake. - - uint64_t primary_key() const{return id;} - uint64_t by_account() const { return account.value; } - - EOSLIB_SERIALIZE( account_staking_info,(id) - (account)(total_srp)(total_staked_fio) - ) -}; -typedef eosio::multi_index<"accountstake"_n, account_staking_info, -indexed_by<"byaccount"_n, const_mem_fun> -> account_staking_table; - -//FIP-21 FIO staking typedef eosio::singleton<"global"_n, eosio_global_state> global_state_singleton; typedef eosio::singleton<"global2"_n, eosio_global_state2> global_state2_singleton; typedef eosio::singleton<"global3"_n, eosio_global_state3> global_state3_singleton; -typedef eosio::singleton<"staking"_n, global_staking_state> global_staking_singleton; + static constexpr uint32_t seconds_per_day = 24 * 3600; @@ -343,11 +304,9 @@ class [[eosio::contract("fio.system")]] system_contract : public native { global_state_singleton _global; global_state2_singleton _global2; global_state3_singleton _global3; - global_staking_singleton _staking; eosio_global_state _gstate; eosio_global_state2 _gstate2; eosio_global_state3 _gstate3; - global_staking_state _gstaking; fioio::fionames_table _fionames; fioio::domains_table _domains; fioio::fiofee_table _fiofees; diff --git a/contracts/fio.system/include/fio.system/native.hpp b/contracts/fio.system/include/fio.system/native.hpp index 16b51e84..c43a4b90 100755 --- a/contracts/fio.system/include/fio.system/native.hpp +++ b/contracts/fio.system/include/fio.system/native.hpp @@ -147,7 +147,8 @@ namespace eosiosystem { account == fioio::TokenContract || account == fioio::TREASURYACCOUNT || account == fioio::FIOSYSTEMACCOUNT || - account == fioio::FIOACCOUNT) + account == fioio::STAKINGACCOUNT || + account == fioio::FIOACCOUNT ) ) { //get the sizes of the tx. diff --git a/contracts/fio.system/src/fio.system.cpp b/contracts/fio.system/src/fio.system.cpp index 8e51bf5a..0ba69727 100755 --- a/contracts/fio.system/src/fio.system.cpp +++ b/contracts/fio.system/src/fio.system.cpp @@ -25,7 +25,6 @@ namespace eosiosystem { _global(_self, _self.value), _global2(_self, _self.value), _global3(_self, _self.value), - _staking(_self, _self.value), _lockedtokens(_self,_self.value), _generallockedtokens(_self, _self.value), _fionames(AddressContract, AddressContract.value), @@ -35,7 +34,6 @@ namespace eosiosystem { _gstate = _global.exists() ? _global.get() : get_default_parameters(); _gstate2 = _global2.exists() ? _global2.get() : eosio_global_state2{}; _gstate3 = _global3.exists() ? _global3.get() : eosio_global_state3{}; - _gstaking = _staking.exists() ? _staking.get() : global_staking_state{}; } eosiosystem::eosio_global_state eosiosystem::system_contract::get_default_parameters() { @@ -176,6 +174,7 @@ namespace eosiosystem { acnt == TPIDContract || acnt == TokenContract || acnt == TREASURYACCOUNT || + acnt == STAKINGACCOUNT || acnt == FIOSYSTEMACCOUNT || acnt == FIOACCOUNT),"set abi not permitted." ); @@ -219,7 +218,6 @@ namespace eosiosystem { }); } - void eosiosystem::system_contract::addgenlocked(const name &owner, const vector &periods, const bool &canvote, const int64_t &amount) { require_auth(TokenContract); From 20343d20960a72783a54cf9bce003447005dc8f1 Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Wed, 31 Mar 2021 18:47:46 -0600 Subject: [PATCH 06/32] comments comments --- contracts/fio.staking/fio.staking.cpp | 8 ++++---- contracts/fio.staking/fio.staking.hpp | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/contracts/fio.staking/fio.staking.cpp b/contracts/fio.staking/fio.staking.cpp index cc6a9699..c42fcc31 100644 --- a/contracts/fio.staking/fio.staking.cpp +++ b/contracts/fio.staking/fio.staking.cpp @@ -1,9 +1,9 @@ -/** FioTPID implementation file +/** Fio Staking implementation file * Description: - * @author Adam Androulidakis, Ed Rotthoff + * @author Ed Rotthoff * @modifedby - * @file fio.tpid.cpp - * @license FIO Foundation ( https://github.com/fioprotocol/fio/blob/master/LICENSE ) Dapix + * @file fio.staking.cpp + * @license FIO Foundation ( https://github.com/fioprotocol/fio/blob/master/LICENSE ) */ #include "fio.staking.hpp" diff --git a/contracts/fio.staking/fio.staking.hpp b/contracts/fio.staking/fio.staking.hpp index 3f76be1b..1091f9a3 100644 --- a/contracts/fio.staking/fio.staking.hpp +++ b/contracts/fio.staking/fio.staking.hpp @@ -1,9 +1,9 @@ -/** FioTPID implementation file +/** Fio Staking implementation file * Description: - * @author Adam Androulidakis + * @author Ed Rotthoff * @modifedby - * @file fio.tpid.cpp - * @license FIO Foundation ( https://github.com/fioprotocol/fio/blob/master/LICENSE ) Dapix + * @file fio.staking.cpp + * @license FIO Foundation ( https://github.com/fioprotocol/fio/blob/master/LICENSE ) */ #pragma once @@ -54,7 +54,7 @@ namespace fioio { typedef eosio::multi_index<"accountstake"_n, account_staking_info, indexed_by<"byaccount"_n, const_mem_fun> > account_staking_table; - + typedef eosio::singleton<"staking"_n, global_staking_state> global_staking_singleton; } From 7a0a3eb09d52a86e5dfc3b6b2c3442e9133a1861 Mon Sep 17 00:00:00 2001 From: Casey Gardiner <44983607+fiocasey@users.noreply.github.com> Date: Fri, 2 Apr 2021 14:03:40 -0600 Subject: [PATCH 07/32] Revert "[FIP-1.b] Contracts Part 3: Final Integration of request and obt data restructuring. (#183)(OLD #10)" --- contracts/fio.request.obt/fio.request.obt.abi | 239 ++++++++++++++++++ contracts/fio.request.obt/fio.request.obt.cpp | 71 +++++- contracts/fio.request.obt/fio.request.obt.hpp | 126 ++++++++- 3 files changed, 430 insertions(+), 6 deletions(-) diff --git a/contracts/fio.request.obt/fio.request.obt.abi b/contracts/fio.request.obt/fio.request.obt.abi index a0cbe996..0ebc5714 100644 --- a/contracts/fio.request.obt/fio.request.obt.abi +++ b/contracts/fio.request.obt/fio.request.obt.abi @@ -5,6 +5,148 @@ ], "structs":[ + { + "name":"fioreqctxt", + "base":"", + "fields":[ + { + "name":"fio_request_id", + "type":"uint64" + }, + { + "name":"payer_fio_address", + "type":"uint128" + }, + { + "name":"payee_fio_address", + "type":"uint128" + }, + { + "name":"payer_fio_address_hex_str", + "type":"string" + }, + { + "name":"payee_fio_address_hex_str", + "type":"string" + }, + { + "name":"payer_fio_address_with_time", + "type":"uint128" + }, + { + "name":"payee_fio_address_with_time", + "type":"uint128" + }, + { + "name":"content", + "type":"string" + }, + { + "name":"time_stamp", + "type":"uint64" + }, + { + "name":"payer_fio_addr", + "type":"string" + }, + { + "name":"payee_fio_addr", + "type":"string" + }, + { + "name":"payer_key", + "type":"string" + }, + { + "name":"payee_key", + "type":"string" + } + ] + }, + { + "name":"recordobt_info", + "base":"", + "fields":[ + { + "name":"id", + "type":"uint64" + }, + { + "name":"payer_fio_address", + "type":"uint128" + }, + { + "name":"payee_fio_address", + "type":"uint128" + }, + { + "name":"payer_fio_address_hex_str", + "type":"string" + }, + { + "name":"payee_fio_address_hex_str", + "type":"string" + }, + { + "name":"payer_fio_address_with_time", + "type":"uint128" + }, + { + "name":"payee_fio_address_with_time", + "type":"uint128" + }, + { + "name":"content", + "type":"string" + }, + { + "name":"time_stamp", + "type":"uint64" + }, + { + "name":"payer_fio_addr", + "type":"string" + }, + { + "name":"payee_fio_addr", + "type":"string" + }, + { + "name":"payer_key", + "type":"string" + }, + { + "name":"payee_key", + "type":"string" + } + ] + }, + { + "name":"fioreqsts", + "base":"", + "fields":[ + { + "name":"id", + "type":"uint64" + }, + { + "name":"fio_request_id", + "type":"uint64" + }, + { + "name":"status", + "type":"uint64" + }, + { + "name":"metadata", + "type":"string" + }, + { + "name":"time_stamp", + "type":"uint64" + } + ] + }, { "name":"fiotrxt_info", "base":"", @@ -71,6 +213,54 @@ } ] }, + { + "name":"migrledger", + "base":"", + "fields":[ + { + "name":"id", + "type":"uint64" + }, + { + "name":"beginobt", + "type":"int64" + }, + { + "name":"currentobt", + "type":"int64" + }, + { + "name":"beginrq", + "type":"int64" + }, + { + "name":"currentrq", + "type":"int64" + }, + { + "name":"currentsta", + "type":"int64" + }, + { + "name":"isFinished", + "type":"int8" + } + ] + }, + { + "name":"migrtrx", + "base":"", + "fields":[ + { + "name":"amount", + "type":"int16" + }, + { + "name":"actor", + "type":"string" + } + ] + }, { "name":"recordobt", "base":"", @@ -181,6 +371,11 @@ } ], "actions":[ + { + "name":"migrtrx", + "type":"migrtrx", + "ricardian_contract":"" + }, { "name":"recordobt", "type":"recordobt", @@ -203,6 +398,39 @@ } ], "tables":[ + { + "name":"fioreqctxts", + "index_type":"i64", + "key_names":[ + "fio_request_id" + ], + "key_types":[ + "uint64" + ], + "type":"fioreqctxt" + }, + { + "name":"recordobts", + "index_type":"i64", + "key_names":[ + "id" + ], + "key_types":[ + "uint64" + ], + "type":"recordobt_info" + }, + { + "name":"fioreqstss", + "index_type":"i64", + "key_names":[ + "id" + ], + "key_types":[ + "uint64" + ], + "type":"fioreqsts" + }, { "name":"fiotrxtss", "index_type":"i64", @@ -213,6 +441,17 @@ "uint64" ], "type":"fiotrxt_info" + }, + { + "name":"migrledgers", + "index_type":"i64", + "key_names":[ + "id" + ], + "key_types":[ + "uint64" + ], + "type":"migrledger" } ], "ricardian_clauses":[ diff --git a/contracts/fio.request.obt/fio.request.obt.cpp b/contracts/fio.request.obt/fio.request.obt.cpp index 2c70e3da..d8615735 100644 --- a/contracts/fio.request.obt/fio.request.obt.cpp +++ b/contracts/fio.request.obt/fio.request.obt.cpp @@ -21,27 +21,92 @@ namespace fioio { class [[eosio::contract("FioRequestObt")]] FioRequestObt : public eosio::contract { private: - fiotrxts_contexts_table fioTransactionsTable; + fiotrxts_contexts_table fioTransactionsTable; //Migration Table + migrledgers_table mgrStatsTable; // Migration Ledger (temp) + fiorequest_contexts_table fiorequestContextsTable; + fiorequest_status_table fiorequestStatusTable; fionames_table fionames; domains_table domains; eosio_names_table clientkeys; fiofee_table fiofees; config appConfig; tpids_table tpids; + recordobt_table recordObtTable; + + eosiosystem::producers_table producers; // Temp reference used for migration public: explicit FioRequestObt(name s, name code, datastream ds) : contract(s, code, ds), fioTransactionsTable(_self, _self.value), + fiorequestContextsTable(_self, _self.value), + fiorequestStatusTable(_self, _self.value), fionames(AddressContract, AddressContract.value), domains(AddressContract, AddressContract.value), fiofees(FeeContract, FeeContract.value), clientkeys(AddressContract, AddressContract.value), - tpids(AddressContract, AddressContract.value){ + tpids(AddressContract, AddressContract.value), + producers(SYSTEMACCOUNT, SYSTEMACCOUNT.value), //Temp + mgrStatsTable(_self, _self.value), // Temp + recordObtTable(_self,_self.value) { configs_singleton configsSingleton(FeeContract, FeeContract.value); appConfig = configsSingleton.get_or_default(config()); } + //TEMP MIGRATION ACTION + // @abi action + [[eosio::action]] + void migrtrx(const uint16_t amount, const string &actor) { + name executor = name("fio.reqobt"); + name aactor = name(actor); + require_auth(aactor); + + auto prodbyowner = producers.get_index<"byowner"_n>(); + auto proditer = prodbyowner.find(aactor.value); + + fio_400_assert(proditer != prodbyowner.end(), "actor", actor, + "Actor not active producer", ErrorNoFioAddressProducer); + + uint16_t limit = amount; + uint16_t count = 0; + bool isSuccessful = false; + if (amount > 25) { limit = 25; } + auto obtTable = recordObtTable.begin(); + auto reqTable = fiorequestContextsTable.begin(); + auto statTable = fiorequestStatusTable.begin(); + auto trxTable = fioTransactionsTable.begin(); + + auto migrLedger = mgrStatsTable.begin(); + if (migrLedger != mgrStatsTable.end()) { mgrStatsTable.erase(migrLedger); } + + while (obtTable != recordObtTable.end()) { //obt record migrate + recordObtTable.erase(obtTable); + count++; + obtTable = recordObtTable.begin(); + if (count == limit) { return; } + } + + if (count != limit) { //request table migrate + while (reqTable != fiorequestContextsTable.end()) { + fiorequestContextsTable.erase(reqTable); + count++; + reqTable = fiorequestContextsTable.begin(); + if (count == limit) { return; } + } + } + + if (count != limit) { //status table migrate + while (statTable != fiorequestStatusTable.end()) { + fiorequestStatusTable.erase(statTable); + count++; + statTable = fiorequestStatusTable.begin(); + if (count == limit) { return; } + } + } + } + // END OF TEMP MIGRATION ACTION + + /******* * This action will record the send of funds from one FIO address to another, either * in response to a request for funds or as a result of a direct send of funds from @@ -694,5 +759,5 @@ namespace fioio { } }; - EOSIO_DISPATCH(FioRequestObt, (recordobt)(newfundsreq)(rejectfndreq)(cancelfndreq)) + EOSIO_DISPATCH(FioRequestObt, (migrtrx)(recordobt)(newfundsreq)(rejectfndreq)(cancelfndreq)) } diff --git a/contracts/fio.request.obt/fio.request.obt.hpp b/contracts/fio.request.obt/fio.request.obt.hpp index 4387a161..0a1251b0 100644 --- a/contracts/fio.request.obt/fio.request.obt.hpp +++ b/contracts/fio.request.obt/fio.request.obt.hpp @@ -2,10 +2,9 @@ * Description: The FIO request other blockchain transaction (or obt) contract contains the * tables that hold the requests for funds that have been made along with the status of any * response to each request for funds. - * @author Casey Gardiner, Adam Androulidakis - * + * @author Adam Androulidakis, Casey Gardiner, Ciju John, Ed Rotthoff * @file fio.request.obt.hpp - * @license FIO Foundation ( https://github.com/fioprotocol/fio/blob/master/LICENSE ) + * @license FIO Foundation ( https://github.com/fioprotocol/fio/blob/master/LICENSE ) Dapix */ @@ -33,6 +32,106 @@ namespace fioio { other = 5 //Future Use }; + // The request context table holds the requests for funds that have been requested, it provides + // searching by id, payer and payee. + // @abi table fioreqctxts i64 + struct [[eosio::action]] fioreqctxt { + uint64_t fio_request_id; + uint128_t payer_fio_address; + uint128_t payee_fio_address; + string payer_fio_address_hex_str; + string payee_fio_address_hex_str; + uint128_t payer_fio_address_with_time; + uint128_t payee_fio_address_with_time; + string content; //this content is a encrypted blob containing the details of the request. + uint64_t time_stamp; + string payer_fio_addr; + string payee_fio_addr; + string payer_key = nullptr; + string payee_key = nullptr; + + uint64_t primary_key() const { return fio_request_id; } + uint128_t by_receiver() const { return payer_fio_address; } + uint128_t by_originator() const { return payee_fio_address; } + uint128_t by_payerwtime() const { return payer_fio_address_with_time;} + uint128_t by_payeewtime() const { return payee_fio_address_with_time;} + + EOSLIB_SERIALIZE(fioreqctxt, + (fio_request_id)(payer_fio_address)(payee_fio_address)(payer_fio_address_hex_str)(payee_fio_address_hex_str) + (payer_fio_address_with_time)(payee_fio_address_with_time) + (content)(time_stamp)(payer_fio_addr)(payee_fio_addr)(payer_key)(payee_key) + ) + }; + + + typedef multi_index<"fioreqctxts"_n, fioreqctxt, + indexed_by<"byreceiver"_n, const_mem_fun < fioreqctxt, uint128_t, &fioreqctxt::by_receiver>>, + indexed_by<"byoriginator"_n, const_mem_fun>, + indexed_by<"bypayerwtime"_n, const_mem_fun>, + indexed_by<"bypayeewtime"_n, const_mem_fun + >> + fiorequest_contexts_table; + + //this struct holds records relating to the items sent via record obt, we call them recordobt_info items. + struct [[eosio::action]] recordobt_info { + uint64_t id; + uint128_t payer_fio_address; + uint128_t payee_fio_address; + string payer_fio_address_hex_str; + string payee_fio_address_hex_str; + uint128_t payer_fio_address_with_time; + uint128_t payee_fio_address_with_time; + string content; //this content is a encrypted blob containing the details of the request. + uint64_t time_stamp; + string payer_fio_addr; + string payee_fio_addr; + string payer_key = nullptr; + string payee_key = nullptr; + + uint64_t primary_key() const { return id; } + uint128_t by_payee() const { return payee_fio_address; } + uint128_t by_payer() const { return payer_fio_address; } + uint128_t by_payeewtime() const { return payee_fio_address_with_time; } + uint128_t by_payerwtime() const { return payer_fio_address_with_time; } + + + EOSLIB_SERIALIZE(recordobt_info, + (id)(payer_fio_address)(payee_fio_address)(payer_fio_address_hex_str)(payee_fio_address_hex_str) + (payer_fio_address_with_time)(payee_fio_address_with_time) + (content)(time_stamp)(payer_fio_addr)(payee_fio_addr)(payer_key)(payee_key) + ) + }; + + typedef multi_index<"recordobts"_n, recordobt_info, + indexed_by<"bypayee"_n, const_mem_fun < recordobt_info, uint128_t, &recordobt_info::by_payee>>, + indexed_by<"bypayer"_n, const_mem_fun>, + indexed_by<"bypayerwtime"_n, const_mem_fun>, + indexed_by<"bypayeewtime"_n, const_mem_fun + >> + recordobt_table; + + // The FIO request status table references FIO requests that have had funds sent, or have been rejected. + // the table provides a means to find the status of a request. + // @abi table fioreqstss i64 + struct [[eosio::action]] fioreqsts { + uint64_t id; + uint64_t fio_request_id; + uint64_t status; + string metadata; //this contains a json string with meta data regarding the response to a request. + uint64_t time_stamp; + + uint64_t primary_key() const { return id; } + uint64_t by_fioreqid() const { return fio_request_id; } + + EOSLIB_SERIALIZE(fioreqsts, (id)(fio_request_id)(status)(metadata)(time_stamp) + ) + }; + + typedef multi_index<"fioreqstss"_n, fioreqsts, + indexed_by<"byfioreqid"_n, const_mem_fun < fioreqsts, uint64_t, &fioreqsts::by_fioreqid> > + > + fiorequest_status_table; + // The request context table holds the requests for funds that have been requested, it provides // searching by id, payer and payee. // @abi table fiotrxt_info i64 @@ -102,4 +201,25 @@ namespace fioio { indexed_by<"bypayeereq"_n, const_mem_fun >> fiotrxts_contexts_table; + + struct [[eosio::action]] migrledger { + + uint64_t id; + + uint64_t beginobt = -1; + uint64_t currentobt = 0; + + uint64_t beginrq = -1; + uint64_t currentrq = 0; + + uint64_t currentsta = 0; + + uint8_t isFinished = 0; + + uint64_t primary_key() const { return id; } + + EOSLIB_SERIALIZE(migrledger, (id)(beginobt)(currentobt)(beginrq)(currentrq)(currentsta)(isFinished)) + }; + + typedef multi_index<"migrledgers"_n, migrledger> migrledgers_table; } From e2d02fed3bab0c5693215a968aaae10e95bd4060 Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Wed, 28 Apr 2021 11:10:05 -0600 Subject: [PATCH 08/32] implemnent actions called by system implement actions called by system --- contracts/fio.staking/fio.staking.abi | 84 +++++++++++++++++++ contracts/fio.staking/fio.staking.cpp | 114 ++++++++++++++++++++++++-- contracts/fio.staking/fio.staking.hpp | 4 +- 3 files changed, 192 insertions(+), 10 deletions(-) diff --git a/contracts/fio.staking/fio.staking.abi b/contracts/fio.staking/fio.staking.abi index e8933940..2eebb907 100644 --- a/contracts/fio.staking/fio.staking.abi +++ b/contracts/fio.staking/fio.staking.abi @@ -53,6 +53,70 @@ "type": "uint64" } ] + },{ + "name": "decgstake", + "base": "", + "fields": [ + { + "name": "fiostakedsufs", + "type": "int64" + }, + { + "name": "fiorewardedsufs", + "type": "int64" + }, + { + "name": "srpcountsus", + "type": "int64" + } + ] + },{ + "name": "incgstake", + "base": "", + "fields": [ + { + "name": "fiostakedsufs", + "type": "int64" + }, + { + "name": "srpcountsus", + "type": "int64" + } + ] + },{ + "name": "incacctstake", + "base": "", + "fields": [ + { + "name": "owner", + "type": "name" + }, + { + "name": "fiostakedsufs", + "type": "int64" + }, + { + "name": "srpaawardedsus", + "type": "int64" + } + ] + },{ + "name": "decacctstake", + "base": "", + "fields": [ + { + "name": "owner", + "type": "name" + }, + { + "name": "fiostakedsufs", + "type": "int64" + }, + { + "name": "srprewardedsus", + "type": "int64" + } + ] },{ "name": "stakefio", "base": "", @@ -99,6 +163,26 @@ ], "types": [], "actions": [ + { + "name": "decgstake", + "type": "decgstake", + "ricardian_contract": "" + }, + { + "name": "incgstake", + "type": "incgstake", + "ricardian_contract": "" + }, + { + "name": "incacctstake", + "type": "incacctstake", + "ricardian_contract": "" + }, + { + "name": "decacctstake", + "type": "decacctstake", + "ricardian_contract": "" + }, { "name": "stakefio", "type": "stakefio", diff --git a/contracts/fio.staking/fio.staking.cpp b/contracts/fio.staking/fio.staking.cpp index c42fcc31..5b422c24 100644 --- a/contracts/fio.staking/fio.staking.cpp +++ b/contracts/fio.staking/fio.staking.cpp @@ -16,6 +16,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { global_staking_singleton staking; global_staking_state gstaking; + account_staking_table accountstaking; bool debugout = false; public: @@ -23,13 +24,19 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { Staking(name s, name code, datastream ds) : contract(s, code, ds), - staking(_self, _self.value){ + staking(_self, _self.value), + accountstaking(_self,_self.value){ gstaking = staking.exists() ? staking.get() : global_staking_state{}; } + ~Staking() { + staking.set(gstaking, _self); + } + //FIP-21 actions to update staking state. + //(implement 5) //perfstake performs updates to state required upon staking. // params // owner, @@ -39,6 +46,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { // call incgstake // call incacctstake + //(implement 6) //perfunstake performs updates to state required upon unstaking. // params // owner, @@ -49,6 +57,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { // call decacctstake + // (implement 1) //incgstake performs the staking state increments when staking occurs // params // fiostakedsufs, this is the amount of fio staked in SUFs @@ -57,7 +66,21 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { // increment the combined_token_pool by fiostaked. // increment the staked_token_pool by fiostaked. // increment the global_srp_count by srpcount. - + // + [[eosio::action]] + void incgstake(const int64_t &fiostakedsufs, const int64_t &srpcountsus) { + //check auth fio.staking or fio.system + eosio_assert((has_auth(SYSTEMACCOUNT) || has_auth(STAKINGACCOUNT)), + "missing required authority of staking or eosio"); + // increment the combined_token_pool by fiostaked. + gstaking.combined_token_pool += fiostakedsufs; + // increment the staked_token_pool by fiostaked. + gstaking.staked_token_pool += fiostakedsufs; + // increment the global_srp_count by srpcount. + gstaking.global_srp_count += srpcountsus; + } + + //(implement 2) //decgstake performs the staking state decrements when unstaking occurs // params // fiounstakedsufs, this is the amount of FIO being unstaked, units SUFs @@ -67,7 +90,26 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { // decrement the combined_token_pool by fiostaked+fiorewarded. // decrement the staked_token_pool by fiostaked. // decrement the global_srp_count by srpcount. - + [[eosio::action]] + void decgstake(const int64_t &fiostakedsufs, const int64_t &fiorewardededsufs,const int64_t &srpcountsus) { + //check auth fio.staking or fio.system + eosio_assert((has_auth(SYSTEMACCOUNT) || has_auth(STAKINGACCOUNT)), + "missing required authority of staking or eosio"); + + eosio_assert(gstaking.combined_token_pool >= (fiostakedsufs+fiorewardededsufs),"decgstake combined token pool must be greater or equal to staked sufs plus fio rewarded sufs. " ); + eosio_assert(gstaking.staked_token_pool >= fiostakedsufs,"decgstake staked token pool must be greater or equal to staked sufs. " ); + eosio_assert(gstaking.global_srp_count >= srpcountsus,"decgstake global srp count must be greater or equal to srp count. " ); + + + // decrement the combined_token_pool by fiostaked+fiorewarded. + gstaking.combined_token_pool -= (fiostakedsufs+fiorewardededsufs); + // decrement the staked_token_pool by fiostaked. + gstaking.staked_token_pool -= fiostakedsufs; + // decrement the global_srp_count by srpcount. + gstaking.global_srp_count -= srpcountsus; + } + + //(implement 7) //incgrewards performs the staking state increments when rewards are identified during fee collection. // params // fioamountsufs, this is the amount of FIO being added to the rewards (from fees or when minted). units SUFs @@ -76,16 +118,19 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { // increment daily_staking_rewards // increment combined_token_pool. + //(implement 8) //clrgdailyrew performs the clearing of the daily rewards. // params none! // logic // set daily_staking_rewards = 0; + //(implement 9) //incgstkmint increments the staking_rewards_reserves_minted // params // amountfiosufs, this is the amount of FIO that has been minted, units SUFs //FIP-21 actions to update staking state. + //(implement 3) //FIP-21 actions to update accountstake table. //incacctstake this performs the incrementing of account wise info upon staking. // params @@ -93,6 +138,35 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { // fiostakesufs, this is the amount of fio being staked, units SUFs // srpawardedsus, this is the number of SRPs being awarded this stake, units SUSs // logic + [[eosio::action]] + void incacctstake(const name &owner, const int64_t &fiostakedsufs, const int64_t &srpaawardedsus) { + //check auth fio.staking or fio.system + eosio_assert((has_auth(SYSTEMACCOUNT) || has_auth(STAKINGACCOUNT)), + "missing required authority of staking or eosio"); + eosio_assert(fiostakedsufs > 0,"incacctstake fiostakedsuf must be greater than 0. " ); + eosio_assert(srpaawardedsus > 0,"srpaawardedsus fiostakedsuf must be greater than 0. " ); + + auto astakebyaccount = accountstaking.get_index<"byaccount"_n>(); + auto astakeiter = astakebyaccount.find(owner.value); + if (astakeiter != astakebyaccount.end()) { + eosio_assert(astakeiter->account == owner,"incacctstake owner lookup error." ); + //update the existing record + astakebyaccount.modify(astakeiter, _self, [&](struct account_staking_info &a) { + a.total_staked_fio += fiostakedsufs; + a.total_srp += srpaawardedsus; + }); + } else { + const uint64_t id = accountstaking.available_primary_key(); + accountstaking.emplace(get_self(), [&](struct account_staking_info &p) { + p.id = id; + p.account = owner; + p.total_staked_fio = fiostakedsufs; + p.total_srp = srpaawardedsus; + }); + } + } + + //(implement 4) //decacctstake this performs the decrementing of account wise info upon staking. // params // owner, this is the account that owns the fio being unstaked (the signer of the unstake) @@ -100,6 +174,30 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { // srprewardedsus, this is the number of SRPs being rewarded this unstake, units SUSs // logic //FIP-21 actions to update accountstake table. + [[eosio::action]] + void decacctstake(const name &owner, const int64_t &fiostakedsufs, const int64_t &srprewardedsus) { + //check auth fio.staking or fio.system + eosio_assert((has_auth(SYSTEMACCOUNT) || has_auth(STAKINGACCOUNT)), + "missing required authority of staking or eosio"); + eosio_assert(fiostakedsufs > 0,"incacctstake fiostakedsuf must be greater than 0. " ); + eosio_assert(srprewardedsus > 0,"srprewardedsus fiostakedsuf must be greater than 0. " ); + + auto astakebyaccount = accountstaking.get_index<"byaccount"_n>(); + auto astakeiter = astakebyaccount.find(owner.value); + + eosio_assert(astakeiter != astakebyaccount.end(),"decacctstake owner not found in account staking." ); + eosio_assert(astakeiter->account == owner,"decacctstake owner lookup error." ); + eosio_assert(astakeiter->total_srp >= srprewardedsus,"decacctstake total srp for account must be greater than or equal srprewardedsus." ); + eosio_assert(astakeiter->total_staked_fio >= fiostakedsufs,"decacctstake total staked fio for account must be greater than or equal fiostakedsufs." ); + + //update the existing record + astakebyaccount.modify(astakeiter, _self, [&](struct account_staking_info &a) { + a.total_staked_fio -= fiostakedsufs; + a.total_srp -= srprewardedsus; + }); + + } + [[eosio::action]] @@ -119,12 +217,12 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { Account Tokens Staked is incremented by amount in account related table. Account Tokens Staked cannot be spent by the user. Account Staking Reward Point is incremented by SRPs to Award in account related table - (call incacctstake) + (implement) (call incacctstake) Combined Token Pool count is incremented by amount. Global SRP count is incremented by SRPs to Award. staked_token_pool is incremented by amount. - (call incgstake) + (implement) (call incgstake) check for maximum FIO transaction size is applied @@ -163,7 +261,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { Account Tokens Staked is decremented by amount in account related table. Account Staking Reward Point is decremented by SRPs to Award in account related table - (call decacctstake) + (implement) (call decacctstake) Staking Reward Amount is transferred to Staker's Account. Memo: "Paying Staking Rewards" @@ -171,7 +269,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { Global SRP count is decremented by SRPs to Claim . Combined Token Pool count is decremented by amount + Staking Reward Amount. staked token pool is decremented by amount - (call decgstake) + (implement) (call decgstake) If tpid was provided, TPID Reward Amount is awarded to the tpid and decremented from Combined Token Pool. check for max FIO transaction size exceeded will be applied. @@ -193,5 +291,5 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { }; //class Staking -EOSIO_DISPATCH(Staking, (stakefio)(unstakefio) ) +EOSIO_DISPATCH(Staking, (stakefio)(unstakefio)(incgstake)(decgstake)(incacctstake)(decacctstake) ) } diff --git a/contracts/fio.staking/fio.staking.hpp b/contracts/fio.staking/fio.staking.hpp index 1091f9a3..8b07aedf 100644 --- a/contracts/fio.staking/fio.staking.hpp +++ b/contracts/fio.staking/fio.staking.hpp @@ -19,8 +19,8 @@ namespace fioio { //staking info is a global state table used to track information relating to staking within the FIO protocol. - struct [[eosio::table("staking"), eosio::contract("fio.staking")]] global_staking_state { - global_staking_state() {} + struct [[eosio::table]] global_staking_state { + global_staking_state(){} uint64_t staked_token_pool = 0; //total FIO tokens staked for all accounts, units sufs. uint64_t combined_token_pool = 0; //total fio tokens staked for all accounts plus fio rewards all accounts, units SUFs, // incremented by the staked amount when user stakes, when tokens are earmarked as staking rewards, From 6e0b13de1c7443fe66cd25890ef904fe6ff945d9 Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Fri, 30 Apr 2021 10:38:12 -0600 Subject: [PATCH 09/32] implement fio staking implement fio staking in the staking contract --- contracts/fio.address/fio.address.cpp | 4 +- contracts/fio.common/fio.common.hpp | 4 + contracts/fio.staking/CMakeLists.txt | 1 + contracts/fio.staking/fio.staking.abi | 8 + contracts/fio.staking/fio.staking.cpp | 237 +++++++++++------- contracts/fio.staking/fio.staking.hpp | 4 +- .../fio.token/include/fio.token/fio.token.hpp | 28 ++- 7 files changed, 191 insertions(+), 95 deletions(-) diff --git a/contracts/fio.address/fio.address.cpp b/contracts/fio.address/fio.address.cpp index 95a5b682..94b1dc7d 100644 --- a/contracts/fio.address/fio.address.cpp +++ b/contracts/fio.address/fio.address.cpp @@ -1694,9 +1694,9 @@ namespace fioio { void decrcounter(const string &fio_address, const int32_t &step) { check(step > 0, "step must be greater than 0"); - check((has_auth(AddressContract) || has_auth(TokenContract) || has_auth(TREASURYACCOUNT) || + check((has_auth(AddressContract) || has_auth(TokenContract) || has_auth(TREASURYACCOUNT) || has_auth(STAKINGACCOUNT) || has_auth(REQOBTACCOUNT) || has_auth(SYSTEMACCOUNT) || has_auth(FeeContract)), - "missing required authority of fio.address, fio.token, fio.fee, fio.treasury, fio.reqobt, fio.system"); + "missing required authority of fio.address, fio.token, fio.fee, fio.treasury, fio.reqobt, fio.system, fio.staking "); auto namesbyname = fionames.get_index<"byname"_n>(); auto fioname_iter = namesbyname.find(string_to_uint128_hash(fio_address.c_str())); diff --git a/contracts/fio.common/fio.common.hpp b/contracts/fio.common/fio.common.hpp index a7b517f2..50da78da 100644 --- a/contracts/fio.common/fio.common.hpp +++ b/contracts/fio.common/fio.common.hpp @@ -43,6 +43,8 @@ #define STAKINGREWARDSRESERVEMAXIMUM 25000000000000000 // 25M FIO SUFS. #define DAILYSTAKINGMINTTHRESHOLD 25000000000000 //25k FIO threshold for MINTING staking rewards. +#define STAKE_FIO_TOKENS_ENDPOINT "stake_fio_tokens" +#define UNSTAKE_FIO_TOKENS_ENDPOINT "unstake_fio_tokens" #define REGISTER_ADDRESS_ENDPOINT "register_fio_address" #define REGISTER_DOMAIN_ENDPOINT "register_fio_domain" #define RENEW_ADDRESS_ENDPOINT "renew_fio_address" @@ -408,6 +410,8 @@ namespace fioio { static const uint64_t INITIALACCOUNTRAM = 25600; static const uint64_t ADDITIONALRAMBPDESCHEDULING = 25600; + static const uint64_t STAKEFIOTOKENSRAM = 1024; //integrated. + static const uint64_t UNSTAKEFIOTOKENSRAM = 1024; //integrated. static const uint64_t REGDOMAINRAM = 2560; //integrated. static const uint64_t REGADDRESSRAM = 2560; //integrated. static const uint64_t ADDADDRESSRAM = 512; //integrated. diff --git a/contracts/fio.staking/CMakeLists.txt b/contracts/fio.staking/CMakeLists.txt index d8b5c9ff..7a770788 100644 --- a/contracts/fio.staking/CMakeLists.txt +++ b/contracts/fio.staking/CMakeLists.txt @@ -5,6 +5,7 @@ target_include_directories(fio.staking ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../fio.system/include ${CMAKE_CURRENT_SOURCE_DIR}/../ + ${CMAKE_CURRENT_SOURCE_DIR}/../fio.token/include ) diff --git a/contracts/fio.staking/fio.staking.abi b/contracts/fio.staking/fio.staking.abi index 2eebb907..af59906a 100644 --- a/contracts/fio.staking/fio.staking.abi +++ b/contracts/fio.staking/fio.staking.abi @@ -121,6 +121,10 @@ "name": "stakefio", "base": "", "fields": [ + { + "name": "fio_address", + "type": "string" + }, { "name": "amount", "type": "int64" @@ -142,6 +146,10 @@ "name": "unstakefio", "base": "", "fields": [ + { + "name": "fio_address", + "type": "string" + }, { "name": "amount", "type": "int64" diff --git a/contracts/fio.staking/fio.staking.cpp b/contracts/fio.staking/fio.staking.cpp index 5b422c24..bc21f860 100644 --- a/contracts/fio.staking/fio.staking.cpp +++ b/contracts/fio.staking/fio.staking.cpp @@ -6,7 +6,11 @@ * @license FIO Foundation ( https://github.com/fioprotocol/fio/blob/master/LICENSE ) */ +#include #include "fio.staking.hpp" +#include +#include +#include namespace fioio { @@ -17,6 +21,9 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { global_staking_singleton staking; global_staking_state gstaking; account_staking_table accountstaking; + eosiosystem::voters_table voters; + fionames_table fionames; + fiofee_table fiofees; bool debugout = false; public: @@ -25,7 +32,10 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { Staking(name s, name code, datastream ds) : contract(s, code, ds), staking(_self, _self.value), - accountstaking(_self,_self.value){ + accountstaking(_self,_self.value), + voters(SYSTEMACCOUNT,SYSTEMACCOUNT.value), + fiofees(FeeContract, FeeContract.value), + fionames(AddressContract, AddressContract.value){ gstaking = staking.exists() ? staking.get() : global_staking_state{}; } @@ -57,30 +67,6 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { // call decacctstake - // (implement 1) - //incgstake performs the staking state increments when staking occurs - // params - // fiostakedsufs, this is the amount of fio staked in SUFs - // srpcountsus, this is the number of SRPs computed for this stake, units SUSs - // logic - // increment the combined_token_pool by fiostaked. - // increment the staked_token_pool by fiostaked. - // increment the global_srp_count by srpcount. - // - [[eosio::action]] - void incgstake(const int64_t &fiostakedsufs, const int64_t &srpcountsus) { - //check auth fio.staking or fio.system - eosio_assert((has_auth(SYSTEMACCOUNT) || has_auth(STAKINGACCOUNT)), - "missing required authority of staking or eosio"); - // increment the combined_token_pool by fiostaked. - gstaking.combined_token_pool += fiostakedsufs; - // increment the staked_token_pool by fiostaked. - gstaking.staked_token_pool += fiostakedsufs; - // increment the global_srp_count by srpcount. - gstaking.global_srp_count += srpcountsus; - } - - //(implement 2) //decgstake performs the staking state decrements when unstaking occurs // params // fiounstakedsufs, this is the amount of FIO being unstaked, units SUFs @@ -96,10 +82,12 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { eosio_assert((has_auth(SYSTEMACCOUNT) || has_auth(STAKINGACCOUNT)), "missing required authority of staking or eosio"); + //avoid overflows due to negative results. eosio_assert(gstaking.combined_token_pool >= (fiostakedsufs+fiorewardededsufs),"decgstake combined token pool must be greater or equal to staked sufs plus fio rewarded sufs. " ); eosio_assert(gstaking.staked_token_pool >= fiostakedsufs,"decgstake staked token pool must be greater or equal to staked sufs. " ); eosio_assert(gstaking.global_srp_count >= srpcountsus,"decgstake global srp count must be greater or equal to srp count. " ); + //should we compute an intermediate result here and check it against supply. // decrement the combined_token_pool by fiostaked+fiorewarded. gstaking.combined_token_pool -= (fiostakedsufs+fiorewardededsufs); @@ -130,43 +118,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { // amountfiosufs, this is the amount of FIO that has been minted, units SUFs //FIP-21 actions to update staking state. - //(implement 3) - //FIP-21 actions to update accountstake table. - //incacctstake this performs the incrementing of account wise info upon staking. - // params - // owner, this is the account that owns the fio being staked (the signer of the stake) - // fiostakesufs, this is the amount of fio being staked, units SUFs - // srpawardedsus, this is the number of SRPs being awarded this stake, units SUSs - // logic - [[eosio::action]] - void incacctstake(const name &owner, const int64_t &fiostakedsufs, const int64_t &srpaawardedsus) { - //check auth fio.staking or fio.system - eosio_assert((has_auth(SYSTEMACCOUNT) || has_auth(STAKINGACCOUNT)), - "missing required authority of staking or eosio"); - eosio_assert(fiostakedsufs > 0,"incacctstake fiostakedsuf must be greater than 0. " ); - eosio_assert(srpaawardedsus > 0,"srpaawardedsus fiostakedsuf must be greater than 0. " ); - auto astakebyaccount = accountstaking.get_index<"byaccount"_n>(); - auto astakeiter = astakebyaccount.find(owner.value); - if (astakeiter != astakebyaccount.end()) { - eosio_assert(astakeiter->account == owner,"incacctstake owner lookup error." ); - //update the existing record - astakebyaccount.modify(astakeiter, _self, [&](struct account_staking_info &a) { - a.total_staked_fio += fiostakedsufs; - a.total_srp += srpaawardedsus; - }); - } else { - const uint64_t id = accountstaking.available_primary_key(); - accountstaking.emplace(get_self(), [&](struct account_staking_info &p) { - p.id = id; - p.account = owner; - p.total_staked_fio = fiostakedsufs; - p.total_srp = srpaawardedsus; - }); - } - } - - //(implement 4) //decacctstake this performs the decrementing of account wise info upon staking. // params // owner, this is the account that owns the fio being unstaked (the signer of the unstake) @@ -179,8 +131,8 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { //check auth fio.staking or fio.system eosio_assert((has_auth(SYSTEMACCOUNT) || has_auth(STAKINGACCOUNT)), "missing required authority of staking or eosio"); - eosio_assert(fiostakedsufs > 0,"incacctstake fiostakedsuf must be greater than 0. " ); - eosio_assert(srprewardedsus > 0,"srprewardedsus fiostakedsuf must be greater than 0. " ); + eosio_assert(fiostakedsufs > 0,"decacctstake fiostakedsuf must be greater than 0. " ); + eosio_assert(srprewardedsus > 0,"decacctstake srprewardedsus must be greater than 0. " ); auto astakebyaccount = accountstaking.get_index<"byaccount"_n>(); auto astakeiter = astakebyaccount.find(owner.value); @@ -201,47 +153,152 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { [[eosio::action]] - void stakefio(const int64_t &amount, const int64_t &max_fee, + void stakefio(const string &fio_address, const int64_t &amount, const int64_t &max_fee, const string &tpid, const name &actor) { + //signer not actor. require_auth(actor); print("EDEDEDEDEDEDEDEDEDEDEDEDED call into stakefio amount ", amount," max_fee ",max_fee," tpid ",tpid," actor ",actor, "\n"); - /* - * Request is validated per Exception handling. - * - stake_fio_tokens fee is collected. + //check if the actor has voted. + auto votersbyowner = voters.get_index<"byowner"_n>(); + auto voter = votersbyowner.find(actor.value); + fio_400_assert(voter != votersbyowner.end(), "actor", + actor.to_string(), "Account has not voted and has not proxied.",ErrorInvalidValue); + //if they are in the table check if they are is_auto_proxy, or if they have a proxy, or if they have producers not empty + fio_400_assert((((voter->proxy) || (voter->producers.size() > 0) || (voter->is_auto_proxy))), + "actor", actor.to_string(), "Account has not voted and has not proxied.",ErrorInvalidValue); - RAM of signer is increased. amount of RAM increase will be computed during development and updated in this FIP + fio_400_assert(amount > 0, "amount", to_string(amount), "Invalid amount value",ErrorInvalidValue); + fio_400_assert(max_fee >= 0, "amount", to_string(max_fee), "Invalid fee value",ErrorInvalidValue); + fio_400_assert(validateTPIDFormat(tpid), "tpid", tpid,"TPID must be empty or valid FIO address",ErrorPubKeyValid); - SRPs to Award are computed: amount / Rate of Exchange + //process the fio address specified + FioAddress fa; + getFioAddressStruct(fio_address, fa); - Account Tokens Staked is incremented by amount in account related table. Account Tokens Staked cannot be spent by the user. - Account Staking Reward Point is incremented by SRPs to Award in account related table - (implement) (call incacctstake) + fio_400_assert(validateFioNameFormat(fa) && !fa.domainOnly, "fio_address", fa.fioaddress, "Invalid FIO Address", + ErrorDomainAlreadyRegistered); - Combined Token Pool count is incremented by amount. - Global SRP count is incremented by SRPs to Award. - staked_token_pool is incremented by amount. - (implement) (call incgstake) + const uint128_t nameHash = string_to_uint128_hash(fa.fioaddress.c_str()); + auto namesbyname = fionames.get_index<"byname"_n>(); + auto fioname_iter = namesbyname.find(nameHash); + fio_400_assert(fioname_iter != namesbyname.end(), "fio_address", fa.fioaddress, + "FIO Address not registered", ErrorFioNameAlreadyRegistered); + fio_403_assert(fioname_iter->owner_account == actor.value, ErrorSignature); - check for maximum FIO transaction size is applied + const uint32_t expiration = fioname_iter->expiration; + const uint32_t present_time = now(); + fio_400_assert(present_time <= expiration, "fio_address", fio_address, "FIO Address expired. Renew first.", + ErrorDomainExpired); - Account not voted or proxied Staker's account has not voted in the last 30 days and is not proxying. 400 "actor" Value sent in, e.g. "aftyershcu22" "Account has not voted in the last 30 days and is not proxying." - Invalid amount value amount format is not valid 400 "amount" Value sent in, e.g. "-100" "Invalid amount value" - Invalid fee value max_fee format is not valid 400 "max_fee" Value sent in, e.g. "-100" "Invalid fee value" - Fee exceeds maximum Actual fee is greater than supplied max_fee 400 "max_fee" Value sent in, e.g. "1000000000" "Fee exceeds supplied maximum" - Insufficient balance Available (unlocked and unstaked) balance in Staker's account is less than chain fee + amount 400 "max_oracle_fee" Value sent in, e.g. "100000000000" "Insufficient balance" - Invalid TPID tpid format is not valid 400 "tpid" Value sent in, e.g. "notvalidfioaddress" "TPID must be empty or valid FIO address" - Signer not actor Signer not actor 403 Type: invalid_signature - */ + //get the usable balance for the account + //this is account balance - genesis locked tokens - general locked balance. + auto stakeablebalance = eosio::token::computeusablebalance(actor); - check(is_account(actor),"account must pre exist"); - check(amount > 0,"cannot stake token amount less or equal 0."); + + uint64_t paid_fee_amount = 0; + //begin, bundle eligible fee logic for staking + const uint128_t endpoint_hash = string_to_uint128_hash(STAKE_FIO_TOKENS_ENDPOINT); + + auto fees_by_endpoint = fiofees.get_index<"byendpoint"_n>(); + auto fee_iter = fees_by_endpoint.find(endpoint_hash); + + //if the fee isnt found for the endpoint, then 400 error. + fio_400_assert(fee_iter != fees_by_endpoint.end(), "endpoint_name", STAKE_FIO_TOKENS_ENDPOINT, + "FIO fee not found for endpoint", ErrorNoEndpoint); + + const int64_t fee_amount = fee_iter->suf_amount; + const uint64_t fee_type = fee_iter->type; + + fio_400_assert(fee_type == 1, "fee_type", to_string(fee_type), + "unexpected fee type for endpoint stake_fio_tokens, expected 0", + ErrorNoEndpoint); + + const uint64_t bundleeligiblecountdown = fioname_iter->bundleeligiblecountdown; + + if (bundleeligiblecountdown > 0) { + action{ + permission_level{_self, "active"_n}, + AddressContract, + "decrcounter"_n, + make_tuple(fio_address, 1) + }.send(); + } else { + paid_fee_amount = fee_iter->suf_amount; + fio_400_assert(max_fee >= (int64_t)paid_fee_amount, "max_fee", to_string(max_fee), "Fee exceeds supplied maximum.", + ErrorMaxFeeExceeded); + + fio_fees(actor, asset(fee_amount, FIOSYMBOL), STAKE_FIO_TOKENS_ENDPOINT); + process_rewards(tpid, fee_amount,get_self(), actor); + + if (fee_amount > 0) { + INLINE_ACTION_SENDER(eosiosystem::system_contract, updatepower) + ("eosio"_n, {{_self, "active"_n}}, + {actor, true} + ); + } + } + + fio_400_assert(stakeablebalance >= (paid_fee_amount + (uint64_t)amount), "max_fee", to_string(max_fee), "Insufficient balance.", + ErrorMaxFeeExceeded); + //End, bundle eligible fee logic for staking + + //RAM bump + if (STAKEFIOTOKENSRAM > 0) { + action( + permission_level{SYSTEMACCOUNT, "active"_n}, + "eosio"_n, + "incram"_n, + std::make_tuple(actor, STAKEFIOTOKENSRAM) + ).send(); + } + + + //compute rate of exchange and SRPs + uint64_t rateofexchange = 1; + if (gstaking.combined_token_pool >= 1000000000000000) { + rateofexchange = gstaking.combined_token_pool / gstaking.global_srp_count; + } + + uint64_t srptoaward = amount / rateofexchange; + + gstaking.combined_token_pool += amount; + gstaking.global_srp_count += srptoaward; + gstaking.staked_token_pool += amount; + + + //increment account staking info + auto astakebyaccount = accountstaking.get_index<"byaccount"_n>(); + auto astakeiter = astakebyaccount.find(actor.value); + if (astakeiter != astakebyaccount.end()) { + eosio_assert(astakeiter->account == actor,"incacctstake owner lookup error." ); + //update the existing record + astakebyaccount.modify(astakeiter, _self, [&](struct account_staking_info &a) { + a.total_staked_fio += amount; + a.total_srp += srptoaward; + }); + } else { + const uint64_t id = accountstaking.available_primary_key(); + accountstaking.emplace(get_self(), [&](struct account_staking_info &p) { + p.id = id; + p.account = actor; + p.total_staked_fio = amount; + p.total_srp = srptoaward; + }); + } + //end increment account staking info + const string response_string = string("{\"status\": \"OK\",\"fee_collected\":") + + to_string(paid_fee_amount) + string("}"); + + fio_400_assert(transaction_size() <= MAX_TRX_SIZE, "transaction_size", std::to_string(transaction_size()), + "Transaction is too large", ErrorTransaction); + + send_response(response_string.c_str()); } [[eosio::action]] - void unstakefio(const int64_t &amount, const int64_t &max_fee, + void unstakefio(const string &fio_address,const int64_t &amount, const int64_t &max_fee, const string &tpid, const name &actor) { require_auth(actor); print("EDEDEDEDEDEDEDEDEDEDEDEDED call into unstakefio amount ", amount," max_fee ",max_fee," tpid ",tpid," actor ",actor, "\n"); @@ -291,5 +348,5 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { }; //class Staking -EOSIO_DISPATCH(Staking, (stakefio)(unstakefio)(incgstake)(decgstake)(incacctstake)(decacctstake) ) +EOSIO_DISPATCH(Staking, (stakefio)(unstakefio)(decgstake)(decacctstake) ) } diff --git a/contracts/fio.staking/fio.staking.hpp b/contracts/fio.staking/fio.staking.hpp index 8b07aedf..be8fff3d 100644 --- a/contracts/fio.staking/fio.staking.hpp +++ b/contracts/fio.staking/fio.staking.hpp @@ -22,11 +22,11 @@ namespace fioio { struct [[eosio::table]] global_staking_state { global_staking_state(){} uint64_t staked_token_pool = 0; //total FIO tokens staked for all accounts, units sufs. - uint64_t combined_token_pool = 0; //total fio tokens staked for all accounts plus fio rewards all accounts, units SUFs, + uint64_t combined_token_pool = 1; //total fio tokens staked for all accounts plus fio rewards all accounts, units SUFs, // incremented by the staked amount when user stakes, when tokens are earmarked as staking rewards, // decremented by unstaked amount + reward amount when users unstake uint64_t rewards_token_pool = 0; //total counter how much has come in from fees AND minting units SUFs - uint64_t global_srp_count = 0; //total SRP for all FIO users, increment when users stake, decrement when users unstake. + uint64_t global_srp_count = 1; // units SUS, total SRP for all FIO users, increment when users stake, decrement when users unstake. uint64_t daily_staking_rewards = 0; //this is used to track the daily staking rewards collected from fees, // its used only to determine if the protocol should mint FIO whe rewards are under the DAILYSTAKINGMINTTHRESHOLD uint64_t staking_rewards_reserves_minted = 0; //the total amount of FIO used in minting rewards tokens, will not exceed STAKINGREWARDSRESERVEMAXIMUM diff --git a/contracts/fio.token/include/fio.token/fio.token.hpp b/contracts/fio.token/include/fio.token/fio.token.hpp index d30f065b..22bf01d2 100755 --- a/contracts/fio.token/include/fio.token/fio.token.hpp +++ b/contracts/fio.token/include/fio.token/fio.token.hpp @@ -13,6 +13,7 @@ #include #include #include +#include namespace eosiosystem { class system_contract; @@ -32,6 +33,7 @@ namespace eosio { fioio::fionames_table fionames; eosiosystem::locked_tokens_table lockedTokensTable; eosiosystem::general_locks_table generalLockTokensTable; + fioio::account_staking_table accountstaking; public: token(name s, name code, datastream ds) : contract(s, code, ds), @@ -42,7 +44,8 @@ namespace eosio { fiofees(fioio::FeeContract, fioio::FeeContract.value), tpids(TPIDContract, TPIDContract.value), lockedTokensTable(SYSTEMACCOUNT, SYSTEMACCOUNT.value), - generalLockTokensTable(SYSTEMACCOUNT, SYSTEMACCOUNT.value){ + generalLockTokensTable(SYSTEMACCOUNT, SYSTEMACCOUNT.value), + accountstaking(STAKINGACCOUNT,STAKINGACCOUNT.value){ fioio::configs_singleton configsSingleton(fioio::FeeContract, fioio::FeeContract.value); appConfig = configsSingleton.get_or_default(fioio::config()); } @@ -151,6 +154,29 @@ namespace eosio { bool existing; }; + //This action will compute the number of unlocked tokens contained within an account. + // This considers + static uint64_t computeusablebalance(const name &owner){ + uint64_t genesislockedamount = computeremaininglockedtokens(owner,true); + uint64_t generallockedamount = computegenerallockedtokens(owner,true); + uint64_t stakedfio = 0; + + fioio::account_staking_table accountstaking(STAKINGACCOUNT, STAKINGACCOUNT.value); + auto astakebyaccount = accountstaking.get_index<"byaccount"_n>(); + auto astakeiter = astakebyaccount.find(owner.value); + if (astakeiter != astakebyaccount.end()) { + check(astakeiter->account == owner,"incacctstake owner lookup error." ); + stakedfio = astakeiter->total_staked_fio; + } + //apply a little QC. + const auto my_balance = eosio::token::get_balance("fio.token"_n, owner, FIOSYMBOL.code()); + check(my_balance.amount >= (generallockedamount + generallockedamount + stakedfio), + "computeusablebalance, amount of locked fio plus staked is greater than balance!! for " + owner.to_string() ); + uint64_t amount = my_balance.amount - (generallockedamount + generallockedamount + stakedfio); + return amount; + + } + //this will compute the present unlocked tokens for this user based on the From cde6875142f7717d73006f73dca9c99166ec4ffe Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Fri, 30 Apr 2021 10:41:54 -0600 Subject: [PATCH 10/32] constant constant --- contracts/fio.staking/fio.staking.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/fio.staking/fio.staking.cpp b/contracts/fio.staking/fio.staking.cpp index bc21f860..8295bbeb 100644 --- a/contracts/fio.staking/fio.staking.cpp +++ b/contracts/fio.staking/fio.staking.cpp @@ -257,7 +257,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { //compute rate of exchange and SRPs uint64_t rateofexchange = 1; - if (gstaking.combined_token_pool >= 1000000000000000) { + if (gstaking.combined_token_pool >= COMBINEDTOKENPOOLMINIMUM) { rateofexchange = gstaking.combined_token_pool / gstaking.global_srp_count; } From 7d333ced6e37ebcea2f640bf2c4ea0f975f82964 Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Fri, 30 Apr 2021 11:01:37 -0600 Subject: [PATCH 11/32] print print --- contracts/fio.staking/fio.staking.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contracts/fio.staking/fio.staking.cpp b/contracts/fio.staking/fio.staking.cpp index 8295bbeb..22c4f206 100644 --- a/contracts/fio.staking/fio.staking.cpp +++ b/contracts/fio.staking/fio.staking.cpp @@ -157,8 +157,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { const string &tpid, const name &actor) { //signer not actor. require_auth(actor); - print("EDEDEDEDEDEDEDEDEDEDEDEDED call into stakefio amount ", amount," max_fee ",max_fee," tpid ",tpid," actor ",actor, "\n"); - + //check if the actor has voted. auto votersbyowner = voters.get_index<"byowner"_n>(); auto voter = votersbyowner.find(actor.value); From 5b7e684b4b8db060cef7faaa0bf23b9608a72dbd Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Fri, 30 Apr 2021 15:52:39 -0600 Subject: [PATCH 12/32] first dev iteration on unstakefio implement all logic of unstakefio, except the locking. --- contracts/fio.common/fio.accounts.hpp | 1 + contracts/fio.staking/fio.staking.cpp | 297 +++++++++++++++--------- contracts/fio.tpid/fio.tpid.cpp | 4 +- contracts/fio.treasury/fio.treasury.abi | 19 ++ contracts/fio.treasury/fio.treasury.cpp | 18 +- 5 files changed, 223 insertions(+), 116 deletions(-) diff --git a/contracts/fio.common/fio.accounts.hpp b/contracts/fio.common/fio.accounts.hpp index 63e82e55..c56579c1 100644 --- a/contracts/fio.common/fio.accounts.hpp +++ b/contracts/fio.common/fio.accounts.hpp @@ -30,6 +30,7 @@ namespace fioio { static const name REQOBTACCOUNT = name("fio.reqobt"); static const name FeeContract = name("fio.fee"); + static const name StakingContract = name("fio.staking"); static const name AddressContract = name("fio.address"); static const name TPIDContract = name("fio.tpid"); static const name TokenContract = name("fio.token"); diff --git a/contracts/fio.staking/fio.staking.cpp b/contracts/fio.staking/fio.staking.cpp index 22c4f206..c2fb26c3 100644 --- a/contracts/fio.staking/fio.staking.cpp +++ b/contracts/fio.staking/fio.staking.cpp @@ -46,56 +46,6 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { //FIP-21 actions to update staking state. - //(implement 5) - //perfstake performs updates to state required upon staking. - // params - // owner, - // fiostakedsufs, - // srpsawardedsuss - // logic - // call incgstake - // call incacctstake - - //(implement 6) - //perfunstake performs updates to state required upon unstaking. - // params - // owner, - // fiostakedsufs, - // srpsawardedsuss - // logic - // call decgstake - // call decacctstake - - - //decgstake performs the staking state decrements when unstaking occurs - // params - // fiounstakedsufs, this is the amount of FIO being unstaked, units SUFs - // fiorewardedsufs, this is the amount of FIO being rewarded for this unstaked, units SUFs - // srpcountsus, this is the number of SRPs being rewarded for this unstake, units SUSs - // logic - // decrement the combined_token_pool by fiostaked+fiorewarded. - // decrement the staked_token_pool by fiostaked. - // decrement the global_srp_count by srpcount. - [[eosio::action]] - void decgstake(const int64_t &fiostakedsufs, const int64_t &fiorewardededsufs,const int64_t &srpcountsus) { - //check auth fio.staking or fio.system - eosio_assert((has_auth(SYSTEMACCOUNT) || has_auth(STAKINGACCOUNT)), - "missing required authority of staking or eosio"); - - //avoid overflows due to negative results. - eosio_assert(gstaking.combined_token_pool >= (fiostakedsufs+fiorewardededsufs),"decgstake combined token pool must be greater or equal to staked sufs plus fio rewarded sufs. " ); - eosio_assert(gstaking.staked_token_pool >= fiostakedsufs,"decgstake staked token pool must be greater or equal to staked sufs. " ); - eosio_assert(gstaking.global_srp_count >= srpcountsus,"decgstake global srp count must be greater or equal to srp count. " ); - - //should we compute an intermediate result here and check it against supply. - - // decrement the combined_token_pool by fiostaked+fiorewarded. - gstaking.combined_token_pool -= (fiostakedsufs+fiorewardededsufs); - // decrement the staked_token_pool by fiostaked. - gstaking.staked_token_pool -= fiostakedsufs; - // decrement the global_srp_count by srpcount. - gstaking.global_srp_count -= srpcountsus; - } //(implement 7) //incgrewards performs the staking state increments when rewards are identified during fee collection. @@ -119,38 +69,6 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { //FIP-21 actions to update staking state. - //decacctstake this performs the decrementing of account wise info upon staking. - // params - // owner, this is the account that owns the fio being unstaked (the signer of the unstake) - // fiostakesufs, this is the amount of FIO being unstaked, units SUFs - // srprewardedsus, this is the number of SRPs being rewarded this unstake, units SUSs - // logic - //FIP-21 actions to update accountstake table. - [[eosio::action]] - void decacctstake(const name &owner, const int64_t &fiostakedsufs, const int64_t &srprewardedsus) { - //check auth fio.staking or fio.system - eosio_assert((has_auth(SYSTEMACCOUNT) || has_auth(STAKINGACCOUNT)), - "missing required authority of staking or eosio"); - eosio_assert(fiostakedsufs > 0,"decacctstake fiostakedsuf must be greater than 0. " ); - eosio_assert(srprewardedsus > 0,"decacctstake srprewardedsus must be greater than 0. " ); - - auto astakebyaccount = accountstaking.get_index<"byaccount"_n>(); - auto astakeiter = astakebyaccount.find(owner.value); - - eosio_assert(astakeiter != astakebyaccount.end(),"decacctstake owner not found in account staking." ); - eosio_assert(astakeiter->account == owner,"decacctstake owner lookup error." ); - eosio_assert(astakeiter->total_srp >= srprewardedsus,"decacctstake total srp for account must be greater than or equal srprewardedsus." ); - eosio_assert(astakeiter->total_staked_fio >= fiostakedsufs,"decacctstake total staked fio for account must be greater than or equal fiostakedsufs." ); - - //update the existing record - astakebyaccount.modify(astakeiter, _self, [&](struct account_staking_info &a) { - a.total_staked_fio -= fiostakedsufs; - a.total_srp -= srprewardedsus; - }); - - } - - [[eosio::action]] void stakefio(const string &fio_address, const int64_t &amount, const int64_t &max_fee, @@ -262,12 +180,13 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { uint64_t srptoaward = amount / rateofexchange; + //update global staking state gstaking.combined_token_pool += amount; gstaking.global_srp_count += srptoaward; gstaking.staked_token_pool += amount; - //increment account staking info + //update account staking info auto astakebyaccount = accountstaking.get_index<"byaccount"_n>(); auto astakeiter = astakebyaccount.find(actor.value); if (astakeiter != astakebyaccount.end()) { @@ -300,52 +219,204 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { void unstakefio(const string &fio_address,const int64_t &amount, const int64_t &max_fee, const string &tpid, const name &actor) { require_auth(actor); - print("EDEDEDEDEDEDEDEDEDEDEDEDED call into unstakefio amount ", amount," max_fee ",max_fee," tpid ",tpid," actor ",actor, "\n"); - /* - * Request is validated per Exception handling. - * - unstake_fio_tokens fee is collected. + fio_400_assert(amount > 0, "amount", to_string(amount), "Invalid amount value",ErrorInvalidValue); + fio_400_assert(max_fee >= 0, "amount", to_string(max_fee), "Invalid fee value",ErrorInvalidValue); + fio_400_assert(validateTPIDFormat(tpid), "tpid", tpid,"TPID must be empty or valid FIO address",ErrorPubKeyValid); + + //process the fio address specified + FioAddress fa; + getFioAddressStruct(fio_address, fa); + + fio_400_assert(validateFioNameFormat(fa) && !fa.domainOnly, "fio_address", fa.fioaddress, "Invalid FIO Address", + ErrorDomainAlreadyRegistered); - RAM of signer is increased, amount of ram increment will be computed and updated into FIP during development + const uint128_t nameHash = string_to_uint128_hash(fa.fioaddress.c_str()); + auto namesbyname = fionames.get_index<"byname"_n>(); + auto fioname_iter = namesbyname.find(nameHash); + fio_400_assert(fioname_iter != namesbyname.end(), "fio_address", fa.fioaddress, + "FIO Address not registered", ErrorFioNameAlreadyRegistered); - SRPs to Claim are computed: Staker's Account SRPs * (Unstaked amount / Total Tokens Staked in Staker's Account) + fio_403_assert(fioname_iter->owner_account == actor.value, ErrorSignature); - Staking Reward Amount is computed: ((SRPs to Claim * Rate of Exchnage) - Unstake amount) * 0.9 + const uint32_t expiration = fioname_iter->expiration; + const uint32_t present_time = now(); + fio_400_assert(present_time <= expiration, "fio_address", fio_address, "FIO Address expired. Renew first.", + ErrorDomainExpired); - TPID Reward Amount is computed: ((SRPs to Claim * Rate of Exchnage) - Unstake amount) * 0.1 + auto astakebyaccount = accountstaking.get_index<"byaccount"_n>(); + auto astakeiter = astakebyaccount.find(actor.value); + eosio_assert(astakeiter != astakebyaccount.end(),"incacctstake, actor has no accountstake record." ); + eosio_assert(astakeiter->account == actor,"incacctstake, actor accountstake lookup error." ); + fio_400_assert(astakeiter->total_staked_fio >= amount, "amount", to_string(amount), "Cannot unstake more than staked.", + ErrorInvalidValue); - Account Tokens Staked is decremented by amount in account related table. - Account Staking Reward Point is decremented by SRPs to Award in account related table - (implement) (call decacctstake) + //get the usable balance for the account + //this is account balance - genesis locked tokens - general locked balance. + auto stakeablebalance = eosio::token::computeusablebalance(actor); - Staking Reward Amount is transferred to Staker's Account. - Memo: "Paying Staking Rewards" + uint64_t paid_fee_amount = 0; + //begin, bundle eligible fee logic for staking + const uint128_t endpoint_hash = string_to_uint128_hash(UNSTAKE_FIO_TOKENS_ENDPOINT); - Global SRP count is decremented by SRPs to Claim . - Combined Token Pool count is decremented by amount + Staking Reward Amount. - staked token pool is decremented by amount - (implement) (call decgstake) + auto fees_by_endpoint = fiofees.get_index<"byendpoint"_n>(); + auto fee_iter = fees_by_endpoint.find(endpoint_hash); - If tpid was provided, TPID Reward Amount is awarded to the tpid and decremented from Combined Token Pool. - check for max FIO transaction size exceeded will be applied. + //if the fee isnt found for the endpoint, then 400 error. + fio_400_assert(fee_iter != fees_by_endpoint.end(), "endpoint_name", UNSTAKE_FIO_TOKENS_ENDPOINT, + "FIO fee not found for endpoint", ErrorNoEndpoint); + + const int64_t fee_amount = fee_iter->suf_amount; + const uint64_t fee_type = fee_iter->type; + + fio_400_assert(fee_type == 1, "fee_type", to_string(fee_type), + "unexpected fee type for endpoint unstake_fio_tokens, expected 0", + ErrorNoEndpoint); + + const uint64_t bundleeligiblecountdown = fioname_iter->bundleeligiblecountdown; + + if (bundleeligiblecountdown > 0) { + action{ + permission_level{_self, "active"_n}, + AddressContract, + "decrcounter"_n, + make_tuple(fio_address, 1) + }.send(); + } else { + paid_fee_amount = fee_iter->suf_amount; + fio_400_assert(max_fee >= (int64_t)paid_fee_amount, "max_fee", to_string(max_fee), "Fee exceeds supplied maximum.", + ErrorMaxFeeExceeded); + + fio_fees(actor, asset(fee_amount, FIOSYMBOL), UNSTAKE_FIO_TOKENS_ENDPOINT); + process_rewards(tpid, fee_amount,get_self(), actor); + + if (fee_amount > 0) { + INLINE_ACTION_SENDER(eosiosystem::system_contract, updatepower) + ("eosio"_n, {{_self, "active"_n}}, + {actor, true} + ); + } + } + + fio_400_assert(stakeablebalance >= (paid_fee_amount + (uint64_t)amount), "max_fee", to_string(max_fee), "Insufficient balance.", + ErrorMaxFeeExceeded); + //End, bundle eligible fee logic for staking + + //RAM bump + if (UNSTAKEFIOTOKENSRAM > 0) { + action( + permission_level{SYSTEMACCOUNT, "active"_n}, + "eosio"_n, + "incram"_n, + std::make_tuple(actor, UNSTAKEFIOTOKENSRAM) + ).send(); + } + + //SRPs to Claim are computed: Staker's Account SRPs * (Unstaked amount / Total Tokens Staked in Staker's Account) + uint64_t srpstoclaim = astakeiter->total_srp * ( amount / astakeiter->total_staked_fio); + + //compute rate of exchange + uint64_t rateofexchange = 1; + if (gstaking.combined_token_pool >= COMBINEDTOKENPOOLMINIMUM) { + rateofexchange = gstaking.combined_token_pool / gstaking.global_srp_count; + } + + eosio_assert((srpstoclaim * rateofexchange) >= amount, "unstakefio, invalid calc in totalrewardamount, must be that (srpstoclaim * rateofexchange) > amount. "); + uint64_t totalrewardamount = ((srpstoclaim * rateofexchange) - amount); + uint64_t tenpercent = totalrewardamount / 10; + //Staking Reward Amount is computed: ((SRPs to Claim * Rate of Exchnage) - Unstake amount) * 0.9 + uint64_t stakingrewardamount = tenpercent * 9; + // TPID Reward Amount is computed: ((SRPs to Claim * Rate of Exchnage) - Unstake amount) * 0.1 + uint64_t tpidrewardamount = tenpercent; + + //decrement staking by account. + eosio_assert(astakeiter->total_srp >= srpstoclaim,"unstakefio, total srp for account must be greater than or equal srpstoclaim." ); + eosio_assert(astakeiter->total_staked_fio >= amount,"unstakefio, total staked fio for account must be greater than or equal fiostakedsufs." ); + + //update the existing record + astakebyaccount.modify(astakeiter, _self, [&](struct account_staking_info &a) { + a.total_staked_fio -= amount; + a.total_srp -= srpstoclaim; + }); + + //transfer the staking reward amount. + if (stakingrewardamount > 0) { + //Staking Reward Amount is transferred to Staker's Account. + // Memo: "Paying Staking Rewards" + action(permission_level{get_self(), "active"_n}, + TREASURYACCOUNT, "paystake"_n, + make_tuple(actor, stakingrewardamount) + ).send(); + } + + //decrement the global state + //avoid overflows due to negative results. + eosio_assert(gstaking.combined_token_pool >= (amount+stakingrewardamount),"unstakefio, combined token pool must be greater or equal to amount plus stakingrewardamount. " ); + eosio_assert(gstaking.staked_token_pool >= amount,"unstakefio, staked token pool must be greater or equal to staked amount. " ); + eosio_assert(gstaking.global_srp_count >= srpstoclaim,"unstakefio, global srp count must be greater or equal to srpstoclaim. " ); + + // decrement the combined_token_pool by fiostaked+fiorewarded. + gstaking.combined_token_pool -= (amount+stakingrewardamount); + // decrement the staked_token_pool by fiostaked. + gstaking.staked_token_pool -= amount; + // decrement the global_srp_count by srpcount. + gstaking.global_srp_count -= srpstoclaim; + + //pay the tpid. + if ((tpid.length() > 0)&&(tpidrewardamount>0)){ + //get the owner of the tpid and pay them. + const uint128_t tnameHash = string_to_uint128_hash(tpid.c_str()); + auto tfioname_iter = namesbyname.find(tnameHash); + fio_400_assert(tfioname_iter != namesbyname.end(), "fio_address", fa.fioaddress, + "FIO Address not registered", ErrorFioNameAlreadyRegistered); + + const uint32_t expiration = tfioname_iter->expiration; + const uint32_t present_time = now(); + fio_400_assert(present_time <= expiration, "fio_address", fio_address, "FIO Address expired. Renew first.", + ErrorDomainExpired); + + //pay the tpid + action( + permission_level{get_self(), "active"_n}, + TPIDContract, + "updatetpid"_n, + std::make_tuple(tpid, actor, tpidrewardamount) + ).send(); + + + + //decrement the amount paid from combined token pool. + if(tpidrewardamount<= gstaking.combined_token_pool) { + gstaking.combined_token_pool -= tpidrewardamount; + } + } + + + //TODO!!!!!! + // amount + Staking Reward Amount is locked in Staker's Account for 7 days. + + /* + * Request is validated per Exception handling. + * + * + * + * amount + Staking Reward Amount is locked in Staker's Account for 7 days. - Invalid amount value amount format is not valid 400 "amount" Value sent in, e.g. "-100" "Invalid amount value" - Ustake exceeds staked amount to unstake is greater than the total staked by account 400 "amount" Value sent in, e.g. "100000000000" "Cannot unstake more than staked." - Invalid fee value max_fee format is not valid 400 "max_fee" Value sent in, e.g. "-100" "Invalid fee value" - Fee exceeds maximum Actual fee is greater than supplied max_fee 400 "max_fee" Value sent in, e.g. "1000000000" "Fee exceeds supplied maximum" - Insufficient balance Available (unlocked and unstaked) balance in Staker's account is less than chain fee + amount 400 "max_oracle_fee" Value sent in, e.g. "100000000000" "Insufficient balance" - Invalid TPID tpid format is not valid 400 "tpid" Value sent in, e.g. "notvalidfioaddress" "TPID must be empty or valid FIO address" - Signer not actor Signer not actor 403 Type: invalid_signature + */ - check(is_account(actor),"account must pre exist"); - check(amount > 0,"cannot unstake token amount less or equal 0."); + const string response_string = string("{\"status\": \"OK\",\"fee_collected\":") + + to_string(paid_fee_amount) + string("}"); + + fio_400_assert(transaction_size() <= MAX_TRX_SIZE, "transaction_size", std::to_string(transaction_size()), + "Transaction is too large", ErrorTransaction); + + send_response(response_string.c_str()); } }; //class Staking -EOSIO_DISPATCH(Staking, (stakefio)(unstakefio)(decgstake)(decacctstake) ) +EOSIO_DISPATCH(Staking, (stakefio)(unstakefio) ) } diff --git a/contracts/fio.tpid/fio.tpid.cpp b/contracts/fio.tpid/fio.tpid.cpp index 0df1b5ee..78ac0d69 100644 --- a/contracts/fio.tpid/fio.tpid.cpp +++ b/contracts/fio.tpid/fio.tpid.cpp @@ -95,8 +95,8 @@ class [[eosio::contract("TPIDController")]] TPIDController: public eosio::contr void updatetpid(const string &tpid, const name owner, const uint64_t &amount) { eosio_assert(has_auth(AddressContract) || has_auth(TokenContract) || has_auth(TREASURYACCOUNT) || - has_auth("fio.reqobt"_n) || has_auth("eosio"_n), - "missing required authority of fio.address, fio.treasury, fio.token, eosio or fio.reqobt"); + has_auth(STAKINGACCOUNT) || has_auth("fio.reqobt"_n) || has_auth("eosio"_n), + "missing required authority of fio.address, fio.treasury, fio.token, eosio or fio.reqobt or fio.staking"); if (debugout) { print("update tpid calling updatetpid with tpid ", tpid, " owner ", owner, "\n"); } diff --git a/contracts/fio.treasury/fio.treasury.abi b/contracts/fio.treasury/fio.treasury.abi index a8825c17..8084c0b3 100644 --- a/contracts/fio.treasury/fio.treasury.abi +++ b/contracts/fio.treasury/fio.treasury.abi @@ -31,6 +31,20 @@ } ] }, + { + "name": "paystake", + "base": "", + "fields": [ + { + "name": "actor", + "type": "name" + }, + { + "name": "amount", + "type": "uint64" + } + ] + }, { "name": "treasurystate", "base": "", @@ -151,6 +165,11 @@ "type": "bpclaim", "ricardian_contract": "" }, + { + "name": "paystake", + "type": "paystake", + "ricardian_contract": "" + }, { "name": "startclock", "type": "startclock", diff --git a/contracts/fio.treasury/fio.treasury.cpp b/contracts/fio.treasury/fio.treasury.cpp index c34e58ae..05fe5570 100644 --- a/contracts/fio.treasury/fio.treasury.cpp +++ b/contracts/fio.treasury/fio.treasury.cpp @@ -108,6 +108,22 @@ class [[eosio::contract("FIOTreasury")]] FIOTreasury: public eosio::contract { send_response(response_string.c_str()); } //tpid_claim + + // @abi action + [[eosio::action]] + void paystake( const name &actor, const uint64_t &amount) { + require_auth(STAKINGACCOUNT); + + action(permission_level{get_self(), "active"_n}, + TokenContract, "transfer"_n, + make_tuple(TREASURYACCOUNT, name(actor), + asset(amount, FIOSYMBOL), + string("Paying Staking Rewards")) + ).send(); + + } + + // @abi action [[eosio::action]] void bpclaim(const string &fio_address, const name &actor) { @@ -376,5 +392,5 @@ class [[eosio::contract("FIOTreasury")]] FIOTreasury: public eosio::contract { }; //class FIOTreasury EOSIO_DISPATCH(FIOTreasury, (tpidclaim)(startclock)(bprewdupdate)(fdtnrwdupdat)(bppoolupdate) - (bpclaim)) + (bpclaim)(paystake)) } From 7000e8d8863ea5e4f34b50052738868283ed6d60 Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Sat, 1 May 2021 10:27:50 -0600 Subject: [PATCH 13/32] make fio_address to be optional make fio address parameter to be optional --- contracts/fio.staking/fio.staking.cpp | 68 +++++++++++-------- .../fio.system/src/delegate_bandwidth.cpp | 3 +- contracts/fio.treasury/fio.treasury.cpp | 10 ++- 3 files changed, 44 insertions(+), 37 deletions(-) diff --git a/contracts/fio.staking/fio.staking.cpp b/contracts/fio.staking/fio.staking.cpp index c2fb26c3..80d45d8a 100644 --- a/contracts/fio.staking/fio.staking.cpp +++ b/contracts/fio.staking/fio.staking.cpp @@ -67,9 +67,6 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { // params // amountfiosufs, this is the amount of FIO that has been minted, units SUFs //FIP-21 actions to update staking state. - - - [[eosio::action]] void stakefio(const string &fio_address, const int64_t &amount, const int64_t &max_fee, const string &tpid, const name &actor) { @@ -89,25 +86,28 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { fio_400_assert(max_fee >= 0, "amount", to_string(max_fee), "Invalid fee value",ErrorInvalidValue); fio_400_assert(validateTPIDFormat(tpid), "tpid", tpid,"TPID must be empty or valid FIO address",ErrorPubKeyValid); + uint64_t bundleeligiblecountdown = 0; //process the fio address specified FioAddress fa; getFioAddressStruct(fio_address, fa); - - fio_400_assert(validateFioNameFormat(fa) && !fa.domainOnly, "fio_address", fa.fioaddress, "Invalid FIO Address", + fio_400_assert(fio_address == "" || validateFioNameFormat(fa), "fio_address", fio_address, "Invalid FIO Address format", ErrorDomainAlreadyRegistered); - const uint128_t nameHash = string_to_uint128_hash(fa.fioaddress.c_str()); - auto namesbyname = fionames.get_index<"byname"_n>(); - auto fioname_iter = namesbyname.find(nameHash); - fio_400_assert(fioname_iter != namesbyname.end(), "fio_address", fa.fioaddress, - "FIO Address not registered", ErrorFioNameAlreadyRegistered); + if (!fio_address.empty()) { + const uint128_t nameHash = string_to_uint128_hash(fa.fioaddress.c_str()); + auto namesbyname = fionames.get_index<"byname"_n>(); + auto fioname_iter = namesbyname.find(nameHash); + fio_400_assert(fioname_iter != namesbyname.end(), "fio_address", fa.fioaddress, + "FIO Address not registered", ErrorFioNameAlreadyRegistered); - fio_403_assert(fioname_iter->owner_account == actor.value, ErrorSignature); + fio_403_assert(fioname_iter->owner_account == actor.value, ErrorSignature); - const uint32_t expiration = fioname_iter->expiration; - const uint32_t present_time = now(); - fio_400_assert(present_time <= expiration, "fio_address", fio_address, "FIO Address expired. Renew first.", - ErrorDomainExpired); + const uint32_t expiration = fioname_iter->expiration; + const uint32_t present_time = now(); + fio_400_assert(present_time <= expiration, "fio_address", fio_address, "FIO Address expired. Renew first.", + ErrorDomainExpired); + bundleeligiblecountdown = fioname_iter->bundleeligiblecountdown; + } //get the usable balance for the account //this is account balance - genesis locked tokens - general locked balance. @@ -132,7 +132,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { "unexpected fee type for endpoint stake_fio_tokens, expected 0", ErrorNoEndpoint); - const uint64_t bundleeligiblecountdown = fioname_iter->bundleeligiblecountdown; + if (bundleeligiblecountdown > 0) { action{ @@ -215,6 +215,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { send_response(response_string.c_str()); } + [[eosio::action]] void unstakefio(const string &fio_address,const int64_t &amount, const int64_t &max_fee, const string &tpid, const name &actor) { @@ -224,25 +225,31 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { fio_400_assert(max_fee >= 0, "amount", to_string(max_fee), "Invalid fee value",ErrorInvalidValue); fio_400_assert(validateTPIDFormat(tpid), "tpid", tpid,"TPID must be empty or valid FIO address",ErrorPubKeyValid); + //process the fio address specified FioAddress fa; getFioAddressStruct(fio_address, fa); - fio_400_assert(validateFioNameFormat(fa) && !fa.domainOnly, "fio_address", fa.fioaddress, "Invalid FIO Address", + fio_400_assert(fio_address == "" || validateFioNameFormat(fa), "fio_address", fio_address, "Invalid FIO Address format", ErrorDomainAlreadyRegistered); - const uint128_t nameHash = string_to_uint128_hash(fa.fioaddress.c_str()); - auto namesbyname = fionames.get_index<"byname"_n>(); - auto fioname_iter = namesbyname.find(nameHash); - fio_400_assert(fioname_iter != namesbyname.end(), "fio_address", fa.fioaddress, - "FIO Address not registered", ErrorFioNameAlreadyRegistered); + uint64_t bundleeligiblecountdown = 0; - fio_403_assert(fioname_iter->owner_account == actor.value, ErrorSignature); + if (!fio_address.empty()) { + const uint128_t nameHash = string_to_uint128_hash(fa.fioaddress.c_str()); + auto namesbyname = fionames.get_index<"byname"_n>(); + auto fioname_iter = namesbyname.find(nameHash); + fio_400_assert(fioname_iter != namesbyname.end(), "fio_address", fa.fioaddress, + "FIO Address not registered", ErrorFioNameAlreadyRegistered); - const uint32_t expiration = fioname_iter->expiration; - const uint32_t present_time = now(); - fio_400_assert(present_time <= expiration, "fio_address", fio_address, "FIO Address expired. Renew first.", - ErrorDomainExpired); + fio_403_assert(fioname_iter->owner_account == actor.value, ErrorSignature); + + const uint32_t expiration = fioname_iter->expiration; + const uint32_t present_time = now(); + fio_400_assert(present_time <= expiration, "fio_address", fio_address, "FIO Address expired. Renew first.", + ErrorDomainExpired); + bundleeligiblecountdown = fioname_iter->bundleeligiblecountdown; + } auto astakebyaccount = accountstaking.get_index<"byaccount"_n>(); auto astakeiter = astakebyaccount.find(actor.value); @@ -273,7 +280,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { "unexpected fee type for endpoint unstake_fio_tokens, expected 0", ErrorNoEndpoint); - const uint64_t bundleeligiblecountdown = fioname_iter->bundleeligiblecountdown; + if (bundleeligiblecountdown > 0) { action{ @@ -366,8 +373,9 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { if ((tpid.length() > 0)&&(tpidrewardamount>0)){ //get the owner of the tpid and pay them. const uint128_t tnameHash = string_to_uint128_hash(tpid.c_str()); - auto tfioname_iter = namesbyname.find(tnameHash); - fio_400_assert(tfioname_iter != namesbyname.end(), "fio_address", fa.fioaddress, + auto tnamesbyname = fionames.get_index<"byname"_n>(); + auto tfioname_iter = tnamesbyname.find(tnameHash); + fio_400_assert(tfioname_iter != tnamesbyname.end(), "fio_address", tpid, "FIO Address not registered", ErrorFioNameAlreadyRegistered); const uint32_t expiration = tfioname_iter->expiration; diff --git a/contracts/fio.system/src/delegate_bandwidth.cpp b/contracts/fio.system/src/delegate_bandwidth.cpp index ebf08b2c..20c12e41 100755 --- a/contracts/fio.system/src/delegate_bandwidth.cpp +++ b/contracts/fio.system/src/delegate_bandwidth.cpp @@ -60,9 +60,10 @@ namespace eosiosystem { has_auth(REQOBTACCOUNT) || has_auth(SYSTEMACCOUNT) || has_auth(FeeContract) || + has_auth(StakingContract) || has_auth(REQOBTACCOUNT) ), - "missing required authority of fio.address, fio.treasury, eosio, fio.fee, fio.token, or fio.reqobt"); + "missing required authority of fio.address, fio.treasury, eosio, fio.fee, fio.token, fio.staking, or fio.reqobt"); auto votersbyowner = _voters.get_index<"byowner"_n>(); auto voter_itr = votersbyowner.find(voter.value); diff --git a/contracts/fio.treasury/fio.treasury.cpp b/contracts/fio.treasury/fio.treasury.cpp index 05fe5570..a0142e07 100644 --- a/contracts/fio.treasury/fio.treasury.cpp +++ b/contracts/fio.treasury/fio.treasury.cpp @@ -361,8 +361,8 @@ class [[eosio::contract("FIOTreasury")]] FIOTreasury: public eosio::contract { void bprewdupdate(const uint64_t &amount) { eosio_assert((has_auth(AddressContract) || has_auth(TokenContract) || has_auth(TREASURYACCOUNT) || - has_auth(REQOBTACCOUNT) || has_auth(SYSTEMACCOUNT) || has_auth(FeeContract)), - "missing required authority of fio.address, fio.treasury, fio.fee, fio.token, eosio or fio.reqobt"); + has_auth(STAKINGACCOUNT) || has_auth(REQOBTACCOUNT) || has_auth(SYSTEMACCOUNT) || has_auth(FeeContract)), + "missing required authority of fio.address, fio.treasury, fio.fee, fio.token, fio.stakng, eosio or fio.reqobt"); bprewards.set(bprewards.exists() ? bpreward{bprewards.get().rewards + amount} : bpreward{amount}, get_self()); } @@ -380,13 +380,11 @@ class [[eosio::contract("FIOTreasury")]] FIOTreasury: public eosio::contract { // @abi action [[eosio::action]] void fdtnrwdupdat(const uint64_t &amount) { - eosio_assert((has_auth(AddressContract) || has_auth(TokenContract) || has_auth(TREASURYACCOUNT) || - has_auth(REQOBTACCOUNT) || has_auth(SYSTEMACCOUNT) || has_auth(FeeContract)), - "missing required authority of fio.address, fio.token, fio.fee, fio.treasury or fio.reqobt"); + has_auth(STAKINGACCOUNT) || has_auth(REQOBTACCOUNT) || has_auth(SYSTEMACCOUNT) || has_auth(FeeContract)), + "missing required authority of fio.address, fio.token, fio.fee, fio.treasury, fio.staking, or fio.reqobt"); fdtnrewards.set(fdtnrewards.exists() ? fdtnreward{fdtnrewards.get().rewards + amount} : fdtnreward{amount}, get_self()); - } }; //class FIOTreasury From 7521bb8e767c959d0921dd32e74aeb1117b7b2bc Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Sun, 2 May 2021 11:56:18 -0600 Subject: [PATCH 14/32] on unstake perform all of the required logic add adapting of existing general locks. --- contracts/fio.staking/fio.staking.cpp | 150 +++++++++++++++--- .../include/fio.system/fio.system.hpp | 3 + contracts/fio.system/src/fio.system.cpp | 46 +++++- .../fio.token/include/fio.token/fio.token.hpp | 4 +- 4 files changed, 179 insertions(+), 24 deletions(-) diff --git a/contracts/fio.staking/fio.staking.cpp b/contracts/fio.staking/fio.staking.cpp index 80d45d8a..6ecfe1e3 100644 --- a/contracts/fio.staking/fio.staking.cpp +++ b/contracts/fio.staking/fio.staking.cpp @@ -11,6 +11,7 @@ #include #include #include +#include namespace fioio { @@ -18,12 +19,13 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { private: - global_staking_singleton staking; - global_staking_state gstaking; - account_staking_table accountstaking; - eosiosystem::voters_table voters; - fionames_table fionames; - fiofee_table fiofees; + global_staking_singleton staking; + global_staking_state gstaking; + account_staking_table accountstaking; + eosiosystem::voters_table voters; + fionames_table fionames; + fiofee_table fiofees; + eosiosystem::general_locks_table generallocks; bool debugout = false; public: @@ -35,7 +37,8 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { accountstaking(_self,_self.value), voters(SYSTEMACCOUNT,SYSTEMACCOUNT.value), fiofees(FeeContract, FeeContract.value), - fionames(AddressContract, AddressContract.value){ + fionames(AddressContract, AddressContract.value), + generallocks(SYSTEMACCOUNT,SYSTEMACCOUNT.value){ gstaking = staking.exists() ? staking.get() : global_staking_state{}; } @@ -369,6 +372,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { // decrement the global_srp_count by srpcount. gstaking.global_srp_count -= srpstoclaim; + const uint32_t present_time = now(); //pay the tpid. if ((tpid.length() > 0)&&(tpidrewardamount>0)){ //get the owner of the tpid and pay them. @@ -379,7 +383,6 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { "FIO Address not registered", ErrorFioNameAlreadyRegistered); const uint32_t expiration = tfioname_iter->expiration; - const uint32_t present_time = now(); fio_400_assert(present_time <= expiration, "fio_address", fio_address, "FIO Address expired. Renew first.", ErrorDomainExpired); @@ -391,8 +394,6 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { std::make_tuple(tpid, actor, tpidrewardamount) ).send(); - - //decrement the amount paid from combined token pool. if(tpidrewardamount<= gstaking.combined_token_pool) { gstaking.combined_token_pool -= tpidrewardamount; @@ -400,20 +401,129 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { } - //TODO!!!!!! - // amount + Staking Reward Amount is locked in Staker's Account for 7 days. + //look and see if they have any general locks. + auto locks_by_owner = generallocks.get_index<"byowner"_n>(); + auto lockiter = locks_by_owner.find(actor.value); + if (lockiter != locks_by_owner.end()) { + //if they have general locks then adapt the locks. + //get the amount of the lock. + int64_t newlockamount = lockiter->lock_amount + (stakingrewardamount + amount); + //get the remaining unlocked of the lock. + int64_t newremaininglockamount = lockiter->remaining_lock_amount + (stakingrewardamount + amount); + //get the timestamp of the lock. + print("EDEDDEDEDEDED present time ", present_time,"\n"); + print("EDEDDEDEDEDED time stamp lock ", lockiter->timestamp,"\n"); + + + print("EDEDDEDEDEDED lock amount ", lockiter->lock_amount,"\n"); + print("EDEDDEDEDEDED staking reward amount ", stakingrewardamount,"\n"); + print("EDEDDEDEDEDED unstake amount ", amount,"\n"); + + uint32_t insertperiod = (present_time - lockiter->timestamp) + 604800; + double oldlockpercentofnewtotal = (((double) lockiter->lock_amount) / + (double) (lockiter->lock_amount + stakingrewardamount + amount)); + print("EDEDDEDEDEDED oldlockpercentofnewtotal ", oldlockpercentofnewtotal,"\n"); + vector newperiods; + //gotta truncate tne new percent at 3 decimal places + bool insertintoexisting = false; + uint32_t lastperiodduration = 0; + int insertindex = -1; + double totalnewpercent = 0.0; + for (int i = 0; i < lockiter->periods.size(); i++) { + double newpercent = lockiter->periods[i].percent * oldlockpercentofnewtotal; + + //truncate it at 3 digits resolution. + newpercent = ((double(int(newpercent * 1000.0))) / 1000.0); + print("EDEDEDEDED newpercent is ",newpercent,"\n"); + totalnewpercent += newpercent; + if (lockiter->periods[i].duration == insertperiod) { + insertintoexisting = true; + } + if (lockiter->periods[i].duration > insertperiod) { + insertindex = i; + } + lastperiodduration = lockiter->periods[i].duration; + eosiosystem::lockperiods tperiod; + tperiod.duration = lockiter->periods[i].duration; + tperiod.percent = newpercent; + newperiods.push_back(tperiod); + } - /* - * Request is validated per Exception handling. - * - * - * - * + if(insertperiod > lastperiodduration) + { + insertindex = lockiter->periods.size(); + } - amount + Staking Reward Amount is locked in Staker's Account for 7 days. + print("EDEDEDEDEDEDEDED INSERT INDEX IS ",insertindex); + + //adapting an existing period. + if (insertintoexisting) { + double t = newperiods[insertindex - 1].percent + (100.0 - totalnewpercent); + t = ((double(int(t * 1000.0))) / 1000.0); + newperiods[insertindex - 1].percent = t; + } else { //add the new period + double t = (100.0 - totalnewpercent); + t = ((double(int(t * 1000.0))) / 1000.0); + eosiosystem::lockperiods iperiod; + iperiod.duration = insertperiod; + iperiod.percent = t; + newperiods.insert(newperiods.begin() + insertindex, iperiod); + print("EDEDEDEDED newpercent added is ",t,"\n"); + } - */ + //update the locks table.. modgenlocked + action( + permission_level{get_self(), "active"_n}, + SYSTEMACCOUNT, + "modgenlocked"_n, + std::make_tuple(actor, newperiods, newlockamount, newremaininglockamount) + ).send(); + + /* + * First compute origpercent as (old amount of lock / (old lock amount + additional lock amount))/100. + + For each percent in the lock + newpercent = percent * (origpercent). + If duration == new duration + Add the new amount to the period + Keep this as the index which will need the add on percent for final. + If duration > new duration + Add in the new period here! + Keep this as the index which will need the add on percent for final. + + Lock amount start 22 + Lock amount added 100 + + Periods + 1— 5% .9% + 2— 15% 2.7% + 3— 80% 14.4% + ————————————————— + 22 is 18% 122 so multiply each percent by (18/100) to get new percent. + * + * + * + * + */ + // insertperiod = (now - timestamp) + 7 days is the new unlock period we are adding. + // go through the periods until end of list or period >= insertperiod. + // 5 + + }else { + //else make new lock. + bool canvote = true; + int64_t lockamount = (int64_t)(stakingrewardamount + amount); + vector periods; + eosiosystem::lockperiods period; + period.duration = 604800; + period.percent = 100.0; + periods.push_back(period); + INLINE_ACTION_SENDER(eosiosystem::system_contract, addgenlocked) + ("eosio"_n, {{_self, "active"_n}}, + {actor, periods, canvote, lockamount} + ); + } const string response_string = string("{\"status\": \"OK\",\"fee_collected\":") + to_string(paid_fee_amount) + string("}"); diff --git a/contracts/fio.system/include/fio.system/fio.system.hpp b/contracts/fio.system/include/fio.system/fio.system.hpp index fc4e3431..0d668892 100755 --- a/contracts/fio.system/include/fio.system/fio.system.hpp +++ b/contracts/fio.system/include/fio.system/fio.system.hpp @@ -341,6 +341,9 @@ class [[eosio::contract("fio.system")]] system_contract : public native { [[eosio::action]] void addgenlocked(const name &owner, const vector &periods, const bool &canvote,const int64_t &amount); + [[eosio::action]] + void modgenlocked(const name &owner, const vector &periods, const int64_t &amount,const int64_t &rem_lock_amount); + [[eosio::action]] void onblock(ignore header); diff --git a/contracts/fio.system/src/fio.system.cpp b/contracts/fio.system/src/fio.system.cpp index 0ba69727..8107f6db 100755 --- a/contracts/fio.system/src/fio.system.cpp +++ b/contracts/fio.system/src/fio.system.cpp @@ -220,7 +220,9 @@ namespace eosiosystem { void eosiosystem::system_contract::addgenlocked(const name &owner, const vector &periods, const bool &canvote, const int64_t &amount) { - require_auth(TokenContract); + + eosio_assert((has_auth(TokenContract) || has_auth(StakingContract)), + "missing required authority of fio.token or fio.staking"); check(is_account(owner),"account must pre exist"); check(amount > 0,"cannot add locked token amount less or equal 0."); @@ -237,6 +239,46 @@ namespace eosiosystem { }); } + void eosiosystem::system_contract::modgenlocked(const name &owner, const vector &periods, + const int64_t &amount, const int64_t &rem_lock_amount) { + + eosio_assert( has_auth(StakingContract), + "missing required authority of fio.staking"); + + check(is_account(owner),"account must pre exist"); + check(amount > 0,"cannot add locked token amount less or equal 0."); + check(rem_lock_amount > 0,"cannot add remaining locked token amount less or equal 0."); + + double totp = 0.0; + double tv = 0.0; + int64_t longestperiod = 0; + for(int i=0;i 0.0, "unlock_periods", "Invalid unlock periods", + "Invalid percentage value in unlock periods", ErrorInvalidUnlockPeriods); + tv = periods[i].percent - (double(int(periods[i].percent * 1000.0)))/1000.0; + fio_400_assert(tv == 0.0, "unlock_periods", "Invalid unlock periods", + "Invalid precision for percentage in unlock periods", ErrorInvalidUnlockPeriods); + fio_400_assert(periods[i].duration > 0, "unlock_periods", "Invalid unlock periods", + "Invalid duration value in unlock periods", ErrorInvalidUnlockPeriods); + totp += periods[i].percent; + if (periods[i].duration > longestperiod){ + longestperiod = periods[i].duration; + } + } + fio_400_assert(totp == 100.0, "unlock_periods", "Invalid unlock periods", + "Invalid total percentage for unlock periods", ErrorInvalidUnlockPeriods); + + auto locks_by_owner = _generallockedtokens.get_index<"byowner"_n>(); + auto lockiter = locks_by_owner.find(owner.value); + check(lockiter != locks_by_owner.end(),"error looking up lock owner."); + //call the system contract and update the record. + locks_by_owner.modify(lockiter, get_self(), [&](auto &av) { + av.remaining_lock_amount = rem_lock_amount; + av.lock_amount = amount; + av.periods = periods; + }); + } + } /// fio.system @@ -244,7 +286,7 @@ EOSIO_DISPATCH( eosiosystem::system_contract, // native.hpp (newaccount definition is actually in fio.system.cpp) (newaccount)(addaction)(remaction)(updateauth)(deleteauth)(linkauth)(unlinkauth)(canceldelay)(onerror)(setabi) // fio.system.cpp -(init)(addlocked)(addgenlocked)(setparams)(setpriv) +(init)(addlocked)(addgenlocked)(modgenlocked)(setparams)(setpriv) (rmvproducer)(updtrevision) // delegate_bandwidth.cpp (updatepower) diff --git a/contracts/fio.token/include/fio.token/fio.token.hpp b/contracts/fio.token/include/fio.token/fio.token.hpp index 22bf01d2..e8762821 100755 --- a/contracts/fio.token/include/fio.token/fio.token.hpp +++ b/contracts/fio.token/include/fio.token/fio.token.hpp @@ -170,9 +170,9 @@ namespace eosio { } //apply a little QC. const auto my_balance = eosio::token::get_balance("fio.token"_n, owner, FIOSYMBOL.code()); - check(my_balance.amount >= (generallockedamount + generallockedamount + stakedfio), + check(my_balance.amount >= (generallockedamount + genesislockedamount + stakedfio), "computeusablebalance, amount of locked fio plus staked is greater than balance!! for " + owner.to_string() ); - uint64_t amount = my_balance.amount - (generallockedamount + generallockedamount + stakedfio); + uint64_t amount = my_balance.amount - (generallockedamount + genesislockedamount + stakedfio); return amount; } From 795be4a789f03047a28a1ec7308ec234d3d32079 Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Wed, 5 May 2021 09:20:34 -0600 Subject: [PATCH 15/32] changes for transfer and voting allow genesis locks and general locks to co exist --- contracts/fio.staking/fio.staking.cpp | 4 +- contracts/fio.system/src/voting.cpp | 46 +++++++++++++------ .../fio.token/include/fio.token/fio.token.hpp | 6 +-- contracts/fio.token/src/fio.token.cpp | 19 +++++++- 4 files changed, 56 insertions(+), 19 deletions(-) diff --git a/contracts/fio.staking/fio.staking.cpp b/contracts/fio.staking/fio.staking.cpp index 6ecfe1e3..da495f4e 100644 --- a/contracts/fio.staking/fio.staking.cpp +++ b/contracts/fio.staking/fio.staking.cpp @@ -114,7 +114,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { //get the usable balance for the account //this is account balance - genesis locked tokens - general locked balance. - auto stakeablebalance = eosio::token::computeusablebalance(actor); + auto stakeablebalance = eosio::token::computeusablebalance(actor,true); uint64_t paid_fee_amount = 0; @@ -263,7 +263,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { //get the usable balance for the account //this is account balance - genesis locked tokens - general locked balance. - auto stakeablebalance = eosio::token::computeusablebalance(actor); + auto stakeablebalance = eosio::token::computeusablebalance(actor,true); uint64_t paid_fee_amount = 0; //begin, bundle eligible fee logic for staking diff --git a/contracts/fio.system/src/voting.cpp b/contracts/fio.system/src/voting.cpp index 4516b830..a99bb92d 100755 --- a/contracts/fio.system/src/voting.cpp +++ b/contracts/fio.system/src/voting.cpp @@ -790,10 +790,11 @@ namespace eosiosystem { amount = damount; } - }else{ + }//STAKING comment out to permit genesis and general locks to co-exist. + // else{ //amount is all the available tokens in the account. - return amount; - } + // return amount; + // } } //TEST TEST TEST LOCKED TOKENS //TEST TEST TEST LOCKED TOKENS uint32_t issueplus210 = lockiter->timestamp+(25*60); @@ -812,9 +813,26 @@ namespace eosiosystem { } } } + + //STAKING + //now add in the logic for the general locks. + auto locks_by_owner = _generallockedtokens.get_index<"byowner"_n>(); + auto glockiter = locks_by_owner.find(tokenowner.value); + if(glockiter != locks_by_owner.end()){ + //if can vote -- + if (glockiter->can_vote == 0){ + if (amount > glockiter->remaining_lock_amount) { + amount = amount - glockiter->remaining_lock_amount; + }else{ + amount = 0; + } + } + } + return amount; } + //STAKING -- this will be obsoleted, logic will be included in get_votable_balance. glockresult system_contract::get_general_votable_balance(const name &tokenowner){ glockresult res; @@ -868,12 +886,13 @@ namespace eosiosystem { //change to get_unlocked_balance() Ed 11/25/2019 uint64_t amount = 0; - glockresult res = get_general_votable_balance(voter->owner); - if(res.lockfound){ - amount = res.amount; - }else { + + // STAKING genesis locks and general can co exist. glockresult res = get_general_votable_balance(voter->owner); + // if(res.lockfound){ + // amount = res.amount; + // }else { amount = get_votable_balance(voter->owner); - } + // } //on the first vote we update the total voted fio. @@ -1274,12 +1293,13 @@ namespace eosiosystem { check(!voter.proxy || !voter.is_proxy, "account registered as a proxy is not allowed to use a proxy"); uint64_t amount = 0; - glockresult res = get_general_votable_balance(voter.owner); - if(res.lockfound){ - amount = res.amount; - }else { + // STAKING genesis and genersal locks can co exist + // glockresult res = get_general_votable_balance(voter.owner); + // if(res.lockfound){ + // amount = res.amount; + // }else { amount = get_votable_balance(voter.owner); - } + // } //instead of staked we use the voters current FIO balance MAS-522 eliminate stake from voting. auto new_weight = (double)amount; if (voter.is_proxy) { diff --git a/contracts/fio.token/include/fio.token/fio.token.hpp b/contracts/fio.token/include/fio.token/fio.token.hpp index e8762821..d7938319 100755 --- a/contracts/fio.token/include/fio.token/fio.token.hpp +++ b/contracts/fio.token/include/fio.token/fio.token.hpp @@ -156,9 +156,9 @@ namespace eosio { //This action will compute the number of unlocked tokens contained within an account. // This considers - static uint64_t computeusablebalance(const name &owner){ - uint64_t genesislockedamount = computeremaininglockedtokens(owner,true); - uint64_t generallockedamount = computegenerallockedtokens(owner,true); + static uint64_t computeusablebalance(const name &owner,bool updatelocks){ + uint64_t genesislockedamount = computeremaininglockedtokens(owner,updatelocks); + uint64_t generallockedamount = computegenerallockedtokens(owner,updatelocks); uint64_t stakedfio = 0; fioio::account_staking_table accountstaking(STAKINGACCOUNT, STAKINGACCOUNT.value); diff --git a/contracts/fio.token/src/fio.token.cpp b/contracts/fio.token/src/fio.token.cpp index 4238e634..d8317362 100755 --- a/contracts/fio.token/src/fio.token.cpp +++ b/contracts/fio.token/src/fio.token.cpp @@ -130,6 +130,7 @@ namespace eosio { ) { //recompute the remaining locked amount based on vesting. uint64_t lockedTokenAmount = computeremaininglockedtokens(tokenowner, false);//-feeamount; + //subtract the lock amount from the balance if (lockedTokenAmount < amount) { amount -= lockedTokenAmount; @@ -188,7 +189,8 @@ namespace eosio { const name &actor, const string &tpid, const int64_t &feeamount, - const bool &errorifaccountexists) { + const bool &errorifaccountexists) + { require_auth(actor); asset qty; @@ -240,6 +242,7 @@ namespace eosio { "Locked tokens can only be transferred to new account", ErrorPubKeyValid); } + auto other = eosionames.find(new_account_name.value); if (other == eosionames.end()) { //the name is not in the table. @@ -304,6 +307,7 @@ namespace eosio { "Insufficient balance", ErrorLowFunds); + //must do these three in this order!! can transfer can transfer computeusablebalance fio_400_assert(can_transfer(actor, feeamount, qty.amount, false), "amount", to_string(qty.amount), "Insufficient balance tokens locked", ErrorInsufficientUnlockedFunds); @@ -312,6 +316,12 @@ namespace eosio { "Funds locked", ErrorInsufficientUnlockedFunds); + uint64_t uamount = computeusablebalance(actor,false); + fio_400_assert(uamount >= qty.amount, "actor", to_string(actor.value), + "Insufficient Funds.", + ErrorInsufficientUnlockedFunds); + + sub_balance(actor, qty); add_balance(new_account_name, qty, actor); @@ -380,6 +390,12 @@ namespace eosio { "Funds locked", ErrorInsufficientUnlockedFunds); + + int64_t amount = computeusablebalance(from,false); + fio_400_assert(amount >= quantity.amount, "actor", to_string(from.value), + "Insufficient Funds.", + ErrorInsufficientUnlockedFunds); + auto payer = has_auth(to) ? to : from; sub_balance(from, quantity); @@ -492,6 +508,7 @@ namespace eosio { //check for pre existing account is done here. name owner = transfer_public_key(payee_public_key,amount,max_fee,actor,tpid,reg_amount,true); + //if no locked tokens in the account do this. bool canvote = (can_vote == 1); INLINE_ACTION_SENDER(eosiosystem::system_contract, addgenlocked) ("eosio"_n, {{_self, "active"_n}}, From 90d2afdc589756d172c2f31b3fa39bf8b8134734 Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Fri, 7 May 2021 14:24:20 -0600 Subject: [PATCH 16/32] fix computation of srp to claim fix computation of srp to claim --- contracts/fio.staking/fio.staking.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/contracts/fio.staking/fio.staking.cpp b/contracts/fio.staking/fio.staking.cpp index da495f4e..639c4b6a 100644 --- a/contracts/fio.staking/fio.staking.cpp +++ b/contracts/fio.staking/fio.staking.cpp @@ -321,9 +321,13 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { std::make_tuple(actor, UNSTAKEFIOTOKENSRAM) ).send(); } - //SRPs to Claim are computed: Staker's Account SRPs * (Unstaked amount / Total Tokens Staked in Staker's Account) - uint64_t srpstoclaim = astakeiter->total_srp * ( amount / astakeiter->total_staked_fio); + // this needs to be a floating point (double) operation + uint64_t srpstoclaim = (uint64_t)((double)astakeiter->total_srp * (double)( (double)amount / (double)astakeiter->total_staked_fio)); + + print("EDEDEDEDEDED total staked fio is ",astakeiter->total_staked_fio, "\n"); + print("EDEDEDEDEDED amount is ",amount, "\n"); + print("EDEDEDEDEDED total srp is ",astakeiter->total_srp, "\n"); //compute rate of exchange uint64_t rateofexchange = 1; @@ -331,6 +335,8 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { rateofexchange = gstaking.combined_token_pool / gstaking.global_srp_count; } + print("EDEDEDEDEDED rate of exchange is ",rateofexchange, "\n"); + eosio_assert((srpstoclaim * rateofexchange) >= amount, "unstakefio, invalid calc in totalrewardamount, must be that (srpstoclaim * rateofexchange) > amount. "); uint64_t totalrewardamount = ((srpstoclaim * rateofexchange) - amount); uint64_t tenpercent = totalrewardamount / 10; @@ -343,12 +349,15 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { eosio_assert(astakeiter->total_srp >= srpstoclaim,"unstakefio, total srp for account must be greater than or equal srpstoclaim." ); eosio_assert(astakeiter->total_staked_fio >= amount,"unstakefio, total staked fio for account must be greater than or equal fiostakedsufs." ); + print("EDEDEDEDEDED updating astake by account!!!! ", "\n"); //100000000000 + //update the existing record astakebyaccount.modify(astakeiter, _self, [&](struct account_staking_info &a) { a.total_staked_fio -= amount; a.total_srp -= srpstoclaim; }); + print("EDEDEDEDEDED after astake by account!!!! ", "\n"); //100000000000 //transfer the staking reward amount. if (stakingrewardamount > 0) { //Staking Reward Amount is transferred to Staker's Account. @@ -365,6 +374,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { eosio_assert(gstaking.staked_token_pool >= amount,"unstakefio, staked token pool must be greater or equal to staked amount. " ); eosio_assert(gstaking.global_srp_count >= srpstoclaim,"unstakefio, global srp count must be greater or equal to srpstoclaim. " ); + print("EDEDEDEDEDED decr global state!!!! ", "\n"); //100000000000 // decrement the combined_token_pool by fiostaked+fiorewarded. gstaking.combined_token_pool -= (amount+stakingrewardamount); // decrement the staked_token_pool by fiostaked. @@ -372,6 +382,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { // decrement the global_srp_count by srpcount. gstaking.global_srp_count -= srpstoclaim; + print("EDEDEDEDEDED after decr global state!!!! ", "\n"); //100000000000 const uint32_t present_time = now(); //pay the tpid. if ((tpid.length() > 0)&&(tpidrewardamount>0)){ @@ -511,6 +522,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { // 5 }else { + print("EDEDEDEDEDED making lock!!!! ", "\n"); //100000000000 //else make new lock. bool canvote = true; int64_t lockamount = (int64_t)(stakingrewardamount + amount); @@ -523,6 +535,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { ("eosio"_n, {{_self, "active"_n}}, {actor, periods, canvote, lockamount} ); + print("EDEDEDEDEDED done making lock!!!! ", "\n"); //100000000000 } const string response_string = string("{\"status\": \"OK\",\"fee_collected\":") + From 9c9f9f1b1d5b806ea366d1a55249b00268dc24c0 Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Sat, 8 May 2021 15:10:39 -0600 Subject: [PATCH 17/32] add staking rewards collection, minting of rewards add staking rewards collection, minting of staking rewards --- contracts/fio.common/fio.common.hpp | 40 ++++++++++++++--- contracts/fio.staking/fio.staking.cpp | 36 ++++++++++----- contracts/fio.treasury/fio.treasury.cpp | 58 ++++++++++++++++++++++++- 3 files changed, 117 insertions(+), 17 deletions(-) diff --git a/contracts/fio.common/fio.common.hpp b/contracts/fio.common/fio.common.hpp index 50da78da..9c70e323 100644 --- a/contracts/fio.common/fio.common.hpp +++ b/contracts/fio.common/fio.common.hpp @@ -288,7 +288,13 @@ namespace fioio { permission_level{auth, "active"_n}, TREASURYACCOUNT, "bprewdupdate"_n, - std::make_tuple((uint64_t)(static_cast(amount) * .85)) + std::make_tuple((uint64_t)(static_cast(amount) * .60)) + ).send(); + action( + permission_level{auth, "active"_n}, + STAKINGACCOUNT, + "incgrewards"_n, + std::make_tuple((uint64_t)(static_cast(amount) * .25)) ).send(); } else { @@ -296,7 +302,13 @@ namespace fioio { permission_level{auth, "active"_n}, TREASURYACCOUNT, "bprewdupdate"_n, - std::make_tuple((uint64_t)(static_cast(amount) * .95)) + std::make_tuple((uint64_t)(static_cast(amount) * .70)) + ).send(); + action( + permission_level{auth, "active"_n}, + STAKINGACCOUNT, + "incgrewards"_n, + std::make_tuple((uint64_t)(static_cast(amount) * .25)) ).send(); } } @@ -350,7 +362,13 @@ namespace fioio { permission_level{auth, "active"_n}, TREASURYACCOUNT, "bppoolupdate"_n, - std::make_tuple((uint64_t)(static_cast(amount) * .85)) + std::make_tuple((uint64_t)(static_cast(amount) * .60)) + ).send(); + action( + permission_level{auth, "active"_n}, + STAKINGACCOUNT, + "incgrewards"_n, + std::make_tuple((uint64_t)(static_cast(amount) * .25)) ).send(); } else { @@ -358,7 +376,13 @@ namespace fioio { permission_level{auth, "active"_n}, TREASURYACCOUNT, "bppoolupdate"_n, - std::make_tuple((uint64_t)(static_cast(amount) * .95)) + std::make_tuple((uint64_t)(static_cast(amount) * .70)) + ).send(); + action( + permission_level{auth, "active"_n}, + STAKINGACCOUNT, + "incgrewards"_n, + std::make_tuple((uint64_t)(static_cast(amount) * .25)) ).send(); } } @@ -372,7 +396,13 @@ namespace fioio { permission_level{actor, "active"_n}, TREASURYACCOUNT, "bprewdupdate"_n, - std::make_tuple((uint64_t)(static_cast(amount) * .95)) + std::make_tuple((uint64_t)(static_cast(amount) * .70)) + ).send(); + action( + permission_level{actor, "active"_n}, + STAKINGACCOUNT, + "incgrewards"_n, + std::make_tuple((uint64_t)(static_cast(amount) * .25)) ).send(); action( diff --git a/contracts/fio.staking/fio.staking.cpp b/contracts/fio.staking/fio.staking.cpp index 639c4b6a..ad96e2be 100644 --- a/contracts/fio.staking/fio.staking.cpp +++ b/contracts/fio.staking/fio.staking.cpp @@ -50,20 +50,36 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { //FIP-21 actions to update staking state. + //(implement 7) - //incgrewards performs the staking state increments when rewards are identified during fee collection. + //incgrewards performs the staking state increments when rewards are identified (including minted) during fee collection. // params // fioamountsufs, this is the amount of FIO being added to the rewards (from fees or when minted). units SUFs // logic - // increment rewards_token_pool + // increment rewards_token_pool total counter how much has come in from fees AND minting units SUFs // increment daily_staking_rewards - // increment combined_token_pool. + // increment combined_token_pool. increment whenever funds earmarked as staking rewards. + [[eosio::action]] + void incgrewards(const int64_t &fioamountsufs ) { + eosio_assert((has_auth(AddressContract) || has_auth(TokenContract) || has_auth(TREASURYACCOUNT) || + has_auth(STAKINGACCOUNT) || has_auth(REQOBTACCOUNT) || has_auth(SYSTEMACCOUNT) || has_auth(FeeContract)), + "missing required authority of fio.address, fio.treasury, fio.fee, fio.token, fio.stakng, eosio or fio.reqobt"); + gstaking.rewards_token_pool += fioamountsufs; + gstaking.daily_staking_rewards += fioamountsufs; + gstaking.combined_token_pool += fioamountsufs; + } - //(implement 8) - //clrgdailyrew performs the clearing of the daily rewards. - // params none! - // logic - // set daily_staking_rewards = 0; + [[eosio::action]] + void recorddaily(const int64_t &amounttomint ) { + eosio_assert( has_auth(TREASURYACCOUNT), + "missing required authority of fio.treasury"); + if (amounttomint > 0) { + gstaking.staking_rewards_reserves_minted += amounttomint; + gstaking.daily_staking_rewards += amounttomint; + } + gstaking.combined_token_pool += gstaking.daily_staking_rewards; + gstaking.daily_staking_rewards = 0; + } //(implement 9) //incgstkmint increments the staking_rewards_reserves_minted @@ -335,7 +351,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { rateofexchange = gstaking.combined_token_pool / gstaking.global_srp_count; } - print("EDEDEDEDEDED rate of exchange is ",rateofexchange, "\n"); + print("EDEDEDEDEDED rate of exchange is ",rateofexchange, "\n"); eosio_assert((srpstoclaim * rateofexchange) >= amount, "unstakefio, invalid calc in totalrewardamount, must be that (srpstoclaim * rateofexchange) > amount. "); uint64_t totalrewardamount = ((srpstoclaim * rateofexchange) - amount); @@ -549,5 +565,5 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { }; //class Staking -EOSIO_DISPATCH(Staking, (stakefio)(unstakefio) ) +EOSIO_DISPATCH(Staking, (stakefio)(unstakefio)(incgrewards)(recorddaily) ) } diff --git a/contracts/fio.treasury/fio.treasury.cpp b/contracts/fio.treasury/fio.treasury.cpp index a0142e07..17479e57 100644 --- a/contracts/fio.treasury/fio.treasury.cpp +++ b/contracts/fio.treasury/fio.treasury.cpp @@ -15,6 +15,7 @@ #define PAYABLETPIDS 100 #include "fio.treasury.hpp" +#include namespace fioio { @@ -31,6 +32,8 @@ class [[eosio::contract("FIOTreasury")]] FIOTreasury: public eosio::contract { voteshares_table voteshares; eosiosystem::eosio_global_state gstate; eosiosystem::global_state_singleton global; + fioio::global_staking_singleton staking; + fioio::global_staking_state gstaking; eosiosystem::producers_table producers; bool rewardspaid; uint64_t lasttpidpayout; @@ -47,7 +50,8 @@ class [[eosio::contract("FIOTreasury")]] FIOTreasury: public eosio::contract { producers(SYSTEMACCOUNT, SYSTEMACCOUNT.value), global(SYSTEMACCOUNT, SYSTEMACCOUNT.value), fdtnrewards(get_self(), get_self().value), - bucketrewards(get_self(), get_self().value) { + bucketrewards(get_self(), get_self().value), + staking(STAKINGACCOUNT, STAKINGACCOUNT.value){ state = clockstate.get_or_default(); } @@ -182,6 +186,50 @@ class [[eosio::contract("FIOTreasury")]] FIOTreasury: public eosio::contract { //*********** CREATE PAYSCHEDULE ************** // If there is no pay schedule then create a new one if (std::distance(voteshares.begin(), voteshares.end()) == 0) { //if new payschedule + + //process the staking rewards, once per day. + /* + If Daily Staking Rewards is less than 25,000 FIO Tokens and Staking Rewards Reserves Minted is less than Staking Rewards Reserves Maximum: + The difference between 25,000 FIO Tokens and Daily Staking Rewards + (or difference between Staking Rewards Reserves Minted and Staking Rewards Reserves Maximum, whichever is smaller) + is minted, transferred to treasury account and added to Staking Rewards Reserves Minted. + Daily Staking Rewards is incremented by the tokens minted. + Daily Staking Rewards amount is: + Added to Combined Token Pool, which modifies ROE + Set to 0 + */ + gstaking = staking.get(); + uint64_t amounttomint = 0; + if ((gstaking.daily_staking_rewards < DAILYSTAKINGMINTTHRESHOLD)&& + (gstaking.staking_rewards_reserves_minted < STAKINGREWARDSRESERVEMAXIMUM)){ + uint64_t twentyfivekminusdaily = DAILYSTAKINGMINTTHRESHOLD - gstaking.daily_staking_rewards; + uint64_t reservemaxminusminted = STAKINGREWARDSRESERVEMAXIMUM - gstaking.staking_rewards_reserves_minted; + amounttomint = reservemaxminusminted; + if (amounttomint > twentyfivekminusdaily){ + amounttomint = twentyfivekminusdaily; + } + print ("EDEDEDEDEDEDEDEDED minting staking rewards!!"); + print ("EDEDEDEDEDEDEDEDED minting staking rewards!!"); + //mint and update accounting. + action(permission_level{get_self(), "active"_n}, + TokenContract, "mintfio"_n, + make_tuple(TREASURYACCOUNT,amounttomint) + ).send(); + + } + + print ("EDEDEDEDEDEDEDEDED updating staking rewards accounting!!"); + //update daily accounting, and zero daily staking + action(permission_level{get_self(), "active"_n}, + STAKINGACCOUNT, "recorddaily"_n, + make_tuple(amounttomint) + ).send(); + print ("EDEDEDEDEDEDEDEDED updating done staking rewards accounting!!", "\n"); + + //end process staking rewards. + + + print ("EDEDEDEDEDEDEDEDED creating schedule!!","\n"); //Create the payment schedule int64_t bpcounter = 0; uint64_t activecount = 0; @@ -205,6 +253,8 @@ class [[eosio::contract("FIOTreasury")]] FIOTreasury: public eosio::contract { itr++; if (bpcounter >= MAXBPS) break; } // &itr : producers table + print ("EDEDEDEDEDEDEDEDED done with schedule!!","\n"); + print ("EDEDEDEDEDEDEDEDED start bp reserve mint!!","\n"); //Move 1/365 of the bucketpool to the bpshare bprewards.set(bpreward{bprewards.get().rewards + static_cast(bucketrewards.get().rewards / YEARDAYS)}, get_self()); bucketrewards.set(bucketpool{bucketrewards.get().rewards - static_cast(bucketrewards.get().rewards / YEARDAYS)}, get_self()); @@ -238,6 +288,8 @@ class [[eosio::contract("FIOTreasury")]] FIOTreasury: public eosio::contract { } //!!!rewards is now 0 in the bprewards table and can no longer be referred to. If needed use projectedpay + print ("EDEDEDEDEDEDEDEDED done minting!!","\n"); + print ("EDEDEDEDEDEDEDEDED start foundation mint!!","\n"); uint64_t fdtntomint = FDTNMAXTOMINT; const uint64_t fdtnremainingreserve = FDTNMAXRESERVE - state.fdtnreservetokensminted; @@ -287,6 +339,7 @@ class [[eosio::contract("FIOTreasury")]] FIOTreasury: public eosio::contract { } } //if new payschedule + print ("EDEDEDEDEDEDEDEDED end creat pay schedule!!","\n"); //*********** END OF CREATE PAYSCHEDULE ************** auto bpiter = voteshares.find(producer); prodbyowner = producers.get_index<"byowner"_n>(); @@ -301,6 +354,7 @@ class [[eosio::contract("FIOTreasury")]] FIOTreasury: public eosio::contract { check(proditer->is_active, "producer does not have an active key"); if (payout > 0) { + print ("EDEDEDEDEDEDEDEDED payout to !!",bpiter->owner,"!!\n"); action(permission_level{get_self(), "active"_n}, TokenContract, "transfer"_n, make_tuple(TREASURYACCOUNT, name(bpiter->owner), asset(payout, FIOSYMBOL), @@ -321,7 +375,7 @@ class [[eosio::contract("FIOTreasury")]] FIOTreasury: public eosio::contract { ).send(); } - + print ("EDEDEDEDEDEDEDEDED payout to !!",FOUNDATIONACCOUNT,"!!\n"); // PAY FOUNDATION // auto fdtnstate = fdtnrewards.get(); if(fdtnstate.rewards > 0) { From 3ce5447f47342b1dc1aa5c4804b72e534799ca2d Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Tue, 11 May 2021 10:25:05 -0600 Subject: [PATCH 18/32] clean up prints clean up prints --- contracts/fio.staking/fio.staking.cpp | 73 +------------------------ contracts/fio.treasury/fio.treasury.cpp | 16 +----- 2 files changed, 2 insertions(+), 87 deletions(-) diff --git a/contracts/fio.staking/fio.staking.cpp b/contracts/fio.staking/fio.staking.cpp index ad96e2be..d16a49e4 100644 --- a/contracts/fio.staking/fio.staking.cpp +++ b/contracts/fio.staking/fio.staking.cpp @@ -47,18 +47,10 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { } - //FIP-21 actions to update staking state. - - - //(implement 7) //incgrewards performs the staking state increments when rewards are identified (including minted) during fee collection. // params // fioamountsufs, this is the amount of FIO being added to the rewards (from fees or when minted). units SUFs - // logic - // increment rewards_token_pool total counter how much has come in from fees AND minting units SUFs - // increment daily_staking_rewards - // increment combined_token_pool. increment whenever funds earmarked as staking rewards. [[eosio::action]] void incgrewards(const int64_t &fioamountsufs ) { eosio_assert((has_auth(AddressContract) || has_auth(TokenContract) || has_auth(TREASURYACCOUNT) || @@ -69,6 +61,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { gstaking.combined_token_pool += fioamountsufs; } + //recorddaily will perform the daily update of global state, when bps claim rewards. [[eosio::action]] void recorddaily(const int64_t &amounttomint ) { eosio_assert( has_auth(TREASURYACCOUNT), @@ -81,11 +74,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { gstaking.daily_staking_rewards = 0; } - //(implement 9) //incgstkmint increments the staking_rewards_reserves_minted - // params - // amountfiosufs, this is the amount of FIO that has been minted, units SUFs - //FIP-21 actions to update staking state. [[eosio::action]] void stakefio(const string &fio_address, const int64_t &amount, const int64_t &max_fee, const string &tpid, const name &actor) { @@ -151,8 +140,6 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { "unexpected fee type for endpoint stake_fio_tokens, expected 0", ErrorNoEndpoint); - - if (bundleeligiblecountdown > 0) { action{ permission_level{_self, "active"_n}, @@ -341,18 +328,12 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { // this needs to be a floating point (double) operation uint64_t srpstoclaim = (uint64_t)((double)astakeiter->total_srp * (double)( (double)amount / (double)astakeiter->total_staked_fio)); - print("EDEDEDEDEDED total staked fio is ",astakeiter->total_staked_fio, "\n"); - print("EDEDEDEDEDED amount is ",amount, "\n"); - print("EDEDEDEDEDED total srp is ",astakeiter->total_srp, "\n"); - //compute rate of exchange uint64_t rateofexchange = 1; if (gstaking.combined_token_pool >= COMBINEDTOKENPOOLMINIMUM) { rateofexchange = gstaking.combined_token_pool / gstaking.global_srp_count; } - print("EDEDEDEDEDED rate of exchange is ",rateofexchange, "\n"); - eosio_assert((srpstoclaim * rateofexchange) >= amount, "unstakefio, invalid calc in totalrewardamount, must be that (srpstoclaim * rateofexchange) > amount. "); uint64_t totalrewardamount = ((srpstoclaim * rateofexchange) - amount); uint64_t tenpercent = totalrewardamount / 10; @@ -365,15 +346,12 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { eosio_assert(astakeiter->total_srp >= srpstoclaim,"unstakefio, total srp for account must be greater than or equal srpstoclaim." ); eosio_assert(astakeiter->total_staked_fio >= amount,"unstakefio, total staked fio for account must be greater than or equal fiostakedsufs." ); - print("EDEDEDEDEDED updating astake by account!!!! ", "\n"); //100000000000 - //update the existing record astakebyaccount.modify(astakeiter, _self, [&](struct account_staking_info &a) { a.total_staked_fio -= amount; a.total_srp -= srpstoclaim; }); - print("EDEDEDEDEDED after astake by account!!!! ", "\n"); //100000000000 //transfer the staking reward amount. if (stakingrewardamount > 0) { //Staking Reward Amount is transferred to Staker's Account. @@ -390,7 +368,6 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { eosio_assert(gstaking.staked_token_pool >= amount,"unstakefio, staked token pool must be greater or equal to staked amount. " ); eosio_assert(gstaking.global_srp_count >= srpstoclaim,"unstakefio, global srp count must be greater or equal to srpstoclaim. " ); - print("EDEDEDEDEDED decr global state!!!! ", "\n"); //100000000000 // decrement the combined_token_pool by fiostaked+fiorewarded. gstaking.combined_token_pool -= (amount+stakingrewardamount); // decrement the staked_token_pool by fiostaked. @@ -398,7 +375,6 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { // decrement the global_srp_count by srpcount. gstaking.global_srp_count -= srpstoclaim; - print("EDEDEDEDEDED after decr global state!!!! ", "\n"); //100000000000 const uint32_t present_time = now(); //pay the tpid. if ((tpid.length() > 0)&&(tpidrewardamount>0)){ @@ -438,18 +414,9 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { //get the remaining unlocked of the lock. int64_t newremaininglockamount = lockiter->remaining_lock_amount + (stakingrewardamount + amount); //get the timestamp of the lock. - print("EDEDDEDEDEDED present time ", present_time,"\n"); - print("EDEDDEDEDEDED time stamp lock ", lockiter->timestamp,"\n"); - - - print("EDEDDEDEDEDED lock amount ", lockiter->lock_amount,"\n"); - print("EDEDDEDEDEDED staking reward amount ", stakingrewardamount,"\n"); - print("EDEDDEDEDEDED unstake amount ", amount,"\n"); - uint32_t insertperiod = (present_time - lockiter->timestamp) + 604800; double oldlockpercentofnewtotal = (((double) lockiter->lock_amount) / (double) (lockiter->lock_amount + stakingrewardamount + amount)); - print("EDEDDEDEDEDED oldlockpercentofnewtotal ", oldlockpercentofnewtotal,"\n"); vector newperiods; //gotta truncate tne new percent at 3 decimal places bool insertintoexisting = false; @@ -461,7 +428,6 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { //truncate it at 3 digits resolution. newpercent = ((double(int(newpercent * 1000.0))) / 1000.0); - print("EDEDEDEDED newpercent is ",newpercent,"\n"); totalnewpercent += newpercent; if (lockiter->periods[i].duration == insertperiod) { insertintoexisting = true; @@ -481,9 +447,6 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { insertindex = lockiter->periods.size(); } - - print("EDEDEDEDEDEDEDED INSERT INDEX IS ",insertindex); - //adapting an existing period. if (insertintoexisting) { double t = newperiods[insertindex - 1].percent + (100.0 - totalnewpercent); @@ -496,7 +459,6 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { iperiod.duration = insertperiod; iperiod.percent = t; newperiods.insert(newperiods.begin() + insertindex, iperiod); - print("EDEDEDEDED newpercent added is ",t,"\n"); } //update the locks table.. modgenlocked @@ -506,39 +468,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { "modgenlocked"_n, std::make_tuple(actor, newperiods, newlockamount, newremaininglockamount) ).send(); - - /* - * First compute origpercent as (old amount of lock / (old lock amount + additional lock amount))/100. - - For each percent in the lock - newpercent = percent * (origpercent). - If duration == new duration - Add the new amount to the period - Keep this as the index which will need the add on percent for final. - If duration > new duration - Add in the new period here! - Keep this as the index which will need the add on percent for final. - - Lock amount start 22 - Lock amount added 100 - - Periods - 1— 5% .9% - 2— 15% 2.7% - 3— 80% 14.4% - ————————————————— - 22 is 18% 122 so multiply each percent by (18/100) to get new percent. - * - * - * - * - */ - // insertperiod = (now - timestamp) + 7 days is the new unlock period we are adding. - // go through the periods until end of list or period >= insertperiod. - // 5 - }else { - print("EDEDEDEDEDED making lock!!!! ", "\n"); //100000000000 //else make new lock. bool canvote = true; int64_t lockamount = (int64_t)(stakingrewardamount + amount); @@ -551,7 +481,6 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { ("eosio"_n, {{_self, "active"_n}}, {actor, periods, canvote, lockamount} ); - print("EDEDEDEDEDED done making lock!!!! ", "\n"); //100000000000 } const string response_string = string("{\"status\": \"OK\",\"fee_collected\":") + diff --git a/contracts/fio.treasury/fio.treasury.cpp b/contracts/fio.treasury/fio.treasury.cpp index 17479e57..2cf5e34e 100644 --- a/contracts/fio.treasury/fio.treasury.cpp +++ b/contracts/fio.treasury/fio.treasury.cpp @@ -208,8 +208,6 @@ class [[eosio::contract("FIOTreasury")]] FIOTreasury: public eosio::contract { if (amounttomint > twentyfivekminusdaily){ amounttomint = twentyfivekminusdaily; } - print ("EDEDEDEDEDEDEDEDED minting staking rewards!!"); - print ("EDEDEDEDEDEDEDEDED minting staking rewards!!"); //mint and update accounting. action(permission_level{get_self(), "active"_n}, TokenContract, "mintfio"_n, @@ -218,18 +216,14 @@ class [[eosio::contract("FIOTreasury")]] FIOTreasury: public eosio::contract { } - print ("EDEDEDEDEDEDEDEDED updating staking rewards accounting!!"); //update daily accounting, and zero daily staking action(permission_level{get_self(), "active"_n}, STAKINGACCOUNT, "recorddaily"_n, make_tuple(amounttomint) ).send(); - print ("EDEDEDEDEDEDEDEDED updating done staking rewards accounting!!", "\n"); //end process staking rewards. - - print ("EDEDEDEDEDEDEDEDED creating schedule!!","\n"); //Create the payment schedule int64_t bpcounter = 0; uint64_t activecount = 0; @@ -253,8 +247,6 @@ class [[eosio::contract("FIOTreasury")]] FIOTreasury: public eosio::contract { itr++; if (bpcounter >= MAXBPS) break; } // &itr : producers table - print ("EDEDEDEDEDEDEDEDED done with schedule!!","\n"); - print ("EDEDEDEDEDEDEDEDED start bp reserve mint!!","\n"); //Move 1/365 of the bucketpool to the bpshare bprewards.set(bpreward{bprewards.get().rewards + static_cast(bucketrewards.get().rewards / YEARDAYS)}, get_self()); bucketrewards.set(bucketpool{bucketrewards.get().rewards - static_cast(bucketrewards.get().rewards / YEARDAYS)}, get_self()); @@ -287,9 +279,6 @@ class [[eosio::contract("FIOTreasury")]] FIOTreasury: public eosio::contract { print("Block producers reserve minting exhausted"); } //!!!rewards is now 0 in the bprewards table and can no longer be referred to. If needed use projectedpay - - print ("EDEDEDEDEDEDEDEDED done minting!!","\n"); - print ("EDEDEDEDEDEDEDEDED start foundation mint!!","\n"); uint64_t fdtntomint = FDTNMAXTOMINT; const uint64_t fdtnremainingreserve = FDTNMAXRESERVE - state.fdtnreservetokensminted; @@ -339,7 +328,6 @@ class [[eosio::contract("FIOTreasury")]] FIOTreasury: public eosio::contract { } } //if new payschedule - print ("EDEDEDEDEDEDEDEDED end creat pay schedule!!","\n"); //*********** END OF CREATE PAYSCHEDULE ************** auto bpiter = voteshares.find(producer); prodbyowner = producers.get_index<"byowner"_n>(); @@ -354,7 +342,6 @@ class [[eosio::contract("FIOTreasury")]] FIOTreasury: public eosio::contract { check(proditer->is_active, "producer does not have an active key"); if (payout > 0) { - print ("EDEDEDEDEDEDEDEDED payout to !!",bpiter->owner,"!!\n"); action(permission_level{get_self(), "active"_n}, TokenContract, "transfer"_n, make_tuple(TREASURYACCOUNT, name(bpiter->owner), asset(payout, FIOSYMBOL), @@ -374,8 +361,7 @@ class [[eosio::contract("FIOTreasury")]] FIOTreasury: public eosio::contract { make_tuple(producer) ).send(); } - - print ("EDEDEDEDEDEDEDEDED payout to !!",FOUNDATIONACCOUNT,"!!\n"); + // PAY FOUNDATION // auto fdtnstate = fdtnrewards.get(); if(fdtnstate.rewards > 0) { From 3aa5eae20ab0482a4005a96ce2862df021428df9 Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Tue, 11 May 2021 10:28:48 -0600 Subject: [PATCH 19/32] set the locking periods to be shortened set the locking periods to be shortened --- contracts/fio.common/fio.accounts.hpp | 2 +- contracts/fio.token/include/fio.token/fio.token.hpp | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/contracts/fio.common/fio.accounts.hpp b/contracts/fio.common/fio.accounts.hpp index c56579c1..67c17f6c 100644 --- a/contracts/fio.common/fio.accounts.hpp +++ b/contracts/fio.common/fio.accounts.hpp @@ -34,7 +34,7 @@ namespace fioio { static const name AddressContract = name("fio.address"); static const name TPIDContract = name("fio.tpid"); static const name TokenContract = name("fio.token"); - static const name FOUNDATIONACCOUNT = name("tw4tjkmo4eyd"); + static const name FOUNDATIONACCOUNT = name("htjonrkf1lgs"); static const name TREASURYACCOUNT = name("fio.treasury"); static const name STAKINGACCOUNT = name("fio.staking"); static const name FIOSYSTEMACCOUNT= name("fio.system"); diff --git a/contracts/fio.token/include/fio.token/fio.token.hpp b/contracts/fio.token/include/fio.token/fio.token.hpp index d7938319..2c89df21 100755 --- a/contracts/fio.token/include/fio.token/fio.token.hpp +++ b/contracts/fio.token/include/fio.token/fio.token.hpp @@ -193,13 +193,18 @@ namespace eosio { } if (lockiter->unlocked_period_count < 6) { //to shorten the vesting schedule adapt these variables. + // TESTING ONLY!!! comment out genesis locking periods..DO NOT DELIVER THIS + /* uint32_t daysSinceGrant = (int) ((present_time - lockiter->timestamp) / SECONDSPERDAY); uint32_t firstPayPeriod = 90; uint32_t payoutTimePeriod = 180; + */ - //TEST LOCKED TOKENS uint32_t daysSinceGrant = (int)((present_time - lockiter->timestamp) / 60); - //TEST LOCKED TOKENS uint32_t firstPayPeriod = 15; - //TEST LOCKED TOKENS uint32_t payoutTimePeriod = 15; + //TEST LOCKED TOKENS + // TESTING ONLY!!! shorten genesis locking periods..DO NOT DELIVER THIS + uint32_t daysSinceGrant = (int)((present_time - lockiter->timestamp) / 60); + uint32_t firstPayPeriod = 10; + uint32_t payoutTimePeriod = 10; bool ninetyDaysSinceGrant = daysSinceGrant >= firstPayPeriod; From cea56b14694658e8948634d91e5428d024e64371 Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Tue, 18 May 2021 10:37:49 -0600 Subject: [PATCH 20/32] main net locks to 2 minutes main net locks to 2 minutes for automated tests --- contracts/fio.token/include/fio.token/fio.token.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/fio.token/include/fio.token/fio.token.hpp b/contracts/fio.token/include/fio.token/fio.token.hpp index 2c89df21..df88d986 100755 --- a/contracts/fio.token/include/fio.token/fio.token.hpp +++ b/contracts/fio.token/include/fio.token/fio.token.hpp @@ -203,8 +203,8 @@ namespace eosio { //TEST LOCKED TOKENS // TESTING ONLY!!! shorten genesis locking periods..DO NOT DELIVER THIS uint32_t daysSinceGrant = (int)((present_time - lockiter->timestamp) / 60); - uint32_t firstPayPeriod = 10; - uint32_t payoutTimePeriod = 10; + uint32_t firstPayPeriod = 2; + uint32_t payoutTimePeriod = 2; bool ninetyDaysSinceGrant = daysSinceGrant >= firstPayPeriod; From efab69a29151a324d94a731d01bf2942a4076a0f Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Thu, 20 May 2021 07:19:19 -0600 Subject: [PATCH 21/32] dev testing. mod the locks to pay out completely during last unlock, address rounding and resolution issues while adapting locks during unstaking --- contracts/fio.staking/fio.staking.cpp | 53 +++++++++++++------ contracts/fio.system/src/fio.system.cpp | 10 +++- .../fio.token/include/fio.token/fio.token.hpp | 48 +++++++++++------ contracts/fio.token/src/fio.token.cpp | 1 + 4 files changed, 78 insertions(+), 34 deletions(-) diff --git a/contracts/fio.staking/fio.staking.cpp b/contracts/fio.staking/fio.staking.cpp index d16a49e4..d20562a1 100644 --- a/contracts/fio.staking/fio.staking.cpp +++ b/contracts/fio.staking/fio.staking.cpp @@ -119,7 +119,8 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { //get the usable balance for the account //this is account balance - genesis locked tokens - general locked balance. - auto stakeablebalance = eosio::token::computeusablebalance(actor,true); + print("EDEDEDEDEDEDEDEDEDED calling from staking!!!!!!!!!"); + auto stakeablebalance = eosio::token::computeusablebalance(actor,false); uint64_t paid_fee_amount = 0; @@ -266,7 +267,8 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { //get the usable balance for the account //this is account balance - genesis locked tokens - general locked balance. - auto stakeablebalance = eosio::token::computeusablebalance(actor,true); + // print("EDEDEDEDEDEDEDEDEDED calling from unstaking!!!!!!!!!"); + auto stakeablebalance = eosio::token::computeusablebalance(actor,false); uint64_t paid_fee_amount = 0; //begin, bundle eligible fee logic for staking @@ -326,8 +328,9 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { } //SRPs to Claim are computed: Staker's Account SRPs * (Unstaked amount / Total Tokens Staked in Staker's Account) // this needs to be a floating point (double) operation - uint64_t srpstoclaim = (uint64_t)((double)astakeiter->total_srp * (double)( (double)amount / (double)astakeiter->total_staked_fio)); + uint64_t srpstoclaim = (uint64_t)(((double)astakeiter->total_srp * (double)( (double)amount / (double)astakeiter->total_staked_fio))+0.5); + print("EDEEEDEDEDEDEDED srps to claim is ",to_string(srpstoclaim),"\n"); //compute rate of exchange uint64_t rateofexchange = 1; if (gstaking.combined_token_pool >= COMBINEDTOKENPOOLMINIMUM) { @@ -417,23 +420,27 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { uint32_t insertperiod = (present_time - lockiter->timestamp) + 604800; double oldlockpercentofnewtotal = (((double) lockiter->lock_amount) / (double) (lockiter->lock_amount + stakingrewardamount + amount)); + vector newperiods; - //gotta truncate tne new percent at 3 decimal places + bool insertintoexisting = false; uint32_t lastperiodduration = 0; int insertindex = -1; double totalnewpercent = 0.0; - for (int i = 0; i < lockiter->periods.size(); i++) { - double newpercent = lockiter->periods[i].percent * oldlockpercentofnewtotal; - //truncate it at 3 digits resolution. + for (int i = 0; i < lockiter->periods.size(); i++) { + uint64_t percentthisperiod = (lockiter->periods[i].percent * 1000); + uint64_t lockamountsmaller = lockiter->lock_amount / 10000; + uint64_t amountthisperiod = ((lockamountsmaller * percentthisperiod)/100000) * 10000; + double newpercent = ((double)amountthisperiod / (double) (lockiter->lock_amount + stakingrewardamount + amount)) * 100.0 ; newpercent = ((double(int(newpercent * 1000.0))) / 1000.0); totalnewpercent += newpercent; - if (lockiter->periods[i].duration == insertperiod) { - insertintoexisting = true; - } - if (lockiter->periods[i].duration > insertperiod) { + + if (lockiter->periods[i].duration >= insertperiod) { insertindex = i; + if (lockiter->periods[i].duration == insertperiod) { + insertintoexisting = true; + } } lastperiodduration = lockiter->periods[i].duration; eosiosystem::lockperiods tperiod; @@ -447,14 +454,30 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { insertindex = lockiter->periods.size(); } + double newpercent = ((double)(stakingrewardamount + amount) / (double) (lockiter->lock_amount + stakingrewardamount + amount))*100.0 ; + newpercent = ((double(int(newpercent * 1000.0))) / 1000.0); + //adapting an existing period. if (insertintoexisting) { - double t = newperiods[insertindex - 1].percent + (100.0 - totalnewpercent); - t = ((double(int(t * 1000.0))) / 1000.0); - newperiods[insertindex - 1].percent = t; + // print("EDEDEDEDEDEDEDEDED totalnewpercent ",totalnewpercent,"\n"); + // print("EDEDEDEDEDEDEDEDED newpercent ",newpercent,"\n"); + double t1 = totalnewpercent + newpercent; + t1 = (100.0 - t1); + // print("EDEDEDEDEDEDEDEDED 100 minus t1 raw ",t1,"\n"); + t1 = ((double(int((t1 * 1000.0)+0.5))) / 1000.0); + // print("EDEDEDEDEDEDEDEDED 100 minus t1 ",t1,"\n"); + // print("EDEDEDEDEDEDEDEDED existing percent ",newperiods[insertindex].percent,"\n"); + t1 = newperiods[insertindex].percent + newpercent + t1; + // print("EDEDEDEDEDEDEDEDED t1 + newpercent + percent ",t1,"\n"); + t1 = ((double(int((t1 * 1000.0)+0.5))) / 1000.0); + // print("EDEDEDEDEDEDEDEDED t1 ",t1,"\n"); + newperiods[insertindex].percent = t1; } else { //add the new period + // print("EDEDEDEDEDEDEDEDED totalnewpercent ",totalnewpercent,"\n"); double t = (100.0 - totalnewpercent); - t = ((double(int(t * 1000.0))) / 1000.0); + // print("EDEDEDEDEDEDEDEDED 100 minus totalnewpercent ",t,"\n"); + t = ((double(int((t * 1000.0)+0.5))) / 1000.0); + // print("EDEDEDEDEDEDEDEDED t ",t,"\n"); eosiosystem::lockperiods iperiod; iperiod.duration = insertperiod; iperiod.percent = t; diff --git a/contracts/fio.system/src/fio.system.cpp b/contracts/fio.system/src/fio.system.cpp index 8107f6db..a7e936ea 100755 --- a/contracts/fio.system/src/fio.system.cpp +++ b/contracts/fio.system/src/fio.system.cpp @@ -256,16 +256,22 @@ namespace eosiosystem { fio_400_assert(periods[i].percent > 0.0, "unlock_periods", "Invalid unlock periods", "Invalid percentage value in unlock periods", ErrorInvalidUnlockPeriods); tv = periods[i].percent - (double(int(periods[i].percent * 1000.0)))/1000.0; + string t = "Invalid precision for percentage in unlock periods " + to_string(periods[i].percent); fio_400_assert(tv == 0.0, "unlock_periods", "Invalid unlock periods", - "Invalid precision for percentage in unlock periods", ErrorInvalidUnlockPeriods); + t , ErrorInvalidUnlockPeriods); fio_400_assert(periods[i].duration > 0, "unlock_periods", "Invalid unlock periods", "Invalid duration value in unlock periods", ErrorInvalidUnlockPeriods); + // print("EDEDEDEDEDEDED adding in period percent ",periods[i].percent,"\n"); totp += periods[i].percent; if (periods[i].duration > longestperiod){ longestperiod = periods[i].duration; } } - fio_400_assert(totp == 100.0, "unlock_periods", "Invalid unlock periods", + + string thestr = "Invalid unlock periods " + to_string(totp); + //rounding! + int itotp = (int)((double)(totp) + 0.0001); + fio_400_assert(itotp == 100 , "unlock_periods", thestr, "Invalid total percentage for unlock periods", ErrorInvalidUnlockPeriods); auto locks_by_owner = _generallockedtokens.get_index<"byowner"_n>(); diff --git a/contracts/fio.token/include/fio.token/fio.token.hpp b/contracts/fio.token/include/fio.token/fio.token.hpp index df88d986..43171d17 100755 --- a/contracts/fio.token/include/fio.token/fio.token.hpp +++ b/contracts/fio.token/include/fio.token/fio.token.hpp @@ -318,6 +318,8 @@ namespace eosio { numberVestingPayouts--; } + + //process the rest of the payout periods, other than the first period. if (payoutsDue > numberVestingPayouts) { remainingPayouts = payoutsDue - numberVestingPayouts; @@ -328,16 +330,22 @@ namespace eosio { //this logic assumes to have 3 decimal places in the specified percentage percentperblock = 18800; } else if (lockiter->grant_type == 4) { - //this is assumed to have 3 decimal places in the specified percentage return lockiter->remaining_locked_amount; } else { //unknown lock type, dont unlock return lockiter->remaining_locked_amount; } - //we eliminate the last 5 digits of the SUFs to avoid overflow in the calculations - //that follow. - uint64_t totalgrantsmaller = totalgrantamount/10000; - amountpay = ((remainingPayouts * (totalgrantsmaller * percentperblock)) / 100000) * 10000; + + if(payoutsDue >= 5){ + //always pay all the rest at the end of the locks life. + amountpay = lockiter->remaining_locked_amount; + } + else { + //we eliminate the last 5 digits of the SUFs to avoid overflow in the calculations + //that follow. + uint64_t totalgrantsmaller = totalgrantamount / 10000; + amountpay = ((remainingPayouts * (totalgrantsmaller * percentperblock)) / 100000) * 10000; + } if (newlockedamount > amountpay) { newlockedamount -= amountpay; @@ -347,6 +355,7 @@ namespace eosio { didsomething = true; } + if (didsomething && doupdate) { //get fio balance for this account, uint32_t present_time = now(); @@ -366,9 +375,7 @@ namespace eosio { av.unlocked_period_count += remainingPayouts + addone; }); } - return newlockedamount; - } else { return lockiter->remaining_locked_amount; } @@ -392,6 +399,7 @@ namespace eosio { uint32_t secondsSinceGrant = (present_time - lockiter->timestamp); uint32_t payoutsDue = 0; + for (int i=0;iperiods.size(); i++){ if (lockiter->periods[i].duration <= secondsSinceGrant){ payoutsDue++; @@ -403,16 +411,22 @@ namespace eosio { bool didsomething = false; if (payoutsDue > lockiter->payouts_performed) { - - uint64_t percentperblock = 0; - for (int i=lockiter->payouts_performed; iperiods[i].percent * 1000); - uint64_t lockamountsmaller = lockiter->lock_amount / 10000; - uint64_t amountadded = ((lockamountsmaller * percentperblock)/100000) * 10000; - amountpay += amountadded; - } + if((lockiter->payouts_performed + payoutsDue) >= lockiter->periods.size()) + { + //payout the remaining lock amount. + amountpay = newlockedamount; + } + else { + uint64_t percentperblock = 0; + for (int i = lockiter->payouts_performed; i < payoutsDue; i++) { + //special note -- we allow 3 decimal places for precision. this needs enforced + //in the input validation of these values. + percentperblock = (lockiter->periods[i].percent * 1000); + uint64_t lockamountsmaller = lockiter->lock_amount / 10000; + uint64_t amountadded = ((lockamountsmaller * percentperblock) / 100000) * 10000; + amountpay += amountadded; + } + } if (newlockedamount > amountpay) { newlockedamount -= amountpay; diff --git a/contracts/fio.token/src/fio.token.cpp b/contracts/fio.token/src/fio.token.cpp index d8317362..57e1248b 100755 --- a/contracts/fio.token/src/fio.token.cpp +++ b/contracts/fio.token/src/fio.token.cpp @@ -316,6 +316,7 @@ namespace eosio { "Funds locked", ErrorInsufficientUnlockedFunds); + uint64_t uamount = computeusablebalance(actor,false); fio_400_assert(uamount >= qty.amount, "actor", to_string(actor.value), "Insufficient Funds.", From 77ec7e4354476df4729d11393e5fd77aef162e43 Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Tue, 25 May 2021 10:18:19 -0600 Subject: [PATCH 22/32] address rounding issues address rounding issues. --- contracts/fio.staking/fio.staking.cpp | 43 ++++++++++++++++--- contracts/fio.system/src/fio.system.cpp | 7 +-- .../fio.token/include/fio.token/fio.token.hpp | 4 ++ contracts/fio.token/src/fio.token.cpp | 3 +- 4 files changed, 47 insertions(+), 10 deletions(-) diff --git a/contracts/fio.staking/fio.staking.cpp b/contracts/fio.staking/fio.staking.cpp index d20562a1..6ed31812 100644 --- a/contracts/fio.staking/fio.staking.cpp +++ b/contracts/fio.staking/fio.staking.cpp @@ -182,7 +182,14 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { //compute rate of exchange and SRPs uint64_t rateofexchange = 1; if (gstaking.combined_token_pool >= COMBINEDTOKENPOOLMINIMUM) { + print("EDEDEDEDEDEDEDEDEDEDED global srp count ", gstaking.global_srp_count); + print("EDEDEDEDEDEDEDEDEDEDED combined_token_pool ", gstaking.combined_token_pool); rateofexchange = gstaking.combined_token_pool / gstaking.global_srp_count; + print("EDEDEDEDEDEDEDEDEDEDED rate of exchange set to ", rateofexchange); + if(rateofexchange < 1) { + print("EDEDEDEDEDEDEDEDEDEDED RATE OF EXCHANGE LESS THAN 1 ", rateofexchange); + rateofexchange = 1; + } } uint64_t srptoaward = amount / rateofexchange; @@ -328,20 +335,30 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { } //SRPs to Claim are computed: Staker's Account SRPs * (Unstaked amount / Total Tokens Staked in Staker's Account) // this needs to be a floating point (double) operation + //round this to avoid issues with decimal representations uint64_t srpstoclaim = (uint64_t)(((double)astakeiter->total_srp * (double)( (double)amount / (double)astakeiter->total_staked_fio))+0.5); print("EDEEEDEDEDEDEDED srps to claim is ",to_string(srpstoclaim),"\n"); //compute rate of exchange uint64_t rateofexchange = 1; if (gstaking.combined_token_pool >= COMBINEDTOKENPOOLMINIMUM) { + print("EDEDEDEDEDEDEDEDEDEDED global srp count ", gstaking.global_srp_count); + print("EDEDEDEDEDEDEDEDEDEDED combined_token_pool ", gstaking.combined_token_pool); rateofexchange = gstaking.combined_token_pool / gstaking.global_srp_count; + print("EDEDEDEDEDEDEDEDEDEDED rate of exchange set to ", rateofexchange); + if(rateofexchange < 1) { + print("EDEDEDEDEDEDEDEDEDEDED RATE OF EXCHANGE LESS THAN 1 ", rateofexchange); + rateofexchange = 1; + } } eosio_assert((srpstoclaim * rateofexchange) >= amount, "unstakefio, invalid calc in totalrewardamount, must be that (srpstoclaim * rateofexchange) > amount. "); uint64_t totalrewardamount = ((srpstoclaim * rateofexchange) - amount); + print("EDEDEDEDEDEDEDEDEDEDED total reward amount is ", totalrewardamount); uint64_t tenpercent = totalrewardamount / 10; //Staking Reward Amount is computed: ((SRPs to Claim * Rate of Exchnage) - Unstake amount) * 0.9 uint64_t stakingrewardamount = tenpercent * 9; + print("EDEDEDEDEDEDEDEDEDEDED staking reward amount is ", totalrewardamount); // TPID Reward Amount is computed: ((SRPs to Claim * Rate of Exchnage) - Unstake amount) * 0.1 uint64_t tpidrewardamount = tenpercent; @@ -418,9 +435,6 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { int64_t newremaininglockamount = lockiter->remaining_lock_amount + (stakingrewardamount + amount); //get the timestamp of the lock. uint32_t insertperiod = (present_time - lockiter->timestamp) + 604800; - double oldlockpercentofnewtotal = (((double) lockiter->lock_amount) / - (double) (lockiter->lock_amount + stakingrewardamount + amount)); - vector newperiods; bool insertintoexisting = false; @@ -429,11 +443,19 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { double totalnewpercent = 0.0; for (int i = 0; i < lockiter->periods.size(); i++) { + print("EDEDEDEDEDEDED percent this period ",lockiter->periods[i].percent,"\n"); uint64_t percentthisperiod = (lockiter->periods[i].percent * 1000); uint64_t lockamountsmaller = lockiter->lock_amount / 10000; uint64_t amountthisperiod = ((lockamountsmaller * percentthisperiod)/100000) * 10000; - double newpercent = ((double)amountthisperiod / (double) (lockiter->lock_amount + stakingrewardamount + amount)) * 100.0 ; - newpercent = ((double(int(newpercent * 1000.0))) / 1000.0); + print("EDEDEDEDEDEDED percentthisperiod times 1000 ",percentthisperiod,"\n"); + print("EDEDEDEDEDEDED amountthisperiod sufs ",amountthisperiod,"\n"); + uint64_t newtotal = lockiter->lock_amount + stakingrewardamount + amount; + print("EDEDEDEDEDEDED new lock total ",newtotal,"\n"); + double newpercent = ((double)amountthisperiod / (double) (newtotal)) * 100.0 ; + print("EDEDEDEDEDEDED new percent ",newpercent,"\n"); + newpercent = ((double(int((newpercent * 1000.0)+0.5))) / 1000.0); + // newpercent = ((double(int(newpercent * 1000.0))) / 1000.0); + print("EDEDEDEDEDEDED new percent three digits. ",newpercent,"\n"); totalnewpercent += newpercent; if (lockiter->periods[i].duration >= insertperiod) { @@ -445,6 +467,8 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { lastperiodduration = lockiter->periods[i].duration; eosiosystem::lockperiods tperiod; tperiod.duration = lockiter->periods[i].duration; + eosio_assert(newpercent > 0.0,"unstakefio, ERROR -- zero percent not permitted during adaptation of general locks. " ); + tperiod.percent = newpercent; newperiods.push_back(tperiod); } @@ -455,7 +479,8 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { } double newpercent = ((double)(stakingrewardamount + amount) / (double) (lockiter->lock_amount + stakingrewardamount + amount))*100.0 ; - newpercent = ((double(int(newpercent * 1000.0))) / 1000.0); + newpercent = ((double(int((newpercent * 1000.0)+0.5))) / 1000.0); + //newpercent = ((double(int(newpercent * 1000.0))) / 1000.0); //adapting an existing period. if (insertintoexisting) { @@ -464,6 +489,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { double t1 = totalnewpercent + newpercent; t1 = (100.0 - t1); // print("EDEDEDEDEDEDEDEDED 100 minus t1 raw ",t1,"\n"); + //address rounding on very small deltas. t1 = ((double(int((t1 * 1000.0)+0.5))) / 1000.0); // print("EDEDEDEDEDEDEDEDED 100 minus t1 ",t1,"\n"); // print("EDEDEDEDEDEDEDEDED existing percent ",newperiods[insertindex].percent,"\n"); @@ -471,6 +497,8 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { // print("EDEDEDEDEDEDEDEDED t1 + newpercent + percent ",t1,"\n"); t1 = ((double(int((t1 * 1000.0)+0.5))) / 1000.0); // print("EDEDEDEDEDEDEDEDED t1 ",t1,"\n"); + eosio_assert(t1 > 0.0,"unstakefio, ERROR -- zero percent not permitted during adaptation of existing general locks period. " ); + newperiods[insertindex].percent = t1; } else { //add the new period // print("EDEDEDEDEDEDEDEDED totalnewpercent ",totalnewpercent,"\n"); @@ -481,6 +509,8 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { eosiosystem::lockperiods iperiod; iperiod.duration = insertperiod; iperiod.percent = t; + eosio_assert(t > 0.0,"unstakefio, ERROR -- zero percent not permitted during insertion of new general locks period. " ); + newperiods.insert(newperiods.begin() + insertindex, iperiod); } @@ -495,6 +525,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { //else make new lock. bool canvote = true; int64_t lockamount = (int64_t)(stakingrewardamount + amount); + print("EDEDEDEDEDEDEDEDED creating general lock for amount ", lockamount, "\n"); vector periods; eosiosystem::lockperiods period; period.duration = 604800; diff --git a/contracts/fio.system/src/fio.system.cpp b/contracts/fio.system/src/fio.system.cpp index a7e936ea..c0b1e082 100755 --- a/contracts/fio.system/src/fio.system.cpp +++ b/contracts/fio.system/src/fio.system.cpp @@ -255,10 +255,11 @@ namespace eosiosystem { for(int i=0;i 0.0, "unlock_periods", "Invalid unlock periods", "Invalid percentage value in unlock periods", ErrorInvalidUnlockPeriods); - tv = periods[i].percent - (double(int(periods[i].percent * 1000.0)))/1000.0; - string t = "Invalid precision for percentage in unlock periods " + to_string(periods[i].percent); + double t1 = (double(int((periods[i].percent * 1000.0)+0.5)))/1000.0; + tv = periods[i].percent - t1; + string ts = "Invalid precision for percentage in unlock periods " + to_string(periods[i].percent); fio_400_assert(tv == 0.0, "unlock_periods", "Invalid unlock periods", - t , ErrorInvalidUnlockPeriods); + ts , ErrorInvalidUnlockPeriods); fio_400_assert(periods[i].duration > 0, "unlock_periods", "Invalid unlock periods", "Invalid duration value in unlock periods", ErrorInvalidUnlockPeriods); // print("EDEDEDEDEDEDED adding in period percent ",periods[i].percent,"\n"); diff --git a/contracts/fio.token/include/fio.token/fio.token.hpp b/contracts/fio.token/include/fio.token/fio.token.hpp index 43171d17..b2d995cf 100755 --- a/contracts/fio.token/include/fio.token/fio.token.hpp +++ b/contracts/fio.token/include/fio.token/fio.token.hpp @@ -421,8 +421,12 @@ namespace eosio { for (int i = lockiter->payouts_performed; i < payoutsDue; i++) { //special note -- we allow 3 decimal places for precision. this needs enforced //in the input validation of these values. + //1.234 goes to (int) 1234 percentperblock = (lockiter->periods[i].percent * 1000); + //we take off 4 zeros from the SUFs to protect against overflow. uint64_t lockamountsmaller = lockiter->lock_amount / 10000; + //we divide by 100000 to get back to lockamountsmaller units, then multiply + // by 10000 to get back to SUFs uint64_t amountadded = ((lockamountsmaller * percentperblock) / 100000) * 10000; amountpay += amountadded; } diff --git a/contracts/fio.token/src/fio.token.cpp b/contracts/fio.token/src/fio.token.cpp index 57e1248b..3412ca02 100755 --- a/contracts/fio.token/src/fio.token.cpp +++ b/contracts/fio.token/src/fio.token.cpp @@ -465,7 +465,8 @@ namespace eosio { for(int i=0;i 0.0, "unlock_periods", "Invalid unlock periods", "Invalid percentage value in unlock periods", ErrorInvalidUnlockPeriods); - tv = periods[i].percent - (double(int(periods[i].percent * 1000.0)))/1000.0; + tv = periods[i].percent - (double(int((periods[i].percent * 1000.0)+0.5)))/1000.0; + //tv = periods[i].percent - (double(int(periods[i].percent * 1000.0)))/1000.0; fio_400_assert(tv == 0.0, "unlock_periods", "Invalid unlock periods", "Invalid precision for percentage in unlock periods", ErrorInvalidUnlockPeriods); fio_400_assert(periods[i].duration > 0, "unlock_periods", "Invalid unlock periods", From 2fa97c0c501332fd713196791585f9574dd2b737 Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Wed, 26 May 2021 13:53:13 -0600 Subject: [PATCH 23/32] add logic to remove expired periods, use same day on unstake remove expired periods, use period in this same day for unstaking period. --- contracts/fio.staking/fio.staking.cpp | 65 ++++++++++++------- .../include/fio.system/fio.system.hpp | 3 +- contracts/fio.system/src/fio.system.cpp | 8 ++- 3 files changed, 50 insertions(+), 26 deletions(-) diff --git a/contracts/fio.staking/fio.staking.cpp b/contracts/fio.staking/fio.staking.cpp index 6ed31812..361f3d82 100644 --- a/contracts/fio.staking/fio.staking.cpp +++ b/contracts/fio.staking/fio.staking.cpp @@ -119,7 +119,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { //get the usable balance for the account //this is account balance - genesis locked tokens - general locked balance. - print("EDEDEDEDEDEDEDEDEDED calling from staking!!!!!!!!!"); + // print("EDEDEDEDEDEDEDEDEDED calling from staking!!!!!!!!!"); auto stakeablebalance = eosio::token::computeusablebalance(actor,false); @@ -249,6 +249,8 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { uint64_t bundleeligiblecountdown = 0; + const uint32_t present_time = now(); + if (!fio_address.empty()) { const uint128_t nameHash = string_to_uint128_hash(fa.fioaddress.c_str()); auto namesbyname = fionames.get_index<"byname"_n>(); @@ -259,7 +261,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { fio_403_assert(fioname_iter->owner_account == actor.value, ErrorSignature); const uint32_t expiration = fioname_iter->expiration; - const uint32_t present_time = now(); + fio_400_assert(present_time <= expiration, "fio_address", fio_address, "FIO Address expired. Renew first.", ErrorDomainExpired); bundleeligiblecountdown = fioname_iter->bundleeligiblecountdown; @@ -338,7 +340,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { //round this to avoid issues with decimal representations uint64_t srpstoclaim = (uint64_t)(((double)astakeiter->total_srp * (double)( (double)amount / (double)astakeiter->total_staked_fio))+0.5); - print("EDEEEDEDEDEDEDED srps to claim is ",to_string(srpstoclaim),"\n"); + //print("EDEEEDEDEDEDEDED srps to claim is ",to_string(srpstoclaim),"\n"); //compute rate of exchange uint64_t rateofexchange = 1; if (gstaking.combined_token_pool >= COMBINEDTOKENPOOLMINIMUM) { @@ -395,7 +397,6 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { // decrement the global_srp_count by srpcount. gstaking.global_srp_count -= srpstoclaim; - const uint32_t present_time = now(); //pay the tpid. if ((tpid.length() > 0)&&(tpidrewardamount>0)){ //get the owner of the tpid and pay them. @@ -435,32 +436,42 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { int64_t newremaininglockamount = lockiter->remaining_lock_amount + (stakingrewardamount + amount); //get the timestamp of the lock. uint32_t insertperiod = (present_time - lockiter->timestamp) + 604800; + //the days since launch. + uint32_t insertday = (lockiter->timestamp + insertperiod) / SECONDSPERDAY; + //if your duration is less than this the period is in the past. + uint32_t expirednowduration = present_time - lockiter->timestamp; + uint32_t payouts = lockiter->payouts_performed; + + vector newperiods; bool insertintoexisting = false; uint32_t lastperiodduration = 0; int insertindex = -1; double totalnewpercent = 0.0; + uint32_t daysforperiod = 0; for (int i = 0; i < lockiter->periods.size(); i++) { - print("EDEDEDEDEDEDED percent this period ",lockiter->periods[i].percent,"\n"); + // print("EDEDEDEDEDEDED percent this period ",lockiter->periods[i].percent,"\n"); uint64_t percentthisperiod = (lockiter->periods[i].percent * 1000); uint64_t lockamountsmaller = lockiter->lock_amount / 10000; uint64_t amountthisperiod = ((lockamountsmaller * percentthisperiod)/100000) * 10000; - print("EDEDEDEDEDEDED percentthisperiod times 1000 ",percentthisperiod,"\n"); - print("EDEDEDEDEDEDED amountthisperiod sufs ",amountthisperiod,"\n"); + // print("EDEDEDEDEDEDED percentthisperiod times 1000 ",percentthisperiod,"\n"); + // print("EDEDEDEDEDEDED amountthisperiod sufs ",amountthisperiod,"\n"); uint64_t newtotal = lockiter->lock_amount + stakingrewardamount + amount; - print("EDEDEDEDEDEDED new lock total ",newtotal,"\n"); + // print("EDEDEDEDEDEDED new lock total ",newtotal,"\n"); double newpercent = ((double)amountthisperiod / (double) (newtotal)) * 100.0 ; - print("EDEDEDEDEDEDED new percent ",newpercent,"\n"); + // print("EDEDEDEDEDEDED new percent ",newpercent,"\n"); newpercent = ((double(int((newpercent * 1000.0)+0.5))) / 1000.0); // newpercent = ((double(int(newpercent * 1000.0))) / 1000.0); - print("EDEDEDEDEDEDED new percent three digits. ",newpercent,"\n"); + // print("EDEDEDEDEDEDED new percent three digits. ",newpercent,"\n"); totalnewpercent += newpercent; + daysforperiod = (lockiter->timestamp + lockiter->periods[i].duration)/SECONDSPERDAY; - if (lockiter->periods[i].duration >= insertperiod) { - insertindex = i; - if (lockiter->periods[i].duration == insertperiod) { + if (daysforperiod >= insertday) { + insertindex = newperiods.size(); + //always insert into the same day. + if (daysforperiod == insertday) { insertintoexisting = true; } } @@ -468,14 +479,21 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { eosiosystem::lockperiods tperiod; tperiod.duration = lockiter->periods[i].duration; eosio_assert(newpercent > 0.0,"unstakefio, ERROR -- zero percent not permitted during adaptation of general locks. " ); - tperiod.percent = newpercent; - newperiods.push_back(tperiod); + + //only those periods not in the past go into the list of periods. + //remove old periods. + if( tperiod.duration >= expirednowduration) { + newperiods.push_back(tperiod); + }else{ + eosio_assert(payouts > 0 ,"unstakefio, internal error decrementing payouts. " ); + payouts --; + } } if(insertperiod > lastperiodduration) { - insertindex = lockiter->periods.size(); + insertindex = newperiods.size(); } double newpercent = ((double)(stakingrewardamount + amount) / (double) (lockiter->lock_amount + stakingrewardamount + amount))*100.0 ; @@ -485,21 +503,22 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { //adapting an existing period. if (insertintoexisting) { // print("EDEDEDEDEDEDEDEDED totalnewpercent ",totalnewpercent,"\n"); - // print("EDEDEDEDEDEDEDEDED newpercent ",newpercent,"\n"); - double t1 = totalnewpercent + newpercent; - t1 = (100.0 - t1); + + // double t1 = totalnewpercent + newpercent; + // t1 = (100.0 - t1); // print("EDEDEDEDEDEDEDEDED 100 minus t1 raw ",t1,"\n"); //address rounding on very small deltas. - t1 = ((double(int((t1 * 1000.0)+0.5))) / 1000.0); + // t1 = ((double(int((t1 * 1000.0)+0.5))) / 1000.0); // print("EDEDEDEDEDEDEDEDED 100 minus t1 ",t1,"\n"); // print("EDEDEDEDEDEDEDEDED existing percent ",newperiods[insertindex].percent,"\n"); - t1 = newperiods[insertindex].percent + newpercent + t1; + double t1 = newperiods[insertindex-1].percent + newpercent; // print("EDEDEDEDEDEDEDEDED t1 + newpercent + percent ",t1,"\n"); t1 = ((double(int((t1 * 1000.0)+0.5))) / 1000.0); + print("EDEDEDEDEDEDEDEDED newpercent set for period ",newperiods[insertindex-1].duration," percent is ", t1,"\n"); // print("EDEDEDEDEDEDEDEDED t1 ",t1,"\n"); eosio_assert(t1 > 0.0,"unstakefio, ERROR -- zero percent not permitted during adaptation of existing general locks period. " ); - newperiods[insertindex].percent = t1; + newperiods[insertindex-1].percent = t1; } else { //add the new period // print("EDEDEDEDEDEDEDEDED totalnewpercent ",totalnewpercent,"\n"); double t = (100.0 - totalnewpercent); @@ -519,7 +538,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { permission_level{get_self(), "active"_n}, SYSTEMACCOUNT, "modgenlocked"_n, - std::make_tuple(actor, newperiods, newlockamount, newremaininglockamount) + std::make_tuple(actor, newperiods, newlockamount, newremaininglockamount, payouts) ).send(); }else { //else make new lock. diff --git a/contracts/fio.system/include/fio.system/fio.system.hpp b/contracts/fio.system/include/fio.system/fio.system.hpp index 0d668892..4806bed2 100755 --- a/contracts/fio.system/include/fio.system/fio.system.hpp +++ b/contracts/fio.system/include/fio.system/fio.system.hpp @@ -342,7 +342,8 @@ class [[eosio::contract("fio.system")]] system_contract : public native { void addgenlocked(const name &owner, const vector &periods, const bool &canvote,const int64_t &amount); [[eosio::action]] - void modgenlocked(const name &owner, const vector &periods, const int64_t &amount,const int64_t &rem_lock_amount); + void modgenlocked(const name &owner, const vector &periods, const int64_t &amount,const int64_t &rem_lock_amount, + const uint32_t &payouts); [[eosio::action]] void onblock(ignore header); diff --git a/contracts/fio.system/src/fio.system.cpp b/contracts/fio.system/src/fio.system.cpp index c0b1e082..785c16df 100755 --- a/contracts/fio.system/src/fio.system.cpp +++ b/contracts/fio.system/src/fio.system.cpp @@ -240,7 +240,8 @@ namespace eosiosystem { } void eosiosystem::system_contract::modgenlocked(const name &owner, const vector &periods, - const int64_t &amount, const int64_t &rem_lock_amount) { + const int64_t &amount, const int64_t &rem_lock_amount, + const uint32_t &payouts) { eosio_assert( has_auth(StakingContract), "missing required authority of fio.staking"); @@ -248,6 +249,7 @@ namespace eosiosystem { check(is_account(owner),"account must pre exist"); check(amount > 0,"cannot add locked token amount less or equal 0."); check(rem_lock_amount > 0,"cannot add remaining locked token amount less or equal 0."); + check(payouts >= 0,"cannot add payouts less than 0."); double totp = 0.0; double tv = 0.0; @@ -272,7 +274,7 @@ namespace eosiosystem { string thestr = "Invalid unlock periods " + to_string(totp); //rounding! int itotp = (int)((double)(totp) + 0.0001); - fio_400_assert(itotp == 100 , "unlock_periods", thestr, + fio_400_assert(itotp <= 100 , "unlock_periods", thestr, "Invalid total percentage for unlock periods", ErrorInvalidUnlockPeriods); auto locks_by_owner = _generallockedtokens.get_index<"byowner"_n>(); @@ -282,7 +284,9 @@ namespace eosiosystem { locks_by_owner.modify(lockiter, get_self(), [&](auto &av) { av.remaining_lock_amount = rem_lock_amount; av.lock_amount = amount; + av.payouts_performed = payouts; av.periods = periods; + }); } From 7c87c9d30f30519aa38a45e97d67b2fd6cb0e318 Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Wed, 2 Jun 2021 12:44:38 -0600 Subject: [PATCH 24/32] changes to general locks to use amount instead of percent changes to general locks to use amount instead of percetn --- contracts/fio.staking/fio.staking.cpp | 81 +++++-------------- .../include/fio.system/fio.system.hpp | 48 ++++++++++- contracts/fio.system/src/fio.system.cpp | 35 +++----- .../fio.token/include/fio.token/fio.token.hpp | 19 ++--- contracts/fio.token/src/fio.token.cpp | 22 ++--- 5 files changed, 92 insertions(+), 113 deletions(-) diff --git a/contracts/fio.staking/fio.staking.cpp b/contracts/fio.staking/fio.staking.cpp index 361f3d82..58b9d4ae 100644 --- a/contracts/fio.staking/fio.staking.cpp +++ b/contracts/fio.staking/fio.staking.cpp @@ -25,7 +25,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { eosiosystem::voters_table voters; fionames_table fionames; fiofee_table fiofees; - eosiosystem::general_locks_table generallocks; + eosiosystem::general_locks_table_v2 generallocks; bool debugout = false; public: @@ -235,7 +235,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { const string &tpid, const name &actor) { require_auth(actor); - fio_400_assert(amount > 0, "amount", to_string(amount), "Invalid amount value",ErrorInvalidValue); + fio_400_assert(amount > 10000, "amount", to_string(amount), "Invalid amount value",ErrorInvalidValue); fio_400_assert(max_fee >= 0, "amount", to_string(max_fee), "Invalid fee value",ErrorInvalidValue); fio_400_assert(validateTPIDFormat(tpid), "tpid", tpid,"TPID must be empty or valid FIO address",ErrorPubKeyValid); @@ -322,8 +322,8 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { } } - fio_400_assert(stakeablebalance >= (paid_fee_amount + (uint64_t)amount), "max_fee", to_string(max_fee), "Insufficient balance.", - ErrorMaxFeeExceeded); + //fio_400_assert(stakeablebalance >= (paid_fee_amount + (uint64_t)amount), "max_fee", to_string(max_fee), "Insufficient balance.", + // ErrorMaxFeeExceeded); //End, bundle eligible fee logic for staking //RAM bump @@ -443,43 +443,28 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { uint32_t payouts = lockiter->payouts_performed; - vector newperiods; + vector newperiods; bool insertintoexisting = false; uint32_t lastperiodduration = 0; int insertindex = -1; - double totalnewpercent = 0.0; uint32_t daysforperiod = 0; for (int i = 0; i < lockiter->periods.size(); i++) { - // print("EDEDEDEDEDEDED percent this period ",lockiter->periods[i].percent,"\n"); - uint64_t percentthisperiod = (lockiter->periods[i].percent * 1000); - uint64_t lockamountsmaller = lockiter->lock_amount / 10000; - uint64_t amountthisperiod = ((lockamountsmaller * percentthisperiod)/100000) * 10000; - // print("EDEDEDEDEDEDED percentthisperiod times 1000 ",percentthisperiod,"\n"); - // print("EDEDEDEDEDEDED amountthisperiod sufs ",amountthisperiod,"\n"); - uint64_t newtotal = lockiter->lock_amount + stakingrewardamount + amount; - // print("EDEDEDEDEDEDED new lock total ",newtotal,"\n"); - double newpercent = ((double)amountthisperiod / (double) (newtotal)) * 100.0 ; - // print("EDEDEDEDEDEDED new percent ",newpercent,"\n"); - newpercent = ((double(int((newpercent * 1000.0)+0.5))) / 1000.0); - // newpercent = ((double(int(newpercent * 1000.0))) / 1000.0); - // print("EDEDEDEDEDEDED new percent three digits. ",newpercent,"\n"); - totalnewpercent += newpercent; daysforperiod = (lockiter->timestamp + lockiter->periods[i].duration)/SECONDSPERDAY; - + uint64_t amountthisperiod = lockiter->periods[i].amount; if (daysforperiod >= insertday) { insertindex = newperiods.size(); //always insert into the same day. if (daysforperiod == insertday) { insertintoexisting = true; + amountthisperiod += (stakingrewardamount + amount); } } lastperiodduration = lockiter->periods[i].duration; - eosiosystem::lockperiods tperiod; + eosiosystem::lockperiodv2 tperiod; tperiod.duration = lockiter->periods[i].duration; - eosio_assert(newpercent > 0.0,"unstakefio, ERROR -- zero percent not permitted during adaptation of general locks. " ); - tperiod.percent = newpercent; + tperiod.amount = amountthisperiod; //only those periods not in the past go into the list of periods. //remove old periods. @@ -487,49 +472,19 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { newperiods.push_back(tperiod); }else{ eosio_assert(payouts > 0 ,"unstakefio, internal error decrementing payouts. " ); + newlockamount -= tperiod.amount; + eosio_assert(newlockamount >= newremaininglockamount,"unstakefio, inconsistent general lock state lock amount less than remaining lock amount. " ); payouts --; } } - if(insertperiod > lastperiodduration) - { - insertindex = newperiods.size(); - } - double newpercent = ((double)(stakingrewardamount + amount) / (double) (lockiter->lock_amount + stakingrewardamount + amount))*100.0 ; - newpercent = ((double(int((newpercent * 1000.0)+0.5))) / 1000.0); - //newpercent = ((double(int(newpercent * 1000.0))) / 1000.0); - - //adapting an existing period. - if (insertintoexisting) { - // print("EDEDEDEDEDEDEDEDED totalnewpercent ",totalnewpercent,"\n"); - - // double t1 = totalnewpercent + newpercent; - // t1 = (100.0 - t1); - // print("EDEDEDEDEDEDEDEDED 100 minus t1 raw ",t1,"\n"); - //address rounding on very small deltas. - // t1 = ((double(int((t1 * 1000.0)+0.5))) / 1000.0); - // print("EDEDEDEDEDEDEDEDED 100 minus t1 ",t1,"\n"); - // print("EDEDEDEDEDEDEDEDED existing percent ",newperiods[insertindex].percent,"\n"); - double t1 = newperiods[insertindex-1].percent + newpercent; - // print("EDEDEDEDEDEDEDEDED t1 + newpercent + percent ",t1,"\n"); - t1 = ((double(int((t1 * 1000.0)+0.5))) / 1000.0); - print("EDEDEDEDEDEDEDEDED newpercent set for period ",newperiods[insertindex-1].duration," percent is ", t1,"\n"); - // print("EDEDEDEDEDEDEDEDED t1 ",t1,"\n"); - eosio_assert(t1 > 0.0,"unstakefio, ERROR -- zero percent not permitted during adaptation of existing general locks period. " ); - - newperiods[insertindex-1].percent = t1; - } else { //add the new period + //add the period to the list. + if (!insertintoexisting) { // print("EDEDEDEDEDEDEDEDED totalnewpercent ",totalnewpercent,"\n"); - double t = (100.0 - totalnewpercent); - // print("EDEDEDEDEDEDEDEDED 100 minus totalnewpercent ",t,"\n"); - t = ((double(int((t * 1000.0)+0.5))) / 1000.0); - // print("EDEDEDEDEDEDEDEDED t ",t,"\n"); - eosiosystem::lockperiods iperiod; + eosiosystem::lockperiodv2 iperiod; iperiod.duration = insertperiod; - iperiod.percent = t; - eosio_assert(t > 0.0,"unstakefio, ERROR -- zero percent not permitted during insertion of new general locks period. " ); - + iperiod.amount = amount; newperiods.insert(newperiods.begin() + insertindex, iperiod); } @@ -545,10 +500,10 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { bool canvote = true; int64_t lockamount = (int64_t)(stakingrewardamount + amount); print("EDEDEDEDEDEDEDEDED creating general lock for amount ", lockamount, "\n"); - vector periods; - eosiosystem::lockperiods period; + vector periods; + eosiosystem::lockperiodv2 period; period.duration = 604800; - period.percent = 100.0; + period.amount = lockamount; periods.push_back(period); INLINE_ACTION_SENDER(eosiosystem::system_contract, addgenlocked) ("eosio"_n, {{_self, "active"_n}}, diff --git a/contracts/fio.system/include/fio.system/fio.system.hpp b/contracts/fio.system/include/fio.system/fio.system.hpp index 4806bed2..fd2b599b 100755 --- a/contracts/fio.system/include/fio.system/fio.system.hpp +++ b/contracts/fio.system/include/fio.system/fio.system.hpp @@ -146,6 +146,8 @@ struct glockresult { uint64_t amount; //amount votable EOSLIB_SERIALIZE( glockresult, (lockfound)(amount)) }; + +/* TEMPORARY, COMMENT OUT ONLY FOR DEV PURPOSES struct lockperiods { int64_t duration = 0; //duration in seconds. each duration is seconds after grant creation. double percent; //this is the percent to be unlocked @@ -176,8 +178,48 @@ typedef eosio::multi_index<"locktokens"_n, locked_tokens_info, > general_locks_table; + */ +//end general locks + + +//begin general locks V2, these locks are used to hold tokens granted by any fio user +//to any other fio user. + +struct lockperiodv2 { + int64_t duration = 0; //duration in seconds. each duration is seconds after grant creation. + int64_t amount; //this is the amount in SUFs to be unlocked + EOSLIB_SERIALIZE( lockperiodv2, (duration)(amount)) +}; + +struct [[eosio::table, eosio::contract("fio.system")]] locked_tokens_info_v2 { + int64_t id; //this is the identifier of the lock, primary key + name owner_account; //this is the account that owns the lock, secondary key + int64_t lock_amount = 0; //this is the amount of the lock in FIO SUF + int32_t payouts_performed = 0; //this is the number of payouts performed thus far. + int32_t can_vote = 0; //this is the flag indicating if the lock is votable/proxy-able + std::vector periods;// this is the locking periods for the lock + int64_t remaining_lock_amount = 0; //this is the amount remaining in the lock in FIO SUF, get decremented as unlocking occurs. + uint32_t timestamp = 0; //this is the time of creation of the lock, locking periods are relative to this time. + + uint64_t primary_key() const { return id; } + uint64_t by_owner() const{return owner_account.value;} + + EOSLIB_SERIALIZE( locked_tokens_info_v2, (id)(owner_account) + (lock_amount)(payouts_performed)(can_vote)(periods)(remaining_lock_amount)(timestamp) + ) + +}; + +typedef eosio::multi_index<"locktokensv2"_n, locked_tokens_info_v2, + indexed_by<"byowner"_n, const_mem_fun < locked_tokens_info_v2, uint64_t, &locked_tokens_info_v2::by_owner> > + +> +general_locks_table_v2; //end general locks + +// + //Top producers that are calculated every block in update_elected_producers struct [[eosio::table, eosio::contract("fio.system")]] top_prod_info { name producer; @@ -299,7 +341,7 @@ class [[eosio::contract("fio.system")]] system_contract : public native { producers_table _producers; top_producers_table _topprods; locked_tokens_table _lockedtokens; - general_locks_table _generallockedtokens; + general_locks_table_v2 _generallockedtokens; //MAS-522 eliminate producers2 producers_table2 _producers2; global_state_singleton _global; global_state2_singleton _global2; @@ -339,10 +381,10 @@ class [[eosio::contract("fio.system")]] system_contract : public native { const int16_t &locktype); [[eosio::action]] - void addgenlocked(const name &owner, const vector &periods, const bool &canvote,const int64_t &amount); + void addgenlocked(const name &owner, const vector &periods, const bool &canvote,const int64_t &amount); [[eosio::action]] - void modgenlocked(const name &owner, const vector &periods, const int64_t &amount,const int64_t &rem_lock_amount, + void modgenlocked(const name &owner, const vector &periods, const int64_t &amount,const int64_t &rem_lock_amount, const uint32_t &payouts); [[eosio::action]] diff --git a/contracts/fio.system/src/fio.system.cpp b/contracts/fio.system/src/fio.system.cpp index 785c16df..4b2bc7f8 100755 --- a/contracts/fio.system/src/fio.system.cpp +++ b/contracts/fio.system/src/fio.system.cpp @@ -218,7 +218,7 @@ namespace eosiosystem { }); } - void eosiosystem::system_contract::addgenlocked(const name &owner, const vector &periods, const bool &canvote, + void eosiosystem::system_contract::addgenlocked(const name &owner, const vector &periods, const bool &canvote, const int64_t &amount) { eosio_assert((has_auth(TokenContract) || has_auth(StakingContract)), @@ -227,7 +227,7 @@ namespace eosiosystem { check(is_account(owner),"account must pre exist"); check(amount > 0,"cannot add locked token amount less or equal 0."); - _generallockedtokens.emplace(owner, [&](struct locked_tokens_info &a) { + _generallockedtokens.emplace(owner, [&](struct locked_tokens_info_v2 &a) { a.id = _generallockedtokens.available_primary_key(); a.owner_account = owner; a.lock_amount = amount; @@ -239,7 +239,7 @@ namespace eosiosystem { }); } - void eosiosystem::system_contract::modgenlocked(const name &owner, const vector &periods, + void eosiosystem::system_contract::modgenlocked(const name &owner, const vector &periods, const int64_t &amount, const int64_t &rem_lock_amount, const uint32_t &payouts) { @@ -251,31 +251,22 @@ namespace eosiosystem { check(rem_lock_amount > 0,"cannot add remaining locked token amount less or equal 0."); check(payouts >= 0,"cannot add payouts less than 0."); - double totp = 0.0; - double tv = 0.0; - int64_t longestperiod = 0; + uint64_t tota = 0; + for(int i=0;i 0.0, "unlock_periods", "Invalid unlock periods", - "Invalid percentage value in unlock periods", ErrorInvalidUnlockPeriods); - double t1 = (double(int((periods[i].percent * 1000.0)+0.5)))/1000.0; - tv = periods[i].percent - t1; - string ts = "Invalid precision for percentage in unlock periods " + to_string(periods[i].percent); - fio_400_assert(tv == 0.0, "unlock_periods", "Invalid unlock periods", - ts , ErrorInvalidUnlockPeriods); + fio_400_assert(periods[i].amount > 0, "unlock_periods", "Invalid unlock periods", + "Invalid amount value in unlock periods", ErrorInvalidUnlockPeriods); fio_400_assert(periods[i].duration > 0, "unlock_periods", "Invalid unlock periods", "Invalid duration value in unlock periods", ErrorInvalidUnlockPeriods); - // print("EDEDEDEDEDEDED adding in period percent ",periods[i].percent,"\n"); - totp += periods[i].percent; - if (periods[i].duration > longestperiod){ - longestperiod = periods[i].duration; + tota += periods[i].amount; + if (i>1){ + fio_400_assert(periods[i].duration > periods[i-1].duration, "unlock_periods", "Invalid unlock periods", + "Invalid duration value in unlock periods, must be sorted", ErrorInvalidUnlockPeriods); } } - string thestr = "Invalid unlock periods " + to_string(totp); - //rounding! - int itotp = (int)((double)(totp) + 0.0001); - fio_400_assert(itotp <= 100 , "unlock_periods", thestr, - "Invalid total percentage for unlock periods", ErrorInvalidUnlockPeriods); + fio_400_assert(tota == amount, "unlock_periods", "Invalid unlock periods", + "Invalid total amount for unlock periods", ErrorInvalidUnlockPeriods); auto locks_by_owner = _generallockedtokens.get_index<"byowner"_n>(); auto lockiter = locks_by_owner.find(owner.value); diff --git a/contracts/fio.token/include/fio.token/fio.token.hpp b/contracts/fio.token/include/fio.token/fio.token.hpp index b2d995cf..674bcbe7 100755 --- a/contracts/fio.token/include/fio.token/fio.token.hpp +++ b/contracts/fio.token/include/fio.token/fio.token.hpp @@ -32,7 +32,7 @@ namespace eosio { fioio::tpids_table tpids; fioio::fionames_table fionames; eosiosystem::locked_tokens_table lockedTokensTable; - eosiosystem::general_locks_table generalLockTokensTable; + eosiosystem::general_locks_table_v2 generalLockTokensTable; fioio::account_staking_table accountstaking; public: @@ -78,7 +78,7 @@ namespace eosio { [[eosio::action]] void trnsloctoks(const string &payee_public_key, const int32_t &can_vote, - const vector periods, + const vector periods, const int64_t &amount, const int64_t &max_fee, const name &actor, @@ -390,7 +390,7 @@ namespace eosio { static uint64_t computegenerallockedtokens(const name &actor, bool doupdate) { uint32_t present_time = now(); - eosiosystem::general_locks_table generalLockTokensTable(SYSTEMACCOUNT, SYSTEMACCOUNT.value); + eosiosystem::general_locks_table_v2 generalLockTokensTable(SYSTEMACCOUNT, SYSTEMACCOUNT.value); auto locks_by_owner = generalLockTokensTable.get_index<"byowner"_n>(); auto lockiter = locks_by_owner.find(actor.value); if (lockiter != locks_by_owner.end()) { @@ -417,18 +417,9 @@ namespace eosio { amountpay = newlockedamount; } else { - uint64_t percentperblock = 0; + for (int i = lockiter->payouts_performed; i < payoutsDue; i++) { - //special note -- we allow 3 decimal places for precision. this needs enforced - //in the input validation of these values. - //1.234 goes to (int) 1234 - percentperblock = (lockiter->periods[i].percent * 1000); - //we take off 4 zeros from the SUFs to protect against overflow. - uint64_t lockamountsmaller = lockiter->lock_amount / 10000; - //we divide by 100000 to get back to lockamountsmaller units, then multiply - // by 10000 to get back to SUFs - uint64_t amountadded = ((lockamountsmaller * percentperblock) / 100000) * 10000; - amountpay += amountadded; + amountpay += lockiter->periods[i].amount; } } diff --git a/contracts/fio.token/src/fio.token.cpp b/contracts/fio.token/src/fio.token.cpp index 3412ca02..d0223f6c 100755 --- a/contracts/fio.token/src/fio.token.cpp +++ b/contracts/fio.token/src/fio.token.cpp @@ -451,7 +451,7 @@ namespace eosio { void token::trnsloctoks(const string &payee_public_key, const int32_t &can_vote, - const vector periods, + const vector periods, const int64_t &amount, const int64_t &max_fee, const name &actor, @@ -459,25 +459,25 @@ namespace eosio { fio_400_assert(((periods.size()) >= 1 && (periods.size() <= 365)), "unlock_periods", "Invalid unlock periods", "Invalid number of unlock periods", ErrorTransactionTooLarge); - double totp = 0.0; + uint64_t tota = 0; double tv = 0.0; int64_t longestperiod = 0; for(int i=0;i 0.0, "unlock_periods", "Invalid unlock periods", - "Invalid percentage value in unlock periods", ErrorInvalidUnlockPeriods); - tv = periods[i].percent - (double(int((periods[i].percent * 1000.0)+0.5)))/1000.0; - //tv = periods[i].percent - (double(int(periods[i].percent * 1000.0)))/1000.0; - fio_400_assert(tv == 0.0, "unlock_periods", "Invalid unlock periods", - "Invalid precision for percentage in unlock periods", ErrorInvalidUnlockPeriods); + fio_400_assert(periods[i].amount > 0, "unlock_periods", "Invalid unlock periods", + "Invalid amount value in unlock periods", ErrorInvalidUnlockPeriods); fio_400_assert(periods[i].duration > 0, "unlock_periods", "Invalid unlock periods", "Invalid duration value in unlock periods", ErrorInvalidUnlockPeriods); - totp += periods[i].percent; + tota += periods[i].amount; + if (i>1){ + fio_400_assert(periods[i].duration > periods[i-1].duration, "unlock_periods", "Invalid unlock periods", + "Invalid duration value in unlock periods, must be sorted", ErrorInvalidUnlockPeriods); + } if (periods[i].duration > longestperiod){ longestperiod = periods[i].duration; } } - fio_400_assert(totp == 100.0, "unlock_periods", "Invalid unlock periods", - "Invalid total percentage for unlock periods", ErrorInvalidUnlockPeriods); + fio_400_assert(tota == amount, "unlock_periods", "Invalid unlock periods", + "Invalid total amount for unlock periods", ErrorInvalidUnlockPeriods); fio_400_assert(((can_vote == 0)||(can_vote == 1)), "can_vote", to_string(can_vote), "Invalid can_vote value", ErrorInvalidValue); From 1f685688ad8b7a4f9659855d0084c608df004ad2 Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Fri, 4 Jun 2021 14:21:01 -0600 Subject: [PATCH 25/32] fix indexing error on order check fix indexing error on order check --- contracts/fio.system/src/fio.system.cpp | 2 +- contracts/fio.token/src/fio.token.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/fio.system/src/fio.system.cpp b/contracts/fio.system/src/fio.system.cpp index 4b2bc7f8..a788eaf3 100755 --- a/contracts/fio.system/src/fio.system.cpp +++ b/contracts/fio.system/src/fio.system.cpp @@ -259,7 +259,7 @@ namespace eosiosystem { fio_400_assert(periods[i].duration > 0, "unlock_periods", "Invalid unlock periods", "Invalid duration value in unlock periods", ErrorInvalidUnlockPeriods); tota += periods[i].amount; - if (i>1){ + if (i>0){ fio_400_assert(periods[i].duration > periods[i-1].duration, "unlock_periods", "Invalid unlock periods", "Invalid duration value in unlock periods, must be sorted", ErrorInvalidUnlockPeriods); } diff --git a/contracts/fio.token/src/fio.token.cpp b/contracts/fio.token/src/fio.token.cpp index d0223f6c..85c8783a 100755 --- a/contracts/fio.token/src/fio.token.cpp +++ b/contracts/fio.token/src/fio.token.cpp @@ -468,7 +468,7 @@ namespace eosio { fio_400_assert(periods[i].duration > 0, "unlock_periods", "Invalid unlock periods", "Invalid duration value in unlock periods", ErrorInvalidUnlockPeriods); tota += periods[i].amount; - if (i>1){ + if (i>0){ fio_400_assert(periods[i].duration > periods[i-1].duration, "unlock_periods", "Invalid unlock periods", "Invalid duration value in unlock periods, must be sorted", ErrorInvalidUnlockPeriods); } From 2571e51f35cd5988453cbf2afdf4e904ed9ea12e Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Mon, 7 Jun 2021 10:03:43 -0600 Subject: [PATCH 26/32] change table def fix devnet issue change table def fix devnet issue --- contracts/fio.staking/fio.staking.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contracts/fio.staking/fio.staking.hpp b/contracts/fio.staking/fio.staking.hpp index be8fff3d..4ad625fc 100644 --- a/contracts/fio.staking/fio.staking.hpp +++ b/contracts/fio.staking/fio.staking.hpp @@ -17,9 +17,8 @@ namespace fioio { using namespace eosio; - //staking info is a global state table used to track information relating to staking within the FIO protocol. - struct [[eosio::table]] global_staking_state { + struct [[eosio::table("staking"), eosio::contract("fio.staking")]] global_staking_state { global_staking_state(){} uint64_t staked_token_pool = 0; //total FIO tokens staked for all accounts, units sufs. uint64_t combined_token_pool = 1; //total fio tokens staked for all accounts plus fio rewards all accounts, units SUFs, From 042c7250093e40d34f7b61c37c24e2e3590e8b48 Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Sun, 13 Jun 2021 10:36:05 -0600 Subject: [PATCH 27/32] code brush up handle auto proxy code brush up handle auto proxy --- contracts/fio.common/fio.common.hpp | 19 ++++ contracts/fio.staking/fio.staking.cpp | 131 +++++++++++++++++++------- 2 files changed, 117 insertions(+), 33 deletions(-) diff --git a/contracts/fio.common/fio.common.hpp b/contracts/fio.common/fio.common.hpp index 8ea442db..70a78c4f 100644 --- a/contracts/fio.common/fio.common.hpp +++ b/contracts/fio.common/fio.common.hpp @@ -241,6 +241,25 @@ namespace fioio { typedef singleton<"bounties"_n, bounty> bounties_table; + //this will call update tpid in the tpid contract, + //add the info to the tpid table for this TPID and also set up the auto proxy if needed. + void set_auto_proxy(const string &tpid, const uint64_t &amount, const name &auth, const name &actor){ + fionames_table fionames(AddressContract, AddressContract.value); + uint128_t fioaddhash = string_to_uint128_hash(tpid.c_str()); + + auto namesbyname = fionames.get_index<"byname"_n>(); + auto fionamefound = namesbyname.find(fioaddhash); + + if (fionamefound != namesbyname.end()) { + action( + permission_level{auth, "active"_n}, + TPIDContract, + "updatetpid"_n, + std::make_tuple(tpid, actor, amount) + ).send(); + } + } + void process_rewards(const string &tpid, const uint64_t &amount, const name &auth, const name &actor) { action( diff --git a/contracts/fio.staking/fio.staking.cpp b/contracts/fio.staking/fio.staking.cpp index 58b9d4ae..b68463ce 100644 --- a/contracts/fio.staking/fio.staking.cpp +++ b/contracts/fio.staking/fio.staking.cpp @@ -19,13 +19,19 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { private: + //these holds global staking state for fio global_staking_singleton staking; global_staking_state gstaking; account_staking_table accountstaking; + //access to the voters table for voting info. eosiosystem::voters_table voters; + //access to fionames for address info fionames_table fionames; + //access to fio fees for computation of fees. fiofee_table fiofees; + //access to general locks to adapt general locks on unstake eosiosystem::general_locks_table_v2 generallocks; + //debug output flag bool debugout = false; public: @@ -74,27 +80,19 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { gstaking.daily_staking_rewards = 0; } - //incgstkmint increments the staking_rewards_reserves_minted + //this action performs staking of fio tokens [[eosio::action]] void stakefio(const string &fio_address, const int64_t &amount, const int64_t &max_fee, const string &tpid, const name &actor) { //signer not actor. require_auth(actor); - - //check if the actor has voted. - auto votersbyowner = voters.get_index<"byowner"_n>(); - auto voter = votersbyowner.find(actor.value); - fio_400_assert(voter != votersbyowner.end(), "actor", - actor.to_string(), "Account has not voted and has not proxied.",ErrorInvalidValue); - //if they are in the table check if they are is_auto_proxy, or if they have a proxy, or if they have producers not empty - fio_400_assert((((voter->proxy) || (voter->producers.size() > 0) || (voter->is_auto_proxy))), - "actor", actor.to_string(), "Account has not voted and has not proxied.",ErrorInvalidValue); - fio_400_assert(amount > 0, "amount", to_string(amount), "Invalid amount value",ErrorInvalidValue); - fio_400_assert(max_fee >= 0, "amount", to_string(max_fee), "Invalid fee value",ErrorInvalidValue); - fio_400_assert(validateTPIDFormat(tpid), "tpid", tpid,"TPID must be empty or valid FIO address",ErrorPubKeyValid); + if(debugout) { + print(" calling stakefio fio address ", fio_address); + } uint64_t bundleeligiblecountdown = 0; + //process the fio address specified FioAddress fa; getFioAddressStruct(fio_address, fa); @@ -117,13 +115,9 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { bundleeligiblecountdown = fioname_iter->bundleeligiblecountdown; } - //get the usable balance for the account - //this is account balance - genesis locked tokens - general locked balance. - // print("EDEDEDEDEDEDEDEDEDED calling from staking!!!!!!!!!"); - auto stakeablebalance = eosio::token::computeusablebalance(actor,false); - uint64_t paid_fee_amount = 0; + bool skipvotecheck = false; //begin, bundle eligible fee logic for staking const uint128_t endpoint_hash = string_to_uint128_hash(STAKE_FIO_TOKENS_ENDPOINT); @@ -148,6 +142,35 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { "decrcounter"_n, make_tuple(fio_address, 1) }.send(); + + if (debugout) { + print(" calling process auto proxy with ", tpid); + } + set_auto_proxy(tpid, 0,get_self(), actor); + + //when a tpid is used, if this is the first call for this account to use a tpid, + //then the auto proxy will be set in an inline action which executes outside of this + //execution stack. We check if the tpid is a proxy, and if it is then we know that + //the owner will be auto proxied in this transaction, but in an action outside of this one. + //so we set a local flag to skip the checks for the "has voted" requirement since we + //know the owner is auto proxied, this handles the edge condition if the staking is called + //very early by a new account integrated using tpid. + FioAddress fa1; + getFioAddressStruct(tpid, fa1); + const uint128_t nameHash = string_to_uint128_hash(fa1.fioaddress.c_str()); + auto namesbyname = fionames.get_index<"byname"_n>(); + auto fioname_iter = namesbyname.find(nameHash); + fio_400_assert(fioname_iter != namesbyname.end(), "tpid", fa.fioaddress, + "FIO Address not registered", ErrorFioNameAlreadyRegistered); + //now use the owner to find the voting record. + auto votersbyowner = voters.get_index<"byowner"_n>(); + const auto viter = votersbyowner.find(fioname_iter->owner_account); + if (viter != votersbyowner.end()) { + if (viter->is_proxy){ + skipvotecheck = true; + } + } + } else { paid_fee_amount = fee_iter->suf_amount; fio_400_assert(max_fee >= (int64_t)paid_fee_amount, "max_fee", to_string(max_fee), "Fee exceeds supplied maximum.", @@ -163,10 +186,30 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { ); } } + //End, bundle eligible fee logic for staking + + //if we are not auto proxying for the first time, check if the actor has voted. + if (!skipvotecheck) { + auto votersbyowner = voters.get_index<"byowner"_n>(); + auto voter = votersbyowner.find(actor.value); + fio_400_assert(voter != votersbyowner.end(), "actor", + actor.to_string(), "Account has not voted and has not proxied.",ErrorInvalidValue); + //if they are in the table check if they are is_auto_proxy, or if they have a proxy, or if they have producers not empty + fio_400_assert((((voter->proxy) || (voter->producers.size() > 0) || (voter->is_auto_proxy))), + "actor", actor.to_string(), "Account has not voted and has not proxied.", ErrorInvalidValue); + } + + + fio_400_assert(amount > 0, "amount", to_string(amount), "Invalid amount value",ErrorInvalidValue); + fio_400_assert(max_fee >= 0, "amount", to_string(max_fee), "Invalid fee value",ErrorInvalidValue); + fio_400_assert(validateTPIDFormat(tpid), "tpid", tpid,"TPID must be empty or valid FIO address",ErrorPubKeyValid); + + + //get the usable balance for the account + auto stakeablebalance = eosio::token::computeusablebalance(actor,false); fio_400_assert(stakeablebalance >= (paid_fee_amount + (uint64_t)amount), "max_fee", to_string(max_fee), "Insufficient balance.", ErrorMaxFeeExceeded); - //End, bundle eligible fee logic for staking //RAM bump if (STAKEFIOTOKENSRAM > 0) { @@ -182,12 +225,18 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { //compute rate of exchange and SRPs uint64_t rateofexchange = 1; if (gstaking.combined_token_pool >= COMBINEDTOKENPOOLMINIMUM) { - print("EDEDEDEDEDEDEDEDEDEDED global srp count ", gstaking.global_srp_count); - print("EDEDEDEDEDEDEDEDEDEDED combined_token_pool ", gstaking.combined_token_pool); + if (debugout) { + print(" global srp count ", gstaking.global_srp_count); + print(" combined_token_pool ", gstaking.combined_token_pool); + } rateofexchange = gstaking.combined_token_pool / gstaking.global_srp_count; - print("EDEDEDEDEDEDEDEDEDEDED rate of exchange set to ", rateofexchange); + if(debugout) { + print(" rate of exchange set to ", rateofexchange); + } if(rateofexchange < 1) { - print("EDEDEDEDEDEDEDEDEDEDED RATE OF EXCHANGE LESS THAN 1 ", rateofexchange); + if(debugout) { + print(" RATE OF EXCHANGE LESS THAN 1 ", rateofexchange); + } rateofexchange = 1; } } @@ -220,6 +269,9 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { }); } //end increment account staking info + + + const string response_string = string("{\"status\": \"OK\",\"fee_collected\":") + to_string(paid_fee_amount) + string("}"); @@ -230,6 +282,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { } + //this action performs the unstaking of fio tokens. [[eosio::action]] void unstakefio(const string &fio_address,const int64_t &amount, const int64_t &max_fee, const string &tpid, const name &actor) { @@ -275,8 +328,6 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { ErrorInvalidValue); //get the usable balance for the account - //this is account balance - genesis locked tokens - general locked balance. - // print("EDEDEDEDEDEDEDEDEDED calling from unstaking!!!!!!!!!"); auto stakeablebalance = eosio::token::computeusablebalance(actor,false); uint64_t paid_fee_amount = 0; @@ -340,27 +391,39 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { //round this to avoid issues with decimal representations uint64_t srpstoclaim = (uint64_t)(((double)astakeiter->total_srp * (double)( (double)amount / (double)astakeiter->total_staked_fio))+0.5); - //print("EDEEEDEDEDEDEDED srps to claim is ",to_string(srpstoclaim),"\n"); + if (debugout) { + print("srps to claim is ", to_string(srpstoclaim), "\n"); + } //compute rate of exchange uint64_t rateofexchange = 1; if (gstaking.combined_token_pool >= COMBINEDTOKENPOOLMINIMUM) { - print("EDEDEDEDEDEDEDEDEDEDED global srp count ", gstaking.global_srp_count); - print("EDEDEDEDEDEDEDEDEDEDED combined_token_pool ", gstaking.combined_token_pool); + if(debugout) { + print(" global srp count ", gstaking.global_srp_count); + print(" combined_token_pool ", gstaking.combined_token_pool); + } rateofexchange = gstaking.combined_token_pool / gstaking.global_srp_count; - print("EDEDEDEDEDEDEDEDEDEDED rate of exchange set to ", rateofexchange); + if (debugout) { + print(" rate of exchange set to ", rateofexchange); + } if(rateofexchange < 1) { - print("EDEDEDEDEDEDEDEDEDEDED RATE OF EXCHANGE LESS THAN 1 ", rateofexchange); + if(debugout) { + print(" RATE OF EXCHANGE LESS THAN 1 ", rateofexchange); + } rateofexchange = 1; } } eosio_assert((srpstoclaim * rateofexchange) >= amount, "unstakefio, invalid calc in totalrewardamount, must be that (srpstoclaim * rateofexchange) > amount. "); uint64_t totalrewardamount = ((srpstoclaim * rateofexchange) - amount); - print("EDEDEDEDEDEDEDEDEDEDED total reward amount is ", totalrewardamount); + if(debugout) { + print("total reward amount is ", totalrewardamount); + } uint64_t tenpercent = totalrewardamount / 10; //Staking Reward Amount is computed: ((SRPs to Claim * Rate of Exchnage) - Unstake amount) * 0.9 uint64_t stakingrewardamount = tenpercent * 9; - print("EDEDEDEDEDEDEDEDEDEDED staking reward amount is ", totalrewardamount); + if(debugout) { + print(" staking reward amount is ", totalrewardamount); + } // TPID Reward Amount is computed: ((SRPs to Claim * Rate of Exchnage) - Unstake amount) * 0.1 uint64_t tpidrewardamount = tenpercent; @@ -499,7 +562,9 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { //else make new lock. bool canvote = true; int64_t lockamount = (int64_t)(stakingrewardamount + amount); - print("EDEDEDEDEDEDEDEDED creating general lock for amount ", lockamount, "\n"); + if(debugout) { + print(" creating general lock for amount ", lockamount, "\n"); + } vector periods; eosiosystem::lockperiodv2 period; period.duration = 604800; From 84534525a156de7491c4d5e79b440e043866f4f1 Mon Sep 17 00:00:00 2001 From: Casey Gardiner <44983607+fiocasey@users.noreply.github.com> Date: Tue, 15 Jun 2021 15:41:32 -0600 Subject: [PATCH 28/32] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cf91d3d3..6943a44a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # fio.contracts -## Version : 2.3.5 +## Version : 2.4.0 Smart contracts that provide some of the basic functions of the FIO blockchain From 12b4d2bdf3ceaf9759a8f80054f713f1f2c77f51 Mon Sep 17 00:00:00 2001 From: Casey Gardiner <44983607+fiocasey@users.noreply.github.com> Date: Tue, 15 Jun 2021 15:42:13 -0600 Subject: [PATCH 29/32] Update CMakeLists.txt --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7addb486..b736ea26 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,9 +3,9 @@ cmake_minimum_required(VERSION 3.5) project(fio.contracts) set(VERSION_MAJOR 2) -set(VERSION_MINOR 3) -set(VERSION_PATCH 5) -#set(VERSION_SUFFIX rc3) +set(VERSION_MINOR 4) +set(VERSION_PATCH 0) +#set(VERSION_SUFFIX rc1) if (VERSION_SUFFIX) set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_SUFFIX}") From 119dd752f6684c2e9e169b34fe40058cc7185b34 Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Thu, 24 Jun 2021 12:15:42 -0600 Subject: [PATCH 30/32] fix bug in tpid auto proxy when no tpid specified fix bug when no tpid specified. --- contracts/fio.common/fio.accounts.hpp | 2 +- contracts/fio.staking/fio.staking.cpp | 56 ++++++++++--------- .../fio.token/include/fio.token/fio.token.hpp | 9 ++- 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/contracts/fio.common/fio.accounts.hpp b/contracts/fio.common/fio.accounts.hpp index 67c17f6c..c56579c1 100644 --- a/contracts/fio.common/fio.accounts.hpp +++ b/contracts/fio.common/fio.accounts.hpp @@ -34,7 +34,7 @@ namespace fioio { static const name AddressContract = name("fio.address"); static const name TPIDContract = name("fio.tpid"); static const name TokenContract = name("fio.token"); - static const name FOUNDATIONACCOUNT = name("htjonrkf1lgs"); + static const name FOUNDATIONACCOUNT = name("tw4tjkmo4eyd"); static const name TREASURYACCOUNT = name("fio.treasury"); static const name STAKINGACCOUNT = name("fio.staking"); static const name FIOSYSTEMACCOUNT= name("fio.system"); diff --git a/contracts/fio.staking/fio.staking.cpp b/contracts/fio.staking/fio.staking.cpp index b68463ce..501aaab0 100644 --- a/contracts/fio.staking/fio.staking.cpp +++ b/contracts/fio.staking/fio.staking.cpp @@ -103,6 +103,7 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { const uint128_t nameHash = string_to_uint128_hash(fa.fioaddress.c_str()); auto namesbyname = fionames.get_index<"byname"_n>(); auto fioname_iter = namesbyname.find(nameHash); + fio_400_assert(fioname_iter != namesbyname.end(), "fio_address", fa.fioaddress, "FIO Address not registered", ErrorFioNameAlreadyRegistered); @@ -143,31 +144,36 @@ class [[eosio::contract("Staking")]] Staking: public eosio::contract { make_tuple(fio_address, 1) }.send(); - if (debugout) { - print(" calling process auto proxy with ", tpid); - } - set_auto_proxy(tpid, 0,get_self(), actor); - - //when a tpid is used, if this is the first call for this account to use a tpid, - //then the auto proxy will be set in an inline action which executes outside of this - //execution stack. We check if the tpid is a proxy, and if it is then we know that - //the owner will be auto proxied in this transaction, but in an action outside of this one. - //so we set a local flag to skip the checks for the "has voted" requirement since we - //know the owner is auto proxied, this handles the edge condition if the staking is called - //very early by a new account integrated using tpid. - FioAddress fa1; - getFioAddressStruct(tpid, fa1); - const uint128_t nameHash = string_to_uint128_hash(fa1.fioaddress.c_str()); - auto namesbyname = fionames.get_index<"byname"_n>(); - auto fioname_iter = namesbyname.find(nameHash); - fio_400_assert(fioname_iter != namesbyname.end(), "tpid", fa.fioaddress, - "FIO Address not registered", ErrorFioNameAlreadyRegistered); - //now use the owner to find the voting record. - auto votersbyowner = voters.get_index<"byowner"_n>(); - const auto viter = votersbyowner.find(fioname_iter->owner_account); - if (viter != votersbyowner.end()) { - if (viter->is_proxy){ - skipvotecheck = true; + if (!tpid.empty()) { + if (debugout) { + print(" calling process auto proxy with ", tpid); + } + set_auto_proxy(tpid, 0,get_self(), actor); + + //when a tpid is used, if this is the first call for this account to use a tpid, + //then the auto proxy will be set in an inline action which executes outside of this + //execution stack. We check if the tpid is a proxy, and if it is then we know that + //the owner will be auto proxied in this transaction, but in an action outside of this one. + //so we set a local flag to skip the checks for the "has voted" requirement since we + //know the owner is auto proxied, this handles the edge condition if the staking is called + //very early by a new account integrated using tpid. + + + FioAddress fa1; + getFioAddressStruct(tpid, fa1); + + const uint128_t nameHash = string_to_uint128_hash(fa1.fioaddress.c_str()); + auto namesbyname = fionames.get_index<"byname"_n>(); + auto fioname_iter = namesbyname.find(nameHash); + fio_400_assert(fioname_iter != namesbyname.end(), "tpid", fa1.fioaddress, + "FIO Address not registered", ErrorFioNameAlreadyRegistered); + //now use the owner to find the voting record. + auto votersbyowner = voters.get_index<"byowner"_n>(); + const auto viter = votersbyowner.find(fioname_iter->owner_account); + if (viter != votersbyowner.end()) { + if (viter->is_proxy) { + skipvotecheck = true; + } } } diff --git a/contracts/fio.token/include/fio.token/fio.token.hpp b/contracts/fio.token/include/fio.token/fio.token.hpp index 674bcbe7..ba01d7d3 100755 --- a/contracts/fio.token/include/fio.token/fio.token.hpp +++ b/contracts/fio.token/include/fio.token/fio.token.hpp @@ -194,11 +194,12 @@ namespace eosio { if (lockiter->unlocked_period_count < 6) { //to shorten the vesting schedule adapt these variables. // TESTING ONLY!!! comment out genesis locking periods..DO NOT DELIVER THIS - /* - uint32_t daysSinceGrant = (int) ((present_time - lockiter->timestamp) / SECONDSPERDAY); + /* uint32_t daysSinceGrant = (int) ((present_time - lockiter->timestamp) / SECONDSPERDAY); uint32_t firstPayPeriod = 90; uint32_t payoutTimePeriod = 180; - */ + */ + + //TEST LOCKED TOKENS // TESTING ONLY!!! shorten genesis locking periods..DO NOT DELIVER THIS @@ -206,6 +207,8 @@ namespace eosio { uint32_t firstPayPeriod = 2; uint32_t payoutTimePeriod = 2; + + bool ninetyDaysSinceGrant = daysSinceGrant >= firstPayPeriod; uint64_t payoutsDue = 0; From 462769e558762aa1920abdea0fa9ac7ce775123f Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Fri, 25 Jun 2021 09:35:56 -0600 Subject: [PATCH 31/32] add return status for use with typescript sdk add return status for use with typescript sdk --- contracts/fio.system/src/fio.system.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contracts/fio.system/src/fio.system.cpp b/contracts/fio.system/src/fio.system.cpp index a788eaf3..451368cb 100755 --- a/contracts/fio.system/src/fio.system.cpp +++ b/contracts/fio.system/src/fio.system.cpp @@ -216,6 +216,9 @@ namespace eosiosystem { a.remaining_locked_amount = amount; a.timestamp = now(); }); + //return status added for staking, to permit unit testing using typescript sdk. + const string response_string = string("{\"status\": \"OK\"}"); + send_response(response_string.c_str()); } void eosiosystem::system_contract::addgenlocked(const name &owner, const vector &periods, const bool &canvote, From 5e7c4a124e8b101cb28d36dcc036a9a84c512a85 Mon Sep 17 00:00:00 2001 From: Ed Rotthoff Date: Fri, 25 Jun 2021 11:16:06 -0600 Subject: [PATCH 32/32] set to prduction settings for genesis locking set to production settings for genesis locking --- .../fio.token/include/fio.token/fio.token.hpp | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/contracts/fio.token/include/fio.token/fio.token.hpp b/contracts/fio.token/include/fio.token/fio.token.hpp index ba01d7d3..aab77e87 100755 --- a/contracts/fio.token/include/fio.token/fio.token.hpp +++ b/contracts/fio.token/include/fio.token/fio.token.hpp @@ -194,21 +194,10 @@ namespace eosio { if (lockiter->unlocked_period_count < 6) { //to shorten the vesting schedule adapt these variables. // TESTING ONLY!!! comment out genesis locking periods..DO NOT DELIVER THIS - /* uint32_t daysSinceGrant = (int) ((present_time - lockiter->timestamp) / SECONDSPERDAY); + uint32_t daysSinceGrant = (int) ((present_time - lockiter->timestamp) / SECONDSPERDAY); uint32_t firstPayPeriod = 90; uint32_t payoutTimePeriod = 180; - */ - - - - //TEST LOCKED TOKENS - // TESTING ONLY!!! shorten genesis locking periods..DO NOT DELIVER THIS - uint32_t daysSinceGrant = (int)((present_time - lockiter->timestamp) / 60); - uint32_t firstPayPeriod = 2; - uint32_t payoutTimePeriod = 2; - - - + bool ninetyDaysSinceGrant = daysSinceGrant >= firstPayPeriod; uint64_t payoutsDue = 0;