From 2a375a3866fa2c8942d36888c6ae1c10a3d6d08e Mon Sep 17 00:00:00 2001 From: Pi Lanningham <pi.lanningham@gmail.com> Date: Sat, 13 Jan 2024 00:31:05 -0500 Subject: [PATCH] Resolve SSW-304 The `datum` parameter was redundant, as we were already recursively passing down each of the fields anyway. However, as we hyper-optimized the swap operation, we added specific fields for each swap, and left the other order types unchanged. By passing in those specific parameters to individual functions, we can simplify the code and make it easier to reason about during the audit. --- lib/calculation/deposit.ak | 16 +++++++++------- lib/calculation/donation.ak | 21 +++++++++++---------- lib/calculation/process.ak | 15 ++++++--------- lib/calculation/withdrawal.ak | 14 ++++++++------ 4 files changed, 34 insertions(+), 32 deletions(-) diff --git a/lib/calculation/deposit.ak b/lib/calculation/deposit.ak index cc7c72d..e6c2d8b 100644 --- a/lib/calculation/deposit.ak +++ b/lib/calculation/deposit.ak @@ -4,16 +4,17 @@ use aiken/transaction/credential.{Address, VerificationKeyCredential} use aiken/transaction/value.{Value, ada_policy_id, ada_asset_name} use calculation/shared.{PoolState} as calc_shared use sundae/multisig -use types/order.{Destination, Deposit, OrderDatum} +use shared.{SingletonValue} +use types/order.{Destination, OrderDatum} pub fn do_deposit( pool_state: PoolState, input_value: Value, - order: OrderDatum, + assets: (SingletonValue, SingletonValue), + destination: Destination, actual_protocol_fee: Int, output: Output, ) -> PoolState { - expect order.Deposit { assets } = order.details let (asset_a, asset_b) = assets // Policy ID and token name of the assets must match the pool. @@ -74,8 +75,8 @@ pub fn do_deposit( issued_lp_tokens, ) - expect output.address == order.destination.address - expect output.datum == order.destination.datum + expect output.address == destination.address + expect output.datum == destination.datum expect output.value == out_value PoolState { quantity_a: ( @@ -119,6 +120,7 @@ test deposit_test() { let input_value = value.from_lovelace(14_500_000) |> value.add(rberry.1st, rberry.2nd, 10_000_000) + let assets = ((ada.1st, ada.2nd, 10_000_000), (rberry.1st, rberry.2nd, 10_000_000)) let order = OrderDatum { pool_ident: None, owner: multisig.Signature( @@ -130,7 +132,7 @@ test deposit_test() { datum: NoDatum, }, details: order.Deposit { - assets: ((ada.1st, ada.2nd, 10_000_000), (rberry.1st, rberry.2nd, 10_000_000)), + assets: assets, }, extension: Void, } @@ -141,7 +143,7 @@ test deposit_test() { datum: NoDatum, reference_script: None, } - let final_pool_state = do_deposit(pool_state, input_value, order, 2_500_000, output) + let final_pool_state = do_deposit(pool_state, input_value, assets, order.destination, 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 diff --git a/lib/calculation/donation.ak b/lib/calculation/donation.ak index cfb2937..6b15c4d 100644 --- a/lib/calculation/donation.ak +++ b/lib/calculation/donation.ak @@ -2,18 +2,18 @@ use aiken/transaction.{NoDatum, Output} use aiken/transaction/credential.{Address, VerificationKeyCredential} use aiken/transaction/value.{Value} use calculation/shared.{PoolState} as calc_shared -use shared +use shared.{SingletonValue} use sundae/multisig use types/order.{Destination, OrderDatum} pub fn do_donation( pool_state: PoolState, input_value: Value, - order: OrderDatum, + assets: (SingletonValue, SingletonValue), + destination: Destination, actual_protocol_fee: Int, output: Output, ) -> (PoolState, Bool) { - expect order.Donation { assets } = order.details expect assets.1st.1st == pool_state.quantity_a.1st expect assets.1st.2nd == pool_state.quantity_a.2nd expect assets.2nd.1st == pool_state.quantity_b.1st @@ -27,8 +27,8 @@ pub fn do_donation( let has_remainder = remainder != value.zero() let Void = if has_remainder { - expect output.address == order.destination.address - expect output.datum == order.destination.datum + expect output.address == destination.address + expect output.datum == destination.datum expect output.value == remainder Void } else { @@ -77,6 +77,10 @@ test donation() { let input_value = value.from_lovelace(1_000_000) |> value.add(rberry.1st, rberry.2nd, 1_000_000) + let assets = ( + (ada.1st, ada.2nd, 1_000_000), + (rberry.1st, rberry.2nd, 1_000_000), + ) let order = OrderDatum { pool_ident: None, @@ -86,10 +90,7 @@ test donation() { max_protocol_fee: 2_500_000, destination: Destination { address: addr, datum: NoDatum }, details: order.Donation { - assets: ( - (ada.1st, ada.2nd, 1_000_000), - (rberry.1st, rberry.2nd, 1_000_000), - ), + assets: assets, }, extension: Void, } @@ -102,7 +103,7 @@ test donation() { reference_script: None, } let (final_pool_state, has_remainder) = - do_donation(pool_state, input_value, order, 2_500_000, output) + do_donation(pool_state, input_value, assets, order.destination, 2_500_000, output) 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 diff --git a/lib/calculation/process.ak b/lib/calculation/process.ak index 4c455b6..ce610c4 100644 --- a/lib/calculation/process.ak +++ b/lib/calculation/process.ak @@ -96,7 +96,6 @@ pub fn process_order( value: Value, details: Order, max_protocol_fee: Int, - datum: OrderDatum, destination: Destination, amortized_base_fee: Int, simple_fee: Int, @@ -122,7 +121,6 @@ pub fn process_order( value, details, max_protocol_fee, - datum, destination, amortized_base_fee, // We pass strategy_fee here, instead of simple_fee, @@ -150,28 +148,28 @@ pub fn process_order( ) (next, rest_outputs, fee) } - order.Deposit(..) -> { + order.Deposit(assets) -> { // 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) + let next = deposit.do_deposit(initial, value, assets, destination, fee, output) (next, rest_outputs, fee) } - order.Withdrawal(..) -> { + order.Withdrawal(amount) -> { // 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 = - withdrawal.do_withdrawal(initial, value, datum, fee, output) + withdrawal.do_withdrawal(initial, value, amount, destination, fee, output) (next, rest_outputs, fee) } // order.Zap(..) -> do_zap(initial, input, datum) - order.Donation(..) -> { + order.Donation(assets) -> { // 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, used_output) = - donation.do_donation(initial, value, datum, fee, output) + donation.do_donation(initial, value, assets, destination, fee, output) if used_output { (next, rest_outputs, fee) } else { @@ -238,7 +236,6 @@ pub fn process_orders( order.value, details, max_protocol_fee, - datum, // TODO: can we get rid of this? destination, amortized_base_fee, simple_fee, diff --git a/lib/calculation/withdrawal.ak b/lib/calculation/withdrawal.ak index 4588d62..393a509 100644 --- a/lib/calculation/withdrawal.ak +++ b/lib/calculation/withdrawal.ak @@ -5,16 +5,17 @@ use aiken/transaction/credential.{Address, VerificationKeyCredential} use aiken/transaction/value.{Value, ada_policy_id, ada_asset_name} use calculation/shared.{PoolState} as calc_shared use sundae/multisig +use shared.{SingletonValue} use types/order.{Destination, OrderDatum} pub fn do_withdrawal( pool_state: PoolState, input_value: Value, - order: OrderDatum, + amount: SingletonValue, + destination: Destination, actual_protocol_fee: Int, output: Output, ) -> PoolState { - expect order.Withdrawal { amount } = order.details let (lp_policy, lp_asset_name, amount) = amount expect lp_policy == pool_state.quantity_lp.1st @@ -41,8 +42,8 @@ pub fn do_withdrawal( ) // Check that the payout is satisfied by the next output - expect output.address == order.destination.address - expect output.datum == order.destination.datum + expect output.address == destination.address + expect output.datum == destination.datum expect output.value == remainder PoolState { quantity_a: ( @@ -125,6 +126,7 @@ fn withdrawal_test(options: WithdrawalTestOptions) { let input_value = value.from_lovelace(4_500_000) |> value.add(lp.1st, lp.2nd, 10_000_000) + let amount = (lp.1st, lp.2nd, 10_000_000) let order = OrderDatum { pool_ident: None, owner: multisig.Signature( @@ -136,7 +138,7 @@ fn withdrawal_test(options: WithdrawalTestOptions) { datum: NoDatum, }, details: order.Withdrawal { - amount: (lp.1st, lp.2nd, 10_000_000), + amount }, extension: Void, } @@ -150,7 +152,7 @@ fn withdrawal_test(options: WithdrawalTestOptions) { datum: NoDatum, reference_script: None, } - let final_pool_state = do_withdrawal(pool_state, input_value, order, 2_500_000, output) + let final_pool_state = do_withdrawal(pool_state, input_value, amount, order.destination, 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