diff --git a/contracts/CMakeLists.txt b/contracts/CMakeLists.txt index bfd6c83727e2ffce1ee1ff2f1cd1e181d450699b..ec6ae03267d52fe8fa09ee2d77fc57d4dbbd0707 100644 --- a/contracts/CMakeLists.txt +++ b/contracts/CMakeLists.txt @@ -1,3 +1,4 @@ +add_subdirectory(eosio.system) add_subdirectory(asserter) add_subdirectory(currency) add_subdirectory(exchange) diff --git a/contracts/eosio.system/CMakeLists.txt b/contracts/eosio.system/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..22ecb1546ce5209bafd39449bf9096e3ce99f6ef --- /dev/null +++ b/contracts/eosio.system/CMakeLists.txt @@ -0,0 +1,3 @@ +file(GLOB ABI_FILES "*.abi") +configure_file("${ABI_FILES}" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) +add_wast_target(eosio.system "${CMAKE_SOURCE_DIR}/contracts" ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/contracts/eosio.system/README.md b/contracts/eosio.system/README.md new file mode 100644 index 0000000000000000000000000000000000000000..a954337f886696d1000b770bd65375910cbaab80 --- /dev/null +++ b/contracts/eosio.system/README.md @@ -0,0 +1,84 @@ +eosio.system +---------- + +This contract enables users to stake tokens, and then configure and vote on producers and worker proposals. + +Users can also proxy their voting influence to other users. + +The state of this contract is read to determine the 21 active block producers. + +Actions: +The naming convention is codeaccount::actionname followed by a list of paramters. + +Indicates that a particular account wishes to become a producer +## eosio.system::cfgproducer account config + - **account** the producer account to update + - updates the configuration settings for a particular producer, these + + Storage changes are billed to 'account' + +## eosio.system::okproducer account producer vote + - **account** the account which is doing the voting + - **producer** the producer which is being voted for (or unvoted for) + - **vote** true if the producer should be voted for, false if not + + Each account has a maximum number of votes it can maintain. Storage changes will be billed to 'account' + +## eosio.system::setproxy account proxy + - **account** the account which is updating it's proxy + - **proxy** the account which will have the power to vote account's stake + + All current votes are removed and a new proxy link is created. The votes for every producer the proxy + has voted for are updated immediately. + + Storage changes will be billed to 'account' + +## eosio.system::unstake account quantity + - **account** - the account which is requsting their balance be unstaked + - **quantity** - the quantity which will be unstaked, unstaked tokens lose voting influence immediately + + - in order to unstake tokens, an account must request them. The user will receive them over + time via weekly withdraws. The length of time will be configured by the median time as set by + the active producers. + + - If this is called while in the process of unstaking, the currently pending unstake is canceled as if + quantity were 0, then it is applied as if a new unstake request was made. + + - all producers this 'from' has voted for will have their votes updated immediately. + + - bandwidth and storage for the deferred transaction will be billed to 'from' + +## eosio.system::withdraw account + - this action can only be triggered by eosio.system via a deferred transaction generated by unstake + - this will generate an inline eosio.token::transfer call from=eosio.system to=account and amount equal to the next withdraw increment + - this will generate another deferred withdraw to continue the process if there are still withdraws to be made + + +## eosio.system::transfer from to amount memo + - decrements balance of from if amount <= balance + - increments balance of to by amount + - memo is ignored + +## eosio.system::stakevote account amount + - the primary currency of eosio is controlled by the token contract which enables users to transfer + balances from one user to another. The receiver is notified on incoming balances and the vote contract + will stake the tokens on receipt. + + - all producers this 'from' has voted for will have their votes updated immediately. + + +## eosio.system::onblock account blocktime blocknum + - this special action is triggered when a block is applied by the given producer and cannot be generated from + any other source. It is used to pay producers and calculate missed blocks of other producers. + + - producer pay is deposited into the prodcer's stake balance and can be withdrawn over time. + + - if blocknum is the start of a new round this may update the active producer config from the producer votes. + +## eosio.system::freeze producer accounts true|false + - requires permission of the @producers account + - if an account is frozen, all authorizations of that account are rejected and the code for that account will not be run + +## eosio.system::paystandby producer + - every block some amount of tokens is paid + - at most once per day a producer may claim a percentage of the standby pay equal to their totalvotes / allvotes diff --git a/contracts/eosio.system/eosio.system.abi b/contracts/eosio.system/eosio.system.abi new file mode 100644 index 0000000000000000000000000000000000000000..c8d8e4b16e908bcede68ba02f90bd7d86d7ed391 --- /dev/null +++ b/contracts/eosio.system/eosio.system.abi @@ -0,0 +1,37 @@ +{ + "types": [{ + "new_type_name": "account_name", + "type": "name" + } + ], + "structs": [{ + "name": "transfer", + "base": "", + "fields": [ + {"name":"from", "type":"account_name"}, + {"name":"to", "type":"account_name"}, + {"name":"quantity", "type":"uint64"} + ] + },{ + "name": "account", + "base": "", + "fields": [ + {"name":"key", "type":"name"}, + {"name":"balance", "type":"uint64"} + ] + } + ], + "actions": [{ + "name": "transfer", + "type": "transfer" + } + ], + "tables": [{ + "name": "account", + "type": "account", + "index_type": "i64", + "key_names" : ["key"], + "key_types" : ["name"] + } + ] +} \ No newline at end of file diff --git a/contracts/eosio.system/eosio.system.cpp b/contracts/eosio.system/eosio.system.cpp new file mode 100644 index 0000000000000000000000000000000000000000..558495332ff44542ca5dbfd06260aa95284c50b0 --- /dev/null +++ b/contracts/eosio.system/eosio.system.cpp @@ -0,0 +1,52 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ + +#include + +namespace eosiosystem { + using namespace eosio; + + /// When storing accounts, check for empty balance and remove account + void store_account( account_name account_to_store, const account& a ) { + /// value, scope + accounts::store( a, account_to_store ); + } + + void on( const eosiosystem::transfer& transfer_msg ) { + require_recipient( transfer_msg.to, transfer_msg.from ); + require_auth( transfer_msg.from ); + + auto from = get_account( transfer_msg.from ); + auto to = get_account( transfer_msg.to ); + + from.balance -= transfer_msg.quantity; /// token subtraction has underflow assertion + to.balance += transfer_msg.quantity; /// token addition has overflow assertion + + store_account( transfer_msg.from, from ); + store_account( transfer_msg.to, to ); + } + + void init() { + // TODO verify that + //store_account( system_name, account( native_tokens(1000ll*1000ll*1000ll) ) ); + } + +} // namespace eosiosystem + +using namespace eosiosystem; + +extern "C" { + + /// The apply method implements the dispatch of events to this contract + void apply( uint64_t code, uint64_t action ) { + if( code == system_code ) { + if( action == N(init) ) { + init(); + } else if( action == N(transfer) ) { + on( current_action< eosiosystem::transfer >() ); + } + } + } +} diff --git a/contracts/eosio.system/eosio.system.hpp b/contracts/eosio.system/eosio.system.hpp new file mode 100644 index 0000000000000000000000000000000000000000..baf165337930ea1812abca828df9b2d502a99be5 --- /dev/null +++ b/contracts/eosio.system/eosio.system.hpp @@ -0,0 +1,116 @@ +/** + * @file + * @copyright defined in eos/LICENSE.txt + */ + +#include +#include +#include + +namespace eosiosystem { + + /** + * @defgroup eosio.system EOSIO System Contract + * @brief Defines the wasm components of the system contract + * + * @{ + */ + + /** + * We create the native EOSIO token type + */ + typedef eosio::token native_tokens; + const account_name system_code = N(eosio.system); + const table_name account_table = N(account); + + /** + * transfer requires that the sender and receiver be the first two + * accounts notified and that the sender has provided authorization. + * @abi action + */ + struct transfer { + /** + * account to transfer from + */ + account_name from; + /** + * account to transfer to + */ + account_name to; + /** + * quantity to transfer + */ + native_tokens quantity; + }; + + + + /** + * @brief row in account table stored within each scope + * @abi table + */ + struct account { + /** + Constructor with default zero quantity (balance). + */ + account( native_tokens b = native_tokens() ):balance(b){} + + /** + * The key is constant because there is only one record per scope/currency/accounts + */ + const uint64_t key = N(account); + + /** + * Balance number of tokens in account + **/ + native_tokens balance; + native_tokens vote_stake; + native_tokens proxied_vote_stake; + uint64_t last_vote_weight = 0; + //time_point last_stake_withdraw; + account_name proxy; + + + /** + Method to check if accoutn is empty. + @return true if account balance is zero. + **/ + bool is_empty()const { return balance.quantity == 0; } + }; + + struct producer { + account_name key; /// producer name + uint64_t votes; /// total votes received by producer + /// producer config... + }; + + struct producer_vote { + account_name voter; + account_name producer; + uint64_t voteweight = 0; + }; + + /** + Defines the database table for account information + **/ + using accounts = eosio::table; + + /** + * accounts information for owner is stored: + * + * owner/TOKEN_NAME/account/account -> account + * + * This API is made available for 3rd parties wanting read access to + * the users balance. If the account doesn't exist a default constructed + * account will be returned. + * @param owner The account owner + * @return account instance + */ + inline account get_account( account_name owner ) { + account owned_account; + /// scope, record + accounts::get( owned_account, owner ); + return owned_account; + } + +} /// @} /// currencyapi diff --git a/contracts/eoslib/token.hpp b/contracts/eoslib/token.hpp index 642394c83000128e9f74dbb77ab657e1b948dec3..ede0fbc91f352e411e7c13b7b5e197b3b42a2586 100644 --- a/contracts/eoslib/token.hpp +++ b/contracts/eoslib/token.hpp @@ -56,13 +56,13 @@ namespace eosio { * * @{ */ - template + template struct token { /** * Type of the currency (e.g. eos) represented as an unsigned 64 bit integer * @brief Type of the currency */ - static const uint64_t currency_type = currency; + static const uint64_t currency_type = Currency; /** * Default constructor @@ -289,7 +289,6 @@ namespace eosio { * @return quote token */ friend QuoteToken operator / ( BaseToken b, const price& q ) { - eosio::print( "operator/ ", uint128(b.quantity), " * ", uint128( precision ), " / ", q.base_per_quote, "\n" ); return QuoteToken( uint64_t((uint128(b.quantity) * uint128(precision) / q.base_per_quote)) ); } @@ -301,8 +300,6 @@ namespace eosio { * @return base token */ friend BaseToken operator * ( const QuoteToken& b, const price& q ) { - eosio::print( "b: ", b, " \n" ); - eosio::print( "operator* ", uint128(b.quantity), " * ", uint128( q.base_per_quote ), " / ", precision, "\n" ); //return QuoteToken( uint64_t( mult_div_i128( b.quantity, q.base_per_quote, precision ) ) ); return BaseToken( uint64_t((b.quantity * q.base_per_quote) / precision) ); }