diff --git a/genesis.json b/genesis.json index 511cd03e..b3825d0a 100644 --- a/genesis.json +++ b/genesis.json @@ -201,6 +201,16 @@ "distribution_base_fee": 0, "distribution_fee_per_holder": 0 } + ],[ + 47,{ + "fee": 100000 + } + ],[ + 48,{ + "fee": 51000000 + } + ],[ + 49,{} ] ], "scale": 10 diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 5a94e827..77a3e9fd 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -327,7 +327,16 @@ void database::init_genesis(const genesis_state_type& genesis_state) a.network_fee_percentage = 0; a.lifetime_referrer_fee_percentage = GRAPHENE_100_PERCENT; }).get_id() == GRAPHENE_PROXY_TO_SELF_ACCOUNT); - + FC_ASSERT(create([this](account_object& a) { + a.name = "test-dividend-distribution"; + a.statistics = create([&](account_statistics_object& s){s.owner = a.id;}).id; + a.owner.weight_threshold = 1; + a.active.weight_threshold = 1; + a.registrar = a.lifetime_referrer = a.referrer = GRAPHENE_PROXY_TO_SELF_ACCOUNT; + a.membership_expiration_date = time_point_sec::maximum(); + a.network_fee_percentage = 0; + a.lifetime_referrer_fee_percentage = GRAPHENE_100_PERCENT; + }).get_id() == TOURNAMENT_RAKE_FEE_ACCOUNT_ID); // Create more special accounts while( true ) { @@ -353,6 +362,22 @@ void database::init_genesis(const genesis_state_type& genesis_state) create([&](asset_dynamic_data_object& a) { a.current_supply = GRAPHENE_MAX_SHARE_SUPPLY; }); + + const asset_dividend_data_object& div_asset = + create([&](asset_dividend_data_object& a) { + a.options.minimum_distribution_interval = 3*24*60*60; + a.options.minimum_fee_percentage = 10*GRAPHENE_1_PERCENT; + a.options.next_payout_time = genesis_state.initial_timestamp + fc::hours(1); + a.options.payout_interval = 7*24*60*60; + a.dividend_distribution_account = TOURNAMENT_RAKE_FEE_ACCOUNT_ID; + }); + const asset_bitasset_data_object& bit_asset = + create([&](asset_bitasset_data_object& a) { + a.current_feed.maintenance_collateral_ratio = 1750; + a.current_feed.maximum_short_squeeze_ratio = 1500; + a.current_feed_publication_time = genesis_state.initial_timestamp + fc::hours(1); + }); + const asset_object& core_asset = create( [&]( asset_object& a ) { a.symbol = GRAPHENE_SYMBOL; @@ -360,15 +385,58 @@ void database::init_genesis(const genesis_state_type& genesis_state) a.precision = GRAPHENE_BLOCKCHAIN_PRECISION_DIGITS; a.options.flags = 0; a.options.issuer_permissions = 0; - a.issuer = GRAPHENE_NULL_ACCOUNT; + a.issuer = GRAPHENE_COMMITTEE_ACCOUNT; a.options.core_exchange_rate.base.amount = 1; a.options.core_exchange_rate.base.asset_id = asset_id_type(0); a.options.core_exchange_rate.quote.amount = 1; a.options.core_exchange_rate.quote.asset_id = asset_id_type(0); a.dynamic_asset_data_id = dyn_asset.id; - }); + a.dividend_data_id = div_asset.id; + a.bitasset_data_id = bit_asset.id; +}); assert( asset_id_type(core_asset.id) == asset().asset_id ); assert( get_balance(account_id_type(), asset_id_type()) == asset(dyn_asset.current_supply) ); + +#ifdef _DEFAULT_DIVIDEND_ASSET + // Create default dividend asset + const asset_dynamic_data_object& dyn_asset1 = + create([&](asset_dynamic_data_object& a) { + a.current_supply = GRAPHENE_MAX_SHARE_SUPPLY; + }); + const asset_dividend_data_object& div_asset1 = + create([&](asset_dividend_data_object& a) { + a.options.minimum_distribution_interval = 3*24*60*60; + a.options.minimum_fee_percentage = 10*GRAPHENE_1_PERCENT; + a.options.next_payout_time = genesis_state.initial_timestamp + fc::hours(1); + a.options.payout_interval = 7*24*60*60; + a.dividend_distribution_account = TOURNAMENT_RAKE_FEE_ACCOUNT_ID; + }); + const asset_bitasset_data_object& bit_asset1 = + create([&](asset_bitasset_data_object& a) { + a.current_feed.maintenance_collateral_ratio = 1750; + a.current_feed.maximum_short_squeeze_ratio = 1500; + a.current_feed_publication_time = genesis_state.initial_timestamp + fc::hours(1); + }); + + const asset_object& default_asset = + create( [&]( asset_object& a ) { + a.symbol = "DEFAULT"; + a.options.max_market_fee = + a.options.max_supply = genesis_state.max_core_supply; + a.precision = GRAPHENE_BLOCKCHAIN_PRECISION_DIGITS; + a.options.flags = 0; + a.options.issuer_permissions = 79; + a.issuer = TOURNAMENT_RAKE_FEE_ACCOUNT_ID; + a.options.core_exchange_rate.base.amount = 1; + a.options.core_exchange_rate.base.asset_id = asset_id_type(0); + a.options.core_exchange_rate.quote.amount = 1; + a.options.core_exchange_rate.quote.asset_id = asset_id_type(1); + a.dynamic_asset_data_id = dyn_asset1.id; + a.dividend_data_id = div_asset1.id; + a.bitasset_data_id = bit_asset1.id; + }); + assert( default_asset.id == asset_id_type(1) ); +#endif // Create more special assets while( true ) { @@ -634,6 +702,12 @@ void database::init_genesis(const genesis_state_type& genesis_state) { total_supplies[ asset_id_type(0) ] = GRAPHENE_MAX_SHARE_SUPPLY; } +#ifdef _DEFAULT_DIVIDEND_ASSET + total_debts[ asset_id_type(1) ] = + total_supplies[ asset_id_type(1) ] = 0; +#endif + // it is workaround, should be clarified + total_debts[ asset_id_type() ] = total_supplies[ asset_id_type() ]; const auto& idx = get_index_type().indices().get(); auto it = idx.begin(); @@ -653,6 +727,7 @@ void database::init_genesis(const genesis_state_type& genesis_state) elog( "Genesis for asset ${aname} is not balanced\n" " Debt is ${debt}\n" " Supply is ${supply}\n", + ("aname", debt_itr->first) ("debt", debt_itr->second) ("supply", supply_itr->second) ); diff --git a/libraries/chain/include/graphene/chain/asset_object.hpp b/libraries/chain/include/graphene/chain/asset_object.hpp index 70f8443d..3e2fd24d 100644 --- a/libraries/chain/include/graphene/chain/asset_object.hpp +++ b/libraries/chain/include/graphene/chain/asset_object.hpp @@ -352,6 +352,8 @@ FC_REFLECT_DERIVED( graphene::chain::asset_dividend_data_object, (graphene::db:: (options) (last_scheduled_payout_time) (last_payout_time ) + (last_scheduled_distribution_time) + (last_distribution_time) (dividend_distribution_account) ) @@ -369,4 +371,5 @@ FC_REFLECT_DERIVED( graphene::chain::asset_object, (graphene::db::object), (dynamic_asset_data_id) (bitasset_data_id) (buyback_account) + (dividend_data_id) ) diff --git a/libraries/chain/include/graphene/chain/config.hpp b/libraries/chain/include/graphene/chain/config.hpp index 089f9c3b..0c9f4a88 100644 --- a/libraries/chain/include/graphene/chain/config.hpp +++ b/libraries/chain/include/graphene/chain/config.hpp @@ -168,6 +168,8 @@ #define GRAPHENE_TEMP_ACCOUNT (graphene::chain::account_id_type(4)) /// Represents the canonical account for specifying you will vote directly (as opposed to a proxy) #define GRAPHENE_PROXY_TO_SELF_ACCOUNT (graphene::chain::account_id_type(5)) +/// +#define TOURNAMENT_RAKE_FEE_ACCOUNT_ID (graphene::chain::account_id_type(6)) /// Sentinel value used in the scheduler. #define GRAPHENE_NULL_WITNESS (graphene::chain::witness_id_type(0)) ///@} diff --git a/libraries/chain/include/graphene/chain/protocol/asset_ops.hpp b/libraries/chain/include/graphene/chain/protocol/asset_ops.hpp index ca82526c..62c9c9a2 100644 --- a/libraries/chain/include/graphene/chain/protocol/asset_ops.hpp +++ b/libraries/chain/include/graphene/chain/protocol/asset_ops.hpp @@ -595,6 +595,8 @@ FC_REFLECT( graphene::chain::asset_options, FC_REFLECT( graphene::chain::dividend_asset_options, (next_payout_time) (payout_interval) + (minimum_fee_percentage) + (minimum_distribution_interval) (extensions) ) diff --git a/libraries/chain/tournament_object.cpp b/libraries/chain/tournament_object.cpp index 8b3d6f07..ef4252fb 100644 --- a/libraries/chain/tournament_object.cpp +++ b/libraries/chain/tournament_object.cpp @@ -268,13 +268,12 @@ namespace graphene { namespace chain { assert(event.match.match_winners.size() == 1); const account_id_type& winner = *event.match.match_winners.begin(); uint16_t rake_fee_percentage = event.db.get_global_properties().parameters.rake_fee_percentage; - share_type rake_amount = (fc::uint128_t(fsm.tournament_obj->prize_pool.value) * rake_fee_percentage / GRAPHENE_1_PERCENT).to_uint64(); + share_type rake_amount = (fc::uint128_t(fsm.tournament_obj->prize_pool.value) * rake_fee_percentage / GRAPHENE_1_PERCENT / 100).to_uint64(); event.db.adjust_balance(account_id_type(TOURNAMENT_RAKE_FEE_ACCOUNT_ID), asset(rake_amount, fsm.tournament_obj->options.buy_in.asset_id)); event.db.adjust_balance(winner, asset(fsm.tournament_obj->prize_pool - rake_amount, fsm.tournament_obj->options.buy_in.asset_id)); - tournament_object& tournament = *fsm.tournament_obj; - tournament.end_time = event.db.head_block_time(); + fsm.tournament_obj->end_time = event.db.head_block_time(); } }; diff --git a/libraries/plugins/generate_genesis/generate_genesis.cpp b/libraries/plugins/generate_genesis/generate_genesis.cpp index 2348aeb2..e11fc6b0 100644 --- a/libraries/plugins/generate_genesis/generate_genesis.cpp +++ b/libraries/plugins/generate_genesis/generate_genesis.cpp @@ -32,7 +32,10 @@ #include #include +#include + #include +#include using namespace graphene::generate_genesis_plugin; using std::string; @@ -41,187 +44,246 @@ using std::vector; namespace bpo = boost::program_options; void generate_genesis_plugin::plugin_set_program_options( - boost::program_options::options_description& command_line_options, - boost::program_options::options_description& config_file_options) + boost::program_options::options_description& command_line_options, + boost::program_options::options_description& config_file_options) { - command_line_options.add_options() - ("output-genesis-file,o", bpo::value()->default_value("genesis.json"), "Genesis file to create") - ("snapshot-block-number", bpo::value()->default_value(0), "Block number at which to snapshot balances") - ; - config_file_options.add(command_line_options); + command_line_options.add_options() + ("output-genesis-file,o", bpo::value()->default_value("genesis.json"), "Genesis file to create") + ("output-csvlog-file,o", bpo::value()->default_value("log.csv"), "CSV log file to create") + ("snapshot-block-number", bpo::value()->default_value(0), "Block number at which to snapshot balances") + ; + config_file_options.add(command_line_options); } std::string generate_genesis_plugin::plugin_name()const { - return "generate_genesis"; + return "generate_genesis"; } void generate_genesis_plugin::plugin_initialize(const boost::program_options::variables_map& options) { try { - ilog("generate genesis plugin: plugin_initialize() begin"); - _options = &options; + ilog("generate genesis plugin: plugin_initialize() begin"); + _options = &options; - _genesis_filename = options["output-genesis-file"].as(); - _block_to_snapshot = options["snapshot-block-number"].as(); - database().applied_block.connect([this](const graphene::chain::signed_block& b){ block_applied(b); }); - ilog("generate genesis plugin: plugin_initialize() end"); -} FC_LOG_AND_RETHROW() } + _genesis_filename = options["output-genesis-file"].as(); + _csvlog_filename = options["output-csvlog-file"].as(); + _block_to_snapshot = options["snapshot-block-number"].as(); + database().applied_block.connect([this](const graphene::chain::signed_block& b){ block_applied(b); }); + ilog("generate genesis plugin: plugin_initialize() end"); + } FC_LOG_AND_RETHROW() } void generate_genesis_plugin::plugin_startup() { try { - ilog("generate genesis plugin: plugin_startup() begin"); - chain::database& d = database(); - if (d.head_block_num() == _block_to_snapshot) - { - ilog("generate genesis plugin: already at snapshot block"); - generate_snapshot(); - } - else if (d.head_block_num() > _block_to_snapshot) - elog("generate genesis plugin: already passed snapshot block, you must reindex to return to the snapshot state"); - else - elog("generate genesis plugin: waiting for block ${snapshot_block} to generate snapshot, current head is ${head}", - ("snapshot_block", _block_to_snapshot)("head", d.head_block_num())); + ilog("generate genesis plugin: plugin_startup() begin"); + chain::database& d = database(); + if (d.head_block_num() == _block_to_snapshot) + { + ilog("generate genesis plugin: already at snapshot block"); + generate_snapshot(); + } + else if (d.head_block_num() > _block_to_snapshot) + elog("generate genesis plugin: already passed snapshot block, you must reindex to return to the snapshot state"); + else + elog("generate genesis plugin: waiting for block ${snapshot_block} to generate snapshot, current head is ${head}", + ("snapshot_block", _block_to_snapshot)("head", d.head_block_num())); - ilog("generate genesis plugin: plugin_startup() end"); -} FC_CAPTURE_AND_RETHROW() } + ilog("generate genesis plugin: plugin_startup() end"); + } FC_CAPTURE_AND_RETHROW() } void generate_genesis_plugin::block_applied(const graphene::chain::signed_block& b) { - if (b.block_num() == _block_to_snapshot) - { - ilog("generate genesis plugin: snapshot block has arrived"); - generate_snapshot(); - } + if (b.block_num() == _block_to_snapshot) + { + ilog("generate genesis plugin: snapshot block has arrived"); + generate_snapshot(); + } } std::string modify_account_name(const std::string& name) { - return std::string("bts-") + name; + return std::string("bts-") + name; } bool is_special_account(const graphene::chain::account_id_type& account_id) { - return account_id.instance < 100; + return account_id.instance < 100; } bool is_exchange(const std::string& account_name) { - return account_name == "poloniexcoldstorage" || - account_name == "btc38-public-for-bts-cold" || - account_name == "poloniexwallet" || - account_name == "btercom" || - account_name == "yunbi-cold-wallet" || - account_name == "btc38-btsx-octo-72722" || - account_name == "bittrex-deposit" || - account_name == "btc38btsxwithdrawal"; + return account_name == "poloniexcoldstorage" || + account_name == "btc38-public-for-bts-cold" || + account_name == "poloniexwallet" || + account_name == "btercom" || + account_name == "yunbi-cold-wallet" || + account_name == "btc38-btsx-octo-72722" || + account_name == "bittrex-deposit" || + account_name == "btc38btsxwithdrawal"; } void generate_genesis_plugin::generate_snapshot() { - ilog("generate genesis plugin: generating snapshot now"); - graphene::chain::genesis_state_type new_genesis_state; - chain::database& d = database(); + ilog("generate genesis plugin: generating snapshot now"); + graphene::chain::genesis_state_type new_genesis_state; + chain::database& d = database(); + // we'll distribute 5% of 1,000,000 tokens, so: + graphene::chain::share_type total_amount_to_distribute = 50000 * GRAPHENE_BLOCKCHAIN_PRECISION; - // we'll distribute 5% of 1,000,000 tokens, so: - graphene::chain::share_type total_amount_to_distribute = 50000 * GRAPHENE_BLOCKCHAIN_PRECISION; + // we need collection of mutable objects + std::vector db_balances; + // copy const objects to our collection + auto& balance_index = d.get_index_type().indices().get(); + for (auto balance_iter = balance_index.begin(); balance_iter != balance_index.end() && balance_iter->asset_type == graphene::chain::asset_id_type(); ++balance_iter) + if (!is_special_account(balance_iter->owner) && !is_exchange(balance_iter->owner(d).name)) + { + // it is possible due to constructor + db_balances.emplace_back(*balance_iter); + } - // walk through the balances; this index has the largest BTS balances first - // First, calculate the combined value of all BTS - auto& balance_index = d.get_index_type().indices().get(); - graphene::chain::share_type total_bts_balance; - graphene::chain::share_type total_shares_dropped; - for (auto balance_iter = balance_index.begin(); balance_iter != balance_index.end() && balance_iter->asset_type == graphene::chain::asset_id_type(); ++balance_iter) - if (!is_special_account(balance_iter->owner) && !is_exchange(balance_iter->owner(d).name)) - total_bts_balance += balance_iter->balance; + // walk through the balances; this index has the largest BTS balances first + // first, calculate orders and collaterals + // second, update balance + graphene::chain::share_type orders; + graphene::chain::share_type collaterals; + graphene::chain::share_type total_bts_balance; + std::ofstream logfile; - // Now, we assume we're distributing balances to all BTS holders proportionally, figure - // the smallest balance we can distribute and still assign the user a satoshi of the share drop - graphene::chain::share_type effective_total_bts_balance; - auto balance_iter = balance_index.begin(); - for (; balance_iter != balance_index.end() && balance_iter->asset_type == graphene::chain::asset_id_type(); ++balance_iter) - if (!is_special_account(balance_iter->owner) && !is_exchange(balance_iter->owner(d).name)) - { - fc::uint128 share_drop_amount = total_amount_to_distribute.value; - share_drop_amount *= balance_iter->balance.value; - share_drop_amount /= total_bts_balance.value; - if (!share_drop_amount.to_uint64()) + bool sort = false; + for (auto balance_iter = db_balances.begin(); balance_iter != db_balances.end(); ++balance_iter) + { + orders = 0; + collaterals = 0; + // BTS tied up in market orders + auto order_range = d.get_index_type().indices().get().equal_range(balance_iter->owner); + std::for_each(order_range.first, order_range.second, + [&orders] (const graphene::chain::limit_order_object& order) { + if (order.amount_for_sale().asset_id == graphene::chain::asset_id_type()) + orders += order.amount_for_sale().amount; + }); + // BTS tied up in collateral for SmartCoins + auto collateral_range = d.get_index_type().indices().get().equal_range(balance_iter->owner); + + std::for_each(collateral_range.first, collateral_range.second, + [&collaterals] (const graphene::chain::call_order_object& order) { + collaterals += order.collateral; + }); + + balance_iter->initial_balance = balance_iter->balance; + balance_iter->orders = orders; + balance_iter->collaterals = collaterals; + balance_iter->balance += orders + collaterals; + sort = sort || orders.value > 0 || collaterals.value > 0; + total_bts_balance += balance_iter->balance; + } + + if (sort) + { + ilog("generate genesis plugin: sorting"); + std::sort(db_balances.begin(), db_balances.end(), + [](const my_account_balance_object & a, const my_account_balance_object & b) -> bool + { + return a.balance.value > b.balance.value; + }); + } + + graphene::chain::share_type total_shares_dropped; + // Now, we assume we're distributing balances to all BTS holders proportionally, figure + // the smallest balance we can distribute and still assign the user a satoshi of the share drop + graphene::chain::share_type effective_total_bts_balance; + auto balance_iter = db_balances.begin(); + for (balance_iter = db_balances.begin(); balance_iter != db_balances.end(); ++balance_iter) + { + fc::uint128 share_drop_amount = total_amount_to_distribute.value; + share_drop_amount *= balance_iter->balance.value; + share_drop_amount /= total_bts_balance.value; + if (!share_drop_amount.to_uint64()) break; // balances are decreasing, so every balance after will also round to zero - total_shares_dropped += share_drop_amount.to_uint64(); - effective_total_bts_balance += balance_iter->balance; - } + total_shares_dropped += share_drop_amount.to_uint64(); + effective_total_bts_balance += balance_iter->balance; + } - // our iterator is just after the smallest balance we will process, - // walk it backwards towards the larger balances, distributing the sharedrop as we go - graphene::chain::share_type remaining_amount_to_distribute = total_amount_to_distribute; - graphene::chain::share_type bts_balance_remaining = effective_total_bts_balance; - std::map sharedrop_balances; + // our iterator is just after the smallest balance we will process, + // walk it backwards towards the larger balances, distributing the sharedrop as we go + graphene::chain::share_type remaining_amount_to_distribute = total_amount_to_distribute; + graphene::chain::share_type bts_balance_remaining = effective_total_bts_balance; + std::map sharedrop_balances; - do { - --balance_iter; - if (!is_special_account(balance_iter->owner) && !is_exchange(balance_iter->owner(d).name)) - { - fc::uint128 share_drop_amount = remaining_amount_to_distribute.value; - share_drop_amount *= balance_iter->balance.value; - share_drop_amount /= bts_balance_remaining.value; - graphene::chain::share_type amount_distributed = share_drop_amount.to_uint64(); - sharedrop_balances[balance_iter->owner] = amount_distributed; + do { + --balance_iter; + fc::uint128 share_drop_amount = remaining_amount_to_distribute.value; + share_drop_amount *= balance_iter->balance.value; + share_drop_amount /= bts_balance_remaining.value; + graphene::chain::share_type amount_distributed = share_drop_amount.to_uint64(); + sharedrop_balances[balance_iter->owner] = amount_distributed; + balance_iter->sharedrop = amount_distributed; - remaining_amount_to_distribute -= amount_distributed; - bts_balance_remaining -= balance_iter->balance.value; - } - } while (balance_iter != balance_index.begin()); - assert(remaining_amount_to_distribute == 0); + remaining_amount_to_distribute -= amount_distributed; + bts_balance_remaining -= balance_iter->balance.value; + } while (balance_iter != db_balances.begin()); + assert(remaining_amount_to_distribute == 0); - auto& account_index = d.get_index_type(); - auto& account_by_id_index = account_index.indices().get(); - // inefficient way of crawling the graph, but we only do it once - std::set already_generated; - for (;;) - { - unsigned accounts_generated_this_round = 0; - for (const auto& sharedrop_value : sharedrop_balances) - { - const graphene::chain::account_id_type& account_id = sharedrop_value.first; - const graphene::chain::share_type& sharedrop_amount = sharedrop_value.second; - const graphene::chain::account_object& account_obj = account_id(d); - if (already_generated.find(account_id) == already_generated.end()) - { - graphene::chain::genesis_state_type::initial_bts_account_type::initial_authority owner; - owner.weight_threshold = account_obj.owner.weight_threshold; - owner.key_auths = account_obj.owner.key_auths; - for (const auto& value : account_obj.owner.account_auths) + logfile.open(_csvlog_filename); + assert(logfile.is_open()); + logfile << "name,balance+orders+collaterals,balance,orders,collaterals,sharedrop\n"; + char del = ','; + char nl = '\n'; + for(const auto& o : db_balances) + { + logfile << o.owner(d).name << del << o.balance.value << del << o.initial_balance.value << del << o.orders.value << del << o.collaterals.value << del << o.sharedrop.value << nl; + } + ilog("CSV log written to file ${filename}", ("filename", _csvlog_filename)); + logfile.close(); + + //auto& account_index = d.get_index_type(); + //auto& account_by_id_index = account_index.indices().get(); + // inefficient way of crawling the graph, but we only do it once + std::set already_generated; + for (;;) + { + unsigned accounts_generated_this_round = 0; + for (const auto& sharedrop_value : sharedrop_balances) + { + const graphene::chain::account_id_type& account_id = sharedrop_value.first; + const graphene::chain::share_type& sharedrop_amount = sharedrop_value.second; + const graphene::chain::account_object& account_obj = account_id(d); + if (already_generated.find(account_id) == already_generated.end()) { - owner.account_auths.insert(std::make_pair(modify_account_name(value.first(d).name), value.second)); - sharedrop_balances[value.first] += 0; // make sure the account is generated, even if it has a zero balance - } - owner.key_auths = account_obj.owner.key_auths; - owner.address_auths = account_obj.owner.address_auths; - - graphene::chain::genesis_state_type::initial_bts_account_type::initial_authority active; - active.weight_threshold = account_obj.active.weight_threshold; - active.key_auths = account_obj.active.key_auths; - for (const auto& value : account_obj.active.account_auths) - { - active.account_auths.insert(std::make_pair(modify_account_name(value.first(d).name), value.second)); - sharedrop_balances[value.first] += 0; // make sure the account is generated, even if it has a zero balance - } - active.key_auths = account_obj.active.key_auths; - active.address_auths = account_obj.active.address_auths; + graphene::chain::genesis_state_type::initial_bts_account_type::initial_authority owner; + owner.weight_threshold = account_obj.owner.weight_threshold; + owner.key_auths = account_obj.owner.key_auths; + for (const auto& value : account_obj.owner.account_auths) + { + owner.account_auths.insert(std::make_pair(modify_account_name(value.first(d).name), value.second)); + sharedrop_balances[value.first] += 0; // make sure the account is generated, even if it has a zero balance + } + owner.key_auths = account_obj.owner.key_auths; + owner.address_auths = account_obj.owner.address_auths; - new_genesis_state.initial_bts_accounts.emplace_back( - graphene::chain::genesis_state_type::initial_bts_account_type(modify_account_name(account_obj.name), - owner, active, - sharedrop_amount)); - already_generated.insert(account_id); - ++accounts_generated_this_round; - } - } - if (accounts_generated_this_round == 0) - break; - } - fc::json::save_to_file(new_genesis_state, _genesis_filename); - ilog("New genesis state written to file ${filename}", ("filename", _genesis_filename)); + graphene::chain::genesis_state_type::initial_bts_account_type::initial_authority active; + active.weight_threshold = account_obj.active.weight_threshold; + active.key_auths = account_obj.active.key_auths; + for (const auto& value : account_obj.active.account_auths) + { + active.account_auths.insert(std::make_pair(modify_account_name(value.first(d).name), value.second)); + sharedrop_balances[value.first] += 0; // make sure the account is generated, even if it has a zero balance + } + active.key_auths = account_obj.active.key_auths; + active.address_auths = account_obj.active.address_auths; + + new_genesis_state.initial_bts_accounts.emplace_back( + graphene::chain::genesis_state_type::initial_bts_account_type(modify_account_name(account_obj.name), + owner, active, + sharedrop_amount)); + already_generated.insert(account_id); + ++accounts_generated_this_round; + } + } + if (accounts_generated_this_round == 0) + break; + } + fc::json::save_to_file(new_genesis_state, _genesis_filename); + ilog("New genesis state written to file ${filename}", ("filename", _genesis_filename)); } void generate_genesis_plugin::plugin_shutdown() diff --git a/libraries/plugins/generate_genesis/include/graphene/generate_genesis/generate_genesis_plugin.hpp b/libraries/plugins/generate_genesis/include/graphene/generate_genesis/generate_genesis_plugin.hpp index d91dd900..16e4f655 100644 --- a/libraries/plugins/generate_genesis/include/graphene/generate_genesis/generate_genesis_plugin.hpp +++ b/libraries/plugins/generate_genesis/include/graphene/generate_genesis/generate_genesis_plugin.hpp @@ -54,6 +54,19 @@ private: uint32_t _block_to_snapshot; std::string _genesis_filename; + std::string _csvlog_filename; +}; + +class my_account_balance_object : public graphene::chain::account_balance_object +{ +public: + // constructor copying from base class + my_account_balance_object(const graphene::chain::account_balance_object& abo) : graphene::chain::account_balance_object(abo) {} + + graphene::chain::share_type initial_balance; + graphene::chain::share_type orders; + graphene::chain::share_type collaterals; + graphene::chain::share_type sharedrop; }; } } //graphene::generate_genesis_plugin diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index 94a4bdea..8cc12174 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -1451,6 +1451,20 @@ class wallet_api const variant_object& changed_values, bool broadcast = false); + /** Propose a dividend asset update. + * + * @param proposing_account The account paying the fee to propose the tx + * @param expiration_time Timestamp specifying when the proposal will either take effect or expire. + * @param changed_values dividend asset parameters to update + * @param broadcast true if you wish to broadcast the transaction + * @return the signed version of the transaction + */ + signed_transaction propose_dividend_asset_update( + const string& proposing_account, + fc::time_point_sec expiration_time, + const variant_object& changed_values, + bool broadcast = false); + /** Approve or disapprove a proposal. * * @param fee_paying_account The account paying the fee for the op. @@ -1682,6 +1696,7 @@ FC_API( graphene::wallet::wallet_api, (get_prototype_operation) (propose_parameter_change) (propose_fee_change) + (propose_dividend_asset_update) (approve_proposal) (dbg_make_uia) (dbg_make_mia) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index d4414404..c31beed2 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2804,6 +2804,46 @@ public: return sign_transaction(tx, broadcast); } + signed_transaction propose_dividend_asset_update( + const string& proposing_account, + fc::time_point_sec expiration_time, + const variant_object& changed_values, + bool broadcast = false) + { + FC_ASSERT( changed_values.contains("asset_to_update") ); + + const chain_parameters& current_params = get_global_properties().parameters; + asset_update_dividend_operation changed_op; + fc::reflector::visit( + fc::from_variant_visitor( changed_values, changed_op ) + ); + + optional asset_to_update = find_asset(changed_op.asset_to_update); + if (!asset_to_update) + FC_THROW("No asset with that symbol exists!"); + + asset_update_dividend_operation update_op; + update_op.issuer = asset_to_update->issuer; + update_op.asset_to_update = asset_to_update->id; + update_op.new_options = changed_op.new_options; + + proposal_create_operation prop_op; + + prop_op.expiration_time = expiration_time; + prop_op.review_period_seconds = current_params.committee_proposal_review_period; + prop_op.fee_paying_account = get_account(proposing_account).id; + + prop_op.proposed_ops.emplace_back( update_op ); + current_params.current_fees->set_fee( prop_op.proposed_ops.back().op ); + + signed_transaction tx; + tx.operations.push_back(prop_op); + set_operation_fees(tx, current_params.current_fees); + tx.validate(); + + return sign_transaction(tx, broadcast); + } + signed_transaction approve_proposal( const string& fee_paying_account, const string& proposal_id, @@ -3877,6 +3917,16 @@ signed_transaction wallet_api::propose_fee_change( return my->propose_fee_change( proposing_account, expiration_time, changed_fees, broadcast ); } +signed_transaction wallet_api::propose_dividend_asset_update( + const string& proposing_account, + fc::time_point_sec expiration_time, + const variant_object& changed_fees, + bool broadcast /* = false */ + ) +{ + return my->propose_dividend_asset_update( proposing_account, expiration_time, changed_fees, broadcast ); +} + signed_transaction wallet_api::approve_proposal( const string& fee_paying_account, const string& proposal_id, @@ -3887,6 +3937,9 @@ signed_transaction wallet_api::approve_proposal( return my->approve_proposal( fee_paying_account, proposal_id, delta, broadcast ); } + + + global_property_object wallet_api::get_global_properties() const { return my->get_global_properties();