From b953a3420be7a651ccd3870868b502a439076da9 Mon Sep 17 00:00:00 2001 From: Pi Lanningham Date: Sat, 13 Jan 2024 02:06:53 -0500 Subject: [PATCH 1/3] Remove protocol fees from interim state Since we have to count the orders at the start anyway, we can just compute amortized_base_fee and the final protocol fee directly, without having to accumulate it per-order. This is the first step for that change, removing the fees from the interim state. --- lib/calculation/deposit.ak | 3 --- lib/calculation/donation.ak | 3 --- lib/calculation/process.ak | 4 ---- lib/calculation/shared.ak | 2 -- lib/calculation/swap.ak | 5 ----- lib/calculation/withdrawal.ak | 3 --- validators/pool.ak | 3 --- 7 files changed, 23 deletions(-) diff --git a/lib/calculation/deposit.ak b/lib/calculation/deposit.ak index cc7c72d..7345b40 100644 --- a/lib/calculation/deposit.ak +++ b/lib/calculation/deposit.ak @@ -94,7 +94,6 @@ pub fn do_deposit( pool_state.quantity_lp.3rd + issued_lp_tokens, ), fees_per_10_thousand: pool_state.fees_per_10_thousand, - protocol_fees: pool_state.protocol_fees + actual_protocol_fee, } } @@ -114,7 +113,6 @@ test deposit_test() { quantity_b: (rberry.1st, rberry.2nd, 1_000_000_000), quantity_lp: (lp.1st, lp.2nd, 1_000_000_000), fees_per_10_thousand: 5, - protocol_fees: 2_000_000, } let input_value = value.from_lovelace(14_500_000) @@ -144,6 +142,5 @@ test deposit_test() { let final_pool_state = do_deposit(pool_state, input_value, order, 2_500_000, output) expect final_pool_state.quantity_a.3rd == 1_010_000_000 expect final_pool_state.quantity_b.3rd == 1_010_000_000 - expect final_pool_state.protocol_fees == 4_500_000 True } diff --git a/lib/calculation/donation.ak b/lib/calculation/donation.ak index cfb2937..4371743 100644 --- a/lib/calculation/donation.ak +++ b/lib/calculation/donation.ak @@ -48,7 +48,6 @@ pub fn do_donation( ), quantity_lp: pool_state.quantity_lp, fees_per_10_thousand: pool_state.fees_per_10_thousand, - protocol_fees: pool_state.protocol_fees + actual_protocol_fee, }, has_remainder, ) @@ -72,7 +71,6 @@ test donation() { quantity_b: (rberry.1st, rberry.2nd, 1_000_000_000), quantity_lp: (lp.1st, lp.2nd, 1_000_000_000), fees_per_10_thousand: 5, - protocol_fees: 2_000_000, } let input_value = value.from_lovelace(1_000_000) @@ -106,6 +104,5 @@ test donation() { expect !has_remainder expect final_pool_state.quantity_a.3rd == 1_001_000_000 expect final_pool_state.quantity_b.3rd == 1_001_000_000 - expect final_pool_state.protocol_fees == 4_500_000 True } diff --git a/lib/calculation/process.ak b/lib/calculation/process.ak index 4c455b6..a2c04bf 100644 --- a/lib/calculation/process.ak +++ b/lib/calculation/process.ak @@ -76,8 +76,6 @@ pub fn pool_input_to_state( ), quantity_lp: (pool_token_policy, pool_lp_name(identifier), circulating_lp), fees_per_10_thousand: fees, - // Pay the transaction fee out of the protocol_fees - protocol_fees, } } @@ -286,7 +284,6 @@ test process_orders_test() { quantity_b: (rberry.1st, rberry.2nd, 1_000_000_000), quantity_lp: (lp.1st, lp.2nd, 1_000_000_000), fees_per_10_thousand: 5, - protocol_fees: 2_000_000, } let order_datum = OrderDatum { pool_ident: None, @@ -348,7 +345,6 @@ test process_orders_test() { expect final_pool_state.quantity_a.3rd == 1_001_000_000 expect final_pool_state.quantity_b.3rd == 1_001_000_000 - expect final_pool_state.protocol_fees == 4_500_000 expect simple == 1 expect strategies == 0 expect fee == 2_500_000 diff --git a/lib/calculation/shared.ak b/lib/calculation/shared.ak index dcc7abc..66da9c3 100644 --- a/lib/calculation/shared.ak +++ b/lib/calculation/shared.ak @@ -13,8 +13,6 @@ pub type PoolState { quantity_lp: SingletonValue, /// The fee the pool charges fees_per_10_thousand: Int, - /// The protocol_fees accumulated in the pool - protocol_fees: Int, } pub fn unsafe_fast_index_skip_with_tail(inputs: List, idx: Int) -> List { diff --git a/lib/calculation/swap.ak b/lib/calculation/swap.ak index b594d71..d806252 100644 --- a/lib/calculation/swap.ak +++ b/lib/calculation/swap.ak @@ -64,7 +64,6 @@ pub fn do_swap( quantity_b, quantity_lp, fees_per_10_thousand, - protocol_fees, } = pool_state let (a_policy_id, a_asset_name, a_amt) = quantity_a let (b_policy_id, b_asset_name, b_amt) = quantity_b @@ -97,7 +96,6 @@ pub fn do_swap( quantity_b: (b_policy_id, b_asset_name, b_amt - takes), quantity_lp, fees_per_10_thousand, - protocol_fees: protocol_fees + actual_protocol_fee, } } else if offer_policy_id == b_policy_id && offer_asset_name == b_asset_name { expect min_received.1st == a_policy_id @@ -126,7 +124,6 @@ pub fn do_swap( quantity_b: (b_policy_id, b_asset_name, b_amt + offer_amt), quantity_lp, fees_per_10_thousand, - protocol_fees: protocol_fees + actual_protocol_fee, } } else { fail @@ -152,7 +149,6 @@ test swap_mintakes_too_high() fail { quantity_b: (rberry.1st, rberry.2nd, 1_000_000_000), quantity_lp: (lp.1st, lp.2nd, 1_000_000_000), fees_per_10_thousand: 5, - protocol_fees: 2_000_000, } let input_value = value.from_lovelace(14_500_000) @@ -181,6 +177,5 @@ test swap_mintakes_too_high() fail { let final_pool_state = do_swap(pool_state, input_value, order.destination, 2_500_000, swap_offer, swap_min_received, output) expect final_pool_state.quantity_a.3rd == 1_000_000_000 + 10_000_000 expect final_pool_state.quantity_b.3rd == 1_000_000_000 - 9_896_088 - expect final_pool_state.protocol_fees == 4_500_000 True } diff --git a/lib/calculation/withdrawal.ak b/lib/calculation/withdrawal.ak index 4588d62..450a0e0 100644 --- a/lib/calculation/withdrawal.ak +++ b/lib/calculation/withdrawal.ak @@ -61,7 +61,6 @@ pub fn do_withdrawal( pool_state.quantity_lp.3rd - withdrawn, ), fees_per_10_thousand: pool_state.fees_per_10_thousand, - protocol_fees: pool_state.protocol_fees + actual_protocol_fee, } } @@ -120,7 +119,6 @@ fn withdrawal_test(options: WithdrawalTestOptions) { quantity_b: (rberry.1st, rberry.2nd, 1_010_000_000), quantity_lp: (lp.1st, lp.2nd, 1_010_000_000), fees_per_10_thousand: 5, - protocol_fees: 2_000_000, } let input_value = value.from_lovelace(4_500_000) @@ -153,6 +151,5 @@ fn withdrawal_test(options: WithdrawalTestOptions) { let final_pool_state = do_withdrawal(pool_state, input_value, order, 2_500_000, output) expect final_pool_state.quantity_a.3rd == 1_000_000_000 expect final_pool_state.quantity_b.3rd == 1_000_000_000 - expect final_pool_state.protocol_fees == 4_500_000 True } diff --git a/validators/pool.ak b/validators/pool.ak index 27a0566..a977adc 100644 --- a/validators/pool.ak +++ b/validators/pool.ak @@ -167,7 +167,6 @@ validator(settings_policy_id: PolicyId) { ) let PoolState { quantity_lp: expected_circulating_lp, - protocol_fees: expected_protocol_fees, .. } = outcome @@ -220,8 +219,6 @@ validator(settings_policy_id: PolicyId) { // expect pool_output_correct // Must update the circulating LP if tokens are minted expect actual_circulating_lp == expected_circulating_lp.3rd - // Must update the protocol fees field as expected - expect actual_protocol_fees == expected_protocol_fees // Must not update the immutable fields expect datum.identifier == output_datum.identifier expect datum.assets == output_datum.assets From b5a25f914d9dd3007c4b297690888f83eaf5215f Mon Sep 17 00:00:00 2001 From: Pi Lanningham Date: Sat, 13 Jan 2024 02:12:27 -0500 Subject: [PATCH 2/3] Calculate fees more straight-forwardly Since we have to count the number of orders anyway, we can just do so upfront; that lets us calculate the amortized protocol fees instead of relying on the scooper. We also can just calculate the final fee directly from the base fee, the number of simple orders, and the number of strategies. This may save quite a bit of calculation per order, but I haven't run the benchmark yet. It's also worth noting that I left amortized_base_fee in the redeemer for now, so we don't have to update all of our off-chain serialization code right away, but we should do this before launch. --- lib/calculation/process.ak | 29 +++++++++++------------- lib/types/pool.ak | 1 + validators/pool.ak | 46 +++++++++++++++++++++++--------------- 3 files changed, 42 insertions(+), 34 deletions(-) diff --git a/lib/calculation/process.ak b/lib/calculation/process.ak index a2c04bf..ee1bf31 100644 --- a/lib/calculation/process.ak +++ b/lib/calculation/process.ak @@ -25,7 +25,7 @@ pub fn pool_input_to_state( datum: PoolDatum, input: Output, valid_from: IntervalBound, -) -> PoolState { +) -> (PoolState, Int) { let PoolDatum { assets, protocol_fees, @@ -63,7 +63,7 @@ pub fn pool_input_to_state( fees_per_10_thousand.1st + (elapsed * range / duration) } } - PoolState { + (PoolState { quantity_a: ( asset_a_policy_id, asset_a_name, @@ -76,7 +76,7 @@ pub fn pool_input_to_state( ), quantity_lp: (pool_token_policy, pool_lp_name(identifier), circulating_lp), fees_per_10_thousand: fees, - } + }, protocol_fees) } fn validate_pool_id(order_pool_ident: Option, pool_ident: Ident) -> Bool { @@ -102,7 +102,7 @@ pub fn process_order( output: Output, outputs: List, rest_outputs: List -) -> (PoolState, List, Int) { +) -> (PoolState, List) { when details is { order.Strategy(signer) -> { expect Some(execution) = signed_execution @@ -146,14 +146,14 @@ pub fn process_order( min_received, output, ) - (next, rest_outputs, fee) + (next, rest_outputs) } order.Deposit(..) -> { // Make sure the scooper can only take up to the max fee the user has agreed to let fee = amortized_base_fee + simple_fee expect max_protocol_fee >= fee let next = deposit.do_deposit(initial, value, datum, fee, output) - (next, rest_outputs, fee) + (next, rest_outputs) } order.Withdrawal(..) -> { // Make sure the scooper can only take up to the max fee the user has agreed to @@ -161,7 +161,7 @@ pub fn process_order( expect max_protocol_fee >= fee let next = withdrawal.do_withdrawal(initial, value, datum, fee, output) - (next, rest_outputs, fee) + (next, rest_outputs) } // order.Zap(..) -> do_zap(initial, input, datum) order.Donation(..) -> { @@ -171,9 +171,9 @@ pub fn process_order( let (next, used_output) = donation.do_donation(initial, value, datum, fee, output) if used_output { - (next, rest_outputs, fee) + (next, rest_outputs) } else { - (next, outputs, fee) + (next, outputs) } } } @@ -195,10 +195,9 @@ pub fn process_orders( uniqueness_flag: Int, simple_count: Int, strategy_count: Int, - total_fee: Int, -) -> (PoolState, Int, Int, Int) { +) -> (PoolState, Int, Int) { when input_order is { - [] -> (initial, simple_count, strategy_count, total_fee) + [] -> (initial, simple_count, strategy_count) [(idx, sse), ..rest] -> { // Check that this idx is unique let next_uniqueness_flag = check_and_set_unique(uniqueness_flag, idx) @@ -228,7 +227,7 @@ pub fn process_orders( _ -> (simple_count + 1, strategy_count) } - let (next_state, next_orders, fee) = process_order( + let (next_state, next_orders) = process_order( initial, sse, output_reference, @@ -262,7 +261,6 @@ pub fn process_orders( next_uniqueness_flag, next_simple_count, next_strategy_count, - total_fee + fee ) } } @@ -341,12 +339,11 @@ test process_orders_test() { let inputs = [input] let outputs = [output] - let (final_pool_state, simple, strategies, fee) = process_orders(#"", valid_range, datums, pool_state, input_order, 2_500_000, 0, 0, 0, inputs, inputs, outputs, 0, 0, 0, 0) + let (final_pool_state, simple, strategies) = process_orders(#"", valid_range, datums, pool_state, input_order, 2_500_000, 0, 0, 0, inputs, inputs, outputs, 0, 0, 0) expect final_pool_state.quantity_a.3rd == 1_001_000_000 expect final_pool_state.quantity_b.3rd == 1_001_000_000 expect simple == 1 expect strategies == 0 - expect fee == 2_500_000 True } diff --git a/lib/types/pool.ak b/lib/types/pool.ak index eb7fff5..2d73b54 100644 --- a/lib/types/pool.ak +++ b/lib/types/pool.ak @@ -16,6 +16,7 @@ pub type PoolRedeemer { PoolScoop { signatory_index: Int, scooper_index: Int, + // TODO: remove this, and update all our off-chain tx building code amortized_base_fee: Int, input_order: List<(Int, Option)>, } diff --git a/validators/pool.ak b/validators/pool.ak index a977adc..be318fe 100644 --- a/validators/pool.ak +++ b/validators/pool.ak @@ -52,14 +52,15 @@ fn has_expected_pool_value( identifier: Ident, output_value: Value, outcome: PoolState, + final_protocol_fees: Int, ) -> Bool { // OPTIMIZATION: check that lovelace and assets match, rather than constructing a value - let PoolState { quantity_a, quantity_b, protocol_fees, .. } = outcome + let PoolState { quantity_a, quantity_b, .. } = outcome let (quantity_a_policy_id, quantity_a_name, quantity_a_amt) = quantity_a let (quantity_b_policy_id, quantity_b_name, quantity_b_amt) = quantity_b if quantity_a_policy_id == ada_policy_id { expect has_exact_token_count(output_value, 3) - expect value.lovelace_of(output_value) == protocol_fees + quantity_a_amt + expect value.lovelace_of(output_value) == final_protocol_fees + quantity_a_amt expect value.quantity_of(output_value, quantity_b_policy_id, quantity_b_name) == quantity_b_amt expect @@ -71,7 +72,7 @@ fn has_expected_pool_value( True } else { expect has_exact_token_count(output_value, 4) - expect value.lovelace_of(output_value) == protocol_fees + expect value.lovelace_of(output_value) == final_protocol_fees expect value.quantity_of(output_value, quantity_a_policy_id, quantity_a_name) == quantity_a_amt expect @@ -137,16 +138,27 @@ validator(settings_policy_id: PolicyId) { let settings_datum = find_settings_datum(reference_inputs, settings_policy_id) when redeemer is { - PoolScoop{ signatory_index, scooper_index, amortized_base_fee, input_order } -> { + PoolScoop{ signatory_index, scooper_index, input_order, .. } -> { // Deconstruct the settings datum with the fields we need for a scoop let SettingsDatum { authorized_scoopers, base_fee, simple_fee, strategy_fee, .. } = settings_datum + // Do a simple scan over the orders to count up the number of orders we'll be processing + // This is unavoidable, because it's part of making sure that the provided redeemer set isn't + // excluding orders + let real_order_count = count_orders(inputs) + // Calculate the portion of the fee that each order will be + // entitled to pay; + // Because the division is rounded down, we add real_order_count and subtact 1 + // to ensure that we take the ceiling instead, and round in the protocols favor. + let amortized_base_fee = (base_fee + real_order_count - 1) / real_order_count + // Make sure it's not negative, for example if base_fee was negative + expect amortized_base_fee >= 0 // Construct the initial pool state from the datum and the locked values - let initial_state = pool_input_to_state(pool_script_hash, datum, pool_input, validity_range.lower_bound) + let (initial_state, initial_protocol_fees) = pool_input_to_state(pool_script_hash, datum, pool_input, validity_range.lower_bound) // Process the orders in order, and decide the final pool state we should see // OPTIMIZATION: pass in the list of outputs, to pop off and compare in parallel - let (outcome, simple_count, strategy_count, total_protocol_fee) = + let (outcome, simple_count, strategy_count) = process_orders( actual_identifier, validity_range, @@ -163,7 +175,6 @@ validator(settings_policy_id: PolicyId) { 0, 0, 0, - 0, ) let PoolState { quantity_lp: expected_circulating_lp, @@ -172,20 +183,18 @@ validator(settings_policy_id: PolicyId) { // We need to make sure that the number of orders matches the amount that we processed // so the scooper doesn't "under-report" the orders and steal the funds on the order - let real_order_count = count_orders(inputs) expect simple_count + strategy_count == real_order_count - // the protocol enforces that the scooper doesn't take *more* than the max_protocol_fee - // but we can't enforce that it takes *exactly* this amount, because of rounding - // imagine with 30 orders, the max_protocol_fee is 1 ada + 30 * 0.1 ada = 4 ada - // the per-order fee would then be 0.133333 repeating; if we round up, - // we exceed the fee by 20 lovelace. If we round down, we undershoot by 10 lovelace - // so we just make sure that we have *at least 0* (to prevent a negative in the redeemer) - // and at most max_protocol_fee - let max_protocol_fee = base_fee + simple_count * simple_fee + strategy_count * strategy_fee + // We calculate the expected total collected protocol fee + // We multiply amortized_base_fee, which everyone paid, by the number of orders + // and then the respective fees for each simple order and strategy order + let expected_fees_collected = + amortized_base_fee * real_order_count + + simple_count * simple_fee + + strategy_count * strategy_fee - expect amortized_base_fee >= 0 - expect total_protocol_fee <= max_protocol_fee + // Make sure we actually increased the protocol fee by exactly this amount + expect actual_protocol_fees == initial_protocol_fees + expected_fees_collected // The pool should have all of the scooper fees, and the quantity of each token of the outcome // Note that initializing the state with `-transaction.fee` means this gets subracted out of the protocol fees @@ -215,6 +224,7 @@ validator(settings_policy_id: PolicyId) { output_datum.identifier, pool_output.value, outcome, + actual_protocol_fees, ) // expect pool_output_correct // Must update the circulating LP if tokens are minted From 6bcfd9f32e761a69c9d02b6204ee9800916bdbb1 Mon Sep 17 00:00:00 2001 From: Pi Lanningham Date: Sat, 13 Jan 2024 02:22:09 -0500 Subject: [PATCH 3/3] Remove fees_per_10k from intermediate state It never changes, so we were just incurring extra cost to construct a new pool_state with it; instead, we pass it in to the process_orders, so we can use it to calculate the swap. I have not benchmarked this, but figured it fit with simplifying the fees as a response to SSW-305. --- lib/calculation/deposit.ak | 2 -- lib/calculation/donation.ak | 2 -- lib/calculation/process.ak | 14 +++++++++----- lib/calculation/shared.ak | 2 -- lib/calculation/swap.ak | 7 ++----- lib/calculation/withdrawal.ak | 2 -- validators/pool.ak | 3 ++- 7 files changed, 13 insertions(+), 19 deletions(-) diff --git a/lib/calculation/deposit.ak b/lib/calculation/deposit.ak index 7345b40..bc388d8 100644 --- a/lib/calculation/deposit.ak +++ b/lib/calculation/deposit.ak @@ -93,7 +93,6 @@ pub fn do_deposit( pool_state.quantity_lp.2nd, pool_state.quantity_lp.3rd + issued_lp_tokens, ), - fees_per_10_thousand: pool_state.fees_per_10_thousand, } } @@ -112,7 +111,6 @@ test deposit_test() { quantity_a: (#"", #"", 1_000_000_000), quantity_b: (rberry.1st, rberry.2nd, 1_000_000_000), quantity_lp: (lp.1st, lp.2nd, 1_000_000_000), - fees_per_10_thousand: 5, } let input_value = value.from_lovelace(14_500_000) diff --git a/lib/calculation/donation.ak b/lib/calculation/donation.ak index 4371743..6f36099 100644 --- a/lib/calculation/donation.ak +++ b/lib/calculation/donation.ak @@ -47,7 +47,6 @@ pub fn do_donation( pool_state.quantity_b.3rd + assets.2nd.3rd, ), quantity_lp: pool_state.quantity_lp, - fees_per_10_thousand: pool_state.fees_per_10_thousand, }, has_remainder, ) @@ -70,7 +69,6 @@ test donation() { quantity_a: (#"", #"", 1_000_000_000), quantity_b: (rberry.1st, rberry.2nd, 1_000_000_000), quantity_lp: (lp.1st, lp.2nd, 1_000_000_000), - fees_per_10_thousand: 5, } let input_value = value.from_lovelace(1_000_000) diff --git a/lib/calculation/process.ak b/lib/calculation/process.ak index ee1bf31..d02695e 100644 --- a/lib/calculation/process.ak +++ b/lib/calculation/process.ak @@ -25,7 +25,7 @@ pub fn pool_input_to_state( datum: PoolDatum, input: Output, valid_from: IntervalBound, -) -> (PoolState, Int) { +) -> (PoolState, Int, Int) { let PoolDatum { assets, protocol_fees, @@ -75,8 +75,7 @@ pub fn pool_input_to_state( value.quantity_of(input.value, asset_b_policy_id, asset_b_name), ), quantity_lp: (pool_token_policy, pool_lp_name(identifier), circulating_lp), - fees_per_10_thousand: fees, - }, protocol_fees) + }, fees, protocol_fees) } fn validate_pool_id(order_pool_ident: Option, pool_ident: Ident) -> Bool { @@ -96,6 +95,7 @@ pub fn process_order( max_protocol_fee: Int, datum: OrderDatum, destination: Destination, + fees_per_10_thousand: Int, amortized_base_fee: Int, simple_fee: Int, strategy_fee: Int, @@ -122,6 +122,7 @@ pub fn process_order( max_protocol_fee, datum, destination, + fees_per_10_thousand, amortized_base_fee, // We pass strategy_fee here, instead of simple_fee, // reuse the code to calculate the result, but charge the higher fee @@ -141,6 +142,7 @@ pub fn process_order( initial, value, destination, + fees_per_10_thousand, fee, offer, min_received, @@ -185,6 +187,7 @@ pub fn process_orders( datums: Dict, Data>, initial: PoolState, input_order: List<(Int, Option)>, + fees_per_10_thousand: Int, amortized_base_fee: Int, simple_fee: Int, strategy_fee: Int, @@ -237,6 +240,7 @@ pub fn process_orders( max_protocol_fee, datum, // TODO: can we get rid of this? destination, + fees_per_10_thousand, amortized_base_fee, simple_fee, strategy_fee, @@ -251,6 +255,7 @@ pub fn process_orders( datums, next_state, rest, + fees_per_10_thousand, amortized_base_fee, simple_fee, strategy_fee, @@ -281,7 +286,6 @@ test process_orders_test() { quantity_a: (#"", #"", 1_000_000_000), quantity_b: (rberry.1st, rberry.2nd, 1_000_000_000), quantity_lp: (lp.1st, lp.2nd, 1_000_000_000), - fees_per_10_thousand: 5, } let order_datum = OrderDatum { pool_ident: None, @@ -339,7 +343,7 @@ test process_orders_test() { let inputs = [input] let outputs = [output] - let (final_pool_state, simple, strategies) = process_orders(#"", valid_range, datums, pool_state, input_order, 2_500_000, 0, 0, 0, inputs, inputs, outputs, 0, 0, 0) + let (final_pool_state, simple, strategies) = process_orders(#"", valid_range, datums, pool_state, input_order, 5, 2_500_000, 0, 0, 0, inputs, inputs, outputs, 0, 0, 0) expect final_pool_state.quantity_a.3rd == 1_001_000_000 expect final_pool_state.quantity_b.3rd == 1_001_000_000 diff --git a/lib/calculation/shared.ak b/lib/calculation/shared.ak index 66da9c3..17ba03d 100644 --- a/lib/calculation/shared.ak +++ b/lib/calculation/shared.ak @@ -11,8 +11,6 @@ pub type PoolState { quantity_b: SingletonValue, /// The quantity of LP tokens in the pool quantity_lp: SingletonValue, - /// The fee the pool charges - fees_per_10_thousand: Int, } pub fn unsafe_fast_index_skip_with_tail(inputs: List, idx: Int) -> List { diff --git a/lib/calculation/swap.ak b/lib/calculation/swap.ak index d806252..8244a1f 100644 --- a/lib/calculation/swap.ak +++ b/lib/calculation/swap.ak @@ -53,6 +53,7 @@ pub fn do_swap( pool_state: PoolState, input_value: Value, destination: Destination, + fees_per_10_thousand: Int, actual_protocol_fee: Int, offer: SingletonValue, min_received: SingletonValue, @@ -63,7 +64,6 @@ pub fn do_swap( quantity_a, quantity_b, quantity_lp, - fees_per_10_thousand, } = pool_state let (a_policy_id, a_asset_name, a_amt) = quantity_a let (b_policy_id, b_asset_name, b_amt) = quantity_b @@ -95,7 +95,6 @@ pub fn do_swap( quantity_a: (a_policy_id, a_asset_name, a_amt + offer_amt), quantity_b: (b_policy_id, b_asset_name, b_amt - takes), quantity_lp, - fees_per_10_thousand, } } else if offer_policy_id == b_policy_id && offer_asset_name == b_asset_name { expect min_received.1st == a_policy_id @@ -123,7 +122,6 @@ pub fn do_swap( quantity_a: (a_policy_id, a_asset_name, a_amt - takes), quantity_b: (b_policy_id, b_asset_name, b_amt + offer_amt), quantity_lp, - fees_per_10_thousand, } } else { fail @@ -148,7 +146,6 @@ test swap_mintakes_too_high() fail { quantity_a: (#"", #"", 1_000_000_000), quantity_b: (rberry.1st, rberry.2nd, 1_000_000_000), quantity_lp: (lp.1st, lp.2nd, 1_000_000_000), - fees_per_10_thousand: 5, } let input_value = value.from_lovelace(14_500_000) @@ -174,7 +171,7 @@ test swap_mintakes_too_high() fail { datum: NoDatum, reference_script: None, } - let final_pool_state = do_swap(pool_state, input_value, order.destination, 2_500_000, swap_offer, swap_min_received, output) + let final_pool_state = do_swap(pool_state, input_value, order.destination, 5, 2_500_000, swap_offer, swap_min_received, output) expect final_pool_state.quantity_a.3rd == 1_000_000_000 + 10_000_000 expect final_pool_state.quantity_b.3rd == 1_000_000_000 - 9_896_088 True diff --git a/lib/calculation/withdrawal.ak b/lib/calculation/withdrawal.ak index 450a0e0..55bba18 100644 --- a/lib/calculation/withdrawal.ak +++ b/lib/calculation/withdrawal.ak @@ -60,7 +60,6 @@ pub fn do_withdrawal( pool_state.quantity_lp.2nd, pool_state.quantity_lp.3rd - withdrawn, ), - fees_per_10_thousand: pool_state.fees_per_10_thousand, } } @@ -118,7 +117,6 @@ fn withdrawal_test(options: WithdrawalTestOptions) { quantity_a: (#"", #"", 1_010_000_000), quantity_b: (rberry.1st, rberry.2nd, 1_010_000_000), quantity_lp: (lp.1st, lp.2nd, 1_010_000_000), - fees_per_10_thousand: 5, } let input_value = value.from_lovelace(4_500_000) diff --git a/validators/pool.ak b/validators/pool.ak index be318fe..83ef12c 100644 --- a/validators/pool.ak +++ b/validators/pool.ak @@ -155,7 +155,7 @@ validator(settings_policy_id: PolicyId) { // Make sure it's not negative, for example if base_fee was negative expect amortized_base_fee >= 0 // Construct the initial pool state from the datum and the locked values - let (initial_state, initial_protocol_fees) = pool_input_to_state(pool_script_hash, datum, pool_input, validity_range.lower_bound) + let (initial_state, fees_per_10_thousand, initial_protocol_fees) = pool_input_to_state(pool_script_hash, datum, pool_input, validity_range.lower_bound) // Process the orders in order, and decide the final pool state we should see // OPTIMIZATION: pass in the list of outputs, to pop off and compare in parallel let (outcome, simple_count, strategy_count) = @@ -165,6 +165,7 @@ validator(settings_policy_id: PolicyId) { datums, initial_state, input_order, + fees_per_10_thousand, amortized_base_fee, simple_fee, strategy_fee,