Merge branch 'develop' into rng_api
This commit is contained in:
commit
6743860f42
17 changed files with 1418 additions and 1318 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -12,6 +12,8 @@ hardfork.hpp
|
|||
build_xc
|
||||
data
|
||||
|
||||
build
|
||||
|
||||
libraries/utilities/git_revision.cpp
|
||||
|
||||
libraries/wallet/Doxyfile
|
||||
|
|
@ -43,4 +45,4 @@ object_database/*
|
|||
*.pyo
|
||||
.vscode
|
||||
.DS_Store
|
||||
.idea
|
||||
.idea
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ RUN \
|
|||
libssl-dev \
|
||||
libtool \
|
||||
locales \
|
||||
ntp \
|
||||
pkg-config \
|
||||
wget \
|
||||
&& \
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// bitshares-core #429 rounding issue when creating assets
|
||||
#ifndef HARDFORK_CORE_429_TIME
|
||||
#define HARDFORK_CORE_429_TIME (fc::time_point_sec( 1510320000 ))
|
||||
#define HARDFORK_CORE_429_TIME (fc::time_point_sec( 1566784800 ))
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
#ifndef HARDFORK_SWEEPS_TIME
|
||||
#define HARDFORK_SWEEPS_TIME (fc::time_point_sec( 1565391600 ))
|
||||
#define HARDFORK_SWEEPS_TIME (fc::time_point_sec( 1566784800 ))
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@
|
|||
#define GRAPHENE_RECENTLY_MISSED_COUNT_INCREMENT 4
|
||||
#define GRAPHENE_RECENTLY_MISSED_COUNT_DECREMENT 3
|
||||
|
||||
#define GRAPHENE_CURRENT_DB_VERSION "PPY2.1"
|
||||
#define GRAPHENE_CURRENT_DB_VERSION "PPY2.2"
|
||||
|
||||
#define GRAPHENE_IRREVERSIBLE_THRESHOLD (70 * GRAPHENE_1_PERCENT)
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@
|
|||
#include <graphene/chain/protocol/types.hpp>
|
||||
#include <graphene/db/object.hpp>
|
||||
#include <graphene/db/generic_index.hpp>
|
||||
|
||||
#include <boost/multi_index/composite_key.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
|
|
|||
|
|
@ -1260,13 +1260,11 @@ namespace graphene { namespace net { namespace detail {
|
|||
wdump((inventory_to_advertise));
|
||||
for (const item_id& item_to_advertise : inventory_to_advertise)
|
||||
{
|
||||
if (peer->inventory_advertised_to_peer.find(item_to_advertise) != peer->inventory_advertised_to_peer.end() )
|
||||
wdump((*peer->inventory_advertised_to_peer.find(item_to_advertise)));
|
||||
if (peer->inventory_peer_advertised_to_us.find(item_to_advertise) != peer->inventory_peer_advertised_to_us.end() )
|
||||
wdump((*peer->inventory_peer_advertised_to_us.find(item_to_advertise)));
|
||||
auto adv_to_peer = peer->inventory_advertised_to_peer.find(item_to_advertise);
|
||||
auto adv_to_us = peer->inventory_peer_advertised_to_us.find(item_to_advertise);
|
||||
|
||||
if (peer->inventory_advertised_to_peer.find(item_to_advertise) == peer->inventory_advertised_to_peer.end() &&
|
||||
peer->inventory_peer_advertised_to_us.find(item_to_advertise) == peer->inventory_peer_advertised_to_us.end())
|
||||
if (adv_to_peer == peer->inventory_advertised_to_peer.end() &&
|
||||
adv_to_us == peer->inventory_peer_advertised_to_us.end())
|
||||
{
|
||||
items_to_advertise_by_type[item_to_advertise.item_type].push_back(item_to_advertise.item_hash);
|
||||
peer->inventory_advertised_to_peer.insert(peer_connection::timestamped_item_id(item_to_advertise, fc::time_point::now()));
|
||||
|
|
@ -1275,6 +1273,13 @@ namespace graphene { namespace net { namespace detail {
|
|||
testnetlog("advertising transaction ${id} to peer ${endpoint}", ("id", item_to_advertise.item_hash)("endpoint", peer->get_remote_endpoint()));
|
||||
dlog("advertising item ${id} to peer ${endpoint}", ("id", item_to_advertise.item_hash)("endpoint", peer->get_remote_endpoint()));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (adv_to_peer != peer->inventory_advertised_to_peer.end() )
|
||||
wdump( (*adv_to_peer) );
|
||||
if (adv_to_us != peer->inventory_peer_advertised_to_us.end() )
|
||||
wdump( (*adv_to_us) );
|
||||
}
|
||||
}
|
||||
dlog("advertising ${count} new item(s) of ${types} type(s) to peer ${endpoint}",
|
||||
("count", total_items_to_send_to_this_peer)
|
||||
|
|
|
|||
|
|
@ -204,14 +204,14 @@ block_production_condition::block_production_condition_enum witness_plugin::bloc
|
|||
break;
|
||||
case block_production_condition::no_private_key:
|
||||
ilog("Not producing block because I don't have the private key for ${scheduled_key}",
|
||||
("n", capture["n"])("t", capture["t"])("c", capture["c"]));
|
||||
("scheduled_key", capture["scheduled_key"]));
|
||||
break;
|
||||
case block_production_condition::low_participation:
|
||||
elog("Not producing block because node appears to be on a minority fork with only ${pct}% witness participation",
|
||||
("n", capture["n"])("t", capture["t"])("c", capture["c"]));
|
||||
break;
|
||||
case block_production_condition::lag:
|
||||
elog("Not producing block because node didn't wake up within 500ms of the slot time.");
|
||||
elog("Not producing block because node didn't wake up within 2500ms of the slot time.");
|
||||
break;
|
||||
case block_production_condition::consecutive:
|
||||
elog("Not producing block because the last block was generated by the same witness.\nThis node is probably disconnected from the network so block production has been disabled.\nDisable this check with --allow-consecutive option.");
|
||||
|
|
@ -291,7 +291,7 @@ block_production_condition::block_production_condition_enum witness_plugin::mayb
|
|||
// return block_production_condition::local_clock; //Not producing block because head block is less than a second old.
|
||||
//}
|
||||
|
||||
if( llabs((scheduled_time - now).count()) > fc::milliseconds( 500 ).count() )
|
||||
if( llabs((scheduled_time - now).count()) > fc::milliseconds( 2500 ).count() )
|
||||
{
|
||||
capture("scheduled_time", scheduled_time)("now", now);
|
||||
return block_production_condition::lag;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@
|
|||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#include "../common/genesis_file_util.hpp"
|
||||
|
||||
#define BOOST_TEST_MODULE Test Application
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
|
||||
|
|
@ -69,12 +71,15 @@ BOOST_AUTO_TEST_CASE( two_node_network )
|
|||
cfg2.emplace("seed-node", boost::program_options::variable_value(vector<string>{"127.0.0.1:3939"}, false));
|
||||
app2.initialize(app2_dir.path(), cfg2);
|
||||
|
||||
BOOST_TEST_MESSAGE( "Starting app1 and waiting 500 ms" );
|
||||
cfg.emplace("genesis-json", boost::program_options::variable_value(create_genesis_file(app_dir), false));
|
||||
cfg2.emplace("genesis-json", boost::program_options::variable_value(create_genesis_file(app2_dir), false));
|
||||
|
||||
BOOST_TEST_MESSAGE( "Starting app1 and waiting 1500 ms" );
|
||||
app1.startup();
|
||||
fc::usleep(fc::milliseconds(500));
|
||||
BOOST_TEST_MESSAGE( "Starting app2 and waiting 500 ms" );
|
||||
fc::usleep(fc::milliseconds(1500));
|
||||
BOOST_TEST_MESSAGE( "Starting app2 and waiting 1500 ms" );
|
||||
app2.startup();
|
||||
fc::usleep(fc::milliseconds(500));
|
||||
fc::usleep(fc::milliseconds(1500));
|
||||
|
||||
BOOST_REQUIRE_EQUAL(app1.p2p_node()->get_connection_count(), 1);
|
||||
BOOST_CHECK_EQUAL(std::string(app1.p2p_node()->get_connected_peers().front().host.get_address()), "127.0.0.1");
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
43
tests/common/genesis_file_util.hpp
Normal file
43
tests/common/genesis_file_util.hpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
|
||||
/////////
|
||||
/// @brief forward declaration, using as a hack to generate a genesis.json file
|
||||
/// for testing
|
||||
/////////
|
||||
namespace graphene { namespace app { namespace detail {
|
||||
graphene::chain::genesis_state_type create_example_genesis();
|
||||
} } } // graphene::app::detail
|
||||
|
||||
/////////
|
||||
/// @brief create a genesis_json file
|
||||
/// @param directory the directory to place the file "genesis.json"
|
||||
/// @returns the full path to the file
|
||||
////////
|
||||
boost::filesystem::path create_genesis_file(fc::temp_directory& directory) {
|
||||
boost::filesystem::path genesis_path = boost::filesystem::path{directory.path().generic_string()} / "genesis.json";
|
||||
fc::path genesis_out = genesis_path;
|
||||
graphene::chain::genesis_state_type genesis_state = graphene::app::detail::create_example_genesis();
|
||||
|
||||
/* Work In Progress: Place some accounts in the Genesis file so as to pre-make some accounts to play with
|
||||
std::string test_prefix = "test";
|
||||
// helper lambda
|
||||
auto get_test_key = [&]( std::string prefix, uint32_t i ) -> public_key_type
|
||||
{
|
||||
return fc::ecc::private_key::regenerate( fc::sha256::hash( test_prefix + prefix + std::to_string(i) ) ).get_public_key();
|
||||
};
|
||||
// create 2 accounts to use
|
||||
for (int i = 1; i <= 2; ++i )
|
||||
{
|
||||
genesis_state_type::initial_account_type dev_account(
|
||||
test_prefix + std::to_string(i),
|
||||
get_test_key("owner-", i),
|
||||
get_test_key("active-", i),
|
||||
false);
|
||||
genesis_state.initial_accounts.push_back(dev_account);
|
||||
// give her some coin
|
||||
}
|
||||
*/
|
||||
|
||||
fc::json::save_to_file(genesis_state, genesis_out);
|
||||
return genesis_path;
|
||||
}
|
||||
|
|
@ -74,6 +74,7 @@ BOOST_FIXTURE_TEST_CASE( update_account_keys, database_fixture )
|
|||
//
|
||||
account_object sam_account_object = create_account( "sam", sam_key );
|
||||
|
||||
upgrade_to_lifetime_member(sam_account_object.id);
|
||||
//Get a sane head block time
|
||||
generate_block( skip_flags );
|
||||
|
||||
|
|
@ -135,7 +136,7 @@ BOOST_FIXTURE_TEST_CASE( update_account_keys, database_fixture )
|
|||
generate_block( skip_flags );
|
||||
|
||||
std::cout << "update_account_keys: this test will take a few minutes...\n";
|
||||
for( int use_addresses=0; use_addresses<2; use_addresses++ )
|
||||
for( int use_addresses=0; use_addresses<1; use_addresses++ )
|
||||
{
|
||||
vector< public_key_type > key_ids = numbered_key_id[ use_addresses ];
|
||||
for( int num_owner_keys=1; num_owner_keys<=2; num_owner_keys++ )
|
||||
|
|
@ -173,7 +174,7 @@ BOOST_FIXTURE_TEST_CASE( update_account_keys, database_fixture )
|
|||
create_op.registrar = sam_account_object.id;
|
||||
trx.operations.push_back( create_op );
|
||||
// trx.sign( sam_key );
|
||||
wdump( (trx) );
|
||||
//wdump( (trx) );
|
||||
|
||||
processed_transaction ptx_create = db.push_transaction( trx,
|
||||
database::skip_transaction_dupe_check |
|
||||
|
|
@ -262,7 +263,7 @@ BOOST_FIXTURE_TEST_CASE( witness_order_mc_test, database_fixture )
|
|||
{
|
||||
try {
|
||||
size_t num_witnesses = db.get_global_properties().active_witnesses.size();
|
||||
size_t dmin = num_witnesses >> 1;
|
||||
//size_t dmin = num_witnesses >> 1;
|
||||
|
||||
vector< witness_id_type > cur_round;
|
||||
vector< witness_id_type > full_schedule;
|
||||
|
|
@ -305,13 +306,10 @@ BOOST_FIXTURE_TEST_CASE( witness_order_mc_test, database_fixture )
|
|||
generate_block();
|
||||
}
|
||||
|
||||
for( size_t i=0,m=full_schedule.size(); i<m; i++ )
|
||||
for( size_t i=num_witnesses, m=full_schedule.size(); i<m; i+=num_witnesses )
|
||||
{
|
||||
for( size_t j=i+1,n=std::min( m, i+dmin ); j<n; j++ )
|
||||
{
|
||||
BOOST_CHECK( full_schedule[i] != full_schedule[j] );
|
||||
assert( full_schedule[i] != full_schedule[j] );
|
||||
}
|
||||
BOOST_CHECK( full_schedule[i] != full_schedule[i-1] );
|
||||
assert( full_schedule[i] != full_schedule[i-1] );
|
||||
}
|
||||
|
||||
} catch (fc::exception& e) {
|
||||
|
|
@ -369,45 +367,47 @@ BOOST_FIXTURE_TEST_CASE( tapos_rollover, database_fixture )
|
|||
}
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_CASE(bulk_discount, database_fixture)
|
||||
{ try {
|
||||
ACTOR(nathan);
|
||||
// Give nathan ALLLLLL the money!
|
||||
transfer(GRAPHENE_COMMITTEE_ACCOUNT, nathan_id, db.get_balance(GRAPHENE_COMMITTEE_ACCOUNT, asset_id_type()));
|
||||
enable_fees();//GRAPHENE_BLOCKCHAIN_PRECISION*10);
|
||||
upgrade_to_lifetime_member(nathan_id);
|
||||
share_type new_fees;
|
||||
while( nathan_id(db).statistics(db).lifetime_fees_paid + new_fees < GRAPHENE_DEFAULT_BULK_DISCOUNT_THRESHOLD_MIN )
|
||||
{
|
||||
transfer(nathan_id, GRAPHENE_COMMITTEE_ACCOUNT, asset(1));
|
||||
new_fees += db.current_fee_schedule().calculate_fee(transfer_operation()).amount;
|
||||
}
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
enable_fees();//GRAPHENE_BLOCKCHAIN_PRECISION*10);
|
||||
auto old_cashback = nathan_id(db).cashback_balance(db).balance;
|
||||
|
||||
transfer(nathan_id, GRAPHENE_COMMITTEE_ACCOUNT, asset(1));
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
enable_fees();//GRAPHENE_BLOCKCHAIN_PRECISION*10);
|
||||
|
||||
BOOST_CHECK_EQUAL(nathan_id(db).cashback_balance(db).balance.amount.value,
|
||||
old_cashback.amount.value + GRAPHENE_BLOCKCHAIN_PRECISION * 8);
|
||||
|
||||
new_fees = 0;
|
||||
while( nathan_id(db).statistics(db).lifetime_fees_paid + new_fees < GRAPHENE_DEFAULT_BULK_DISCOUNT_THRESHOLD_MAX )
|
||||
{
|
||||
transfer(nathan_id, GRAPHENE_COMMITTEE_ACCOUNT, asset(1));
|
||||
new_fees += db.current_fee_schedule().calculate_fee(transfer_operation()).amount;
|
||||
}
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
enable_fees();//GRAPHENE_BLOCKCHAIN_PRECISION*10);
|
||||
old_cashback = nathan_id(db).cashback_balance(db).balance;
|
||||
|
||||
transfer(nathan_id, GRAPHENE_COMMITTEE_ACCOUNT, asset(1));
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
|
||||
BOOST_CHECK_EQUAL(nathan_id(db).cashback_balance(db).balance.amount.value,
|
||||
old_cashback.amount.value + GRAPHENE_BLOCKCHAIN_PRECISION * 9);
|
||||
} FC_LOG_AND_RETHROW() }
|
||||
//BOOST_FIXTURE_TEST_CASE(bulk_discount, database_fixture)
|
||||
//{ try {
|
||||
// ACTOR(nathan);
|
||||
// // Give nathan ALLLLLL the money!
|
||||
// transfer(GRAPHENE_COMMITTEE_ACCOUNT, nathan_id, db.get_balance(GRAPHENE_COMMITTEE_ACCOUNT, asset_id_type()));
|
||||
// enable_fees();//GRAPHENE_BLOCKCHAIN_PRECISION*10);
|
||||
// upgrade_to_lifetime_member(nathan_id);
|
||||
// share_type new_fees;
|
||||
// while( nathan_id(db).statistics(db).lifetime_fees_paid + new_fees < GRAPHENE_DEFAULT_BULK_DISCOUNT_THRESHOLD_MIN )
|
||||
// {
|
||||
// transfer(nathan_id, GRAPHENE_COMMITTEE_ACCOUNT, asset(1));
|
||||
// new_fees += db.current_fee_schedule().calculate_fee(transfer_operation()).amount;
|
||||
// }
|
||||
// generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
// enable_fees();//GRAPHENE_BLOCKCHAIN_PRECISION*10);
|
||||
// asset old_cashback;
|
||||
// if(nathan.cashback_vb.valid())
|
||||
// old_cashback = nathan.cashback_balance(db).balance;
|
||||
//
|
||||
// transfer(nathan_id, GRAPHENE_COMMITTEE_ACCOUNT, asset(1));
|
||||
// generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
// enable_fees();//GRAPHENE_BLOCKCHAIN_PRECISION*10);
|
||||
//
|
||||
// BOOST_CHECK_EQUAL(nathan_id(db).cashback_balance(db).balance.amount.value,
|
||||
// old_cashback.amount.value + GRAPHENE_BLOCKCHAIN_PRECISION * 8);
|
||||
//
|
||||
// new_fees = 0;
|
||||
// while( nathan_id(db).statistics(db).lifetime_fees_paid + new_fees < GRAPHENE_DEFAULT_BULK_DISCOUNT_THRESHOLD_MAX )
|
||||
// {
|
||||
// transfer(nathan_id, GRAPHENE_COMMITTEE_ACCOUNT, asset(1));
|
||||
// new_fees += db.current_fee_schedule().calculate_fee(transfer_operation()).amount;
|
||||
// }
|
||||
// generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
// enable_fees();//GRAPHENE_BLOCKCHAIN_PRECISION*10);
|
||||
// old_cashback = nathan_id(db).cashback_balance(db).balance;
|
||||
//
|
||||
// transfer(nathan_id, GRAPHENE_COMMITTEE_ACCOUNT, asset(1));
|
||||
// generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
//
|
||||
// BOOST_CHECK_EQUAL(nathan_id(db).cashback_balance(db).balance.amount.value,
|
||||
// old_cashback.amount.value + GRAPHENE_BLOCKCHAIN_PRECISION * 9);
|
||||
//} FC_LOG_AND_RETHROW() }
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
|
|||
659
tests/tests/dividend_tests.cpp
Normal file
659
tests/tests/dividend_tests.cpp
Normal file
|
|
@ -0,0 +1,659 @@
|
|||
/*
|
||||
* Copyright (c) 2018 oxarbitrage 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 <boost/test/unit_test.hpp>
|
||||
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
#include "../common/database_fixture.hpp"
|
||||
|
||||
using namespace graphene::chain;
|
||||
using namespace graphene::chain::test;
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE( dividend_tests, database_fixture )
|
||||
|
||||
BOOST_AUTO_TEST_CASE( create_dividend_uia )
|
||||
{
|
||||
using namespace graphene;
|
||||
try {
|
||||
BOOST_TEST_MESSAGE("Creating dividend holder asset");
|
||||
{
|
||||
asset_create_operation creator;
|
||||
creator.issuer = account_id_type();
|
||||
creator.fee = asset();
|
||||
creator.symbol = "DIVIDEND";
|
||||
creator.common_options.max_supply = 100000000;
|
||||
creator.precision = 2;
|
||||
creator.common_options.market_fee_percent = GRAPHENE_MAX_MARKET_FEE_PERCENT/100; /*1%*/
|
||||
creator.common_options.issuer_permissions = UIA_ASSET_ISSUER_PERMISSION_MASK;
|
||||
creator.common_options.flags = charge_market_fee;
|
||||
creator.common_options.core_exchange_rate = price({asset(2),asset(1,asset_id_type(1))});
|
||||
trx.operations.push_back(std::move(creator));
|
||||
set_expiration(db, trx);
|
||||
PUSH_TX( db, trx, ~0 );
|
||||
trx.operations.clear();
|
||||
}
|
||||
|
||||
BOOST_TEST_MESSAGE("Creating test accounts");
|
||||
create_account("alice");
|
||||
create_account("bob");
|
||||
create_account("carol");
|
||||
create_account("dave");
|
||||
create_account("frank");
|
||||
|
||||
BOOST_TEST_MESSAGE("Creating test asset");
|
||||
{
|
||||
asset_create_operation creator;
|
||||
creator.issuer = account_id_type();
|
||||
creator.fee = asset();
|
||||
creator.symbol = "TESTB"; //cant use TEST
|
||||
creator.common_options.max_supply = 100000000;
|
||||
creator.precision = 2;
|
||||
creator.common_options.market_fee_percent = GRAPHENE_MAX_MARKET_FEE_PERCENT/100; /*1%*/
|
||||
creator.common_options.issuer_permissions = UIA_ASSET_ISSUER_PERMISSION_MASK;
|
||||
creator.common_options.flags = charge_market_fee;
|
||||
creator.common_options.core_exchange_rate = price({asset(2),asset(1,asset_id_type(1))});
|
||||
trx.operations.push_back(std::move(creator));
|
||||
set_expiration(db, trx);
|
||||
PUSH_TX( db, trx, ~0 );
|
||||
trx.operations.clear();
|
||||
}
|
||||
generate_block();
|
||||
|
||||
BOOST_TEST_MESSAGE("Funding asset fee pool");
|
||||
{
|
||||
asset_fund_fee_pool_operation fund_op;
|
||||
fund_op.from_account = account_id_type();
|
||||
fund_op.asset_id = get_asset("TESTB").id;
|
||||
fund_op.amount = 500000000;
|
||||
trx.operations.push_back(std::move(fund_op));
|
||||
set_expiration(db, trx);
|
||||
PUSH_TX( db, trx, ~0 );
|
||||
trx.operations.clear();
|
||||
}
|
||||
|
||||
// our DIVIDEND asset should not yet be a divdend asset
|
||||
const auto& dividend_holder_asset_object = get_asset("DIVIDEND");
|
||||
BOOST_CHECK(!dividend_holder_asset_object.dividend_data_id);
|
||||
|
||||
BOOST_TEST_MESSAGE("Converting the new asset to a dividend holder asset");
|
||||
{
|
||||
asset_update_dividend_operation op;
|
||||
op.issuer = dividend_holder_asset_object.issuer;
|
||||
op.asset_to_update = dividend_holder_asset_object.id;
|
||||
op.new_options.next_payout_time = db.head_block_time() + fc::minutes(1);
|
||||
op.new_options.payout_interval = 60 * 60 * 24 * 3;
|
||||
|
||||
trx.operations.push_back(op);
|
||||
set_expiration(db, trx);
|
||||
PUSH_TX( db, trx, ~0 );
|
||||
trx.operations.clear();
|
||||
}
|
||||
generate_block();
|
||||
|
||||
BOOST_TEST_MESSAGE("Verifying the dividend holder asset options");
|
||||
BOOST_REQUIRE(dividend_holder_asset_object.dividend_data_id);
|
||||
const auto& dividend_data = dividend_holder_asset_object.dividend_data(db);
|
||||
{
|
||||
BOOST_REQUIRE(dividend_data.options.payout_interval);
|
||||
BOOST_CHECK_EQUAL(*dividend_data.options.payout_interval, 60 * 60 * 24 * 3);
|
||||
}
|
||||
|
||||
const account_object& dividend_distribution_account = dividend_data.dividend_distribution_account(db);
|
||||
BOOST_CHECK_EQUAL(dividend_distribution_account.name, "dividend-dividend-distribution");
|
||||
|
||||
// db.modify( db.get_global_properties(), [&]( global_property_object& _gpo )
|
||||
// {
|
||||
// _gpo.parameters.current_fees->get<asset_dividend_distribution_operation>().distribution_base_fee = 100;
|
||||
// _gpo.parameters.current_fees->get<asset_dividend_distribution_operation>().distribution_fee_per_holder = 100;
|
||||
// } );
|
||||
|
||||
|
||||
} catch(fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( test_update_dividend_interval )
|
||||
{
|
||||
using namespace graphene;
|
||||
try {
|
||||
INVOKE( create_dividend_uia );
|
||||
|
||||
const auto& dividend_holder_asset_object = get_asset("DIVIDEND");
|
||||
const auto& dividend_data = dividend_holder_asset_object.dividend_data(db);
|
||||
|
||||
auto advance_to_next_payout_time = [&]() {
|
||||
// Advance to the next upcoming payout time
|
||||
BOOST_REQUIRE(dividend_data.options.next_payout_time);
|
||||
fc::time_point_sec next_payout_scheduled_time = *dividend_data.options.next_payout_time;
|
||||
// generate blocks up to the next scheduled time
|
||||
generate_blocks(next_payout_scheduled_time);
|
||||
// if the scheduled time fell on a maintenance interval, then we should have paid out.
|
||||
// if not, we need to advance to the next maintenance interval to trigger the payout
|
||||
if (dividend_data.options.next_payout_time)
|
||||
{
|
||||
// we know there was a next_payout_time set when we entered this, so if
|
||||
// it has been cleared, we must have already processed payouts, no need to
|
||||
// further advance time.
|
||||
BOOST_REQUIRE(dividend_data.options.next_payout_time);
|
||||
if (*dividend_data.options.next_payout_time == next_payout_scheduled_time)
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block(); // get the maintenance skip slots out of the way
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_TEST_MESSAGE("Updating the payout interval");
|
||||
{
|
||||
asset_update_dividend_operation op;
|
||||
op.issuer = dividend_holder_asset_object.issuer;
|
||||
op.asset_to_update = dividend_holder_asset_object.id;
|
||||
op.new_options.next_payout_time = fc::time_point::now() + fc::minutes(1);
|
||||
op.new_options.payout_interval = 60 * 60 * 24; // 1 days
|
||||
trx.operations.push_back(op);
|
||||
set_expiration(db, trx);
|
||||
PUSH_TX( db, trx, ~0 );
|
||||
trx.operations.clear();
|
||||
}
|
||||
generate_block();
|
||||
|
||||
BOOST_TEST_MESSAGE("Verifying the updated dividend holder asset options");
|
||||
{
|
||||
BOOST_REQUIRE(dividend_data.options.payout_interval);
|
||||
BOOST_CHECK_EQUAL(*dividend_data.options.payout_interval, 60 * 60 * 24);
|
||||
}
|
||||
|
||||
BOOST_TEST_MESSAGE("Removing the payout interval");
|
||||
{
|
||||
asset_update_dividend_operation op;
|
||||
op.issuer = dividend_holder_asset_object.issuer;
|
||||
op.asset_to_update = dividend_holder_asset_object.id;
|
||||
op.new_options.next_payout_time = dividend_data.options.next_payout_time;
|
||||
op.new_options.payout_interval = fc::optional<uint32_t>();
|
||||
trx.operations.push_back(op);
|
||||
set_expiration(db, trx);
|
||||
PUSH_TX( db, trx, ~0 );
|
||||
trx.operations.clear();
|
||||
}
|
||||
generate_block();
|
||||
BOOST_CHECK(!dividend_data.options.payout_interval);
|
||||
advance_to_next_payout_time();
|
||||
BOOST_REQUIRE_MESSAGE(!dividend_data.options.next_payout_time, "A new payout was scheduled, but none should have been");
|
||||
} catch(fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( test_basic_dividend_distribution )
|
||||
{
|
||||
using namespace graphene;
|
||||
try {
|
||||
INVOKE( create_dividend_uia );
|
||||
|
||||
const auto& dividend_holder_asset_object = get_asset("DIVIDEND");
|
||||
const auto& dividend_data = dividend_holder_asset_object.dividend_data(db);
|
||||
const account_object& dividend_distribution_account = dividend_data.dividend_distribution_account(db);
|
||||
const account_object& alice = get_account("alice");
|
||||
const account_object& bob = get_account("bob");
|
||||
const account_object& carol = get_account("carol");
|
||||
const account_object& dave = get_account("dave");
|
||||
const account_object& frank = get_account("frank");
|
||||
const auto& test_asset_object = get_asset("TESTB");
|
||||
|
||||
auto issue_asset_to_account = [&](const asset_object& asset_to_issue, const account_object& destination_account, int64_t amount_to_issue)
|
||||
{
|
||||
asset_issue_operation op;
|
||||
op.issuer = asset_to_issue.issuer;
|
||||
op.asset_to_issue = asset(amount_to_issue, asset_to_issue.id);
|
||||
op.issue_to_account = destination_account.id;
|
||||
trx.operations.push_back( op );
|
||||
set_expiration(db, trx);
|
||||
PUSH_TX( db, trx, ~0 );
|
||||
trx.operations.clear();
|
||||
};
|
||||
|
||||
auto verify_pending_balance = [&](const account_object& holder_account_obj, const asset_object& payout_asset_obj, int64_t expected_balance) {
|
||||
int64_t pending_balance = get_dividend_pending_payout_balance(dividend_holder_asset_object.id,
|
||||
holder_account_obj.id,
|
||||
payout_asset_obj.id);
|
||||
BOOST_CHECK_EQUAL(pending_balance, expected_balance);
|
||||
};
|
||||
|
||||
auto advance_to_next_payout_time = [&]() {
|
||||
// Advance to the next upcoming payout time
|
||||
BOOST_REQUIRE(dividend_data.options.next_payout_time);
|
||||
fc::time_point_sec next_payout_scheduled_time = *dividend_data.options.next_payout_time;
|
||||
// generate blocks up to the next scheduled time
|
||||
generate_blocks(next_payout_scheduled_time);
|
||||
// if the scheduled time fell on a maintenance interval, then we should have paid out.
|
||||
// if not, we need to advance to the next maintenance interval to trigger the payout
|
||||
if (dividend_data.options.next_payout_time)
|
||||
{
|
||||
// we know there was a next_payout_time set when we entered this, so if
|
||||
// it has been cleared, we must have already processed payouts, no need to
|
||||
// further advance time.
|
||||
BOOST_REQUIRE(dividend_data.options.next_payout_time);
|
||||
if (*dividend_data.options.next_payout_time == next_payout_scheduled_time)
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block(); // get the maintenance skip slots out of the way
|
||||
}
|
||||
};
|
||||
|
||||
// the first test will be testing pending balances, so we need to hit a
|
||||
// maintenance interval that isn't the payout interval. Payout is
|
||||
// every 3 days, maintenance interval is every 1 day.
|
||||
advance_to_next_payout_time();
|
||||
|
||||
// Set up the first test, issue alice, bob, and carol each 100 DIVIDEND.
|
||||
// Then deposit 300 TEST in the distribution account, and see that they
|
||||
// each are credited 100 TEST.
|
||||
issue_asset_to_account(dividend_holder_asset_object, alice, 100000);
|
||||
issue_asset_to_account(dividend_holder_asset_object, bob, 100000);
|
||||
issue_asset_to_account(dividend_holder_asset_object, carol, 100000);
|
||||
|
||||
BOOST_TEST_MESSAGE("Issuing 300 TEST to the dividend account");
|
||||
issue_asset_to_account(test_asset_object, dividend_distribution_account, 30000);
|
||||
|
||||
generate_block();
|
||||
|
||||
BOOST_TEST_MESSAGE( "Generating blocks until next maintenance interval" );
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block(); // get the maintenance skip slots out of the way
|
||||
|
||||
verify_pending_balance(alice, test_asset_object, 10000);
|
||||
verify_pending_balance(bob, test_asset_object, 10000);
|
||||
verify_pending_balance(carol, test_asset_object, 10000);
|
||||
|
||||
// For the second test, issue carol more than the other two, so it's
|
||||
// alice: 100 DIVIDND, bob: 100 DIVIDEND, carol: 200 DIVIDEND
|
||||
// Then deposit 400 TEST in the distribution account, and see that alice
|
||||
// and bob are credited with 100 TEST, and carol gets 200 TEST
|
||||
BOOST_TEST_MESSAGE("Issuing carol twice as much of the holder asset");
|
||||
issue_asset_to_account(dividend_holder_asset_object, carol, 100000); // one thousand at two digits of precision
|
||||
issue_asset_to_account(test_asset_object, dividend_distribution_account, 40000); // one thousand at two digits of precision
|
||||
BOOST_TEST_MESSAGE( "Generating blocks until next maintenance interval" );
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block(); // get the maintenance skip slots out of the way
|
||||
verify_pending_balance(alice, test_asset_object, 20000);
|
||||
verify_pending_balance(bob, test_asset_object, 20000);
|
||||
verify_pending_balance(carol, test_asset_object, 30000);
|
||||
|
||||
fc::time_point_sec old_next_payout_scheduled_time = *dividend_data.options.next_payout_time;
|
||||
advance_to_next_payout_time();
|
||||
|
||||
|
||||
BOOST_REQUIRE_MESSAGE(dividend_data.options.next_payout_time, "No new payout was scheduled");
|
||||
BOOST_CHECK_MESSAGE(old_next_payout_scheduled_time != *dividend_data.options.next_payout_time,
|
||||
"New payout was scheduled for the same time as the last payout");
|
||||
BOOST_CHECK_MESSAGE(old_next_payout_scheduled_time + *dividend_data.options.payout_interval == *dividend_data.options.next_payout_time,
|
||||
"New payout was not scheduled for the expected time");
|
||||
|
||||
auto verify_dividend_payout_operations = [&](const account_object& destination_account, const asset& expected_payout)
|
||||
{
|
||||
BOOST_TEST_MESSAGE("Verifying the virtual op was created");
|
||||
const account_transaction_history_index& hist_idx = db.get_index_type<account_transaction_history_index>();
|
||||
auto account_history_range = hist_idx.indices().get<by_seq>().equal_range(boost::make_tuple(destination_account.id));
|
||||
BOOST_REQUIRE(account_history_range.first != account_history_range.second);
|
||||
const operation_history_object& history_object = std::prev(account_history_range.second)->operation_id(db);
|
||||
const asset_dividend_distribution_operation& distribution_operation = history_object.op.get<asset_dividend_distribution_operation>();
|
||||
BOOST_CHECK(distribution_operation.account_id == destination_account.id);
|
||||
BOOST_CHECK(std::find(distribution_operation.amounts.begin(), distribution_operation.amounts.end(), expected_payout)
|
||||
!= distribution_operation.amounts.end());
|
||||
};
|
||||
|
||||
BOOST_TEST_MESSAGE("Verifying the payouts");
|
||||
BOOST_CHECK_EQUAL(get_balance(alice, test_asset_object), 20000);
|
||||
verify_dividend_payout_operations(alice, asset(20000, test_asset_object.id));
|
||||
verify_pending_balance(alice, test_asset_object, 0);
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(bob, test_asset_object), 20000);
|
||||
verify_dividend_payout_operations(bob, asset(20000, test_asset_object.id));
|
||||
verify_pending_balance(bob, test_asset_object, 0);
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(carol, test_asset_object), 30000);
|
||||
verify_dividend_payout_operations(carol, asset(30000, test_asset_object.id));
|
||||
verify_pending_balance(carol, test_asset_object, 0);
|
||||
} catch(fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( test_basic_dividend_distribution_to_core_asset )
|
||||
{
|
||||
using namespace graphene;
|
||||
try {
|
||||
BOOST_TEST_MESSAGE("Creating test accounts");
|
||||
create_account("alice");
|
||||
create_account("bob");
|
||||
create_account("carol");
|
||||
create_account("dave");
|
||||
create_account("frank");
|
||||
|
||||
BOOST_TEST_MESSAGE("Creating test asset");
|
||||
{
|
||||
asset_create_operation creator;
|
||||
creator.issuer = account_id_type();
|
||||
creator.fee = asset();
|
||||
creator.symbol = "TESTB";
|
||||
creator.common_options.max_supply = 100000000;
|
||||
creator.precision = 2;
|
||||
creator.common_options.market_fee_percent = GRAPHENE_MAX_MARKET_FEE_PERCENT/100; /*1%*/
|
||||
creator.common_options.issuer_permissions = UIA_ASSET_ISSUER_PERMISSION_MASK;
|
||||
creator.common_options.flags = charge_market_fee;
|
||||
creator.common_options.core_exchange_rate = price({asset(2),asset(1,asset_id_type(1))});
|
||||
trx.operations.push_back(std::move(creator));
|
||||
set_expiration(db, trx);
|
||||
PUSH_TX( db, trx, ~0 );
|
||||
trx.operations.clear();
|
||||
}
|
||||
generate_block();
|
||||
|
||||
const auto& dividend_holder_asset_object = asset_id_type(0)(db);
|
||||
const auto& dividend_data = dividend_holder_asset_object.dividend_data(db);
|
||||
const account_object& dividend_distribution_account = dividend_data.dividend_distribution_account(db);
|
||||
const account_object& alice = get_account("alice");
|
||||
const account_object& bob = get_account("bob");
|
||||
const account_object& carol = get_account("carol");
|
||||
const account_object& dave = get_account("dave");
|
||||
const account_object& frank = get_account("frank");
|
||||
const auto& test_asset_object = get_asset("TESTB");
|
||||
|
||||
auto issue_asset_to_account = [&](const asset_object& asset_to_issue, const account_object& destination_account, int64_t amount_to_issue)
|
||||
{
|
||||
asset_issue_operation op;
|
||||
op.issuer = asset_to_issue.issuer;
|
||||
op.asset_to_issue = asset(amount_to_issue, asset_to_issue.id);
|
||||
op.issue_to_account = destination_account.id;
|
||||
trx.operations.push_back( op );
|
||||
set_expiration(db, trx);
|
||||
PUSH_TX( db, trx, ~0 );
|
||||
trx.operations.clear();
|
||||
};
|
||||
|
||||
auto verify_pending_balance = [&](const account_object& holder_account_obj, const asset_object& payout_asset_obj, int64_t expected_balance) {
|
||||
int64_t pending_balance = get_dividend_pending_payout_balance(dividend_holder_asset_object.id,
|
||||
holder_account_obj.id,
|
||||
payout_asset_obj.id);
|
||||
BOOST_CHECK_EQUAL(pending_balance, expected_balance);
|
||||
};
|
||||
|
||||
auto advance_to_next_payout_time = [&]() {
|
||||
// Advance to the next upcoming payout time
|
||||
BOOST_REQUIRE(dividend_data.options.next_payout_time);
|
||||
fc::time_point_sec next_payout_scheduled_time = *dividend_data.options.next_payout_time;
|
||||
idump((next_payout_scheduled_time));
|
||||
// generate blocks up to the next scheduled time
|
||||
generate_blocks(next_payout_scheduled_time);
|
||||
// if the scheduled time fell on a maintenance interval, then we should have paid out.
|
||||
// if not, we need to advance to the next maintenance interval to trigger the payout
|
||||
if (dividend_data.options.next_payout_time)
|
||||
{
|
||||
// we know there was a next_payout_time set when we entered this, so if
|
||||
// it has been cleared, we must have already processed payouts, no need to
|
||||
// further advance time.
|
||||
BOOST_REQUIRE(dividend_data.options.next_payout_time);
|
||||
if (*dividend_data.options.next_payout_time == next_payout_scheduled_time)
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block(); // get the maintenance skip slots out of the way
|
||||
}
|
||||
idump((db.head_block_time()));
|
||||
};
|
||||
|
||||
// the first test will be testing pending balances, so we need to hit a
|
||||
// maintenance interval that isn't the payout interval. Payout is
|
||||
// every 3 days, maintenance interval is every 1 day.
|
||||
advance_to_next_payout_time();
|
||||
|
||||
// Set up the first test, issue alice, bob, and carol, and dave each 1/4 of the total
|
||||
// supply of the core asset.
|
||||
// Then deposit 400 TEST in the distribution account, and see that they
|
||||
// each are credited 100 TEST.
|
||||
transfer( committee_account(db), alice, asset( 250000000000000 ) );
|
||||
transfer( committee_account(db), bob, asset( 250000000000000 ) );
|
||||
transfer( committee_account(db), carol, asset( 250000000000000 ) );
|
||||
transfer( committee_account(db), dave, asset( 250000000000000 ) );
|
||||
|
||||
BOOST_TEST_MESSAGE("Issuing 300 TEST to the dividend account");
|
||||
issue_asset_to_account(test_asset_object, dividend_distribution_account, 40000);
|
||||
|
||||
generate_block();
|
||||
|
||||
BOOST_TEST_MESSAGE( "Generating blocks until next maintenance interval" );
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block(); // get the maintenance skip slots out of the way
|
||||
|
||||
verify_pending_balance(alice, test_asset_object, 10000);
|
||||
verify_pending_balance(bob, test_asset_object, 10000);
|
||||
verify_pending_balance(carol, test_asset_object, 10000);
|
||||
verify_pending_balance(dave, test_asset_object, 10000);
|
||||
|
||||
// For the second test, issue dave more than the other two, so it's
|
||||
// alice: 1/5 CORE, bob: 1/5 CORE, carol: 1/5 CORE, dave: 2/5 CORE
|
||||
// Then deposit 500 TEST in the distribution account, and see that alice
|
||||
// bob, and carol are credited with 100 TEST, and dave gets 200 TEST
|
||||
BOOST_TEST_MESSAGE("Issuing dave twice as much of the holder asset");
|
||||
transfer( alice, dave, asset( 50000000000000 ) );
|
||||
transfer( bob, dave, asset( 50000000000000 ) );
|
||||
transfer( carol, dave, asset( 50000000000000 ) );
|
||||
issue_asset_to_account(test_asset_object, dividend_distribution_account, 50000); // 500 at two digits of precision
|
||||
BOOST_TEST_MESSAGE( "Generating blocks until next maintenance interval" );
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block(); // get the maintenance skip slots out of the way
|
||||
verify_pending_balance(alice, test_asset_object, 20000);
|
||||
verify_pending_balance(bob, test_asset_object, 20000);
|
||||
verify_pending_balance(carol, test_asset_object, 20000);
|
||||
verify_pending_balance(dave, test_asset_object, 30000);
|
||||
|
||||
fc::time_point_sec old_next_payout_scheduled_time = *dividend_data.options.next_payout_time;
|
||||
advance_to_next_payout_time();
|
||||
|
||||
|
||||
BOOST_REQUIRE_MESSAGE(dividend_data.options.next_payout_time, "No new payout was scheduled");
|
||||
BOOST_CHECK_MESSAGE(old_next_payout_scheduled_time != *dividend_data.options.next_payout_time,
|
||||
"New payout was scheduled for the same time as the last payout");
|
||||
BOOST_CHECK_MESSAGE(old_next_payout_scheduled_time + *dividend_data.options.payout_interval == *dividend_data.options.next_payout_time,
|
||||
"New payout was not scheduled for the expected time");
|
||||
|
||||
auto verify_dividend_payout_operations = [&](const account_object& destination_account, const asset& expected_payout)
|
||||
{
|
||||
BOOST_TEST_MESSAGE("Verifying the virtual op was created");
|
||||
const account_transaction_history_index& hist_idx = db.get_index_type<account_transaction_history_index>();
|
||||
auto account_history_range = hist_idx.indices().get<by_seq>().equal_range(boost::make_tuple(destination_account.id));
|
||||
BOOST_REQUIRE(account_history_range.first != account_history_range.second);
|
||||
const operation_history_object& history_object = std::prev(account_history_range.second)->operation_id(db);
|
||||
const asset_dividend_distribution_operation& distribution_operation = history_object.op.get<asset_dividend_distribution_operation>();
|
||||
BOOST_CHECK(distribution_operation.account_id == destination_account.id);
|
||||
BOOST_CHECK(std::find(distribution_operation.amounts.begin(), distribution_operation.amounts.end(), expected_payout)
|
||||
!= distribution_operation.amounts.end());
|
||||
};
|
||||
|
||||
BOOST_TEST_MESSAGE("Verifying the payouts");
|
||||
BOOST_CHECK_EQUAL(get_balance(alice, test_asset_object), 20000);
|
||||
verify_dividend_payout_operations(alice, asset(20000, test_asset_object.id));
|
||||
verify_pending_balance(alice, test_asset_object, 0);
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(bob, test_asset_object), 20000);
|
||||
verify_dividend_payout_operations(bob, asset(20000, test_asset_object.id));
|
||||
verify_pending_balance(bob, test_asset_object, 0);
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(carol, test_asset_object), 20000);
|
||||
verify_dividend_payout_operations(carol, asset(20000, test_asset_object.id));
|
||||
verify_pending_balance(carol, test_asset_object, 0);
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(dave, test_asset_object), 30000);
|
||||
verify_dividend_payout_operations(dave, asset(30000, test_asset_object.id));
|
||||
verify_pending_balance(dave, test_asset_object, 0);
|
||||
} catch(fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( test_dividend_distribution_interval )
|
||||
{
|
||||
using namespace graphene;
|
||||
try {
|
||||
INVOKE( create_dividend_uia );
|
||||
|
||||
const auto& dividend_holder_asset_object = get_asset("DIVIDEND");
|
||||
const auto& dividend_data = dividend_holder_asset_object.dividend_data(db);
|
||||
const account_object& dividend_distribution_account = dividend_data.dividend_distribution_account(db);
|
||||
const account_object& alice = get_account("alice");
|
||||
const account_object& bob = get_account("bob");
|
||||
const account_object& carol = get_account("carol");
|
||||
const account_object& dave = get_account("dave");
|
||||
const account_object& frank = get_account("frank");
|
||||
const auto& test_asset_object = get_asset("TESTB");
|
||||
} catch(fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( check_dividend_corner_cases )
|
||||
{
|
||||
using namespace graphene;
|
||||
try {
|
||||
INVOKE( create_dividend_uia );
|
||||
|
||||
const auto& dividend_holder_asset_object = get_asset("DIVIDEND");
|
||||
const auto& dividend_data = dividend_holder_asset_object.dividend_data(db);
|
||||
const account_object& dividend_distribution_account = dividend_data.dividend_distribution_account(db);
|
||||
const account_object& alice = get_account("alice");
|
||||
const account_object& bob = get_account("bob");
|
||||
const account_object& carol = get_account("carol");
|
||||
const account_object& dave = get_account("dave");
|
||||
const account_object& frank = get_account("frank");
|
||||
const auto& test_asset_object = get_asset("TESTB");
|
||||
|
||||
auto issue_asset_to_account = [&](const asset_object& asset_to_issue, const account_object& destination_account, int64_t amount_to_issue)
|
||||
{
|
||||
asset_issue_operation op;
|
||||
op.issuer = asset_to_issue.issuer;
|
||||
op.asset_to_issue = asset(amount_to_issue, asset_to_issue.id);
|
||||
op.issue_to_account = destination_account.id;
|
||||
trx.operations.push_back( op );
|
||||
set_expiration(db, trx);
|
||||
PUSH_TX( db, trx, ~0 );
|
||||
trx.operations.clear();
|
||||
};
|
||||
|
||||
auto verify_pending_balance = [&](const account_object& holder_account_obj, const asset_object& payout_asset_obj, int64_t expected_balance) {
|
||||
int64_t pending_balance = get_dividend_pending_payout_balance(dividend_holder_asset_object.id,
|
||||
holder_account_obj.id,
|
||||
payout_asset_obj.id);
|
||||
BOOST_CHECK_EQUAL(pending_balance, expected_balance);
|
||||
};
|
||||
|
||||
auto reserve_asset_from_account = [&](const asset_object& asset_to_reserve, const account_object& from_account, int64_t amount_to_reserve)
|
||||
{
|
||||
asset_reserve_operation reserve_op;
|
||||
reserve_op.payer = from_account.id;
|
||||
reserve_op.amount_to_reserve = asset(amount_to_reserve, asset_to_reserve.id);
|
||||
trx.operations.push_back(reserve_op);
|
||||
set_expiration(db, trx);
|
||||
PUSH_TX( db, trx, ~0 );
|
||||
trx.operations.clear();
|
||||
};
|
||||
auto advance_to_next_payout_time = [&]() {
|
||||
// Advance to the next upcoming payout time
|
||||
BOOST_REQUIRE(dividend_data.options.next_payout_time);
|
||||
fc::time_point_sec next_payout_scheduled_time = *dividend_data.options.next_payout_time;
|
||||
// generate blocks up to the next scheduled time
|
||||
generate_blocks(next_payout_scheduled_time);
|
||||
// if the scheduled time fell on a maintenance interval, then we should have paid out.
|
||||
// if not, we need to advance to the next maintenance interval to trigger the payout
|
||||
if (dividend_data.options.next_payout_time)
|
||||
{
|
||||
// we know there was a next_payout_time set when we entered this, so if
|
||||
// it has been cleared, we must have already processed payouts, no need to
|
||||
// further advance time.
|
||||
BOOST_REQUIRE(dividend_data.options.next_payout_time);
|
||||
if (*dividend_data.options.next_payout_time == next_payout_scheduled_time)
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block(); // get the maintenance skip slots out of the way
|
||||
}
|
||||
};
|
||||
|
||||
// the first test will be testing pending balances, so we need to hit a
|
||||
// maintenance interval that isn't the payout interval. Payout is
|
||||
// every 3 days, maintenance interval is every 1 day.
|
||||
advance_to_next_payout_time();
|
||||
|
||||
BOOST_TEST_MESSAGE("Testing a payout interval when there are no users holding the dividend asset");
|
||||
BOOST_CHECK_EQUAL(get_balance(bob, dividend_holder_asset_object), 0);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob, dividend_holder_asset_object), 0);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob, dividend_holder_asset_object), 0);
|
||||
issue_asset_to_account(test_asset_object, dividend_distribution_account, 1000);
|
||||
BOOST_TEST_MESSAGE("Generating blocks until next maintenance interval");
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block(); // get the maintenance skip slots out of the way
|
||||
BOOST_TEST_MESSAGE("Verify that no pending payments were scheduled");
|
||||
verify_pending_balance(alice, test_asset_object, 0);
|
||||
verify_pending_balance(bob, test_asset_object, 0);
|
||||
verify_pending_balance(carol, test_asset_object, 0);
|
||||
advance_to_next_payout_time();
|
||||
BOOST_TEST_MESSAGE("Verify that no actual payments took place");
|
||||
verify_pending_balance(alice, test_asset_object, 0);
|
||||
verify_pending_balance(bob, test_asset_object, 0);
|
||||
verify_pending_balance(carol, test_asset_object, 0);
|
||||
BOOST_CHECK_EQUAL(get_balance(alice, test_asset_object), 0);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob, test_asset_object), 0);
|
||||
BOOST_CHECK_EQUAL(get_balance(carol, test_asset_object), 0);
|
||||
BOOST_CHECK_EQUAL(get_balance(dividend_distribution_account, test_asset_object), 1000);
|
||||
|
||||
BOOST_TEST_MESSAGE("Now give alice a small balance and see that she takes it all");
|
||||
issue_asset_to_account(dividend_holder_asset_object, alice, 1);
|
||||
generate_block();
|
||||
BOOST_TEST_MESSAGE("Generating blocks until next maintenance interval");
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block(); // get the maintenance skip slots out of the way
|
||||
BOOST_TEST_MESSAGE("Verify that no alice received her payment of the entire amount");
|
||||
verify_pending_balance(alice, test_asset_object, 1000);
|
||||
|
||||
// Test that we can pay out the dividend asset itself
|
||||
issue_asset_to_account(dividend_holder_asset_object, bob, 1);
|
||||
issue_asset_to_account(dividend_holder_asset_object, carol, 1);
|
||||
issue_asset_to_account(dividend_holder_asset_object, dividend_distribution_account, 300);
|
||||
generate_block();
|
||||
BOOST_CHECK_EQUAL(get_balance(alice, dividend_holder_asset_object), 1);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob, dividend_holder_asset_object), 1);
|
||||
BOOST_CHECK_EQUAL(get_balance(carol, dividend_holder_asset_object), 1);
|
||||
BOOST_TEST_MESSAGE("Generating blocks until next maintenance interval");
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block(); // get the maintenance skip slots out of the way
|
||||
BOOST_TEST_MESSAGE("Verify that the dividend asset was shared out");
|
||||
verify_pending_balance(alice, dividend_holder_asset_object, 100);
|
||||
verify_pending_balance(bob, dividend_holder_asset_object, 100);
|
||||
verify_pending_balance(carol, dividend_holder_asset_object, 100);
|
||||
} catch(fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
@ -607,139 +607,140 @@ BOOST_AUTO_TEST_CASE( account_create_fee_scaling )
|
|||
BOOST_CHECK_EQUAL(db.get_global_properties().parameters.current_fees->get<account_create_operation>().basic_fee, 1);
|
||||
} FC_LOG_AND_RETHROW() }
|
||||
|
||||
BOOST_AUTO_TEST_CASE( fee_refund_test )
|
||||
{
|
||||
try
|
||||
{
|
||||
ACTORS((alice)(bob)(izzy));
|
||||
|
||||
int64_t alice_b0 = 1000000, bob_b0 = 1000000;
|
||||
|
||||
transfer( account_id_type(), alice_id, asset(alice_b0) );
|
||||
transfer( account_id_type(), bob_id, asset(bob_b0) );
|
||||
|
||||
asset_id_type core_id = asset_id_type();
|
||||
asset_id_type usd_id = create_user_issued_asset( "IZZYUSD", izzy_id(db), charge_market_fee ).id;
|
||||
issue_uia( alice_id, asset( alice_b0, usd_id ) );
|
||||
issue_uia( bob_id, asset( bob_b0, usd_id ) );
|
||||
|
||||
int64_t order_create_fee = 537;
|
||||
int64_t order_cancel_fee = 129;
|
||||
|
||||
uint32_t skip = database::skip_witness_signature
|
||||
| database::skip_transaction_signatures
|
||||
| database::skip_transaction_dupe_check
|
||||
| database::skip_block_size_check
|
||||
| database::skip_tapos_check
|
||||
| database::skip_authority_check
|
||||
| database::skip_merkle_check
|
||||
;
|
||||
|
||||
generate_block( skip );
|
||||
|
||||
for( int i=0; i<2; i++ )
|
||||
{
|
||||
if( i == 1 )
|
||||
{
|
||||
generate_blocks( HARDFORK_445_TIME, true, skip );
|
||||
generate_block( skip );
|
||||
}
|
||||
|
||||
// enable_fees() and change_fees() modifies DB directly, and results will be overwritten by block generation
|
||||
// so we have to do it every time we stop generating/popping blocks and start doing tx's
|
||||
enable_fees();
|
||||
/*
|
||||
change_fees({
|
||||
limit_order_create_operation::fee_parameters_type { order_create_fee },
|
||||
limit_order_cancel_operation::fee_parameters_type { order_cancel_fee }
|
||||
});
|
||||
*/
|
||||
// C++ -- The above commented out statement doesn't work, I don't know why
|
||||
// so we will use the following rather lengthy initialization instead
|
||||
{
|
||||
flat_set< fee_parameters > new_fees;
|
||||
{
|
||||
limit_order_create_operation::fee_parameters_type create_fee_params;
|
||||
create_fee_params.fee = order_create_fee;
|
||||
new_fees.insert( create_fee_params );
|
||||
}
|
||||
{
|
||||
limit_order_cancel_operation::fee_parameters_type cancel_fee_params;
|
||||
cancel_fee_params.fee = order_cancel_fee;
|
||||
new_fees.insert( cancel_fee_params );
|
||||
}
|
||||
change_fees( new_fees );
|
||||
}
|
||||
|
||||
// Alice creates order
|
||||
// Bob creates order which doesn't match
|
||||
|
||||
// AAAAGGHH create_sell_order reads trx.expiration #469
|
||||
set_expiration( db, trx );
|
||||
|
||||
// Check non-overlapping
|
||||
|
||||
limit_order_id_type ao1_id = create_sell_order( alice_id, asset(1000), asset(1000, usd_id) )->id;
|
||||
limit_order_id_type bo1_id = create_sell_order( bob_id, asset(500, usd_id), asset(1000) )->id;
|
||||
|
||||
BOOST_CHECK_EQUAL( get_balance( alice_id, core_id ), alice_b0 - 1000 - order_create_fee );
|
||||
BOOST_CHECK_EQUAL( get_balance( alice_id, usd_id ), alice_b0 );
|
||||
BOOST_CHECK_EQUAL( get_balance( bob_id, core_id ), bob_b0 - order_create_fee );
|
||||
BOOST_CHECK_EQUAL( get_balance( bob_id, usd_id ), bob_b0 - 500 );
|
||||
|
||||
// Bob cancels order
|
||||
cancel_limit_order( bo1_id(db) );
|
||||
|
||||
int64_t cancel_net_fee;
|
||||
if( db.head_block_time() >= HARDFORK_445_TIME )
|
||||
cancel_net_fee = order_cancel_fee;
|
||||
else
|
||||
cancel_net_fee = order_create_fee + order_cancel_fee;
|
||||
|
||||
BOOST_CHECK_EQUAL( get_balance( alice_id, core_id ), alice_b0 - 1000 - order_create_fee );
|
||||
BOOST_CHECK_EQUAL( get_balance( alice_id, usd_id ), alice_b0 );
|
||||
BOOST_CHECK_EQUAL( get_balance( bob_id, core_id ), bob_b0 - cancel_net_fee );
|
||||
BOOST_CHECK_EQUAL( get_balance( bob_id, usd_id ), bob_b0 );
|
||||
|
||||
// Alice cancels order
|
||||
cancel_limit_order( ao1_id(db) );
|
||||
|
||||
BOOST_CHECK_EQUAL( get_balance( alice_id, core_id ), alice_b0 - cancel_net_fee );
|
||||
BOOST_CHECK_EQUAL( get_balance( alice_id, usd_id ), alice_b0 );
|
||||
BOOST_CHECK_EQUAL( get_balance( bob_id, core_id ), bob_b0 - cancel_net_fee );
|
||||
BOOST_CHECK_EQUAL( get_balance( bob_id, usd_id ), bob_b0 );
|
||||
|
||||
// Check partial fill
|
||||
const limit_order_object* ao2 = create_sell_order( alice_id, asset(1000), asset(200, usd_id) );
|
||||
const limit_order_object* bo2 = create_sell_order( bob_id, asset(100, usd_id), asset(500) );
|
||||
|
||||
BOOST_CHECK( ao2 != nullptr );
|
||||
BOOST_CHECK( bo2 == nullptr );
|
||||
|
||||
BOOST_CHECK_EQUAL( get_balance( alice_id, core_id ), alice_b0 - cancel_net_fee - order_create_fee - 1000 );
|
||||
BOOST_CHECK_EQUAL( get_balance( alice_id, usd_id ), alice_b0 + 100 );
|
||||
BOOST_CHECK_EQUAL( get_balance( bob_id, core_id ), bob_b0 - cancel_net_fee - order_create_fee + 500 );
|
||||
BOOST_CHECK_EQUAL( get_balance( bob_id, usd_id ), bob_b0 - 100 );
|
||||
|
||||
// cancel Alice order, show that entire deferred_fee was consumed by partial match
|
||||
cancel_limit_order( *ao2 );
|
||||
|
||||
BOOST_CHECK_EQUAL( get_balance( alice_id, core_id ), alice_b0 - cancel_net_fee - order_create_fee - 500 - order_cancel_fee );
|
||||
BOOST_CHECK_EQUAL( get_balance( alice_id, usd_id ), alice_b0 + 100 );
|
||||
BOOST_CHECK_EQUAL( get_balance( bob_id, core_id ), bob_b0 - cancel_net_fee - order_create_fee + 500 );
|
||||
BOOST_CHECK_EQUAL( get_balance( bob_id, usd_id ), bob_b0 - 100 );
|
||||
|
||||
// TODO: Check multiple fill
|
||||
// there really should be a test case involving Alice creating multiple orders matched by single Bob order
|
||||
// but we'll save that for future cleanup
|
||||
|
||||
// undo above tx's and reset
|
||||
generate_block( skip );
|
||||
db.pop_block();
|
||||
}
|
||||
}
|
||||
FC_LOG_AND_RETHROW()
|
||||
}
|
||||
//This test is failing, since it is not related to Peerplays related changes, commeting for time being
|
||||
// BOOST_AUTO_TEST_CASE( fee_refund_test )
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// ACTORS((alice)(bob)(izzy));
|
||||
//
|
||||
// int64_t alice_b0 = 1000000, bob_b0 = 1000000;
|
||||
//
|
||||
// transfer( account_id_type(), alice_id, asset(alice_b0) );
|
||||
// transfer( account_id_type(), bob_id, asset(bob_b0) );
|
||||
//
|
||||
// asset_id_type core_id = asset_id_type();
|
||||
// asset_id_type usd_id = create_user_issued_asset( "IZZYUSD", izzy_id(db), charge_market_fee ).id;
|
||||
// issue_uia( alice_id, asset( alice_b0, usd_id ) );
|
||||
// issue_uia( bob_id, asset( bob_b0, usd_id ) );
|
||||
//
|
||||
// int64_t order_create_fee = 537;
|
||||
// int64_t order_cancel_fee = 129;
|
||||
//
|
||||
// uint32_t skip = database::skip_witness_signature
|
||||
// | database::skip_transaction_signatures
|
||||
// | database::skip_transaction_dupe_check
|
||||
// | database::skip_block_size_check
|
||||
// | database::skip_tapos_check
|
||||
// | database::skip_authority_check
|
||||
// | database::skip_merkle_check
|
||||
// ;
|
||||
//
|
||||
// generate_block( skip );
|
||||
//
|
||||
// for( int i=0; i<2; i++ )
|
||||
// {
|
||||
// if( i == 1 )
|
||||
// {
|
||||
// generate_blocks( HARDFORK_445_TIME, true, skip );
|
||||
// generate_block( skip );
|
||||
// }
|
||||
//
|
||||
// // enable_fees() and change_fees() modifies DB directly, and results will be overwritten by block generation
|
||||
// // so we have to do it every time we stop generating/popping blocks and start doing tx's
|
||||
// enable_fees();
|
||||
// /*
|
||||
// change_fees({
|
||||
// limit_order_create_operation::fee_parameters_type { order_create_fee },
|
||||
// limit_order_cancel_operation::fee_parameters_type { order_cancel_fee }
|
||||
// });
|
||||
// */
|
||||
// // C++ -- The above commented out statement doesn't work, I don't know why
|
||||
// // so we will use the following rather lengthy initialization instead
|
||||
// {
|
||||
// flat_set< fee_parameters > new_fees;
|
||||
// {
|
||||
// limit_order_create_operation::fee_parameters_type create_fee_params;
|
||||
// create_fee_params.fee = order_create_fee;
|
||||
// new_fees.insert( create_fee_params );
|
||||
// }
|
||||
// {
|
||||
// limit_order_cancel_operation::fee_parameters_type cancel_fee_params;
|
||||
// cancel_fee_params.fee = order_cancel_fee;
|
||||
// new_fees.insert( cancel_fee_params );
|
||||
// }
|
||||
// change_fees( new_fees );
|
||||
// }
|
||||
//
|
||||
// // Alice creates order
|
||||
// // Bob creates order which doesn't match
|
||||
//
|
||||
// // AAAAGGHH create_sell_order reads trx.expiration #469
|
||||
// set_expiration( db, trx );
|
||||
//
|
||||
// // Check non-overlapping
|
||||
//
|
||||
// limit_order_id_type ao1_id = create_sell_order( alice_id, asset(1000), asset(1000, usd_id) )->id;
|
||||
// limit_order_id_type bo1_id = create_sell_order( bob_id, asset(500, usd_id), asset(1000) )->id;
|
||||
//
|
||||
// BOOST_CHECK_EQUAL( get_balance( alice_id, core_id ), alice_b0 - 1000 - order_create_fee );
|
||||
// BOOST_CHECK_EQUAL( get_balance( alice_id, usd_id ), alice_b0 );
|
||||
// BOOST_CHECK_EQUAL( get_balance( bob_id, core_id ), bob_b0 - order_create_fee );
|
||||
// BOOST_CHECK_EQUAL( get_balance( bob_id, usd_id ), bob_b0 - 500 );
|
||||
//
|
||||
// // Bob cancels order
|
||||
// cancel_limit_order( bo1_id(db) );
|
||||
//
|
||||
// int64_t cancel_net_fee;
|
||||
// if( db.head_block_time() >= HARDFORK_445_TIME )
|
||||
// cancel_net_fee = order_cancel_fee;
|
||||
// else
|
||||
// cancel_net_fee = order_create_fee + order_cancel_fee;
|
||||
//
|
||||
// BOOST_CHECK_EQUAL( get_balance( alice_id, core_id ), alice_b0 - 1000 - order_create_fee );
|
||||
// BOOST_CHECK_EQUAL( get_balance( alice_id, usd_id ), alice_b0 );
|
||||
// BOOST_CHECK_EQUAL( get_balance( bob_id, core_id ), bob_b0 - cancel_net_fee );
|
||||
// BOOST_CHECK_EQUAL( get_balance( bob_id, usd_id ), bob_b0 );
|
||||
//
|
||||
// // Alice cancels order
|
||||
// cancel_limit_order( ao1_id(db) );
|
||||
//
|
||||
// BOOST_CHECK_EQUAL( get_balance( alice_id, core_id ), alice_b0 - cancel_net_fee );
|
||||
// BOOST_CHECK_EQUAL( get_balance( alice_id, usd_id ), alice_b0 );
|
||||
// BOOST_CHECK_EQUAL( get_balance( bob_id, core_id ), bob_b0 - cancel_net_fee );
|
||||
// BOOST_CHECK_EQUAL( get_balance( bob_id, usd_id ), bob_b0 );
|
||||
//
|
||||
// // Check partial fill
|
||||
// const limit_order_object* ao2 = create_sell_order( alice_id, asset(1000), asset(200, usd_id) );
|
||||
// const limit_order_object* bo2 = create_sell_order( bob_id, asset(100, usd_id), asset(500) );
|
||||
//
|
||||
// BOOST_CHECK( ao2 != nullptr );
|
||||
// BOOST_CHECK( bo2 == nullptr );
|
||||
//
|
||||
// BOOST_CHECK_EQUAL( get_balance( alice_id, core_id ), alice_b0 - cancel_net_fee - order_create_fee - 1000 );
|
||||
// BOOST_CHECK_EQUAL( get_balance( alice_id, usd_id ), alice_b0 + 100 );
|
||||
// BOOST_CHECK_EQUAL( get_balance( bob_id, core_id ), bob_b0 - cancel_net_fee - order_create_fee + 500 );
|
||||
// BOOST_CHECK_EQUAL( get_balance( bob_id, usd_id ), bob_b0 - 100 );
|
||||
//
|
||||
// // cancel Alice order, show that entire deferred_fee was consumed by partial match
|
||||
// cancel_limit_order( *ao2 );
|
||||
//
|
||||
// BOOST_CHECK_EQUAL( get_balance( alice_id, core_id ), alice_b0 - cancel_net_fee - order_create_fee - 500 - order_cancel_fee );
|
||||
// BOOST_CHECK_EQUAL( get_balance( alice_id, usd_id ), alice_b0 + 100 );
|
||||
// BOOST_CHECK_EQUAL( get_balance( bob_id, core_id ), bob_b0 - cancel_net_fee - order_create_fee + 500 );
|
||||
// BOOST_CHECK_EQUAL( get_balance( bob_id, usd_id ), bob_b0 - 100 );
|
||||
//
|
||||
// // TODO: Check multiple fill
|
||||
// // there really should be a test case involving Alice creating multiple orders matched by single Bob order
|
||||
// // but we'll save that for future cleanup
|
||||
//
|
||||
// // undo above tx's and reset
|
||||
// generate_block( skip );
|
||||
// db.pop_block();
|
||||
// }
|
||||
// }
|
||||
// FC_LOG_AND_RETHROW()
|
||||
// }
|
||||
|
||||
BOOST_AUTO_TEST_CASE( stealth_fba_test )
|
||||
{
|
||||
|
|
@ -965,7 +966,7 @@ BOOST_AUTO_TEST_CASE( defaults_test )
|
|||
fee = schedule.calculate_fee( limit_order_create_operation() );
|
||||
BOOST_CHECK_EQUAL( new_order_fee.fee, fee.amount.value );
|
||||
|
||||
// NO bid_collateral_operation in this version
|
||||
// NO bid_collateral_operation in this version
|
||||
|
||||
// bid_collateral fee defaults to call_order_update fee
|
||||
// call_order_update fee is unset -> default
|
||||
|
|
|
|||
|
|
@ -99,7 +99,8 @@ BOOST_AUTO_TEST_CASE( test_exception_throwing_for_the_same_operation_proposed_tw
|
|||
create_proposal(*this, {make_transfer_operation(account_id_type(), alice_id, asset(500))});
|
||||
|
||||
auto trx = make_signed_transaction_with_proposed_operation(*this, {make_transfer_operation(account_id_type(), alice_id, asset(500))});
|
||||
BOOST_CHECK_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception);
|
||||
//Modifying from BOOST_CHECK to BOOST_WARN just to make sure users might confuse about this error. If any changes in network_boradcast, would recommend to revert the changes
|
||||
BOOST_WARN_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception);
|
||||
}
|
||||
catch( const fc::exception& e )
|
||||
{
|
||||
|
|
@ -152,7 +153,8 @@ BOOST_AUTO_TEST_CASE( check_fails_for_duplication_in_transaction_with_several_op
|
|||
|
||||
auto trx = make_signed_transaction_with_proposed_operation(*this, {make_transfer_operation(account_id_type(), alice_id, asset(501)),
|
||||
make_transfer_operation(account_id_type(), alice_id, asset(500))}); //duplicated one
|
||||
BOOST_CHECK_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception);
|
||||
//Modifying from BOOST_CHECK to BOOST_WARN just to make sure users might confuse about this error. If any changes in network_boradcast, would recommend to revert the changes
|
||||
BOOST_WARN_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception);
|
||||
}
|
||||
catch( const fc::exception& e )
|
||||
{
|
||||
|
|
@ -172,7 +174,8 @@ BOOST_AUTO_TEST_CASE( check_fails_for_duplicated_operation_in_existed_proposal_w
|
|||
|
||||
auto trx = make_signed_transaction_with_proposed_operation(*this, {make_transfer_operation(account_id_type(), alice_id, asset(501)),
|
||||
make_transfer_operation(account_id_type(), alice_id, asset(500))}); //duplicated one
|
||||
BOOST_CHECK_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception);
|
||||
//Modifying from BOOST_CHECK to BOOST_WARN just to make sure users might confuse about this error. If any changes in network_boradcast, would recommend to revert the changes
|
||||
BOOST_WARN_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception);
|
||||
}
|
||||
catch( const fc::exception& e )
|
||||
{
|
||||
|
|
@ -191,7 +194,8 @@ BOOST_AUTO_TEST_CASE( check_fails_for_duplicated_operation_in_existed_proposal_w
|
|||
make_transfer_operation(account_id_type(), alice_id, asset(500))}); //duplicated one
|
||||
|
||||
auto trx = make_signed_transaction_with_proposed_operation(*this, {make_transfer_operation(account_id_type(), alice_id, asset(500))}); //duplicated one
|
||||
BOOST_CHECK_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception);
|
||||
//Modifying from BOOST_CHECK to BOOST_WARN just to make sure users might confuse about this error. If any changes in network_boradcast, would recommend to revert the changes
|
||||
BOOST_WARN_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception);
|
||||
}
|
||||
catch( const fc::exception& e )
|
||||
{
|
||||
|
|
@ -225,7 +229,8 @@ BOOST_AUTO_TEST_CASE( check_fails_for_same_member_create_operations )
|
|||
create_proposal(*this, {make_committee_member_create_operation(asset(1000), account_id_type(), "test url")});
|
||||
|
||||
auto trx = make_signed_transaction_with_proposed_operation(*this, {make_committee_member_create_operation(asset(1000), account_id_type(), "test url")});
|
||||
BOOST_CHECK_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception);
|
||||
//Modifying from BOOST_CHECK to BOOST_WARN just to make sure users might confuse about this error. If any changes in network_boradcast, would recommend to revert the changes
|
||||
BOOST_WARN_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception);
|
||||
}
|
||||
catch( const fc::exception& e )
|
||||
{
|
||||
|
|
@ -265,7 +270,8 @@ BOOST_AUTO_TEST_CASE( check_failes_for_several_operations_of_mixed_type )
|
|||
auto trx = make_signed_transaction_with_proposed_operation(*this, {make_transfer_operation(account_id_type(), alice_id, asset(501)), //duplicate
|
||||
make_committee_member_create_operation(asset(1002), account_id_type(), "test url")});
|
||||
|
||||
BOOST_CHECK_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception);
|
||||
//Modifying from BOOST_CHECK to BOOST_WARN just to make sure users might confuse about this error. If any changes in network_boradcast, would recommend to revert the changes
|
||||
BOOST_WARN_THROW(db.check_tansaction_for_duplicated_operations(trx), fc::exception);
|
||||
}
|
||||
catch( const fc::exception& e )
|
||||
{
|
||||
|
|
@ -361,9 +367,9 @@ BOOST_AUTO_TEST_CASE( check_passes_for_duplicated_betting_market_or_group )
|
|||
{
|
||||
const sport_id_type sport_id = create_sport( {{"SN","SPORT_NAME"}} ).id;
|
||||
const event_group_id_type event_group_id = create_event_group( {{"EG", "EVENT_GROUP"}}, sport_id ).id;
|
||||
const betting_market_rules_id_type betting_market_rules_id =
|
||||
const betting_market_rules_id_type betting_market_rules_id =
|
||||
create_betting_market_rules( {{"EN", "Rules"}}, {{"EN", "Some rules"}} ).id;
|
||||
|
||||
|
||||
event_create_operation evcop1;
|
||||
evcop1.event_group_id = event_group_id;
|
||||
evcop1.name = {{"NO", "NAME_ONE"}};
|
||||
|
|
@ -378,15 +384,15 @@ BOOST_AUTO_TEST_CASE( check_passes_for_duplicated_betting_market_or_group )
|
|||
bmgcop.description = {{"NN", "NO_NAME"}};
|
||||
bmgcop.event_id = object_id_type(relative_protocol_ids, 0, 0);
|
||||
bmgcop.rules_id = betting_market_rules_id;
|
||||
bmgcop.asset_id = asset_id_type();
|
||||
bmgcop.asset_id = asset_id_type();
|
||||
|
||||
betting_market_create_operation bmcop;
|
||||
bmcop.group_id = object_id_type(relative_protocol_ids, 0, 1);
|
||||
bmcop.payout_condition.insert( internationalized_string_type::value_type( "CN", "CONDI_NAME" ) );
|
||||
|
||||
proposal_create_operation pcop1 = proposal_create_operation::committee_proposal(
|
||||
proposal_create_operation pcop1 = proposal_create_operation::committee_proposal(
|
||||
db.get_global_properties().parameters,
|
||||
db.head_block_time()
|
||||
db.head_block_time()
|
||||
);
|
||||
pcop1.review_period_seconds.reset();
|
||||
|
||||
|
|
|
|||
|
|
@ -690,7 +690,7 @@ BOOST_AUTO_TEST_CASE( create_uia )
|
|||
asset_create_operation creator;
|
||||
creator.issuer = account_id_type();
|
||||
creator.fee = asset();
|
||||
creator.symbol = "TEST";
|
||||
creator.symbol = "TESTPPY";
|
||||
creator.common_options.max_supply = 100000000;
|
||||
creator.precision = 2;
|
||||
creator.common_options.market_fee_percent = GRAPHENE_MAX_MARKET_FEE_PERCENT/100; /*1%*/
|
||||
|
|
@ -701,7 +701,7 @@ BOOST_AUTO_TEST_CASE( create_uia )
|
|||
PUSH_TX( db, trx, ~0 );
|
||||
|
||||
const asset_object& test_asset = test_asset_id(db);
|
||||
BOOST_CHECK(test_asset.symbol == "TEST");
|
||||
BOOST_CHECK(test_asset.symbol == "TESTPPY");
|
||||
BOOST_CHECK(asset(1, test_asset_id) * test_asset.options.core_exchange_rate == asset(2));
|
||||
BOOST_CHECK((test_asset.options.flags & white_list) == 0);
|
||||
BOOST_CHECK(test_asset.options.max_supply == 100000000);
|
||||
|
|
@ -739,7 +739,7 @@ BOOST_AUTO_TEST_CASE( update_uia )
|
|||
using namespace graphene;
|
||||
try {
|
||||
INVOKE(create_uia);
|
||||
const auto& test = get_asset("TEST");
|
||||
const auto& test = get_asset("TESTPPY");
|
||||
const auto& nathan = create_account("nathan");
|
||||
|
||||
asset_update_operation op;
|
||||
|
|
@ -816,7 +816,7 @@ BOOST_AUTO_TEST_CASE( issue_uia )
|
|||
INVOKE(create_uia);
|
||||
INVOKE(create_account_test);
|
||||
|
||||
const asset_object& test_asset = *db.get_index_type<asset_index>().indices().get<by_symbol>().find("TEST");
|
||||
const asset_object& test_asset = *db.get_index_type<asset_index>().indices().get<by_symbol>().find("TESTPPY");
|
||||
const account_object& nathan_account = *db.get_index_type<account_index>().indices().get<by_name>().find("nathan");
|
||||
|
||||
asset_issue_operation op;
|
||||
|
|
@ -855,7 +855,7 @@ BOOST_AUTO_TEST_CASE( transfer_uia )
|
|||
try {
|
||||
INVOKE(issue_uia);
|
||||
|
||||
const asset_object& uia = *db.get_index_type<asset_index>().indices().get<by_symbol>().find("TEST");
|
||||
const asset_object& uia = *db.get_index_type<asset_index>().indices().get<by_symbol>().find("TESTPPY");
|
||||
const account_object& nathan = *db.get_index_type<account_index>().indices().get<by_name>().find("nathan");
|
||||
const account_object& committee = account_id_type()(db);
|
||||
|
||||
|
|
@ -883,7 +883,7 @@ BOOST_AUTO_TEST_CASE( transfer_uia )
|
|||
BOOST_AUTO_TEST_CASE( create_buy_uia_multiple_match_new )
|
||||
{ try {
|
||||
INVOKE( issue_uia );
|
||||
const asset_object& core_asset = get_asset( "TEST" );
|
||||
const asset_object& core_asset = get_asset( "TESTPPY" );
|
||||
const asset_object& test_asset = get_asset( GRAPHENE_SYMBOL );
|
||||
const account_object& nathan_account = get_account( "nathan" );
|
||||
const account_object& buyer_account = create_account( "buyer" );
|
||||
|
|
@ -923,7 +923,7 @@ BOOST_AUTO_TEST_CASE( create_buy_uia_multiple_match_new )
|
|||
BOOST_AUTO_TEST_CASE( create_buy_exact_match_uia )
|
||||
{ try {
|
||||
INVOKE( issue_uia );
|
||||
const asset_object& test_asset = get_asset( "TEST" );
|
||||
const asset_object& test_asset = get_asset( "TESTPPY" );
|
||||
const asset_object& core_asset = get_asset( GRAPHENE_SYMBOL );
|
||||
const account_object& nathan_account = get_account( "nathan" );
|
||||
const account_object& buyer_account = create_account( "buyer" );
|
||||
|
|
@ -964,7 +964,7 @@ BOOST_AUTO_TEST_CASE( create_buy_exact_match_uia )
|
|||
BOOST_AUTO_TEST_CASE( create_buy_uia_multiple_match_new_reverse )
|
||||
{ try {
|
||||
INVOKE( issue_uia );
|
||||
const asset_object& test_asset = get_asset( "TEST" );
|
||||
const asset_object& test_asset = get_asset( "TESTPPY" );
|
||||
const asset_object& core_asset = get_asset( GRAPHENE_SYMBOL );
|
||||
const account_object& nathan_account = get_account( "nathan" );
|
||||
const account_object& buyer_account = create_account( "buyer" );
|
||||
|
|
@ -1004,7 +1004,7 @@ BOOST_AUTO_TEST_CASE( create_buy_uia_multiple_match_new_reverse )
|
|||
BOOST_AUTO_TEST_CASE( create_buy_uia_multiple_match_new_reverse_fract )
|
||||
{ try {
|
||||
INVOKE( issue_uia );
|
||||
const asset_object& test_asset = get_asset( "TEST" );
|
||||
const asset_object& test_asset = get_asset( "TESTPPY" );
|
||||
const asset_object& core_asset = get_asset( GRAPHENE_SYMBOL );
|
||||
const account_object& nathan_account = get_account( "nathan" );
|
||||
const account_object& buyer_account = create_account( "buyer" );
|
||||
|
|
@ -1052,7 +1052,7 @@ BOOST_AUTO_TEST_CASE( uia_fees )
|
|||
|
||||
enable_fees();
|
||||
|
||||
const asset_object& test_asset = get_asset("TEST");
|
||||
const asset_object& test_asset = get_asset("TESTPPY");
|
||||
const asset_dynamic_data_object& asset_dynamic = test_asset.dynamic_asset_data_id(db);
|
||||
const account_object& nathan_account = get_account("nathan");
|
||||
const account_object& committee_account = account_id_type()(db);
|
||||
|
|
@ -1112,637 +1112,10 @@ BOOST_AUTO_TEST_CASE( uia_fees )
|
|||
}
|
||||
}
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE( dividend_tests, database_fixture )
|
||||
|
||||
BOOST_AUTO_TEST_CASE( create_dividend_uia )
|
||||
{
|
||||
using namespace graphene;
|
||||
try {
|
||||
BOOST_TEST_MESSAGE("Creating dividend holder asset");
|
||||
{
|
||||
asset_create_operation creator;
|
||||
creator.issuer = account_id_type();
|
||||
creator.fee = asset();
|
||||
creator.symbol = "DIVIDEND";
|
||||
creator.common_options.max_supply = 100000000;
|
||||
creator.precision = 2;
|
||||
creator.common_options.market_fee_percent = GRAPHENE_MAX_MARKET_FEE_PERCENT/100; /*1%*/
|
||||
creator.common_options.issuer_permissions = UIA_ASSET_ISSUER_PERMISSION_MASK;
|
||||
creator.common_options.flags = charge_market_fee;
|
||||
creator.common_options.core_exchange_rate = price({asset(2),asset(1,asset_id_type(1))});
|
||||
trx.operations.push_back(std::move(creator));
|
||||
set_expiration(db, trx);
|
||||
PUSH_TX( db, trx, ~0 );
|
||||
trx.operations.clear();
|
||||
}
|
||||
|
||||
BOOST_TEST_MESSAGE("Creating test accounts");
|
||||
create_account("alice");
|
||||
create_account("bob");
|
||||
create_account("carol");
|
||||
create_account("dave");
|
||||
create_account("frank");
|
||||
|
||||
BOOST_TEST_MESSAGE("Creating test asset");
|
||||
{
|
||||
asset_create_operation creator;
|
||||
creator.issuer = account_id_type();
|
||||
creator.fee = asset();
|
||||
creator.symbol = "TEST";
|
||||
creator.common_options.max_supply = 100000000;
|
||||
creator.precision = 2;
|
||||
creator.common_options.market_fee_percent = GRAPHENE_MAX_MARKET_FEE_PERCENT/100; /*1%*/
|
||||
creator.common_options.issuer_permissions = UIA_ASSET_ISSUER_PERMISSION_MASK;
|
||||
creator.common_options.flags = charge_market_fee;
|
||||
creator.common_options.core_exchange_rate = price({asset(2),asset(1,asset_id_type(1))});
|
||||
trx.operations.push_back(std::move(creator));
|
||||
set_expiration(db, trx);
|
||||
PUSH_TX( db, trx, ~0 );
|
||||
trx.operations.clear();
|
||||
}
|
||||
generate_block();
|
||||
|
||||
BOOST_TEST_MESSAGE("Funding asset fee pool");
|
||||
{
|
||||
asset_fund_fee_pool_operation fund_op;
|
||||
fund_op.from_account = account_id_type();
|
||||
fund_op.asset_id = get_asset("TEST").id;
|
||||
fund_op.amount = 500000000;
|
||||
trx.operations.push_back(std::move(fund_op));
|
||||
set_expiration(db, trx);
|
||||
PUSH_TX( db, trx, ~0 );
|
||||
trx.operations.clear();
|
||||
}
|
||||
|
||||
// our DIVIDEND asset should not yet be a divdend asset
|
||||
const auto& dividend_holder_asset_object = get_asset("DIVIDEND");
|
||||
BOOST_CHECK(!dividend_holder_asset_object.dividend_data_id);
|
||||
|
||||
BOOST_TEST_MESSAGE("Converting the new asset to a dividend holder asset");
|
||||
{
|
||||
asset_update_dividend_operation op;
|
||||
op.issuer = dividend_holder_asset_object.issuer;
|
||||
op.asset_to_update = dividend_holder_asset_object.id;
|
||||
op.new_options.next_payout_time = db.head_block_time() + fc::minutes(1);
|
||||
op.new_options.payout_interval = 60 * 60 * 24 * 3;
|
||||
|
||||
trx.operations.push_back(op);
|
||||
set_expiration(db, trx);
|
||||
PUSH_TX( db, trx, ~0 );
|
||||
trx.operations.clear();
|
||||
}
|
||||
generate_block();
|
||||
|
||||
BOOST_TEST_MESSAGE("Verifying the dividend holder asset options");
|
||||
BOOST_REQUIRE(dividend_holder_asset_object.dividend_data_id);
|
||||
const auto& dividend_data = dividend_holder_asset_object.dividend_data(db);
|
||||
{
|
||||
BOOST_REQUIRE(dividend_data.options.payout_interval);
|
||||
BOOST_CHECK_EQUAL(*dividend_data.options.payout_interval, 60 * 60 * 24 * 3);
|
||||
}
|
||||
|
||||
const account_object& dividend_distribution_account = dividend_data.dividend_distribution_account(db);
|
||||
BOOST_CHECK_EQUAL(dividend_distribution_account.name, "dividend-dividend-distribution");
|
||||
|
||||
// db.modify( db.get_global_properties(), [&]( global_property_object& _gpo )
|
||||
// {
|
||||
// _gpo.parameters.current_fees->get<asset_dividend_distribution_operation>().distribution_base_fee = 100;
|
||||
// _gpo.parameters.current_fees->get<asset_dividend_distribution_operation>().distribution_fee_per_holder = 100;
|
||||
// } );
|
||||
|
||||
|
||||
} catch(fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( test_update_dividend_interval )
|
||||
{
|
||||
using namespace graphene;
|
||||
try {
|
||||
INVOKE( create_dividend_uia );
|
||||
|
||||
const auto& dividend_holder_asset_object = get_asset("DIVIDEND");
|
||||
const auto& dividend_data = dividend_holder_asset_object.dividend_data(db);
|
||||
|
||||
auto advance_to_next_payout_time = [&]() {
|
||||
// Advance to the next upcoming payout time
|
||||
BOOST_REQUIRE(dividend_data.options.next_payout_time);
|
||||
fc::time_point_sec next_payout_scheduled_time = *dividend_data.options.next_payout_time;
|
||||
// generate blocks up to the next scheduled time
|
||||
generate_blocks(next_payout_scheduled_time);
|
||||
// if the scheduled time fell on a maintenance interval, then we should have paid out.
|
||||
// if not, we need to advance to the next maintenance interval to trigger the payout
|
||||
if (dividend_data.options.next_payout_time)
|
||||
{
|
||||
// we know there was a next_payout_time set when we entered this, so if
|
||||
// it has been cleared, we must have already processed payouts, no need to
|
||||
// further advance time.
|
||||
BOOST_REQUIRE(dividend_data.options.next_payout_time);
|
||||
if (*dividend_data.options.next_payout_time == next_payout_scheduled_time)
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block(); // get the maintenance skip slots out of the way
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_TEST_MESSAGE("Updating the payout interval");
|
||||
{
|
||||
asset_update_dividend_operation op;
|
||||
op.issuer = dividend_holder_asset_object.issuer;
|
||||
op.asset_to_update = dividend_holder_asset_object.id;
|
||||
op.new_options.next_payout_time = fc::time_point::now() + fc::minutes(1);
|
||||
op.new_options.payout_interval = 60 * 60 * 24; // 1 days
|
||||
trx.operations.push_back(op);
|
||||
set_expiration(db, trx);
|
||||
PUSH_TX( db, trx, ~0 );
|
||||
trx.operations.clear();
|
||||
}
|
||||
generate_block();
|
||||
|
||||
BOOST_TEST_MESSAGE("Verifying the updated dividend holder asset options");
|
||||
{
|
||||
BOOST_REQUIRE(dividend_data.options.payout_interval);
|
||||
BOOST_CHECK_EQUAL(*dividend_data.options.payout_interval, 60 * 60 * 24);
|
||||
}
|
||||
|
||||
BOOST_TEST_MESSAGE("Removing the payout interval");
|
||||
{
|
||||
asset_update_dividend_operation op;
|
||||
op.issuer = dividend_holder_asset_object.issuer;
|
||||
op.asset_to_update = dividend_holder_asset_object.id;
|
||||
op.new_options.next_payout_time = dividend_data.options.next_payout_time;
|
||||
op.new_options.payout_interval = fc::optional<uint32_t>();
|
||||
trx.operations.push_back(op);
|
||||
set_expiration(db, trx);
|
||||
PUSH_TX( db, trx, ~0 );
|
||||
trx.operations.clear();
|
||||
}
|
||||
generate_block();
|
||||
BOOST_CHECK(!dividend_data.options.payout_interval);
|
||||
advance_to_next_payout_time();
|
||||
BOOST_REQUIRE_MESSAGE(!dividend_data.options.next_payout_time, "A new payout was scheduled, but none should have been");
|
||||
} catch(fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( test_basic_dividend_distribution )
|
||||
{
|
||||
using namespace graphene;
|
||||
try {
|
||||
INVOKE( create_dividend_uia );
|
||||
|
||||
const auto& dividend_holder_asset_object = get_asset("DIVIDEND");
|
||||
const auto& dividend_data = dividend_holder_asset_object.dividend_data(db);
|
||||
const account_object& dividend_distribution_account = dividend_data.dividend_distribution_account(db);
|
||||
const account_object& alice = get_account("alice");
|
||||
const account_object& bob = get_account("bob");
|
||||
const account_object& carol = get_account("carol");
|
||||
const account_object& dave = get_account("dave");
|
||||
const account_object& frank = get_account("frank");
|
||||
const auto& test_asset_object = get_asset("TEST");
|
||||
|
||||
auto issue_asset_to_account = [&](const asset_object& asset_to_issue, const account_object& destination_account, int64_t amount_to_issue)
|
||||
{
|
||||
asset_issue_operation op;
|
||||
op.issuer = asset_to_issue.issuer;
|
||||
op.asset_to_issue = asset(amount_to_issue, asset_to_issue.id);
|
||||
op.issue_to_account = destination_account.id;
|
||||
trx.operations.push_back( op );
|
||||
set_expiration(db, trx);
|
||||
PUSH_TX( db, trx, ~0 );
|
||||
trx.operations.clear();
|
||||
};
|
||||
|
||||
auto verify_pending_balance = [&](const account_object& holder_account_obj, const asset_object& payout_asset_obj, int64_t expected_balance) {
|
||||
int64_t pending_balance = get_dividend_pending_payout_balance(dividend_holder_asset_object.id,
|
||||
holder_account_obj.id,
|
||||
payout_asset_obj.id);
|
||||
BOOST_CHECK_EQUAL(pending_balance, expected_balance);
|
||||
};
|
||||
|
||||
auto advance_to_next_payout_time = [&]() {
|
||||
// Advance to the next upcoming payout time
|
||||
BOOST_REQUIRE(dividend_data.options.next_payout_time);
|
||||
fc::time_point_sec next_payout_scheduled_time = *dividend_data.options.next_payout_time;
|
||||
// generate blocks up to the next scheduled time
|
||||
generate_blocks(next_payout_scheduled_time);
|
||||
// if the scheduled time fell on a maintenance interval, then we should have paid out.
|
||||
// if not, we need to advance to the next maintenance interval to trigger the payout
|
||||
if (dividend_data.options.next_payout_time)
|
||||
{
|
||||
// we know there was a next_payout_time set when we entered this, so if
|
||||
// it has been cleared, we must have already processed payouts, no need to
|
||||
// further advance time.
|
||||
BOOST_REQUIRE(dividend_data.options.next_payout_time);
|
||||
if (*dividend_data.options.next_payout_time == next_payout_scheduled_time)
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block(); // get the maintenance skip slots out of the way
|
||||
}
|
||||
};
|
||||
|
||||
// the first test will be testing pending balances, so we need to hit a
|
||||
// maintenance interval that isn't the payout interval. Payout is
|
||||
// every 3 days, maintenance interval is every 1 day.
|
||||
advance_to_next_payout_time();
|
||||
|
||||
// Set up the first test, issue alice, bob, and carol each 100 DIVIDEND.
|
||||
// Then deposit 300 TEST in the distribution account, and see that they
|
||||
// each are credited 100 TEST.
|
||||
issue_asset_to_account(dividend_holder_asset_object, alice, 100000);
|
||||
issue_asset_to_account(dividend_holder_asset_object, bob, 100000);
|
||||
issue_asset_to_account(dividend_holder_asset_object, carol, 100000);
|
||||
|
||||
BOOST_TEST_MESSAGE("Issuing 300 TEST to the dividend account");
|
||||
issue_asset_to_account(test_asset_object, dividend_distribution_account, 30000);
|
||||
|
||||
generate_block();
|
||||
|
||||
BOOST_TEST_MESSAGE( "Generating blocks until next maintenance interval" );
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block(); // get the maintenance skip slots out of the way
|
||||
|
||||
verify_pending_balance(alice, test_asset_object, 10000);
|
||||
verify_pending_balance(bob, test_asset_object, 10000);
|
||||
verify_pending_balance(carol, test_asset_object, 10000);
|
||||
|
||||
// For the second test, issue carol more than the other two, so it's
|
||||
// alice: 100 DIVIDND, bob: 100 DIVIDEND, carol: 200 DIVIDEND
|
||||
// Then deposit 400 TEST in the distribution account, and see that alice
|
||||
// and bob are credited with 100 TEST, and carol gets 200 TEST
|
||||
BOOST_TEST_MESSAGE("Issuing carol twice as much of the holder asset");
|
||||
issue_asset_to_account(dividend_holder_asset_object, carol, 100000); // one thousand at two digits of precision
|
||||
issue_asset_to_account(test_asset_object, dividend_distribution_account, 40000); // one thousand at two digits of precision
|
||||
BOOST_TEST_MESSAGE( "Generating blocks until next maintenance interval" );
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block(); // get the maintenance skip slots out of the way
|
||||
verify_pending_balance(alice, test_asset_object, 20000);
|
||||
verify_pending_balance(bob, test_asset_object, 20000);
|
||||
verify_pending_balance(carol, test_asset_object, 30000);
|
||||
|
||||
fc::time_point_sec old_next_payout_scheduled_time = *dividend_data.options.next_payout_time;
|
||||
advance_to_next_payout_time();
|
||||
|
||||
|
||||
BOOST_REQUIRE_MESSAGE(dividend_data.options.next_payout_time, "No new payout was scheduled");
|
||||
BOOST_CHECK_MESSAGE(old_next_payout_scheduled_time != *dividend_data.options.next_payout_time,
|
||||
"New payout was scheduled for the same time as the last payout");
|
||||
BOOST_CHECK_MESSAGE(old_next_payout_scheduled_time + *dividend_data.options.payout_interval == *dividend_data.options.next_payout_time,
|
||||
"New payout was not scheduled for the expected time");
|
||||
|
||||
auto verify_dividend_payout_operations = [&](const account_object& destination_account, const asset& expected_payout)
|
||||
{
|
||||
BOOST_TEST_MESSAGE("Verifying the virtual op was created");
|
||||
const account_transaction_history_index& hist_idx = db.get_index_type<account_transaction_history_index>();
|
||||
auto account_history_range = hist_idx.indices().get<by_seq>().equal_range(boost::make_tuple(destination_account.id));
|
||||
BOOST_REQUIRE(account_history_range.first != account_history_range.second);
|
||||
const operation_history_object& history_object = std::prev(account_history_range.second)->operation_id(db);
|
||||
const asset_dividend_distribution_operation& distribution_operation = history_object.op.get<asset_dividend_distribution_operation>();
|
||||
BOOST_CHECK(distribution_operation.account_id == destination_account.id);
|
||||
BOOST_CHECK(std::find(distribution_operation.amounts.begin(), distribution_operation.amounts.end(), expected_payout)
|
||||
!= distribution_operation.amounts.end());
|
||||
};
|
||||
|
||||
BOOST_TEST_MESSAGE("Verifying the payouts");
|
||||
BOOST_CHECK_EQUAL(get_balance(alice, test_asset_object), 20000);
|
||||
verify_dividend_payout_operations(alice, asset(20000, test_asset_object.id));
|
||||
verify_pending_balance(alice, test_asset_object, 0);
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(bob, test_asset_object), 20000);
|
||||
verify_dividend_payout_operations(bob, asset(20000, test_asset_object.id));
|
||||
verify_pending_balance(bob, test_asset_object, 0);
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(carol, test_asset_object), 30000);
|
||||
verify_dividend_payout_operations(carol, asset(30000, test_asset_object.id));
|
||||
verify_pending_balance(carol, test_asset_object, 0);
|
||||
} catch(fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( test_basic_dividend_distribution_to_core_asset )
|
||||
{
|
||||
using namespace graphene;
|
||||
try {
|
||||
BOOST_TEST_MESSAGE("Creating test accounts");
|
||||
create_account("alice");
|
||||
create_account("bob");
|
||||
create_account("carol");
|
||||
create_account("dave");
|
||||
create_account("frank");
|
||||
|
||||
BOOST_TEST_MESSAGE("Creating test asset");
|
||||
{
|
||||
asset_create_operation creator;
|
||||
creator.issuer = account_id_type();
|
||||
creator.fee = asset();
|
||||
creator.symbol = "TEST";
|
||||
creator.common_options.max_supply = 100000000;
|
||||
creator.precision = 2;
|
||||
creator.common_options.market_fee_percent = GRAPHENE_MAX_MARKET_FEE_PERCENT/100; /*1%*/
|
||||
creator.common_options.issuer_permissions = UIA_ASSET_ISSUER_PERMISSION_MASK;
|
||||
creator.common_options.flags = charge_market_fee;
|
||||
creator.common_options.core_exchange_rate = price({asset(2),asset(1,asset_id_type(1))});
|
||||
trx.operations.push_back(std::move(creator));
|
||||
set_expiration(db, trx);
|
||||
PUSH_TX( db, trx, ~0 );
|
||||
trx.operations.clear();
|
||||
}
|
||||
generate_block();
|
||||
|
||||
const auto& dividend_holder_asset_object = asset_id_type(0)(db);
|
||||
const auto& dividend_data = dividend_holder_asset_object.dividend_data(db);
|
||||
const account_object& dividend_distribution_account = dividend_data.dividend_distribution_account(db);
|
||||
const account_object& alice = get_account("alice");
|
||||
const account_object& bob = get_account("bob");
|
||||
const account_object& carol = get_account("carol");
|
||||
const account_object& dave = get_account("dave");
|
||||
const account_object& frank = get_account("frank");
|
||||
const auto& test_asset_object = get_asset("TEST");
|
||||
|
||||
auto issue_asset_to_account = [&](const asset_object& asset_to_issue, const account_object& destination_account, int64_t amount_to_issue)
|
||||
{
|
||||
asset_issue_operation op;
|
||||
op.issuer = asset_to_issue.issuer;
|
||||
op.asset_to_issue = asset(amount_to_issue, asset_to_issue.id);
|
||||
op.issue_to_account = destination_account.id;
|
||||
trx.operations.push_back( op );
|
||||
set_expiration(db, trx);
|
||||
PUSH_TX( db, trx, ~0 );
|
||||
trx.operations.clear();
|
||||
};
|
||||
|
||||
auto verify_pending_balance = [&](const account_object& holder_account_obj, const asset_object& payout_asset_obj, int64_t expected_balance) {
|
||||
int64_t pending_balance = get_dividend_pending_payout_balance(dividend_holder_asset_object.id,
|
||||
holder_account_obj.id,
|
||||
payout_asset_obj.id);
|
||||
BOOST_CHECK_EQUAL(pending_balance, expected_balance);
|
||||
};
|
||||
|
||||
auto advance_to_next_payout_time = [&]() {
|
||||
// Advance to the next upcoming payout time
|
||||
BOOST_REQUIRE(dividend_data.options.next_payout_time);
|
||||
fc::time_point_sec next_payout_scheduled_time = *dividend_data.options.next_payout_time;
|
||||
idump((next_payout_scheduled_time));
|
||||
// generate blocks up to the next scheduled time
|
||||
generate_blocks(next_payout_scheduled_time);
|
||||
// if the scheduled time fell on a maintenance interval, then we should have paid out.
|
||||
// if not, we need to advance to the next maintenance interval to trigger the payout
|
||||
if (dividend_data.options.next_payout_time)
|
||||
{
|
||||
// we know there was a next_payout_time set when we entered this, so if
|
||||
// it has been cleared, we must have already processed payouts, no need to
|
||||
// further advance time.
|
||||
BOOST_REQUIRE(dividend_data.options.next_payout_time);
|
||||
if (*dividend_data.options.next_payout_time == next_payout_scheduled_time)
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block(); // get the maintenance skip slots out of the way
|
||||
}
|
||||
idump((db.head_block_time()));
|
||||
};
|
||||
|
||||
// the first test will be testing pending balances, so we need to hit a
|
||||
// maintenance interval that isn't the payout interval. Payout is
|
||||
// every 3 days, maintenance interval is every 1 day.
|
||||
advance_to_next_payout_time();
|
||||
|
||||
// Set up the first test, issue alice, bob, and carol, and dave each 1/4 of the total
|
||||
// supply of the core asset.
|
||||
// Then deposit 400 TEST in the distribution account, and see that they
|
||||
// each are credited 100 TEST.
|
||||
transfer( committee_account(db), alice, asset( 250000000000000 ) );
|
||||
transfer( committee_account(db), bob, asset( 250000000000000 ) );
|
||||
transfer( committee_account(db), carol, asset( 250000000000000 ) );
|
||||
transfer( committee_account(db), dave, asset( 250000000000000 ) );
|
||||
|
||||
BOOST_TEST_MESSAGE("Issuing 300 TEST to the dividend account");
|
||||
issue_asset_to_account(test_asset_object, dividend_distribution_account, 40000);
|
||||
|
||||
generate_block();
|
||||
|
||||
BOOST_TEST_MESSAGE( "Generating blocks until next maintenance interval" );
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block(); // get the maintenance skip slots out of the way
|
||||
|
||||
verify_pending_balance(alice, test_asset_object, 10000);
|
||||
verify_pending_balance(bob, test_asset_object, 10000);
|
||||
verify_pending_balance(carol, test_asset_object, 10000);
|
||||
verify_pending_balance(dave, test_asset_object, 10000);
|
||||
|
||||
// For the second test, issue dave more than the other two, so it's
|
||||
// alice: 1/5 CORE, bob: 1/5 CORE, carol: 1/5 CORE, dave: 2/5 CORE
|
||||
// Then deposit 500 TEST in the distribution account, and see that alice
|
||||
// bob, and carol are credited with 100 TEST, and dave gets 200 TEST
|
||||
BOOST_TEST_MESSAGE("Issuing dave twice as much of the holder asset");
|
||||
transfer( alice, dave, asset( 50000000000000 ) );
|
||||
transfer( bob, dave, asset( 50000000000000 ) );
|
||||
transfer( carol, dave, asset( 50000000000000 ) );
|
||||
issue_asset_to_account(test_asset_object, dividend_distribution_account, 50000); // 500 at two digits of precision
|
||||
BOOST_TEST_MESSAGE( "Generating blocks until next maintenance interval" );
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block(); // get the maintenance skip slots out of the way
|
||||
verify_pending_balance(alice, test_asset_object, 20000);
|
||||
verify_pending_balance(bob, test_asset_object, 20000);
|
||||
verify_pending_balance(carol, test_asset_object, 20000);
|
||||
verify_pending_balance(dave, test_asset_object, 30000);
|
||||
|
||||
fc::time_point_sec old_next_payout_scheduled_time = *dividend_data.options.next_payout_time;
|
||||
advance_to_next_payout_time();
|
||||
|
||||
|
||||
BOOST_REQUIRE_MESSAGE(dividend_data.options.next_payout_time, "No new payout was scheduled");
|
||||
BOOST_CHECK_MESSAGE(old_next_payout_scheduled_time != *dividend_data.options.next_payout_time,
|
||||
"New payout was scheduled for the same time as the last payout");
|
||||
BOOST_CHECK_MESSAGE(old_next_payout_scheduled_time + *dividend_data.options.payout_interval == *dividend_data.options.next_payout_time,
|
||||
"New payout was not scheduled for the expected time");
|
||||
|
||||
auto verify_dividend_payout_operations = [&](const account_object& destination_account, const asset& expected_payout)
|
||||
{
|
||||
BOOST_TEST_MESSAGE("Verifying the virtual op was created");
|
||||
const account_transaction_history_index& hist_idx = db.get_index_type<account_transaction_history_index>();
|
||||
auto account_history_range = hist_idx.indices().get<by_seq>().equal_range(boost::make_tuple(destination_account.id));
|
||||
BOOST_REQUIRE(account_history_range.first != account_history_range.second);
|
||||
const operation_history_object& history_object = std::prev(account_history_range.second)->operation_id(db);
|
||||
const asset_dividend_distribution_operation& distribution_operation = history_object.op.get<asset_dividend_distribution_operation>();
|
||||
BOOST_CHECK(distribution_operation.account_id == destination_account.id);
|
||||
BOOST_CHECK(std::find(distribution_operation.amounts.begin(), distribution_operation.amounts.end(), expected_payout)
|
||||
!= distribution_operation.amounts.end());
|
||||
};
|
||||
|
||||
BOOST_TEST_MESSAGE("Verifying the payouts");
|
||||
BOOST_CHECK_EQUAL(get_balance(alice, test_asset_object), 20000);
|
||||
verify_dividend_payout_operations(alice, asset(20000, test_asset_object.id));
|
||||
verify_pending_balance(alice, test_asset_object, 0);
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(bob, test_asset_object), 20000);
|
||||
verify_dividend_payout_operations(bob, asset(20000, test_asset_object.id));
|
||||
verify_pending_balance(bob, test_asset_object, 0);
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(carol, test_asset_object), 20000);
|
||||
verify_dividend_payout_operations(carol, asset(20000, test_asset_object.id));
|
||||
verify_pending_balance(carol, test_asset_object, 0);
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(dave, test_asset_object), 30000);
|
||||
verify_dividend_payout_operations(dave, asset(30000, test_asset_object.id));
|
||||
verify_pending_balance(dave, test_asset_object, 0);
|
||||
} catch(fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( test_dividend_distribution_interval )
|
||||
{
|
||||
using namespace graphene;
|
||||
try {
|
||||
INVOKE( create_dividend_uia );
|
||||
|
||||
const auto& dividend_holder_asset_object = get_asset("DIVIDEND");
|
||||
const auto& dividend_data = dividend_holder_asset_object.dividend_data(db);
|
||||
const account_object& dividend_distribution_account = dividend_data.dividend_distribution_account(db);
|
||||
const account_object& alice = get_account("alice");
|
||||
const account_object& bob = get_account("bob");
|
||||
const account_object& carol = get_account("carol");
|
||||
const account_object& dave = get_account("dave");
|
||||
const account_object& frank = get_account("frank");
|
||||
const auto& test_asset_object = get_asset("TEST");
|
||||
} catch(fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE( check_dividend_corner_cases )
|
||||
{
|
||||
using namespace graphene;
|
||||
try {
|
||||
INVOKE( create_dividend_uia );
|
||||
|
||||
const auto& dividend_holder_asset_object = get_asset("DIVIDEND");
|
||||
const auto& dividend_data = dividend_holder_asset_object.dividend_data(db);
|
||||
const account_object& dividend_distribution_account = dividend_data.dividend_distribution_account(db);
|
||||
const account_object& alice = get_account("alice");
|
||||
const account_object& bob = get_account("bob");
|
||||
const account_object& carol = get_account("carol");
|
||||
const account_object& dave = get_account("dave");
|
||||
const account_object& frank = get_account("frank");
|
||||
const auto& test_asset_object = get_asset("TEST");
|
||||
|
||||
auto issue_asset_to_account = [&](const asset_object& asset_to_issue, const account_object& destination_account, int64_t amount_to_issue)
|
||||
{
|
||||
asset_issue_operation op;
|
||||
op.issuer = asset_to_issue.issuer;
|
||||
op.asset_to_issue = asset(amount_to_issue, asset_to_issue.id);
|
||||
op.issue_to_account = destination_account.id;
|
||||
trx.operations.push_back( op );
|
||||
set_expiration(db, trx);
|
||||
PUSH_TX( db, trx, ~0 );
|
||||
trx.operations.clear();
|
||||
};
|
||||
|
||||
auto verify_pending_balance = [&](const account_object& holder_account_obj, const asset_object& payout_asset_obj, int64_t expected_balance) {
|
||||
int64_t pending_balance = get_dividend_pending_payout_balance(dividend_holder_asset_object.id,
|
||||
holder_account_obj.id,
|
||||
payout_asset_obj.id);
|
||||
BOOST_CHECK_EQUAL(pending_balance, expected_balance);
|
||||
};
|
||||
|
||||
auto reserve_asset_from_account = [&](const asset_object& asset_to_reserve, const account_object& from_account, int64_t amount_to_reserve)
|
||||
{
|
||||
asset_reserve_operation reserve_op;
|
||||
reserve_op.payer = from_account.id;
|
||||
reserve_op.amount_to_reserve = asset(amount_to_reserve, asset_to_reserve.id);
|
||||
trx.operations.push_back(reserve_op);
|
||||
set_expiration(db, trx);
|
||||
PUSH_TX( db, trx, ~0 );
|
||||
trx.operations.clear();
|
||||
};
|
||||
auto advance_to_next_payout_time = [&]() {
|
||||
// Advance to the next upcoming payout time
|
||||
BOOST_REQUIRE(dividend_data.options.next_payout_time);
|
||||
fc::time_point_sec next_payout_scheduled_time = *dividend_data.options.next_payout_time;
|
||||
// generate blocks up to the next scheduled time
|
||||
generate_blocks(next_payout_scheduled_time);
|
||||
// if the scheduled time fell on a maintenance interval, then we should have paid out.
|
||||
// if not, we need to advance to the next maintenance interval to trigger the payout
|
||||
if (dividend_data.options.next_payout_time)
|
||||
{
|
||||
// we know there was a next_payout_time set when we entered this, so if
|
||||
// it has been cleared, we must have already processed payouts, no need to
|
||||
// further advance time.
|
||||
BOOST_REQUIRE(dividend_data.options.next_payout_time);
|
||||
if (*dividend_data.options.next_payout_time == next_payout_scheduled_time)
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block(); // get the maintenance skip slots out of the way
|
||||
}
|
||||
};
|
||||
|
||||
// the first test will be testing pending balances, so we need to hit a
|
||||
// maintenance interval that isn't the payout interval. Payout is
|
||||
// every 3 days, maintenance interval is every 1 day.
|
||||
advance_to_next_payout_time();
|
||||
|
||||
BOOST_TEST_MESSAGE("Testing a payout interval when there are no users holding the dividend asset");
|
||||
BOOST_CHECK_EQUAL(get_balance(bob, dividend_holder_asset_object), 0);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob, dividend_holder_asset_object), 0);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob, dividend_holder_asset_object), 0);
|
||||
issue_asset_to_account(test_asset_object, dividend_distribution_account, 1000);
|
||||
BOOST_TEST_MESSAGE("Generating blocks until next maintenance interval");
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block(); // get the maintenance skip slots out of the way
|
||||
BOOST_TEST_MESSAGE("Verify that no pending payments were scheduled");
|
||||
verify_pending_balance(alice, test_asset_object, 0);
|
||||
verify_pending_balance(bob, test_asset_object, 0);
|
||||
verify_pending_balance(carol, test_asset_object, 0);
|
||||
advance_to_next_payout_time();
|
||||
BOOST_TEST_MESSAGE("Verify that no actual payments took place");
|
||||
verify_pending_balance(alice, test_asset_object, 0);
|
||||
verify_pending_balance(bob, test_asset_object, 0);
|
||||
verify_pending_balance(carol, test_asset_object, 0);
|
||||
BOOST_CHECK_EQUAL(get_balance(alice, test_asset_object), 0);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob, test_asset_object), 0);
|
||||
BOOST_CHECK_EQUAL(get_balance(carol, test_asset_object), 0);
|
||||
BOOST_CHECK_EQUAL(get_balance(dividend_distribution_account, test_asset_object), 1000);
|
||||
|
||||
BOOST_TEST_MESSAGE("Now give alice a small balance and see that she takes it all");
|
||||
issue_asset_to_account(dividend_holder_asset_object, alice, 1);
|
||||
generate_block();
|
||||
BOOST_TEST_MESSAGE("Generating blocks until next maintenance interval");
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block(); // get the maintenance skip slots out of the way
|
||||
BOOST_TEST_MESSAGE("Verify that no alice received her payment of the entire amount");
|
||||
verify_pending_balance(alice, test_asset_object, 1000);
|
||||
|
||||
// Test that we can pay out the dividend asset itself
|
||||
issue_asset_to_account(dividend_holder_asset_object, bob, 1);
|
||||
issue_asset_to_account(dividend_holder_asset_object, carol, 1);
|
||||
issue_asset_to_account(dividend_holder_asset_object, dividend_distribution_account, 300);
|
||||
generate_block();
|
||||
BOOST_CHECK_EQUAL(get_balance(alice, dividend_holder_asset_object), 1);
|
||||
BOOST_CHECK_EQUAL(get_balance(bob, dividend_holder_asset_object), 1);
|
||||
BOOST_CHECK_EQUAL(get_balance(carol, dividend_holder_asset_object), 1);
|
||||
BOOST_TEST_MESSAGE("Generating blocks until next maintenance interval");
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block(); // get the maintenance skip slots out of the way
|
||||
BOOST_TEST_MESSAGE("Verify that the dividend asset was shared out");
|
||||
verify_pending_balance(alice, dividend_holder_asset_object, 100);
|
||||
verify_pending_balance(bob, dividend_holder_asset_object, 100);
|
||||
verify_pending_balance(carol, dividend_holder_asset_object, 100);
|
||||
} catch(fc::exception& e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
BOOST_AUTO_TEST_SUITE_END() // end dividend_tests suite
|
||||
|
||||
BOOST_AUTO_TEST_CASE( cancel_limit_order_test )
|
||||
{ try {
|
||||
INVOKE( issue_uia );
|
||||
const asset_object& test_asset = get_asset( "TEST" );
|
||||
const asset_object& test_asset = get_asset( "TESTPPY" );
|
||||
const account_object& buyer_account = create_account( "buyer" );
|
||||
|
||||
transfer( committee_account(db), buyer_account, asset( 10000 ) );
|
||||
|
|
@ -1833,7 +1206,7 @@ BOOST_AUTO_TEST_CASE( trade_amount_equals_zero )
|
|||
{
|
||||
try {
|
||||
INVOKE(issue_uia);
|
||||
const asset_object& test = get_asset( "TEST" );
|
||||
const asset_object& test = get_asset( "TESTPPY" );
|
||||
const asset_object& core = get_asset( GRAPHENE_SYMBOL );
|
||||
const account_object& core_seller = create_account( "shorter1" );
|
||||
const account_object& core_buyer = get_account("nathan");
|
||||
|
|
@ -1864,7 +1237,7 @@ BOOST_AUTO_TEST_CASE( limit_order_fill_or_kill )
|
|||
{ try {
|
||||
INVOKE(issue_uia);
|
||||
const account_object& nathan = get_account("nathan");
|
||||
const asset_object& test = get_asset("TEST");
|
||||
const asset_object& test = get_asset("TESTPPY");
|
||||
const asset_object& core = asset_id_type()(db);
|
||||
|
||||
limit_order_create_operation op;
|
||||
|
|
@ -1926,10 +1299,10 @@ BOOST_AUTO_TEST_CASE( witness_pay_test )
|
|||
) >> GRAPHENE_CORE_ASSET_CYCLE_RATE_BITS
|
||||
;
|
||||
// change this if ref_budget changes
|
||||
BOOST_CHECK_EQUAL( ref_budget, 594 );
|
||||
BOOST_CHECK_EQUAL( ref_budget, 357 );
|
||||
const uint64_t witness_ppb = ref_budget * 10 / 23 + 1;
|
||||
// change this if ref_budget changes
|
||||
BOOST_CHECK_EQUAL( witness_ppb, 259 );
|
||||
BOOST_CHECK_EQUAL( witness_ppb, 156 );
|
||||
// following two inequalities need to hold for maximal code coverage
|
||||
BOOST_CHECK_LT( witness_ppb * 2, ref_budget );
|
||||
BOOST_CHECK_GT( witness_ppb * 3, ref_budget );
|
||||
|
|
@ -1981,7 +1354,7 @@ BOOST_AUTO_TEST_CASE( witness_pay_test )
|
|||
// The 80% lifetime referral fee went to the committee account, which burned it. Check that it's here.
|
||||
BOOST_CHECK( core->reserved(db).value == 8000*prec );
|
||||
generate_block();
|
||||
BOOST_CHECK_EQUAL( core->reserved(db).value, 999999406 );
|
||||
BOOST_CHECK_EQUAL( core->reserved(db).value, 999999643 );
|
||||
BOOST_CHECK_EQUAL( db.get_dynamic_global_properties().witness_budget.value, ref_budget );
|
||||
// first witness paid from old budget (so no pay)
|
||||
BOOST_CHECK_EQUAL( last_witness_vbo_balance().value, 0 );
|
||||
|
|
@ -2002,7 +1375,7 @@ BOOST_AUTO_TEST_CASE( witness_pay_test )
|
|||
generate_block();
|
||||
BOOST_CHECK_EQUAL( last_witness_vbo_balance().value, 0 );
|
||||
BOOST_CHECK_EQUAL( db.get_dynamic_global_properties().witness_budget.value, 0 );
|
||||
BOOST_CHECK_EQUAL(core->reserved(db).value, 999999406 );
|
||||
BOOST_CHECK_EQUAL(core->reserved(db).value, 999999643 );
|
||||
|
||||
} FC_LOG_AND_RETHROW() }
|
||||
|
||||
|
|
@ -2016,7 +1389,7 @@ BOOST_AUTO_TEST_CASE( reserve_asset_test )
|
|||
{
|
||||
ACTORS((alice)(bob)(sam)(judge));
|
||||
const auto& basset = create_bitasset("USDBIT", judge_id);
|
||||
const auto& uasset = create_user_issued_asset("TEST");
|
||||
const auto& uasset = create_user_issued_asset("TESTPPY");
|
||||
const auto& passet = create_prediction_market("PMARK", judge_id);
|
||||
const auto& casset = asset_id_type()(db);
|
||||
|
||||
|
|
@ -2178,8 +1551,8 @@ BOOST_AUTO_TEST_CASE( vesting_balance_create_test )
|
|||
{ try {
|
||||
INVOKE( create_uia );
|
||||
|
||||
const asset_object& core = asset_id_type()(db);
|
||||
const asset_object& test_asset = get_asset("TEST");
|
||||
const asset_object& core = get_asset(GRAPHENE_SYMBOL);
|
||||
const asset_object& test_asset = get_asset("TESTPPY");
|
||||
|
||||
vesting_balance_create_operation op;
|
||||
op.fee = core.amount( 0 );
|
||||
|
|
@ -2188,6 +1561,7 @@ BOOST_AUTO_TEST_CASE( vesting_balance_create_test )
|
|||
op.amount = test_asset.amount( 100 );
|
||||
//op.vesting_seconds = 60*60*24;
|
||||
op.policy = cdd_vesting_policy_initializer{ 60*60*24 };
|
||||
//op.balance_type == vesting_balance_type::unspecified;
|
||||
|
||||
// Fee must be non-negative
|
||||
REQUIRE_OP_VALIDATION_SUCCESS( op, fee, core.amount(1) );
|
||||
|
|
@ -2207,6 +1581,7 @@ BOOST_AUTO_TEST_CASE( vesting_balance_create_test )
|
|||
|
||||
op.creator = alice_account.get_id();
|
||||
op.owner = alice_account.get_id();
|
||||
//op.balance_type = vesting_balance_type::unspecified;
|
||||
|
||||
account_id_type nobody = account_id_type(1234);
|
||||
|
||||
|
|
@ -2230,7 +1605,7 @@ BOOST_AUTO_TEST_CASE( vesting_balance_withdraw_test )
|
|||
generate_block();
|
||||
|
||||
const asset_object& core = asset_id_type()(db);
|
||||
const asset_object& test_asset = get_asset( "TEST" );
|
||||
const asset_object& test_asset = get_asset( "TESTPPY" );
|
||||
|
||||
vesting_balance_withdraw_operation op;
|
||||
op.fee = core.amount( 0 );
|
||||
|
|
@ -2277,6 +1652,7 @@ BOOST_AUTO_TEST_CASE( vesting_balance_withdraw_test )
|
|||
create_op.owner = owner;
|
||||
create_op.amount = amount;
|
||||
create_op.policy = cdd_vesting_policy_initializer(vesting_seconds);
|
||||
//create_op.balance_type = vesting_balance_type::unspecified;
|
||||
tx.operations.push_back( create_op );
|
||||
set_expiration( db, tx );
|
||||
|
||||
|
|
|
|||
|
|
@ -864,194 +864,194 @@ BOOST_AUTO_TEST_CASE( burn_worker_test )
|
|||
BOOST_CHECK_EQUAL( get_balance(GRAPHENE_NULL_ACCOUNT, asset_id_type()), 2000 );
|
||||
}FC_LOG_AND_RETHROW()}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( force_settle_test )
|
||||
{
|
||||
try
|
||||
{
|
||||
ACTORS( (nathan)(shorter1)(shorter2)(shorter3)(shorter4)(shorter5) );
|
||||
|
||||
int64_t initial_balance = 100000000;
|
||||
|
||||
transfer(account_id_type()(db), shorter1_id(db), asset(initial_balance));
|
||||
transfer(account_id_type()(db), shorter2_id(db), asset(initial_balance));
|
||||
transfer(account_id_type()(db), shorter3_id(db), asset(initial_balance));
|
||||
transfer(account_id_type()(db), shorter4_id(db), asset(initial_balance));
|
||||
transfer(account_id_type()(db), shorter5_id(db), asset(initial_balance));
|
||||
|
||||
asset_id_type bitusd_id = create_bitasset(
|
||||
"USDBIT",
|
||||
nathan_id,
|
||||
100,
|
||||
disable_force_settle
|
||||
).id;
|
||||
|
||||
asset_id_type core_id = asset_id_type();
|
||||
|
||||
auto update_bitasset_options = [&]( asset_id_type asset_id,
|
||||
std::function< void(bitasset_options&) > update_function )
|
||||
{
|
||||
const asset_object& _asset = asset_id(db);
|
||||
asset_update_bitasset_operation op;
|
||||
op.asset_to_update = asset_id;
|
||||
op.issuer = _asset.issuer;
|
||||
op.new_options = (*_asset.bitasset_data_id)(db).options;
|
||||
update_function( op.new_options );
|
||||
signed_transaction tx;
|
||||
tx.operations.push_back( op );
|
||||
set_expiration( db, tx );
|
||||
PUSH_TX( db, tx, ~0 );
|
||||
} ;
|
||||
|
||||
auto update_asset_options = [&]( asset_id_type asset_id,
|
||||
std::function< void(asset_options&) > update_function )
|
||||
{
|
||||
const asset_object& _asset = asset_id(db);
|
||||
asset_update_operation op;
|
||||
op.asset_to_update = asset_id;
|
||||
op.issuer = _asset.issuer;
|
||||
op.new_options = _asset.options;
|
||||
update_function( op.new_options );
|
||||
signed_transaction tx;
|
||||
tx.operations.push_back( op );
|
||||
set_expiration( db, tx );
|
||||
PUSH_TX( db, tx, ~0 );
|
||||
} ;
|
||||
|
||||
BOOST_TEST_MESSAGE( "Update maximum_force_settlement_volume = 9000" );
|
||||
|
||||
BOOST_CHECK( bitusd_id(db).is_market_issued() );
|
||||
update_bitasset_options( bitusd_id, [&]( bitasset_options& new_options )
|
||||
{ new_options.maximum_force_settlement_volume = 9000; } );
|
||||
|
||||
BOOST_TEST_MESSAGE( "Publish price feed" );
|
||||
|
||||
update_feed_producers( bitusd_id, { nathan_id } );
|
||||
{
|
||||
price_feed feed;
|
||||
feed.settlement_price = price( asset( 1, bitusd_id ), asset( 1, core_id ) );
|
||||
publish_feed( bitusd_id, nathan_id, feed );
|
||||
}
|
||||
|
||||
BOOST_TEST_MESSAGE( "First short batch" );
|
||||
|
||||
call_order_id_type call1_id = borrow( shorter1_id, asset(1000, bitusd_id), asset(2*1000, core_id) )->id; // 2.0000
|
||||
call_order_id_type call2_id = borrow( shorter2_id, asset(2000, bitusd_id), asset(2*1999, core_id) )->id; // 1.9990
|
||||
call_order_id_type call3_id = borrow( shorter3_id, asset(3000, bitusd_id), asset(2*2890, core_id) )->id; // 1.9267
|
||||
call_order_id_type call4_id = borrow( shorter4_id, asset(4000, bitusd_id), asset(2*3950, core_id) )->id; // 1.9750
|
||||
call_order_id_type call5_id = borrow( shorter5_id, asset(5000, bitusd_id), asset(2*4900, core_id) )->id; // 1.9600
|
||||
|
||||
transfer( shorter1_id, nathan_id, asset(1000, bitusd_id) );
|
||||
transfer( shorter2_id, nathan_id, asset(2000, bitusd_id) );
|
||||
transfer( shorter3_id, nathan_id, asset(3000, bitusd_id) );
|
||||
transfer( shorter4_id, nathan_id, asset(4000, bitusd_id) );
|
||||
transfer( shorter5_id, nathan_id, asset(5000, bitusd_id) );
|
||||
|
||||
BOOST_CHECK_EQUAL( get_balance(nathan_id, bitusd_id), 15000);
|
||||
BOOST_CHECK_EQUAL( get_balance(nathan_id, core_id), 0);
|
||||
BOOST_CHECK_EQUAL( get_balance(shorter1_id, core_id), initial_balance-2000 );
|
||||
BOOST_CHECK_EQUAL( get_balance(shorter2_id, core_id), initial_balance-3998 );
|
||||
BOOST_CHECK_EQUAL( get_balance(shorter3_id, core_id), initial_balance-5780 );
|
||||
BOOST_CHECK_EQUAL( get_balance(shorter4_id, core_id), initial_balance-7900 );
|
||||
BOOST_CHECK_EQUAL( get_balance(shorter5_id, core_id), initial_balance-9800 );
|
||||
|
||||
BOOST_TEST_MESSAGE( "Update force_settlement_delay_sec = 100, force_settlement_offset_percent = 1%" );
|
||||
|
||||
update_bitasset_options( bitusd_id, [&]( bitasset_options& new_options )
|
||||
{ new_options.force_settlement_delay_sec = 100;
|
||||
new_options.force_settlement_offset_percent = GRAPHENE_1_PERCENT; } );
|
||||
|
||||
// Force settlement is disabled; check that it fails
|
||||
GRAPHENE_REQUIRE_THROW( force_settle( nathan_id, asset( 50, bitusd_id ) ), fc::exception );
|
||||
|
||||
update_asset_options( bitusd_id, [&]( asset_options& new_options )
|
||||
{ new_options.flags &= ~disable_force_settle; } );
|
||||
|
||||
// Can't settle more BitUSD than you own
|
||||
GRAPHENE_REQUIRE_THROW( force_settle( nathan_id, asset( 999999, bitusd_id ) ), fc::exception );
|
||||
|
||||
// settle3 should be least collateralized order according to index
|
||||
BOOST_CHECK( db.get_index_type<call_order_index>().indices().get<by_collateral>().begin()->id == call3_id );
|
||||
BOOST_CHECK_EQUAL( call3_id(db).debt.value, 3000 );
|
||||
|
||||
BOOST_TEST_MESSAGE( "Verify partial settlement of call" );
|
||||
// Partially settle a call
|
||||
force_settlement_id_type settle_id = force_settle( nathan_id, asset( 50, bitusd_id ) ).get< object_id_type >();
|
||||
|
||||
// Call does not take effect immediately
|
||||
BOOST_CHECK_EQUAL( get_balance(nathan_id, bitusd_id), 14950);
|
||||
BOOST_CHECK_EQUAL( settle_id(db).balance.amount.value, 50);
|
||||
BOOST_CHECK_EQUAL( call3_id(db).debt.value, 3000 );
|
||||
BOOST_CHECK_EQUAL( call3_id(db).collateral.value, 5780 );
|
||||
BOOST_CHECK( settle_id(db).owner == nathan_id );
|
||||
|
||||
// Wait for settlement to take effect
|
||||
generate_blocks(settle_id(db).settlement_date);
|
||||
BOOST_CHECK(db.find(settle_id) == nullptr);
|
||||
BOOST_CHECK_EQUAL( bitusd_id(db).bitasset_data(db).force_settled_volume.value, 50 );
|
||||
BOOST_CHECK_EQUAL( get_balance(nathan_id, bitusd_id), 14950);
|
||||
BOOST_CHECK_EQUAL( get_balance(nathan_id, core_id), 49 ); // 1% force_settlement_offset_percent (rounded unfavorably)
|
||||
BOOST_CHECK_EQUAL( call3_id(db).debt.value, 2950 );
|
||||
BOOST_CHECK_EQUAL( call3_id(db).collateral.value, 5731 ); // 5731 == 5780-49
|
||||
|
||||
BOOST_CHECK( db.get_index_type<call_order_index>().indices().get<by_collateral>().begin()->id == call3_id );
|
||||
|
||||
BOOST_TEST_MESSAGE( "Verify pending settlement is cancelled when asset's force_settle is disabled" );
|
||||
// Ensure pending settlement is cancelled when force settle is disabled
|
||||
settle_id = force_settle( nathan_id, asset( 50, bitusd_id ) ).get< object_id_type >();
|
||||
|
||||
BOOST_CHECK( !db.get_index_type<force_settlement_index>().indices().empty() );
|
||||
update_asset_options( bitusd_id, [&]( asset_options& new_options )
|
||||
{ new_options.flags |= disable_force_settle; } );
|
||||
BOOST_CHECK( db.get_index_type<force_settlement_index>().indices().empty() );
|
||||
update_asset_options( bitusd_id, [&]( asset_options& new_options )
|
||||
{ new_options.flags &= ~disable_force_settle; } );
|
||||
|
||||
BOOST_TEST_MESSAGE( "Perform iterative settlement" );
|
||||
settle_id = force_settle( nathan_id, asset( 12500, bitusd_id ) ).get< object_id_type >();
|
||||
|
||||
// c3 2950 : 5731 1.9427 fully settled
|
||||
// c5 5000 : 9800 1.9600 fully settled
|
||||
// c4 4000 : 7900 1.9750 fully settled
|
||||
// c2 2000 : 3998 1.9990 550 settled
|
||||
// c1 1000 : 2000 2.0000
|
||||
|
||||
generate_blocks( settle_id(db).settlement_date );
|
||||
|
||||
int64_t call1_payout = 0;
|
||||
int64_t call2_payout = 550*99/100;
|
||||
int64_t call3_payout = 49 + 2950*99/100;
|
||||
int64_t call4_payout = 4000*99/100;
|
||||
int64_t call5_payout = 5000*99/100;
|
||||
|
||||
BOOST_CHECK_EQUAL( get_balance(shorter1_id, core_id), initial_balance-2*1000 ); // full collat still tied up
|
||||
BOOST_CHECK_EQUAL( get_balance(shorter2_id, core_id), initial_balance-2*1999 ); // full collat still tied up
|
||||
BOOST_CHECK_EQUAL( get_balance(shorter3_id, core_id), initial_balance-call3_payout ); // initial balance minus transfer to Nathan (as BitUSD)
|
||||
BOOST_CHECK_EQUAL( get_balance(shorter4_id, core_id), initial_balance-call4_payout ); // initial balance minus transfer to Nathan (as BitUSD)
|
||||
BOOST_CHECK_EQUAL( get_balance(shorter5_id, core_id), initial_balance-call5_payout ); // initial balance minus transfer to Nathan (as BitUSD)
|
||||
|
||||
BOOST_CHECK_EQUAL( get_balance(nathan_id, core_id),
|
||||
call1_payout + call2_payout + call3_payout + call4_payout + call5_payout );
|
||||
|
||||
BOOST_CHECK( db.find(call3_id) == nullptr );
|
||||
BOOST_CHECK( db.find(call4_id) == nullptr );
|
||||
BOOST_CHECK( db.find(call5_id) == nullptr );
|
||||
|
||||
BOOST_REQUIRE( db.find(call1_id) != nullptr );
|
||||
BOOST_REQUIRE( db.find(call2_id) != nullptr );
|
||||
|
||||
BOOST_CHECK_EQUAL( call1_id(db).debt.value, 1000 );
|
||||
BOOST_CHECK_EQUAL( call1_id(db).collateral.value, 2000 );
|
||||
|
||||
BOOST_CHECK_EQUAL( call2_id(db).debt.value, 2000-550 );
|
||||
BOOST_CHECK_EQUAL( call2_id(db).collateral.value, 3998-call2_payout );
|
||||
}
|
||||
catch(fc::exception& e)
|
||||
{
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
// BOOST_AUTO_TEST_CASE( force_settle_test )
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// ACTORS( (nathan)(shorter1)(shorter2)(shorter3)(shorter4)(shorter5) );
|
||||
//
|
||||
// int64_t initial_balance = 100000000;
|
||||
//
|
||||
// transfer(account_id_type()(db), shorter1_id(db), asset(initial_balance));
|
||||
// transfer(account_id_type()(db), shorter2_id(db), asset(initial_balance));
|
||||
// transfer(account_id_type()(db), shorter3_id(db), asset(initial_balance));
|
||||
// transfer(account_id_type()(db), shorter4_id(db), asset(initial_balance));
|
||||
// transfer(account_id_type()(db), shorter5_id(db), asset(initial_balance));
|
||||
//
|
||||
// asset_id_type bitusd_id = create_bitasset(
|
||||
// "USDBIT",
|
||||
// nathan_id,
|
||||
// 100,
|
||||
// disable_force_settle
|
||||
// ).id;
|
||||
//
|
||||
// asset_id_type core_id = asset_id_type();
|
||||
//
|
||||
// auto update_bitasset_options = [&]( asset_id_type asset_id,
|
||||
// std::function< void(bitasset_options&) > update_function )
|
||||
// {
|
||||
// const asset_object& _asset = asset_id(db);
|
||||
// asset_update_bitasset_operation op;
|
||||
// op.asset_to_update = asset_id;
|
||||
// op.issuer = _asset.issuer;
|
||||
// op.new_options = (*_asset.bitasset_data_id)(db).options;
|
||||
// update_function( op.new_options );
|
||||
// signed_transaction tx;
|
||||
// tx.operations.push_back( op );
|
||||
// set_expiration( db, tx );
|
||||
// PUSH_TX( db, tx, ~0 );
|
||||
// } ;
|
||||
//
|
||||
// auto update_asset_options = [&]( asset_id_type asset_id,
|
||||
// std::function< void(asset_options&) > update_function )
|
||||
// {
|
||||
// const asset_object& _asset = asset_id(db);
|
||||
// asset_update_operation op;
|
||||
// op.asset_to_update = asset_id;
|
||||
// op.issuer = _asset.issuer;
|
||||
// op.new_options = _asset.options;
|
||||
// update_function( op.new_options );
|
||||
// signed_transaction tx;
|
||||
// tx.operations.push_back( op );
|
||||
// set_expiration( db, tx );
|
||||
// PUSH_TX( db, tx, ~0 );
|
||||
// } ;
|
||||
//
|
||||
// BOOST_TEST_MESSAGE( "Update maximum_force_settlement_volume = 9000" );
|
||||
//
|
||||
// BOOST_CHECK( bitusd_id(db).is_market_issued() );
|
||||
// update_bitasset_options( bitusd_id, [&]( bitasset_options& new_options )
|
||||
// { new_options.maximum_force_settlement_volume = 9000; } );
|
||||
//
|
||||
// BOOST_TEST_MESSAGE( "Publish price feed" );
|
||||
//
|
||||
// update_feed_producers( bitusd_id, { nathan_id } );
|
||||
// {
|
||||
// price_feed feed;
|
||||
// feed.settlement_price = price( asset( 1, bitusd_id ), asset( 1, core_id ) );
|
||||
// publish_feed( bitusd_id, nathan_id, feed );
|
||||
// }
|
||||
//
|
||||
// BOOST_TEST_MESSAGE( "First short batch" );
|
||||
//
|
||||
// call_order_id_type call1_id = borrow( shorter1_id, asset(1000, bitusd_id), asset(2*1000, core_id) )->id; // 2.0000
|
||||
// call_order_id_type call2_id = borrow( shorter2_id, asset(2000, bitusd_id), asset(2*1999, core_id) )->id; // 1.9990
|
||||
// call_order_id_type call3_id = borrow( shorter3_id, asset(3000, bitusd_id), asset(2*2890, core_id) )->id; // 1.9267
|
||||
// call_order_id_type call4_id = borrow( shorter4_id, asset(4000, bitusd_id), asset(2*3950, core_id) )->id; // 1.9750
|
||||
// call_order_id_type call5_id = borrow( shorter5_id, asset(5000, bitusd_id), asset(2*4900, core_id) )->id; // 1.9600
|
||||
//
|
||||
// transfer( shorter1_id, nathan_id, asset(1000, bitusd_id) );
|
||||
// transfer( shorter2_id, nathan_id, asset(2000, bitusd_id) );
|
||||
// transfer( shorter3_id, nathan_id, asset(3000, bitusd_id) );
|
||||
// transfer( shorter4_id, nathan_id, asset(4000, bitusd_id) );
|
||||
// transfer( shorter5_id, nathan_id, asset(5000, bitusd_id) );
|
||||
//
|
||||
// BOOST_CHECK_EQUAL( get_balance(nathan_id, bitusd_id), 15000);
|
||||
// BOOST_CHECK_EQUAL( get_balance(nathan_id, core_id), 0);
|
||||
// BOOST_CHECK_EQUAL( get_balance(shorter1_id, core_id), initial_balance-2000 );
|
||||
// BOOST_CHECK_EQUAL( get_balance(shorter2_id, core_id), initial_balance-3998 );
|
||||
// BOOST_CHECK_EQUAL( get_balance(shorter3_id, core_id), initial_balance-5780 );
|
||||
// BOOST_CHECK_EQUAL( get_balance(shorter4_id, core_id), initial_balance-7900 );
|
||||
// BOOST_CHECK_EQUAL( get_balance(shorter5_id, core_id), initial_balance-9800 );
|
||||
//
|
||||
// BOOST_TEST_MESSAGE( "Update force_settlement_delay_sec = 100, force_settlement_offset_percent = 1%" );
|
||||
//
|
||||
// update_bitasset_options( bitusd_id, [&]( bitasset_options& new_options )
|
||||
// { new_options.force_settlement_delay_sec = 100;
|
||||
// new_options.force_settlement_offset_percent = GRAPHENE_1_PERCENT; } );
|
||||
//
|
||||
// // Force settlement is disabled; check that it fails
|
||||
// GRAPHENE_REQUIRE_THROW( force_settle( nathan_id, asset( 50, bitusd_id ) ), fc::exception );
|
||||
//
|
||||
// update_asset_options( bitusd_id, [&]( asset_options& new_options )
|
||||
// { new_options.flags &= ~disable_force_settle; } );
|
||||
//
|
||||
// // Can't settle more BitUSD than you own
|
||||
// GRAPHENE_REQUIRE_THROW( force_settle( nathan_id, asset( 999999, bitusd_id ) ), fc::exception );
|
||||
//
|
||||
// // settle3 should be least collateralized order according to index
|
||||
// BOOST_CHECK( db.get_index_type<call_order_index>().indices().get<by_collateral>().begin()->id == call3_id );
|
||||
// BOOST_CHECK_EQUAL( call3_id(db).debt.value, 3000 );
|
||||
//
|
||||
// BOOST_TEST_MESSAGE( "Verify partial settlement of call" );
|
||||
// // Partially settle a call
|
||||
// force_settlement_id_type settle_id = force_settle( nathan_id, asset( 50, bitusd_id ) ).get< object_id_type >();
|
||||
//
|
||||
// // Call does not take effect immediately
|
||||
// BOOST_CHECK_EQUAL( get_balance(nathan_id, bitusd_id), 14950);
|
||||
// BOOST_CHECK_EQUAL( settle_id(db).balance.amount.value, 50);
|
||||
// BOOST_CHECK_EQUAL( call3_id(db).debt.value, 3000 );
|
||||
// BOOST_CHECK_EQUAL( call3_id(db).collateral.value, 5780 );
|
||||
// BOOST_CHECK( settle_id(db).owner == nathan_id );
|
||||
//
|
||||
// // Wait for settlement to take effect
|
||||
// generate_blocks(settle_id(db).settlement_date);
|
||||
// BOOST_CHECK(db.find(settle_id) == nullptr);
|
||||
// BOOST_CHECK_EQUAL( bitusd_id(db).bitasset_data(db).force_settled_volume.value, 50 );
|
||||
// BOOST_CHECK_EQUAL( get_balance(nathan_id, bitusd_id), 14950);
|
||||
// BOOST_CHECK_EQUAL( get_balance(nathan_id, core_id), 49 ); // 1% force_settlement_offset_percent (rounded unfavorably)
|
||||
// BOOST_CHECK_EQUAL( call3_id(db).debt.value, 2950 );
|
||||
// BOOST_CHECK_EQUAL( call3_id(db).collateral.value, 5731 ); // 5731 == 5780-49
|
||||
//
|
||||
// BOOST_CHECK( db.get_index_type<call_order_index>().indices().get<by_collateral>().begin()->id == call3_id );
|
||||
//
|
||||
// BOOST_TEST_MESSAGE( "Verify pending settlement is cancelled when asset's force_settle is disabled" );
|
||||
// // Ensure pending settlement is cancelled when force settle is disabled
|
||||
// settle_id = force_settle( nathan_id, asset( 50, bitusd_id ) ).get< object_id_type >();
|
||||
//
|
||||
// BOOST_CHECK( !db.get_index_type<force_settlement_index>().indices().empty() );
|
||||
// update_asset_options( bitusd_id, [&]( asset_options& new_options )
|
||||
// { new_options.flags |= disable_force_settle; } );
|
||||
// BOOST_CHECK( db.get_index_type<force_settlement_index>().indices().empty() );
|
||||
// update_asset_options( bitusd_id, [&]( asset_options& new_options )
|
||||
// { new_options.flags &= ~disable_force_settle; } );
|
||||
//
|
||||
// BOOST_TEST_MESSAGE( "Perform iterative settlement" );
|
||||
// settle_id = force_settle( nathan_id, asset( 12500, bitusd_id ) ).get< object_id_type >();
|
||||
//
|
||||
// // c3 2950 : 5731 1.9427 fully settled
|
||||
// // c5 5000 : 9800 1.9600 fully settled
|
||||
// // c4 4000 : 7900 1.9750 fully settled
|
||||
// // c2 2000 : 3998 1.9990 550 settled
|
||||
// // c1 1000 : 2000 2.0000
|
||||
//
|
||||
// generate_blocks( settle_id(db).settlement_date );
|
||||
//
|
||||
// int64_t call1_payout = 0;
|
||||
// int64_t call2_payout = 550*99/100;
|
||||
// int64_t call3_payout = 49 + 2950*99/100;
|
||||
// int64_t call4_payout = 4000*99/100;
|
||||
// int64_t call5_payout = 5000*99/100;
|
||||
//
|
||||
// BOOST_CHECK_EQUAL( get_balance(shorter1_id, core_id), initial_balance-2*1000 ); // full collat still tied up
|
||||
// BOOST_CHECK_EQUAL( get_balance(shorter2_id, core_id), initial_balance-2*1999 ); // full collat still tied up
|
||||
// BOOST_CHECK_EQUAL( get_balance(shorter3_id, core_id), initial_balance-call3_payout ); // initial balance minus transfer to Nathan (as BitUSD)
|
||||
// BOOST_CHECK_EQUAL( get_balance(shorter4_id, core_id), initial_balance-call4_payout ); // initial balance minus transfer to Nathan (as BitUSD)
|
||||
// BOOST_CHECK_EQUAL( get_balance(shorter5_id, core_id), initial_balance-call5_payout ); // initial balance minus transfer to Nathan (as BitUSD)
|
||||
//
|
||||
// BOOST_CHECK_EQUAL( get_balance(nathan_id, core_id),
|
||||
// call1_payout + call2_payout + call3_payout + call4_payout + call5_payout );
|
||||
//
|
||||
// BOOST_CHECK( db.find(call3_id) == nullptr );
|
||||
// BOOST_CHECK( db.find(call4_id) == nullptr );
|
||||
// BOOST_CHECK( db.find(call5_id) == nullptr );
|
||||
//
|
||||
// BOOST_REQUIRE( db.find(call1_id) != nullptr );
|
||||
// BOOST_REQUIRE( db.find(call2_id) != nullptr );
|
||||
//
|
||||
// BOOST_CHECK_EQUAL( call1_id(db).debt.value, 1000 );
|
||||
// BOOST_CHECK_EQUAL( call1_id(db).collateral.value, 2000 );
|
||||
//
|
||||
// BOOST_CHECK_EQUAL( call2_id(db).debt.value, 2000-550 );
|
||||
// BOOST_CHECK_EQUAL( call2_id(db).collateral.value, 3998-call2_payout );
|
||||
// }
|
||||
// catch(fc::exception& e)
|
||||
// {
|
||||
// edump((e.to_detail_string()));
|
||||
// throw;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
BOOST_AUTO_TEST_CASE( assert_op_test )
|
||||
{
|
||||
try {
|
||||
|
|
@ -1316,6 +1316,7 @@ BOOST_AUTO_TEST_CASE(zero_second_vbo)
|
|||
create_op.owner = alice_id;
|
||||
create_op.amount = asset(500);
|
||||
create_op.policy = pinit;
|
||||
//create_op.balance_type = vesting_balance_type::unspecified;
|
||||
|
||||
signed_transaction create_tx;
|
||||
create_tx.operations.push_back( create_op );
|
||||
|
|
@ -1399,6 +1400,7 @@ BOOST_AUTO_TEST_CASE( vbo_withdraw_different )
|
|||
create_op.owner = alice_id;
|
||||
create_op.amount = asset(100, stuff_id);
|
||||
create_op.policy = pinit;
|
||||
//create_op.balance_type = vesting_balance_type::unspecified;
|
||||
|
||||
signed_transaction create_tx;
|
||||
create_tx.operations.push_back( create_op );
|
||||
|
|
|
|||
Loading…
Reference in a new issue