/* * Copyright (c) 2015 Cryptonomex, Inc., and contributors. * * The MIT License * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include namespace graphene { namespace chain { share_type cut_fee(share_type a, uint16_t p) { if( a == 0 || p == 0 ) return 0; if( p == GRAPHENE_100_PERCENT ) return a; fc::uint128 r(a.value); r *= p; r /= GRAPHENE_100_PERCENT; return r.to_uint64(); } void account_balance_object::adjust_balance(const asset& delta) { assert(delta.asset_id == asset_type); balance += delta.amount; } void account_statistics_object::process_fees(const account_object& a, database& d) const { if( pending_fees > 0 || pending_vested_fees > 0 ) { auto pay_out_fees = [&](const account_object& account, share_type core_fee_total, bool require_vesting) { // Check the referrer -- if he's no longer a member, pay to the lifetime referrer instead. // No need to check the registrar; registrars are required to be lifetime members. if( account.referrer(d).is_basic_account(d.head_block_time()) ) d.modify(account, [](account_object& a) { a.referrer = a.lifetime_referrer; }); share_type network_cut = cut_fee(core_fee_total, account.network_fee_percentage); assert( network_cut <= core_fee_total ); #ifndef NDEBUG const auto& props = d.get_global_properties(); share_type reserveed = cut_fee(network_cut, props.parameters.reserve_percent_of_fee); share_type accumulated = network_cut - reserveed; assert( accumulated + reserveed == network_cut ); #endif share_type lifetime_cut = cut_fee(core_fee_total, account.lifetime_referrer_fee_percentage); share_type referral = core_fee_total - network_cut - lifetime_cut; d.modify(asset_dynamic_data_id_type()(d), [network_cut](asset_dynamic_data_object& d) { d.accumulated_fees += network_cut; }); // Potential optimization: Skip some of this math and object lookups by special casing on the account type. // For example, if the account is a lifetime member, we can skip all this and just deposit the referral to // it directly. share_type referrer_cut = cut_fee(referral, account.referrer_rewards_percentage); share_type registrar_cut = referral - referrer_cut; d.deposit_cashback(d.get(account.lifetime_referrer), lifetime_cut, require_vesting); d.deposit_cashback(d.get(account.referrer), referrer_cut, require_vesting); d.deposit_cashback(d.get(account.registrar), registrar_cut, require_vesting); assert( referrer_cut + registrar_cut + accumulated + reserveed + lifetime_cut == core_fee_total ); }; pay_out_fees(a, pending_fees, true); pay_out_fees(a, pending_vested_fees, false); d.modify(*this, [&](account_statistics_object& s) { s.lifetime_fees_paid += pending_fees + pending_vested_fees; s.pending_fees = 0; s.pending_vested_fees = 0; }); } } void account_statistics_object::pay_fee( share_type core_fee, share_type cashback_vesting_threshold ) { if( core_fee > cashback_vesting_threshold ) pending_fees += core_fee; else pending_vested_fees += core_fee; } set account_member_index::get_account_members(const account_object& a)const { set result; for( auto auth : a.owner.account_auths ) result.insert(auth.first); for( auto auth : a.active.account_auths ) result.insert(auth.first); return result; } set account_member_index::get_key_members(const account_object& a)const { set result; for( auto auth : a.owner.key_auths ) result.insert(auth.first); for( auto auth : a.active.key_auths ) result.insert(auth.first); result.insert( a.options.memo_key ); return result; } set
account_member_index::get_address_members(const account_object& a)const { set
result; for( auto auth : a.owner.address_auths ) result.insert(auth.first); for( auto auth : a.active.address_auths ) result.insert(auth.first); result.insert( a.options.memo_key ); return result; } void account_member_index::object_inserted(const object& obj) { assert( dynamic_cast(&obj) ); // for debug only const account_object& a = static_cast(obj); auto account_members = get_account_members(a); for( auto item : account_members ) account_to_account_memberships[item].insert(obj.id); auto key_members = get_key_members(a); for( auto item : key_members ) account_to_key_memberships[item].insert(obj.id); auto address_members = get_address_members(a); for( auto item : address_members ) account_to_address_memberships[item].insert(obj.id); } void account_member_index::object_removed(const object& obj) { assert( dynamic_cast(&obj) ); // for debug only const account_object& a = static_cast(obj); auto key_members = get_key_members(a); for( auto item : key_members ) account_to_key_memberships[item].erase( obj.id ); auto address_members = get_address_members(a); for( auto item : address_members ) account_to_address_memberships[item].erase( obj.id ); auto account_members = get_account_members(a); for( auto item : account_members ) account_to_account_memberships[item].erase( obj.id ); } void account_member_index::about_to_modify(const object& before) { before_key_members.clear(); before_account_members.clear(); assert( dynamic_cast(&before) ); // for debug only const account_object& a = static_cast(before); before_key_members = get_key_members(a); before_address_members = get_address_members(a); before_account_members = get_account_members(a); } void account_member_index::object_modified(const object& after) { assert( dynamic_cast(&after) ); // for debug only const account_object& a = static_cast(after); { set after_account_members = get_account_members(a); vector removed; removed.reserve(before_account_members.size()); std::set_difference(before_account_members.begin(), before_account_members.end(), after_account_members.begin(), after_account_members.end(), std::inserter(removed, removed.end())); for( auto itr = removed.begin(); itr != removed.end(); ++itr ) account_to_account_memberships[*itr].erase(after.id); vector added; added.reserve(after_account_members.size()); std::set_difference(after_account_members.begin(), after_account_members.end(), before_account_members.begin(), before_account_members.end(), std::inserter(added, added.end())); for( auto itr = added.begin(); itr != added.end(); ++itr ) account_to_account_memberships[*itr].insert(after.id); } { set after_key_members = get_key_members(a); vector removed; removed.reserve(before_key_members.size()); std::set_difference(before_key_members.begin(), before_key_members.end(), after_key_members.begin(), after_key_members.end(), std::inserter(removed, removed.end())); for( auto itr = removed.begin(); itr != removed.end(); ++itr ) account_to_key_memberships[*itr].erase(after.id); vector added; added.reserve(after_key_members.size()); std::set_difference(after_key_members.begin(), after_key_members.end(), before_key_members.begin(), before_key_members.end(), std::inserter(added, added.end())); for( auto itr = added.begin(); itr != added.end(); ++itr ) account_to_key_memberships[*itr].insert(after.id); } { set
after_address_members = get_address_members(a); vector
removed; removed.reserve(before_address_members.size()); std::set_difference(before_address_members.begin(), before_address_members.end(), after_address_members.begin(), after_address_members.end(), std::inserter(removed, removed.end())); for( auto itr = removed.begin(); itr != removed.end(); ++itr ) account_to_address_memberships[*itr].erase(after.id); vector
added; added.reserve(after_address_members.size()); std::set_difference(after_address_members.begin(), after_address_members.end(), before_address_members.begin(), before_address_members.end(), std::inserter(added, added.end())); for( auto itr = added.begin(); itr != added.end(); ++itr ) account_to_address_memberships[*itr].insert(after.id); } } void account_referrer_index::object_inserted( const object& obj ) { } void account_referrer_index::object_removed( const object& obj ) { } void account_referrer_index::about_to_modify( const object& before ) { } void account_referrer_index::object_modified( const object& after ) { } } } // graphene::chain