diff --git a/queries/orderbook/batch_rewards.sql b/queries/orderbook/batch_rewards.sql index 31e6dc25..664c0f01 100644 --- a/queries/orderbook/batch_rewards.sql +++ b/queries/orderbook/batch_rewards.sql @@ -28,13 +28,130 @@ WITH observed_settlements AS (SELECT WHERE block_deadline >= {{start_block}} AND block_deadline <= {{end_block}} GROUP BY ss.auction_id), +-- protocol fees: +order_surplus AS ( + SELECT + ss.winner as solver, + at.auction_id, + s.tx_hash, + t.order_uid, + o.sell_token, + o.buy_token, + t.sell_amount, -- the total amount the user sends + t.buy_amount, -- the total amount the user receives + oe.surplus_fee as observed_fee, -- the total discrepancy between what the user sends and what they would have send if they traded at clearing price + o.kind, + CASE + WHEN o.kind = 'sell' + THEN t.buy_amount - t.sell_amount * o.buy_amount / (o.sell_amount + o.fee_amount) + WHEN o.kind = 'buy' + THEN t.buy_amount * (o.sell_amount + o.fee_amount) / o.buy_amount - t.sell_amount + END AS surplus, + CASE + WHEN o.kind = 'sell' + THEN o.buy_token + WHEN o.kind = 'buy' + THEN o.sell_token + END AS surplus_token + FROM settlements s -- links block_number and log_index to tx_from and tx_nonce + JOIN auction_transaction at -- links auction_id to tx_from and tx_nonce + ON s.tx_from = at.tx_from AND s.tx_nonce = at.tx_nonce + JOIN settlement_scores ss -- contains block_deadline + ON at.auction_id = ss.auction_id + JOIN trades t -- contains traded amounts + ON s.block_number = t.block_number -- log_index cannot be checked, does not work correctly with multiple auctions on the same block + JOIN orders o -- contains tokens and limit amounts + ON t.order_uid = o.uid + JOIN order_execution oe -- contains surplus fee + ON t.order_uid = oe.order_uid AND at.auction_id = oe.auction_id + WHERE ss.block_deadline >= {{start_block}} + AND ss.block_deadline <= {{end_block}} +) +,order_protocol_fee AS ( + SELECT + os.auction_id, + os.solver, + os.tx_hash, + os.sell_amount, + os.buy_amount, + os.sell_token, + os.observed_fee, + os.surplus, + os.surplus_token, + CASE + WHEN fp.kind = 'surplus' + THEN + CASE + WHEN os.kind = 'sell' + THEN + -- We assume that the case surplus_factor != 1 always. In + -- that case reconstructing the protocol fee would be + -- impossible anyways. This query will return a division by + -- zero error in that case. + LEAST( + fp.max_volume_factor * os.sell_amount * os.buy_amount / (os.sell_amount - os.observed_fee), -- at most charge a fraction of volume + fp.surplus_factor / (1 - fp.surplus_factor) * surplus -- charge a fraction of surplus + ) + WHEN os.kind = 'buy' + THEN + LEAST( + fp.max_volume_factor / (1 + fp.max_volume_factor) * os.sell_amount, -- at most charge a fraction of volume + fp.surplus_factor / (1 - fp.surplus_factor) * surplus -- charge a fraction of surplus + ) + END + WHEN fp.kind = 'volume' + THEN fp.volume_factor / (1 + fp.volume_factor) * os.sell_amount + END AS protocol_fee, + CASE + WHEN fp.kind = 'surplus' + THEN os.surplus_token + WHEN fp.kind = 'volume' + THEN os.sell_token + END AS protocol_fee_token + FROM order_surplus os + JOIN fee_policies fp -- contains protocol fee policy + ON os.auction_id = fp.auction_id AND os.order_uid = fp.order_uid +) +,order_protocol_fee_prices AS ( + SELECT + opf.solver, + opf.tx_hash, + opf.surplus, + opf.protocol_fee, + CASE + WHEN opf.sell_token != opf.protocol_fee_token + THEN (opf.sell_amount - opf.observed_fee) / opf.buy_amount * opf.protocol_fee + ELSE opf.protocol_fee + END AS network_fee_correction, + opf.sell_token as network_fee_token, + ap_surplus.price / pow(10, 18) as surplus_token_price, + ap_protocol.price / pow(10, 18) as protocol_fee_token_price, + ap_sell.price / pow(10, 18) as network_fee_token_price + FROM order_protocol_fee opf + JOIN auction_prices ap_sell -- contains price: sell token + ON opf.auction_id = ap_sell.auction_id AND opf.sell_token = ap_sell.token + JOIN auction_prices ap_surplus -- contains price: surplus token + ON opf.auction_id = ap_surplus.auction_id AND opf.surplus_token = ap_surplus.token + JOIN auction_prices ap_protocol -- contains price: protocol fee token + ON opf.auction_id = ap_protocol.auction_id AND opf.protocol_fee_token = ap_protocol.token +), +batch_protocol_fees AS ( + SELECT + solver, + tx_hash, + -- sum(surplus * surplus_token_price) as surplus, + sum(protocol_fee * protocol_fee_token_price) as protocol_fee, + sum(network_fee_correction * network_fee_token_price) as network_fee_correction + FROM order_protocol_fee_prices + group by solver, tx_hash +), reward_data AS (SELECT -- observations - tx_hash, + os.tx_hash, ss.auction_id, -- TODO - Assuming that `solver == winner` when both not null -- We will need to monitor that `solver == winner`! - coalesce(solver, winner) as solver, + coalesce(os.solver, winner) as solver, block_number as settlement_block, block_deadline, case @@ -50,7 +167,10 @@ WITH observed_settlements AS (SELECT winning_score, reference_score, -- auction_participation - participating_solvers + participating_solvers, + -- protocol_fees + coalesce(cast(protocol_fee as numeric(78, 0)), 0) as protocol_fee, + coalesce(cast(network_fee_correction as numeric(78, 0)), 0) as network_fee_correction FROM settlement_scores ss -- If there are reported scores, -- there will always be a record of auction participants @@ -58,7 +178,9 @@ WITH observed_settlements AS (SELECT ON ss.auction_id = ap.auction_id -- outer joins made in order to capture non-existent settlements. LEFT OUTER JOIN observed_settlements os - ON os.auction_id = ss.auction_id), + ON os.auction_id = ss.auction_id + LEFT OUTER JOIN batch_protocol_fees bpf + ON bpf.tx_hash = os.tx_hash), reward_per_auction as (SELECT tx_hash, auction_id, settlement_block, @@ -66,10 +188,11 @@ WITH observed_settlements AS (SELECT solver, execution_cost, surplus, - fee, - surplus + fee - reference_score as uncapped_reward_eth, - -- Uncapped Reward = CLAMP_[-E, E + exec_cost](uncapped_reward_eth) - LEAST(GREATEST(-{{EPSILON}}, surplus + fee - reference_score), + protocol_fee, + fee - network_fee_correction as network_fee, + surplus + protocol_fee + fee - network_fee_correction - reference_score as uncapped_reward_eth, + -- capped Reward = CLAMP_[-E, E + exec_cost](uncapped_reward_eth) + LEAST(GREATEST(-{{EPSILON}}, surplus + coalesce(protocol_fee - network_fee_correction, 0) + fee - reference_score), {{EPSILON}} + execution_cost) as capped_payment, winning_score, reference_score, @@ -85,14 +208,21 @@ WITH observed_settlements AS (SELECT SUM(execution_cost) as exececution_cost_wei FROM reward_per_auction rpt GROUP BY solver), + protocol_fees as (SELECT solver, + SUM(protocol_fee) as protocol_fee_wei + FROM reward_per_auction rpt + GROUP BY solver), aggregate_results as (SELECT concat('0x', encode(pc.solver, 'hex')) as solver, coalesce(payment_wei, 0) as payment_eth, coalesce(exececution_cost_wei, 0) as execution_cost_eth, - num_participating_batches + num_participating_batches, + coalesce(protocol_fee_wei, 0) as protocol_fee_eth FROM participation_counts pc LEFT OUTER JOIN primary_rewards pr - ON pr.solver = pc.solver) - + ON pr.solver = pc.solver + LEFT OUTER JOIN protocol_fees pf + ON pf.solver = pc.solver) +-- select * from aggregate_results order by solver; diff --git a/src/fetch/payouts.py b/src/fetch/payouts.py index 45998382..4724f0ee 100644 --- a/src/fetch/payouts.py +++ b/src/fetch/payouts.py @@ -25,6 +25,8 @@ PERIOD_BUDGET_COW = 306646 * 10**18 QUOTE_REWARD = 9 * 10**18 +PROTOCOL_FEE_SAFE = Address("0xB64963f95215FDe6510657e719bd832BB8bb941B") + PAYMENT_COLUMNS = { "solver", "payment_eth", @@ -33,6 +35,7 @@ "reward_cow", "secondary_reward_cow", "quote_reward_cow", + "protocol_fee_eth", } SLIPPAGE_COLUMNS = { "solver", @@ -50,6 +53,7 @@ "secondary_reward_cow", "secondary_reward_eth", "quote_reward_cow", + "protocol_fee_eth", ] @@ -308,6 +312,14 @@ def prepare_transfers(payout_df: DataFrame, period: AccountingPeriod) -> PeriodP overdrafts.append(overdraft) transfers += payout_datum.as_payouts() + transfers.append( + Transfer( + token=None, + recipient=PROTOCOL_FEE_SAFE, + amount_wei=int(payout_df.protocol_fee_eth.sum()), + ) + ) + return PeriodPayouts(overdrafts, transfers) @@ -396,10 +408,12 @@ def construct_payouts( performance_reward = complete_payout_df["reward_cow"].sum() participation_reward = complete_payout_df["secondary_reward_cow"].sum() quote_reward = complete_payout_df["quote_reward_cow"].sum() + protocol_fee = complete_payout_df["protocol_fee_eth"].sum() dune.log_saver.print( f"Performance Reward: {performance_reward / 10 ** 18:.4f}\n" f"Participation Reward: {participation_reward / 10 ** 18:.4f}\n" - f"Quote Reward: {quote_reward / 10 ** 18:.4f}\n", + f"Quote Reward: {quote_reward / 10 ** 18:.4f}\n" + f"Protocol Fees: {protocol_fee / 10 ** 18:.4f}\n", category=Category.TOTALS, ) payouts = prepare_transfers(complete_payout_df, dune.period) diff --git a/tests/queries/batch_rewards_test_db.sql b/tests/queries/batch_rewards_test_db.sql index c984e1d4..05f92e5c 100644 --- a/tests/queries/batch_rewards_test_db.sql +++ b/tests/queries/batch_rewards_test_db.sql @@ -3,6 +3,14 @@ DROP TABLE IF EXISTS auction_transaction; DROP TABLE IF EXISTS auction_participants; DROP TABLE IF EXISTS settlement_scores; DROP TABLE IF EXISTS settlement_observations; +DROP TABLE IF EXISTS auction_prices; +DROP TABLE IF EXISTS orders; +DROP TYPE IF EXISTS OrderKind; +DROP TYPE IF EXISTS OrderClass; +DROP TABLE IF EXISTS trades; +DROP TABLE IF EXISTS order_execution; +DROP TABLE IF EXISTS fee_policies; +DROP TYPE IF EXISTS PolicyKind; CREATE TABLE IF NOT EXISTS settlements ( @@ -55,12 +63,83 @@ CREATE TABLE IF NOT EXISTS settlement_observations PRIMARY KEY (block_number, log_index) ); +CREATE TABLE IF NOT EXISTS auction_prices +( + auction_id bigint NOT NULL, + token bytea NOT NULL, + price numeric(78, 0) NOT NULL, + + PRIMARY KEY (auction_id, token) +); + +-- orders table +CREATE TYPE OrderKind AS ENUM ('buy', 'sell'); +CREATE TYPE OrderClass AS ENUM ('market', 'limit'); + +CREATE TABLE orders ( + uid bytea PRIMARY KEY, + sell_token bytea NOT NULL, + buy_token bytea NOT NULL, + sell_amount numeric(78,0) NOT NULL, + buy_amount numeric(78,0) NOT NULL, + fee_amount numeric(78,0) NOT NULL, + kind OrderKind NOT NULL, + partially_fillable boolean NOT NULL, + full_fee_amount numeric(78,0) NOT NULL, + class OrderClass NOT NULL +); + +CREATE TABLE IF NOT EXISTS trades +( + block_number bigint NOT NULL, + log_index bigint NOT NULL, + order_uid bytea NOT NULL, + sell_amount numeric(78, 0) NOT NULL, + buy_amount numeric(78, 0) NOT NULL, + fee_amount numeric(78, 0) NOT NULL, + + PRIMARY KEY (block_number, log_index) +); + +CREATE TABLE IF NOT EXISTS order_execution +( + order_uid bytea NOT NULL, + auction_id bigint NOT NULL, + reward double precision NOT NULL, + surplus_fee numeric(78, 0) NOT NULL, + solver_fee numeric(78, 0), + + PRIMARY KEY (order_uid, auction_id) +); + +CREATE TYPE PolicyKind AS ENUM ('surplus', 'volume'); + +CREATE TABLE fee_policies ( + auction_id bigint NOT NULL, + order_uid bytea NOT NULL, + -- The order in which the fee policies are inserted and applied. + application_order SERIAL NOT NULL, + -- The type of the fee policy. + kind PolicyKind NOT NULL, + -- The fee should be taken as a percentage of the price improvement. The value is between 0 and 1. + surplus_factor double precision, + -- Cap the fee at a certain percentage of the order volume. The value is between 0 and 1. + max_volume_factor double precision, + -- The fee should be taken as a percentage of the order volume. The value is between 0 and 1. + volume_factor double precision, + PRIMARY KEY (auction_id, order_uid, application_order) +); + TRUNCATE settlements; TRUNCATE auction_transaction; TRUNCATE auction_participants; TRUNCATE settlement_scores; TRUNCATE settlement_observations; +TRUNCATE auction_prices; +TRUNCATE orders; +TRUNCATE trades; +TRUNCATE fee_policies; INSERT INTO settlements (block_number, log_index, solver, tx_hash, tx_from, tx_nonce) @@ -70,7 +149,13 @@ VALUES (1, 10, '\x5111111111111111111111111111111111111111'::bytea, '\x7111'::by -- would the following entry be in the data base? (submitted too late) -- YES (20, 10, '\x5111111111111111111111111111111111111111'::bytea, '\x7444'::bytea, '\x5111111111111111111111111111111111111111'::bytea, 3), (25, 10, '\x5111111111111111111111111111111111111111'::bytea, '\x7555'::bytea, '\x5111111111111111111111111111111111111111'::bytea, 4), - (26, 10, '\x5111111111111111111111111111111111111111'::bytea, '\x7666'::bytea, '\x5111111111111111111111111111111111111111'::bytea, 6); + (26, 10, '\x5111111111111111111111111111111111111111'::bytea, '\x7666'::bytea, '\x5111111111111111111111111111111111111111'::bytea, 6), + (51, 10, '\x01'::bytea, '\x01'::bytea, '\x01'::bytea, 1), + (52, 10, '\x02'::bytea, '\x02'::bytea, '\x02'::bytea, 1), + (53, 10, '\x01'::bytea, '\x03'::bytea, '\x01'::bytea, 2), + (54, 10, '\x02'::bytea, '\x04'::bytea, '\x02'::bytea, 2), + (55, 10, '\x01'::bytea, '\x05'::bytea, '\x01'::bytea, 3), + (56, 10, '\x02'::bytea, '\x06'::bytea, '\x02'::bytea, 3); INSERT INTO auction_transaction (auction_id, tx_from, tx_nonce) VALUES (1, '\x5111111111111111111111111111111111111111'::bytea, 1), @@ -80,7 +165,13 @@ VALUES (1, '\x5111111111111111111111111111111111111111'::bytea, 1), (7, '\x5111111111111111111111111111111111111111'::bytea, 4), (8, '\x5111111111111111111111111111111111111111'::bytea, 5), -- would that entry be in the data base? (failed transaction) (9, '\x5111111111111111111111111111111111111111'::bytea, 6), - (10, '\x5333333333333333333333333333333333333333'::bytea, 1); -- would that entry be in the data base? (failed transaction) + (10, '\x5333333333333333333333333333333333333333'::bytea, 1), -- would that entry be in the data base? (failed transaction) + (51, '\x01'::bytea, 1), + (52, '\x02'::bytea, 1), + (53, '\x01'::bytea, 2), + (54, '\x02'::bytea, 2), + (55, '\x01'::bytea, 3), + (56, '\x02'::bytea, 3); INSERT INTO auction_participants (auction_id, participant) VALUES (1, '\x5222222222222222222222222222222222222222'::bytea), @@ -104,7 +195,13 @@ VALUES (1, '\x5222222222222222222222222222222222222222'::bytea), (9, '\x5333333333333333333333333333333333333333'::bytea), (9, '\x5111111111111111111111111111111111111111'::bytea), (10, '\x5444444444444444444444444444444444444444'::bytea), - (10, '\x5333333333333333333333333333333333333333'::bytea); + (10, '\x5333333333333333333333333333333333333333'::bytea), + (51, '\x01'::bytea), + (52, '\x02'::bytea), + (53, '\x01'::bytea), + (54, '\x02'::bytea), + (55, '\x01'::bytea), + (56, '\x02'::bytea); INSERT INTO settlement_scores (auction_id, winning_score, reference_score, winner, block_deadline, simulation_block) VALUES (1, 5000000000000000000, 4000000000000000000, '\x5111111111111111111111111111111111111111'::bytea, 10, 0), @@ -115,7 +212,13 @@ VALUES (1, 5000000000000000000, 4000000000000000000, '\x511111111111111111111111 (7, 5000000000000000000, 0, '\x5111111111111111111111111111111111111111'::bytea, 30, 6), -- no competition (8, 5000000000000000000, 0, '\x5111111111111111111111111111111111111111'::bytea, 35, 7), -- no competition, failed transaction (9, 5000000000000000000, 1000000000000000000, '\x5111111111111111111111111111111111111111'::bytea, 36, 8), -- score larger than quality - (10, 5000000000000000000, 4000000000000000000, '\x5333333333333333333333333333333333333333'::bytea, 37, 9); -- participant with net negative payment + (10, 5000000000000000000, 4000000000000000000, '\x5333333333333333333333333333333333333333'::bytea, 37, 9), -- participant with net negative payment + (51, 500000000000000, 0, '\x01'::bytea, 60, 50), + (52, 500000000000000, 0, '\x02'::bytea, 61, 51), + (53, 1000000000000000, 0, '\x01'::bytea, 62, 52), + (54, 2000000000000000, 0, '\x02'::bytea, 62, 52), + (55, 500000000000000, 0, '\x01'::bytea, 64, 54), + (56, 500000000000000, 0, '\x02'::bytea, 65, 55); -- score probably wrong, does not take protocol fee into account INSERT INTO settlement_observations (block_number, log_index, gas_used, effective_gas_price, surplus, fee) VALUES (1, 10, 100000, 2000000000, 6000000000000000000, 200000000000000), @@ -125,4 +228,52 @@ VALUES (1, 10, 100000, 2000000000, 6000000000000000000, 200000000000000), -- I would prefer to use the real numbers. What is backend gonna do. (20, 10, 100000, 2000000000, 0, 0), -- would that entry be in the data base? (submitted too late) (25, 10, 100000, 2000000000, 6000000000000000000, 200000000000000), - (26, 10, 100000, 2000000000, 0, 400000000000000); + (26, 10, 100000, 2000000000, 0, 400000000000000), + (51, 10, 100000, 25000000000, 500000000000000, 2500000000000000), + (52, 10, 100000, 25000000000, 500000000000000, 2500000000000000), + (53, 10, 100000, 25000000000, 500000000000000, 3000000000000000), + (54, 10, 100000, 25000000000, 500000000000000, 4000000000000000), + (55, 10, 100000, 25000000000, 500000000000000, 2500000000000000), + (56, 10, 100000, 25000000000, 500000000000000, 2500000000000000); + +INSERT INTO auction_prices (auction_id, token, price) +VALUES (51, '\x01', 500000000000000000000000000), +(51, '\x02', 500000000000000), +(52, '\x01', 500000000000000000000000000), +(52, '\x02', 500000000000000), +(53, '\x01', 500000000000000000000000000), +(53, '\x02', 500000000000000), +(54, '\x01', 500000000000000000000000000), +(54, '\x02', 500000000000000), +(55, '\x01', 500000000000000000000000000), +(55, '\x02', 500000000000000), +(56, '\x01', 500000000000000000000000000), +(56, '\x02', 500000000000000); + +INSERT INTO orders (uid, sell_token, buy_token, sell_amount, buy_amount, fee_amount, kind, partially_fillable, full_fee_amount, class) +VALUES ('\x01'::bytea, '\x01'::bytea, '\x02'::bytea, 95000000, 94000000000000000000, 5000000, 'sell', 'f', 5000000, 'market'), -- sell market order +('\x02'::bytea, '\x01'::bytea, '\x02'::bytea, 101000000, 100000000000000000000, 5000000, 'buy', 'f', 5000000, 'market'), -- buy market order +('\x03'::bytea, '\x01'::bytea, '\x02'::bytea, 100000000, 100000000000000000000, 0, 'sell', 't', 0, 'limit'), -- partially fillable sell limit order +('\x04'::bytea, '\x01'::bytea, '\x02'::bytea, 100000000, 100000000000000000000, 0, 'buy', 't', 0, 'limit'), -- partially fillable buy limit order +('\x05'::bytea, '\x01'::bytea, '\x02'::bytea, 100000000, 94000000000000000000, 0, 'sell', 'f', 0, 'limit'), -- in market sell limit order +('\x06'::bytea, '\x01'::bytea, '\x02'::bytea, 106000000, 100000000000000000000, 0, 'buy', 'f', 0, 'limit'); -- in market buy limit order + +INSERT INTO trades (block_number, log_index, order_uid, sell_amount, buy_amount, fee_amount) +VALUES (51, 0, '\x01'::bytea, 100000000, 95000000000000000000, 5000000), +(52, 0, '\x02'::bytea, 106000000, 100000000000000000000, 5000000), +(53, 0, '\x03'::bytea, 100000000, 101000000000000000000, 0), +(54, 0, '\x04'::bytea, 99000000, 100000000000000000000, 0), +(55, 0, '\x05'::bytea, 100000000, 95000000000000000000, 0), +(56, 0, '\x06'::bytea, 105000000, 100000000000000000000, 0); + +INSERT INTO order_execution (order_uid, auction_id, reward, surplus_fee, solver_fee) +VALUES ('\x03'::bytea, 53, 0, 5931372, NULL), +('\x04'::bytea, 54, 0, 6000000, NULL), +('\x05'::bytea, 55, 0, 6000000, NULL), +('\x06'::bytea, 56, 0, 6000000, NULL); + +INSERT INTO fee_policies (auction_id, order_uid, application_order, kind, surplus_factor, max_volume_factor, volume_factor) +VALUES (53, '\x03'::bytea, 3, 'surplus', 0.5, 0.02, NULL), +(54, '\x04'::bytea, 4, 'surplus', 0.75, 0.1, NULL), +(55, '\x05'::bytea, 5, 'volume', NULL, NULL, 0.0015), +(56, '\x06'::bytea, 6, 'surplus', 0.9, 0.01, NULL); diff --git a/tests/queries/test_batch_rewards.py b/tests/queries/test_batch_rewards.py index fc6f3fb2..f0605711 100644 --- a/tests/queries/test_batch_rewards.py +++ b/tests/queries/test_batch_rewards.py @@ -21,29 +21,45 @@ def test_get_batch_rewards(self): expected = DataFrame( { "solver": [ + "0x01", + "0x02", "0x5111111111111111111111111111111111111111", "0x5222222222222222222222222222222222222222", "0x5333333333333333333333333333333333333333", "0x5444444444444444444444444444444444444444", ], "payment_eth": [ + 9.534313722772278e15, + 10.5e15, 600000000000000.00000, 10450000000000000.00000, -10000000000000000.00000, 0.00000, ], "execution_cost_eth": [ + 7500000000000000.0, + 7500000000000000.0, 800000000000000.00000, 450000000000000.00000, 0.00000, 0.00000, ], "num_participating_batches": [ + 3, + 3, 7, 2, 7, 6, ], + "protocol_fee_eth": [ + 5.748876684972541e14, # 0.5 / (1 - 0.5) * 1e18 * 5e14 / 1e18 + 0.0015 / (1 + 0.0015) * 1e8 * 5e26 / 1e18 + 2.0198019801980198e15, # 0.75 / (1 - 0.75) * 1e6 * 5e26 / 1e18 + 0.01 / (1 + 0.01) * 105e6 * 5e26 / 1e18 + 0.0, + 0.0, + 0.0, + 0.0, + ], } ) self.assertIsNone(pandas.testing.assert_frame_equal(expected, batch_rewards)) diff --git a/tests/unit/test_payouts.py b/tests/unit/test_payouts.py index fc4ff8e5..682187f8 100644 --- a/tests/unit/test_payouts.py +++ b/tests/unit/test_payouts.py @@ -14,6 +14,7 @@ prepare_transfers, RewardAndPenaltyDatum, QUOTE_REWARD, + PROTOCOL_FEE_SAFE, ) from src.models.accounting_period import AccountingPeriod from src.models.overdraft import Overdraft @@ -67,6 +68,12 @@ def setUp(self) -> None: 7, 6, ] + self.protocol_fee_eth = [ + 1000000000000000.0, + 2000000000000000.0, + 0.0, + 0.0, + ] # Mocking TokenConversion! self.mock_converter = TokenConversion( eth_to_token=lambda t: int(t * 1000), token_to_eth=lambda t: t // 1000 @@ -79,6 +86,7 @@ def test_extend_payment_df(self): "payment_eth": self.eth_payments, "execution_cost_eth": self.execution_costs, "num_participating_batches": self.batch_participation, + "protocol_fee_eth": self.protocol_fee_eth, } base_payout_df = DataFrame(base_data_dict) result = extend_payment_df(base_payout_df, converter=self.mock_converter) @@ -88,6 +96,7 @@ def test_extend_payment_df(self): "payment_eth": self.eth_payments, "execution_cost_eth": self.execution_costs, "num_participating_batches": self.batch_participation, + "protocol_fee_eth": self.protocol_fee_eth, "reward_eth": [ -200000000000000.00000, 10000000000000000.00000, @@ -142,6 +151,7 @@ def test_validate_df_columns(self): "payment_eth": [], "execution_cost_eth": [], "num_participating_batches": [], + "protocol_fee_eth": [], "reward_eth": [], "reward_cow": [], "secondary_reward_cow": [], @@ -191,6 +201,7 @@ def test_construct_payouts(self): "payment_eth": self.eth_payments, "execution_cost_eth": self.execution_costs, "num_participating_batches": self.batch_participation, + "protocol_fee_eth": self.protocol_fee_eth, } ), converter=self.mock_converter, @@ -219,6 +230,12 @@ def test_construct_payouts(self): "payment_eth": [600000000000000.0, 1.045e16, -1e16, 0.0], "execution_cost_eth": [800000000000000.0, 450000000000000.0, 0.0, 0.0], "num_participating_batches": [7, 2, 7, 6], + "protocol_fee_eth": [ + 1000000000000000.0, + 2000000000000000.0, + 0.0, + 0.0, + ], "reward_eth": [-200000000000000.0, 1e16, -1e16, 0.0], "reward_cow": [ -200000000000000000, @@ -265,6 +282,7 @@ def test_prepare_transfers(self): "num_quotes": self.num_quotes, "payment_eth": [600000000000000.0, 1.045e16, -1e16, 0.0], "execution_cost_eth": [800000000000000.0, 450000000000000.0, 0.0, 0.0], + "protocol_fee_eth": self.protocol_fee_eth, "reward_eth": [-200000000000000.0, 1e16, -1e16, 0.0], "reward_cow": [ -200000000000000000, @@ -335,6 +353,11 @@ def test_prepare_transfers(self): recipient=Address(self.reward_targets[3]), amount_wei=54545454545454544, ), + Transfer( + token=None, + recipient=PROTOCOL_FEE_SAFE, + amount_wei=3000000000000000, + ), ], )