Skip to content

Commit

Permalink
BSIP81: Test default taker fees are used after hardfork if the asset …
Browse files Browse the repository at this point in the history
…owner does not set the taker fee
  • Loading branch information
MichelSantos committed Apr 21, 2020
1 parent 096d759 commit 5baa27f
Showing 1 changed file with 359 additions and 0 deletions.
359 changes: 359 additions & 0 deletions tests/tests/simple_maker_taker_fee_tests.cpp
Expand Up @@ -1152,6 +1152,141 @@ BOOST_FIXTURE_TEST_SUITE(simple_maker_taker_fee_tests, simple_maker_taker_databa
}


/**
* Test of **default** taker fees charged when filling limit orders after HF for a UIA.
*
* This test is similar to simple_match_and_fill_with_different_fees_uia_1
* except that the taker fee is not explicitly set and instead defaults to the maker fee.
*/
BOOST_AUTO_TEST_CASE(simple_match_and_fill_with_different_fees_uia_4) {
try {
// Initialize for the current time
trx.clear();
set_expiration(db, trx);

// Initialize actors
ACTORS((jill)(izzy)(alice)(bob));

// Initialize tokens
price price(asset(1, asset_id_type(1)), asset(1));

const uint16_t JILL_PRECISION = 100;
const uint16_t jill_market_fee_percent = 2 * GRAPHENE_1_PERCENT;
create_user_issued_asset("JCOIN", jill, charge_market_fee, price, 2,
jill_market_fee_percent);

const uint16_t IZZY_PRECISION = 1000;
const uint16_t izzy_market_fee_percent = 5 * GRAPHENE_1_PERCENT;
create_user_issued_asset("ICOIN", izzy, charge_market_fee, price, 3,
izzy_market_fee_percent);

// Obtain asset object after a block is generated to obtain the final object that is commited to the database
generate_block();
const asset_object& jillcoin = get_asset("JCOIN");
const asset_object& izzycoin = get_asset("ICOIN");


//////
// Advance to activate hardfork
//////
generate_blocks(HARDFORK_BSIP_81_TIME);
generate_block();
trx.clear();
set_expiration(db, trx);


//////
// After HF, test that default taker values has not been set
//////
// The taker fees should automatically default to maker fees if the taker fee is not explicitly set
// UNUSED: uint16_t jill_maker_fee_percent = jill_market_fee_percent;
uint16_t jill_taker_fee_percent = jill_market_fee_percent;

uint16_t izzy_maker_fee_percent = izzy_market_fee_percent;
// UNUSED: uint16_t izzy_taker_fee_percent = izzy_market_fee_percent;

// Check the taker fee for JCOIN: it should still not be set
asset_object updated_asset = jillcoin.get_id()(db);
BOOST_CHECK(!updated_asset.options.extensions.value.taker_fee_percent.valid());

// Check the taker fee for ICOIN: it should still not be set
updated_asset = izzycoin.get_id()(db);
BOOST_CHECK(!updated_asset.options.extensions.value.taker_fee_percent.valid());


//////
// After HF, create limit orders that will perfectly match
//////
BOOST_TEST_MESSAGE("Issuing 10 jillcoin to alice");
issue_uia(alice, jillcoin.amount(10 * JILL_PRECISION));
BOOST_TEST_MESSAGE("Checking alice's balance");
BOOST_REQUIRE_EQUAL(get_balance(alice, jillcoin), 10 * JILL_PRECISION);

BOOST_TEST_MESSAGE("Issuing 300 izzycoin to bob");
issue_uia(bob, izzycoin.amount(300 * IZZY_PRECISION));
BOOST_TEST_MESSAGE("Checking bob's balance");
BOOST_REQUIRE_EQUAL(get_balance(bob, izzycoin), 300 * IZZY_PRECISION);

// Alice and Bob place orders which match, and are completely filled by each other
// Alice is willing to sell 10 JILLCOIN for at least 300 IZZYCOIN
limit_order_create_operation alice_sell_op = create_sell_operation(alice.id,
jillcoin.amount(10 * JILL_PRECISION),
izzycoin.amount(300 *
IZZY_PRECISION));
trx.clear();
trx.operations.push_back(alice_sell_op);
asset alice_sell_fee = db.current_fee_schedule().set_fee(trx.operations.back());
sign(trx, alice_private_key);
processed_transaction ptx = PUSH_TX(db, trx); // No exception should be thrown
limit_order_id_type alice_order_id = ptx.operation_results[0].get<object_id_type>();

const limit_order_object* alice_order_before = db.find<limit_order_object>(alice_order_id);
BOOST_CHECK(alice_order_before != nullptr);

// Bob is willing to sell 300 IZZYCOIN for at least 10 JILLCOIN
limit_order_create_operation bob_sell_op = create_sell_operation(bob.id, izzycoin.amount(300 * IZZY_PRECISION),
jillcoin.amount(
10 *
JILL_PRECISION));
trx.clear();
trx.operations.push_back(bob_sell_op);
asset bob_sell_fee = db.current_fee_schedule().set_fee(trx.operations.back());
sign(trx, bob_private_key);
ptx = PUSH_TX(db, trx); // No exception should be thrown
limit_order_id_type bob_order_id = ptx.operation_results[0].get<object_id_type>();

// Check that the orders were filled by ensuring that they are no longer on the order books
const limit_order_object* alice_order = db.find<limit_order_object>(alice_order_id);
BOOST_CHECK(alice_order == nullptr);
const limit_order_object* bob_order = db.find<limit_order_object>(bob_order_id);
BOOST_CHECK(bob_order == nullptr);


// Check the new balances of the maker
// Alice was the maker; she is receiving IZZYCOIN
asset expected_izzy_fee = izzycoin.amount(
300 * IZZY_PRECISION * izzy_maker_fee_percent / GRAPHENE_100_PERCENT);
BOOST_REQUIRE_EQUAL(get_balance(alice, izzycoin),
(300 * IZZY_PRECISION) - alice_sell_fee.amount.value - expected_izzy_fee.amount.value);
BOOST_REQUIRE_EQUAL(get_balance(alice, jillcoin), 0);

// Check the new balance of the taker
// Bob was the taker; he is receiving JILLCOIN
asset expected_jill_fee = jillcoin.amount(
10 * JILL_PRECISION * jill_taker_fee_percent / GRAPHENE_100_PERCENT);
BOOST_REQUIRE_EQUAL(get_balance(bob, jillcoin),
(10 * JILL_PRECISION) - bob_sell_fee.amount.value - expected_jill_fee.amount.value);
BOOST_REQUIRE_EQUAL(get_balance(bob, izzycoin), 0);

// Check the asset issuer's accumulated fees
BOOST_CHECK(izzycoin.dynamic_asset_data_id(db).accumulated_fees == expected_izzy_fee.amount);
BOOST_CHECK(jillcoin.dynamic_asset_data_id(db).accumulated_fees == expected_jill_fee.amount);

} FC_LOG_AND_RETHROW()
}



/**
* Test of different maker and taker fees charged when filling limit orders after HF for a smart asset
*/
Expand Down Expand Up @@ -1590,4 +1725,228 @@ BOOST_FIXTURE_TEST_SUITE(simple_maker_taker_fee_tests, simple_maker_taker_databa
} FC_LOG_AND_RETHROW()
}


/**
* Test of **default** taker fees charged when filling limit orders after HF for a smart asset
* and a user-issued asset
*
* This test is similar to partial_maker_partial_taker_fills_1 except that
* (a) the taker fee is not explicitly set and instead defaults to the maker fee, and
* (b) Orders 1 and 2 are placed before the HF and Order 3 is placed after the HF.
*
* 1. (Order 1) An order will be placed to offer JCOIN
*
* 2. (Order 2) A matching-order will be placed to offer SMARTBIT.
* Order 2 is large enough that it should be partially filled, and Order 1 will be completely filled.
* Order 1 should be charged a maker fee, and Order 2 should be charged a taker fee.
* Order 2 should remain on the book.
*
* 3. (Order 3) A matching order will be placed to offer JCOIN.
* Order 3 should be charged a taker fee, and Order 2 should be charged a maker fee.
*
* Summary: Order 2 should be charged a taker fee when matching Order 1,
* and Order 2 should be charged a maker fee when matching Order 3.
*/
BOOST_AUTO_TEST_CASE(partial_maker_partial_taker_fills_2) {
try {
// Initialize for the current time
trx.clear();
set_expiration(db, trx);

// Initialize actors
ACTORS((jill)(izzy)(alice)(bob)(charlie));
ACTORS((smartissuer)(feedproducer));

// Initialize tokens
price price(asset(1, asset_id_type(1)), asset(1));
const uint16_t JILL_PRECISION = 100;
const uint16_t jill_market_fee_percent = 2 * GRAPHENE_1_PERCENT;
const asset_object jillcoin = create_user_issued_asset("JCOIN", jill, charge_market_fee, price, 2,
jill_market_fee_percent);

const uint16_t SMARTBIT_PRECISION = 10000;
const uint16_t smartbit_market_fee_percent = 2 * GRAPHENE_1_PERCENT;
create_bitasset("SMARTBIT", smartissuer.id, smartbit_market_fee_percent,
charge_market_fee, 4);

uint16_t jill_maker_fee_percent = jill_market_fee_percent;
uint16_t jill_taker_fee_percent = jill_market_fee_percent;

uint16_t smartbit_maker_fee_percent = smartbit_market_fee_percent;
uint16_t smartbit_taker_fee_percent = smartbit_market_fee_percent;


// Obtain asset object after a block is generated to obtain the final object that is commited to the database
generate_block();
const asset_object &smartbit = get_asset("SMARTBIT");

const auto &core = asset_id_type()(db);

update_feed_producers(smartbit, {feedproducer.id});

price_feed current_feed;
current_feed.settlement_price = smartbit.amount(100) / core.amount(100);
current_feed.maintenance_collateral_ratio = 1750; // need to set this explicitly, testnet has a different default
publish_feed(smartbit, feedproducer, current_feed);

FC_ASSERT(smartbit.bitasset_data(db).current_feed.settlement_price == current_feed.settlement_price);


//////
// Create Orders 1 and 2 to match.
// Order 1 will be completely filled, and Order 2 will be partially filled.
//////
// Initialize token balance of actors
BOOST_TEST_MESSAGE("Issuing 10 JCOIN to alice");
issue_uia(alice, jillcoin.amount(10 * JILL_PRECISION));
BOOST_TEST_MESSAGE("Checking alice's balance");
BOOST_REQUIRE_EQUAL(get_balance(alice, jillcoin), 10 * JILL_PRECISION);

BOOST_TEST_MESSAGE("Issuing 600 SMARTBIT to bob");
transfer(committee_account, bob.id, asset(2 * 1000 * SMARTBIT_PRECISION));
publish_feed(smartbit, feedproducer, current_feed); // Publish a recent feed
borrow(bob, smartbit.amount(600 * SMARTBIT_PRECISION), asset(2 * 600 * SMARTBIT_PRECISION));
BOOST_TEST_MESSAGE("Checking bob's balance");
BOOST_REQUIRE_EQUAL(get_balance(bob, smartbit), 600 * SMARTBIT_PRECISION);

// Alice and Bob place orders which match, and are completely filled by each other
// Alice is willing to sell 10 JILLCOIN for at least 300 SMARTBIT
limit_order_create_operation order_1_op = create_sell_operation(alice.id,
jillcoin.amount(10 * JILL_PRECISION),
smartbit.amount(300 * SMARTBIT_PRECISION));
trx.clear();
trx.operations.push_back(order_1_op);
asset alice_sell_fee = db.current_fee_schedule().set_fee(trx.operations.back());
sign(trx, alice_private_key);
processed_transaction ptx = PUSH_TX(db, trx); // No exception should be thrown
limit_order_id_type order_1_id = ptx.operation_results[0].get<object_id_type>();

const limit_order_object *order_1_before = db.find<limit_order_object>(order_1_id);
BOOST_CHECK(order_1_before != nullptr);


// Bob is willing to sell 600 SMARTBIT for at least 20 JILLCOIN
limit_order_create_operation order_2_op
= create_sell_operation(bob.id, smartbit.amount(600 * SMARTBIT_PRECISION),
jillcoin.amount(20 * JILL_PRECISION));
trx.clear();
trx.operations.push_back(order_2_op);
asset order_2_sell_fee = db.current_fee_schedule().set_fee(trx.operations.back());
sign(trx, bob_private_key);
ptx = PUSH_TX(db, trx); // No exception should be thrown
limit_order_id_type order_2_id = ptx.operation_results[0].get<object_id_type>();

// Check that order 1 was completely filled by ensuring that they it is no longer on the order book
const limit_order_object *order_1 = db.find<limit_order_object>(order_1_id);
BOOST_CHECK(order_1 == nullptr);
// Check that order 2 was partially filled by ensuring that they it is still on the order book
const limit_order_object *order_2 = db.find<limit_order_object>(order_2_id);
BOOST_CHECK(order_2 != nullptr);


// Check the new balances of the maker
// Alice was the maker; she is receiving SMARTBIT
asset expected_smartbit_fee = smartbit.amount(
300 * SMARTBIT_PRECISION * smartbit_maker_fee_percent / GRAPHENE_100_PERCENT);
int64_t expected_alice_balance_after_order_2 =
(300 * SMARTBIT_PRECISION) - alice_sell_fee.amount.value - expected_smartbit_fee.amount.value;
BOOST_REQUIRE_EQUAL(get_balance(alice, smartbit), expected_alice_balance_after_order_2);
BOOST_REQUIRE_EQUAL(get_balance(alice, jillcoin), 0);

// Check the new balance of the taker
// Bob was the taker; he is receiving JILLCOIN
asset expected_jill_fee = jillcoin.amount(
10 * JILL_PRECISION * jill_taker_fee_percent / GRAPHENE_100_PERCENT);
int64_t expected_bob_balance_after_order_2 =
(10 * JILL_PRECISION) - order_2_sell_fee.amount.value - expected_jill_fee.amount.value;
BOOST_REQUIRE_EQUAL(get_balance(bob, jillcoin), expected_bob_balance_after_order_2);
BOOST_REQUIRE_EQUAL(get_balance(bob, smartbit), 0);

// Check the asset issuer's accumulated fees
share_type expected_smartbit_fee_after_order_2 = expected_smartbit_fee.amount;
share_type expected_jill_fee_after_order_2 = expected_jill_fee.amount;
BOOST_CHECK(smartbit.dynamic_asset_data_id(db).accumulated_fees == expected_smartbit_fee_after_order_2);
BOOST_CHECK(jillcoin.dynamic_asset_data_id(db).accumulated_fees == expected_jill_fee_after_order_2);


//////
// After HF, The taker fees should automatically default to maker fees when the taker fee is not explicitly set
//////
// Check the taker fee for JILLCOIN
asset_object updated_asset = jillcoin.get_id()(db);
BOOST_CHECK(!updated_asset.options.extensions.value.taker_fee_percent.valid());

// Check the maker fee for JILLCOIN
uint16_t expected_maker_fee_percent = jill_maker_fee_percent;
BOOST_CHECK_EQUAL(expected_maker_fee_percent, updated_asset.options.market_fee_percent);

// Check the taker fee for SMARTBIT
updated_asset = smartbit.get_id()(db);
BOOST_CHECK(!updated_asset.options.extensions.value.taker_fee_percent.valid());

// Check the maker fee for SMARTBIT
expected_maker_fee_percent = smartbit_maker_fee_percent;
BOOST_CHECK_EQUAL(expected_maker_fee_percent, updated_asset.options.market_fee_percent);


//////
// Create Order 3 to match the remainder of match Order 2
//////
// Initialize token balance of actors
BOOST_TEST_MESSAGE("Issuing 5 JCOIN to charlie");
trx.clear();
issue_uia(charlie, jillcoin.amount(5 * JILL_PRECISION));
BOOST_TEST_MESSAGE("Checking charlie's balance");
BOOST_REQUIRE_EQUAL(get_balance(charlie, jillcoin), 5 * JILL_PRECISION);

// Charlie is is willing to sell 5 JILLCOIN for at least 150 SMARTBIT
limit_order_create_operation order_3_op = create_sell_operation(charlie.id,
jillcoin.amount(5 * JILL_PRECISION),
smartbit.amount(150 * SMARTBIT_PRECISION));
trx.clear();
trx.operations.push_back(order_3_op);
asset charlie_sell_fee = db.current_fee_schedule().set_fee(trx.operations.back());
sign(trx, charlie_private_key);
ptx = PUSH_TX(db, trx); // No exception should be thrown
limit_order_id_type order_3_id = ptx.operation_results[0].get<object_id_type>();

// Order 3 should be completely filled
const limit_order_object *order_3 = db.find<limit_order_object>(order_3_id);
BOOST_CHECK(order_3 == nullptr);

// Order 2 should be partially filled and still present on the order books
const limit_order_object *order_2_after = db.find<limit_order_object>(order_2_id);
BOOST_CHECK(order_2_after != nullptr);

// Check the new balance of the taker
// Charlie was the taker; he is receiving SMARTBIT
expected_smartbit_fee = smartbit.amount(
150 * SMARTBIT_PRECISION * smartbit_taker_fee_percent / GRAPHENE_100_PERCENT);
int64_t expected_charlie_balance_after_order_3 =
(150 * SMARTBIT_PRECISION) - charlie_sell_fee.amount.value - expected_smartbit_fee.amount.value;
BOOST_REQUIRE_EQUAL(get_balance(charlie, smartbit), expected_charlie_balance_after_order_3);
BOOST_REQUIRE_EQUAL(get_balance(charlie, jillcoin), 0);

// Check the new balance of the maker
// Bob was the maker; he is receiving JILLCOIN
asset expected_jill_order_3_fee = jillcoin.amount(
5 * JILL_PRECISION * jill_maker_fee_percent / GRAPHENE_100_PERCENT);
int64_t expected_bob_balance_after_order_3 =
expected_bob_balance_after_order_2
+ (5 * JILL_PRECISION) - expected_jill_order_3_fee.amount.value;
BOOST_REQUIRE_EQUAL(get_balance(bob, jillcoin), expected_bob_balance_after_order_3);
BOOST_REQUIRE_EQUAL(get_balance(bob, smartbit), 0);

// Check the asset issuer's accumulated fees
share_type expected_smartbit_fee_after_order_3 =
expected_smartbit_fee_after_order_2 + expected_smartbit_fee.amount;
share_type expected_jill_fee_after_order_3 = expected_jill_fee_after_order_2 + expected_jill_order_3_fee.amount;
BOOST_CHECK(smartbit.dynamic_asset_data_id(db).accumulated_fees == expected_smartbit_fee_after_order_3);
BOOST_CHECK(jillcoin.dynamic_asset_data_id(db).accumulated_fees == expected_jill_fee_after_order_3);
wdump((jillcoin.dynamic_asset_data_id(db).accumulated_fees)(expected_jill_fee_after_order_3)(expected_jill_fee_after_order_2)(expected_jill_fee.amount));
wdump((get_asset("JCOIN").dynamic_asset_data_id(db).accumulated_fees));

} FC_LOG_AND_RETHROW()
}

BOOST_AUTO_TEST_SUITE_END()

0 comments on commit 5baa27f

Please sign in to comment.