diff --git a/aiken.lock b/aiken.lock index 9c94672..81dbdaf 100644 --- a/aiken.lock +++ b/aiken.lock @@ -13,7 +13,7 @@ source = "github" [[requirements]] name = "aiken-extra/tx_util" -version = "1.170.202312" +version = "39d4bceebeba6e02ffa72d2a2411487d97d2a738" source = "github" [[packages]] @@ -30,7 +30,7 @@ source = "github" [[packages]] name = "aiken-extra/tx_util" -version = "1.170.202312" +version = "39d4bceebeba6e02ffa72d2a2411487d97d2a738" requirements = [] source = "github" diff --git a/aiken.toml b/aiken.toml index 59afb2a..dc33795 100644 --- a/aiken.toml +++ b/aiken.toml @@ -20,5 +20,5 @@ source = "github" [[dependencies]] name = "aiken-extra/tx_util" -version = "1.170.202312" +version = "39d4bceebeba6e02ffa72d2a2411487d97d2a738" source = "github" diff --git a/build.sh b/build.sh index 5de9121..279db81 100755 --- a/build.sh +++ b/build.sh @@ -1,37 +1,120 @@ +AIKEN=$1 + aiken() { - /usr/bin/env aiken $* + ${AIKEN} $* } set -e -aiken build +echo "Software versions:" +echo " Git commit = $(git rev-parse HEAD)" +echo " Aiken Version = $(aiken --version)" + + +echo +echo "File hashes:" +SHA256=$(cat validators/oracle.ak | sha256sum | cut -f 1 -d ' ') +echo " validators/oracle.ak = ${SHA256}" +SHA256=$(cat validators/order.ak | sha256sum | cut -f 1 -d ' ') +echo " validators/order.ak = ${SHA256}" +SHA256=$(cat validators/pool_stake.ak | sha256sum | cut -f 1 -d ' ') +echo " validators/pool_stake.ak = ${SHA256}" +SHA256=$(cat validators/pool.ak | sha256sum | cut -f 1 -d ' ') +echo " validators/pool.ak = ${SHA256}" +SHA256=$(cat validators/settings.ak | sha256sum | cut -f 1 -d ' ') +echo " validators/settings.ak = ${SHA256}" +SHA256=$(cat validators/stake.ak | sha256sum | cut -f 1 -d ' ') +echo " validators/stake.ak = ${SHA256}" +echo +SHA256=$(cat lib/shared.ak | sha256sum | cut -f 1 -d ' ') +echo " lib/shared.ak = ${SHA256}" +SHA256=$(cat lib/types/oracle.ak | sha256sum | cut -f 1 -d ' ') +echo " lib/types/oracle.ak = ${SHA256}" +SHA256=$(cat lib/types/order.ak | sha256sum | cut -f 1 -d ' ') +echo " lib/types/order.ak = ${SHA256}" +SHA256=$(cat lib/types/pool.ak | sha256sum | cut -f 1 -d ' ') +echo " lib/types/pool.ak = ${SHA256}" +SHA256=$(cat lib/types/settings.ak | sha256sum | cut -f 1 -d ' ') +echo " lib/types/settings.ak = ${SHA256}" +SHA256=$(cat lib/calculation/deposit.ak | sha256sum | cut -f 1 -d ' ') +echo " lib/calculation/deposit.ak = ${SHA256}" +SHA256=$(cat lib/calculation/donation.ak | sha256sum | cut -f 1 -d ' ') +echo " lib/calculation/donation.ak = ${SHA256}" +SHA256=$(cat lib/calculation/process.ak | sha256sum | cut -f 1 -d ' ') +echo " lib/calculation/process.ak = ${SHA256}" +SHA256=$(cat lib/calculation/record.ak | sha256sum | cut -f 1 -d ' ') +echo " lib/calculation/record.ak = ${SHA256}" +SHA256=$(cat lib/calculation/shared.ak | sha256sum | cut -f 1 -d ' ') +echo " lib/calculation/shared.ak = ${SHA256}" +SHA256=$(cat lib/calculation/strategy.ak | sha256sum | cut -f 1 -d ' ') +echo " lib/calculation/strategy.ak = ${SHA256}" +SHA256=$(cat lib/calculation/swap.ak | sha256sum | cut -f 1 -d ' ') +echo " lib/calculation/swap.ak = ${SHA256}" +SHA256=$(cat lib/calculation/withdrawal.ak | sha256sum | cut -f 1 -d ' ') +echo " lib/calculation/withdrawal.ak = ${SHA256}" + +aiken build &> /dev/null -PROTOCOL_BOOT_UTXO="d8799fd8799f5820ebcee8dcdbd7312f5e04a0033472465003617abe9935a6e56f007961897cfabbff01ff" -aiken blueprint apply -v settings.spend $PROTOCOL_BOOT_UTXO > tmp +PROTOCOL_BOOT_TX="fad11baadca1e52bf34599746fb0152d9d10b31c2591b79deab34536a7998ea0" +PROTOCOL_BOOT_IX="01" +PROTOCOL_BOOT_UTXO="d8799fd8799f5820${PROTOCOL_BOOT_TX}ff${PROTOCOL_BOOT_IX}ff" + +aiken blueprint apply -v settings.spend $PROTOCOL_BOOT_UTXO 2> /dev/null > tmp mv tmp plutus.json -aiken blueprint apply -v settings.mint $PROTOCOL_BOOT_UTXO > tmp +aiken blueprint apply -v settings.mint $PROTOCOL_BOOT_UTXO 2> /dev/null > tmp mv tmp plutus.json -SETTINGS_SCRIPT_HASH="581c$(aiken blueprint policy -v settings.mint)" -aiken blueprint apply -v pool.manage $SETTINGS_SCRIPT_HASH > tmp +SETTINGS_SCRIPT_HASH="$(aiken blueprint policy -v settings.mint 2> /dev/null)" +aiken blueprint apply -v pool.manage "581c${SETTINGS_SCRIPT_HASH}" 2> /dev/null > tmp mv tmp plutus.json -MANAGE_STAKE_SCRIPT_HASH="581c$(aiken blueprint policy -v pool.manage)" -aiken blueprint apply -v pool.spend $MANAGE_STAKE_SCRIPT_HASH > tmp +MANAGE_STAKE_SCRIPT_HASH="$(aiken blueprint policy -v pool.manage 2> /dev/null)" +aiken blueprint apply -v pool.spend "581c${MANAGE_STAKE_SCRIPT_HASH}" 2> /dev/null > tmp mv tmp plutus.json -aiken blueprint apply -v pool.spend $SETTINGS_SCRIPT_HASH > tmp +aiken blueprint apply -v pool.spend "581c${SETTINGS_SCRIPT_HASH}" 2> /dev/null > tmp mv tmp plutus.json -aiken blueprint apply -v pool.mint $MANAGE_STAKE_SCRIPT_HASH > tmp +aiken blueprint apply -v pool.mint "581c${MANAGE_STAKE_SCRIPT_HASH}" 2> /dev/null > tmp +mv tmp plutus.json +aiken blueprint apply -v pool.mint "581c${SETTINGS_SCRIPT_HASH}" 2> /dev/null > tmp mv tmp plutus.json -aiken blueprint apply -v pool.mint $SETTINGS_SCRIPT_HASH > tmp + +POOL_SCRIPT_HASH="$(aiken blueprint policy -v pool.mint 2> /dev/null)" +aiken blueprint apply -v stake.stake "581c${POOL_SCRIPT_HASH}" 2> /dev/null > tmp mv tmp plutus.json -POOL_SCRIPT_HASH="581c$(aiken blueprint policy -v pool.mint)" -aiken blueprint apply -v stake.stake $POOL_SCRIPT_HASH > tmp +aiken blueprint apply -v pool_stake.stake "581c${SETTINGS_SCRIPT_HASH}" 2> /dev/null > tmp +mv tmp plutus.json +aiken blueprint apply -v pool_stake.stake "00" 2> /dev/null > tmp mv tmp plutus.json -STAKE_SCRIPT_HASH="581c$(aiken blueprint policy -v stake.stake)" -aiken blueprint apply -v order.spend $STAKE_SCRIPT_HASH > tmp +aiken blueprint apply -v oracle.spend "581c${POOL_SCRIPT_HASH}" 2> /dev/null > tmp mv tmp plutus.json +aiken blueprint apply -v oracle.mint "581c${POOL_SCRIPT_HASH}" 2> /dev/null > tmp +mv tmp plutus.json + +STAKE_SCRIPT_HASH="$(aiken blueprint policy -v stake.stake 2> /dev/null)" +aiken blueprint apply -v order.spend "581c${STAKE_SCRIPT_HASH}" 2> /dev/null > tmp +mv tmp plutus.json + +ORACLE_SCRIPT_HASH="$(aiken blueprint policy -v oracle.mint 2> /dev/null)" +POOL_STAKE_SCRIPT_HASH="$(aiken blueprint policy -v pool_stake.stake 2> /dev/null)" +ORDER_SCRIPT_HASH="$(aiken blueprint hash -v order.spend 2> /dev/null)" + +echo +echo "Parameters:" +echo -e " PROTOCOL_BOOT_UTXO = \e[32m ${PROTOCOL_BOOT_TX}#${PROTOCOL_BOOT_IX} \e[0m" + +echo +echo "Script Hashes:" +echo -e " Settings Script Hash / Policy = \e[32m ${SETTINGS_SCRIPT_HASH} \e[0m" +echo -e " Pool Script Hash / Policy = \e[32m ${POOL_SCRIPT_HASH} \e[0m" +echo -e " Pool Stake Script Hash = \e[32m ${POOL_STAKE_SCRIPT_HASH} \e[0m" +echo -e " Manage Stake Script Hash = \e[32m ${MANAGE_STAKE_SCRIPT_HASH} \e[0m" +echo -e " Treasury Stake Script Hash = \e[32m ${STAKE_SCRIPT_HASH} \e[0m" +echo -e " Order Script Hash = \e[32m ${ORDER_SCRIPT_HASH} \e[0m" +echo -e " Oracle Script Hash = \e[32m ${ORACLE_SCRIPT_HASH} \e[0m" + +echo +echo diff --git a/lib/calculation/deposit.ak b/lib/calculation/deposit.ak index 4335089..1fbe961 100644 --- a/lib/calculation/deposit.ak +++ b/lib/calculation/deposit.ak @@ -1,11 +1,11 @@ use aiken/math -use aiken/transaction.{NoDatum, Output, InlineDatum} +use aiken/transaction.{InlineDatum, NoDatum, Output} use aiken/transaction/credential.{Address, VerificationKeyCredential} -use aiken/transaction/value.{ada_policy_id, ada_asset_name, PolicyId, AssetName} +use aiken/transaction/value.{AssetName, PolicyId, ada_asset_name, ada_policy_id} use calculation/shared.{PoolState} as calc_shared -use sundae/multisig use shared.{SingletonValue} -use types/order.{Destination, Fixed, Self, OrderDatum} +use sundae/multisig +use types/order.{Destination, Fixed, OrderDatum, Self} /// Calculate the result of depositing some amount of tokens into the pool /// @@ -73,8 +73,7 @@ pub fn do_deposit( // The ratio of a to b might have shifted since the user created their order amount // So some small amount of a or b might be returned to the user // So, calculate how much "b" do we have, in units of asset A, so we can check which is greater - let b_in_units_of_a = - user_gives_b * pool_quantity_a / pool_quantity_b + let b_in_units_of_a = user_gives_b * pool_quantity_a / pool_quantity_b // Amount that user actually deposits in the pool, after giving back change. let (deposited_a, deposited_b) = @@ -84,7 +83,7 @@ pub fn do_deposit( // Make sure to do ceiling division here, to round in favor fo the protocol // That is, when in doubt, take up to one more token from the user than the // LP tokens we issue would entail - let give_b = ((pool_quantity_b * user_gives_a - 1) / pool_quantity_a) + 1 + let give_b = ( pool_quantity_b * user_gives_a - 1 ) / pool_quantity_a + 1 (user_gives_a, give_b) } else { (b_in_units_of_a, user_gives_b) @@ -98,8 +97,7 @@ pub fn do_deposit( // issued_lp_tokens / (pool_state.quantity_lp.3rd + issued_lp_tokens) = deposited_a / (pool_state.quantity_a.3rd + deposited_a) // // Solving for `issued_lp_tokens` gives: - let issued_lp_tokens = - deposited_a * pool_quantity_lp / pool_quantity_a + let issued_lp_tokens = deposited_a * pool_quantity_lp / pool_quantity_a // Make sure we don't ever allow this to round to zero, which would just eat some of the users assets expect issued_lp_tokens > 0 @@ -112,31 +110,27 @@ pub fn do_deposit( |> value.add(asset_a.1st, asset_a.2nd, -deposited_a) |> value.add(asset_b.1st, asset_b.2nd, -deposited_b) |> value.add(ada_policy_id, ada_asset_name, -actual_protocol_fee) - |> value.add( - pool_policy_lp, - pool_asset_name_lp, - issued_lp_tokens, - ) + |> value.add(pool_policy_lp, pool_asset_name_lp, issued_lp_tokens) // Make sure we're paying the result to the correct destination (both the address and the datum), // with the correct amount; In the special case where Datum is "Self" (for example for a repeating strategy) // use the input datum for validation expect output.value == out_value - expect when destination is { - Fixed { address, datum } -> { - and { - output.address == address, - output.datum == datum + expect + when destination is { + Fixed { address, datum } -> and { + output.address == address, + output.datum == datum, + } + Self -> { + let Output { address: input_address, datum: input_datum, .. } = + input_utxo + and { + output.address == input_address, + output.datum == input_datum, + } } } - Self -> { - let Output { address: input_address, datum: input_datum, .. } = input_utxo - and { - output.address == input_address, - output.datum == input_datum - } - } - } // And construct the final pool state continuation( @@ -155,53 +149,67 @@ test deposit_test() { None, ) let ada = (#"", #"") - let rberry = (#"01010101010101010101010101010101010101010101010101010101", "RBERRY") + let rberry = + (#"01010101010101010101010101010101010101010101010101010101", "RBERRY") let lp = (#"99999999999999999999999999999999999999999999999999999999", "LP") - let pool_state = PoolState { - 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), - } + let pool_state = + PoolState { + 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), + } 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( - #"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513", - ), - max_protocol_fee: 2_500_000, - destination: Fixed { + 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( + #"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513", + ), + max_protocol_fee: 2_500_000, + destination: Fixed { address: addr, datum: NoDatum }, + details: order.Deposit { assets }, + extension: Void, + } + let output = + Output { address: addr, + value: value.from_lovelace(2_000_000) + |> value.add(lp.1st, lp.2nd, 10_000_000), datum: NoDatum, - }, - details: order.Deposit { - assets: assets, - }, - extension: Void, - } - let output = Output { - address: addr, - value: value.from_lovelace(2_000_000) - |> value.add(lp.1st, lp.2nd, 10_000_000), - datum: NoDatum, - reference_script: None, - } - let input = Output { - address: addr, - value: input_value, - datum: InlineDatum(order), - reference_script: None, - } - let new_a, new_b, new_lp <- do_deposit( - pool_state.quantity_a.1st, pool_state.quantity_a.2nd, pool_state.quantity_a.3rd, - pool_state.quantity_b.1st, pool_state.quantity_b.2nd, pool_state.quantity_b.3rd, - pool_state.quantity_lp.1st, pool_state.quantity_lp.2nd, pool_state.quantity_lp.3rd, - input, assets, - order.destination, 2_500_000, - output - ) + reference_script: None, + } + let input = + Output { + address: addr, + value: input_value, + datum: InlineDatum(order), + reference_script: None, + } + let + new_a, + new_b, + new_lp, + <- + do_deposit( + pool_state.quantity_a.1st, + pool_state.quantity_a.2nd, + pool_state.quantity_a.3rd, + pool_state.quantity_b.1st, + pool_state.quantity_b.2nd, + pool_state.quantity_b.3rd, + pool_state.quantity_lp.1st, + pool_state.quantity_lp.2nd, + pool_state.quantity_lp.3rd, + input, + assets, + order.destination, + 2_500_000, + output, + ) expect new_a == 1_010_000_000 expect new_b == 1_010_000_000 expect new_lp == 1_000_000_000 + 10_000_000 diff --git a/lib/calculation/donation.ak b/lib/calculation/donation.ak index 9a83b10..4a4728d 100644 --- a/lib/calculation/donation.ak +++ b/lib/calculation/donation.ak @@ -1,15 +1,15 @@ use aiken/transaction.{Output} -use aiken/transaction/value.{ada_policy_id, ada_asset_name, PolicyId, AssetName} +use aiken/transaction/value.{AssetName, PolicyId, ada_asset_name, ada_policy_id} use shared.{SingletonValue} use types/order.{Destination, Fixed, Self} +// +// Calculates the new pool state, and whether to consume this output or not /// A donation describes an amount of assets to deposit into the pool, receiving nothing in return (except for the extra change on the UTXO). /// Because every LP token holder has an entitlement to a percentage of the assets in the pool, the donation is distributed to all LP token holders /// pro-rata. /// An end-user might have little use for something like this, but it becomes a powerful primitive for other protocols to create automated /// incentive programs on chain. For example, revenue from activity on chain can be donated to the project tokens pool as a liquidity incentive. -// -// Calculates the new pool state, and whether to consume this output or not pub fn do_donation( /// The pool state as a result of processing all orders before this one pool_policy_a: PolicyId, @@ -31,10 +31,13 @@ pub fn do_donation( /// If there is no change leftover, this output is ignored and used for the next order output: Output, // A continuation to call with the new pool balances, and whether to skip an output; more efficient than constructing an object each time - continuation: fn(Int, Int, Bool) -> Bool + continuation: fn(Int, Int, Bool) -> Bool, ) -> Bool { let Output { value: input_value, .. } = input_utxo - let ((asset_a_policy_id, asset_a_asset_name, asset_a_qty), (asset_b_policy_id, asset_b_asset_name, asset_b_qty)) = assets + let ( + (asset_a_policy_id, asset_a_asset_name, asset_a_qty), + (asset_b_policy_id, asset_b_asset_name, asset_b_qty), + ) = assets // Make sure we're actually donating the pool assets; this is to prevent setting // poolIdent to None, and then filling the pool UTXO with garbage tokens and eventually locking it expect asset_a_policy_id == pool_policy_a @@ -52,30 +55,28 @@ pub fn do_donation( // If we have a remainder, then we need to check the details of the output; this awkward structure // is so that we can do a few expects without having to return a value right away expect or { - !has_remainder, - // Make sure we're paying the result to the correct destination (both the address and the datum), - // with the correct amount; In the special case where Datum is "Self" (for example for a repeating strategy) - // use the input datum for validation - and { - output.value == remainder, - when destination is { - Fixed { address, datum } -> { - and { - output.address == address, - output.datum == datum - } - } - Self -> { - let Output { address: input_address, datum: input_datum, .. } = input_utxo - and { - output.address == input_address, - output.datum == input_datum + !has_remainder, + // Make sure we're paying the result to the correct destination (both the address and the datum), + // with the correct amount; In the special case where Datum is "Self" (for example for a repeating strategy) + // use the input datum for validation + and { + output.value == remainder, + when destination is { + Fixed { address, datum } -> and { + output.address == address, + output.datum == datum, + } + Self -> { + let Output { address: input_address, datum: input_datum, .. } = + input_utxo + and { + output.address == input_address, + output.datum == input_datum, + } } - } + }, }, } - } - // Continue with the new pool state, which is exactly the old pool state, plus the // quantities of assets donated, plus the protocol fee! // We also returned whether we had a remainder or not, so the calling function knows diff --git a/lib/calculation/process.ak b/lib/calculation/process.ak index 79658c4..6683bc7 100644 --- a/lib/calculation/process.ak +++ b/lib/calculation/process.ak @@ -1,65 +1,50 @@ use aiken/bytearray use aiken/cbor -use aiken/math use aiken/dict.{Dict} use aiken/hash.{Blake2b_256, Hash} -use aiken/interval.{IntervalBound, NegativeInfinity, Finite} -use aiken/transaction.{InlineDatum, NoDatum, Input, Output, OutputReference, TransactionId, ValidityRange} -use aiken/transaction/credential.{Address, ScriptCredential, StakeCredential, VerificationKeyCredential} -use aiken/transaction/value.{Value, PolicyId, AssetName} -use aiken/time.{PosixTime} +use aiken/interval +use aiken/transaction.{ + InlineDatum, Input, NoDatum, Output, OutputReference, TransactionId, + ValidityRange, +} +use aiken/transaction/credential.{ + Address, ScriptCredential, StakeCredential, VerificationKeyCredential, +} +use aiken/transaction/value.{AssetName, PolicyId, Value} use calculation/deposit use calculation/donation use calculation/record use calculation/shared.{ PoolState, check_and_set_unique, unsafe_fast_index_skip_with_tail, } as calc_shared +use calculation/strategy use calculation/swap use calculation/withdrawal -use calculation/strategy -use shared.{Ident, datum_of, pool_lp_name, is_script} +use shared.{Ident, datum_of, is_script, pool_lp_name} use sundae/multisig -use types/order.{Order, Destination, Fixed, OrderDatum, SignedStrategyExecution} +use types/order.{Destination, Fixed, Order, OrderDatum, SignedStrategyExecution} use types/pool.{PoolDatum} -pub fn calculate_fees( - fees: (Int, Int), - market_open: PosixTime, - fee_finalized: PosixTime, - valid_from: PosixTime, -) { - // So, if the transaction is guaranteed to run after fee_finalized, charge the final fee rate - if valid_from > fee_finalized { - fees.2nd - } else { - // Otherwise, calculate the duration of this decay period - let duration = fee_finalized - market_open - if duration == 0 { - // If it's zero (market_open == fee_finalized) then just use the final fee rate - fees.2nd - } else { - // Otherwise, calculate how much has elapsed since the market open - // then the full range of the fee rate - // then, starting from the opening fee rate, linearly increase (or decrease) the fees by that range - let elapsed = valid_from - market_open - let range = fees.2nd - fees.1st - fees.1st + (elapsed * range / duration) - } - } -} - /// Construct the initial pool state for processing a set of orders pub fn pool_input_to_state( pool_token_policy: PolicyId, datum: PoolDatum, input: Output, - valid_from: IntervalBound, continuation: fn( - PolicyId, AssetName, Int, - PolicyId, AssetName, Int, - PolicyId, AssetName, Int, - Int, Int, Int - ) -> Bool, + PolicyId, + AssetName, + Int, + PolicyId, + AssetName, + Int, + PolicyId, + AssetName, + Int, + Int, + Int, + Int, + ) -> + Bool, ) -> Bool { let PoolDatum { assets, @@ -68,8 +53,6 @@ pub fn pool_input_to_state( circulating_lp, bid_fees_per_10_thousand, ask_fees_per_10_thousand, - market_open, - fee_finalized, .. } = datum let (asset_a, asset_b) = assets @@ -83,29 +66,28 @@ pub fn pool_input_to_state( } else { 0 } - // Get the maximum of market_open and the transaction valid from so we can calculate the fees correctly // Note: we use valid_from, as this favors the protocol: you pay the fees for the *earliest* moment your order *could* have executed. // Scoopers could in theory set a wide validity range to cause users to overpay, but this should be considered malicious activity and // get the scooper removed from the list of valid scoopers / ignore scooper rewards // TODO: we could solve this by enforcing a validity range, and checking the length is within 4 hours. - let valid_from = when valid_from.bound_type is { - NegativeInfinity -> market_open - Finite(t) -> math.max(t, market_open) - _ -> error - } - // Calculate the fees per 10k rate to use for this whole scoop - // We let the creator of the pool specify a fee rate that decays (or increases) between market_open and fee_finalized - let bid_fees = calculate_fees(bid_fees_per_10_thousand, market_open, fee_finalized, valid_from) - let ask_fees = calculate_fees(ask_fees_per_10_thousand, market_open, fee_finalized, valid_from) - + let bid_fees = bid_fees_per_10_thousand + let ask_fees = ask_fees_per_10_thousand // Then construct the pool state. We include the assets here, instead of just the reserves, so we can check the values of each order // TODO: we could potentially save quite a bit by not passing around this object, and passing around a lot of parameters instead... continuation( - asset_a_policy_id, asset_a_name, value.quantity_of(input.value, asset_a_policy_id, asset_a_name) - min_utxo, - asset_b_policy_id, asset_b_name, value.quantity_of(input.value, asset_b_policy_id, asset_b_name), - pool_token_policy, pool_lp_name(identifier), circulating_lp, - bid_fees, ask_fees, protocol_fees + asset_a_policy_id, + asset_a_name, + value.quantity_of(input.value, asset_a_policy_id, asset_a_name) - min_utxo, + asset_b_policy_id, + asset_b_name, + value.quantity_of(input.value, asset_b_policy_id, asset_b_name), + pool_token_policy, + pool_lp_name(identifier), + circulating_lp, + bid_fees, + ask_fees, + protocol_fees, ) } @@ -162,18 +144,20 @@ pub fn process_order( outputs: List, // A continuation to call with the next pool state and the list of outputs; this is more efficient than constructing an object and tuples continuation: fn(Int, Int, Int, List) -> Bool, -) -> Bool { // Returns the updated pool state, the correct list of outputs to resume from, and total fee charged by the order +) -> Bool { + // Returns the updated pool state, the correct list of outputs to resume from, and total fee charged by the order when details is { order.Strategy(signer) -> { // For a strategy, we can basically "unpack" (and validate) the signed execution, and then recurse to process the deferred order expect Some(execution) = signed_execution - let details = strategy.get_strategy( - output_reference, - tx_valid_range, - withdrawals, - signer, - execution, - ) + let details = + strategy.get_strategy( + output_reference, + tx_valid_range, + withdrawals, + signer, + execution, + ) process_order( pool_policy_a, pool_asset_name_a, @@ -184,7 +168,8 @@ pub fn process_order( pool_policy_lp, pool_asset_name_lp, pool_quantity_lp, - None, // No need to pass a signed execution through again; it doesn't make sense to have multiple nested strategies + None, + // No need to pass a signed execution through again; it doesn't make sense to have multiple nested strategies output_reference, tx_valid_range, withdrawals, @@ -210,7 +195,10 @@ pub fn process_order( let fee = amortized_base_fee + simple_fee expect max_protocol_fee >= fee // Calculate the result of the swap itself, according to the AMM formula, and validate it against the output - let new_pool_a, new_pool_b <- + let + new_pool_a, + new_pool_b, + <- swap.do_swap( pool_policy_a, pool_asset_name_a, @@ -236,14 +224,27 @@ pub fn process_order( let fee = amortized_base_fee + simple_fee expect max_protocol_fee >= fee // Calculate and validate the result of a deposit - let new_a, new_b, new_lp <- deposit.do_deposit( - pool_policy_a, pool_asset_name_a, pool_quantity_a, - pool_policy_b, pool_asset_name_b, pool_quantity_b, - pool_policy_lp, pool_asset_name_lp, pool_quantity_lp, - input, assets, - destination, fee, - output - ) + let + new_a, + new_b, + new_lp, + <- + deposit.do_deposit( + pool_policy_a, + pool_asset_name_a, + pool_quantity_a, + pool_policy_b, + pool_asset_name_b, + pool_quantity_b, + pool_policy_lp, + pool_asset_name_lp, + pool_quantity_lp, + input, + assets, + destination, + fee, + output, + ) continuation(new_a, new_b, new_lp, rest_outputs) } order.Withdrawal(amount) -> { @@ -253,14 +254,26 @@ pub fn process_order( let fee = amortized_base_fee + simple_fee expect max_protocol_fee >= fee // Calculate and validate the result of a withdrawal - let new_a, new_b, new_lp <- + let + new_a, + new_b, + new_lp, + <- withdrawal.do_withdrawal( - pool_policy_a, pool_asset_name_a, pool_quantity_a, - pool_policy_b, pool_asset_name_b, pool_quantity_b, - pool_policy_lp, pool_asset_name_lp, pool_quantity_lp, - input, amount, - destination, fee, - output + pool_policy_a, + pool_asset_name_a, + pool_quantity_a, + pool_policy_b, + pool_asset_name_b, + pool_quantity_b, + pool_policy_lp, + pool_asset_name_lp, + pool_quantity_lp, + input, + amount, + destination, + fee, + output, ) continuation(new_a, new_b, new_lp, rest_outputs) } @@ -274,13 +287,23 @@ pub fn process_order( let fee = amortized_base_fee + simple_fee expect max_protocol_fee >= fee // Calculate and validate the result of a donation - let new_a, new_b, used_output <- + let + new_a, + new_b, + used_output, + <- donation.do_donation( - pool_policy_a, pool_asset_name_a, pool_quantity_a, - pool_policy_b, pool_asset_name_b, pool_quantity_b, - input, assets, - destination, fee, - output + pool_policy_a, + pool_asset_name_a, + pool_quantity_a, + pool_policy_b, + pool_asset_name_b, + pool_quantity_b, + input, + assets, + destination, + fee, + output, ) // If a donation has no change (ex it has exactly the donation + the fee) then we don't have an output dedicated to the order // so we can skip over it @@ -297,7 +320,12 @@ pub fn process_order( let fee = amortized_base_fee + simple_fee expect max_protocol_fee >= fee expect record.check_record(input, destination, fee, output, policy) - continuation(pool_quantity_a, pool_quantity_b, pool_quantity_lp, rest_outputs) + continuation( + pool_quantity_a, + pool_quantity_b, + pool_quantity_lp, + rest_outputs, + ) } } } @@ -348,12 +376,20 @@ pub fn process_orders( strategy_count: Int, // A continuation to call with the final pool state; more efficient than constructing tuples / objects continuation: fn(Int, Int, Int, Int, Int) -> Bool, -) -> Bool { // Returns the final pool state, and the count of each order type +) -> Bool { + // Returns the final pool state, and the count of each order type // The main "pump" of the recursive loop is the input_order, which is a set of indices into the inputs list // specified by the scooper for the order to process each order in. // Once we've reached the end of the list, we can return, but otherwise when input_order is { - [] -> continuation(pool_quantity_a, pool_quantity_b, pool_quantity_lp, simple_count, strategy_count) + [] -> + continuation( + pool_quantity_a, + pool_quantity_b, + pool_quantity_lp, + simple_count, + strategy_count, + ) [(idx, sse, _), ..rest] -> { // First, it's important to check that each order is processed only once; // This is quite subtle, so check InputSorting.md for a full explanation @@ -370,9 +406,8 @@ pub fn process_orders( } else { unsafe_fast_index_skip_with_tail(all_inputs, idx) } - expect [input_to_process, ..rest_of_input_list] = next_input_list - let Input{ output_reference, output: order } = input_to_process + let Input { output_reference, output: order } = input_to_process // It's important that we fail if we ever try to process a UTXO from a wallet address // This is a bit unfortunate, because it means we can't support processing orders directly out of a users wallet @@ -392,35 +427,47 @@ pub fn process_orders( // Make sure we're allowed to process this order (i.e. if the user specified a specific pool, we have to honor that) expect validate_pool_id(pool_ident, this_pool_ident) - // Check whether this is a strategy, then increment the count appropriately - let (next_simple_count, next_strategy_count) = when details is { - order.Strategy(..) -> (simple_count, strategy_count + 1) - _ -> (simple_count + 1, strategy_count) - } + let (next_simple_count, next_strategy_count) = + when details is { + order.Strategy(..) -> (simple_count, strategy_count + 1) + _ -> (simple_count + 1, strategy_count) + } // And finally, process this one individual order and compute the next state // Note that we get back next_orders here, which is needed if we process a donation that has no change UTXO - let new_a, new_b, new_lp, next_orders <- process_order( - pool_policy_a, pool_asset_name_a, pool_quantity_a, - pool_policy_b, pool_asset_name_b, pool_quantity_b, - pool_policy_lp, pool_asset_name_lp, pool_quantity_lp, - sse, - output_reference, - tx_valid_range, - withdrawals, - order, - order.value, - details, - max_protocol_fee, - destination, - bid_fees_per_10_thousand, - ask_fees_per_10_thousand, - amortized_base_fee, - simple_fee, - strategy_fee, - outputs, - ) + let + new_a, + new_b, + new_lp, + next_orders, + <- + process_order( + pool_policy_a, + pool_asset_name_a, + pool_quantity_a, + pool_policy_b, + pool_asset_name_b, + pool_quantity_b, + pool_policy_lp, + pool_asset_name_lp, + pool_quantity_lp, + sse, + output_reference, + tx_valid_range, + withdrawals, + order, + order.value, + details, + max_protocol_fee, + destination, + bid_fees_per_10_thousand, + ask_fees_per_10_thousand, + amortized_base_fee, + simple_fee, + strategy_fee, + outputs, + ) // And recursively process the rest of the orders process_orders( @@ -428,17 +475,26 @@ pub fn process_orders( tx_valid_range, withdrawals, datums, - pool_policy_a, pool_asset_name_a, new_a, - pool_policy_b, pool_asset_name_b, new_b, - pool_policy_lp, pool_asset_name_lp, new_lp, - rest, // This advances to the next element from input_order + pool_policy_a, + pool_asset_name_a, + new_a, + pool_policy_b, + pool_asset_name_b, + new_b, + pool_policy_lp, + pool_asset_name_lp, + new_lp, + rest, + // This advances to the next element from input_order bid_fees_per_10_thousand, ask_fees_per_10_thousand, amortized_base_fee, simple_fee, strategy_fee, - idx + 1, // This is the "previous index" within the input list; TODO: I'm not actually sure why we add 1? - all_inputs, // See the notes above about all_inputs vs remaining_inputs + idx + 1, + // This is the "previous index" within the input list; TODO: I'm not actually sure why we add 1? + all_inputs, + // See the notes above about all_inputs vs remaining_inputs rest_of_input_list, next_orders, next_uniqueness_flag, @@ -459,91 +515,121 @@ test process_orders_test() { None, ) let ada = (#"", #"") - let rberry = (#"01010101010101010101010101010101010101010101010101010101", "RBERRY") + let rberry = + (#"01010101010101010101010101010101010101010101010101010101", "RBERRY") let lp = (#"99999999999999999999999999999999999999999999999999999999", "LP") - let pool_state = PoolState { - 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), - } - let order_datum = OrderDatum { - pool_ident: None, - owner: multisig.Signature( - #"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513", - ), - max_protocol_fee: 2_500_000, - destination: Fixed { + let pool_state = + PoolState { + 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), + } + let order_datum = + OrderDatum { + pool_ident: None, + owner: multisig.Signature( + #"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513", + ), + max_protocol_fee: 2_500_000, + destination: Fixed { address: addr, datum: NoDatum }, + details: order.Donation { + assets: ( + (ada.1st, ada.2nd, 1_000_000), + (rberry.1st, rberry.2nd, 1_000_000), + ), + }, + extension: Void, + } + // There's no remainder so do_donation totally ignores this Output record + let output = + Output { address: addr, + value: value.from_lovelace(999_999_999_999_999_999), datum: NoDatum, - }, - details: order.Donation { - assets: ((ada.1st, ada.2nd, 1_000_000), (rberry.1st, rberry.2nd, 1_000_000)), - }, - extension: Void, - } - // There's no remainder so do_donation totally ignores this Output record - let output = Output { - address: addr, - value: value.from_lovelace(999_999_999_999_999_999), - datum: NoDatum, - reference_script: None, - } + reference_script: None, + } - let order_output = Output { - address: Address( - ScriptCredential(#"4af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513"), - None, - ), - value: value.from_lovelace(3_500_000) - |> value.add(rberry.1st, rberry.2nd, 1_000_000), - datum: InlineDatum(order_datum), - reference_script: None, - } + let order_output = + Output { + address: Address( + ScriptCredential( + #"4af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513", + ), + None, + ), + value: value.from_lovelace(3_500_000) + |> value.add(rberry.1st, rberry.2nd, 1_000_000), + datum: InlineDatum(order_datum), + reference_script: None, + } let order_datum_data: Data = order_datum - let datums = dict.new() - |> dict.insert( - key: hash.blake2b_256(cbor.serialise(order_datum)), - value: order_datum_data, - compare: bytearray.compare) + let datums = + dict.new() + |> dict.insert( + key: hash.blake2b_256(cbor.serialise(order_datum)), + value: order_datum_data, + compare: bytearray.compare, + ) - let input = Input { - output_reference: OutputReference { - transaction_id: TransactionId { - hash: #"0000000000000000000000000000000000000000000000000000000000000000" + let input = + Input { + output_reference: OutputReference { + transaction_id: TransactionId { + hash: #"0000000000000000000000000000000000000000000000000000000000000000", + }, + output_index: 0, }, - output_index: 0, - }, - output: order_output, - } - let valid_range = interval.between(1,2) + output: order_output, + } + let valid_range = interval.between(1, 2) - let input_order = [(0, None, 0)] - let inputs = [input] - let outputs = [output] + let input_order = + [(0, None, 0)] + let inputs = + [input] + let outputs = + [output] - let new_a, new_b, new_lp, simple, strategies <- process_orders( - #"", valid_range, dict.new(), datums, - pool_state.quantity_a.1st, - pool_state.quantity_a.2nd, - pool_state.quantity_a.3rd, - pool_state.quantity_b.1st, - pool_state.quantity_b.2nd, - pool_state.quantity_b.3rd, - pool_state.quantity_lp.1st, - pool_state.quantity_lp.2nd, - pool_state.quantity_lp.3rd, - input_order, - 5, 5, 2_500_000, - 0, 0, 0, - inputs, inputs, - outputs, - 0, 0, 0 - ) + let + new_a, + new_b, + new_lp, + simple, + strategies, + <- + process_orders( + #"", + valid_range, + dict.new(), + datums, + pool_state.quantity_a.1st, + pool_state.quantity_a.2nd, + pool_state.quantity_a.3rd, + pool_state.quantity_b.1st, + pool_state.quantity_b.2nd, + pool_state.quantity_b.3rd, + pool_state.quantity_lp.1st, + pool_state.quantity_lp.2nd, + pool_state.quantity_lp.3rd, + input_order, + 5, + 5, + 2_500_000, + 0, + 0, + 0, + inputs, + inputs, + outputs, + 0, + 0, + 0, + ) expect new_a == 1_001_000_000 expect new_b == 1_001_000_000 - expect new_lp== 1_000_000_000 + expect new_lp == 1_000_000_000 expect simple == 1 expect strategies == 0 True @@ -558,117 +644,180 @@ test process_30_shuffled_orders_test() { None, ) let ada = (#"", #"") - let rberry = (#"01010101010101010101010101010101010101010101010101010101", "RBERRY") + let rberry = + (#"01010101010101010101010101010101010101010101010101010101", "RBERRY") let lp = (#"99999999999999999999999999999999999999999999999999999999", "LP") - let pool_state = PoolState { - 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), - } - let order_datum = OrderDatum { - pool_ident: None, - owner: multisig.Signature( - #"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513", - ), - max_protocol_fee: 2_500_000, - destination: Fixed { + let pool_state = + PoolState { + 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), + } + let order_datum = + OrderDatum { + pool_ident: None, + owner: multisig.Signature( + #"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513", + ), + max_protocol_fee: 2_500_000, + destination: Fixed { address: addr, datum: NoDatum }, + details: order.Donation { + assets: ( + (ada.1st, ada.2nd, 1_000_000), + (rberry.1st, rberry.2nd, 1_000_000), + ), + }, + extension: Void, + } + // There's no remainder so do_donation totally ignores this Output record + let output = + Output { address: addr, + value: value.from_lovelace(999_999_999_999_999_999), datum: NoDatum, - }, - details: order.Donation { - assets: ((ada.1st, ada.2nd, 1_000_000), (rberry.1st, rberry.2nd, 1_000_000)), - }, - extension: Void, - } - // There's no remainder so do_donation totally ignores this Output record - let output = Output { - address: addr, - value: value.from_lovelace(999_999_999_999_999_999), - datum: NoDatum, - reference_script: None, - } + reference_script: None, + } - let order_output = Output { - address: Address( - ScriptCredential(#"4af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513"), - None, - ), - value: value.from_lovelace(3_500_000) - |> value.add(rberry.1st, rberry.2nd, 1_000_000), - datum: InlineDatum(order_datum), - reference_script: None, - } + let order_output = + Output { + address: Address( + ScriptCredential( + #"4af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513", + ), + None, + ), + value: value.from_lovelace(3_500_000) + |> value.add(rberry.1st, rberry.2nd, 1_000_000), + datum: InlineDatum(order_datum), + reference_script: None, + } let order_datum_data: Data = order_datum - let datums = dict.new() - |> dict.insert( - key: hash.blake2b_256(cbor.serialise(order_datum)), - value: order_datum_data, - compare: bytearray.compare) + let datums = + dict.new() + |> dict.insert( + key: hash.blake2b_256(cbor.serialise(order_datum)), + value: order_datum_data, + compare: bytearray.compare, + ) - let input = Input { - output_reference: OutputReference { - transaction_id: TransactionId { - hash: #"0000000000000000000000000000000000000000000000000000000000000000" + let input = + Input { + output_reference: OutputReference { + transaction_id: TransactionId { + hash: #"0000000000000000000000000000000000000000000000000000000000000000", + }, + output_index: 0, }, - output_index: 0, - }, - output: order_output, - } - let valid_range = interval.between(1,2) + output: order_output, + } + let valid_range = interval.between(1, 2) - let inputs = [input, input, input, input, input, input, input, input, input, input, input, input, input, input, input, input, input, input, input, input, input, input, input, input, input, input, input, input, input, input] + let inputs = + [ + input, + input, + input, + input, + input, + input, + input, + input, + input, + input, + input, + input, + input, + input, + input, + input, + input, + input, + input, + input, + input, + input, + input, + input, + input, + input, + input, + input, + input, + input, + ] // shuffled order processing: - let input_order = [ - (11, None, 0), - (26, None, 0), - (18, None, 0), - (2, None, 0), - (28, None, 0), - (13, None, 0), - (16, None, 0), - (1, None, 0), - (8, None, 0), - (27, None, 0), - (12, None, 0), - (23, None, 0), - (22, None, 0), - (14, None, 0), - (10, None, 0), - (0, None, 0), - (24, None, 0), - (5, None, 0), - (7, None, 0), - (17, None, 0), - (20, None, 0), - (29, None, 0), - (19, None, 0), - (21, None, 0), - (9, None, 0), - (25, None, 0), - (6, None, 0), - (4, None, 0), - (3, None, 0), - (15, None, 0), - ] - let outputs = [output] + let input_order = + [ + (11, None, 0), + (26, None, 0), + (18, None, 0), + (2, None, 0), + (28, None, 0), + (13, None, 0), + (16, None, 0), + (1, None, 0), + (8, None, 0), + (27, None, 0), + (12, None, 0), + (23, None, 0), + (22, None, 0), + (14, None, 0), + (10, None, 0), + (0, None, 0), + (24, None, 0), + (5, None, 0), + (7, None, 0), + (17, None, 0), + (20, None, 0), + (29, None, 0), + (19, None, 0), + (21, None, 0), + (9, None, 0), + (25, None, 0), + (6, None, 0), + (4, None, 0), + (3, None, 0), + (15, None, 0), + ] + let outputs = + [output] - let new_a, new_b, new_lp, simple, strategies <- process_orders( - #"", valid_range, dict.new(), datums, - pool_state.quantity_a.1st, pool_state.quantity_a.2nd, pool_state.quantity_a.3rd, - pool_state.quantity_b.1st, pool_state.quantity_b.2nd, pool_state.quantity_b.3rd, - pool_state.quantity_lp.1st, pool_state.quantity_lp.2nd, pool_state.quantity_lp.3rd, - input_order, - 5, 5, 2_500_000, - 0, 0, 0, - inputs, inputs, - outputs, - 0, 0, 0 - ) + let + new_a, + new_b, + new_lp, + simple, + strategies, + <- + process_orders( + #"", + valid_range, + dict.new(), + datums, + pool_state.quantity_a.1st, + pool_state.quantity_a.2nd, + pool_state.quantity_a.3rd, + pool_state.quantity_b.1st, + pool_state.quantity_b.2nd, + pool_state.quantity_b.3rd, + pool_state.quantity_lp.1st, + pool_state.quantity_lp.2nd, + pool_state.quantity_lp.3rd, + input_order, + 5, + 5, + 2_500_000, + 0, + 0, + 0, + inputs, + inputs, + outputs, + 0, + 0, + 0, + ) - new_a == 1_030_000_000 && - new_b == 1_030_000_000 && - new_lp == 1_000_000_000 && - simple == 30 && - strategies == 0 + new_a == 1_030_000_000 && new_b == 1_030_000_000 && new_lp == 1_000_000_000 && simple == 30 && strategies == 0 } diff --git a/lib/calculation/record.ak b/lib/calculation/record.ak index 32a6550..1e4d80f 100644 --- a/lib/calculation/record.ak +++ b/lib/calculation/record.ak @@ -1,5 +1,5 @@ use aiken/transaction.{Output} -use aiken/transaction/value.{ada_policy_id, ada_asset_name, PolicyId, AssetName} +use aiken/transaction/value.{AssetName, PolicyId, ada_asset_name, ada_policy_id} use types/order.{Destination, Fixed, Self} pub fn check_record( @@ -18,9 +18,10 @@ pub fn check_record( // and maybe there's a good reason for someone to want that behavior. // We know that the `oracle` token we provide is secure against this, because it must be minted into // its own spending policy, and it must be burned when spent. - let remainder = input.value - |> value.add(ada_policy_id, ada_asset_name, -actual_protocol_fee) - |> value.add(asset_id.1st, asset_id.2nd, 1) + let remainder = + input.value + |> value.add(ada_policy_id, ada_asset_name, -actual_protocol_fee) + |> value.add(asset_id.1st, asset_id.2nd, 1) and { output.value == remainder, @@ -33,6 +34,6 @@ pub fn check_record( Fixed(address, _) -> output.address == address // It doesn't make sense for an oracle to chain into an oracle Self -> False - } + }, } } diff --git a/lib/calculation/shared.ak b/lib/calculation/shared.ak index 36ddc2d..8456c69 100644 --- a/lib/calculation/shared.ak +++ b/lib/calculation/shared.ak @@ -78,7 +78,6 @@ pub fn check_and_set_unique(uniqueness_flags: Int, index: Int) -> Int { // Uniqueness check is a bunch of flipped bits, and we want to blow up if we ever set a bit that is ever hit again // Imagine for example that uniqueness_flags is b0100_0010 - // Construct a number with the `index`th bit set // e.g. if index == 3, then construct b0000_1000 let bit = small_pow2(index) @@ -100,11 +99,10 @@ pub fn check_and_set_unique(uniqueness_flags: Int, index: Int) -> Int { // b0101_0010 // Notice there was a carry that happened! // We can use the fact that the carry happened to detect that we had a duplicate in the list - // At this point I was stuck trying to figure out how to calculate that, and // @Microproofs figured out the dark incantation to make it work: expect flag_set % bit_shifted > uniqueness_flags % bit_shifted - + // Lets take it piece by piece; // uniqueness_flags % bit_shifted // - sets all of the bits at or above the `bit_shifted` to 0 @@ -119,7 +117,6 @@ pub fn check_and_set_unique(uniqueness_flags: Int, index: Int) -> Int { // b0010 > b1010 which is **false**, because we "carried" the one away into the high bits that got masked off // // So we will have failed if we ever set the same bit twice! - // We can return the flag set for the next time through the loop flag_set } @@ -127,7 +124,7 @@ pub fn check_and_set_unique(uniqueness_flags: Int, index: Int) -> Int { /// This is a version of pow2 that's optimized for small batch sizes /// It performs a few more granular loop-unrolls, converging on the small lookup index faster /// This was presented by TxPipe, and squeezes out one extra escrow over math.pow2 for our typical order sizes -pub fn small_pow2(exponent: Int) -> Int { +pub fn small_pow2(exponent: Int) -> Int { // A small bytestring, containing all the powers of two that can fit in a single byte, saves us a an expensive multiplication let single_byte_powers = #[1, 2, 4, 8, 16, 32, 64, 128] if exponent < 8 { @@ -152,4 +149,4 @@ pub fn small_pow2(exponent: Int) -> Int { // unsure why that is! math.pow2(exponent) } -} \ No newline at end of file +} diff --git a/lib/calculation/strategy.ak b/lib/calculation/strategy.ak index a7fd449..07d2e54 100644 --- a/lib/calculation/strategy.ak +++ b/lib/calculation/strategy.ak @@ -1,55 +1,65 @@ use aiken/cbor use aiken/dict.{Dict} -use aiken/interval.{Interval, Finite} +use aiken/interval.{Finite, Interval} use aiken/transaction.{OutputReference, ValidityRange} -use aiken/transaction/credential.{verify_signature, Inline, ScriptCredential, StakeCredential} -use types/order.{StrategyExecution, StrategyAuthorization, Signature, Script, SignedStrategyExecution, Order} +use aiken/transaction/credential.{ + Inline, ScriptCredential, StakeCredential, verify_signature, +} +use types/order.{ + Order, Script, Signature, SignedStrategyExecution, StrategyAuthorization, + StrategyExecution, +} /// Check that the outer interval completely contains the inner interval fn contains_interval(outer: Interval, inner: Interval) -> Bool { // Get the lowest point of the inner interval, by factoring in finite / inclusive bounds - let lowest_inner_point = when inner.lower_bound.bound_type is { - Finite(low) -> - if inner.lower_bound.is_inclusive { - low - } else { - low + 1 - } - _ -> 0 - } + let lowest_inner_point = + when inner.lower_bound.bound_type is { + Finite(low) -> + if inner.lower_bound.is_inclusive { + low + } else { + low + 1 + } + _ -> 0 + } // Get the highest point of the inner interval, by factoring in finite / inclusive bounds - let highest_inner_point = when inner.upper_bound.bound_type is { - Finite(hi) -> - if inner.upper_bound.is_inclusive { - hi - } else { - hi - 1 - } - _ -> 99999999999 // TODO: Maybe there's a cleaner way to handle this code - } + let highest_inner_point = + when inner.upper_bound.bound_type is { + Finite(hi) -> + if inner.upper_bound.is_inclusive { + hi + } else { + hi - 1 + } + _ -> 99999999999 + } + // TODO: Maybe there's a cleaner way to handle this code // Check that the lower bound is satisfied, i.e. <= vs < based on whether the outer bound is inclusive or not - let lower_bound_contained = when outer.lower_bound.bound_type is { - Finite(low) -> - if outer.lower_bound.is_inclusive { - low <= lowest_inner_point - } else { - low < lowest_inner_point - } - _ -> True - } + let lower_bound_contained = + when outer.lower_bound.bound_type is { + Finite(low) -> + if outer.lower_bound.is_inclusive { + low <= lowest_inner_point + } else { + low < lowest_inner_point + } + _ -> True + } // Check that the upper bound is satisfied, i.e. >= vs > based on whether the outer bound is inclusive or not - let upper_bound_contained = when outer.upper_bound.bound_type is { - Finite(hi) -> - if outer.upper_bound.is_inclusive { - hi >= highest_inner_point - } else { - hi > highest_inner_point - } - _ -> True - } + let upper_bound_contained = + when outer.upper_bound.bound_type is { + Finite(hi) -> + if outer.upper_bound.is_inclusive { + hi >= highest_inner_point + } else { + hi > highest_inner_point + } + _ -> True + } and { lower_bound_contained, - upper_bound_contained + upper_bound_contained, } } @@ -64,29 +74,31 @@ pub fn get_strategy( tx_valid_range: ValidityRange, withdrawals: Dict, auth: StrategyAuthorization, - strategy: SignedStrategyExecution, + sse: SignedStrategyExecution, ) -> Order { - let SignedStrategyExecution { strategy, signature } = strategy - let StrategyExecution { tx_ref, validity_range, details, .. } = strategy - // We check that the order_tx_ref from the strategy matches the order we're actually processing, - // to prevent replay / cross-play attacks. - expect order_tx_ref == tx_ref - // Make sure the transaction validity range (all the valid points in time the tx could exist) - // is entirely contained in the *strategy* valid range (all the points where the strategy is valid) - // This is so the user can impose timing restrictions (for example, maybe they only want their order to execute 20 minutes from now) - expect contains_interval(validity_range, tx_valid_range) - when auth is { - Signature { signer } -> { - // And finally, use cbor.serialise and check that the signature is valid - // TODO: is this at risk if cbor.serialise changes? is there a way for us to get the raw bytes of the data? - let strategy_bytes = cbor.serialise(details) - expect Some(signature) = signature - expect verify_signature(signer, strategy_bytes, signature) - details - } - Script { script } -> { - expect dict.has_key(withdrawals, Inline(ScriptCredential(script))) - details - } + let SignedStrategyExecution { execution, signature } = sse + let StrategyExecution { tx_ref, validity_range, details, .. } = execution + // We check that the order_tx_ref from the strategy matches the order we're actually processing, + // to prevent replay / cross-play attacks. + expect order_tx_ref == tx_ref + // Make sure the transaction validity range (all the valid points in time the tx could exist) + // is entirely contained in the *strategy* valid range (all the points where the strategy is valid) + // This is so the user can impose timing restrictions (for example, maybe they only want their order to execute 20 minutes from now) + expect contains_interval(validity_range, tx_valid_range) + when auth is { + Signature { signer } -> { + // And finally, use cbor.serialise and check that the signature is valid + // TODO: is this at risk if cbor.serialise changes? is there a way for us to get the raw bytes of the data? + // NOTE: it's really important that the signature is for the *whole execution* here; otherwise + // you could replay that signature over some other strategy order with the same signing key + let strategy_bytes = cbor.serialise(execution) + expect Some(signature) = signature + expect verify_signature(signer, strategy_bytes, signature) + details } -} \ No newline at end of file + Script { script } -> { + expect dict.has_key(withdrawals, Inline(ScriptCredential(script))) + details + } + } +} diff --git a/lib/calculation/swap.ak b/lib/calculation/swap.ak index b414880..38f0b40 100644 --- a/lib/calculation/swap.ak +++ b/lib/calculation/swap.ak @@ -52,8 +52,18 @@ pub fn swap_takes( let difference = 10000 - fees_per_10_thousand // Check how much the user is actually giving up, by comparing the difference between the input and output values - let order_give = value.quantity_of(input_value, give_policy_id, give_asset_name) - value.quantity_of(output_value, give_policy_id, give_asset_name) - let order_give = if give_policy_id == ada_policy_id { order_give - actual_protocol_fee } else { order_give } + let order_give = + value.quantity_of(input_value, give_policy_id, give_asset_name) - value.quantity_of( + output_value, + give_policy_id, + give_asset_name, + ) + let order_give = + if give_policy_id == ada_policy_id { + order_give - actual_protocol_fee + } else { + order_give + } // TODO: is this neccesary? or will one of the checks below *always* fail? expect order_give > 0 @@ -77,14 +87,15 @@ pub fn swap_takes( // then we need to make sure they would have received the same amount, and this amount is just // more efficient. // Otherwise, they have to be equal (i.e. the scooper can not force the user to give up more than they offered) - expect if order_give < order_offer { - let offer_takes_numerator = pool_take_times_difference * order_offer - let offer_takes_denominator = pool_give_10k + order_offer * difference - let offer_takes = offer_takes_numerator / offer_takes_denominator - offer_takes == give_takes - } else { - order_give == order_offer - } + expect + if order_give < order_offer { + let offer_takes_numerator = pool_take_times_difference * order_offer + let offer_takes_denominator = pool_give_10k + order_offer * difference + let offer_takes = offer_takes_numerator / offer_takes_denominator + offer_takes == give_takes + } else { + order_give == order_offer + } // We need to make sure that the user is getting the most efficient swap // So we check what they would receive with one less unit of the token they're giving @@ -98,12 +109,11 @@ pub fn swap_takes( // We can expand this out, algebraically, and simplify to reuse things we've already calculated // let one_less = - (give_takes_numerator - pool_take_times_difference) / ( + ( give_takes_numerator - pool_take_times_difference ) / ( give_takes_denominator - difference ) // And that *must* give strictly less takes; this means that the user is getting the most efficient order possible expect one_less < give_takes - // And then compute the desired output // which is the input value, minus the tokens being swapped, minus the protocol fee // plus the asset that we get as part of the swap @@ -143,32 +153,36 @@ pub fn do_swap( continuation: fn(Int, Int) -> Bool, ) -> Bool { let Output { value: input_value, .. } = input_utxo - let Output { value: output_value, address: output_address, datum: output_datum, .. } = output + let Output { + value: output_value, + address: output_address, + datum: output_datum, + .. + } = output // Destructure the pool state // TODO: it'd make the code nightmarish, but things would be way more efficient to just always pass these values destructured as parameters... let (offer_policy_id, offer_asset_name, offer_amt) = offer // let (a_policy_id, a_asset_name, a_amt) = pool_quantity_a // let (b_policy_id, b_asset_name, b_amt) = pool_quantity_b - // Make sure we're paying the result to the correct destination (both the address and the datum), // with the correct amount; In the special case where Datum is "Self" (for example for a repeating strategy) // use the input datum for validation - expect when destination is { - Fixed { address, datum } -> { - and { - output_address == address, - output_datum == datum + expect + when destination is { + Fixed { address, datum } -> and { + output_address == address, + output_datum == datum, + } + Self -> { + let Output { address: input_address, datum: input_datum, .. } = + input_utxo + and { + output_address == input_address, + output_datum == input_datum, + } } } - Self -> { - let Output { address: input_address, datum: input_datum, .. } = input_utxo - and { - output_address == input_address, - output_datum == input_datum - } - } - } // There are two symmetric cases, depending on whether you're giving order A or order B // If there's a clever way to write this as one branch it might be clearer to read @@ -178,7 +192,11 @@ pub fn do_swap( expect min_received.1st == pool_policy_b expect min_received.2nd == pool_asset_name_b // Compute the actual takes / change - let takes, gives, out_value <- + let + takes, + gives, + out_value, + <- swap_takes( offer_policy_id, offer_asset_name, @@ -199,16 +217,17 @@ pub fn do_swap( // And check that the min_received (the lowest amount of tokens the user is willing to receive, aka a limit price) // is satisfied expect takes >= min_received.3rd - continuation( - pool_quantity_a + gives, - pool_quantity_b - takes, - ) + continuation(pool_quantity_a + gives, pool_quantity_b - takes) } else if offer_policy_id == pool_policy_b && offer_asset_name == pool_asset_name_b { // This code is a mirror of the above, so should be scrutinized extra carefully during audit; // it's easy to make a mistake when copy-pasting. If there's an easier way to express this symmetry that would be good too expect min_received.1st == pool_policy_a expect min_received.2nd == pool_asset_name_a - let takes, gives, out_value <- + let + takes, + gives, + out_value, + <- swap_takes( offer_policy_id, offer_asset_name, @@ -220,18 +239,14 @@ pub fn do_swap( actual_protocol_fee, offer_amt, input_value, - output_value + output_value, ) // Make sure the correct value (including change) carries through to the output expect output_value == out_value - // Check that mintakes is satisfied expect takes >= min_received.3rd - continuation( - pool_quantity_a - takes, - pool_quantity_b + gives, - ) + continuation(pool_quantity_a - takes, pool_quantity_b + gives) } else { // If neither of the assets match what's being offered, fail the transaction, the scooper has incorrectly chosen an order that can't be satisfied fail diff --git a/lib/calculation/withdrawal.ak b/lib/calculation/withdrawal.ak index 7623a65..f72a579 100644 --- a/lib/calculation/withdrawal.ak +++ b/lib/calculation/withdrawal.ak @@ -1,6 +1,6 @@ use aiken/math use aiken/transaction.{Output} -use aiken/transaction/value.{ada_policy_id, ada_asset_name, PolicyId, AssetName} +use aiken/transaction/value.{AssetName, PolicyId, ada_asset_name, ada_policy_id} use shared.{SingletonValue} use types/order.{Destination, Fixed, Self} @@ -19,13 +19,18 @@ pub fn do_withdrawal( pool_policy_lp: PolicyId, pool_asset_name_lp: AssetName, pool_quantity_lp: Int, - input_utxo: Output, // The incoming UTXO, useful for returning surplus and handling Self destinations - amount: SingletonValue, // The amount to actually withdraw - destination: Destination, // The destination that the LP tokens (and change) should be sent to - actual_protocol_fee: Int, // The protocol fee to deduct - output: Output, // The output to compare the order execution against, to ensure the right quantity was paid out + input_utxo: Output, + // The incoming UTXO, useful for returning surplus and handling Self destinations + amount: SingletonValue, + // The amount to actually withdraw + destination: Destination, + // The destination that the LP tokens (and change) should be sent to + actual_protocol_fee: Int, + // The protocol fee to deduct + output: Output, + // The output to compare the order execution against, to ensure the right quantity was paid out // A continuation; a method to call with the new pool state; more efficient than constructing a new object - continuation: fn(Int, Int, Int) -> Bool + continuation: fn(Int, Int, Int) -> Bool, ) -> Bool { let (lp_policy, lp_asset_name, amount) = amount let Output { value: input_value, .. } = input_utxo @@ -45,10 +50,8 @@ pub fn do_withdrawal( // that corresponds to the percentage of LP token burned. Note we multiply first to minimize precision loss. // OPTIMIZATION: we can probably destructure the SingletonValues once and reuse, but optimizing // deposits/withdrawals isn't as critical as optimizing swaps. - let withdrawn_a = - withdrawn * pool_quantity_a / pool_quantity_lp - let withdrawn_b = - withdrawn * pool_quantity_b / pool_quantity_lp + let withdrawn_a = withdrawn * pool_quantity_a / pool_quantity_lp + let withdrawn_b = withdrawn * pool_quantity_b / pool_quantity_lp // Calculate the remainder that should be directed to the destination: // We start with whatever we got in on the input, deduct the LP tokens we're burning @@ -58,37 +61,28 @@ pub fn do_withdrawal( input_value |> value.add(lp_policy, lp_asset_name, -withdrawn) |> value.add(ada_policy_id, ada_asset_name, -actual_protocol_fee) - |> value.add( - pool_policy_a, - pool_asset_name_a, - withdrawn_a, - ) - |> value.add( - pool_policy_b, - pool_asset_name_b, - withdrawn_b, - ) + |> value.add(pool_policy_a, pool_asset_name_a, withdrawn_a) + |> value.add(pool_policy_b, pool_asset_name_b, withdrawn_b) - // Make sure we're paying the result to the correct destination (both the address and the datum), // with the correct amount; In the special case where Datum is "Self" (for example for a repeating strategy) // use the input datum for validation expect output.value == remainder - expect when destination is { - Fixed { address, datum } -> { - and { - output.address == address, - output.datum == datum + expect + when destination is { + Fixed { address, datum } -> and { + output.address == address, + output.datum == datum, + } + Self -> { + let Output { address: input_address, datum: input_datum, .. } = + input_utxo + and { + output.address == input_address, + output.datum == input_datum, + } } } - Self -> { - let Output { address: input_address, datum: input_datum, .. } = input_utxo - and { - output.address == input_address, - output.datum == input_datum - } - } - } // Return the final pool state continuation( @@ -97,4 +91,3 @@ pub fn do_withdrawal( pool_quantity_lp - withdrawn, ) } - diff --git a/lib/shared.ak b/lib/shared.ak index 37649bf..9f597bb 100644 --- a/lib/shared.ak +++ b/lib/shared.ak @@ -1,30 +1,33 @@ -use aiken/bytearray use aiken/builtin +use aiken/bytearray use aiken/dict.{Dict} use aiken/hash.{Blake2b_256, Hash} use aiken/list use aiken/transaction.{ - DatumHash, InlineDatum, Input, NoDatum, Output, ScriptContext, Spend, - find_input, + DatumHash, InlineDatum, Input, NoDatum, Output, OutputReference, ScriptContext, + Spend, find_input, } use aiken/transaction/credential.{Credential, ScriptCredential} use aiken/transaction/value.{AssetName, PolicyId} - use tests/examples/ex_shared.{ - script_address, wallet_address, mk_output_reference + mk_output_reference, script_address, wallet_address, } /// An alias type for the pool identifier, to make it slightly easier to reason about -pub type Ident = ByteArray +pub type Ident = + ByteArray /// An asset class is a combination of a policy ID and asset name; uniquely identifies one type of token, useful to make the code more readable -pub type AssetClass = (PolicyId, AssetName) +pub type AssetClass = + (PolicyId, AssetName) /// A rational number, represented as the numerator and denominator -pub type Rational = (Int, Int) +pub type Rational = + (Int, Int) /// A "value" for which we know there is only one value; convenient for performance reasons, and to make the code more readable -pub type SingletonValue = (PolicyId, AssetName, Int) +pub type SingletonValue = + (PolicyId, AssetName, Int) /// Convert a singleton value to an actual value; convenient for comparing or adding together values pub fn to_value(sv: SingletonValue) -> value.Value { @@ -56,6 +59,25 @@ pub fn spent_output(ctx: ScriptContext) -> Output { input.output } +/// Find the index of the given "out_ref"; confusingly, this is the the inputs, not the outputs +pub fn own_input_index(ctx: ScriptContext) -> Int { + expect Spend(out_ref) = ctx.purpose + do_own_input_index(ctx.transaction.inputs, out_ref, 0) +} + +pub fn do_own_input_index( + inputs: List, + output_reference: OutputReference, + i: Int, +) -> Int { + expect [input, ..rest] = inputs + if input.output_reference == output_reference { + i + } else { + do_own_input_index(rest, output_reference, i + 1) + } +} + /// Find a specific input index, and validate that it has at least one of the specified token /// Useful for looking up the pool token, etc. /// NOTE: this is actually unused, because we chose to go with the optimization in the body @@ -168,17 +190,20 @@ pub fn has_exact_token_count(val: value.Value, count: Int) { } test test_has_exact_token_count() { - let val = value.from_lovelace(100) - |> value.add("abc", "def", 100) - |> value.add("xyz", "www", 200) + let val = + value.from_lovelace(100) + |> value.add("abc", "def", 100) + |> value.add("xyz", "www", 200) expect has_exact_token_count(val, 3) - let val = value.from_lovelace(100) - |> value.add("abc", "def", 100) + let val = + value.from_lovelace(100) + |> value.add("abc", "def", 100) expect has_exact_token_count(val, 2) - let val = value.from_lovelace(100) - |> value.add("abc", "def", 100) + let val = + value.from_lovelace(100) + |> value.add("abc", "def", 100) expect !has_exact_token_count(val, 3) True } @@ -230,40 +255,58 @@ test count_orders_test() { let hash_of_escrow_script = #"00000000000000000000000000000000000000000000000000000000" let escrow_address = script_address(hash_of_escrow_script) - let escrow1_in = Input { - output_reference: mk_output_reference(2), - output: Output { - address: escrow_address, - value: value.from_lovelace(0), - datum: NoDatum, - reference_script: None, - }, - } - let escrow2_in = Input { - output_reference: mk_output_reference(3), - output: Output { - address: escrow_address, - value: value.from_lovelace(0), - datum: NoDatum, - reference_script: None, - }, - } - let other_address = wallet_address(#"fede0000000000000000000000000000000000000000000000000000") - let other_in = Input { - output_reference: mk_output_reference(4), - output: Output { - address: other_address, - value: value.from_lovelace(0), - datum: NoDatum, - reference_script: None, - }, - } + let escrow1_in = + Input { + output_reference: mk_output_reference(2), + output: Output { + address: escrow_address, + value: value.from_lovelace(0), + datum: NoDatum, + reference_script: None, + }, + } + let escrow2_in = + Input { + output_reference: mk_output_reference(3), + output: Output { + address: escrow_address, + value: value.from_lovelace(0), + datum: NoDatum, + reference_script: None, + }, + } + let other_address = + wallet_address(#"fede0000000000000000000000000000000000000000000000000000") + let other_in = + Input { + output_reference: mk_output_reference(4), + output: Output { + address: other_address, + value: value.from_lovelace(0), + datum: NoDatum, + reference_script: None, + }, + } - let inputs = [ - pool_input, other_in, escrow1_in, escrow2_in, other_in, escrow1_in, - escrow2_in, other_in, escrow1_in, escrow2_in, other_in, escrow1_in, - escrow2_in, other_in, escrow1_in, escrow2_in - ] + let inputs = + [ + pool_input, + other_in, + escrow1_in, + escrow2_in, + other_in, + escrow1_in, + escrow2_in, + other_in, + escrow1_in, + escrow2_in, + other_in, + escrow1_in, + escrow2_in, + other_in, + escrow1_in, + escrow2_in, + ] count_orders(inputs) == 10 } @@ -272,11 +315,9 @@ pub fn oracle_sft_name() { "oracle" } -pub fn fees_in_legal_range(fees: (Int, Int)) { +pub fn fees_in_legal_range(fees: Int) { and { - fees.1st >= 0, - fees.2nd >= 0, - fees.1st <= 10000, - fees.2nd <= 10000, + fees >= 0, + fees <= 10000, } } diff --git a/lib/tests/aiken/deposit.ak b/lib/tests/aiken/deposit.ak index b65c41a..ecf5e04 100644 --- a/lib/tests/aiken/deposit.ak +++ b/lib/tests/aiken/deposit.ak @@ -1,11 +1,11 @@ -use sundae/multisig use aiken/math -use aiken/transaction.{NoDatum, InlineDatum, Output} -use aiken/transaction/value +use aiken/transaction.{InlineDatum, NoDatum, Output} use aiken/transaction/credential.{Address, VerificationKeyCredential} -use calculation/shared.{PoolState} +use aiken/transaction/value use calculation/deposit.{do_deposit} -use types/order.{OrderDatum, Fixed} +use calculation/shared.{PoolState} +use sundae/multisig +use types/order.{Fixed, OrderDatum} test deposit_test() { let lp = (#"99999999999999999999999999999999999999999999999999999999", "LP") @@ -17,7 +17,7 @@ test deposit_test() { 200_000_000, 500_000_000, value.from_lovelace(47_500_000) - |> value.add(lp.1st, lp.2nd, 50_000_000) + |> value.add(lp.1st, lp.2nd, 50_000_000), ) } @@ -29,11 +29,19 @@ test deposit_test_minimum() fail { 150, 151_171_875, 150, - value.from_lovelace(152_000_000) + value.from_lovelace(152_000_000), ) } -fn deposit_test_schema(qa: Int, qb: Int, has_a: Int, has_b: Int, gives_a: Int, gives_b: Int, out_value: value.Value) { +fn deposit_test_schema( + qa: Int, + qb: Int, + has_a: Int, + has_b: Int, + gives_a: Int, + gives_b: Int, + out_value: value.Value, +) { let addr = Address( VerificationKeyCredential( @@ -42,55 +50,66 @@ fn deposit_test_schema(qa: Int, qb: Int, has_a: Int, has_b: Int, gives_a: Int, g None, ) let ada = (#"", #"") - let rberry = (#"01010101010101010101010101010101010101010101010101010101", "RBERRY") + let rberry = + (#"01010101010101010101010101010101010101010101010101010101", "RBERRY") let lp = (#"99999999999999999999999999999999999999999999999999999999", "LP") expect Some(q_lp) = math.sqrt(qa * qb) - let pool_state = PoolState { - quantity_a: (#"", #"", qa), - quantity_b: (rberry.1st, rberry.2nd, qb), - quantity_lp: (lp.1st, lp.2nd, q_lp), - } + let pool_state = + PoolState { + quantity_a: (#"", #"", qa), + quantity_b: (rberry.1st, rberry.2nd, qb), + quantity_lp: (lp.1st, lp.2nd, q_lp), + } let input_value = value.from_lovelace(has_a) |> value.add(rberry.1st, rberry.2nd, has_b) let assets = ((ada.1st, ada.2nd, gives_a), (rberry.1st, rberry.2nd, gives_b)) - let order = OrderDatum { - pool_ident: None, - owner: multisig.Signature( - #"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513", - ), - max_protocol_fee: 2_500_000, - destination: Fixed { + let order = + OrderDatum { + pool_ident: None, + owner: multisig.Signature( + #"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513", + ), + max_protocol_fee: 2_500_000, + destination: Fixed { address: addr, datum: NoDatum }, + details: order.Deposit { assets }, + extension: Void, + } + let output = + Output { address: addr, + value: out_value, datum: NoDatum, - }, - details: order.Deposit { - assets: assets, - }, - extension: Void, - } - let output = Output { - address: addr, - value: out_value, - datum: NoDatum, - reference_script: None, - } - let input = Output { - address: addr, - value: input_value, - datum: InlineDatum(order), - reference_script: None, - } - let _, _, _ <- do_deposit( - pool_state.quantity_a.1st, pool_state.quantity_a.2nd, pool_state.quantity_a.3rd, - pool_state.quantity_b.1st, pool_state.quantity_b.2nd, pool_state.quantity_b.3rd, - pool_state.quantity_lp.1st, pool_state.quantity_lp.2nd, pool_state.quantity_lp.3rd, - input, - assets, - order.destination, - 2_500_000, - output - ) + reference_script: None, + } + let input = + Output { + address: addr, + value: input_value, + datum: InlineDatum(order), + reference_script: None, + } + let + _, + _, + _, + <- + do_deposit( + pool_state.quantity_a.1st, + pool_state.quantity_a.2nd, + pool_state.quantity_a.3rd, + pool_state.quantity_b.1st, + pool_state.quantity_b.2nd, + pool_state.quantity_b.3rd, + pool_state.quantity_lp.1st, + pool_state.quantity_lp.2nd, + pool_state.quantity_lp.3rd, + input, + assets, + order.destination, + 2_500_000, + output, + ) // Test should pass as long as do_deposit didn't throw True } diff --git a/lib/tests/aiken/donation.ak b/lib/tests/aiken/donation.ak index a98ab16..6e14736 100644 --- a/lib/tests/aiken/donation.ak +++ b/lib/tests/aiken/donation.ak @@ -1,8 +1,8 @@ -use aiken/transaction.{NoDatum, InlineDatum, Output} +use aiken/transaction.{InlineDatum, NoDatum, Output} use aiken/transaction/credential.{Address, VerificationKeyCredential} use aiken/transaction/value -use calculation/shared.{PoolState} as calc_shared use calculation/donation.{do_donation} +use calculation/shared.{PoolState} as calc_shared use sundae/multisig use types/order.{Fixed, OrderDatum} @@ -27,10 +27,8 @@ test donation() { let input_value = value.from_lovelace(3_500_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 assets = + ((ada.1st, ada.2nd, 1_000_000), (rberry.1st, rberry.2nd, 1_000_000)) let order = OrderDatum { pool_ident: None, @@ -38,18 +36,17 @@ test donation() { #"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513", ), max_protocol_fee: 2_500_000, - destination: Fixed { address: addr, datum: NoDatum }, - details: order.Donation { - assets: assets, - }, + destination: Fixed { address: addr, datum: NoDatum }, + details: order.Donation { assets }, extension: Void, } - let input = Output { - address: addr, - value: input_value, - datum: InlineDatum(order), - reference_script: None, - } + let input = + Output { + address: addr, + value: input_value, + datum: InlineDatum(order), + reference_script: None, + } // There's no remainder so do_donation totally ignores this Output record let output = Output { @@ -58,13 +55,23 @@ test donation() { datum: NoDatum, reference_script: None, } - let new_a, new_b, has_remainder <- + let + new_a, + new_b, + has_remainder, + <- do_donation( - pool_state.quantity_a.1st, pool_state.quantity_a.2nd, pool_state.quantity_a.3rd, - pool_state.quantity_b.1st, pool_state.quantity_b.2nd, pool_state.quantity_b.3rd, + pool_state.quantity_a.1st, + pool_state.quantity_a.2nd, + pool_state.quantity_a.3rd, + pool_state.quantity_b.1st, + pool_state.quantity_b.2nd, + pool_state.quantity_b.3rd, input, - assets, order.destination, - 2_500_000, output + assets, + order.destination, + 2_500_000, + output, ) expect !has_remainder expect new_a == 1_001_000_000 @@ -72,7 +79,6 @@ test donation() { True } - test donation_with_remainder() { let addr = Address( @@ -94,10 +100,7 @@ test donation_with_remainder() { let input_value = value.from_lovelace(3_500_000) |> value.add(rberry.1st, rberry.2nd, 1_000_000) - let assets = ( - (ada.1st, ada.2nd, 0), - (rberry.1st, rberry.2nd, 1_000_000), - ) + let assets = ((ada.1st, ada.2nd, 0), (rberry.1st, rberry.2nd, 1_000_000)) let order = OrderDatum { pool_ident: None, @@ -105,18 +108,17 @@ test donation_with_remainder() { #"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513", ), max_protocol_fee: 2_500_000, - destination: Fixed { address: addr, datum: NoDatum }, - details: order.Donation { - assets: assets, - }, + destination: Fixed { address: addr, datum: NoDatum }, + details: order.Donation { assets }, extension: Void, } - let input = Output { - address: addr, - value: input_value, - datum: InlineDatum(order), - reference_script: None, - } + let input = + Output { + address: addr, + value: input_value, + datum: InlineDatum(order), + reference_script: None, + } let output = Output { address: addr, @@ -124,13 +126,23 @@ test donation_with_remainder() { datum: NoDatum, reference_script: None, } - let new_a, new_b, has_remainder <- + let + new_a, + new_b, + has_remainder, + <- do_donation( - pool_state.quantity_a.1st, pool_state.quantity_a.2nd, pool_state.quantity_a.3rd, - pool_state.quantity_b.1st, pool_state.quantity_b.2nd, pool_state.quantity_b.3rd, + pool_state.quantity_a.1st, + pool_state.quantity_a.2nd, + pool_state.quantity_a.3rd, + pool_state.quantity_b.1st, + pool_state.quantity_b.2nd, + pool_state.quantity_b.3rd, input, - assets, order.destination, - 2_500_000, output + assets, + order.destination, + 2_500_000, + output, ) expect has_remainder expect new_a == 1_000_000_000 @@ -138,7 +150,6 @@ test donation_with_remainder() { True } - test donation_with_wrong_remainder() fail { let addr = Address( @@ -160,10 +171,7 @@ test donation_with_wrong_remainder() fail { let input_value = value.from_lovelace(3_500_000) |> value.add(rberry.1st, rberry.2nd, 1_000_000) - let assets = ( - (ada.1st, ada.2nd, 0), - (rberry.1st, rberry.2nd, 1_000_000), - ) + let assets = ((ada.1st, ada.2nd, 0), (rberry.1st, rberry.2nd, 1_000_000)) let order = OrderDatum { pool_ident: None, @@ -171,18 +179,17 @@ test donation_with_wrong_remainder() fail { #"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513", ), max_protocol_fee: 2_500_000, - destination: Fixed { address: addr, datum: NoDatum }, - details: order.Donation { - assets: assets, - }, + destination: Fixed { address: addr, datum: NoDatum }, + details: order.Donation { assets }, extension: Void, } - let input = Output { - address: addr, - value: input_value, - datum: InlineDatum(order), - reference_script: None, - } + let input = + Output { + address: addr, + value: input_value, + datum: InlineDatum(order), + reference_script: None, + } let output = Output { address: addr, @@ -190,16 +197,26 @@ test donation_with_wrong_remainder() fail { datum: NoDatum, reference_script: None, } - let new_a, new_b, has_remainder <- + let + new_a, + new_b, + has_remainder, + <- do_donation( - pool_state.quantity_a.1st, pool_state.quantity_a.2nd, pool_state.quantity_a.3rd, - pool_state.quantity_b.1st, pool_state.quantity_b.2nd, pool_state.quantity_b.3rd, + pool_state.quantity_a.1st, + pool_state.quantity_a.2nd, + pool_state.quantity_a.3rd, + pool_state.quantity_b.1st, + pool_state.quantity_b.2nd, + pool_state.quantity_b.3rd, input, - assets, order.destination, - 2_500_000, output + assets, + order.destination, + 2_500_000, + output, ) expect has_remainder expect new_a == 1_000_000_000 expect new_b == 1_001_000_000 True -} \ No newline at end of file +} diff --git a/lib/tests/aiken/record.ak b/lib/tests/aiken/record.ak index f6b964e..c043d08 100644 --- a/lib/tests/aiken/record.ak +++ b/lib/tests/aiken/record.ak @@ -1,6 +1,8 @@ use aiken/interval -use aiken/transaction.{NoDatum, InlineDatum, Output} -use aiken/transaction/credential.{Address, VerificationKeyCredential, ScriptCredential} +use aiken/transaction.{InlineDatum, NoDatum, Output} +use aiken/transaction/credential.{ + Address, ScriptCredential, VerificationKeyCredential, +} use aiken/transaction/value use calculation/record.{check_record} use shared @@ -9,7 +11,8 @@ use types/oracle.{OracleDatum} as types_oracle use types/order.{Fixed} test record() { - let oracle_policy_id = #"00000000000000000000000000000000000000000000000000000000" + let oracle_policy_id = + #"00000000000000000000000000000000000000000000000000000000" let oracle_name = shared.oracle_sft_name() let addr = Address( @@ -18,37 +21,44 @@ test record() { ), None, ) - let input_value = - value.from_lovelace(4_500_000) - let destination = Fixed { - address: addr, - datum: NoDatum, + let input_value = value.from_lovelace(4_500_000) + let destination = Fixed { address: addr, datum: NoDatum } + let input = + Output { + address: addr, + value: input_value, + datum: InlineDatum(Void), + reference_script: None, } - let input = Output { - address: addr, - value: input_value, - datum: InlineDatum(Void), - reference_script: None, - } - let output = Output { - address: addr, - value: value.from_lovelace(2_000_000) - |> value.add(oracle_policy_id, oracle_name, 1), - datum: InlineDatum(OracleDatum { - owner: multisig.AnyOf([]), - valid_range: interval.between(0, 1), - pool_ident: #"00", - reserve_a: (#"00", #"00", 1_000_000), - reserve_b: (#"00", #"00", 1_000_000), - circulating_lp: (#"00", #"00", 1_000_000), - }), - reference_script: None, - } - check_record(input, destination, 2_500_000, output, (oracle_policy_id, oracle_name)) + let output = + Output { + address: addr, + value: value.from_lovelace(2_000_000) + |> value.add(oracle_policy_id, oracle_name, 1), + datum: InlineDatum( + OracleDatum { + owner: multisig.AnyOf([]), + valid_range: interval.between(0, 1), + pool_ident: #"00", + reserve_a: (#"00", #"00", 1_000_000), + reserve_b: (#"00", #"00", 1_000_000), + circulating_lp: (#"00", #"00", 1_000_000), + }, + ), + reference_script: None, + } + check_record( + input, + destination, + 2_500_000, + output, + (oracle_policy_id, oracle_name), + ) } test record_must_pay_to_destination() fail { - let oracle_policy_id = #"00000000000000000000000000000000000000000000000000000000" + let oracle_policy_id = + #"00000000000000000000000000000000000000000000000000000000" let oracle_name = shared.oracle_sft_name() let addr = Address( @@ -57,37 +67,44 @@ test record_must_pay_to_destination() fail { ), None, ) - let input_value = - value.from_lovelace(4_500_000) - let destination = Fixed { - address: addr, - datum: NoDatum, + let input_value = value.from_lovelace(4_500_000) + let destination = Fixed { address: addr, datum: NoDatum } + let input = + Output { + address: addr, + value: input_value, + datum: InlineDatum(Void), + reference_script: None, } - let input = Output { - address: addr, - value: input_value, - datum: InlineDatum(Void), - reference_script: None, - } - let output = Output { - address: Address(VerificationKeyCredential(#"00"), None), - value: value.from_lovelace(2_000_000) - |> value.add(oracle_policy_id, oracle_name, 1), - datum: InlineDatum(OracleDatum { - owner: multisig.AnyOf([]), - valid_range: interval.between(0, 1), - pool_ident: #"00", - reserve_a: (#"00", #"00", 1_000_000), - reserve_b: (#"00", #"00", 1_000_000), - circulating_lp: (#"00", #"00", 1_000_000), - }), - reference_script: None, - } - check_record(input, destination, 2_500_000, output, (oracle_policy_id, oracle_name)) + let output = + Output { + address: Address(VerificationKeyCredential(#"00"), None), + value: value.from_lovelace(2_000_000) + |> value.add(oracle_policy_id, oracle_name, 1), + datum: InlineDatum( + OracleDatum { + owner: multisig.AnyOf([]), + valid_range: interval.between(0, 1), + pool_ident: #"00", + reserve_a: (#"00", #"00", 1_000_000), + reserve_b: (#"00", #"00", 1_000_000), + circulating_lp: (#"00", #"00", 1_000_000), + }, + ), + reference_script: None, + } + check_record( + input, + destination, + 2_500_000, + output, + (oracle_policy_id, oracle_name), + ) } test record_must_have_token() fail { - let oracle_policy_id = #"00000000000000000000000000000000000000000000000000000000" + let oracle_policy_id = + #"00000000000000000000000000000000000000000000000000000000" let oracle_name = shared.oracle_sft_name() let addr = Address( @@ -96,36 +113,43 @@ test record_must_have_token() fail { ), None, ) - let input_value = - value.from_lovelace(4_500_000) - let destination = Fixed { - address: addr, - datum: NoDatum, + let input_value = value.from_lovelace(4_500_000) + let destination = Fixed { address: addr, datum: NoDatum } + let input = + Output { + address: addr, + value: input_value, + datum: InlineDatum(Void), + reference_script: None, + } + let output = + Output { + address: addr, + value: value.from_lovelace(2_000_000), + datum: InlineDatum( + OracleDatum { + owner: multisig.AnyOf([]), + valid_range: interval.between(0, 1), + pool_ident: #"00", + reserve_a: (#"00", #"00", 1_000_000), + reserve_b: (#"00", #"00", 1_000_000), + circulating_lp: (#"00", #"00", 1_000_000), + }, + ), + reference_script: None, } - let input = Output { - address: addr, - value: input_value, - datum: InlineDatum(Void), - reference_script: None, - } - let output = Output { - address: addr, - value: value.from_lovelace(2_000_000), - datum: InlineDatum(OracleDatum { - owner: multisig.AnyOf([]), - valid_range: interval.between(0, 1), - pool_ident: #"00", - reserve_a: (#"00", #"00", 1_000_000), - reserve_b: (#"00", #"00", 1_000_000), - circulating_lp: (#"00", #"00", 1_000_000), - }), - reference_script: None, - } - check_record(input, destination, 2_500_000, output, (oracle_policy_id, oracle_name)) + check_record( + input, + destination, + 2_500_000, + output, + (oracle_policy_id, oracle_name), + ) } test record_bad_datum() fail { - let oracle_policy_id = #"00000000000000000000000000000000000000000000000000000000" + let oracle_policy_id = + #"00000000000000000000000000000000000000000000000000000000" let oracle_name = shared.oracle_sft_name() let addr = Address( @@ -137,29 +161,36 @@ test record_bad_datum() fail { let input_value = value.from_lovelace(4_500_000) |> value.add(oracle_policy_id, oracle_name, 1) - let destination = Fixed { + let destination = Fixed { address: addr, datum: NoDatum } + let input = + Output { address: addr, - datum: NoDatum, + value: input_value, + datum: InlineDatum(Void), + reference_script: None, + } + let output = + Output { + address: addr, + value: value.from_lovelace(2_000_000) + |> value.add(oracle_policy_id, oracle_name, 1), + datum: InlineDatum( + OracleDatum { + owner: multisig.AnyOf([]), + valid_range: interval.between(0, 1), + pool_ident: #"00", + reserve_a: (#"00", #"00", 1_000_000), + reserve_b: (#"00", #"00", 1_000_000), + circulating_lp: (#"00", #"00", 1_000_000), + }, + ), + reference_script: None, } - let input = Output { - address: addr, - value: input_value, - datum: InlineDatum(Void), - reference_script: None, - } - let output = Output { - address: addr, - value: value.from_lovelace(2_000_000) - |> value.add(oracle_policy_id, oracle_name, 1), - datum: InlineDatum(OracleDatum { - owner: multisig.AnyOf([]), - valid_range: interval.between(0, 1), - pool_ident: #"00", - reserve_a: (#"00", #"00", 1_000_000), - reserve_b: (#"00", #"00", 1_000_000), - circulating_lp: (#"00", #"00", 1_000_000), - }), - reference_script: None, - } - check_record(input, destination, 2_500_000, output, (oracle_policy_id, oracle_name)) + check_record( + input, + destination, + 2_500_000, + output, + (oracle_policy_id, oracle_name), + ) } diff --git a/lib/tests/aiken/settings.ak b/lib/tests/aiken/settings.ak index e69de29..8b13789 100644 --- a/lib/tests/aiken/settings.ak +++ b/lib/tests/aiken/settings.ak @@ -0,0 +1 @@ + diff --git a/lib/tests/aiken/swap.ak b/lib/tests/aiken/swap.ak index d34a287..1ac1b55 100644 --- a/lib/tests/aiken/swap.ak +++ b/lib/tests/aiken/swap.ak @@ -1,11 +1,10 @@ -use aiken/transaction.{NoDatum, InlineDatum, Output} +use aiken/transaction.{InlineDatum, NoDatum, Output} use aiken/transaction/credential.{Address, VerificationKeyCredential} use aiken/transaction/value use calculation/shared.{PoolState} as calc_shared +use calculation/swap.{do_swap} use sundae/multisig use types/order.{Fixed, OrderDatum} -use calculation/swap.{do_swap} - test swap_mintakes_too_high() fail { let addr = @@ -16,51 +15,64 @@ test swap_mintakes_too_high() fail { None, ) let ada = (#"", #"") - let rberry = (#"01010101010101010101010101010101010101010101010101010101", "RBERRY") + let rberry = + (#"01010101010101010101010101010101010101010101010101010101", "RBERRY") let lp = (#"99999999999999999999999999999999999999999999999999999999", "LP") - let pool_state = PoolState { - 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), - } - let input_value = - value.from_lovelace(14_500_000) + let pool_state = + PoolState { + 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), + } + let input_value = value.from_lovelace(14_500_000) let swap_offer = (ada.1st, ada.2nd, 10_000_000) let swap_min_received = (rberry.1st, rberry.2nd, 10_000_000) - let order = OrderDatum { - pool_ident: None, - owner: multisig.Signature( - #"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513", - ), - max_protocol_fee: 2_500_000, - destination: Fixed { + let order = + OrderDatum { + pool_ident: None, + owner: multisig.Signature( + #"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513", + ), + max_protocol_fee: 2_500_000, + destination: Fixed { address: addr, datum: NoDatum }, + details: order.Swap { offer: swap_offer, min_received: swap_min_received }, + extension: Void, + } + let output = + Output { address: addr, + value: value.from_lovelace(2_000_000) + |> value.add(rberry.1st, rberry.2nd, 9_896_088), datum: NoDatum, - }, - details: order.Swap { offer: swap_offer, min_received: swap_min_received, }, - extension: Void, - } - let output = Output { - address: addr, - value: value.from_lovelace(2_000_000) - |> value.add(rberry.1st, rberry.2nd, 9_896_088), - datum: NoDatum, - reference_script: None, - } - let input = Output { - address: addr, - value: input_value, - datum: InlineDatum(order), - reference_script: None, - } - let new_a, new_b <- do_swap( - pool_state.quantity_a.1st, pool_state.quantity_a.2nd, pool_state.quantity_a.3rd, - pool_state.quantity_b.1st, pool_state.quantity_b.2nd, pool_state.quantity_b.3rd, - input, order.destination, - 5, 5, 2_500_000, - swap_offer, swap_min_received, - output - ) + reference_script: None, + } + let input = + Output { + address: addr, + value: input_value, + datum: InlineDatum(order), + reference_script: None, + } + let + new_a, + new_b, + <- + do_swap( + pool_state.quantity_a.1st, + pool_state.quantity_a.2nd, + pool_state.quantity_a.3rd, + pool_state.quantity_b.1st, + pool_state.quantity_b.2nd, + pool_state.quantity_b.3rd, + input, + order.destination, + 5, + 5, + 2_500_000, + swap_offer, + swap_min_received, + output, + ) expect new_a == 1_000_000_000 + 10_000_000 expect new_b == 1_000_000_000 - 9_896_088 True @@ -75,50 +87,65 @@ test swap_different_bid_ask() { None, ) let ada = (#"", #"") - let rberry = (#"01010101010101010101010101010101010101010101010101010101", "RBERRY") + let rberry = + (#"01010101010101010101010101010101010101010101010101010101", "RBERRY") let lp = (#"99999999999999999999999999999999999999999999999999999999", "LP") - let pool_state = PoolState { - 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), - } + let pool_state = + PoolState { + 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), + } let input_value = - value.from_lovelace(4_500_000) |> value.add(rberry.1st, rberry.2nd, 10_000_000) + value.from_lovelace(4_500_000) + |> value.add(rberry.1st, rberry.2nd, 10_000_000) let swap_offer = (rberry.1st, rberry.2nd, 10_000_000) let swap_min_received = (ada.1st, ada.2nd, 0) - let order = OrderDatum { - pool_ident: None, - owner: multisig.Signature( - #"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513", - ), - max_protocol_fee: 2_500_000, - destination: Fixed { + let order = + OrderDatum { + pool_ident: None, + owner: multisig.Signature( + #"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513", + ), + max_protocol_fee: 2_500_000, + destination: Fixed { address: addr, datum: NoDatum }, + details: order.Swap { offer: swap_offer, min_received: swap_min_received }, + extension: Void, + } + let output = + Output { address: addr, + value: value.from_lovelace(11_802_950), datum: NoDatum, - }, - details: order.Swap { offer: swap_offer, min_received: swap_min_received, }, - extension: Void, - } - let output = Output { - address: addr, - value: value.from_lovelace(11_802_950), - datum: NoDatum, - reference_script: None, - } - let input = Output { - address: addr, - value: input_value, - datum: InlineDatum(order), - reference_script: None, - } - let new_a, new_b <- do_swap( - pool_state.quantity_a.1st, pool_state.quantity_a.2nd, pool_state.quantity_a.3rd, - pool_state.quantity_b.1st, pool_state.quantity_b.2nd, pool_state.quantity_b.3rd, - input, order.destination, - 5, 100, 2_500_000, - swap_offer, swap_min_received, - output - ) + reference_script: None, + } + let input = + Output { + address: addr, + value: input_value, + datum: InlineDatum(order), + reference_script: None, + } + let + new_a, + new_b, + <- + do_swap( + pool_state.quantity_a.1st, + pool_state.quantity_a.2nd, + pool_state.quantity_a.3rd, + pool_state.quantity_b.1st, + pool_state.quantity_b.2nd, + pool_state.quantity_b.3rd, + input, + order.destination, + 5, + 100, + 2_500_000, + swap_offer, + swap_min_received, + output, + ) // If we charged 5%, from the bid fee, it would be `- 9_896_088`, but because we charged a higher fee, the user got less in return expect new_a == 1_000_000_000 - 9_802_950 expect new_b == 1_000_000_000 + 10_000_000 diff --git a/lib/tests/aiken/withdrawal.ak b/lib/tests/aiken/withdrawal.ak index 0fef208..e7d5461 100644 --- a/lib/tests/aiken/withdrawal.ak +++ b/lib/tests/aiken/withdrawal.ak @@ -1,11 +1,11 @@ use aiken/option -use aiken/transaction.{NoDatum, InlineDatum, Output} +use aiken/transaction.{InlineDatum, NoDatum, Output} use aiken/transaction/credential.{Address, VerificationKeyCredential} use aiken/transaction/value.{Value} use calculation/shared.{PoolState} as calc_shared +use calculation/withdrawal.{do_withdrawal} use sundae/multisig use types/order.{Fixed, OrderDatum} -use calculation/withdrawal.{do_withdrawal} type WithdrawalTestOptions { edit_withdrawal_value: Option, @@ -24,15 +24,16 @@ test withdrawal_ok() { withdrawal_test(options) } -!test withdrawal_wrong_output_value() { - let options = WithdrawalTestOptions { - ..default_withdrawal_test_options(), - edit_withdrawal_value: Some(value.from_lovelace(2_000_000)) - } +test withdrawal_wrong_output_value() fail { + let options = + WithdrawalTestOptions { + ..default_withdrawal_test_options(), + edit_withdrawal_value: Some(value.from_lovelace(2_000_000)), + } withdrawal_test(options) } -!test withdrawal_wrong_payout_address() { +test withdrawal_wrong_payout_address() fail { let burn_addr = Address( VerificationKeyCredential( @@ -40,10 +41,11 @@ test withdrawal_ok() { ), None, ) - let options = WithdrawalTestOptions { - ..default_withdrawal_test_options(), - edit_withdrawal_destination: Some(burn_addr), - } + let options = + WithdrawalTestOptions { + ..default_withdrawal_test_options(), + edit_withdrawal_destination: Some(burn_addr), + } withdrawal_test(options) } @@ -55,56 +57,70 @@ fn withdrawal_test(options: WithdrawalTestOptions) { ), None, ) - let rberry = (#"01010101010101010101010101010101010101010101010101010101", "RBERRY") + let rberry = + (#"01010101010101010101010101010101010101010101010101010101", "RBERRY") let lp = (#"99999999999999999999999999999999999999999999999999999999", "LP") - let pool_state = PoolState { - 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), - } + let pool_state = + PoolState { + 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), + } 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( - #"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513", - ), - max_protocol_fee: 2_500_000, - destination: Fixed { - address: addr, + let order = + OrderDatum { + pool_ident: None, + owner: multisig.Signature( + #"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513", + ), + max_protocol_fee: 2_500_000, + destination: Fixed { address: addr, datum: NoDatum }, + details: order.Withdrawal { amount }, + extension: Void, + } + let output = + Output { + address: option.or_else(options.edit_withdrawal_destination, addr), + value: option.or_else( + options.edit_withdrawal_value, + value.from_lovelace(2_000_000) + |> value.add(#"", #"", 10_000_000) + |> value.add(rberry.1st, rberry.2nd, 10_000_000), + ), datum: NoDatum, - }, - details: order.Withdrawal { - amount - }, - extension: Void, - } - let output = Output { - address: option.or_else(options.edit_withdrawal_destination, addr), - value: option.or_else( - options.edit_withdrawal_value, - value.from_lovelace(2_000_000) - |> value.add(#"", #"", 10_000_000) - |> value.add(rberry.1st, rberry.2nd, 10_000_000)), - datum: NoDatum, - reference_script: None, - } - let input = Output { - address: addr, - value: input_value, - datum: InlineDatum(order), - reference_script: None, - } - let new_a, new_b, new_lp <- do_withdrawal( - pool_state.quantity_a.1st, pool_state.quantity_a.2nd, pool_state.quantity_a.3rd, - pool_state.quantity_b.1st, pool_state.quantity_b.2nd, pool_state.quantity_b.3rd, - pool_state.quantity_lp.1st, pool_state.quantity_lp.2nd, pool_state.quantity_lp.3rd, - input, amount, - order.destination, 2_500_000, - output - ) + reference_script: None, + } + let input = + Output { + address: addr, + value: input_value, + datum: InlineDatum(order), + reference_script: None, + } + let + new_a, + new_b, + new_lp, + <- + do_withdrawal( + pool_state.quantity_a.1st, + pool_state.quantity_a.2nd, + pool_state.quantity_a.3rd, + pool_state.quantity_b.1st, + pool_state.quantity_b.2nd, + pool_state.quantity_b.3rd, + pool_state.quantity_lp.1st, + pool_state.quantity_lp.2nd, + pool_state.quantity_lp.3rd, + input, + amount, + order.destination, + 2_500_000, + output, + ) expect new_a == 1_000_000_000 expect new_b == 1_000_000_000 expect new_lp == 1000000000 diff --git a/lib/tests/examples/ex_order.ak b/lib/tests/examples/ex_order.ak index 1398a5a..35bffb2 100644 --- a/lib/tests/examples/ex_order.ak +++ b/lib/tests/examples/ex_order.ak @@ -1,12 +1,16 @@ use aiken/cbor -use types/order.{Fixed, OrderDatum, Swap, Deposit, Withdrawal, Strategy, StrategyExecution, SignedStrategyExecution, Signature, Scoop, Cancel} -use aiken/transaction.{NoDatum, OutputReference, TransactionId} use aiken/interval +use aiken/transaction.{NoDatum, OutputReference, TransactionId} use sundae/multisig use tests/examples/ex_shared.{print_example, wallet_address} +use types/order.{ + Cancel, Deposit, Fixed, OrderDatum, Scoop, Signature, SignedStrategyExecution, + Strategy, StrategyExecution, Swap, Withdrawal, +} fn mk_swap() -> OrderDatum { - let addr = wallet_address(#"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513") + let addr = + wallet_address(#"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513") let dest = Fixed { address: addr, datum: NoDatum } let swap = Swap( @@ -34,17 +38,20 @@ test example_swap() { } fn mk_deposit() -> OrderDatum { - let addr = wallet_address(#"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513") + let addr = + wallet_address(#"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513") let dest = Fixed { address: addr, datum: NoDatum } let deposit = - Deposit(( - (#"", #"", 10000000), + Deposit( ( - #"d441227553a0f1a965fee7d60a0f724b368dd1bddbc208730fccebcf", - #"44554d4d59", - 10000000, + (#"", #"", 10000000), + ( + #"d441227553a0f1a965fee7d60a0f724b368dd1bddbc208730fccebcf", + #"44554d4d59", + 10000000, + ), ), - )) + ) OrderDatum { pool_ident: None, owner: multisig.Signature( @@ -62,14 +69,15 @@ test example_deposit() { } fn mk_withdrawal() { - let addr = wallet_address(#"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513") + let addr = + wallet_address(#"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513") let dest = Fixed { address: addr, datum: NoDatum } let withdrawal = Withdrawal( ( #"d441227553a0f1a965fee7d60a0f724b368dd1bddbc208730fccebcf", #"6c", - 10000000 + 10000000, ), ) OrderDatum { @@ -89,11 +97,17 @@ test example_withdrawal() { } fn mk_strategy() { - let addr = wallet_address(#"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513") + let addr = + wallet_address(#"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513") let dest = Fixed { address: addr, datum: NoDatum } - let strategy = Strategy(Signature(#"d441227553a0f1a965fee7d60a0f724b368dd1bddbc208730fccebcf")) + let strategy = + Strategy( + Signature(#"d441227553a0f1a965fee7d60a0f724b368dd1bddbc208730fccebcf"), + ) OrderDatum { - pool_ident: Some(#"fc2c4a6ae8048b0b5affc169dfd496a7ace7d08288c476d9d7a5804e"), + pool_ident: Some( + #"fc2c4a6ae8048b0b5affc169dfd496a7ace7d08288c476d9d7a5804e", + ), owner: multisig.Signature( #"c279a3fb3b4e62bbc78e288783b58045d4ae82a18867d8352d02775a", ), @@ -109,10 +123,16 @@ test example_strategy() { } fn mk_strategy_execution() { - let tx_ref = OutputReference(TransactionId(#"797831ec63153a84ae1393bd5fea14196684f1dd12d6485e93cfe373d142e0d3"), 1) + let tx_ref = + OutputReference( + TransactionId( + #"797831ec63153a84ae1393bd5fea14196684f1dd12d6485e93cfe373d142e0d3", + ), + 1, + ) let valid_range = interval.between(1000, 10000) StrategyExecution { - tx_ref: tx_ref, + tx_ref, validity_range: valid_range, details: mk_swap().details, extensions: Void, @@ -126,7 +146,7 @@ test example_strategy_execution() { fn mk_signed_strategy_execution() { let sig = #"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513" SignedStrategyExecution { - strategy: mk_strategy_execution(), + execution: mk_strategy_execution(), signature: Some(sig), } } @@ -138,6 +158,7 @@ test example_signed_strategy_execution() { test example_cancel_redeemer() { print_example(cbor.serialise(Cancel)) } + test example_scoop_redeemer() { print_example(cbor.serialise(Scoop)) } diff --git a/lib/tests/examples/ex_pool.ak b/lib/tests/examples/ex_pool.ak index de19658..1f39bcf 100644 --- a/lib/tests/examples/ex_pool.ak +++ b/lib/tests/examples/ex_pool.ak @@ -1,5 +1,8 @@ -use types/pool.{PoolDatum, PoolRedeemer, PoolMintRedeemer, PoolScoop, ManageRedeemer, CreatePool, WithdrawFees} use tests/examples/ex_shared.{print_example} +use types/pool.{ + CreatePool, ManageRedeemer, PoolDatum, PoolMintRedeemer, PoolRedeemer, + PoolScoop, WithdrawFees, +} fn mk_pool_datum() -> PoolDatum { PoolDatum { @@ -12,11 +15,10 @@ fn mk_pool_datum() -> PoolDatum { ), ), circulating_lp: 20229488080013, - bid_fees_per_10_thousand: (2000, 500), - ask_fees_per_10_thousand: (2000, 500), + bid_fees_per_10_thousand: 2000, + ask_fees_per_10_thousand: 2000, fee_manager: None, market_open: 100, - fee_finalized: 1000, protocol_fees: 10000000, } } @@ -26,7 +28,11 @@ test example_pool_datum() { } fn mk_pool_scoop() -> PoolRedeemer { - PoolScoop { signatory_index: 0, scooper_index: 0, input_order: [(1, None, 0)] } + PoolScoop { + signatory_index: 0, + scooper_index: 0, + input_order: [(1, None, 0)], + } } test example_pool_scoop_redeemer() { diff --git a/lib/tests/examples/ex_settings.ak b/lib/tests/examples/ex_settings.ak index 59cc6c1..a564f45 100644 --- a/lib/tests/examples/ex_settings.ak +++ b/lib/tests/examples/ex_settings.ak @@ -1,35 +1,39 @@ -use aiken/transaction/credential.{Address, VerificationKeyCredential} use aiken/cbor -use sundae/multisig +use aiken/transaction.{InlineDatum, Input, Output} +use aiken/transaction/credential.{Address, VerificationKeyCredential} use aiken/transaction/value +use sundae/multisig +use tests/examples/ex_shared.{mk_output_reference, + print_example, script_address} use types/settings.{SettingsDatum} -use aiken/transaction.{Input, Output, InlineDatum} -use tests/examples/ex_shared.{print_example, script_address, mk_output_reference} -pub const example_settings_admin = #"6313a1d2c296eb3341e159b6c5c6991de11e81062b95108c9aa024ad" -pub const example_metadata_admin = #"7b143ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513" -pub const example_treasury_admin = #"17bbd2d2c296eb3341e159b6c5c6991de11e81062b95108c9aa024ad" -pub const example_treasury_address = #"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513" +pub const example_settings_admin = + #"6313a1d2c296eb3341e159b6c5c6991de11e81062b95108c9aa024ad" + +pub const example_metadata_admin = + #"7b143ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513" -pub fn mk_valid_settings_datum( - scoopers: List, -) -> SettingsDatum { +pub const example_treasury_admin = + #"17bbd2d2c296eb3341e159b6c5c6991de11e81062b95108c9aa024ad" + +pub const example_treasury_address = + #"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513" + +pub fn mk_valid_settings_datum(scoopers: List) -> SettingsDatum { SettingsDatum { - settings_admin: multisig.Signature( - example_settings_admin, + settings_admin: multisig.Signature(example_settings_admin), + metadata_admin: Address( + VerificationKeyCredential(example_metadata_admin), + None, ), - metadata_admin: Address(VerificationKeyCredential(example_metadata_admin), None), - treasury_admin: multisig.Signature( - example_treasury_admin, + treasury_admin: multisig.Signature(example_treasury_admin), + treasury_address: Address( + VerificationKeyCredential(example_treasury_address), + None, ), - treasury_address: Address(VerificationKeyCredential(example_treasury_address), None), treasury_allowance: (1, 10), authorized_scoopers: Some(scoopers), - authorized_staking_keys: [ - VerificationKeyCredential( - example_settings_admin, - ), - ], + authorized_staking_keys: [VerificationKeyCredential(example_settings_admin)], base_fee: 0, simple_fee: 2_500_000, strategy_fee: 5_000_000, @@ -38,16 +42,12 @@ pub fn mk_valid_settings_datum( } } -pub fn mk_valid_settings_input( - scoopers: List, - ix: Int, -) -> Input { +pub fn mk_valid_settings_input(scoopers: List, ix: Int) -> Input { let hash_of_settings_script = #"00000000000000000000000000000000000000000000000000000000" let settings_nft_name = "settings" let settings_address = script_address(hash_of_settings_script) let settings_datum = mk_valid_settings_datum(scoopers) - let settings_input = Input { output_reference: mk_output_reference(ix), @@ -64,44 +64,45 @@ pub fn mk_valid_settings_input( test example_settings_datum() { print_example( - cbor.serialise(mk_valid_settings_datum([ - example_settings_admin, - ])), + cbor.serialise(mk_valid_settings_datum([example_settings_admin])), ) } test example_big_settings_datum() { // 30 scoopers at least - print_example(mk_valid_settings_datum([ - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02400", - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02401", - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02402", - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02403", - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02404", - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02405", - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02406", - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02407", - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02408", - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02409", - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02410", - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02411", - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02412", - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02413", - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02414", - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02415", - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02416", - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02417", - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02418", - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02419", - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02421", - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02422", - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02423", - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02424", - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02425", - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02426", - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02427", - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02428", - #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02429", - ]) + print_example( + mk_valid_settings_datum( + [ + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02400", + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02401", + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02402", + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02403", + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02404", + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02405", + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02406", + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02407", + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02408", + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02409", + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02410", + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02411", + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02412", + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02413", + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02414", + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02415", + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02416", + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02417", + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02418", + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02419", + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02421", + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02422", + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02423", + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02424", + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02425", + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02426", + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02427", + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02428", + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa02429", + ], + ), ) -} \ No newline at end of file +} diff --git a/lib/tests/examples/ex_shared.ak b/lib/tests/examples/ex_shared.ak index 3b4048c..1024152 100644 --- a/lib/tests/examples/ex_shared.ak +++ b/lib/tests/examples/ex_shared.ak @@ -1,9 +1,15 @@ use aiken/bytearray use aiken/cbor -use aiken/transaction.{OutputReference, TransactionId} -use aiken/transaction/credential.{Address, Inline, StakeCredential, ScriptCredential, VerificationKeyCredential} +use aiken/int +use aiken/transaction.{ + Mint, OutputReference, ScriptPurpose, Spend, TransactionId, WithdrawFrom, +} +use aiken/transaction/credential.{ + Address, Inline, ScriptCredential, StakeCredential, VerificationKeyCredential, +} pub const examples_enabled: Int = 1 + pub fn print_example(d: Data) -> Bool { if examples_enabled == 1 { trace bytearray.to_hex(cbor.serialise(d)) @@ -36,15 +42,38 @@ pub fn wallet_address(hash: ByteArray) -> Address { } pub fn compare_stake(left: StakeCredential, right: StakeCredential) -> Ordering { - let left = when left is { - Inline(ScriptCredential(x)) -> x - Inline(VerificationKeyCredential(x)) -> x - _ -> fail + let left = + when left is { + Inline(ScriptCredential(x)) -> x + Inline(VerificationKeyCredential(x)) -> x + _ -> fail } - let right = when right is { - Inline(ScriptCredential(x)) -> x - Inline(VerificationKeyCredential(x)) -> x - _ -> fail + let right = + when right is { + Inline(ScriptCredential(x)) -> x + Inline(VerificationKeyCredential(x)) -> x + _ -> fail } - bytearray.compare(left, right) + bytearray.compare(left, right) +} + +pub fn compare_redeemer(left: ScriptPurpose, right: ScriptPurpose) -> Ordering { + when (left, right) is { + (Mint(p_a), Mint(p_b)) -> bytearray.compare(p_a, p_b) + ( + Spend(OutputReference(TransactionId(tx_a), idx_a)), + Spend(OutputReference(TransactionId(tx_b), idx_b)), + ) -> + when bytearray.compare(tx_a, tx_b) is { + Less -> Less + Greater -> Greater + Equal -> int.compare(idx_a, idx_b) + } + (WithdrawFrom(stake_a), WithdrawFrom(stake_b)) -> + compare_stake(stake_a, stake_b) + (Mint(_), _) -> Less + (Spend(_), _) -> Less + (WithdrawFrom(_), _) -> Less + (_, _) -> Greater + } } diff --git a/lib/types/oracle.ak b/lib/types/oracle.ak index bbecf1f..faa8fb4 100644 --- a/lib/types/oracle.ak +++ b/lib/types/oracle.ak @@ -1,6 +1,6 @@ -use sundae/multisig use aiken/transaction.{ValidityRange} -use shared.{SingletonValue, Ident} +use shared.{Ident, SingletonValue} +use sundae/multisig pub type OracleDatum { // The owner who is allowed to reclaim this datum at the end @@ -16,6 +16,9 @@ pub type OracleDatum { } pub type OracleRedeemer { + // Mint an oracle, observing a specific pool ident, for the orders at + // specific indices on the inputs Mint(Ident, List) + // Burn the oracle token, so it can't be used to lie about the pool Burn } diff --git a/lib/types/order.ak b/lib/types/order.ak index 79e3404..5f06371 100644 --- a/lib/types/order.ak +++ b/lib/types/order.ak @@ -1,9 +1,9 @@ +use aiken/hash.{Blake2b_224, Hash} use aiken/transaction.{Datum, OutputReference, ValidityRange} -use aiken/transaction/credential.{Address, VerificationKey, Signature, Script} -use aiken/transaction/value.{PolicyId, AssetName} +use aiken/transaction/credential.{Address, Script, Signature, VerificationKey} +use aiken/transaction/value.{AssetName, PolicyId} use shared.{Ident, SingletonValue} use sundae/multisig.{MultisigScript} -use aiken/hash.{Hash, Blake2b_224} /// An order to execute within the SundaeSwap ecosystem pub type OrderDatum { @@ -14,12 +14,12 @@ pub type OrderDatum { /// An canonical "owner" of this order, with the possibility of multisig /// schemes and script restrictions. Allows updates or cancellations of the order owner: MultisigScript, + // TODO: consider: does this undercut the usefulness of strategies? i.e. + // might the strategy executor need to adjust the max_protocol_fee? or would that be too dangerous? /// The maximum amount of ADA that can be taken as a protocol fee /// For example, a user would typically set this to baseFee + incrementalFee /// which allows their order to execute as the only order in a batch; if it /// executes as a larger batch, the user may receive some of this ADA back as a rebate. - // TODO: consider: does this undercut the usefulness of strategies? i.e. - // might the strategy executor need to adjust the max_protocol_fee? or would that be too dangerous? max_protocol_fee: Int, /// Where the output of executing an order should be sent destination: Destination, @@ -69,10 +69,10 @@ pub type Order { /// We use an at-most amount semantics to aide in composibility; perhaps the withdrawal is part of a longer chain, /// and you only want to withdraw a portion of your full LP tokens Withdrawal { amount: SingletonValue } - /// Deposit these assets into the pool, and mint the appropriate number of LP tokens // Note: we decided not to implement native ZapIn / ZapOut for the purposes of time; they can be implemented via chained orders or strategies. // ZapIn { assets: (SingletonValue, SingletonValue) } // ZapOut { assets: (Int, Int) } + /// Deposit these assets into the pool, and mint the appropriate number of LP tokens /// Donate some value to the pool; Likely not useful for an end user, but lets other /// protocols create interesting options: for example, an incentive program for their liquidity providers, etc. Donation { assets: (SingletonValue, SingletonValue) } @@ -109,7 +109,7 @@ pub type StrategyExecution { /// A specific strategy execution, plus a signature of that data pub type SignedStrategyExecution { /// The details about how to execute the strategy for a given order - strategy: StrategyExecution, + execution: StrategyExecution, /// An ed25519 signature of the serialized `strategy` signature: Option, } diff --git a/lib/types/pool.ak b/lib/types/pool.ak index eb0fb9b..c6f84de 100644 --- a/lib/types/pool.ak +++ b/lib/types/pool.ak @@ -1,7 +1,7 @@ use aiken/time.{PosixTime} use shared.{AssetClass, Ident} -use types/order.{SignedStrategyExecution} use sundae/multisig +use types/order.{SignedStrategyExecution} /// The current state of a AMM liquidity pool at a UTXO. pub type PoolDatum { @@ -18,19 +18,13 @@ pub type PoolDatum { circulating_lp: Int, /// The basis points to charge on each trade for bid (A -> B) and ask (B -> A) orders /// For example, a 1% fee would be represented as 100 (out of 10,000), and a 0.3% fee would be represented as 30 - /// The two values represent the fees as of `market_open` and as of `fee_finalized`, respectively, with a linear - /// decay from one to the other. - /// The transaction uses the valid_from field to charge the largest fee the transaction *could* be obligated to pay - bid_fees_per_10_thousand: (Int, Int), - ask_fees_per_10_thousand: (Int, Int), + bid_fees_per_10_thousand: Int, + ask_fees_per_10_thousand: Int, // An optional multisig condition under which the protocol fees can be updated fee_manager: Option, /// The UNIX millisecond timestamp at which trading against the pool should be allowed /// TODO: deposits and arguably withdrawals should be processed before the market open market_open: PosixTime, - /// The UNIX millisecond timestamp at which the fees reach their final resting state - /// For example, a pool may be opened at a 20% fee, and decay gradually down to a 1% fee pool over the course of the first month. - fee_finalized: PosixTime, /// The amount of ADA on the UTXO that is set aside by collecting protocol fees /// This should be increased on each scoop to represent collecting fees; deducted from the reserve amount (if one of the tokens in the pair is ADA) /// to calculate the swap amounts, and decreased when some amount is withdrawn. @@ -84,17 +78,16 @@ pub type PoolMintRedeemer { /// That token is given to a "metadata administrator" who can set the appropriate metadata, and update it if needed. /// This is done so we can efficiently skip to the correct metadata output /// This is safe because we validate that the token is paid to the metadata admin - metadata_output: Int + metadata_output: Int, } /// to burn the pool NFT (when permitted by the spending validator) BurnPool { identifier: Ident } } +/// Manage settings about a pool (used against the pool manage script) pub type ManageRedeemer { - WithdrawFees { - amount: Int, - treasury_output: Int, - pool_input: Int, - } - UpdatePoolFees { pool_input: Int, } + // Withdraw some subset of the fees in the pool, paid into the treasury + WithdrawFees { amount: Int, treasury_output: Int, pool_input: Int } + // Update the percentage fee the pool charges + UpdatePoolFees { pool_input: Int } } diff --git a/lib/types/settings.ak b/lib/types/settings.ak index 6cdb84b..fcf9bbc 100644 --- a/lib/types/settings.ak +++ b/lib/types/settings.ak @@ -1,12 +1,10 @@ -use aiken/transaction/credential.{Address, VerificationKey, Credential} -use sundae/multisig.{MultisigScript} -use shared.{Rational} -use aiken/transaction.{ - InlineDatum, Input, Output, -} use aiken/builtin -use aiken/transaction/value.{AssetName, PolicyId} use aiken/dict +use aiken/transaction.{InlineDatum, Input, Output} +use aiken/transaction/credential.{Address, Credential, VerificationKey} +use aiken/transaction/value.{AssetName, PolicyId} +use shared.{Rational} +use sundae/multisig.{MultisigScript} /// Various protocol-wide settings, mostly used as reference inputs to other transactions pub type SettingsDatum { @@ -20,37 +18,37 @@ pub type SettingsDatum { /// - base_fee, simple_fee, strategy_fee, to set the monetary policy /// - extensions, to allow configuring arbitrary non-binding settings data settings_admin: MultisigScript, - /// The address to which the CIP-68 (100) tokens are minted with a void datum, to allow administration of the LP tokens image - metadata_admin: Address, // Who or what governs the evolution of CIP-68 token metadata + metadata_admin: Address, + // Who or what governs the evolution of CIP-68 token metadata /// The conditions under which the treasury admin can act /// For example, this may be a multisig script, or have additional script conditions using a stake withdrawal address /// The treasury admin is allowed to withdraw funds from a pool into the treasury, and can set the following settings /// - treasury_address, to allow setting the destination of the DAO treasury withdrawals; TODO: should this instead be the settings admin, for separation of powers? /// - authorized_staking_keys, to establish a policy of which pools each liquidity pool can be delegated to (each pool can be changed at the time of withdrawal) - treasury_admin: MultisigScript, // Who can withdraw to the treasury and control delegation + treasury_admin: MultisigScript, + // Who can withdraw to the treasury and control delegation /// The address to which the treasury funds must be withdrawn, such as a governance DAO; TODO: should this be a destination or something similar? Should it enforce a null datum? - treasury_address: Address, // Where to withdraw treasury funds + treasury_address: Address, + // Where to withdraw treasury funds /// An allowed withholding that the treasury admin can keep to pay administrative fees /// Asking for a DAO vote for each bit of administrative overhead would quickly deter and overwhelm people from participating in governance /// So, the DAO can instead set a specific percentage of operating funds that go to operating costs /// The treasury administrator is responsible for keeping this percentage, and then paying for things like the scoopers, server infrastructure, etc. - treasury_allowance: Rational, // When withdrawing, what percentage can be released for administrative purposes? - + treasury_allowance: Rational, + // When withdrawing, what percentage can be released for administrative purposes? /// The list of actors who are allowed to execute scoops /// If set to None, *anyone* is allowed to execute a scoop /// Note: this would forfeit first-come-first-serve and MEV protection that Sundae /// currently enjoys, but this at least provides the DAO with flexibility to make that choice. authorized_scoopers: Option>, - /// The list of authorized staking keys that can be attached to a pool; It's a list, so that if the protocol TVL exceeds the saturation point for a single pool, /// or the DAO directs the treasury administrator to split the pool delegation across multiple pools, the treasury administrator can do so. /// Also note, that if any one pool ever exceeds the delegation percentage, it can't be split further. This is a problem we intend to solve with a future version of the protocol authorized_staking_keys: List, - /// The base fee, in lovelace, to be collected each time a batch happens; can be shared among all participants in the batch. base_fee: Int, /// The additional fee, in lovelace, to charge each "simple" order, such as a swap, deposit, withdraw, etc. @@ -62,13 +60,12 @@ pub type SettingsDatum { /// This fee is charged to those who open pools, and represents the minimum initial value for `protocol_fees`. /// It represents another source of revenue for the protocol, should it choose to exercise it. pool_creation_fee: Int, - + // TODO: Perhaps we should split this into separate fields, with different permissions to update it from each administrator + // for example, maybe there is a "settings_extensions", "treasury_extensions", etc. /// Any arbitrary "extension" data that can be added to the datum; This isn't used by any existing scripts, but may be used to: /// - publish data for convenient and canonical access by off-chain actors /// - expose data to the script conditions in the multisig scripts of the two administrator roles /// - expose additional settings for more advanced pool and order types to operate off of - // TODO: Perhaps we should split this into separate fields, with different permissions to update it from each administrator - // for example, maybe there is a "settings_extensions", "treasury_extensions", etc. extensions: Data, } @@ -87,25 +84,28 @@ pub const settings_nft_name: AssetName = "settings" /// Note that this makes the assumption that the settings datum is the first reference input, for performance /// This means that when storing reference scripts on-chain, there needs to be a small amount of "farming" to select /// UTXOs that are higher than the settings datum input. Awkward, but GOTTA GO FAST! -pub fn find_settings_datum(reference_inputs: List, settings_policy_id: PolicyId) -> SettingsDatum { +pub fn find_settings_datum( + reference_inputs: List, + settings_policy_id: PolicyId, +) -> SettingsDatum { // Assume the settings input is at the head of the list. let settings_output = builtin.head_list(reference_inputs).output - /// Convert the value on this UTXO to a list we can easily scan over let settings_value_list = dict.to_list(value.to_dict(settings_output.value)) - /// Since it will always only have ADA and the settings NFT, we make assumptions about this structure - /// TODO: make sure the settings spend scripts enforce this condition expect [_, (found_policy_id, settings_dict)] = settings_value_list - /// Check that the policy ID on that singular token matches the expected settings policy ID - /// This ensures that we have the real settings UTXO, and not one that someone just paid ADA into with an arbitrary datum expect found_policy_id == settings_policy_id - /// Check that the asset name and quantity exactly match what we expect - /// TODO: is this neccesary? if we only allow minting a single settings token, it can't be anything else expect dict.to_list(settings_dict) == [(settings_nft_name, 1)] - /// Extract the datum; note, this makes the assumption that the settings datum will always be inline - /// but this is a safe assumption to make because we don't expect to compose the spending of the settings datum - /// with other scripts expect InlineDatum(settings_datum) = settings_output.datum - /// Cast it to the right type, to ensure it's not some other random datum! expect settings_datum: SettingsDatum = settings_datum settings_datum } +/// Convert the value on this UTXO to a list we can easily scan over +/// Since it will always only have ADA and the settings NFT, we make assumptions about this structure +/// TODO: make sure the settings spend scripts enforce this condition +/// Check that the policy ID on that singular token matches the expected settings policy ID +/// This ensures that we have the real settings UTXO, and not one that someone just paid ADA into with an arbitrary datum +/// Check that the asset name and quantity exactly match what we expect +/// TODO: is this neccesary? if we only allow minting a single settings token, it can't be anything else +/// Extract the datum; note, this makes the assumption that the settings datum will always be inline +/// but this is a safe assumption to make because we don't expect to compose the spending of the settings datum +/// with other scripts +/// Cast it to the right type, to ensure it's not some other random datum! diff --git a/plutus.json b/plutus.json index 89a3098..2200c90 100644 --- a/plutus.json +++ b/plutus.json @@ -12,12 +12,29 @@ "license": "Apache-2.0" }, "validators": [ + { + "title": "documentation.spend", + "datum": { + "title": "_d", + "schema": { + "$ref": "#/definitions/types~1order~1OrderDatum" + } + }, + "redeemer": { + "title": "_r", + "schema": { + "$ref": "#/definitions/Data" + } + }, + "compiledCode": "5906290100003232323232322322253330054a229309b2b191919191919192999804980398051baa00813232323232323232323232325333018301a002132323232498c94ccc064c05c0044c8c94ccc078c0800084c92632533301c301a0011323253330213023002149858dd71810800980f1baa0021533301c30190011323253330213023002149858dd71810800980f1baa00216301c37540022c603c00260366ea801c54ccc064c0580044c8c8c8c94ccc080c0880084c8c926323232323253330263028002149858dd6981300098130011bae30240013024003375c60440046464646464a66604a604e0042930b1bad30250013025002375c604600260460086eb8c08400c58dd6181000098100011bac301e001301b375400e2a666032602600226464a66603c6040004264931919191919191919299981318140010a4c2c6eb4c098004c098008dd7181200098120019bae3022002323232323253330253027002149858dd6981280098128011bae30230013023003375c60420046eb0c078008dd6180e0008b19299980f18101810000899bb0301f001301f3020001163758603c00260366ea801c54ccc064cdc3a400c00226464a66603c6040004264931919191919299981198128010a4c2c6eb4c08c004c08c008dd7181080098108011bae301f001163758603c00260366ea801c54ccc064cdc3a401000226464a66603c6040004264931919191919191919299981318140010a4c2c6eb4c098004c098008dd7181200098120019bae3022002323232323253330253027002149858dd6981280098128011bae30230013023003375c60420046eb0c078008dd6180e0008b19299980f18101810000899bb0301f001301f3020001163758603c00260366ea801c54ccc064cdc3a401400226464a66603c604000426493191bae301e002375c60380022c64a66603c60406040002266ec0c07c004c07cc08000458dd6180f000980d9baa007163019375400c64a666030602c002264646464a66603e6042004264649319299980f180e0008a99981098101baa00314985854ccc078c06c0044c8c94ccc08cc09400852616375c604600260406ea800c54ccc078c0600044c8c94ccc08cc094008526163023001302037540062c603c6ea80094ccc070c068c074dd5001899191919299981198128010991924c64a666044604000226464a66604e6052004264931929998129811800899192999815181600109924c60460022c6054002604e6ea800854ccc094c0880044c8c8c8c8c8c94ccc0b8c0c000852616375a605c002605c0046eb4c0b0004c0b0008dd6981500098139baa00216302537540022c604e00260486ea800c54ccc088c07c00454ccc094c090dd50018a4c2c2c60446ea8008c07000c58c08c004c08c008c084004c078dd50018b0b180f800980f801180e800980d1baa0081533301830150011533301b301a37540102930b0b180c1baa007300e00a325333016301400113232533301b301d002149858dd7180d800980c1baa00c15333016301300115333019301837540182930b0b180b1baa00b16301800130180023016001301600230140013014002375a6024002602400460200026020004601c00260166ea802058c00400488c94ccc028c0200044c8c94ccc03cc04400852616375c601e00260186ea800854ccc028c01c0044c8c94ccc03cc0440084c92633007001233006006001163758601e00260186ea800854ccc028c0100044c8c94ccc03cc0440084c92633007001233006006001163758601e00260186ea800854ccc028cdc3a400c002264646464a666022602600426493198048009198040040008b1bac30110013011002375a601e00260186ea800854ccc028cdc3a401000226464a66601e60220042930b1bad300f001300c37540042a66601466e1d200a00113232533300f3011002149858dd6980780098061baa0021533300a3370e900600089919299980798088010a4c2c6eb8c03c004c030dd50010b18051baa001370e90021119198008008019129998060008a4c26466006006601e0046006601a002464a66600c600800226464a666016601a0042930b1bae300b001300837540042a66600c600600226464a666016601a0042930b1bae300b001300837540042c600c6ea8004dc3a40046e1d20005734aae7555cf2ab9f5742ae89", + "hash": "fdf6390e10925e2d3730af90b67c463677a8c357453472dd2da342e5" + }, { "title": "oracle.spend", "datum": { "title": "datum", "schema": { - "$ref": "#/definitions/Data" + "$ref": "#/definitions/types~1oracle~1OracleDatum" } }, "redeemer": { @@ -26,16 +43,8 @@ "$ref": "#/definitions/RedeemerWrapper$Data" } }, - "parameters": [ - { - "title": "pool_script_hash", - "schema": { - "$ref": "#/definitions/ByteArray" - } - } - ], - "compiledCode": "59162d01000032323232323232232225323232323232323233300d3002300e375401226464a66601ea66601e600860206ea80304c8c8c8c8c94ccc050c024c054dd5000899191919191919299980d9808180e1baa001132533301c3375e6008603c6ea8c010c078dd5000980b998101ba901a4bd70099299980e98099998009bab300b301f375400401200c264a66603c602a603e6ea80044c8c8c8c8c8c8c8c8c8c8c8cdc42400060546ea8c0acc8ccc004004dd6180898161baa3012302c375404c97bdb18010100000103d87a8000222533302f00210011333003003303200232323232533303030250011337606ea000cccc0c0009300103d87a80004c0103d87980001533303030260011325333031302630323754002264a666064604e60666ea80044c8c8c94ccc0d4c0a8c0d8dd500089919191919299981d19baf3022303c3754604460786ea8038c0d4cc0f8dd481325eb804c94ccc0ecc0c0c0f0dd500089919299981e99baf302b303f375400460846086608660866086608660866086607e6ea8c094c0fcdd501c8a99981e99b8f375c6048607e6ea80080b454ccc0f4cdd79812981f9baa0020051533303d3375e6e9c05cc108c10cc10cc10cc0fcdd50010a99981e99baf374e02c60846086608660866086607e6ea800854ccc0f4cdd79ba70153006303f3754004266ec0dd419b8001048008ccc0f403d30103d87a80004c0103d879800016161616161632533303d3032303e37540042646464646464646464646464a666098609e00426464646464931919191919299982a982c0010a4c2c6eb4c158004c158008dd7182a000982a0031bae3052005323232323253330543057002149858dd6982a800982a8011bae30530013053007375c60a200c6464646464a6660a660ac0042930b1bad30540013054002375c60a400260a40106eb8c14001d4ccc128c0fcc12cdd50050991919192999828982a0010991924c602600460240062c60a400260a400460a000260986ea802858c0a402c58dd6182680098268011bac304b001304b0023758609200260920046eb8c11c004c11c008c114004c114008c10c004c0fcdd50010b1299981e9819181f1baa00113232323253330443047002132498c94ccc108c0dc00454ccc114c110dd50020a4c2c2a666084607000226464a66608e60940042930b1bad3048001304437540082a66608460720022a66608a60886ea80105261616304237540062c64a66608860860022a666082606e6084002294454ccc104c0d8c1080045280b0b1baa304500130450023043001303f37540022c6080607a6ea800458cc01cdd59804181e1baa3022303c375406c01c2c6032002600260746ea800c8c0f4c0f8c0f8c0f8c0f8c0f8004c94ccc0dcc0b0c0e0dd500109919191919191919191919192999823182480109919191924c64a66608e607800226464a666098609e00426493192999825181f80089919299982798290010a4c2c6eb8c140004c130dd50010a999825182000089919299982798290010a4c2c6eb8c140004c130dd50010b18251baa00116304d0013049375400e2a66608e607a002264646464a66609c60a200426464931919191919299982a182b8010a4c2c6eb4c154004c154008dd7182980098298019bae3051002323232323253330533056002149858dd6982a000982a0011bae30520013052004375c60a00062c6eb0c13c004c13c008dd6182680098249baa00715333047303e00113232533304c304f002132498c8c8c8c8c8c8c8c94ccc150c15c00852616375a60aa00260aa0046eb8c14c004c14c00cdd7182880119191919192999829982b0010a4c2c6eb4c150004c150008dd7182900098290019bae3050002375860980046eb0c12800458c94ccc130c13cc13c0044cdd81827000982718278008b1bac304d0013049375400e2a66608e608200226464a666098609e0042649319191919192999828982a0010a4c2c6eb4c148004c148008dd7182800098280011bae304e001163758609a00260926ea801c54ccc11cc1000044c8c94ccc130c13c0084c926323232323232323253330543057002149858dd6982a800982a8011bae30530013053003375c60a20046464646464a6660a660ac0042930b1bad30540013054002375c60a400260a40066eb8c140008dd618260011bac304a0011632533304c304f304f001133760609c002609c609e0022c6eb0c134004c124dd50038a999823981f800899192999826182780109924c646eb8c130008dd718250008b19299982618279827800899bb0304e001304e304f001163758609a00260926ea801c58c11cdd5003192999823181d800899191919299982698280010991924c64a66609860820022a66609e609c6ea800c526161533304c30420011323253330513054002149858dd7182900098271baa0031533304c30430011323253330513054002149858c148004c138dd50018b18261baa002533304a303f304b3754006264646464a6660a260a80042646493192999828182280089919299982a982c00109924c64a6660a6609000226464a6660b060b600426493180f8008b182c800982a9baa0021533305330490011323232323232533305c305f002149858dd6982e800982e8011bad305b001305b002375a60b200260aa6ea800858c14cdd50008b182b00098291baa00315333050304600115333053305237540062930b0b18281baa002301800316305200130520023050001304c37540062c2c609c002609c004609800260906ea802054ccc118c0f000454ccc124c120dd50040a4c2c2c608c6ea801cc090028c94ccc110c0e40044c8c94ccc124c13000852616375c6094002608c6ea803054ccc110c0e800454ccc11cc118dd50060a4c2c2c60886ea802c58c11c004c11c008c114004c114008c10c004c10c008dd698208009820801181f800981f801181e800981c9baa002162325333038302d00113232533303d3040002149858dd7181f000981d1baa00215333038302e00113232533303d3040002149858dd7181f000981d1baa00216303837540026074606e6ea800458cc004dd59801181b1baa301c303637540606044606c6ea8c0e4c0d8dd5001911919299981b98160008a6103d87a800015333037302d001132323300100100622533303d00114c0103d87a80001323232533303d3371e00c6eb8c0f800c4c0c4cc1040052f5c026600a00a004607c0046082004607e0026eb8c0f0c0e4dd5001098159981d981e181c9baa0024bd70181b9baa001301c303737540024607060726072607260726072607260726072607260720022c66646002002444a66606e004298103d87a8000132325333036302b0031302a3303a0024bd70099980280280099b8000348004c0ec00cc0e4008dd6180c98199baa30193033375405a6eb4c0d8c0ccdd50008b19991800800911299981b0010a60103d87a8000132325333035302a0031302933039375000497ae01333005005001337000069000981d0019bad303800201f00314bded8c010100000103d87980003330133756603a60626ea800c06d2201066f7261636c650033710900018179baa3030003375a605c0046062004660586ea4098cc0b0dd4809198161816981700325eb80cc0acc0a0008cc0acc0a4008cc0acdd41998059bab3015302937540186eb8c0a0008dd7181480125eb80cc0a8c09c008cc0a8c0a0008cc0a8dd41998051bab3014302837540166eb8c09c008dd7181400125eb80c8cdd81815800981598160009bac302700232337606054002605460560026eb0c094004c8cdd81814800981498150009bac3028001302830243754008a666042602c60446ea800c4c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc0d8c0e40084c8c8c8c926325333037302c00113232533303c303f002132498c06400458c0f4004c0e4dd50058a99981b98168008a99981d181c9baa00b14985858c0dcdd5005191bad303800c375a606c016646eb4c0dc034dd6981a806191919191bae3039003375c606e004646eb8c0e000cdd7181b0011919bb0303a001303a303b0013758606c0206466ec0c0e4004c0e4c0e8004dd6181a0078b1bad30370013037002375a606a002606a0046eb4c0cc004c0cc008c0c4004c0c4008c94ccc0b8c0c4c0c40044cdd81818000981818188008b1bac302f001302f00232533302c302f302f001133760605c002605c605e0022c6eb0c0b4004c0b4008dd69815800981580119299981418159815800899bb0302a001302a302b001163758605200260520046eb8c09c004c08cdd50018b180080091192999811180b80089919299981398150010a4c2c6eb8c0a0004c090dd50010a999811180c000899192999813981500109924c6602e00246600c00c0022c6eb0c0a0004c090dd50010a999811180c800899192999813981500109924c6602e00246600c00c0022c6eb0c0a0004c090dd50010a999811180e0008991919192999814981600109924c660320024660100100022c6eb0c0a8004c0a8008dd6981400098121baa00215333022301b001132325333027302a002149858dd6981400098121baa00215333022301a001132325333027302a002149858dd6981400098121baa002153330223370e900600089919299981398150010a4c2c6eb8c0a0004c090dd50010b18111baa0013023302037540022c6008603e6ea800858888c94ccc080c058c084dd50008a400026eb4c094c088dd5000992999810180b18109baa00114c0103d87a8000132330010013756604c60466ea8008894ccc094004530103d87a8000132323253330253371e00e6eb8c09800c4c064cc0a4dd4000a5eb804cc014014008dd698130011814801181380099198008008021129998120008a6103d87a8000132323253330243371e00e6eb8c09400c4c060cc0a0dd3000a5eb804cc014014008dd59812801181400118130008b1810180e9baa0011632533301e00114c103d87a80001300f3301f30200014bd701bac3001301c3754600460386ea80588c07cc080c0800048c078004cc009220104000de14000007330014881040014df100000622337140040026eb8c064c058dd50008b1800980a9baa00f2301830190013758602c602e0046eb8c054004c044dd50060a5114984d958c94ccc03cc0100044c8c8c8c94ccc058c0640084c926330060012375a0022c6eb0c05c004c05c008dd7180a80098089baa00c1533300f300500115333012301137540182930b0b18079baa00b22323300100100322533301400114984c8cc00c00cc060008c00cc0580044c894ccc03cc8c8c94ccc048c020c04cdd50008991919299980a9999911119198008008029119299980e180880089919198008008041129998110008a5013253330203371e6eb8c09400801052889980180180098128009bae3021301e37540042a66603860240022660106eb0c084c078dd50011198020020008a99980e1809800899198008009bac3022301f375400644a66604200229404c94ccc07ccc018018c09000852889980180180098120008a99980e180b00089919b89375a6044002646660020026eb0c08cc09000920002225333023002100113330030033026002533302033007007302500213370000290010800980f1baa0021533301c301500113232533301e3014301f3754002264a66603e64a66604660440022a666040602c6042002294454ccc080c054c0840045280b0b1baa301030213754602060426ea80204cdc4800801899b88001003375a604660406ea80045281806980f9baa300e301f375400c6eb4c084c078dd50010a99980e180a00089919299980f180a180f9baa001132533301f3253330233022001153330203016302100114a22a666040602a604200229405858dd5180818109baa300f30213754010266e2400c0044cdc40018009bad3023302037540022940c034c07cdd51806980f9baa006375a6042603c6ea80084c8c8cc004004018894ccc088004528099299981019baf0043021302500214a2266006006002604a002602066040602e660406042603c6ea80092f5c097ae0301c3754002600a602e6ea8048dd6180d180d980d980d980d980d980d980d980d980b9baa30053017375400e60346036603660366036603660366036602e6ea8c014c05cdd50039bab301a301b301b301b301b301b301b30173754600a602e6ea801c4cc004dd6180d180d980d980b9baa30053017375400e4601664a66602e601a60306ea8004520001375a603860326ea8004c94ccc05cc034c060dd50008a6103d87a8000132330010013756603a60346ea8008894ccc070004530103d87a80001323232533301c3371e911066f7261636c6500375c603a00626020660406ea00052f5c026600a00a0046eb4c074008c080008c078004c8cc004004dd59804180c9baa00222533301b00114c103d87a80001323232533301b3371e0126eb8c07000c4c03ccc07cdd3000a5eb804cc014014008dd5980e001180f801180e8008a5022323300100100322533301b00114a2264a6660326008603c0042660060060022940c078004c8c8c8c94ccc05cc030c060dd500a0991919191919191919191919299981318148010991919191924c6464646464a66605e60640042930b1bad30300013030002375c605c002605c00c6eb8c0b0014c8c8c8c8c94ccc0b8c0c400852616375a605e002605e0046eb8c0b4004c0b401cdd718158031919191919299981698180010a4c2c6eb4c0b8004c0b8008dd7181600098160041bae302a0075333024301930253754014264646464a666056605c0042646493180a801180a0018b18160009816001181500098131baa00a16300d00b163758604e002604e0046eb0c094004c094008dd6181180098118011bae30210013021002301f001301f002301d001301937540282c60020024464a666030601a00226464a66603a60400042930b1bae301e001301a37540042a666030601c00226464a66603a604000426493198038009198030030008b1bac301e001301a37540042a666030601e00226464a66603a604000426493198038009198030030008b1bac301e001301a37540042a6660306024002264646464a66603e604400426493198048009198040040008b1bac30200013020002375a603c00260346ea800854ccc060c0440044c8c94ccc074c08000852616375a603c00260346ea800854ccc060c0400044c8c94ccc074c08000852616375a603c00260346ea800854ccc060cdc3a401800226464a66603a60400042930b1bae301e001301a37540042c60306ea800494ccc054c028c058dd5000899191919299980e180f80109924c64a666034601e0022a66603a60386ea8010526161533301a301000113232533301f3022002149858dd69810000980e1baa0041533301a30110011533301d301c37540082930b0b180d1baa0031632533301c301b00115333019300f301a00114a22a666032601c603400229405858dd5180e800980e801180d800980b9baa0011622323300100100322533301a00114984c8cc00c00cc078008c00cc070004dd7180b980a1baa00116300130133754600260266ea8c94ccc048c020c04cdd500089929998099804180a1baa00113004301537546030602a6ea800458cc88c8cc00400400c894ccc064004530103d87a80001323253330183375e601060346ea80080144c030cc0700092f5c0266008008002603a00460360026eb0c008c050dd51801180a1baa0043017301437540022c600460266ea800c8c0580048c054c058004526136563012300f37540126e952000370e90001b8748008dc3a40086e1d200a370e90041b8748018dd2a40046eb80055cd2ab9d5573caae7d5d02ba15745", - "hash": "856781e12214a080871d3c4b1ac45cf521c4fb011fbc4252030cf5c9" + "compiledCode": "5915fe010000332323232323232232225323232323232323233300d3001300e375401226464a66601ea66601e600660206ea80304c8c8c8c8c94ccc050c020c054dd5000899191919191919299980d9807980e1baa001132533301c3375e6008603c6ea8c010c078dd5000980b998101ba901a4bd70099299980e98091998009bab300b301f375400401200c264a66603c6028603e6ea80044c8c8c8c8c8c8c8c8c8c8c8cdc42400060546ea8c0acc8ccc004004dd6180898161baa3012302c375404c97bdb1810100000103d87a8000222533302f00210011333003003303200232323232533303030240011337606ea000cccc0c0009300103d87a80004c0103d87980001533303030250011325333031302530323754002264a666064604c60666ea80044c8c8c94ccc0d4c0a4c0d8dd500089919191919299981d19baf3022303c3754604460786ea8038c0d4cc0f8dd481325eb804c94ccc0ecc0bcc0f0dd500089919299981e99baf302b303f375400460846086608660866086608660866086607e6ea8c094c0fcdd501c8a99981e99b8f375c6048607e6ea80080b454ccc0f4cdd79812981f9baa0020051533303d3375e6e9c05cc108c10cc10cc10cc0fcdd50010a99981e99baf374e02c60846086608660866086607e6ea800854ccc0f4cdd79ba70153006303f3754004266ec0dd419b8001048008ccc0f403d30103d87a80004c0103d879800016161616161632533303d3031303e37540042646464646464646464646464a666098609e00426464646464931919191919299982a982c0010a4c2c6eb4c158004c158008dd7182a000982a0031bae3052005323232323253330543057002149858dd6982a800982a8011bae30530013053007375c60a200c6464646464a6660a660ac0042930b1bad30540013054002375c60a400260a40106eb8c14001d4ccc128c0f8c12cdd50050991919192999828982a0010991924c602600460240062c60a400260a400460a000260986ea802858c0a402c58dd6182680098268011bac304b001304b0023758609200260920046eb8c11c004c11c008c114004c114008c10c004c0fcdd50010b1299981e9818981f1baa00113232323253330443047002132498c94ccc108c0d800454ccc114c110dd50020a4c2c2a666084606e00226464a66608e60940042930b1bad3048001304437540082a66608460700022a66608a60886ea80105261616304237540062c64a66608860860022a666082606c6084002294454ccc104c0d4c1080045280b0b1baa304500130450023043001303f37540022c6080607a6ea800458cc01cdd59804181e1baa3022303c375406c01c2c6032002600260746ea800c8c0f4c0f8c0f8c0f8c0f8c0f8004c94ccc0dcc0acc0e0dd500109919191919191919191919192999823182480109919191924c64a66608e607600226464a666098609e00426493192999825181f00089919299982798290010a4c2c6eb8c140004c130dd50010a999825181f80089919299982798290010a4c2c6eb8c140004c130dd50010b18251baa00116304d0013049375400e2a66608e6078002264646464a66609c60a200426464931919191919299982a182b8010a4c2c6eb4c154004c154008dd7182980098298019bae3051002323232323253330533056002149858dd6982a000982a0011bae30520013052004375c60a00062c6eb0c13c004c13c008dd6182680098249baa00715333047303d00113232533304c304f002132498c8c8c8c8c8c8c8c94ccc150c15c00852616375a60aa00260aa0046eb8c14c004c14c00cdd7182880119191919192999829982b0010a4c2c6eb4c150004c150008dd7182900098290019bae3050002375860980046eb0c12800458c94ccc130c13cc13c0044cdd81827000982718278008b1bac304d0013049375400e2a66608e608000226464a666098609e0042649319191919192999828982a0010a4c2c6eb4c148004c148008dd7182800098280011bae304e001163758609a00260926ea801c54ccc11cc0fc0044c8c94ccc130c13c0084c926323232323232323253330543057002149858dd6982a800982a8011bae30530013053003375c60a20046464646464a6660a660ac0042930b1bad30540013054002375c60a400260a40066eb8c140008dd618260011bac304a0011632533304c304f304f001133760609c002609c609e0022c6eb0c134004c124dd50038a999823981f000899192999826182780109924c646eb8c130008dd718250008b19299982618279827800899bb0304e001304e304f001163758609a00260926ea801c58c11cdd5003192999823181d000899191919299982698280010991924c64a66609860800022a66609e609c6ea800c526161533304c30410011323253330513054002149858dd7182900098271baa0031533304c30420011323253330513054002149858c148004c138dd50018b18261baa002533304a303e304b3754006264646464a6660a260a80042646493192999828182200089919299982a982c00109924c64a6660a6608e00226464a6660b060b600426493180f8008b182c800982a9baa0021533305330480011323232323232533305c305f002149858dd6982e800982e8011bad305b001305b002375a60b200260aa6ea800858c14cdd50008b182b00098291baa00315333050304500115333053305237540062930b0b18281baa002301800316305200130520023050001304c37540062c2c609c002609c004609800260906ea802054ccc118c0ec00454ccc124c120dd50040a4c2c2c608c6ea801cc090028c94ccc110c0e00044c8c94ccc124c13000852616375c6094002608c6ea803054ccc110c0e400454ccc11cc118dd50060a4c2c2c60886ea802c58c11c004c11c008c114004c114008c10c004c10c008dd698208009820801181f800981f801181e800981c9baa002162325333038302c00113232533303d3040002149858dd7181f000981d1baa00215333038302d00113232533303d3040002149858dd7181f000981d1baa00216303837540026074606e6ea800458cc004dd59801181b1baa301c303637540606044606c6ea8c0e4c0d8dd5001911919299981b98158008a6103d87a800015333037302c001132323300100100622533303d00114c0103d87a80001323232533303d3371e00c6eb8c0f800c4c0dccc1040052f5c026600a00a004607c0046082004607e0026eb8c0f0c0e4dd5001098189981d981e181c9baa0024bd70181b9baa001301c303737540024607060726072607260726072607260726072607260720022c66646002002444a66606e004298103d87a8000132325333036302a003130303303a0024bd70099980280280099b8000348004c0ec00cc0e4008dd6180c98199baa30193033375405a6eb4c0d8c0ccdd50008b19991800800911299981b0010a60103d87a800013232533303530290031302f33039375000497ae01333005005001337000069000981d0019bad303800201f00314bded8c010100000103d87980003330133756603a60626ea800c06d2201066f7261636c650033710900018179baa3030003375a605c0046062004660586ea4098cc0b0dd4809198161816981700325eb80cc0acc0a0008cc0acc0a4008cc0acdd41998059bab3015302937540186eb8c0a0008dd7181480125eb80cc0a8c09c008cc0a8c0a0008cc0a8dd41998051bab3014302837540166eb8c09c008dd7181400125eb80c8cdd81815800981598160009bac302700232337606054002605460560026eb0c094004c8cdd81814800981498150009bac3028001302830243754008a666042602a60446ea800c4c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc0d0c0dc0084c8c9263253330333027001132325333038303b002132498c05400458c0e4004c0d4dd50038a99981998140008a99981b181a9baa00714985858c0ccdd5003191919191bae3037003375c606a004646eb8c0d800cdd7181a0011919bb03038001303830390013758606801c6466ec0c0dc004c0dcc0e0004dd618190068b1bad30350013035002375a60660026066004606200260620046eb4c0bc004c0bc008dd6981680098168011bad302b001302b002325333028302b302b0011337606054002605460560022c6eb0c0a4004c0a4008dd7181380098119baa003163001001223253330223016001132325333027302a002149858dd7181400098121baa002153330223017001132325333027302a002132498cc05c0048cc01801800458dd6181400098121baa002153330223018001132325333027302a002132498cc05c0048cc01801800458dd6181400098121baa00215333022301b0011323232325333029302c002132498cc0640048cc02002000458dd6181500098150011bad3028001302437540042a666044603400226464a66604e60540042930b1bad3028001302437540042a666044603200226464a66604e60540042930b1bad3028001302437540042a66604466e1d200c001132325333027302a002149858dd7181400098121baa0021630223754002604660406ea800458c010c07cdd50010b111192999810180a98109baa0011480004dd6981298111baa0013253330203015302137540022980103d87a8000132330010013756604c60466ea8008894ccc094004530103d87a8000132323253330253371e00e6eb8c09800c4c07ccc0a4dd4000a5eb804cc014014008dd698130011814801181380099198008008021129998120008a6103d87a8000132323253330243371e00e6eb8c09400c4c078cc0a0dd3000a5eb804cc014014008dd59812801181400118130008b1810180e9baa0011632533301e00114c103d87a8000130153301f30200014bd701bac3001301c3754600460386ea80588c07cc080c0800048c078004cc009220104000de14000007330014881040014df100000622337140040026eb8c064c058dd50008b1800980a9baa00f2301830190013758602c602e0046eb8c054004c044dd50060a5114984d958c94ccc03cc00c0044c8c8c8c94ccc058c0640084c926330060012375a0022c6eb0c05c004c05c008dd7180a80098089baa00c1533300f300400115333012301137540182930b0b18079baa00b22323300100100322533301400114984c8cc00c00cc060008c00cc0580044cc8894ccc040c8c8c94ccc04cc020c050dd500089919299980a9999911119198008008029119299980e180800089919198008008041129998110008a5013253330203371e6eb8c09400801052889980180180098128009bae3021301e37540042a66603860220022660106eb0c084c078dd50011198020020008a99980e1809000899198008009bac3022301f375400644a66604200229404c94ccc07ccc018018c09000852889980180180098120008a99980e180a80089919b89375a6044002646660020026eb0c08cc09000920002225333023002100113330030033026002533302033007007302500213370000290010800980f1baa0021533301c301400113232533301e3013301f3754002264a66603e64a66604660440022a666040602a6042002294454ccc080c050c0840045280b0b1baa300f30213754601e60426ea80204cdc4800801899b88001003375a604660406ea80045281806180f9baa300d301f375400c6eb4c084c078dd50010a99980e180980089919299980f1809980f9baa001132533301f3253330233022001153330203015302100114a22a6660406028604200229405858dd5180798109baa300e30213754010266e2400c0044cdc40018009bad3023302037540022940c030c07cdd51806180f9baa006375a6042603c6ea80084c8c8cc004004018894ccc088004528099299981019baf0043021302500214a2266006006002604a002602c66040602e660406042603c6ea80092f5c097ae0301c37540026008602e6ea8048dd6180d180d980d980d980d980d980d980d980d980b9baa30043017375400c60346036603660366036603660366036602e6ea8c010c05cdd50031bab301a301b301b301b301b301b301b301737546008602e6ea80184cc004dd6180d180d980d980b9baa30043017375400c4601464a66602e601860306ea8004520001375a603860326ea8004c94ccc05cc030c060dd50008a6103d87a8000132330010013756603a60346ea8008894ccc070004530103d87a80001323232533301c3371e911066f7261636c6500375c603a0062602c660406ea00052f5c026600a00a0046eb4c074008c080008c078004c8cc004004dd59803980c9baa00222533301b00114c103d87a80001323232533301b3371e0106eb8c07000c4c054cc07cdd3000a5eb804cc014014008dd5980e001180f801180e8008a5022323300100100322533301b00114a2264a6660326008603c0042660060060022940c078004dd7180c180a9baa00116300130143754600260286ea8c94ccc04cc020c050dd5000899299980a1804180a9baa00113004301637546032602c6ea800458cc88c8cc00400400c894ccc0680045300103d87a80001323253330193375e601060366ea80080144c04ccc0740092f5c0266008008002603c00460380026eb0c008c054dd51801180a9baa0043018301537540022c600460286ea800c8c05c0048c058c05c0045261365632323232533301130053012375401c2646464646464646464646464a666040604600426464646464931919191919299981498160010a4c2c6eb4c0a8004c0a8008dd7181400098140031bae302600532323232325333028302b002149858dd6981480098148011bae30270013027007375c604a00c6464646464a66604e60540042930b1bad30280013028002375c604c002604c0106eb8c09001d4ccc078c048c07cdd5005099191919299981298140010991924c602a00460280062c604c002604c004604800260406ea802858c03402c58dd6181080098108011bac301f001301f0023758603a002603a0046eb8c06c004c06c008c064004c064008c05c004c04cdd50070b180080091192999809180300089919299980b980d0010a4c2c6eb8c060004c050dd50010a999809180380089919299980b980d00109924c6600e00246600c00c0022c6eb0c060004c050dd50010a999809180400089919299980b980d00109924c6600e00246600c00c0022c6eb0c060004c050dd50010a9998091805800899191919299980c980e00109924c660120024660100100022c6eb0c068004c068008dd6980c000980a1baa00215333012300a001132325333017301a002149858dd6980c000980a1baa002153330123009001132325333017301a002149858dd6980c000980a1baa002153330123370e900600089919299980b980d0010a4c2c6eb8c060004c050dd50010b18091baa0012533300f300330103754002264646464a66602c60320042649319299980a18040008a99980b980b1baa00414985854ccc050c0240044c8c94ccc064c07000852616375a6034002602c6ea801054ccc050c02800454ccc05cc058dd50020a4c2c2c60286ea800c58c94ccc058c05400454ccc04cc020c0500045288a9998099803980a0008a5016163754602e002602e004602a00260226ea80045888c8cc00400400c894ccc050004526132330030033018002300330160013012300f37540126e1d2000370e90011b8748010dc3a40146e1d2008370e90031ba548000dd2a40046eb80055cd2ab9d5573caae7d5d02ba157449811e581cbd4e886ee59548d9d6a2be480a4b468da8e8177f52ba6ce05b7b24a30001", + "hash": "e2fe2d97baeb7dbc39da2c3292e346806d28f37eb0a980e46528e61e" }, { "title": "oracle.mint", @@ -45,16 +54,8 @@ "$ref": "#/definitions/types~1oracle~1OracleRedeemer" } }, - "parameters": [ - { - "title": "pool_script_hash", - "schema": { - "$ref": "#/definitions/ByteArray" - } - } - ], - "compiledCode": "59162d01000032323232323232232225323232323232323233300d3002300e375401226464a66601ea66601e600860206ea80304c8c8c8c8c94ccc050c024c054dd5000899191919191919299980d9808180e1baa001132533301c3375e6008603c6ea8c010c078dd5000980b998101ba901a4bd70099299980e98099998009bab300b301f375400401200c264a66603c602a603e6ea80044c8c8c8c8c8c8c8c8c8c8c8cdc42400060546ea8c0acc8ccc004004dd6180898161baa3012302c375404c97bdb18010100000103d87a8000222533302f00210011333003003303200232323232533303030250011337606ea000cccc0c0009300103d87a80004c0103d87980001533303030260011325333031302630323754002264a666064604e60666ea80044c8c8c94ccc0d4c0a8c0d8dd500089919191919299981d19baf3022303c3754604460786ea8038c0d4cc0f8dd481325eb804c94ccc0ecc0c0c0f0dd500089919299981e99baf302b303f375400460846086608660866086608660866086607e6ea8c094c0fcdd501c8a99981e99b8f375c6048607e6ea80080b454ccc0f4cdd79812981f9baa0020051533303d3375e6e9c05cc108c10cc10cc10cc0fcdd50010a99981e99baf374e02c60846086608660866086607e6ea800854ccc0f4cdd79ba70153006303f3754004266ec0dd419b8001048008ccc0f403d30103d87a80004c0103d879800016161616161632533303d3032303e37540042646464646464646464646464a666098609e00426464646464931919191919299982a982c0010a4c2c6eb4c158004c158008dd7182a000982a0031bae3052005323232323253330543057002149858dd6982a800982a8011bae30530013053007375c60a200c6464646464a6660a660ac0042930b1bad30540013054002375c60a400260a40106eb8c14001d4ccc128c0fcc12cdd50050991919192999828982a0010991924c602600460240062c60a400260a400460a000260986ea802858c0a402c58dd6182680098268011bac304b001304b0023758609200260920046eb8c11c004c11c008c114004c114008c10c004c0fcdd50010b1299981e9819181f1baa00113232323253330443047002132498c94ccc108c0dc00454ccc114c110dd50020a4c2c2a666084607000226464a66608e60940042930b1bad3048001304437540082a66608460720022a66608a60886ea80105261616304237540062c64a66608860860022a666082606e6084002294454ccc104c0d8c1080045280b0b1baa304500130450023043001303f37540022c6080607a6ea800458cc01cdd59804181e1baa3022303c375406c01c2c6032002600260746ea800c8c0f4c0f8c0f8c0f8c0f8c0f8004c94ccc0dcc0b0c0e0dd500109919191919191919191919192999823182480109919191924c64a66608e607800226464a666098609e00426493192999825181f80089919299982798290010a4c2c6eb8c140004c130dd50010a999825182000089919299982798290010a4c2c6eb8c140004c130dd50010b18251baa00116304d0013049375400e2a66608e607a002264646464a66609c60a200426464931919191919299982a182b8010a4c2c6eb4c154004c154008dd7182980098298019bae3051002323232323253330533056002149858dd6982a000982a0011bae30520013052004375c60a00062c6eb0c13c004c13c008dd6182680098249baa00715333047303e00113232533304c304f002132498c8c8c8c8c8c8c8c94ccc150c15c00852616375a60aa00260aa0046eb8c14c004c14c00cdd7182880119191919192999829982b0010a4c2c6eb4c150004c150008dd7182900098290019bae3050002375860980046eb0c12800458c94ccc130c13cc13c0044cdd81827000982718278008b1bac304d0013049375400e2a66608e608200226464a666098609e0042649319191919192999828982a0010a4c2c6eb4c148004c148008dd7182800098280011bae304e001163758609a00260926ea801c54ccc11cc1000044c8c94ccc130c13c0084c926323232323232323253330543057002149858dd6982a800982a8011bae30530013053003375c60a20046464646464a6660a660ac0042930b1bad30540013054002375c60a400260a40066eb8c140008dd618260011bac304a0011632533304c304f304f001133760609c002609c609e0022c6eb0c134004c124dd50038a999823981f800899192999826182780109924c646eb8c130008dd718250008b19299982618279827800899bb0304e001304e304f001163758609a00260926ea801c58c11cdd5003192999823181d800899191919299982698280010991924c64a66609860820022a66609e609c6ea800c526161533304c30420011323253330513054002149858dd7182900098271baa0031533304c30430011323253330513054002149858c148004c138dd50018b18261baa002533304a303f304b3754006264646464a6660a260a80042646493192999828182280089919299982a982c00109924c64a6660a6609000226464a6660b060b600426493180f8008b182c800982a9baa0021533305330490011323232323232533305c305f002149858dd6982e800982e8011bad305b001305b002375a60b200260aa6ea800858c14cdd50008b182b00098291baa00315333050304600115333053305237540062930b0b18281baa002301800316305200130520023050001304c37540062c2c609c002609c004609800260906ea802054ccc118c0f000454ccc124c120dd50040a4c2c2c608c6ea801cc090028c94ccc110c0e40044c8c94ccc124c13000852616375c6094002608c6ea803054ccc110c0e800454ccc11cc118dd50060a4c2c2c60886ea802c58c11c004c11c008c114004c114008c10c004c10c008dd698208009820801181f800981f801181e800981c9baa002162325333038302d00113232533303d3040002149858dd7181f000981d1baa00215333038302e00113232533303d3040002149858dd7181f000981d1baa00216303837540026074606e6ea800458cc004dd59801181b1baa301c303637540606044606c6ea8c0e4c0d8dd5001911919299981b98160008a6103d87a800015333037302d001132323300100100622533303d00114c0103d87a80001323232533303d3371e00c6eb8c0f800c4c0c4cc1040052f5c026600a00a004607c0046082004607e0026eb8c0f0c0e4dd5001098159981d981e181c9baa0024bd70181b9baa001301c303737540024607060726072607260726072607260726072607260720022c66646002002444a66606e004298103d87a8000132325333036302b0031302a3303a0024bd70099980280280099b8000348004c0ec00cc0e4008dd6180c98199baa30193033375405a6eb4c0d8c0ccdd50008b19991800800911299981b0010a60103d87a8000132325333035302a0031302933039375000497ae01333005005001337000069000981d0019bad303800201f00314bded8c010100000103d87980003330133756603a60626ea800c06d2201066f7261636c650033710900018179baa3030003375a605c0046062004660586ea4098cc0b0dd4809198161816981700325eb80cc0acc0a0008cc0acc0a4008cc0acdd41998059bab3015302937540186eb8c0a0008dd7181480125eb80cc0a8c09c008cc0a8c0a0008cc0a8dd41998051bab3014302837540166eb8c09c008dd7181400125eb80c8cdd81815800981598160009bac302700232337606054002605460560026eb0c094004c8cdd81814800981498150009bac3028001302830243754008a666042602c60446ea800c4c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc0d8c0e40084c8c8c8c926325333037302c00113232533303c303f002132498c06400458c0f4004c0e4dd50058a99981b98168008a99981d181c9baa00b14985858c0dcdd5005191bad303800c375a606c016646eb4c0dc034dd6981a806191919191bae3039003375c606e004646eb8c0e000cdd7181b0011919bb0303a001303a303b0013758606c0206466ec0c0e4004c0e4c0e8004dd6181a0078b1bad30370013037002375a606a002606a0046eb4c0cc004c0cc008c0c4004c0c4008c94ccc0b8c0c4c0c40044cdd81818000981818188008b1bac302f001302f00232533302c302f302f001133760605c002605c605e0022c6eb0c0b4004c0b4008dd69815800981580119299981418159815800899bb0302a001302a302b001163758605200260520046eb8c09c004c08cdd50018b180080091192999811180b80089919299981398150010a4c2c6eb8c0a0004c090dd50010a999811180c000899192999813981500109924c6602e00246600c00c0022c6eb0c0a0004c090dd50010a999811180c800899192999813981500109924c6602e00246600c00c0022c6eb0c0a0004c090dd50010a999811180e0008991919192999814981600109924c660320024660100100022c6eb0c0a8004c0a8008dd6981400098121baa00215333022301b001132325333027302a002149858dd6981400098121baa00215333022301a001132325333027302a002149858dd6981400098121baa002153330223370e900600089919299981398150010a4c2c6eb8c0a0004c090dd50010b18111baa0013023302037540022c6008603e6ea800858888c94ccc080c058c084dd50008a400026eb4c094c088dd5000992999810180b18109baa00114c0103d87a8000132330010013756604c60466ea8008894ccc094004530103d87a8000132323253330253371e00e6eb8c09800c4c064cc0a4dd4000a5eb804cc014014008dd698130011814801181380099198008008021129998120008a6103d87a8000132323253330243371e00e6eb8c09400c4c060cc0a0dd3000a5eb804cc014014008dd59812801181400118130008b1810180e9baa0011632533301e00114c103d87a80001300f3301f30200014bd701bac3001301c3754600460386ea80588c07cc080c0800048c078004cc009220104000de14000007330014881040014df100000622337140040026eb8c064c058dd50008b1800980a9baa00f2301830190013758602c602e0046eb8c054004c044dd50060a5114984d958c94ccc03cc0100044c8c8c8c94ccc058c0640084c926330060012375a0022c6eb0c05c004c05c008dd7180a80098089baa00c1533300f300500115333012301137540182930b0b18079baa00b22323300100100322533301400114984c8cc00c00cc060008c00cc0580044c894ccc03cc8c8c94ccc048c020c04cdd50008991919299980a9999911119198008008029119299980e180880089919198008008041129998110008a5013253330203371e6eb8c09400801052889980180180098128009bae3021301e37540042a66603860240022660106eb0c084c078dd50011198020020008a99980e1809800899198008009bac3022301f375400644a66604200229404c94ccc07ccc018018c09000852889980180180098120008a99980e180b00089919b89375a6044002646660020026eb0c08cc09000920002225333023002100113330030033026002533302033007007302500213370000290010800980f1baa0021533301c301500113232533301e3014301f3754002264a66603e64a66604660440022a666040602c6042002294454ccc080c054c0840045280b0b1baa301030213754602060426ea80204cdc4800801899b88001003375a604660406ea80045281806980f9baa300e301f375400c6eb4c084c078dd50010a99980e180a00089919299980f180a180f9baa001132533301f3253330233022001153330203016302100114a22a666040602a604200229405858dd5180818109baa300f30213754010266e2400c0044cdc40018009bad3023302037540022940c034c07cdd51806980f9baa006375a6042603c6ea80084c8c8cc004004018894ccc088004528099299981019baf0043021302500214a2266006006002604a002602066040602e660406042603c6ea80092f5c097ae0301c3754002600a602e6ea8048dd6180d180d980d980d980d980d980d980d980d980b9baa30053017375400e60346036603660366036603660366036602e6ea8c014c05cdd50039bab301a301b301b301b301b301b301b30173754600a602e6ea801c4cc004dd6180d180d980d980b9baa30053017375400e4601664a66602e601a60306ea8004520001375a603860326ea8004c94ccc05cc034c060dd50008a6103d87a8000132330010013756603a60346ea8008894ccc070004530103d87a80001323232533301c3371e911066f7261636c6500375c603a00626020660406ea00052f5c026600a00a0046eb4c074008c080008c078004c8cc004004dd59804180c9baa00222533301b00114c103d87a80001323232533301b3371e0126eb8c07000c4c03ccc07cdd3000a5eb804cc014014008dd5980e001180f801180e8008a5022323300100100322533301b00114a2264a6660326008603c0042660060060022940c078004c8c8c8c94ccc05cc030c060dd500a0991919191919191919191919299981318148010991919191924c6464646464a66605e60640042930b1bad30300013030002375c605c002605c00c6eb8c0b0014c8c8c8c8c94ccc0b8c0c400852616375a605e002605e0046eb8c0b4004c0b401cdd718158031919191919299981698180010a4c2c6eb4c0b8004c0b8008dd7181600098160041bae302a0075333024301930253754014264646464a666056605c0042646493180a801180a0018b18160009816001181500098131baa00a16300d00b163758604e002604e0046eb0c094004c094008dd6181180098118011bae30210013021002301f001301f002301d001301937540282c60020024464a666030601a00226464a66603a60400042930b1bae301e001301a37540042a666030601c00226464a66603a604000426493198038009198030030008b1bac301e001301a37540042a666030601e00226464a66603a604000426493198038009198030030008b1bac301e001301a37540042a6660306024002264646464a66603e604400426493198048009198040040008b1bac30200013020002375a603c00260346ea800854ccc060c0440044c8c94ccc074c08000852616375a603c00260346ea800854ccc060c0400044c8c94ccc074c08000852616375a603c00260346ea800854ccc060cdc3a401800226464a66603a60400042930b1bae301e001301a37540042c60306ea800494ccc054c028c058dd5000899191919299980e180f80109924c64a666034601e0022a66603a60386ea8010526161533301a301000113232533301f3022002149858dd69810000980e1baa0041533301a30110011533301d301c37540082930b0b180d1baa0031632533301c301b00115333019300f301a00114a22a666032601c603400229405858dd5180e800980e801180d800980b9baa0011622323300100100322533301a00114984c8cc00c00cc078008c00cc070004dd7180b980a1baa00116300130133754600260266ea8c94ccc048c020c04cdd500089929998099804180a1baa00113004301537546030602a6ea800458cc88c8cc00400400c894ccc064004530103d87a80001323253330183375e601060346ea80080144c030cc0700092f5c0266008008002603a00460360026eb0c008c050dd51801180a1baa0043017301437540022c600460266ea800c8c0580048c054c058004526136563012300f37540126e952000370e90001b8748008dc3a40086e1d200a370e90041b8748018dd2a40046eb80055cd2ab9d5573caae7d5d02ba15745", - "hash": "856781e12214a080871d3c4b1ac45cf521c4fb011fbc4252030cf5c9" + "compiledCode": "5915fe010000332323232323232232225323232323232323233300d3001300e375401226464a66601ea66601e600660206ea80304c8c8c8c8c94ccc050c020c054dd5000899191919191919299980d9807980e1baa001132533301c3375e6008603c6ea8c010c078dd5000980b998101ba901a4bd70099299980e98091998009bab300b301f375400401200c264a66603c6028603e6ea80044c8c8c8c8c8c8c8c8c8c8c8cdc42400060546ea8c0acc8ccc004004dd6180898161baa3012302c375404c97bdb1810100000103d87a8000222533302f00210011333003003303200232323232533303030240011337606ea000cccc0c0009300103d87a80004c0103d87980001533303030250011325333031302530323754002264a666064604c60666ea80044c8c8c94ccc0d4c0a4c0d8dd500089919191919299981d19baf3022303c3754604460786ea8038c0d4cc0f8dd481325eb804c94ccc0ecc0bcc0f0dd500089919299981e99baf302b303f375400460846086608660866086608660866086607e6ea8c094c0fcdd501c8a99981e99b8f375c6048607e6ea80080b454ccc0f4cdd79812981f9baa0020051533303d3375e6e9c05cc108c10cc10cc10cc0fcdd50010a99981e99baf374e02c60846086608660866086607e6ea800854ccc0f4cdd79ba70153006303f3754004266ec0dd419b8001048008ccc0f403d30103d87a80004c0103d879800016161616161632533303d3031303e37540042646464646464646464646464a666098609e00426464646464931919191919299982a982c0010a4c2c6eb4c158004c158008dd7182a000982a0031bae3052005323232323253330543057002149858dd6982a800982a8011bae30530013053007375c60a200c6464646464a6660a660ac0042930b1bad30540013054002375c60a400260a40106eb8c14001d4ccc128c0f8c12cdd50050991919192999828982a0010991924c602600460240062c60a400260a400460a000260986ea802858c0a402c58dd6182680098268011bac304b001304b0023758609200260920046eb8c11c004c11c008c114004c114008c10c004c0fcdd50010b1299981e9818981f1baa00113232323253330443047002132498c94ccc108c0d800454ccc114c110dd50020a4c2c2a666084606e00226464a66608e60940042930b1bad3048001304437540082a66608460700022a66608a60886ea80105261616304237540062c64a66608860860022a666082606c6084002294454ccc104c0d4c1080045280b0b1baa304500130450023043001303f37540022c6080607a6ea800458cc01cdd59804181e1baa3022303c375406c01c2c6032002600260746ea800c8c0f4c0f8c0f8c0f8c0f8c0f8004c94ccc0dcc0acc0e0dd500109919191919191919191919192999823182480109919191924c64a66608e607600226464a666098609e00426493192999825181f00089919299982798290010a4c2c6eb8c140004c130dd50010a999825181f80089919299982798290010a4c2c6eb8c140004c130dd50010b18251baa00116304d0013049375400e2a66608e6078002264646464a66609c60a200426464931919191919299982a182b8010a4c2c6eb4c154004c154008dd7182980098298019bae3051002323232323253330533056002149858dd6982a000982a0011bae30520013052004375c60a00062c6eb0c13c004c13c008dd6182680098249baa00715333047303d00113232533304c304f002132498c8c8c8c8c8c8c8c94ccc150c15c00852616375a60aa00260aa0046eb8c14c004c14c00cdd7182880119191919192999829982b0010a4c2c6eb4c150004c150008dd7182900098290019bae3050002375860980046eb0c12800458c94ccc130c13cc13c0044cdd81827000982718278008b1bac304d0013049375400e2a66608e608000226464a666098609e0042649319191919192999828982a0010a4c2c6eb4c148004c148008dd7182800098280011bae304e001163758609a00260926ea801c54ccc11cc0fc0044c8c94ccc130c13c0084c926323232323232323253330543057002149858dd6982a800982a8011bae30530013053003375c60a20046464646464a6660a660ac0042930b1bad30540013054002375c60a400260a40066eb8c140008dd618260011bac304a0011632533304c304f304f001133760609c002609c609e0022c6eb0c134004c124dd50038a999823981f000899192999826182780109924c646eb8c130008dd718250008b19299982618279827800899bb0304e001304e304f001163758609a00260926ea801c58c11cdd5003192999823181d000899191919299982698280010991924c64a66609860800022a66609e609c6ea800c526161533304c30410011323253330513054002149858dd7182900098271baa0031533304c30420011323253330513054002149858c148004c138dd50018b18261baa002533304a303e304b3754006264646464a6660a260a80042646493192999828182200089919299982a982c00109924c64a6660a6608e00226464a6660b060b600426493180f8008b182c800982a9baa0021533305330480011323232323232533305c305f002149858dd6982e800982e8011bad305b001305b002375a60b200260aa6ea800858c14cdd50008b182b00098291baa00315333050304500115333053305237540062930b0b18281baa002301800316305200130520023050001304c37540062c2c609c002609c004609800260906ea802054ccc118c0ec00454ccc124c120dd50040a4c2c2c608c6ea801cc090028c94ccc110c0e00044c8c94ccc124c13000852616375c6094002608c6ea803054ccc110c0e400454ccc11cc118dd50060a4c2c2c60886ea802c58c11c004c11c008c114004c114008c10c004c10c008dd698208009820801181f800981f801181e800981c9baa002162325333038302c00113232533303d3040002149858dd7181f000981d1baa00215333038302d00113232533303d3040002149858dd7181f000981d1baa00216303837540026074606e6ea800458cc004dd59801181b1baa301c303637540606044606c6ea8c0e4c0d8dd5001911919299981b98158008a6103d87a800015333037302c001132323300100100622533303d00114c0103d87a80001323232533303d3371e00c6eb8c0f800c4c0dccc1040052f5c026600a00a004607c0046082004607e0026eb8c0f0c0e4dd5001098189981d981e181c9baa0024bd70181b9baa001301c303737540024607060726072607260726072607260726072607260720022c66646002002444a66606e004298103d87a8000132325333036302a003130303303a0024bd70099980280280099b8000348004c0ec00cc0e4008dd6180c98199baa30193033375405a6eb4c0d8c0ccdd50008b19991800800911299981b0010a60103d87a800013232533303530290031302f33039375000497ae01333005005001337000069000981d0019bad303800201f00314bded8c010100000103d87980003330133756603a60626ea800c06d2201066f7261636c650033710900018179baa3030003375a605c0046062004660586ea4098cc0b0dd4809198161816981700325eb80cc0acc0a0008cc0acc0a4008cc0acdd41998059bab3015302937540186eb8c0a0008dd7181480125eb80cc0a8c09c008cc0a8c0a0008cc0a8dd41998051bab3014302837540166eb8c09c008dd7181400125eb80c8cdd81815800981598160009bac302700232337606054002605460560026eb0c094004c8cdd81814800981498150009bac3028001302830243754008a666042602a60446ea800c4c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc0d0c0dc0084c8c9263253330333027001132325333038303b002132498c05400458c0e4004c0d4dd50038a99981998140008a99981b181a9baa00714985858c0ccdd5003191919191bae3037003375c606a004646eb8c0d800cdd7181a0011919bb03038001303830390013758606801c6466ec0c0dc004c0dcc0e0004dd618190068b1bad30350013035002375a60660026066004606200260620046eb4c0bc004c0bc008dd6981680098168011bad302b001302b002325333028302b302b0011337606054002605460560022c6eb0c0a4004c0a4008dd7181380098119baa003163001001223253330223016001132325333027302a002149858dd7181400098121baa002153330223017001132325333027302a002132498cc05c0048cc01801800458dd6181400098121baa002153330223018001132325333027302a002132498cc05c0048cc01801800458dd6181400098121baa00215333022301b0011323232325333029302c002132498cc0640048cc02002000458dd6181500098150011bad3028001302437540042a666044603400226464a66604e60540042930b1bad3028001302437540042a666044603200226464a66604e60540042930b1bad3028001302437540042a66604466e1d200c001132325333027302a002149858dd7181400098121baa0021630223754002604660406ea800458c010c07cdd50010b111192999810180a98109baa0011480004dd6981298111baa0013253330203015302137540022980103d87a8000132330010013756604c60466ea8008894ccc094004530103d87a8000132323253330253371e00e6eb8c09800c4c07ccc0a4dd4000a5eb804cc014014008dd698130011814801181380099198008008021129998120008a6103d87a8000132323253330243371e00e6eb8c09400c4c078cc0a0dd3000a5eb804cc014014008dd59812801181400118130008b1810180e9baa0011632533301e00114c103d87a8000130153301f30200014bd701bac3001301c3754600460386ea80588c07cc080c0800048c078004cc009220104000de14000007330014881040014df100000622337140040026eb8c064c058dd50008b1800980a9baa00f2301830190013758602c602e0046eb8c054004c044dd50060a5114984d958c94ccc03cc00c0044c8c8c8c94ccc058c0640084c926330060012375a0022c6eb0c05c004c05c008dd7180a80098089baa00c1533300f300400115333012301137540182930b0b18079baa00b22323300100100322533301400114984c8cc00c00cc060008c00cc0580044cc8894ccc040c8c8c94ccc04cc020c050dd500089919299980a9999911119198008008029119299980e180800089919198008008041129998110008a5013253330203371e6eb8c09400801052889980180180098128009bae3021301e37540042a66603860220022660106eb0c084c078dd50011198020020008a99980e1809000899198008009bac3022301f375400644a66604200229404c94ccc07ccc018018c09000852889980180180098120008a99980e180a80089919b89375a6044002646660020026eb0c08cc09000920002225333023002100113330030033026002533302033007007302500213370000290010800980f1baa0021533301c301400113232533301e3013301f3754002264a66603e64a66604660440022a666040602a6042002294454ccc080c050c0840045280b0b1baa300f30213754601e60426ea80204cdc4800801899b88001003375a604660406ea80045281806180f9baa300d301f375400c6eb4c084c078dd50010a99980e180980089919299980f1809980f9baa001132533301f3253330233022001153330203015302100114a22a6660406028604200229405858dd5180798109baa300e30213754010266e2400c0044cdc40018009bad3023302037540022940c030c07cdd51806180f9baa006375a6042603c6ea80084c8c8cc004004018894ccc088004528099299981019baf0043021302500214a2266006006002604a002602c66040602e660406042603c6ea80092f5c097ae0301c37540026008602e6ea8048dd6180d180d980d980d980d980d980d980d980d980b9baa30043017375400c60346036603660366036603660366036602e6ea8c010c05cdd50031bab301a301b301b301b301b301b301b301737546008602e6ea80184cc004dd6180d180d980d980b9baa30043017375400c4601464a66602e601860306ea8004520001375a603860326ea8004c94ccc05cc030c060dd50008a6103d87a8000132330010013756603a60346ea8008894ccc070004530103d87a80001323232533301c3371e911066f7261636c6500375c603a0062602c660406ea00052f5c026600a00a0046eb4c074008c080008c078004c8cc004004dd59803980c9baa00222533301b00114c103d87a80001323232533301b3371e0106eb8c07000c4c054cc07cdd3000a5eb804cc014014008dd5980e001180f801180e8008a5022323300100100322533301b00114a2264a6660326008603c0042660060060022940c078004dd7180c180a9baa00116300130143754600260286ea8c94ccc04cc020c050dd5000899299980a1804180a9baa00113004301637546032602c6ea800458cc88c8cc00400400c894ccc0680045300103d87a80001323253330193375e601060366ea80080144c04ccc0740092f5c0266008008002603c00460380026eb0c008c054dd51801180a9baa0043018301537540022c600460286ea800c8c05c0048c058c05c0045261365632323232533301130053012375401c2646464646464646464646464a666040604600426464646464931919191919299981498160010a4c2c6eb4c0a8004c0a8008dd7181400098140031bae302600532323232325333028302b002149858dd6981480098148011bae30270013027007375c604a00c6464646464a66604e60540042930b1bad30280013028002375c604c002604c0106eb8c09001d4ccc078c048c07cdd5005099191919299981298140010991924c602a00460280062c604c002604c004604800260406ea802858c03402c58dd6181080098108011bac301f001301f0023758603a002603a0046eb8c06c004c06c008c064004c064008c05c004c04cdd50070b180080091192999809180300089919299980b980d0010a4c2c6eb8c060004c050dd50010a999809180380089919299980b980d00109924c6600e00246600c00c0022c6eb0c060004c050dd50010a999809180400089919299980b980d00109924c6600e00246600c00c0022c6eb0c060004c050dd50010a9998091805800899191919299980c980e00109924c660120024660100100022c6eb0c068004c068008dd6980c000980a1baa00215333012300a001132325333017301a002149858dd6980c000980a1baa002153330123009001132325333017301a002149858dd6980c000980a1baa002153330123370e900600089919299980b980d0010a4c2c6eb8c060004c050dd50010b18091baa0012533300f300330103754002264646464a66602c60320042649319299980a18040008a99980b980b1baa00414985854ccc050c0240044c8c94ccc064c07000852616375a6034002602c6ea801054ccc050c02800454ccc05cc058dd50020a4c2c2c60286ea800c58c94ccc058c05400454ccc04cc020c0500045288a9998099803980a0008a5016163754602e002602e004602a00260226ea80045888c8cc00400400c894ccc050004526132330030033018002300330160013012300f37540126e1d2000370e90011b8748010dc3a40146e1d2008370e90031ba548000dd2a40046eb80055cd2ab9d5573caae7d5d02ba157449811e581cbd4e886ee59548d9d6a2be480a4b468da8e8177f52ba6ce05b7b24a30001", + "hash": "e2fe2d97baeb7dbc39da2c3292e346806d28f37eb0a980e46528e61e" }, { "title": "order.spend", @@ -70,8 +71,8 @@ "$ref": "#/definitions/types~1order~1OrderRedeemer" } }, - "compiledCode": "5909a201000033232323232323223222323232253330093232533300b3005300c375400e264646464646466664444646600200200a4464a6660306026002264646600200201044a66603c00229404c94ccc070cdc79bae302100200414a226600600600260420026eb8c074c068dd50010a99980c1809000899198008009bac301e301b375400644a66603a00229444c94ccc06ccc018018c0800084cc00c00c00452818100008a99980c1806800899198008009bac301e301b375400644a66603a00229404c94ccc06ccc018018c08000852889980180180098100008a99980c180600089919b89375a603c002646660020026eb0c07cc0800092000222533301f002100113330030033022002533301c33007007302100213370000290010800980d1baa00215333018300b00113232533301a3014301b3754002264a66603664a66603e603c0022a666038602c603a002294454ccc070c05cc0740045280b0b1baa300b301d37546016603a6ea80204cdc4800801899b88001003375a603e60386ea80045281807980d9baa3009301b375400c6eb4c074c068dd50010a99980c180500089919299980d180a180d9baa001132533301b32533301f301e0011533301c3016301d00114a22a666038602e603a00229405858dd51805980e9baa3011301d3754010266e2400c0044cdc40018009bad301f301c37540022940c03cc06cdd51807980d9baa006375a603a60346ea80084c8c8cc004004018894ccc078004528099299980e19baf004301d302100214a2266006006002604200266e9520003301c3374a90011980e180e980d1baa0024bd7025eb80c060dd5000980098099baa00e3758602c602e602e602e602e602e602e602e602e60266ea8c01cc04cdd5004980b180b980b980b980b980b980b980b98099baa3007301337540126eacc020c04cdd5180398099baa009230163017001323232325333013300e301437540202646464646464646464646464a666044604a00426464646493192999811980f000899192999814181580109924c64a66604c604200226464a666056605c0042930b1bae302c001302837540042a66604c604000226464a666056605c0042930b1bae302c001302837540042c604c6ea800458c0a4004c094dd50038a999811980e800899191919299981518168010991924c6464646464a66606060660042930b1bad30310013031002375c605e002605e0066eb8c0b4008c8c8c8c8c94ccc0bcc0c800852616375a606000260600046eb8c0b8004c0b8010dd718160018b1bac302b001302b00237586052002604a6ea801c54ccc08cc0600044c8c94ccc0a0c0ac0084c926323232323232323253330303033002149858dd6981880098188011bae302f001302f003375c605a0046464646464a66605e60640042930b1bad30300013030002375c605c002605c0066eb8c0b0008dd618140011bac302600116325333028302b302b0011337606054002605460560022c6eb0c0a4004c094dd50038a999811980b800899192999814181580109924c6464646464a66605a60600042930b1bad302e001302e002375c605800260580046eb8c0a800458dd6181480098129baa007153330233016001132325333028302b002132498c8c8c8c8c8c8c8c94ccc0c0c0cc00852616375a606200260620046eb8c0bc004c0bc00cdd718168011919191919299981798190010a4c2c6eb4c0c0004c0c0008dd7181700098170019bae302c002375860500046eb0c09800458c94ccc0a0c0acc0ac0044cdd81815000981518158008b1bac30290013025375400e2a666046602a00226464a666050605600426493191bae3028002375c604c0022c64a66605060566056002266ec0c0a8004c0a8c0ac00458dd6181480098129baa007163023375400c64a666044603a002264646464a6660526058004264649319299981418118008a99981598151baa00314985854ccc0a0c0880044c8c94ccc0b4c0c000852616375c605c00260546ea800c54ccc0a0c0740044c8c94ccc0b4c0c000852616302e001302a37540062c60506ea80094ccc098c084c09cdd5001899191919299981698180010991924c64a666058604e00226464a666062606800426493192999817981500089919299981a181b80109924c60440022c606a00260626ea800854ccc0bcc0a40044c8c8c8c8c8c94ccc0e0c0ec00852616375a607200260720046eb4c0dc004c0dc008dd6981a80098189baa00216302f37540022c6064002605c6ea800c54ccc0b0c09800454ccc0bcc0b8dd50018a4c2c2c60586ea8008c06c00c58c0b8004c0b8008c0b0004c0a0dd50018b0b18150009815001181400098121baa00815333022301c00115333025302437540102930b0b18111baa007300e00a325333020301b0011323253330253028002149858dd7181300098111baa00c15333020301a00115333023302237540182930b0b18101baa00b163023001302300230210013021002301f001301f002375a603a002603a004603600260360046032002602a6ea804058c00400488c94ccc050c03c0044c8c94ccc064c07000852616375c6034002602c6ea800854ccc050c0380044c8c94ccc064c0700084c926330060012330060060011637586034002602c6ea800854ccc050c0240044c8c94ccc064c0700084c926330060012330060060011637586034002602c6ea800854ccc050c0200044c8c8c8c94ccc06cc0780084c92633008001233008008001163758603800260380046eb4c068004c058dd50010a99980a180380089919299980c980e0010a4c2c6eb4c068004c058dd50010a99980a180300089919299980c980e0010a4c2c6eb4c068004c058dd50010a99980a19b87480300044c8c94ccc064c07000852616375c6034002602c6ea800858c050dd500091191980080080191299980b8008a4c26466006006603600460066032002464a666022601800226464a66602c60320042930b1bae3017001301337540042a666022601600226464a66602c60320042930b1bae3017001301337540042c60226ea8004dc3a40146e1d2008370e90031b87480104c8ccc004004dd5980198071baa3002300e37540089408894ccc04400840044c8ccc010010c05400ccc88c94ccc048c034c04cdd500189929998099806980a1baa001132533301400714a2266e3c004048dd7180c180a9baa001002301730143754006002200860200026eb4c044004c04c0088c0400048c03cc040c040c040c040c040c0400045261365632533300830030011533300b300a37540082930b0a99980418010008a99980598051baa00414985858c020dd50019b8748008dc3a40006eb80055cd2ab9d5573caae7d5d02ba1574498011e581c4387fbb60eacf2c0cd44188552a1be36cad9d2816432529e750be40d0001", - "hash": "cfbf410c308a854764dd3eab5ad91da06fdaf7057b5bcd7c1b915ecc" + "compiledCode": "5909a201000033232323232323223222323232253330093232533300b3005300c375400e264646464646466664444646600200200a4464a6660306026002264646600200201044a66603c00229404c94ccc070cdc79bae302100200414a226600600600260420026eb8c074c068dd50010a99980c1809000899198008009bac301e301b375400644a66603a00229444c94ccc06ccc018018c0800084cc00c00c00452818100008a99980c1806800899198008009bac301e301b375400644a66603a00229404c94ccc06ccc018018c08000852889980180180098100008a99980c180600089919b89375a603c002646660020026eb0c07cc0800092000222533301f002100113330030033022002533301c33007007302100213370000290010800980d1baa00215333018300b00113232533301a3014301b3754002264a66603664a66603e603c0022a666038602c603a002294454ccc070c05cc0740045280b0b1baa300b301d37546016603a6ea80204cdc4800801899b88001003375a603e60386ea80045281807980d9baa3009301b375400c6eb4c074c068dd50010a99980c180500089919299980d180a180d9baa001132533301b32533301f301e0011533301c3016301d00114a22a666038602e603a00229405858dd51805980e9baa3011301d3754010266e2400c0044cdc40018009bad301f301c37540022940c03cc06cdd51807980d9baa006375a603a60346ea80084c8c8cc004004018894ccc078004528099299980e19baf004301d302100214a2266006006002604200266e9520003301c3374a90011980e180e980d1baa0024bd7025eb80c060dd5000980098099baa00e3758602c602e602e602e602e602e602e602e602e60266ea8c01cc04cdd5004980b180b980b980b980b980b980b980b98099baa3007301337540126eacc020c04cdd5180398099baa009230163017001323232325333013300e301437540202646464646464646464646464a666044604a00426464646493192999811980f000899192999814181580109924c64a66604c604200226464a666056605c0042930b1bae302c001302837540042a66604c604000226464a666056605c0042930b1bae302c001302837540042c604c6ea800458c0a4004c094dd50038a999811980e800899191919299981518168010991924c6464646464a66606060660042930b1bad30310013031002375c605e002605e0066eb8c0b4008c8c8c8c8c94ccc0bcc0c800852616375a606000260600046eb8c0b8004c0b8010dd718160018b1bac302b001302b00237586052002604a6ea801c54ccc08cc0600044c8c94ccc0a0c0ac0084c926323232323232323253330303033002149858dd6981880098188011bae302f001302f003375c605a0046464646464a66605e60640042930b1bad30300013030002375c605c002605c0066eb8c0b0008dd618140011bac302600116325333028302b302b0011337606054002605460560022c6eb0c0a4004c094dd50038a999811980b800899192999814181580109924c6464646464a66605a60600042930b1bad302e001302e002375c605800260580046eb8c0a800458dd6181480098129baa007153330233016001132325333028302b002132498c8c8c8c8c8c8c8c94ccc0c0c0cc00852616375a606200260620046eb8c0bc004c0bc00cdd718168011919191919299981798190010a4c2c6eb4c0c0004c0c0008dd7181700098170019bae302c002375860500046eb0c09800458c94ccc0a0c0acc0ac0044cdd81815000981518158008b1bac30290013025375400e2a666046602a00226464a666050605600426493191bae3028002375c604c0022c64a66605060566056002266ec0c0a8004c0a8c0ac00458dd6181480098129baa007163023375400c64a666044603a002264646464a6660526058004264649319299981418118008a99981598151baa00314985854ccc0a0c0880044c8c94ccc0b4c0c000852616375c605c00260546ea800c54ccc0a0c0740044c8c94ccc0b4c0c000852616302e001302a37540062c60506ea80094ccc098c084c09cdd5001899191919299981698180010991924c64a666058604e00226464a666062606800426493192999817981500089919299981a181b80109924c60440022c606a00260626ea800854ccc0bcc0a40044c8c8c8c8c8c94ccc0e0c0ec00852616375a607200260720046eb4c0dc004c0dc008dd6981a80098189baa00216302f37540022c6064002605c6ea800c54ccc0b0c09800454ccc0bcc0b8dd50018a4c2c2c60586ea8008c06c00c58c0b8004c0b8008c0b0004c0a0dd50018b0b18150009815001181400098121baa00815333022301c00115333025302437540102930b0b18111baa007300e00a325333020301b0011323253330253028002149858dd7181300098111baa00c15333020301a00115333023302237540182930b0b18101baa00b163023001302300230210013021002301f001301f002375a603a002603a004603600260360046032002602a6ea804058c00400488c94ccc050c03c0044c8c94ccc064c07000852616375c6034002602c6ea800854ccc050c0380044c8c94ccc064c0700084c926330060012330060060011637586034002602c6ea800854ccc050c0240044c8c94ccc064c0700084c926330060012330060060011637586034002602c6ea800854ccc050c0200044c8c8c8c94ccc06cc0780084c92633008001233008008001163758603800260380046eb4c068004c058dd50010a99980a180380089919299980c980e0010a4c2c6eb4c068004c058dd50010a99980a180300089919299980c980e0010a4c2c6eb4c068004c058dd50010a99980a19b87480300044c8c94ccc064c07000852616375c6034002602c6ea800858c050dd500091191980080080191299980b8008a4c26466006006603600460066032002464a666022601800226464a66602c60320042930b1bae3017001301337540042a666022601600226464a66602c60320042930b1bae3017001301337540042c60226ea8004dc3a40146e1d2008370e90031b87480104c8ccc004004dd5980198071baa3002300e37540089408894ccc04400840044c8ccc010010c05400ccc88c94ccc048c034c04cdd500189929998099806980a1baa001132533301400714a2266e3c004048dd7180c180a9baa001002301730143754006002200860200026eb4c044004c04c0088c0400048c03cc040c040c040c040c040c0400045261365632533300830030011533300b300a37540082930b0a99980418010008a99980598051baa00414985858c020dd50019b8748008dc3a40006eb80055cd2ab9d5573caae7d5d02ba1574498011e581c637dc1c0f2f7e3eb672582dff481680a0a3d4ebc5a7ce67ce4eaf0a10001", + "hash": "d4e90ca452c49731cf611fe45ab5346f0d21d97335fb7f5e54235998" }, { "title": "pool.manage", @@ -81,8 +82,8 @@ "$ref": "#/definitions/types~1pool~1ManageRedeemer" } }, - "compiledCode": "5911ba0100003323232323232322322323232253330083232323232323232323232323232323232323232323232323232325333023301f3024375404026464646464a666050604860526ea80044c8c94ccc0a8c048c0acdd500089919192999816981418171baa00113232323253330313371201a0022a6660626666022603860666ea80580740780804c8c94ccc0ccc0bcc0d0dd5000899299981a19baf302c303637540026072607460746074606c6ea806454ccc0d0cdd7980f981b1baa0014c107d87b9fd87980ff0015332330353371200864a66606c6062606e6ea8004520001375a607660706ea8004c94ccc0d8c0c4c0dcdd50008a6103d87a8000132330010013756607860726ea8008894ccc0ec004530103d87a80001323232533303b3007375c60780062603c6607e6ea00052f5c026600a00a0046eb4c0f0008c0fc008c0f4004c8cc004004dd59810181c1baa00322533303a00114c103d87a80001323232533303a3006375c60760062603a6607c6e980052f5c026600a00a0046eacc0ec008c0f8008c0f000454ccc0d4c0c401854ccc0d4cdc38088028a99981a9919baf374c6600204e910100374c6466002002660046eacc084c0e4dd5007a450022533303b00114bd6f7b6300991981e99bb037526eb8c0e8004dd319198008009bab303c00222533303e00114bd6f7b6300991982019bb037526eb8c0f4004dd419b8148000dd6981f000998018019821001182000099801801981f801181e80091191980080080191299981e0008a5eb7bdb1804c8c8c8c94ccc0f4cdc7803801080189982099bb037520046e98004cc01801800cdd5981f0019bae303c0023040002303e00114a22c2c26464646464a66607466ebcc0c8c0f0dd500119ba548008cc0f8dd4806a5eb8054ccc0e8cdd78021919191919191918121982298230039982298230031982298230029982298230021982298230019982298230011982298230009982298231823800998229ba83370202203a97ae0304600130450013044001304300130420013041001303c37540202a66607466ebcdd30009ba63232323330010013756604e607e6ea8054c94ccc0f8c0e800452f5bded8c0264646600200297adef6c60225333044001133045337609801014000374c00697adef6c601323232325333045300a3300b488100002133049337609801014000374c00e00a2a66608a602200426609266ec13001014000374c00e00626609266ec0dd48011ba6001330060060033756608c0066eb8c110008c120008c118004c8cc0040052f5bded8c044a66608600226608866ec13001014000375000697adef6c60132323232533304430093300a488100002133048337609801014000375000e00a2a666088602000426609066ec13001014000375000e00626609066ec0dd48011ba800133006006003375a608a0066eb8c10c008c11c008c114004cdc0a4000032444a6660840042002264666008008608c0066644646600200200a44a66608e00226609066ec0dd48021ba60034bd6f7b630099191919299982418069980700400109982619bb037520106e9801c01454ccc120cdc78040010992999824982298251baa00113304d337606ea4024c138c12cdd50008020802192999824a9998260008a5114a0298103d87a80001302c3304d374c00297ae032333001001008002222533304e0021001132333004004305200333223233001001005225333053001133054337606ea4010dd4001a5eb7bdb1804c8c8c8c94ccc150c064cc0680200084cc160cdd81ba9008375000e00a2a6660a866e3c0200084c94ccc154c144c158dd500089982c99bb0375201260b460ae6ea80040104010c94ccc154c144004530103d87a80001303833059375000297ae03370000e0022660b066ec0dd48011ba800133006006003375a60aa0066eb8c14c008c15c008c154004dd718268009bad304e001305000213304c337606ea4008dd3000998030030019bab3049003375c608e004609600460920026eb8c104004dd5982100098220011baf4c103d879800022533303c33720004002298103d87980001533303c3371e0040022980103d87a800014c103d87b80001533303a3301b3758607e60806080608060806080608060786ea807c8cdd79812981e9baa003301e3303f301e3303f0014bd7025eb805288b0b0b0b1bab303e303f002303d0013039375460700046070002602e0506e3d2201001616163038303537540022c6602004a01866e04034c8cdc199b8200e375a606664a66606c60726072002266ec0c0e0004c0e0c0e400458dd61800981a1baa017375a606864a66606c60726072002266ec0c0e0004c0e0c0e400458dd61800981a1baa0172303730383038303830380011616375a606a606c606c606c606c606c606c0046eb4c0d0004c0d0c0d0c0c0dd50021bae3032302f37540022c6048605c6ea8c090c0b8dd50021807800981798161baa001163014302b3754002602460546ea8c0b4c0a8dd50008b1980280e9bad302c302d002375a605600260560046eb4c0a4004c094dd50100992999812181018129baa001132325333026300e30273754002264646464646464646464646464a666066600200a2a66606660020062a66606666ebc028c8c8c8c064cc0e8c0ec00ccc0e8c0ec008cc0e8c0ec004cc0e8dd39981d181b8041981d181c00425eb80cc0e8dd39981d181b8031981d181c00325eb80cc0e8014c0f0c0f0c0f0c0f0004c0ec004c0e8004c0d4dd5006899299981a1818181a9baa0011533303433330143039303637540020400420462a66606866ebc024c0b0c0d8dd50080a99981a19baf374c010603c606c6ea80405288b0b0b0b181c181c981c981c981c981c981a9baa00d161616253330333371290001bad3034001153330333371290001bad303500115333033337126eb4c0d000520a09c011337126eb4c0d400520a09c0114a02940528181b181b8011919bb03036001303630370013758606a002606a0046466ec0c0d0004c0d0c0d4004dd6181980098199819981998179baa004375660626064004606000260586ea8c0ac008c0ac004c02806cc02c004c0acc0a0dd50008b180818139baa001300e302637546052604c6ea800458cc004064dd6981418129baa0203001001222533302700214c103d87a80001323253330263022003130093302a0024bd70099980280280099b8000348004c0ac00cc0a40088888c8cc00400401488c94ccc09cc08c0044c8c8cc004004020894ccc0b4004528099299981599b8f375c606000400829444cc00c00c004c0c0004dd7181618149baa002153330273022001132330010013758605a60546ea800c894ccc0b000452889929998151980300318178010998018018008a50302f00115333027300f0011330083758605860526ea80088cc01001000454ccc09ccdc3a400c00226466e24dd69816800991998008009bac302e302f002480008894ccc0b800840044ccc00c00cc0c40094ccc0accc01c01cc0c00084cdc0000a4004200260526ea800854ccc09ccdc3a401000226464a666052604860546ea80044c94ccc0a8c94ccc0b8c0b400454ccc0acc098c0b00045288a999815981398160008a5016163754602860586ea8c050c0b0dd5004099b890010031337100020066eb4c0b8c0acdd50008a503020302a3754602460546ea8018dd6981618149baa002153330273370e9005000899192999814981218151baa001132533302a32533302e302d0011533302b3026302c00114a22a666056604e605800229405858dd5180a18161baa3022302c3754010266e2400c0044cdc40018009bad302e302b37540022940c080c0a8dd5181018151baa006375a605860526ea80084c8c8cc004004018894ccc0b4004528099299981599baf004302c303000214a2266006006002606000260146605666e9520023302b302c3029375400497ae04bd7018139baa00122323300100100322533302600114a0264a6660486008605200429444cc00c00c004c0a40048c94ccc080c070c084dd5000899192999811180518119baa0011323233760008004600e002604e60486ea800458c030c08cdd5000981298111baa00116533302200114c103d87a8000130023302330240014bd701ba54800094ccc074c064c078dd500089919191919191919191919191919191919192999819181a80109919191924c64a666066605e00226464a666070607600426493180d8008b181c800981a9baa00b15333033302e00115333036303537540162930b0b18199baa00a32375a60680186eb4c0c802cc8dd698198069bad303100c32323232375c606a0066eb8c0cc008c8dd7181a0019bae30320023233760606c002606c606e0026eb0c0c8040c8cdd8181a800981a981b0009bac303000f16375a606600260660046eb4c0c4004c0c4008dd6981780098178011816800981680119299981518169816800899bb0302c001302c302d0011637586056002605600464a66605060566056002266ec0c0a8004c0a8c0ac00458dd6181480098148011bad3027001302700232533302430273027001133760604c002604c604e0022c6eb0c094004c094008dd71811800980f9baa0011632323232325333023302600213253330213371e6eb8c08800807c54ccc084cdd79ba60014c10ba14873657474696e677301001325333022300a3023375400226464004a666046603e60486ea80044c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc0f8c1040084c8c8c8c8c8c8c9263302a01123027001325333041303d0011323253330463049002132498cc0b00048dd70008b1bac3047001304337540262a66608260780022a66608860866ea804c526161630413754024646eb4c108050dd69820009981100a181180a981000b181080b8b181f800981f8011bad303d001303d002375a607600260760046eb4c0e4004c0e4008dd6981b800981b8011bac3035001303500230330013033002325333030303330330011337606064002606460660022c6eb0c0c4004c0c4008c0bc004c0bc008c0b4004c0b4008c0ac004c0ac008c0a4004c094dd50008b181398121baa00116300c302337540082c2c6eacc08800458c090004c090dd5980418101baa0013007301f375460446eb0c08804894ccc074c064c078dd5000899191919299981218138010991924c64a666046603e00226464a6660506056004264931929998131811000899192999815981700109924c601a0022c605800260506ea800854ccc098c0840044c8c8c8c8c8c94ccc0bcc0c800852616375a606000260600046eb4c0b8004c0b8008dd6981600098141baa00216302637540022c6052002604a6ea800c54ccc08cc07800454ccc098c094dd50018a4c2c2c60466ea8008c01800c58c094004c094008c08c004c07cdd50008b119299980e980c80089919299981118128010a4c2c6eb8c08c004c07cdd50010a99980e980c00089919299981118128010a4c2c6eb8c08c004c07cdd50010b180e9baa00130010012232533301c30180011323253330213024002149858dd71811000980f1baa0021533301c30170011323253330213024002132498cc01c0048cc01801800458dd61811000980f1baa0021533301c30040011323253330213024002132498cc01c0048cc01801800458dd61811000980f1baa0021533301c3370e90030008991919192999811981300109924c660120024660100100022c6eb0c090004c090008dd69811000980f1baa0021533301c3370e900400089919299981098120010a4c2c6eb4c088004c078dd50010a99980e19b87480280044c8c94ccc084c09000852616375a6044002603c6ea800854ccc070cdc3a401800226464a66604260480042930b1bae3022001301e37540042c60386ea8004dc3a400844646600200200644a66603c002293099198018019811001180198100009180e180e8009180d980e180e0009bac3019301a002301800130180023756602c002602c602c0046eacc050004c050c050008dd61809000980900098088011bac300f001300b3754600260166ea80088c038004526136563253330073003001132323232323253330103013002149858dd6980880098088011bad300f001300f002375a601a00260126ea801054ccc01cc0080044c8c94ccc030c03c00852616375a601a00260126ea801058c01cdd50019b8748008dc3a40006eb80055cd2ab9d5573caae7d5d02ba157449811e581c445b77d214aa36d1b2edeedb8ddad49e0b62d80a1f4b08eb9c8b4c8c0001", - "hash": "fcbeb9b48861ad17eb97cff003df115accf7cf18f09b31a2b7a4afb5" + "compiledCode": "5910f90100003323232323232322322323232253330083232323232323232323232323232323232323232323232323232325333023301f3024375404026464646464a666050604860526ea80044c8c94ccc0a8c048c0acdd500089919192999816981418171baa00113232323253330313371201a0022a6660626666022603860666ea80580740780804c8c94ccc0ccc0bcc0d0dd5000899299981a19baf302c303637540026072607460746074606c6ea806454ccc0d0cdd7980f981b1baa0014c107d87b9fd87980ff0015332330353371200864a66606c6062606e6ea8004520001375a607660706ea8004c94ccc0d8c0c4c0dcdd50008a6103d87a8000132330010013756607860726ea8008894ccc0ec004530103d87a80001323232533303b3007375c60780062603c6607e6ea00052f5c026600a00a0046eb4c0f0008c0fc008c0f4004c8cc004004dd59810181c1baa00322533303a00114c103d87a80001323232533303a3006375c60760062603a6607c6e980052f5c026600a00a0046eacc0ec008c0f8008c0f000454ccc0d4c0c401854ccc0d4cdc38088028a99981a9919baf374c6600204e910100374c6466002002660046eacc084c0e4dd5007a450022533303b00114bd6f7b6300991981e99bb037526eb8c0e8004dd319198008009bab303c00222533303e00114bd6f7b6300991982019bb037526eb8c0f4004dd419b8148000dd6981f000998018019821001182000099801801981f801181e80091191980080080191299981e0008a5eb7bdb1804c8c8c8c94ccc0f4cdc7803801080189982099bb037520046e98004cc01801800cdd5981f0019bae303c0023040002303e00114a22c2c26464646464a66607466ebcc0c8c0f0dd500119ba548008cc0f8dd4806a5eb8054ccc0e8cdd780219191919191918119982218228031982218228029982218228021982218228019982218228011982218228009982218229823000998221ba83370202003897ae030450013044001304300130420013041001303c37540202a66607466ebcdd30009ba63232323330010013756604e607e6ea8054c94ccc0f8c0e800452f5bded8c0264646600200297adef6c6022533304400113304533760981014000374c00697adef6c601323232325333045300a3300b488100002133049337609801014000374c00e00a2a66608a602200426609266ec13001014000374c00e00626609266ec0dd48011ba6001330060060033756608c0066eb8c110008c120008c118004c8cc0040052f5bded8c044a66608600226608866ec13001014000375000697adef6c60132323232533304430093300a488100002133048337609801014000375000e00a2a666088602000426609066ec13001014000375000e00626609066ec0dd48011ba800133006006003375a608a0066eb8c10c008c11c008c114004cdc0a4000032444a6660840042002264666008008608c0066644646600200200a44a66608e00226609066ec0dd48021ba60034bd6f7b630099191919299982418069980700400109982619bb037520106e9801c01454ccc120cdc78040010992999824982298251baa00113304d337606ea4024c138c12cdd50008020802192999824a9998260008a5114a0298103d87a80001302c3304d374c00297ae032333001001008002222533304e0021001132333004004305200333223233001001005225333053001133054337606ea4010dd4001a5eb7bdb1804c8c8c8c94ccc150c064cc0680200084cc160cdd81ba9008375000e00a2a6660a866e3c0200084c94ccc154c144c158dd500089982c99bb0375201260b460ae6ea80040104010c94ccc154c144004530103d87a80001303833059375000297ae03370000e0022660b066ec0dd48011ba800133006006003375a60aa0066eb8c14c008c15c008c154004dd718268009bad304e001305000213304c337606ea4008dd3000998030030019bab3049003375c608e004609600460920026eb8c104004dd5982100098220011baf4c103d879800022533303c33720004002298103d87980001533303c3371e0040022980103d87a800014c103d87b80001533303a3301b3758607e60806080608060806080608060786ea807c8cdd79812981e9baa003301e3303f301e3303f0014bd7025eb805288b0b0b0b1bab303e303f002303d0013039375460700046070002602e0506e3d2201001616163038303537540022c6602004a01866e04034c8cdc199b8200e375a606664a66606c60726072002266ec0c0e0004c0e0c0e400458dd61800981a1baa017375a606864a66606c60726072002266ec0c0e0004c0e0c0e400458dd61800981a1baa0172303730383038303830380011616375a606a606c606c606c606c606c0046eb4c0d0004c0d0c0d0c0c0dd50021bae3032302f37540022c6048605c6ea8c090c0b8dd50021807800981798161baa001163014302b3754002602460546ea8c0b4c0a8dd50008b1980280e9bad302c302d002375a605600260560046eb4c0a4004c094dd50100992999812181018129baa001132325333026300e30273754002264646464646464646464646464a666066600200a2a66606660020062a66606666ebc028c8c8c8c064cc0e8c0ec00ccc0e8c0ec008cc0e8c0ec004cc0e8dd40041981d1ba80063303a005303c303c303c303c001303b001303a0013035375401a264a6660686060606a6ea800454ccc0d0cccc050c0e4c0d8dd50008100108118a99981a19baf009302c30363754020266ebcdd3004180f181b1baa01014a02c2c607060726072607260726072606a6ea803458585894ccc0cccdc4a4000002266e2400520a09c0114a0606c606e0046eb4c0d4004c0d4008dd6981980098199819981998179baa004375660626064004606000260586ea8c0ac008c0ac004c02806cc02c004c0acc0a0dd50008b180818139baa001300e302637546052604c6ea800458cc004064dd6981418129baa0203001001222533302700214c103d87a80001323253330263022003130093302a0024bd70099980280280099b8000348004c0ac00cc0a40088888c8cc00400401488c94ccc09cc08c0044c8c8cc004004020894ccc0b4004528099299981599b8f375c606000400829444cc00c00c004c0c0004dd7181618149baa002153330273022001132330010013758605a60546ea800c894ccc0b000452889929998151980300318178010998018018008a50302f00115333027300f0011330083758605860526ea80088cc01001000454ccc09ccdc3a400c00226466e24dd69816800991998008009bac302e302f002480008894ccc0b800840044ccc00c00cc0c40094ccc0accc01c01cc0c00084cdc0000a4004200260526ea800854ccc09ccdc3a401000226464a666052604860546ea80044c94ccc0a8c94ccc0b8c0b400454ccc0acc098c0b00045288a999815981398160008a5016163754602860586ea8c050c0b0dd5004099b890010031337100020066eb4c0b8c0acdd50008a503020302a3754602460546ea8018dd6981618149baa002153330273370e9005000899192999814981218151baa001132533302a32533302e302d0011533302b3026302c00114a22a666056604e605800229405858dd5180a18161baa3022302c3754010266e2400c0044cdc40018009bad302e302b37540022940c080c0a8dd5181018151baa006375a605860526ea80084c8c8cc004004018894ccc0b4004528099299981599baf004302c303000214a2266006006002606000260146605666e9520023302b302c3029375400497ae04bd7018139baa00122323300100100322533302600114a0264a6660486008605200429444cc00c00c004c0a40048c94ccc080c070c084dd5000899192999811180518119baa0011323233760008004600e002604e60486ea800458c030c08cdd5000981298111baa00116533302200114c103d87a8000130023302330240014bd701ba54800094ccc074c064c078dd5000899191919191919191919191919191919299981818198010991924c64a66605e605600226464a666068606e00426493180b8008b181a80098189baa0071533302f302a001153330323031375400e2930b0b18179baa00632323232375c60660066eb8c0c4008c8dd718190019bae3030002323376060680026068606a0026eb0c0c0038c8cdd818198009819981a0009bac302e00d16375a606200260620046eb4c0bc004c0bc008c0b4004c0b4008dd6981580098158011bad30290013029002375a604e002604e00464a666048604e604e002266ec0c098004c098c09c00458dd6181280098128011bae3023001301f37540022c6464646464a666046604c004264a66604266e3cdd7181100100f8a99981099baf374c0029810ba14873657474696e677301001325333022300a3023375400226464004a666046603e60486ea80044c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc0f8c1040084c8c8c8c8c8c8c9263302a01123027001325333041303d0011323253330463049002132498cc0b00048dd70008b1bac3047001304337540262a66608260780022a66608860866ea804c526161630413754024646eb4c108050dd69820009981100a181180a981000b181080b8b181f800981f8011bad303d001303d002375a607600260760046eb4c0e4004c0e4008dd6981b800981b8011bac3035001303500230330013033002325333030303330330011337606064002606460660022c6eb0c0c4004c0c4008c0bc004c0bc008c0b4004c0b4008c0ac004c0ac008c0a4004c094dd50008b181398121baa00116300c302337540082c2c6eacc08800458c090004c090dd5980418101baa0013007301f375460446eb0c08804894ccc074c064c078dd5000899191919299981218138010991924c64a666046603e00226464a6660506056004264931929998131811000899192999815981700109924c601a0022c605800260506ea800854ccc098c0840044c8c8c8c8c8c94ccc0bcc0c800852616375a606000260600046eb4c0b8004c0b8008dd6981600098141baa00216302637540022c6052002604a6ea800c54ccc08cc07800454ccc098c094dd50018a4c2c2c60466ea8008c01800c58c094004c094008c08c004c07cdd50008b119299980e980c80089919299981118128010a4c2c6eb8c08c004c07cdd50010a99980e980c00089919299981118128010a4c2c6eb8c08c004c07cdd50010b180e9baa00130010012232533301c30180011323253330213024002149858dd71811000980f1baa0021533301c30170011323253330213024002132498cc01c0048cc01801800458dd61811000980f1baa0021533301c30040011323253330213024002132498cc01c0048cc01801800458dd61811000980f1baa0021533301c3370e90030008991919192999811981300109924c660120024660100100022c6eb0c090004c090008dd69811000980f1baa0021533301c3370e900400089919299981098120010a4c2c6eb4c088004c078dd50010a99980e19b87480280044c8c94ccc084c09000852616375a6044002603c6ea800854ccc070cdc3a401800226464a66604260480042930b1bae3022001301e37540042c60386ea8004dc3a400844646600200200644a66603c002293099198018019811001180198100009180e180e8009180d980e180e0009bac3019301a002301800130180023756602c002602c602c0046eacc050004c050c050008dd61809000980900098088011bac300f001300b3754600260166ea80088c038004526136563253330073003001132323232323253330103013002149858dd6980880098088011bad300f001300f002375a601a00260126ea801054ccc01cc0080044c8c94ccc030c03c00852616375a601a00260126ea801058c01cdd50019b8748008dc3a40006eb80055cd2ab9d5573caae7d5d02ba157449811e581c61ed2a57b7baece734dea4af48c089ac2d3d0fe09fd45023120cc2620001", + "hash": "0bf89b13dc30d812fd4fc25122325e8b02b48b7168e30202dcdda59a" }, { "title": "pool.spend", @@ -98,8 +99,8 @@ "$ref": "#/definitions/RedeemerWrapper$types~1pool~1PoolRedeemer" } }, - "compiledCode": "593e5d01000033323232323232322322322253232323232323232323232323233301430063015375401c264a66602a6464646464646464646464a66604060220162646464646464a66604c6030604e6ea80044c8c8c8c94ccc0a8c070c0acdd5000899192999816180e18169baa0011323232323232323232533303530273036375400226464646464646464646464a66608066e24dd69822982318231823182318231823182318231823182318211baa004375a600260846ea80504c8c94ccc108c94ccc10ccdc499b8200200200113371000266e08c0dc008c0dc00852819b820020041323232325333046303830473754002264a66608e66ebcc0b8c124dd5000981698249baa00b15333047303833302a3756605a60926ea800408403c54ccc11ccdd7981618249baa0014c107d87b9fd87980ff001323253330493375e606060966ea8c0c0c12cdd500f9821198269ba90234bd700a99982499198008009bac3003304c375401c44a66609c00229404c94ccc130cdd7981918271baa3033304e3754044607e660a0607e660a060a200497ae04bd700a511330030030013051001153330490161533304900715333049005100114a029405280b0b299982419b8f375c605e60946ea807004854ccc120cdd79ba63304c32533304c304f304f001133760609c002609c609e0022c6eb0c0b8c128dd500e25eb7bdb180dd31982619bb0374e66098609202e66098609402e97ae0374e66098609202c66098609402c97ae04bd6f7b6300a99982419b87375a605a60946ea807001c54ccc120cdc49bad3001304a37540386eb4c134c138c138c138c138c138c138c138c128dd500e0992999824980099299982698281828000899bb0304f001304f3050001163758600c60966ea80744c004c94ccc134c140c1400044cdd81827800982798280008b1bac3033304b375403a294094ccc124c104dd698250008a99982498209bad304b00115333049337126eb4c12800520a09c011337126eb4c12c00520a09c0114a029405280a5014a02940528118269827182718271827182718270008b0b0b182598241baa001163301d37586054608e6ea8c0b0c11cdd501f810999999991911111129998261821002899baf374e660a098101030033050375066e00004030cc140dd40071982826010101004bd701ba733300830070064bd7090100008101000081010000810100001119299982799b8f375c606c0060102660a66ea0004cc14cdd419b80375a606a0046eb4c0d000ccc14cc0d0008cc14cc0300092f5c02a66609ea66609e66e3cdd7181b001803099b8f375c606a00600a29404cc14cdd400099829981a801198299ba8337006eb4c0d0008dd6981a00199829980600125eb8054ccc13ccdd79ba7003374e660a66ea40a4cc14cdd4981800c99829a6010101004bd700998299ba800133053303500233053303400233053375060866eb4c0300092f5c02c60846eb4c0d40044cdd79ba7330504c01010400330503750002660a06ea0030cc140dd40071982826010101004bd701ba733300830070064bd709010000810100008101000081010000810100001119299982798229bae30360031330533750002660a66ea0cdc01bad3035002375a6068006660a66068004660a66018004660a6607200497ae01533304f533304f3371e6eb8c0d800c0204cdc79bae303500300714a02660a66ea0004cc14cc0d4008cc14cdd419b80375a60680046eb4c0d000ccc14cc030008cc14cc0e40092f5c02a66609ea66609e66e3cdd7181b001803099b8f375c606a00600a29404cc14cdd400099829981a80119829981a001198299ba8337006eb4c030008dd6981a00199829981c80125eb8054ccc13ccdd79ba7003374e660a66ea40a4cc14cdd4981800c99829a6010101004bd700998299ba800133053303500233053303400233053300c00233053375060866eb4c0e40092f5c02c60846eb4c0d40048c8cc004004008894ccc12c00452f5c0264666444646600200200644a6660a20022006264660a66e9ccc14cdd4803198299ba9375c60a0002660a66ea0dd69828800a5eb80cc00c00cc154008c14c004dd718250009bab304b00133003003304f002304d00122232333001001004003222533304d002100113330030033050002330043758609e0040026eacc0a8c118dd500d1bae3045013375c608c0266eb8c114048dd718230091bad3005304637540304609260946094609400266ebcdd318159bab302c30443754605260886ea80f0dd31919800998009813998239ba901d3304737520166608e9810101004bd701813998239ba901d3304737520126608e98010101004bd701813998239ba901d3304737520106608e6ea00092f5c04464666002002006004444a6660940042002264666008008609c0066644646600200200a44a66609e0022660a066ec0dd48021ba60034bd6f7b630099191919299982818239981c00400109982a19bb037520106e9801c01454ccc140cdc78040010992999828982198291baa001133055337606ea4024c158c14cdd50008020802192999828a99982a0008a5114a0298103d87a80001304433055374c00297ae03233300100100800222253330560021001132333004004305a0033322323300100100522533305b00113305c337606ea4010dd4001a5eb7bdb1804c8c8c8c94ccc170c14ccc1100200084cc180cdd81ba9008375000e00a2a6660b866e3c0200084c94ccc174c13cc178dd500089983099bb0375201260c460be6ea80040104010c94ccc174c13c004530103d87a80001305033061375000297ae03370000e0022660c066ec0dd48011ba800133006006003375a60ba0066eb8c16c008c17c008c174004dd7182a8009bad30560013058002133054337606ea4008dd3000998030030019bab3051003375c609e00460a600460a20026eb8c124004dd5982500098260010b1bad30263043375402aa66608060646e34dd71820807899b81003375a600260846ea8050400c588c114c118c118c118c118c118c118c118c118004ccc084dd5981218201baa014375c607e0186eb8c100030ccc080dd59811981f9baa013375c607c0186eb8c0fc030c8c8c8c8c94ccc110c11c0084c94ccc108cdc79bae304300203e153330423375e6e980053010ba14873657474696e67730100132533304330333044375400226464004a666088606c608a6ea80044c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc17cc1880084c8c8c8c8c8c8c92633035011230270013253330623054001132325333067306a002132498cc0dc0048dd70008b1bac3068001306437540262a6660c460a60022a6660ca60c86ea804c526161630623754024646eb4c18c050dd69830809981100a181780a981000b181680b8b183000098300011bad305e001305e002375a60b800260b80046eb4c168004c168008dd6982c000982c0011bac30560013056002305400130540023253330513054305400113376060a600260a660a80022c6eb0c148004c148008c140004c140008c138004c138008c130004c130008c128004c118dd50008b182418229baa001163027304437540082c2c6eacc10c00458c114004c114dd5981298209baa00130243040375460866eb0c090c100dd5181298201baa0382533303e3030303f3754002264646464a66608a60900042646493192999822181b000899192999824982600109924c64a66608e607200226464a666098609e0042649318068008b182680098249baa002153330473038001132323232323253330503053002149858dd6982880098288011bad304f001304f002375a609a00260926ea800858c11cdd50008b182500098231baa00315333044303500115333047304637540062930b0b18221baa002300600316304600130460023044001304037540022c464a66607c606000226464a666086608c0042930b1bae3044001304037540042a66607c605e00226464a666086608c0042930b1bae3044001304037540042c607c6ea8004dd7182018208011bae303f001303f002375c607a002660766ea4cc06522104000643b0000013303b37526030002660766ea4cc065221040014df10000014bd7019199b8c48020cdc01b8d0014801c004dca1980c1980c1bae301d30383754603a60706ea8c074c0e0dd5000a4501230032533303733710002904002099b8b00148810016375a603860706ea8c074c0e0dd5000981d181b9baa001163300c37586036606c6ea8c06cc0d8dd5017240006054646464a66606c60500022980103d879800015333036302700113301e00300214c0103d87b8000303637546603a6eb8c0d8010dd7181b0019bae3036002375c606a0046466ec0c0e0004c0e0c0e4004dd6181a0089919bb030370013037303800137586064020a666060604460626ea80104c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc114c1200084c8c8c8c926325333046303800113232533304b304e002132498c06400458c130004c120dd50058a999823181b8008a99982498241baa00b14985858c118dd5005191bad304700c375a608a016646eb4c118034dd69822006191919191bae3048003375c608c004646eb8c11c00cdd718228011919bb030490013049304a0013758608a0206466ec0c120004c120c124004dd618218078b1bad30460013046002375a608800260880046eb4c108004c108008c100004c100008c94ccc0f4c100c1000044cdd8181f800981f98200008b1bac303e001303e00232533303b303e303e001133760607a002607a607c0022c6eb0c0f0004c0f0008dd6981d000981d00119299981b981d181d000899bb030390013039303a001163758607000260700046eb8c0d8004c0c8dd50020b180080091192999818981180089919299981b181c8010a4c2c6eb8c0dc004c0ccdd50010a999818981100089919299981b181c80109924c6600c00246600c00c0022c6eb0c0dc004c0ccdd50010a999818981080089919299981b181c80109924c6600c00246600c00c0022c6eb0c0dc004c0ccdd50010a9998189810000899191919299981c181d80109924c660100024660100100022c6eb0c0e4004c0e4008dd6981b80098199baa00215333031301f0011323253330363039002149858dd6981b80098199baa00215333031301e0011323253330363039002149858dd6981b80098199baa002153330313370e900600089919299981b181c8010a4c2c6eb8c0dc004c0ccdd50010b18189baa00122323300100100322533303400114984c8cc00c00cc0e0008c00cc0d8004c0c4c0b8dd50008b180818169baa001302f302c37540022c660026eb0c038c0acdd5180818159baa0230063001001222533302d00214c0103d87a800013232533302c301e0031301f330300024bd7009998028028009810801981880198178011bae302b302837540022c6016604e6ea807cdd6981498150011bad302800130280023233760604e002604e60500026eb0c098004c088dd500d8a9998101809005899192999811180a18119baa001132323253330253017302637540022a66604a602c6660106eacc02cc09cdd5181518139baa00100300213017333008300e3756601e604e6ea8c030c09cdd500f8018010a501632533302800114c0103d87a80001301833029302a0014bd701bac3009302637546016604c6ea8078c01000cdd7181398121baa001163007302337540366eb8c094c088dd500d899192999811180a18119baa00113375e6e98c02cdd5980618121baa3009302437540386e98c018cc098c09cc090dd5000998131ba93003002330264c010120004bd700b180398119baa01b375c604a60446ea806c8cc00922104000de14000001223371400400244464a666042602460446ea8004520001375a604c60466ea8004c94ccc084c048c088dd50008a60103d87a8000132330010013756604e60486ea8008894ccc098004530103d87a8000132323253330263371e00e6eb8c09c00c4c064cc0a8dd4000a5eb804cc014014008dd698138011815001181400099198008008021129998128008a6103d87a8000132323253330253371e00e6eb8c09800c4c060cc0a4dd3000a5eb804cc014014008dd59813001181480118138009199911299981018090008a5eb7bdb1804c8c8cc0040052f5bded8c044a66604c00226604e66ec0dd48031ba60034bd6f7b6300991919192999813980f1980780500109981599bb037520146e9801c01454ccc09ccdc780500109981599bb037520146e9801c00c4cc0accdd81ba9002374c0026600c00c0066eacc0a000cdd71813001181500118140009919800800a5eb7bdb180894ccc0940044cc098cdd81ba9004375000697adef6c601323232325333026301d3300e00800213302a337606ea4020dd40038028a99981319b8f00800213302a337606ea4020dd400380189981519bb037520046ea0004cc01801800cdd698138019bae302500230290023027001375c60080026eb8c00c004dd6980100091810981118110009181018108009180f80091299980d19b9000200114c103d87980001533301a3371e0040022980103d87a800014c103d87b80002323300100100222533301d00114bd6f7b630099191919299980f180a001080189981119bb037520046e98004cc01801800cdd5980f8019bae301d0023021002301f0012301c301d301d301d301d0013016375402029309b2b19299980a980380089919299980d180e8010a4c2c6eb8c06c004c05cdd50080a99980a98030008991919191919299980f181080109924c646464646eb8c08400cdd7180f801191bae3020003375c603c0046466ec0c088004c088c08c004dd6180f0031919bb03021001302130220013758603800a2c6eb4c07c004c07c008dd6980e800980e80119299980d180e980e800899bb0301c001301c301d0011637586036002602e6ea804054ccc054c0140044c8c94ccc068c07400852616375c6036002602e6ea804058c054dd500789991919191911919191299980f191919191919191919191919191919191919192999818981118191baa00113232323232533303630283037375403a264646464646464646464646464646464646464646464a66609866ebcc0b8c138dd50079822998281ba901b4bd7009919191919191919299982a18260008991919191919191919191919191919191919191919191919999991111119191919191919191919191919191999999999980080080a009808822a40000be66646002002444a6661040266e2400520001002153330850100214bd700999801801984400801183b80082da40049000240009000111111111112999846008038a9998448099b873370000400206e264a6661140266e1c0fccdc00138008a999845009929998458099b87375a60ae611a026ea8218040284c0680044cdd79ba6001374c6611e0266ec0dd4981b1bae306d308d01375410c026ea0cdc08051bad3057308d01375410c0297adef6c6032533308b01307c308c013754002297adef6c6013756612002611a026ea8004cc0d0c8cc004004194894ccc23c0400452f5bded8c0264646464a66612002610c0200420062661280266ec0dd48011ba60013300600600337566122020066eb8c23c04008c24c04008c2440400416454ccc228054ccc22804c1f0c22c04dd501e8991919192999847009840009847809baa001132325333090013082013091013754002266e3c008dd7184a809849009baa0011633003005056375c6126026120026ea800458cc004184158c0040048894ccc24404008530103d87a80001323253330900130820100313083013309401375200497ae01333005005001308501003309501003375c6126020046eb0c23c04c23004dd501e8a51132533308b013232533308d01307e308e013754002264a66611c0264a666124026122020022a66611e02610002612002002294454ccc23c04c20404c240040045280b0b1baa3060309001375460e06120026ea81904cdc4001800899b89003001375a612402611e026ea800452818371847009baa306e308e0137540c46eb4c004c23404dd50430089919299984680991919299984800984300815099baf374e661280298010103003309401375066e00114044cc25004dd40081984a00a6010101004bd701ba733300330020524bd709010000810100008101000081010000111929998498099b8f375c60ea00605a26612e026ea0004cc25c04dd419b80375a60ca0046eb4c17c00ccc25c04c17c008cc25c04c0200092f5c02a66612602a6661260266e3cdd7183a801815899b8f375c60ca00605429404cc25c04dd40009984b8098328011984b809ba8337006eb4c17c008dd6982f8019984b80980400125eb8054ccc24c04cdd79ba7003374e6612e026ea4188cc25c04dd498020299984b80a6010101004bd7009984b809ba8001330970130650023309701305f00233097013750610e026eb4c0200092f5c02c610c026eb4c1d00044cdd79ba733094014c010104003309401375008a66128026ea0044cc25004dd40081984a00a6010101004bd701ba733300330020524bd7090100008101000081010000810100008101000011192999849809844809bae30750031330970137500026612e026ea0cdc01bad3065002375a60be0066612e0260be0046612e0260100046612e02600e00497ae015333093015333093013371e6eb8c1d400c0b44cdc79bae306500302c14a026612e026ea0004cc25c04c194008cc25c04dd419b80375a60be0046eb4c17c00ccc25c04c020008cc25c04c01c0092f5c02a66612602a6661260266e3cdd7183a801815899b8f375c60ca00605429404cc25c04dd40009984b8098328011984b80982f8011984b809ba8337006eb4c020008dd6982f8019984b80980380125eb8054ccc24c04cdd79ba7003374e6612e026ea4188cc25c04dd498020299984b80a6010101004bd7009984b809ba8001330970130650023309701305f0023309701300800233097013750610e026eb4c01c0092f5c02c610c026eb4c1d00048cc0f1220104000de14000001232330010010022253330940100114bd70099199911191980080080191299984d0080088018991984e009ba73309c01375200c66138026ea4dd7184c808009984e009ba8375a61340200297ae033003003309e01002309c01001375c6126020026eacc25004004cc00c00cc26004008c25804004888c8ccc00400401000c8894ccc2580400840044ccc00c00cc26404008cc010dd6184c008010008a9998468099b8704900c1533308d013370e08466e000a801054ccc23404cdc79bae306f308f0137541100209a2a66611a0266ebcdd3198488099299984880984a00984a00800899bb030930100130930130940100116375860be611e026ea8220052f5bded8c06e98cc2440412d2f5bded8c02a66611a0266ebcdd3198488099299984880984a00984a00800899bb03093010013093013094010011637586004611e026ea8220052f5bded8c06e98cc2440411d2f5bded8c02a66611a0266ebcdd3198488099299984880984a00984a00800899bb03093010013093013094010011637586002611e026ea8220052f5bded8c06e98cc244041152f5bded8c02a66611a0266e1cdd698019847809baa0880104313375e60be611e026ea8c1bcc23c04dd502f182f9847809baa05014a029405280a5014a02c2c2c461240261260261260261260261260200246122026124026124026124020022c46120026122026122026122026122026122026122020022c2c2c66e00cdc019b820360373370400407266e080040e0584c8c8c8c8c8c8c8c8c8c94ccc24c054ccc24c04c21004c25004dd5183a984a809baa307530950137540022944528099299984a00984300984a809baa00113232323232323232533309c0132533309d01308f01309e013754002266e3cdd7185100984f809baa00105d14a261420200c2646464664464666600200202c00e0a4444464a66614c02613002002264a66614e026132026150026ea80144cccc018019300103d87a800032323232323253330ad013375e0386164020082a66615a02646464a6661600264a666162026144026164026ea80044c94ccc2c804c94ccc2d804c2d40400454ccc2cc04c29004c2d0040045288a99985980985280985a008008a50161637546108026168026ea8c25004c2d004dd5003899b8900100513371000200a6eb4c2d804c2cc04dd50008a5130920130b20137546124026164026ea80144004528192999858009850809858809baa00113253330b1013253330b50130b401001153330b20130a30130b30100114a22a6661640261480261660200229405858dd51841809859809baa30830130b301375400c266e2400c0044cdc40018009bad30b50130b20137540022944c24404c2c404dd51840809858809baa0043253330af0130a00130b0013754002264a6661600264a666168026166020022a66616202614402616402002294454ccc2c404c28c04c2c8040045280b0b1baa30820130b20137546104026164026ea82180440044c29404004dd6985a009858809baa0011483fa7ede1fa414c24004c2c004dd51840009858009baa084013253330ae01309f0130af013754002264a66615e0264a666166026164020022a66616002614202616202002294454ccc2c004c28804c2c4040045280b0b1baa30810130b10137546122026162026ea82140440044c28c04004dd69859809858009baa001148000c23c04c2bc04dd51847809857809baa08301153330ad01309f0130ae01375400e26464a66615e026142026160026ea801c54ccc2bc04ccdca8010009bae30b40130b101375400e20062c2c6ecc008dd71859009857809baa007153330ad01323233001001087012253330b30100114a0264a6661620266ebc010c2c804c2d804008528899801801800985b00800985000998588098530099858809859009857809baa0074bd7025eb804004585858c2c404c2c804008c2c004004c2c004004c2ac04dd51857008011856809857008009854809baa30ac0130a901375400a0ac2c6156026150026ea800c54c8c8c8c8c8ccc2ac04c270040184c8c8c8c8c94ccc2c0040184c8c8c8c8c8c94ccc2d8054ccc2d8040384c8c94ccc2e004cdd7984d00985d009baa00a30bd0100213375e6108026174026ea8028004528185e00985e80800985c009baa01c1323253330b8013375e6134026174026ea8028c2f4040084cdd7984200985d009baa00a00114a0617802617a02617a020026170026ea809054ccc2d8054ccc2d804cdc7802028099b8f00204f14a02a66616c0266e3cdd7184c008048270a99985b0099b8f375c61100201209a26666666666607a00800409c09a06e06c08e01a00200a44a6661700266ebcc22804c2e804dd50051ba6001153330b801337126eb4c2100402c0084cc020c04800ccdc081c0010b0b0b0b0a99985b00a99985b0099b8f00404e13371e00409a294054ccc2d804cdc79bae309801009050153330b6013371e6eb8c2200402413c4ccccccccccc0f401000814013c0d80dc118034004014894ccc2e004cdd7984500985d009baa00a374c0022a6661700266e24dd698420080580109980419b810390023011003161616161616375a6174026176020046eb8c2e404004c2e40401cdd7185b808031bab30b60130b70130b301375403e4466660240040020620062c616a020546166020526eb0c2c804c2cc04008dd61858808009856809baa008153330ab01309b01006132323253330ae01004132323253330b1013371e6eb8c24c0400c12c54ccc2c404cdc79bae30830100304a153330b1013371e6eb8c24c0400812454ccc2c404cdc79bae30830100204813253330b2013371090000008991919191919299985c0099b884800000454ccc2e004cdd7984500985d009baa00c374c666608a666608a666608a666608a0106eb8c26804028dd718450080518200019bae309a01009375c611402012608000491100488100304000f0870104b001153330b80153330b8010101323253330ba013375e6138026178026ea8038c2fc040084cdd7984300985e009baa00e00114a0617c02617e020026174026ea80784c8c94ccc2e804cdd7984e00985e009baa00e30bf0100213375e610c026178026ea8038004528185f00985f80985f80800985d009baa02613333018301200330110023370006e0020162c2c2c66e0ccdc100101b01c1bad30b801002375a616c02002a6661680266e2000c0044cdd81ba8003375061500266e0cc2a404cdc101a00181a899bb037500026ea0008cdc199b820010340333303b375a60fc0066660b60046eb8c2500400cdd71842008018b1981d1bad307d003337026660b40026eb8c24c0400cdd7184180801a999858809853809bae3093010031337009040497a008040a40002c2c2c2c6eacc2d404c2d804c2c804dd500f1bac30b1010043758615e020062c61660205061620204e6466ec0c2c404004c2c404c2c804004dd61858009856809baa008153330ab01309a01006132323253330ae010041323232323253330b3013371e00a104022a6661660266e3c00c1184c8c8c94ccc2d804cdd7984400985c009baa00a374c666608666660866666086666608600801000c607c00691100488100303e00d05004f00204e04d001153330b60153330b60100e1323253330b8013375e6134026174026ea8030c2f4040084cdd7984200985d009baa00c00114a0617802617a020026170026ea80704c8c94ccc2e004cdd7984d00985d009baa00c30bd0100213375e6108026174026ea8030004528185e00985e80985e80800985c009baa024133330163370206e00466e040d8004cdc081a8018048b0b19b833370400406a06866e0ccdc100081a8199981e00119982e0008028018b0b1bab30b70130b80130b40137540406eb4c2d804c2dc04008dd7185a80800985a808021bae30b3010031630b30102830b1010273758616002615a026ea802054ccc2ac04c264040184c8c8c94ccc2b8040104c8c8c8c8c8c8c8c8c8c8c94ccc2e404cdc78040298a99985c8099b8f006052153330b9013371e0080a22a6661720266e3c0081404c8c94ccc2ec054ccc2ec04ccc2ec040052825114a22a6661760266ebcc23404c2f404dd50079ba6002153330bb010131323253330bd013375e613e02617e026ea8044c308040084cdd7984480985f809baa01100114a0618202618402002617a026ea80844c8c94ccc2f404cdd7984f80985f809baa01130c20100213375e611202617e026ea8044004528186080986100986100800985e809baa02914a026644a66617a020062666603a0040020780202666603a004002078070602a6eb4c21c04dd6185e00808180a1bad3087013758617a020202c6661740266ebcdd3000a6101a0004a0944cccc118cccc118cccc11802d22010048810030410100080063041005004002304100116161616375a617a02617c020046eb8c2f004004c2f004018dd7185d008029bad30b90130ba01002375c6170020026170020066eb8c2d804008dd61859008029bac30b00100437566166026168026160026ea807058c2cc040a0c2c40409cc8cdd81858808009858809859008009bac30b00130ad0137540102646464a66615c020082a66615c02a66615c0266ebcc20004c2c004dd50011ba6333303b333303b37566100026160026ea8071221004881003036005375c615e020066eb8c2c00400d2002153330ae0100613375e6120026160026ea8008c2cc04c2c004dd500a0a5014a02666601c05e05c05a0022c2c61660205061620204e6466ec0c2c404004c2c404c2c804004dd61858009856809baa0083371200202466e00158014c26804c2a404dd50071b80027370004e614c026ea8008dd598389850809baa00d222233333333333025025004003002019309701018014001016006005375a6140020046eb4c278040054ccc27004c23804c27404dd5000899bb0375002a6ea0c240040504cdd81ba830900101537500282c614002614202004613e02002613e020046eb4c27404004c27404c27404004c26004dd5001299984a80984380984b009baa001132323232323232323232323253330a40130a701002132323232498c22404018c94ccc29004c258040044c8c8c8c94ccc2ac04c2b8040084c8c9263253330aa01309c01001153330ad0130ac0137540062930b0a99985500984d80800899192999857809859008010a4c2c6eb8c2c004004c2b004dd50018a99985500984d00800899192999857809859008010a4c2c6160020026158026ea800c58c2a804dd5001183a8018b1856008009856008011855008009853009baa008153330a401309501001153330a70130a60137540102930b0b1852009baa007308c0100a30870100b1630a50100130a50100230a30100130a30100230a10100130a101002375a613e02002613e02004613a02002613a02004613602002612e026ea800458c26404c25804dd50008b1919299984a809843808008a60103d87a80001533309501308601001132323300100106a22533309b0100114c0103d87a80001323232533309b013371e00c6eb8c2700400c4c23804cc27c040052f5c026600a00a004613802004613e02004613a020026eb8c26804c25c04dd500109844009984c80984d00984b809baa0024bd70184a809baa001305f30950137540022c612e02613002004612c020026124026ea8c25404008c254040054ccc23804cdc480580189980880519b8100300b13301106e003533308d0130850100213232325333090013371066e18028008cdc300080108008b19b80009002337049002000a99199847009800a4020260340062a66611c0260029010099b824820010c068cdc0001a401e2a66611c0260029018099b82482020020c068cdc0001a403e2a66611c0260029020099b8248202020040c068cdc0001a405e2a66611c0260029028099b824820202020080c068cdc0001a407e260300066e2000858c24404c2480400cdd69848008011848008041bac308e010073001001222533307f33712900f000899980180198428098428098428098428098428098428098428098428098428098428098428098428098428098428098428080119b800014807454ccc1fccdc4a401c0022666006006610a02610a02610a02610a02610a02610a02610a0200466e00005200d1330040020013001001222533307d306f0011002133300300330830100230720012222222222232323300300133330133333013333301300400d00c300e005488100488100300e00600b00a0013370666e08cdc100380200099b803370401090504e0099b820040013370290504e008029b8148000894ccc1e4cdc40008010800880118008009129919983c1800a40202a6660f0600290000a4000260080042a6660f060029020099b824820010cc00c00ccdc00012401e266e092080808080203300300333700004901f9b88001371c9101080102040810204080002222533307730690011004132323300100100622533307d00113307e337606ea4018dd3001a5eb7bdb1804c8c8c8c94ccc1f8c1d4cc0300280084cc20804cdd81ba900a374c00e00a2a6660fc66e3c0280084c94ccc1fcc1c4c20004dd50008998418099bb037520166108026102026ea80040104010c94ccc1fcc038004530103d87a8000130723308301374c00297ae032330010010022253330830100113308401337606ea402cdd400525eb7bdb1804c8c8c8c94ccc21004c1eccc04803c0084cc22004cdd81ba900f375001c00a2a6661080266e3c03c0084c94ccc21404c1dcc21804dd50008998448099bb03752020611402610e026ea80040104010c94ccc21404c1dc0045300103d87a8000130783308901375000297ae03370000201c2661100266ec0dd48011ba800133006006003375a610a020066eb8c20c04008c21c04008c214040044cc20804cdd81ba9002374c0026600c00c0066eacc1fc00cdd7183e801184080801183f8009919001191980080080111299983e8008a4c264a6660fc00229309919299983e9837983f1baa3300b375c60fc6104020086eb8c1f80084cc014014cc2040400800458c20804008c20004004c20004004cc1eccdd81ba9002375000297adef6c60225333074337200040022980103d8798000153330743371e0040022980103d87a800014c103d87b80002533307500114a22940cdc099980a1bab303d306d375407800a008a6660d660c200a20102900019980a1bab303d306d3754078006004602c6eb8c1c0048dd6983800799998099919bb0307100130713072001375860e001c01601200266660266466ec0c1c4004c1c4c1c8004dd6183800680580480099192999836182f00088060a999836182e800899299983699b8800d0011001100d375a60e260dc6ea800858c1b0dd5000982618361baa304c306c37540806eb8c1ac010dd718348019bae3069003375c60ce0046466ec0c1ac004c1acc1b0004dd618338051919bb0306a001306a306b001375860ca0126eb4c1a0c1a4008dd6983380098338011bad306500130653065001306400130630013062002323376060c200260c260c40026eb0c180004c180004c16cdd502a1111299982e19b880020011375a60bc008264a6660ba609e00226eb4c17c0144cdc01bad305e0053370666e08cdc080100219b81375a60be00a6eb4c178014004cdc080100191119299982d9826182e1baa0011480004dd69830182e9baa00132533305b304c305c37540022980103d87a800013233001001375660c260bc6ea8008894ccc180004530103d87a8000132323253330603371e00e6eb8c18400c4c14ccc190dd4000a5eb804cc014014008dd69830801183200118310009980200180111191980080080191299982e8008a60103d87a80001323232533305d3371e00c6eb8c17800c4c140cc184dd3000a5eb804cc014014008dd5982f0011830801182f800919801245040014df100000122337140040022c66e0cc120cdc01bad305800500100133230010012253330570011480044c94ccc154c118c158dd5181b982b9baa303730573754604e60ae6ea8c1680084c124cc00c00c0044cc00c00c004c1680040c8dd6982b182b8011bad3055001305500130543054002305200130523052305230523052304e375402e2c6eb4c140c144c144008dd69827800982798278011919bb0304e001304e304f0013758609a002609a0046466ec0c130004c130c134004dd6182580098258011bad3049001304900232337606090002609060920026eb0c11c004c11c008dd7182280098209baa30410043756608660880046084002607c6ea8c0f4004c94ccc0f0c0b8c0f4dd500089919299981f1817181f9baa00113232337600080046050002608660806ea800458c024c0fcdd50009820981f1baa00116533303e01714c103d87a80001302e3303f30400174bd701bac303f3040002375a607c002607c0046eb4c0f0004c0e0dd500e8991998008009bab303c303d303d303d303d303d303d303d303d303d30393754603260726ea806928111299981e00108008991998020021820001999119299981e9816981f1baa003132533303e3030303f3754002264a66607e606060806ea80044c94ccc1000205288800a99981f99b8f375c608860826ea80040f44c8c8c94ccc108c0ccc10cdd5000899b87375a608e609060886ea8c11cc110dd50008010b180998219baa024533304030313041375400a26eb4c114c108dd500289bad3045304630463042375400a64a66608060640022646464646464a66609260980042930b1bad304a001304a002375a609000260900046eb4c118004c108dd50028a999820181880089919299982298240010a4c2c6eb4c118004c108dd50028b18201baa00414a0006608660806ea8004008c108c0fcdd50018008802181d800981e000981f001191919299981d981f001099299981c99b8f375c607400406a2a66607266ebcdd3000a6010ba14873657474696e67730100132533303a302a303b375400226464004a666076605a60786ea80044c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc158c1640084c8c8c8c8c8c8c9263304501123028001325333059304b00113232533305e3061002132498cc11c0048dd70008b1bac305f001305b37540262a6660b260940022a6660b860b66ea804c526161630593754024646eb4c168050dd6982c009981180a181f80a981080b181e80b8b182b800982b8011bad30550013055002375a60a600260a60046eb4c144004c144008dd6982780098278011bac304d001304d002304b001304b002325333048304b304b0011337606094002609460960022c6eb0c124004c124008c11c004c11c008c114004c114008c10c004c10c008c104004c0f4dd50008b181f981e1baa001163005303b37540082c2c6eacc0e800458c0f0004c0f0dd59804181c1baa001300730373754607402646074607660760024a666068604c606a6ea80044c8c8c8c94ccc0ecc0f80084c8c92632533303a302c00113232533303f3042002132498c94ccc0f4c0bc0044c8c94ccc108c1140084c926300d001163043001303f37540042a66607a605c0022646464646464a66608c60920042930b1bad30470013047002375a608a002608a0046eb4c10c004c0fcdd50010b181e9baa001163040001303c37540062a66607460560022a66607a60786ea800c5261616303a3754004600c0062c607800260780046074002606c6ea8004588c94ccc0d0c0980044c8c94ccc0e4c0f000852616375c6074002606c6ea800854ccc0d0c0940044c8c94ccc0e4c0f000852616375c6074002606c6ea800858c0d0dd50009bae3036303337540022c602460646ea8c048c0c8dd5000992999818181098189baa00113253330313023303237540022600660666ea8c0d8c0ccdd50008b1991191980080080191299981b8008a6103d87a80001323253330363375e603060706ea80080144c0a4cc0e80092f5c0266008008002607600460720026eb0c048c0c8dd5180918191baa0133035303237540022c600260626ea80488c0d0c0d4004dd59819181998198011bac30310013031002302f001302f0023756605a002605a605a0046eacc0ac004c0acc0ac008dd6181480098148011bac302700130270023758604a00260426ea8c004c084dd5001118120008a4c26cac6464a66603c60200022646464646464a66604e6054004264931980800091919191919192999817181880109924c64a666058603c00226464a6660626068004264932999817181018179baa0011323232325333035303800213232498c0640094ccc0c8c090c0ccdd500189919191919191919299981e9820001099191924c604200aa666076605a60786ea80184c8c8c8c94ccc108c1140084c8c9263024002302300316304300130430023041001303d375400c2ca666074605860766ea801c4c8c8c8c94ccc104c1100084c926533303e3030303f375400626464a666086608c0042930b1bae3044001304037540062c2c6eb4c108004c108008c100004c0f0dd50038b0b181f000981f001181e000981e001181d000981d001181c000981a1baa0031616303600130360023034001303037540022c2c6064002605c6ea801054ccc0b0c07400454ccc0bcc0b8dd50020a4c2c2c60586ea800c58dd698178009817801181680098168011bad302b00137580022c6eb0c0a0004c0a0008dd6981300098130011bad30240013020375400a2a66603c601e0022a66604260406ea80145261616301e37540084a66603a601e603c6ea80044c8c8c8c94ccc090c09c0084c926325333022301400115333025302437540082930b0a999811180980089919299981398150010a4c2c6eb4c0a0004c090dd50020a99981118090008a99981298121baa00414985858c088dd50018b19299981218118008a999810980918110008a51153330213013302200114a02c2c6ea8c094004c094008c08c004c07cdd50008b119299980e9807800899192999811181280109924c64a666040602400226464a66604a60500042930b1bae3026001302237540042a666040602200226464a66604a60500042930b1bae3026001302237540042c60406ea800458c08c004c07cdd50010a99980e9807000899191919299981218138010991924c6464646464a666054605a0042930b1bad302b001302b002375c605200260520066eb8c09c008c8c8c8c8c94ccc0a4c0b000852616375a605400260540046eb8c0a0004c0a0010dd718130018b1bac3025001302500237586046002603e6ea800854ccc074c0340044c8c94ccc088c0940084c9263232323232323232533302a302d002149858dd6981580098158011bae30290013029003375c604e0046464646464a66605260580042930b1bad302a001302a002375c605000260500066eb8c098008dd618110011bac3020001163253330223025302500113376060480026048604a0022c6eb0c08c004c07cdd50010a99980e9806000899192999811181280109924c6464646464a66604e60540042930b1bad30280013028002375c604c002604c0046eb8c09000458dd61811800980f9baa0021533301d300b0011323253330223025002132498c8c8c8c8c8c8c8c94ccc0a8c0b400852616375a605600260560046eb8c0a4004c0a400cdd718138011919191919299981498160010a4c2c6eb4c0a8004c0a8008dd7181400098140019bae3026002375860440046eb0c08000458c94ccc088c094c0940044cdd81812000981218128008b1bac3023001301f37540042a66603a601400226464a666044604a00426493191bae3022002375c60400022c64a666044604a604a002266ec0c090004c090c09400458dd61811800980f9baa00216301d3754002464a666038601c00226464a66604260480042930b1bae3022001301e37540042a666038601a0022a66603e603c6ea80085261616301c375400260020264a666030601460326ea80044c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc0b4c0c00084c8c8c8c92632533302e30200011323253330333036002132498c06800458c0d0004c0c0dd50058a999817180f8008a99981898181baa00b14985858c0b8dd5005191bad302f00c375a605a016646eb4c0b8034dd69816006191919191bae3030003375c605c004646eb8c0bc00cdd718168011919bb03031001303130320013758605a0206466ec0c0c0004c0c0c0c4004dd618158078b1bad302e001302e002375a605800260580046eb4c0a8004c0a8008c0a0004c0a0008c94ccc094c0a0c0a00044cdd81813800981398140008b1bac3026001302600232533302330263026001133760604a002604a604c0022c6eb0c090004c090008dd69811000981100119299980f98111811000899bb0302100130213022001163758604000260400046eb8c078004c068dd50008b18008009119299980c180500089919299980e98100010a4c2c6eb8c078004c068dd50010a99980c180480089919299980e981000109924c6600c00246600c00c0022c6eb0c078004c068dd50010a99980c180400089919299980e981000109924c6600c00246600c00c0022c6eb0c078004c068dd50010a99980c1803800899191919299980f981100109924c660100024660100100022c6eb0c080004c080008dd6980f000980d1baa00215333018300600113232533301d3020002149858dd6980f000980d1baa00215333018300500113232533301d3020002149858dd6980f000980d1baa002153330183370e900600089919299980e98100010a4c2c6eb8c078004c068dd50010b180c1baa00122323300100100322533301b00114984c8cc00c00cc07c008c00cc074004c064c058dd50071b8748028dc3a40106e1d2006370e90021b8748008dc3a40006e952000370090011b8048004dc7a44100375e980103d8798000371290001ba548008dd70009bae0015734aae7555cf2ab9f5740ae855d12611e581cfcbeb9b48861ad17eb97cff003df115accf7cf18f09b31a2b7a4afb5004c011e581c445b77d214aa36d1b2edeedb8ddad49e0b62d80a1f4b08eb9c8b4c8c0001", - "hash": "760318f4ced18f4983fc9bd63005ef187efb4d270520d47a07673751" + "compiledCode": "593d6d01000033323232323232322322322253232323232323232323232323233301430063015375401c264a66602a6464646464646464646464a66604060220162646464646464a66604c6030604e6ea80044c8c8c8c94ccc0a8c070c0acdd5000899192999816180e18169baa0011323232323232323232533303530273036375400226464646464646464646464a66608066e24dd69822982318231823182318231823182318231823182318211baa004375a600260846ea80504c8c94ccc108c94ccc10ccdc499b8200200200113371000266e08c0dc008c0dc00852819b820020041323232325333046303830473754002264a66608e66ebcc0b8c124dd5000981698249baa00b15333047303833302a3756605a60926ea800408403c54ccc11ccdd7981618249baa0014c107d87b9fd87980ff0013253330483375e605e60946ea8c0bcc128dd500f1820998261ba90224bd700a99982419198008009bac304e304f304f304f304f304f304f304b375401a44a66609a00229404c94ccc12ccdd7981898269baa3032304d3754042607c6609e607c6609e60a000497ae04bd700a511330030030013050001153330480151533304800615333048004100114a029405280b0b299982399b8f375c605c60926ea806c04454ccc11ccdd79ba63304b32533304b304e304e001133760609a002609a609c0022c6eb0c0b4c124dd500da5eb7bdb180dd31982599bb0374e66096609002c66096609202c97ae0374e66096609002a66096609202a97ae04bd6f7b6300a99982399b87375a605860926ea806c0184c94ccc120c004dd6980298251baa01c13001375a606460946ea8070528129998241820000899b890014828270045280a5014a02940585858c12cc120dd50008b1980e9bac302a304737546058608e6ea80fc084ccccccc8c88888894ccc130c1080144cdd79ba7533304c303e00b1533304c303e00c1533304c303e00e1330504c1010200330503750002660a0981010000330504c10101004bd700b0b09982826101030033050375066e00004030cc140dd40071982826010101004bd701ba733300830070064bd7090100008101000081010000810100001119299982799b8f375c606c0060102660a66ea0004cc14cdd419b80375a606a0046eb4c0d000ccc14cc0d0008cc14cc0300092f5c02a66609ea66609e66e3cdd7181b001803099b8f375c606a00600a29404cc14cdd400099829981a801198299ba8337006eb4c0d0008dd6981a00199829980600125eb8054ccc13ccdd79ba7003374e660a66ea40a4cc14cdd4981800c99829a6010101004bd700998299ba800133053303500233053303400233053375060866eb4c0300092f5c02c60846eb4c0d40044cdd79ba7533304c303e00b1533304c303e00c1533304c303e00e1330504c1010200330503750002660a0981010000330504c1010000330504c10101004bd700b0b099828261010400330503750002660a06ea0030cc140dd40071982826010101004bd701ba733300830070064bd709010000810100008101000081010000810100001119299982798229bae30360031330533750002660a66ea0cdc01bad3035002375a6068006660a66068004660a66018004660a6607200497ae01533304f533304f3371e6eb8c0d800c0204cdc79bae303500300714a02660a66ea0004cc14cc0d4008cc14cdd419b80375a60680046eb4c0d000ccc14cc030008cc14cc0e40092f5c02a66609ea66609e66e3cdd7181b001803099b8f375c606a00600a29404cc14cdd400099829981a80119829981a001198299ba8337006eb4c030008dd6981a00199829981c80125eb8054ccc13ccdd79ba7003374e660a66ea40a4cc14cdd4981800c99829a6010101004bd700998299ba800133053303500233053303400233053300c00233053375060866eb4c0e40092f5c02c60846eb4c0d40048c8cc004004008894ccc12c00452f5c0264666444646600200200644a6660a20022006264660a66e9ccc14cdd4803198299ba9375c60a0002660a66ea0dd69828800a5eb80cc00c00cc154008c14c004dd718250009bab304b00133003003304f002304d00122232333001001004003222533304d002100113330030033050002330043758609e0040026eacc0a8c118dd500d1bae3045013375c608c0266eb8c114048dd718230091bad3005304637540304609260946094609400266ebcdd318159bab302c30443754605260886ea80f0dd31919800998009813998239ba901d3304737520166608e9810101004bd701813998239ba901d3304737520126608e98010101004bd701813998239ba901d3304737520106608e6ea00092f5c04464666002002006004444a6660940042002264666008008609c0066644646600200200a44a66609e0022660a066ec0dd48021ba60034bd6f7b630099191919299982818239981c00400109982a19bb037520106e9801c01454ccc140cdc78040010992999828982198291baa001133055337606ea4024c158c14cdd50008020802192999828a99982a0008a5114a0298103d87a80001304433055374c00297ae03233300100100800222253330560021001132333004004305a0033322323300100100522533305b00113305c337606ea4010dd4001a5eb7bdb1804c8c8c8c94ccc170c14ccc1100200084cc180cdd81ba9008375000e00a2a6660b866e3c0200084c94ccc174c13cc178dd500089983099bb0375201260c460be6ea80040104010c94ccc174c13c004530103d87a80001305033061375000297ae03370000e0022660c066ec0dd48011ba800133006006003375a60ba0066eb8c16c008c17c008c174004dd7182a8009bad30560013058002133054337606ea4008dd3000998030030019bab3051003375c609e00460a600460a20026eb8c124004dd5982500098260010b1bad30263043375402aa66608060646e34dd71820807899b81003375a600260846ea8050400c588c114c118c118c118c118c118c118c118004ccc084dd5981218201baa014375c607e0186eb8c100030ccc080dd59811981f9baa013375c607c0186eb8c0fc030c8c8c8c8c94ccc110c11c0084c94ccc108cdc79bae304300203e153330423375e6e980053010ba14873657474696e67730100132533304330333044375400226464004a666088606c608a6ea80044c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc17cc1880084c8c8c8c8c8c8c92633035011230270013253330623054001132325333067306a002132498cc0dc0048dd70008b1bac3068001306437540262a6660c460a60022a6660ca60c86ea804c526161630623754024646eb4c18c050dd69830809981100a181780a981000b181680b8b183000098300011bad305e001305e002375a60b800260b80046eb4c168004c168008dd6982c000982c0011bac30560013056002305400130540023253330513054305400113376060a600260a660a80022c6eb0c148004c148008c140004c140008c138004c138008c130004c130008c128004c118dd50008b182418229baa001163027304437540082c2c6eacc10c00458c114004c114dd5981298209baa00130243040375460866eb0c090c100dd5181298201baa0382533303e3030303f3754002264646464a66608a60900042646493192999822181b000899192999824982600109924c64a66608e607200226464a666098609e0042649318068008b182680098249baa002153330473038001132323232323253330503053002149858dd6982880098288011bad304f001304f002375a609a00260926ea800858c11cdd50008b182500098231baa00315333044303500115333047304637540062930b0b18221baa002300600316304600130460023044001304037540022c464a66607c606000226464a666086608c0042930b1bae3044001304037540042a66607c605e00226464a666086608c0042930b1bae3044001304037540042c607c6ea8004dd7182018208011bae303f001303f002375c607a002660766ea4cc06522104000643b0000013303b37526030002660766ea4cc065221040014df10000014bd7019199b8c48020cdc01b8d0014801c004dca1980c1980c1bae301d30383754603a60706ea8c074c0e0dd5000a4501230032533303733710002904002099b8b00148810016375a603860706ea8c074c0e0dd5000981d181b9baa001163300c37586036606c6ea8c06cc0d8dd5017240006054646464a66606c60500022980103d879800015333036302700113301e00300214c0103d87b8000303637546603a6eb8c0d8010dd7181b0019bae3036002375c606a0046466ec0c0e0004c0e0c0e4004dd6181a0089919bb030370013037303800137586064020a666060604460626ea80104c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc10cc1180084c8c9263253330423034001132325333047304a002132498c05400458c120004c110dd50038a99982118198008a99982298221baa00714985858c108dd5003191919191bae3046003375c6088004646eb8c11400cdd718218011919bb03047001304730480013758608601c6466ec0c118004c118c11c004dd618208068b1bad30440013044002375a60840026084004608000260800046eb4c0f8004c0f8008dd6981e000981e0011bad303a001303a002325333037303a303a0011337606072002607260740022c6eb0c0e0004c0e0008dd7181b00098191baa0041630010012232533303130230011323253330363039002149858dd7181b80098199baa0021533303130220011323253330363039002132498cc0180048cc01801800458dd6181b80098199baa0021533303130210011323253330363039002132498cc0180048cc01801800458dd6181b80098199baa0021533303130200011323232325333038303b002132498cc0200048cc02002000458dd6181c800981c8011bad3037001303337540042a666062603e00226464a66606c60720042930b1bad3037001303337540042a666062603c00226464a66606c60720042930b1bad3037001303337540042a66606266e1d200c0011323253330363039002149858dd7181b80098199baa002163031375400244646600200200644a66606800229309919801801981c0011801981b000981898171baa001163010302d3754002605e60586ea800458cc004dd6180718159baa3010302b375404600c6002002444a66605a0042980103d87a800013232533302c301e0031301f330300024bd7009998028028009810801981880198178011bae302b302837540022c6016604e6ea807cdd6981498150011bad302800130280023233760604e002604e60500026eb0c098004c088dd500d8a9998101809005899192999811180a18119baa001132323253330253017302637540022a66604a602c6660106eacc02cc09cdd5181518139baa00100300213017333008300e3756601e604e6ea8c030c09cdd500f8018010a501632533302800114c0103d87a80001301833029302a0014bd701bac3009302637546016604c6ea8078c01000cdd7181398121baa001163007302337540366eb8c094c088dd500d899192999811180a18119baa00113375e6e98c02cdd5980618121baa3009302437540386e98c018cc098c09cc090dd5000998131ba93003002330264c010120004bd700b180398119baa01b375c604a60446ea806c8cc00922104000de14000001223371400400244464a666042602460446ea8004520001375a604c60466ea8004c94ccc084c048c088dd50008a60103d87a8000132330010013756604e60486ea8008894ccc098004530103d87a8000132323253330263371e00e6eb8c09c00c4c064cc0a8dd4000a5eb804cc014014008dd698138011815001181400099198008008021129998128008a6103d87a8000132323253330253371e00e6eb8c09800c4c060cc0a4dd3000a5eb804cc014014008dd59813001181480118138009199911299981018090008a5eb7bdb1804c8c8cc0040052f5bded8c044a66604c00226604e66ec0dd48031ba60034bd6f7b6300991919192999813980f1980780500109981599bb037520146e9801c01454ccc09ccdc780500109981599bb037520146e9801c00c4cc0accdd81ba9002374c0026600c00c0066eacc0a000cdd71813001181500118140009919800800a5eb7bdb180894ccc0940044cc098cdd81ba9004375000697adef6c601323232325333026301d3300e00800213302a337606ea4020dd40038028a99981319b8f00800213302a337606ea4020dd400380189981519bb037520046ea0004cc01801800cdd698138019bae302500230290023027001375c60080026eb8c00c004dd6980100091810981118110009181018108009180f80091299980d19b9000200114c103d87980001533301a3371e0040022980103d87a800014c103d87b80002323300100100222533301d00114bd6f7b630099191919299980f180a001080189981119bb037520046e98004cc01801800cdd5980f8019bae301d0023021002301f0012301c301d301d301d301d0013016375402029309b2b19299980a980380089919299980d180e8010a4c2c6eb8c06c004c05cdd50080a99980a98030008991919191919299980f181080109924c646464646eb8c08400cdd7180f801191bae3020003375c603c0046466ec0c088004c088c08c004dd6180f0031919bb03021001302130220013758603800a2c6eb4c07c004c07c008dd6980e800980e80119299980d180e980e800899bb0301c001301c301d0011637586036002602e6ea804054ccc054c0140044c8c94ccc068c07400852616375c6036002602e6ea804058c054dd500789991919191911919191299980f191919191919191919191919191919191919192999818981118191baa00113232323232533303630283037375403a264646464646464646464646464646464646464646464a66609866ebcc0b8c138dd50079822998281ba901b4bd7009919191919191919299982a1826000899191919191919191919191919191919191999999111111919191919191919191919191919191999999999980080080a80a009020240000b466646002002444a6660fa66e2400520001002153330800100214bd700999801801984180801183900082b240049000240009000111111111112999843808038a9998420099b8733700004002064264a66610a0266e1c0e8cdc00138008a999842809929998430099b87375a60a46110026ea8204040284c06c0044cdd79ba6001374c661140266ec0dd498189bae30683088013754102026ea0cdc08051bad305230880137541020297adef6c603253330860130773087013754002297adef6c60137566116026110026ea8004cc0bcc8cc004004180894ccc2280400452f5bded8c0264646464a66611602610202004200626611e0266ec0dd48011ba60013300600600337566118020066eb8c22804008c23804008c2300400415054ccc214054ccc21404c1dcc21804dd501c099191919299984480983d9845009baa00113232533308b01307d308c013754002266e3c008dd71848009846809baa0011633003005051375c611c026116026ea800458cc004170144c0040048894ccc23004008530103d87a800013232533308b01307d0031307e3308f01375200497ae01333005005001308001003309001003375c611c020046eb0c22804c21c04dd501c0a51132533308601323253330880130793089013754002264a6661120264a66611a026118020022a6661140260f6611602002294454ccc22804c1f0c22c040045280b0b1baa305b308b01375460d66116026ea817c4cdc4001800899b89003001375a611a026114026ea800452818349844809baa306930890137540ba6eb4c004c22004dd50408089919299984400991919299984580984080815099baf374ea6661160260fa01e2a6661160260fa0222a6661160260fa02026611e029810102003308f0137500806611e029810100003308f014c10101004bd700b0b09984780a610103003308f01375066e00100044cc23c04dd40081984780a6010101004bd701ba7333003300204d4bd709010000810100008101000081010000111929998470099b8f375c60e000605a266124026ea0004cc24804dd419b80375a60c00046eb4c16800ccc24804c168008cc24804c0200092f5c02a66611c02a66611c0266e3cdd71838001815899b8f375c60c000605429404cc24804dd40009984900983000119849009ba8337006eb4c168008dd6982d0019984900980400125eb8054ccc23804cdd79ba7003374e66124026ea4174cc24804dd498020271984900a6010101004bd70099849009ba8001330920130600023309201305a002330920137506104026eb4c0200092f5c02c6102026eb4c1bc0044cdd79ba7533308b01307d00f1533308b01307d0111533308b01307d01013308f014c10102003308f0137500806611e029810100003308f014c10100003308f014c10101004bd700b0b09984780a610104003308f0137500806611e026ea0044cc23c04dd40081984780a6010101004bd701ba7333003300204d4bd7090100008101000081010000810100008101000011192999847009842009bae307000313309201375000266124026ea0cdc01bad3060002375a60b4006661240260b4004661240260100046612402600e00497ae01533308e01533308e013371e6eb8c1c000c0b44cdc79bae306000302c14a0266124026ea0004cc24804c180008cc24804dd419b80375a60b40046eb4c16800ccc24804c020008cc24804c01c0092f5c02a66611c02a66611c0266e3cdd71838001815899b8f375c60c000605429404cc24804dd4000998490098300011984900982d00119849009ba8337006eb4c020008dd6982d0019984900980380125eb8054ccc23804cdd79ba7003374e66124026ea4174cc24804dd498020271984900a6010101004bd70099849009ba8001330920130600023309201305a00233092013008002330920137506104026eb4c01c0092f5c02c6102026eb4c1bc0048cc0dd220104000de140000012323300100100222533308f0100114bd70099199911191980080080191299984a8080088018991984b809ba73309701375200c6612e026ea4dd7184a008009984b809ba8375a612a0200297ae033003003309901002309701001375c611c020026eacc23c04004cc00c00cc24c04008c24404004888c8ccc00400401000c8894ccc2440400840044ccc00c00cc25004008cc010dd61849808010008a9998440099b8704400c15333088013370e07a66e000a801054ccc22004cdc79bae306a308a013754106020902a6661100266ebcdd3198460099299984600984780984780800899bb0308e01001308e01308f0100116375860b46114026ea820c052f5bded8c06e98cc230041192f5bded8c02a6661100266e1cdd698011845009baa0830104215333088013370e6eb4c004c22804dd5041808200a9998440099b87375a60066114026ea820c040f84cdd7982d1845009baa306a308a0137540b260b46114026ea812c5280a5014a029405280b0b0b118468098470098470098470098470080091846009846809846809846808008b11845809846009846009846009846009846009846008008b0b0b19b803370066e080c40c8cdc100101a19b8200103316132323232323232323232533308e01533308e01307f308f01375460e06120026ea8c1c0c24004dd50008a5114a0264a66611e026102026120026ea80044c8c8c8c8c8c8c8c94ccc25c04c94ccc26004c22804c26404dd5000899b8f375c613a026134026ea8004160528984e008030991919199119199980080080b003826911119299985080984980800899299985100984a009851809baa005133330060064c0103d87a80003232323232323253330a9013375e03a615c020082a66615202646464a6661580264a66615a02613c02615c026ea80044c94ccc2b804c94ccc2c804c2c40400454ccc2bc04c28004c2c0040045288a999857809850809858008008a50161637546100026160026ea8c24004c2c004dd5003899b8900100513371000200a6eb4c2c804c2bc04dd50008a51308e0130ae013754611c02615c026ea8014400452819299985600984e809856809baa00113253330ad013253330b10130b001001153330ae01309f0130af0100114a22a66615c02614002615e0200229405858dd5183f9857809baa307f30af01375400c266e2400c0044cdc40018009bad30b10130ae0137540022944c23404c2b404dd5183e9856809baa0043253330ab01309c0130ac013754002264a6661580264a66616002615e020022a66615a02613c02615c02002294454ccc2b404c27c04c2b8040045280b0b1baa307e30ae01375460fc615c026ea82080440044c28404004dd69858009856809baa0011483fa7ede1fa414c23004c2b004dd5183e1856009baa080013253330aa01309b0130ab013754002264a6661560264a66615e02615c020022a66615802613a02615a02002294454ccc2b004c27804c2b4040045280b0b1baa307d30ad013754611a02615a026ea82040440044c27c04004dd69857809856009baa001148000c22c04c2ac04dd51845809855809baa07f153330a901309b0130aa01375401026464a66615602613a026158026ea801c54ccc2ac04ccdca8010009bae30b00130ad01375400e20062c2c6ecc01cdd71857009855809baa008153330a901323233001001083012253330af0100114a0264a66615a0266ebc010c2b804c2c804008528899801801800985900800984e00998568098510099856809857009855809baa0084bd7025eb804004585858c2b404c2b804008c2b004004c2b004004c29c04dd50011854809855008011854008009852009baa30a70130a401375400a0a22c614c026146026ea800c54c8c8c8c8c8ccc29804c25c040184c8c8c8c8c94ccc2ac040184c8c8c8c8c8c8c8c8c8c8c94ccc2d8054ccc2d80404c4c8c94ccc2e004cdd7805185e80801099baf00700114a0617802617a020026170026ea80844c8c94ccc2e004cdd7805185e80801099baf00700114a0617802617a02617a020026170026ea80a454ccc2d8054ccc2d804cdc780202a899b8f00205414a02a66616c0266e3cdd7184c008070298a99985b0099b8f375c61100201c0a426666666666660840080040a60a407807609a02400201400c444a6661720266ebcdd30049ba6001153330b901337126eb4c2140404400c4cc038c060008cdc081f0018b0b0b0b0a99985b00a99985b0099b8f00405313371e0040a4294054ccc2d804cdc79bae30980100e055153330b6013371e6eb8c220040381504cccccccccccc1080100081541500ec0f01300480040280188894ccc2e404cdd79ba6009374c0022a6661720266e24dd698428080880189980719b8103f0033017002161616161616375a6174026176020046eb8c2e404004c2e404030dd7185b80805985b00985b808011bab30b50100130b50100230b30100130af0137540086eacc2c404c2c804c2b804dd500f9119998090010008188018b1858008151857008149bac30ad0130ae0100237586158020026150026ea802054ccc29804c258040184c8c8c94ccc2a4040104c8c8c94ccc2b004cdc79bae308e0100304b153330ac013371e6eb8c1f800c12854ccc2b004cdc79bae308e01002049153330ac013371e6eb8c1f80081204c94ccc2b404c0ec0044c8c8c8c8c8c94ccc2cc04c10400454ccc2cc04cdd7984280985a809baa00c374c666608c666608c666608c666608c0106eb8c25404028dd718428080518200019bae309501009375c610a02012608000491100488100304000f0820104c001153330b30153330b3010101323253330b5013375e612e02616e026ea8038c2e8040084cdd7984080985b809baa00e00114a0617202617402002616a026ea80784c8c94ccc2d404cdd7984b80985b809baa00e30ba0100213375e610202616e026ea8038004528185c80985d00985d00800985a809baa02613333018301200330110023370006e0020162c2c2c66e0ccdc100101b01c1bad30b301002375a616202002a66615e0266e2000c0044cdd81ba8003375061460266e0cc29004cdc101a00181a899bb037500026ea0008cdc199b820010340333303c375a60f20066660ac0046eb8c23c0400cdd7183f8018b1981d9bad3078003337026660aa0026eb8c2380400cdd7183f001a999856009851009bae308e010031337009040497a008040a40002c2c2c2c6eacc2c004c2c404c2b404dd500f1bac30ac0100437586154020062c615c0205061580204e6466ec0c2b004004c2b004c2b404004dd61855809854009baa008153330a601309501006132323253330a9010041323232323253330ae013371e00a0fa2a66615c0266e3c00c11c4c8c8c94ccc2c404cdd79841809859809baa00a374c666608866660886666088666608800801000c607c00691100488100303e00d05004f00204e04d001153330b10153330b10100e1323253330b3013375e612a02616a026ea8030c2e0040084cdd7983f985a809baa00c00114a0616e026170020026166026ea80704c8c94ccc2cc04cdd7984a80985a809baa00c30b80100213375e60fe616a026ea8030004528185b80985c00985c008009859809baa024133330163370206e00466e040d8004cdc081a8018048b0b19b833370400406a06866e0ccdc100081a8199981e80119982b8008028018b0b1bab30b20130b30130af0137540406eb4c2c404c2c804008dd71858008009858008021bae30ae010031630ae0102830ac0102737586156026150026ea802054ccc29804c250040184c8c8c94ccc2a4040104c8c8c8c8c8c8c8c8c8c8c94ccc2d004cdc78040298a99985a0099b8f006052153330b4013371e0080a22a6661680266e3c0081404c8c94ccc2d8054ccc2d804ccc2d8040052825114a22a66616c0266ebcc22004c2e004dd50079ba6002153330b6010131323253330b8013375e6134026174026ea8044c2f4040084cdd7984200985d009baa01100114a0617802617a020026170026ea80844c8c94ccc2e004cdd7984d00985d009baa01130bd0100213375e6108026174026ea8044004528185e00985e80985e80800985c009baa02914a026644a666170020062666603a0040020780202666603a004002078070602a6eb4c20804dd6185b80808180a1bad30820137586170020202c66616a0266ebcdd3000a6101a0004a0944cccc11ccccc11ccccc11c02d22010048810030410100080063041005004002304100116161616375a6170026172020046eb8c2dc04004c2dc04018dd7185a808029bad30b40130b501002375c6166020026166020066eb8c2c404008dd61856808029bac30ab010043756615c02615e026156026ea807058c2b8040a0c2b00409cc8cdd81856008009856009856808009bac30ab0130a80137540102646464a666152020082a66615202a6661520266ebcc1ecc2ac04dd50011ba6333303c333303c375660f66156026ea8071221004881003036005375c6154020066eb8c2ac0400d2002153330a90100613375e6116026156026ea8008c2b804c2ac04dd500a0a5014a02666601c05e05c05a0022c2c615c0205061580204e6466ec0c2b004004c2b004c2b404004dd61855809854009baa0083371200202466e00144014c25404c29004dd50071b80027370004e6142026ea8008dd59836184e009baa00d222233333333333025025004003002019309201018014001016006005375a6136020046eb4c264040054ccc25c04c22404c26004dd5000899bb0375002a6ea0c22c040504cdd81ba8308b0101537500282c6136026138020046134020026134020046eb4c26004004c26004c26004004c24c04dd50012999848009841009848809baa0011323232323232323232323232533309f0130a201002132323232498c21004018c94ccc27c04c244040044c8c8c8c94ccc29804c2a4040084c8c9263253330a501309701001153330a80130a70137540062930b0a99985280984b00800899192999855009856808010a4c2c6eb8c2ac04004c29c04dd50018a99985280984a80800899192999855009856808010a4c2c615602002614e026ea800c58c29404dd500118380018b1853808009853808011852808009850809baa0081533309f01309001001153330a20130a10137540102930b0b184f809baa00730870100a30820100b1630a00100130a001002309e01001309e01002309c01001309c01002375a613402002613402004613002002613002004612c020026124026ea800458c25004c24404dd50008b19192999848009841008008a60103d87a8000153330900130810100113232330010010652253330960100114c0103d87a800013232325333096013371e00c6eb8c25c0400c4c22404cc268040052f5c026600a00a004612e020046134020046130020026eb8c25404c24804dd500109841809984a00984a809849009baa0024bd701848009baa001305a30900137540022c612402612602004612202002611a026ea8c24004008c240040054ccc22404cdc480580189980880519b8100300b1330110690035333088013080010021323232533308b013371066e18028008cdc300080108008b19b80009002337049002000a99199844809800a4020260360062a6661120260029010099b824820010c06ccdc0001a401e2a6661120260029018099b82482020020c06ccdc0001a403e2a6661120260029020099b8248202020040c06ccdc0001a405e2a6661120260029028099b824820202020080c06ccdc0001a407e260320066e2000858c23004c2340400cdd69845808011845808041bac3089010073001001222533307a33712900f000899980180198400098400098400098400098400098400098400098400098400098400098400098400098400098400098400080119b800014807454ccc1e8cdc4a401c002266600600661000261000261000261000261000261000261000200466e00005200d13300400200130010012225333078306a00110021333003003307e002306d001222222222222323232533308301301100113232323232533308801301600115333088015333088013371000c018266e1ccdc199b8200500c3370000866e080300200044cdc38030060a9998440099b883370666e0400c014cdc08010040008999804800803199980d999980d999980d80580a009980a80324500488100301500d0120110011616163370600400266e00008cdc100200319b820020033370401890504e0099b8200a00316533308201307800e13370200200e200266e04ccc0a8010034030ccc0a800c034030cdc0a4141380200c6e0520003710900011299983999b880010021001100230010012253233307230014804054ccc1c8c00520001480004c01000854ccc1c8c00520401337049040021980180199b800024803c4cdc124101010100406600600666e00009203f37100026e392210801020408102040800022225333071306300110041323233001001006225333077001133078337606ea4018dd3001a5eb7bdb1804c8c8c8c94ccc1e0c1bccc0300280084cc1f0cdd81ba900a374c00e00a2a6660f066e3c0280084c94ccc1e4c1acc1e8dd500089983e99bb0375201660fc60f66ea80040104010c94ccc1e4c038004530103d87a80001306c3307d374c00297ae0323300100100222533307d00113307e337606ea402cdd400525eb7bdb1804c8c8c8c94ccc1f8c1d4cc04803c0084cc20804cdd81ba900f375001c00a2a6660fc66e3c03c0084c94ccc1fcc1c4c20004dd50008998418099bb037520206108026102026ea80040104010c94ccc1fcc1c40045300103d87a8000130723308301375000297ae03370000201c2661040266ec0dd48011ba800133006006003375a60fe0066eb8c1f4008c20404008c1fc0044cc1f0cdd81ba9002374c0026600c00c0066eacc1e400cdd7183b801183d801183c8009919001191980080080111299983b8008a4c264a6660f000229309919299983b9834983c1baa3300b375c60f060f80086eb8c1e00084cc014014cc1ec00800458c1f0008c1e8004c1e8004cc1d4cdd81ba9002375000297adef6c6022533306e337200040022980103d87980001533306e3371e0040022980103d87a800014c103d87b80002533306f00114a22940cdc09998071bab30373067375406c008006a6660ca60b6008200e290001998071bab30373067375406c00400260206eb8c1a8034dd698350051bad306a009375a60d40106eb8c198010dd718320019bae3064003375c60c40046466ec0c198004c198c19c004dd618310031919bb0306500130653066001375860c000a6eb4c18cc190c190c190004c18c004c188004c184008c8cdd81830000983018308009bac305f001305f001305a37540a644464a6660b6609860b86ea8004520001375a60c060ba6ea8004c94ccc16cc130c170dd50008a60103d87a800013233001001375660c260bc6ea8008894ccc180004530103d87a8000132323253330603371e00e6eb8c18400c4c14ccc190dd4000a5eb804cc014014008dd69830801183200118310009980200180111191980080080191299982e8008a60103d87a80001323232533305d3371e00c6eb8c17800c4c140cc184dd3000a5eb804cc014014008dd5982f0011830801182f800919801245040014df100000122337140040022c66e0cc120cdc01bad305800500100133230010012253330570011480044c94ccc154c118c158dd5181b982b9baa303730573754604e60ae6ea8c1680084c124cc00c00c0044cc00c00c004c1680040c8dd6982b182b8011bad3055001305500130543054002305200130523052305230523052304e375402e2c6eb4c140c144008dd69827800982798278011bad304d001304d002375a609600260960046eb4c124004c124008c8cdd81824000982418248009bac30470013047002375c608a00260826ea8c104010dd5982198220011821000981f1baa303d00132533303c302e303d375400226464a66607c605c607e6ea80044c8c8cdd80020011814000982198201baa001163009303f37540026082607c6ea8004594ccc0f805c5300103d87a80001302e3303f30400174bd701bac303f3040002375a607c002607c0046eb4c0f0004c0e0dd500e8991998008009bab303c303d303d303d303d303d303d303d303d303d30393754603260726ea806928111299981e00108008991998020021820001999119299981e9816981f1baa003132533303e3030303f3754002264a66607e606060806ea80044c94ccc1000205288800a99981f99b8f375c608860826ea80040f44c8cdc3992999820981918211baa001133223233300100100348000888c94ccc11ccdd7981498249baa304c00300510021333004004001303b002304c0023758604660866ea8c08cc10cdd5012182318219baa00116301230423754046a666080606260826ea80144dd6982298211baa0051375a608a608c608c60846ea8014c94ccc100c0c80044c8c8c8c8c8c94ccc124c13000852616375a609400260940046eb4c120004c120008dd6982300098211baa0051533304030310011323253330453048002149858dd6982300098211baa0051630403754008294000cc10cc100dd50008011821181f9baa0030011004303b001303c001303e002323232533303b303e00213253330393371e6eb8c0e80080d454ccc0e4cdd79ba60014c010ba14873657474696e67730100132533303a302a303b375400226464004a666076605a60786ea80044c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc158c1640084c8c8c8c8c8c8c9263304501123028001325333059304b00113232533305e3061002132498cc11c0048dd70008b1bac305f001305b37540262a6660b260940022a6660b860b66ea804c526161630593754024646eb4c168050dd6982c009981180a181f80a981080b181e80b8b182b800982b8011bad30550013055002375a60a600260a60046eb4c144004c144008dd6982780098278011bac304d001304d002304b001304b002325333048304b304b0011337606094002609460960022c6eb0c124004c124008c11c004c11c008c114004c114008c10c004c10c008c104004c0f4dd50008b181f981e1baa001163005303b37540082c2c6eacc0e800458c0f0004c0f0dd59804181c1baa001300730373754607402646074607660760024a666068604c606a6ea80044c8c8c8c94ccc0ecc0f80084c8c92632533303a302c00113232533303f3042002132498c94ccc0f4c0bc0044c8c94ccc108c1140084c926300d001163043001303f37540042a66607a605c0022646464646464a66608c60920042930b1bad30470013047002375a608a002608a0046eb4c10c004c0fcdd50010b181e9baa001163040001303c37540062a66607460560022a66607a60786ea800c5261616303a3754004600c0062c607800260780046074002606c6ea8004588c94ccc0d0c0980044c8c94ccc0e4c0f000852616375c6074002606c6ea800854ccc0d0c0940044c8c94ccc0e4c0f000852616375c6074002606c6ea800858c0d0dd50009bae3036303337540022c602460646ea8c048c0c8dd5000992999818181098189baa00113253330313023303237540022600660666ea8c0d8c0ccdd50008b1991191980080080191299981b8008a6103d87a80001323253330363375e603060706ea80080144c0a4cc0e80092f5c0266008008002607600460720026eb0c048c0c8dd5180918191baa0133035303237540022c600260626ea80488c0d0c0d4004dd59819181998198011bac30310013031002302f001302f0023756605a002605a605a0046eacc0ac004c0acc0ac008dd6181480098148011bac302700130270023758604a00260426ea8c004c084dd5001118120008a4c26cac6464a66603c60200022646464646464a66604e6054004264931980800091919191919192999817181880109924c64a666058603c00226464a6660626068004264932999817181018179baa0011323232325333035303800213232498c0640094ccc0c8c090c0ccdd500189919191919191919299981e9820001099191924c604200aa666076605a60786ea80184c8c8c8c94ccc108c1140084c8c9263024002302300316304300130430023041001303d375400c2ca666074605860766ea801c4c8c8c8c94ccc104c1100084c926533303e3030303f375400626464a666086608c0042930b1bae3044001304037540062c2c6eb4c108004c108008c100004c0f0dd50038b0b181f000981f001181e000981e001181d000981d001181c000981a1baa0031616303600130360023034001303037540022c2c6064002605c6ea801054ccc0b0c07400454ccc0bcc0b8dd50020a4c2c2c60586ea800c58dd698178009817801181680098168011bad302b00137580022c6eb0c0a0004c0a0008dd6981300098130011bad30240013020375400a2a66603c601e0022a66604260406ea80145261616301e37540084a66603a601e603c6ea80044c8c8c8c94ccc090c09c0084c926325333022301400115333025302437540082930b0a999811180980089919299981398150010a4c2c6eb4c0a0004c090dd50020a99981118090008a99981298121baa00414985858c088dd50018b19299981218118008a999810980918110008a51153330213013302200114a02c2c6ea8c094004c094008c08c004c07cdd50008b119299980e9807800899192999811181280109924c64a666040602400226464a66604a60500042930b1bae3026001302237540042a666040602200226464a66604a60500042930b1bae3026001302237540042c60406ea800458c08c004c07cdd50010a99980e9807000899191919299981218138010991924c6464646464a666054605a0042930b1bad302b001302b002375c605200260520066eb8c09c008c8c8c8c8c94ccc0a4c0b000852616375a605400260540046eb8c0a0004c0a0010dd718130018b1bac3025001302500237586046002603e6ea800854ccc074c0340044c8c94ccc088c0940084c9263232323232323232533302a302d002149858dd6981580098158011bae30290013029003375c604e0046464646464a66605260580042930b1bad302a001302a002375c605000260500066eb8c098008dd618110011bac3020001163253330223025302500113376060480026048604a0022c6eb0c08c004c07cdd50010a99980e9806000899192999811181280109924c6464646464a66604e60540042930b1bad30280013028002375c604c002604c0046eb8c09000458dd61811800980f9baa0021533301d300b0011323253330223025002132498c8c8c8c8c8c8c8c94ccc0a8c0b400852616375a605600260560046eb8c0a4004c0a400cdd718138011919191919299981498160010a4c2c6eb4c0a8004c0a8008dd7181400098140019bae3026002375860440046eb0c08000458c94ccc088c094c0940044cdd81812000981218128008b1bac3023001301f37540042a66603a601400226464a666044604a00426493191bae3022002375c60400022c64a666044604a604a002266ec0c090004c090c09400458dd61811800980f9baa00216301d3754002464a666038601c00226464a66604260480042930b1bae3022001301e37540042a666038601a0022a66603e603c6ea80085261616301c375400260020264a666030601460326ea80044c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc0acc0b80084c8c92632533302a301c00113232533302f3032002132498c05800458c0c0004c0b0dd50038a999815180d8008a99981698161baa00714985858c0a8dd5003191919191bae302e003375c6058004646eb8c0b400cdd718158011919bb0302f001302f30300013758605601c6466ec0c0b8004c0b8c0bc004dd618148068b1bad302c001302c002375a60540026054004605000260500046eb4c098004c098008dd6981200098120011bad3022001302200232533301f302230220011337606042002604260440022c6eb0c080004c080008dd7180f000980d1baa00116300100122325333018300a00113232533301d3020002149858dd7180f000980d1baa00215333018300900113232533301d3020002132498cc0180048cc01801800458dd6180f000980d1baa00215333018300800113232533301d3020002132498cc0180048cc01801800458dd6180f000980d1baa002153330183007001132323232533301f3022002132498cc0200048cc02002000458dd6181000098100011bad301e001301a37540042a666030600c00226464a66603a60400042930b1bad301e001301a37540042a666030600a00226464a66603a60400042930b1bad301e001301a37540042a66603066e1d200c00113232533301d3020002149858dd7180f000980d1baa002163018375400244646600200200644a66603600229309919801801980f8011801980e800980c980b1baa00e370e90051b8748020dc3a400c6e1d2004370e90011b8748000dd2a40006e012002370090009b8f488100375e980103d8798000371290001ba548008dd70009bae0015734aae7555cf2ab9f5740ae855d12611e581c0bf89b13dc30d812fd4fc25122325e8b02b48b7168e30202dcdda59a004c011e581c61ed2a57b7baece734dea4af48c089ac2d3d0fe09fd45023120cc2620001", + "hash": "bd4e886ee59548d9d6a2be480a4b468da8e8177f52ba6ce05b7b24a3" }, { "title": "pool.mint", @@ -109,8 +110,8 @@ "$ref": "#/definitions/types~1pool~1PoolMintRedeemer" } }, - "compiledCode": "593e5d01000033323232323232322322322253232323232323232323232323233301430063015375401c264a66602a6464646464646464646464a66604060220162646464646464a66604c6030604e6ea80044c8c8c8c94ccc0a8c070c0acdd5000899192999816180e18169baa0011323232323232323232533303530273036375400226464646464646464646464a66608066e24dd69822982318231823182318231823182318231823182318211baa004375a600260846ea80504c8c94ccc108c94ccc10ccdc499b8200200200113371000266e08c0dc008c0dc00852819b820020041323232325333046303830473754002264a66608e66ebcc0b8c124dd5000981698249baa00b15333047303833302a3756605a60926ea800408403c54ccc11ccdd7981618249baa0014c107d87b9fd87980ff001323253330493375e606060966ea8c0c0c12cdd500f9821198269ba90234bd700a99982499198008009bac3003304c375401c44a66609c00229404c94ccc130cdd7981918271baa3033304e3754044607e660a0607e660a060a200497ae04bd700a511330030030013051001153330490161533304900715333049005100114a029405280b0b299982419b8f375c605e60946ea807004854ccc120cdd79ba63304c32533304c304f304f001133760609c002609c609e0022c6eb0c0b8c128dd500e25eb7bdb180dd31982619bb0374e66098609202e66098609402e97ae0374e66098609202c66098609402c97ae04bd6f7b6300a99982419b87375a605a60946ea807001c54ccc120cdc49bad3001304a37540386eb4c134c138c138c138c138c138c138c138c128dd500e0992999824980099299982698281828000899bb0304f001304f3050001163758600c60966ea80744c004c94ccc134c140c1400044cdd81827800982798280008b1bac3033304b375403a294094ccc124c104dd698250008a99982498209bad304b00115333049337126eb4c12800520a09c011337126eb4c12c00520a09c0114a029405280a5014a02940528118269827182718271827182718270008b0b0b182598241baa001163301d37586054608e6ea8c0b0c11cdd501f810999999991911111129998261821002899baf374e660a098101030033050375066e00004030cc140dd40071982826010101004bd701ba733300830070064bd7090100008101000081010000810100001119299982799b8f375c606c0060102660a66ea0004cc14cdd419b80375a606a0046eb4c0d000ccc14cc0d0008cc14cc0300092f5c02a66609ea66609e66e3cdd7181b001803099b8f375c606a00600a29404cc14cdd400099829981a801198299ba8337006eb4c0d0008dd6981a00199829980600125eb8054ccc13ccdd79ba7003374e660a66ea40a4cc14cdd4981800c99829a6010101004bd700998299ba800133053303500233053303400233053375060866eb4c0300092f5c02c60846eb4c0d40044cdd79ba7330504c01010400330503750002660a06ea0030cc140dd40071982826010101004bd701ba733300830070064bd709010000810100008101000081010000810100001119299982798229bae30360031330533750002660a66ea0cdc01bad3035002375a6068006660a66068004660a66018004660a6607200497ae01533304f533304f3371e6eb8c0d800c0204cdc79bae303500300714a02660a66ea0004cc14cc0d4008cc14cdd419b80375a60680046eb4c0d000ccc14cc030008cc14cc0e40092f5c02a66609ea66609e66e3cdd7181b001803099b8f375c606a00600a29404cc14cdd400099829981a80119829981a001198299ba8337006eb4c030008dd6981a00199829981c80125eb8054ccc13ccdd79ba7003374e660a66ea40a4cc14cdd4981800c99829a6010101004bd700998299ba800133053303500233053303400233053300c00233053375060866eb4c0e40092f5c02c60846eb4c0d40048c8cc004004008894ccc12c00452f5c0264666444646600200200644a6660a20022006264660a66e9ccc14cdd4803198299ba9375c60a0002660a66ea0dd69828800a5eb80cc00c00cc154008c14c004dd718250009bab304b00133003003304f002304d00122232333001001004003222533304d002100113330030033050002330043758609e0040026eacc0a8c118dd500d1bae3045013375c608c0266eb8c114048dd718230091bad3005304637540304609260946094609400266ebcdd318159bab302c30443754605260886ea80f0dd31919800998009813998239ba901d3304737520166608e9810101004bd701813998239ba901d3304737520126608e98010101004bd701813998239ba901d3304737520106608e6ea00092f5c04464666002002006004444a6660940042002264666008008609c0066644646600200200a44a66609e0022660a066ec0dd48021ba60034bd6f7b630099191919299982818239981c00400109982a19bb037520106e9801c01454ccc140cdc78040010992999828982198291baa001133055337606ea4024c158c14cdd50008020802192999828a99982a0008a5114a0298103d87a80001304433055374c00297ae03233300100100800222253330560021001132333004004305a0033322323300100100522533305b00113305c337606ea4010dd4001a5eb7bdb1804c8c8c8c94ccc170c14ccc1100200084cc180cdd81ba9008375000e00a2a6660b866e3c0200084c94ccc174c13cc178dd500089983099bb0375201260c460be6ea80040104010c94ccc174c13c004530103d87a80001305033061375000297ae03370000e0022660c066ec0dd48011ba800133006006003375a60ba0066eb8c16c008c17c008c174004dd7182a8009bad30560013058002133054337606ea4008dd3000998030030019bab3051003375c609e00460a600460a20026eb8c124004dd5982500098260010b1bad30263043375402aa66608060646e34dd71820807899b81003375a600260846ea8050400c588c114c118c118c118c118c118c118c118c118004ccc084dd5981218201baa014375c607e0186eb8c100030ccc080dd59811981f9baa013375c607c0186eb8c0fc030c8c8c8c8c94ccc110c11c0084c94ccc108cdc79bae304300203e153330423375e6e980053010ba14873657474696e67730100132533304330333044375400226464004a666088606c608a6ea80044c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc17cc1880084c8c8c8c8c8c8c92633035011230270013253330623054001132325333067306a002132498cc0dc0048dd70008b1bac3068001306437540262a6660c460a60022a6660ca60c86ea804c526161630623754024646eb4c18c050dd69830809981100a181780a981000b181680b8b183000098300011bad305e001305e002375a60b800260b80046eb4c168004c168008dd6982c000982c0011bac30560013056002305400130540023253330513054305400113376060a600260a660a80022c6eb0c148004c148008c140004c140008c138004c138008c130004c130008c128004c118dd50008b182418229baa001163027304437540082c2c6eacc10c00458c114004c114dd5981298209baa00130243040375460866eb0c090c100dd5181298201baa0382533303e3030303f3754002264646464a66608a60900042646493192999822181b000899192999824982600109924c64a66608e607200226464a666098609e0042649318068008b182680098249baa002153330473038001132323232323253330503053002149858dd6982880098288011bad304f001304f002375a609a00260926ea800858c11cdd50008b182500098231baa00315333044303500115333047304637540062930b0b18221baa002300600316304600130460023044001304037540022c464a66607c606000226464a666086608c0042930b1bae3044001304037540042a66607c605e00226464a666086608c0042930b1bae3044001304037540042c607c6ea8004dd7182018208011bae303f001303f002375c607a002660766ea4cc06522104000643b0000013303b37526030002660766ea4cc065221040014df10000014bd7019199b8c48020cdc01b8d0014801c004dca1980c1980c1bae301d30383754603a60706ea8c074c0e0dd5000a4501230032533303733710002904002099b8b00148810016375a603860706ea8c074c0e0dd5000981d181b9baa001163300c37586036606c6ea8c06cc0d8dd5017240006054646464a66606c60500022980103d879800015333036302700113301e00300214c0103d87b8000303637546603a6eb8c0d8010dd7181b0019bae3036002375c606a0046466ec0c0e0004c0e0c0e4004dd6181a0089919bb030370013037303800137586064020a666060604460626ea80104c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc114c1200084c8c8c8c926325333046303800113232533304b304e002132498c06400458c130004c120dd50058a999823181b8008a99982498241baa00b14985858c118dd5005191bad304700c375a608a016646eb4c118034dd69822006191919191bae3048003375c608c004646eb8c11c00cdd718228011919bb030490013049304a0013758608a0206466ec0c120004c120c124004dd618218078b1bad30460013046002375a608800260880046eb4c108004c108008c100004c100008c94ccc0f4c100c1000044cdd8181f800981f98200008b1bac303e001303e00232533303b303e303e001133760607a002607a607c0022c6eb0c0f0004c0f0008dd6981d000981d00119299981b981d181d000899bb030390013039303a001163758607000260700046eb8c0d8004c0c8dd50020b180080091192999818981180089919299981b181c8010a4c2c6eb8c0dc004c0ccdd50010a999818981100089919299981b181c80109924c6600c00246600c00c0022c6eb0c0dc004c0ccdd50010a999818981080089919299981b181c80109924c6600c00246600c00c0022c6eb0c0dc004c0ccdd50010a9998189810000899191919299981c181d80109924c660100024660100100022c6eb0c0e4004c0e4008dd6981b80098199baa00215333031301f0011323253330363039002149858dd6981b80098199baa00215333031301e0011323253330363039002149858dd6981b80098199baa002153330313370e900600089919299981b181c8010a4c2c6eb8c0dc004c0ccdd50010b18189baa00122323300100100322533303400114984c8cc00c00cc0e0008c00cc0d8004c0c4c0b8dd50008b180818169baa001302f302c37540022c660026eb0c038c0acdd5180818159baa0230063001001222533302d00214c0103d87a800013232533302c301e0031301f330300024bd7009998028028009810801981880198178011bae302b302837540022c6016604e6ea807cdd6981498150011bad302800130280023233760604e002604e60500026eb0c098004c088dd500d8a9998101809005899192999811180a18119baa001132323253330253017302637540022a66604a602c6660106eacc02cc09cdd5181518139baa00100300213017333008300e3756601e604e6ea8c030c09cdd500f8018010a501632533302800114c0103d87a80001301833029302a0014bd701bac3009302637546016604c6ea8078c01000cdd7181398121baa001163007302337540366eb8c094c088dd500d899192999811180a18119baa00113375e6e98c02cdd5980618121baa3009302437540386e98c018cc098c09cc090dd5000998131ba93003002330264c010120004bd700b180398119baa01b375c604a60446ea806c8cc00922104000de14000001223371400400244464a666042602460446ea8004520001375a604c60466ea8004c94ccc084c048c088dd50008a60103d87a8000132330010013756604e60486ea8008894ccc098004530103d87a8000132323253330263371e00e6eb8c09c00c4c064cc0a8dd4000a5eb804cc014014008dd698138011815001181400099198008008021129998128008a6103d87a8000132323253330253371e00e6eb8c09800c4c060cc0a4dd3000a5eb804cc014014008dd59813001181480118138009199911299981018090008a5eb7bdb1804c8c8cc0040052f5bded8c044a66604c00226604e66ec0dd48031ba60034bd6f7b6300991919192999813980f1980780500109981599bb037520146e9801c01454ccc09ccdc780500109981599bb037520146e9801c00c4cc0accdd81ba9002374c0026600c00c0066eacc0a000cdd71813001181500118140009919800800a5eb7bdb180894ccc0940044cc098cdd81ba9004375000697adef6c601323232325333026301d3300e00800213302a337606ea4020dd40038028a99981319b8f00800213302a337606ea4020dd400380189981519bb037520046ea0004cc01801800cdd698138019bae302500230290023027001375c60080026eb8c00c004dd6980100091810981118110009181018108009180f80091299980d19b9000200114c103d87980001533301a3371e0040022980103d87a800014c103d87b80002323300100100222533301d00114bd6f7b630099191919299980f180a001080189981119bb037520046e98004cc01801800cdd5980f8019bae301d0023021002301f0012301c301d301d301d301d0013016375402029309b2b19299980a980380089919299980d180e8010a4c2c6eb8c06c004c05cdd50080a99980a98030008991919191919299980f181080109924c646464646eb8c08400cdd7180f801191bae3020003375c603c0046466ec0c088004c088c08c004dd6180f0031919bb03021001302130220013758603800a2c6eb4c07c004c07c008dd6980e800980e80119299980d180e980e800899bb0301c001301c301d0011637586036002602e6ea804054ccc054c0140044c8c94ccc068c07400852616375c6036002602e6ea804058c054dd500789991919191911919191299980f191919191919191919191919191919191919192999818981118191baa00113232323232533303630283037375403a264646464646464646464646464646464646464646464a66609866ebcc0b8c138dd50079822998281ba901b4bd7009919191919191919299982a18260008991919191919191919191919191919191919191919191919999991111119191919191919191919191919191999999999980080080a009808822a40000be66646002002444a6661040266e2400520001002153330850100214bd700999801801984400801183b80082da40049000240009000111111111112999846008038a9998448099b873370000400206e264a6661140266e1c0fccdc00138008a999845009929998458099b87375a60ae611a026ea8218040284c0680044cdd79ba6001374c6611e0266ec0dd4981b1bae306d308d01375410c026ea0cdc08051bad3057308d01375410c0297adef6c6032533308b01307c308c013754002297adef6c6013756612002611a026ea8004cc0d0c8cc004004194894ccc23c0400452f5bded8c0264646464a66612002610c0200420062661280266ec0dd48011ba60013300600600337566122020066eb8c23c04008c24c04008c2440400416454ccc228054ccc22804c1f0c22c04dd501e8991919192999847009840009847809baa001132325333090013082013091013754002266e3c008dd7184a809849009baa0011633003005056375c6126026120026ea800458cc004184158c0040048894ccc24404008530103d87a80001323253330900130820100313083013309401375200497ae01333005005001308501003309501003375c6126020046eb0c23c04c23004dd501e8a51132533308b013232533308d01307e308e013754002264a66611c0264a666124026122020022a66611e02610002612002002294454ccc23c04c20404c240040045280b0b1baa3060309001375460e06120026ea81904cdc4001800899b89003001375a612402611e026ea800452818371847009baa306e308e0137540c46eb4c004c23404dd50430089919299984680991919299984800984300815099baf374e661280298010103003309401375066e00114044cc25004dd40081984a00a6010101004bd701ba733300330020524bd709010000810100008101000081010000111929998498099b8f375c60ea00605a26612e026ea0004cc25c04dd419b80375a60ca0046eb4c17c00ccc25c04c17c008cc25c04c0200092f5c02a66612602a6661260266e3cdd7183a801815899b8f375c60ca00605429404cc25c04dd40009984b8098328011984b809ba8337006eb4c17c008dd6982f8019984b80980400125eb8054ccc24c04cdd79ba7003374e6612e026ea4188cc25c04dd498020299984b80a6010101004bd7009984b809ba8001330970130650023309701305f00233097013750610e026eb4c0200092f5c02c610c026eb4c1d00044cdd79ba733094014c010104003309401375008a66128026ea0044cc25004dd40081984a00a6010101004bd701ba733300330020524bd7090100008101000081010000810100008101000011192999849809844809bae30750031330970137500026612e026ea0cdc01bad3065002375a60be0066612e0260be0046612e0260100046612e02600e00497ae015333093015333093013371e6eb8c1d400c0b44cdc79bae306500302c14a026612e026ea0004cc25c04c194008cc25c04dd419b80375a60be0046eb4c17c00ccc25c04c020008cc25c04c01c0092f5c02a66612602a6661260266e3cdd7183a801815899b8f375c60ca00605429404cc25c04dd40009984b8098328011984b80982f8011984b809ba8337006eb4c020008dd6982f8019984b80980380125eb8054ccc24c04cdd79ba7003374e6612e026ea4188cc25c04dd498020299984b80a6010101004bd7009984b809ba8001330970130650023309701305f0023309701300800233097013750610e026eb4c01c0092f5c02c610c026eb4c1d00048cc0f1220104000de14000001232330010010022253330940100114bd70099199911191980080080191299984d0080088018991984e009ba73309c01375200c66138026ea4dd7184c808009984e009ba8375a61340200297ae033003003309e01002309c01001375c6126020026eacc25004004cc00c00cc26004008c25804004888c8ccc00400401000c8894ccc2580400840044ccc00c00cc26404008cc010dd6184c008010008a9998468099b8704900c1533308d013370e08466e000a801054ccc23404cdc79bae306f308f0137541100209a2a66611a0266ebcdd3198488099299984880984a00984a00800899bb030930100130930130940100116375860be611e026ea8220052f5bded8c06e98cc2440412d2f5bded8c02a66611a0266ebcdd3198488099299984880984a00984a00800899bb03093010013093013094010011637586004611e026ea8220052f5bded8c06e98cc2440411d2f5bded8c02a66611a0266ebcdd3198488099299984880984a00984a00800899bb03093010013093013094010011637586002611e026ea8220052f5bded8c06e98cc244041152f5bded8c02a66611a0266e1cdd698019847809baa0880104313375e60be611e026ea8c1bcc23c04dd502f182f9847809baa05014a029405280a5014a02c2c2c461240261260261260261260261260200246122026124026124026124020022c46120026122026122026122026122026122026122020022c2c2c66e00cdc019b820360373370400407266e080040e0584c8c8c8c8c8c8c8c8c8c94ccc24c054ccc24c04c21004c25004dd5183a984a809baa307530950137540022944528099299984a00984300984a809baa00113232323232323232533309c0132533309d01308f01309e013754002266e3cdd7185100984f809baa00105d14a261420200c2646464664464666600200202c00e0a4444464a66614c02613002002264a66614e026132026150026ea80144cccc018019300103d87a800032323232323253330ad013375e0386164020082a66615a02646464a6661600264a666162026144026164026ea80044c94ccc2c804c94ccc2d804c2d40400454ccc2cc04c29004c2d0040045288a99985980985280985a008008a50161637546108026168026ea8c25004c2d004dd5003899b8900100513371000200a6eb4c2d804c2cc04dd50008a5130920130b20137546124026164026ea80144004528192999858009850809858809baa00113253330b1013253330b50130b401001153330b20130a30130b30100114a22a6661640261480261660200229405858dd51841809859809baa30830130b301375400c266e2400c0044cdc40018009bad30b50130b20137540022944c24404c2c404dd51840809858809baa0043253330af0130a00130b0013754002264a6661600264a666168026166020022a66616202614402616402002294454ccc2c404c28c04c2c8040045280b0b1baa30820130b20137546104026164026ea82180440044c29404004dd6985a009858809baa0011483fa7ede1fa414c24004c2c004dd51840009858009baa084013253330ae01309f0130af013754002264a66615e0264a666166026164020022a66616002614202616202002294454ccc2c004c28804c2c4040045280b0b1baa30810130b10137546122026162026ea82140440044c28c04004dd69859809858009baa001148000c23c04c2bc04dd51847809857809baa08301153330ad01309f0130ae01375400e26464a66615e026142026160026ea801c54ccc2bc04ccdca8010009bae30b40130b101375400e20062c2c6ecc008dd71859009857809baa007153330ad01323233001001087012253330b30100114a0264a6661620266ebc010c2c804c2d804008528899801801800985b00800985000998588098530099858809859009857809baa0074bd7025eb804004585858c2c404c2c804008c2c004004c2c004004c2ac04dd51857008011856809857008009854809baa30ac0130a901375400a0ac2c6156026150026ea800c54c8c8c8c8c8ccc2ac04c270040184c8c8c8c8c94ccc2c0040184c8c8c8c8c8c94ccc2d8054ccc2d8040384c8c94ccc2e004cdd7984d00985d009baa00a30bd0100213375e6108026174026ea8028004528185e00985e80800985c009baa01c1323253330b8013375e6134026174026ea8028c2f4040084cdd7984200985d009baa00a00114a0617802617a02617a020026170026ea809054ccc2d8054ccc2d804cdc7802028099b8f00204f14a02a66616c0266e3cdd7184c008048270a99985b0099b8f375c61100201209a26666666666607a00800409c09a06e06c08e01a00200a44a6661700266ebcc22804c2e804dd50051ba6001153330b801337126eb4c2100402c0084cc020c04800ccdc081c0010b0b0b0b0a99985b00a99985b0099b8f00404e13371e00409a294054ccc2d804cdc79bae309801009050153330b6013371e6eb8c2200402413c4ccccccccccc0f401000814013c0d80dc118034004014894ccc2e004cdd7984500985d009baa00a374c0022a6661700266e24dd698420080580109980419b810390023011003161616161616375a6174026176020046eb8c2e404004c2e40401cdd7185b808031bab30b60130b70130b301375403e4466660240040020620062c616a020546166020526eb0c2c804c2cc04008dd61858808009856809baa008153330ab01309b01006132323253330ae01004132323253330b1013371e6eb8c24c0400c12c54ccc2c404cdc79bae30830100304a153330b1013371e6eb8c24c0400812454ccc2c404cdc79bae30830100204813253330b2013371090000008991919191919299985c0099b884800000454ccc2e004cdd7984500985d009baa00c374c666608a666608a666608a666608a0106eb8c26804028dd718450080518200019bae309a01009375c611402012608000491100488100304000f0870104b001153330b80153330b8010101323253330ba013375e6138026178026ea8038c2fc040084cdd7984300985e009baa00e00114a0617c02617e020026174026ea80784c8c94ccc2e804cdd7984e00985e009baa00e30bf0100213375e610c026178026ea8038004528185f00985f80985f80800985d009baa02613333018301200330110023370006e0020162c2c2c66e0ccdc100101b01c1bad30b801002375a616c02002a6661680266e2000c0044cdd81ba8003375061500266e0cc2a404cdc101a00181a899bb037500026ea0008cdc199b820010340333303b375a60fc0066660b60046eb8c2500400cdd71842008018b1981d1bad307d003337026660b40026eb8c24c0400cdd7184180801a999858809853809bae3093010031337009040497a008040a40002c2c2c2c6eacc2d404c2d804c2c804dd500f1bac30b1010043758615e020062c61660205061620204e6466ec0c2c404004c2c404c2c804004dd61858009856809baa008153330ab01309a01006132323253330ae010041323232323253330b3013371e00a104022a6661660266e3c00c1184c8c8c94ccc2d804cdd7984400985c009baa00a374c666608666660866666086666608600801000c607c00691100488100303e00d05004f00204e04d001153330b60153330b60100e1323253330b8013375e6134026174026ea8030c2f4040084cdd7984200985d009baa00c00114a0617802617a020026170026ea80704c8c94ccc2e004cdd7984d00985d009baa00c30bd0100213375e6108026174026ea8030004528185e00985e80985e80800985c009baa024133330163370206e00466e040d8004cdc081a8018048b0b19b833370400406a06866e0ccdc100081a8199981e00119982e0008028018b0b1bab30b70130b80130b40137540406eb4c2d804c2dc04008dd7185a80800985a808021bae30b3010031630b30102830b1010273758616002615a026ea802054ccc2ac04c264040184c8c8c94ccc2b8040104c8c8c8c8c8c8c8c8c8c8c94ccc2e404cdc78040298a99985c8099b8f006052153330b9013371e0080a22a6661720266e3c0081404c8c94ccc2ec054ccc2ec04ccc2ec040052825114a22a6661760266ebcc23404c2f404dd50079ba6002153330bb010131323253330bd013375e613e02617e026ea8044c308040084cdd7984480985f809baa01100114a0618202618402002617a026ea80844c8c94ccc2f404cdd7984f80985f809baa01130c20100213375e611202617e026ea8044004528186080986100986100800985e809baa02914a026644a66617a020062666603a0040020780202666603a004002078070602a6eb4c21c04dd6185e00808180a1bad3087013758617a020202c6661740266ebcdd3000a6101a0004a0944cccc118cccc118cccc11802d22010048810030410100080063041005004002304100116161616375a617a02617c020046eb8c2f004004c2f004018dd7185d008029bad30b90130ba01002375c6170020026170020066eb8c2d804008dd61859008029bac30b00100437566166026168026160026ea807058c2cc040a0c2c40409cc8cdd81858808009858809859008009bac30b00130ad0137540102646464a66615c020082a66615c02a66615c0266ebcc20004c2c004dd50011ba6333303b333303b37566100026160026ea8071221004881003036005375c615e020066eb8c2c00400d2002153330ae0100613375e6120026160026ea8008c2cc04c2c004dd500a0a5014a02666601c05e05c05a0022c2c61660205061620204e6466ec0c2c404004c2c404c2c804004dd61858009856809baa0083371200202466e00158014c26804c2a404dd50071b80027370004e614c026ea8008dd598389850809baa00d222233333333333025025004003002019309701018014001016006005375a6140020046eb4c278040054ccc27004c23804c27404dd5000899bb0375002a6ea0c240040504cdd81ba830900101537500282c614002614202004613e02002613e020046eb4c27404004c27404c27404004c26004dd5001299984a80984380984b009baa001132323232323232323232323253330a40130a701002132323232498c22404018c94ccc29004c258040044c8c8c8c94ccc2ac04c2b8040084c8c9263253330aa01309c01001153330ad0130ac0137540062930b0a99985500984d80800899192999857809859008010a4c2c6eb8c2c004004c2b004dd50018a99985500984d00800899192999857809859008010a4c2c6160020026158026ea800c58c2a804dd5001183a8018b1856008009856008011855008009853009baa008153330a401309501001153330a70130a60137540102930b0b1852009baa007308c0100a30870100b1630a50100130a50100230a30100130a30100230a10100130a101002375a613e02002613e02004613a02002613a02004613602002612e026ea800458c26404c25804dd50008b1919299984a809843808008a60103d87a80001533309501308601001132323300100106a22533309b0100114c0103d87a80001323232533309b013371e00c6eb8c2700400c4c23804cc27c040052f5c026600a00a004613802004613e02004613a020026eb8c26804c25c04dd500109844009984c80984d00984b809baa0024bd70184a809baa001305f30950137540022c612e02613002004612c020026124026ea8c25404008c254040054ccc23804cdc480580189980880519b8100300b13301106e003533308d0130850100213232325333090013371066e18028008cdc300080108008b19b80009002337049002000a99199847009800a4020260340062a66611c0260029010099b824820010c068cdc0001a401e2a66611c0260029018099b82482020020c068cdc0001a403e2a66611c0260029020099b8248202020040c068cdc0001a405e2a66611c0260029028099b824820202020080c068cdc0001a407e260300066e2000858c24404c2480400cdd69848008011848008041bac308e010073001001222533307f33712900f000899980180198428098428098428098428098428098428098428098428098428098428098428098428098428098428098428080119b800014807454ccc1fccdc4a401c0022666006006610a02610a02610a02610a02610a02610a02610a0200466e00005200d1330040020013001001222533307d306f0011002133300300330830100230720012222222222232323300300133330133333013333301300400d00c300e005488100488100300e00600b00a0013370666e08cdc100380200099b803370401090504e0099b820040013370290504e008029b8148000894ccc1e4cdc40008010800880118008009129919983c1800a40202a6660f0600290000a4000260080042a6660f060029020099b824820010cc00c00ccdc00012401e266e092080808080203300300333700004901f9b88001371c9101080102040810204080002222533307730690011004132323300100100622533307d00113307e337606ea4018dd3001a5eb7bdb1804c8c8c8c94ccc1f8c1d4cc0300280084cc20804cdd81ba900a374c00e00a2a6660fc66e3c0280084c94ccc1fcc1c4c20004dd50008998418099bb037520166108026102026ea80040104010c94ccc1fcc038004530103d87a8000130723308301374c00297ae032330010010022253330830100113308401337606ea402cdd400525eb7bdb1804c8c8c8c94ccc21004c1eccc04803c0084cc22004cdd81ba900f375001c00a2a6661080266e3c03c0084c94ccc21404c1dcc21804dd50008998448099bb03752020611402610e026ea80040104010c94ccc21404c1dc0045300103d87a8000130783308901375000297ae03370000201c2661100266ec0dd48011ba800133006006003375a610a020066eb8c20c04008c21c04008c214040044cc20804cdd81ba9002374c0026600c00c0066eacc1fc00cdd7183e801184080801183f8009919001191980080080111299983e8008a4c264a6660fc00229309919299983e9837983f1baa3300b375c60fc6104020086eb8c1f80084cc014014cc2040400800458c20804008c20004004c20004004cc1eccdd81ba9002375000297adef6c60225333074337200040022980103d8798000153330743371e0040022980103d87a800014c103d87b80002533307500114a22940cdc099980a1bab303d306d375407800a008a6660d660c200a20102900019980a1bab303d306d3754078006004602c6eb8c1c0048dd6983800799998099919bb0307100130713072001375860e001c01601200266660266466ec0c1c4004c1c4c1c8004dd6183800680580480099192999836182f00088060a999836182e800899299983699b8800d0011001100d375a60e260dc6ea800858c1b0dd5000982618361baa304c306c37540806eb8c1ac010dd718348019bae3069003375c60ce0046466ec0c1ac004c1acc1b0004dd618338051919bb0306a001306a306b001375860ca0126eb4c1a0c1a4008dd6983380098338011bad306500130653065001306400130630013062002323376060c200260c260c40026eb0c180004c180004c16cdd502a1111299982e19b880020011375a60bc008264a6660ba609e00226eb4c17c0144cdc01bad305e0053370666e08cdc080100219b81375a60be00a6eb4c178014004cdc080100191119299982d9826182e1baa0011480004dd69830182e9baa00132533305b304c305c37540022980103d87a800013233001001375660c260bc6ea8008894ccc180004530103d87a8000132323253330603371e00e6eb8c18400c4c14ccc190dd4000a5eb804cc014014008dd69830801183200118310009980200180111191980080080191299982e8008a60103d87a80001323232533305d3371e00c6eb8c17800c4c140cc184dd3000a5eb804cc014014008dd5982f0011830801182f800919801245040014df100000122337140040022c66e0cc120cdc01bad305800500100133230010012253330570011480044c94ccc154c118c158dd5181b982b9baa303730573754604e60ae6ea8c1680084c124cc00c00c0044cc00c00c004c1680040c8dd6982b182b8011bad3055001305500130543054002305200130523052305230523052304e375402e2c6eb4c140c144c144008dd69827800982798278011919bb0304e001304e304f0013758609a002609a0046466ec0c130004c130c134004dd6182580098258011bad3049001304900232337606090002609060920026eb0c11c004c11c008dd7182280098209baa30410043756608660880046084002607c6ea8c0f4004c94ccc0f0c0b8c0f4dd500089919299981f1817181f9baa00113232337600080046050002608660806ea800458c024c0fcdd50009820981f1baa00116533303e01714c103d87a80001302e3303f30400174bd701bac303f3040002375a607c002607c0046eb4c0f0004c0e0dd500e8991998008009bab303c303d303d303d303d303d303d303d303d303d30393754603260726ea806928111299981e00108008991998020021820001999119299981e9816981f1baa003132533303e3030303f3754002264a66607e606060806ea80044c94ccc1000205288800a99981f99b8f375c608860826ea80040f44c8c8c94ccc108c0ccc10cdd5000899b87375a608e609060886ea8c11cc110dd50008010b180998219baa024533304030313041375400a26eb4c114c108dd500289bad3045304630463042375400a64a66608060640022646464646464a66609260980042930b1bad304a001304a002375a609000260900046eb4c118004c108dd50028a999820181880089919299982298240010a4c2c6eb4c118004c108dd50028b18201baa00414a0006608660806ea8004008c108c0fcdd50018008802181d800981e000981f001191919299981d981f001099299981c99b8f375c607400406a2a66607266ebcdd3000a6010ba14873657474696e67730100132533303a302a303b375400226464004a666076605a60786ea80044c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc158c1640084c8c8c8c8c8c8c9263304501123028001325333059304b00113232533305e3061002132498cc11c0048dd70008b1bac305f001305b37540262a6660b260940022a6660b860b66ea804c526161630593754024646eb4c168050dd6982c009981180a181f80a981080b181e80b8b182b800982b8011bad30550013055002375a60a600260a60046eb4c144004c144008dd6982780098278011bac304d001304d002304b001304b002325333048304b304b0011337606094002609460960022c6eb0c124004c124008c11c004c11c008c114004c114008c10c004c10c008c104004c0f4dd50008b181f981e1baa001163005303b37540082c2c6eacc0e800458c0f0004c0f0dd59804181c1baa001300730373754607402646074607660760024a666068604c606a6ea80044c8c8c8c94ccc0ecc0f80084c8c92632533303a302c00113232533303f3042002132498c94ccc0f4c0bc0044c8c94ccc108c1140084c926300d001163043001303f37540042a66607a605c0022646464646464a66608c60920042930b1bad30470013047002375a608a002608a0046eb4c10c004c0fcdd50010b181e9baa001163040001303c37540062a66607460560022a66607a60786ea800c5261616303a3754004600c0062c607800260780046074002606c6ea8004588c94ccc0d0c0980044c8c94ccc0e4c0f000852616375c6074002606c6ea800854ccc0d0c0940044c8c94ccc0e4c0f000852616375c6074002606c6ea800858c0d0dd50009bae3036303337540022c602460646ea8c048c0c8dd5000992999818181098189baa00113253330313023303237540022600660666ea8c0d8c0ccdd50008b1991191980080080191299981b8008a6103d87a80001323253330363375e603060706ea80080144c0a4cc0e80092f5c0266008008002607600460720026eb0c048c0c8dd5180918191baa0133035303237540022c600260626ea80488c0d0c0d4004dd59819181998198011bac30310013031002302f001302f0023756605a002605a605a0046eacc0ac004c0acc0ac008dd6181480098148011bac302700130270023758604a00260426ea8c004c084dd5001118120008a4c26cac6464a66603c60200022646464646464a66604e6054004264931980800091919191919192999817181880109924c64a666058603c00226464a6660626068004264932999817181018179baa0011323232325333035303800213232498c0640094ccc0c8c090c0ccdd500189919191919191919299981e9820001099191924c604200aa666076605a60786ea80184c8c8c8c94ccc108c1140084c8c9263024002302300316304300130430023041001303d375400c2ca666074605860766ea801c4c8c8c8c94ccc104c1100084c926533303e3030303f375400626464a666086608c0042930b1bae3044001304037540062c2c6eb4c108004c108008c100004c0f0dd50038b0b181f000981f001181e000981e001181d000981d001181c000981a1baa0031616303600130360023034001303037540022c2c6064002605c6ea801054ccc0b0c07400454ccc0bcc0b8dd50020a4c2c2c60586ea800c58dd698178009817801181680098168011bad302b00137580022c6eb0c0a0004c0a0008dd6981300098130011bad30240013020375400a2a66603c601e0022a66604260406ea80145261616301e37540084a66603a601e603c6ea80044c8c8c8c94ccc090c09c0084c926325333022301400115333025302437540082930b0a999811180980089919299981398150010a4c2c6eb4c0a0004c090dd50020a99981118090008a99981298121baa00414985858c088dd50018b19299981218118008a999810980918110008a51153330213013302200114a02c2c6ea8c094004c094008c08c004c07cdd50008b119299980e9807800899192999811181280109924c64a666040602400226464a66604a60500042930b1bae3026001302237540042a666040602200226464a66604a60500042930b1bae3026001302237540042c60406ea800458c08c004c07cdd50010a99980e9807000899191919299981218138010991924c6464646464a666054605a0042930b1bad302b001302b002375c605200260520066eb8c09c008c8c8c8c8c94ccc0a4c0b000852616375a605400260540046eb8c0a0004c0a0010dd718130018b1bac3025001302500237586046002603e6ea800854ccc074c0340044c8c94ccc088c0940084c9263232323232323232533302a302d002149858dd6981580098158011bae30290013029003375c604e0046464646464a66605260580042930b1bad302a001302a002375c605000260500066eb8c098008dd618110011bac3020001163253330223025302500113376060480026048604a0022c6eb0c08c004c07cdd50010a99980e9806000899192999811181280109924c6464646464a66604e60540042930b1bad30280013028002375c604c002604c0046eb8c09000458dd61811800980f9baa0021533301d300b0011323253330223025002132498c8c8c8c8c8c8c8c94ccc0a8c0b400852616375a605600260560046eb8c0a4004c0a400cdd718138011919191919299981498160010a4c2c6eb4c0a8004c0a8008dd7181400098140019bae3026002375860440046eb0c08000458c94ccc088c094c0940044cdd81812000981218128008b1bac3023001301f37540042a66603a601400226464a666044604a00426493191bae3022002375c60400022c64a666044604a604a002266ec0c090004c090c09400458dd61811800980f9baa00216301d3754002464a666038601c00226464a66604260480042930b1bae3022001301e37540042a666038601a0022a66603e603c6ea80085261616301c375400260020264a666030601460326ea80044c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc0b4c0c00084c8c8c8c92632533302e30200011323253330333036002132498c06800458c0d0004c0c0dd50058a999817180f8008a99981898181baa00b14985858c0b8dd5005191bad302f00c375a605a016646eb4c0b8034dd69816006191919191bae3030003375c605c004646eb8c0bc00cdd718168011919bb03031001303130320013758605a0206466ec0c0c0004c0c0c0c4004dd618158078b1bad302e001302e002375a605800260580046eb4c0a8004c0a8008c0a0004c0a0008c94ccc094c0a0c0a00044cdd81813800981398140008b1bac3026001302600232533302330263026001133760604a002604a604c0022c6eb0c090004c090008dd69811000981100119299980f98111811000899bb0302100130213022001163758604000260400046eb8c078004c068dd50008b18008009119299980c180500089919299980e98100010a4c2c6eb8c078004c068dd50010a99980c180480089919299980e981000109924c6600c00246600c00c0022c6eb0c078004c068dd50010a99980c180400089919299980e981000109924c6600c00246600c00c0022c6eb0c078004c068dd50010a99980c1803800899191919299980f981100109924c660100024660100100022c6eb0c080004c080008dd6980f000980d1baa00215333018300600113232533301d3020002149858dd6980f000980d1baa00215333018300500113232533301d3020002149858dd6980f000980d1baa002153330183370e900600089919299980e98100010a4c2c6eb8c078004c068dd50010b180c1baa00122323300100100322533301b00114984c8cc00c00cc07c008c00cc074004c064c058dd50071b8748028dc3a40106e1d2006370e90021b8748008dc3a40006e952000370090011b8048004dc7a44100375e980103d8798000371290001ba548008dd70009bae0015734aae7555cf2ab9f5740ae855d12611e581cfcbeb9b48861ad17eb97cff003df115accf7cf18f09b31a2b7a4afb5004c011e581c445b77d214aa36d1b2edeedb8ddad49e0b62d80a1f4b08eb9c8b4c8c0001", - "hash": "760318f4ced18f4983fc9bd63005ef187efb4d270520d47a07673751" + "compiledCode": "593d6d01000033323232323232322322322253232323232323232323232323233301430063015375401c264a66602a6464646464646464646464a66604060220162646464646464a66604c6030604e6ea80044c8c8c8c94ccc0a8c070c0acdd5000899192999816180e18169baa0011323232323232323232533303530273036375400226464646464646464646464a66608066e24dd69822982318231823182318231823182318231823182318211baa004375a600260846ea80504c8c94ccc108c94ccc10ccdc499b8200200200113371000266e08c0dc008c0dc00852819b820020041323232325333046303830473754002264a66608e66ebcc0b8c124dd5000981698249baa00b15333047303833302a3756605a60926ea800408403c54ccc11ccdd7981618249baa0014c107d87b9fd87980ff0013253330483375e605e60946ea8c0bcc128dd500f1820998261ba90224bd700a99982419198008009bac304e304f304f304f304f304f304f304b375401a44a66609a00229404c94ccc12ccdd7981898269baa3032304d3754042607c6609e607c6609e60a000497ae04bd700a511330030030013050001153330480151533304800615333048004100114a029405280b0b299982399b8f375c605c60926ea806c04454ccc11ccdd79ba63304b32533304b304e304e001133760609a002609a609c0022c6eb0c0b4c124dd500da5eb7bdb180dd31982599bb0374e66096609002c66096609202c97ae0374e66096609002a66096609202a97ae04bd6f7b6300a99982399b87375a605860926ea806c0184c94ccc120c004dd6980298251baa01c13001375a606460946ea8070528129998241820000899b890014828270045280a5014a02940585858c12cc120dd50008b1980e9bac302a304737546058608e6ea80fc084ccccccc8c88888894ccc130c1080144cdd79ba7533304c303e00b1533304c303e00c1533304c303e00e1330504c1010200330503750002660a0981010000330504c10101004bd700b0b09982826101030033050375066e00004030cc140dd40071982826010101004bd701ba733300830070064bd7090100008101000081010000810100001119299982799b8f375c606c0060102660a66ea0004cc14cdd419b80375a606a0046eb4c0d000ccc14cc0d0008cc14cc0300092f5c02a66609ea66609e66e3cdd7181b001803099b8f375c606a00600a29404cc14cdd400099829981a801198299ba8337006eb4c0d0008dd6981a00199829980600125eb8054ccc13ccdd79ba7003374e660a66ea40a4cc14cdd4981800c99829a6010101004bd700998299ba800133053303500233053303400233053375060866eb4c0300092f5c02c60846eb4c0d40044cdd79ba7533304c303e00b1533304c303e00c1533304c303e00e1330504c1010200330503750002660a0981010000330504c1010000330504c10101004bd700b0b099828261010400330503750002660a06ea0030cc140dd40071982826010101004bd701ba733300830070064bd709010000810100008101000081010000810100001119299982798229bae30360031330533750002660a66ea0cdc01bad3035002375a6068006660a66068004660a66018004660a6607200497ae01533304f533304f3371e6eb8c0d800c0204cdc79bae303500300714a02660a66ea0004cc14cc0d4008cc14cdd419b80375a60680046eb4c0d000ccc14cc030008cc14cc0e40092f5c02a66609ea66609e66e3cdd7181b001803099b8f375c606a00600a29404cc14cdd400099829981a80119829981a001198299ba8337006eb4c030008dd6981a00199829981c80125eb8054ccc13ccdd79ba7003374e660a66ea40a4cc14cdd4981800c99829a6010101004bd700998299ba800133053303500233053303400233053300c00233053375060866eb4c0e40092f5c02c60846eb4c0d40048c8cc004004008894ccc12c00452f5c0264666444646600200200644a6660a20022006264660a66e9ccc14cdd4803198299ba9375c60a0002660a66ea0dd69828800a5eb80cc00c00cc154008c14c004dd718250009bab304b00133003003304f002304d00122232333001001004003222533304d002100113330030033050002330043758609e0040026eacc0a8c118dd500d1bae3045013375c608c0266eb8c114048dd718230091bad3005304637540304609260946094609400266ebcdd318159bab302c30443754605260886ea80f0dd31919800998009813998239ba901d3304737520166608e9810101004bd701813998239ba901d3304737520126608e98010101004bd701813998239ba901d3304737520106608e6ea00092f5c04464666002002006004444a6660940042002264666008008609c0066644646600200200a44a66609e0022660a066ec0dd48021ba60034bd6f7b630099191919299982818239981c00400109982a19bb037520106e9801c01454ccc140cdc78040010992999828982198291baa001133055337606ea4024c158c14cdd50008020802192999828a99982a0008a5114a0298103d87a80001304433055374c00297ae03233300100100800222253330560021001132333004004305a0033322323300100100522533305b00113305c337606ea4010dd4001a5eb7bdb1804c8c8c8c94ccc170c14ccc1100200084cc180cdd81ba9008375000e00a2a6660b866e3c0200084c94ccc174c13cc178dd500089983099bb0375201260c460be6ea80040104010c94ccc174c13c004530103d87a80001305033061375000297ae03370000e0022660c066ec0dd48011ba800133006006003375a60ba0066eb8c16c008c17c008c174004dd7182a8009bad30560013058002133054337606ea4008dd3000998030030019bab3051003375c609e00460a600460a20026eb8c124004dd5982500098260010b1bad30263043375402aa66608060646e34dd71820807899b81003375a600260846ea8050400c588c114c118c118c118c118c118c118c118004ccc084dd5981218201baa014375c607e0186eb8c100030ccc080dd59811981f9baa013375c607c0186eb8c0fc030c8c8c8c8c94ccc110c11c0084c94ccc108cdc79bae304300203e153330423375e6e980053010ba14873657474696e67730100132533304330333044375400226464004a666088606c608a6ea80044c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc17cc1880084c8c8c8c8c8c8c92633035011230270013253330623054001132325333067306a002132498cc0dc0048dd70008b1bac3068001306437540262a6660c460a60022a6660ca60c86ea804c526161630623754024646eb4c18c050dd69830809981100a181780a981000b181680b8b183000098300011bad305e001305e002375a60b800260b80046eb4c168004c168008dd6982c000982c0011bac30560013056002305400130540023253330513054305400113376060a600260a660a80022c6eb0c148004c148008c140004c140008c138004c138008c130004c130008c128004c118dd50008b182418229baa001163027304437540082c2c6eacc10c00458c114004c114dd5981298209baa00130243040375460866eb0c090c100dd5181298201baa0382533303e3030303f3754002264646464a66608a60900042646493192999822181b000899192999824982600109924c64a66608e607200226464a666098609e0042649318068008b182680098249baa002153330473038001132323232323253330503053002149858dd6982880098288011bad304f001304f002375a609a00260926ea800858c11cdd50008b182500098231baa00315333044303500115333047304637540062930b0b18221baa002300600316304600130460023044001304037540022c464a66607c606000226464a666086608c0042930b1bae3044001304037540042a66607c605e00226464a666086608c0042930b1bae3044001304037540042c607c6ea8004dd7182018208011bae303f001303f002375c607a002660766ea4cc06522104000643b0000013303b37526030002660766ea4cc065221040014df10000014bd7019199b8c48020cdc01b8d0014801c004dca1980c1980c1bae301d30383754603a60706ea8c074c0e0dd5000a4501230032533303733710002904002099b8b00148810016375a603860706ea8c074c0e0dd5000981d181b9baa001163300c37586036606c6ea8c06cc0d8dd5017240006054646464a66606c60500022980103d879800015333036302700113301e00300214c0103d87b8000303637546603a6eb8c0d8010dd7181b0019bae3036002375c606a0046466ec0c0e0004c0e0c0e4004dd6181a0089919bb030370013037303800137586064020a666060604460626ea80104c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc10cc1180084c8c9263253330423034001132325333047304a002132498c05400458c120004c110dd50038a99982118198008a99982298221baa00714985858c108dd5003191919191bae3046003375c6088004646eb8c11400cdd718218011919bb03047001304730480013758608601c6466ec0c118004c118c11c004dd618208068b1bad30440013044002375a60840026084004608000260800046eb4c0f8004c0f8008dd6981e000981e0011bad303a001303a002325333037303a303a0011337606072002607260740022c6eb0c0e0004c0e0008dd7181b00098191baa0041630010012232533303130230011323253330363039002149858dd7181b80098199baa0021533303130220011323253330363039002132498cc0180048cc01801800458dd6181b80098199baa0021533303130210011323253330363039002132498cc0180048cc01801800458dd6181b80098199baa0021533303130200011323232325333038303b002132498cc0200048cc02002000458dd6181c800981c8011bad3037001303337540042a666062603e00226464a66606c60720042930b1bad3037001303337540042a666062603c00226464a66606c60720042930b1bad3037001303337540042a66606266e1d200c0011323253330363039002149858dd7181b80098199baa002163031375400244646600200200644a66606800229309919801801981c0011801981b000981898171baa001163010302d3754002605e60586ea800458cc004dd6180718159baa3010302b375404600c6002002444a66605a0042980103d87a800013232533302c301e0031301f330300024bd7009998028028009810801981880198178011bae302b302837540022c6016604e6ea807cdd6981498150011bad302800130280023233760604e002604e60500026eb0c098004c088dd500d8a9998101809005899192999811180a18119baa001132323253330253017302637540022a66604a602c6660106eacc02cc09cdd5181518139baa00100300213017333008300e3756601e604e6ea8c030c09cdd500f8018010a501632533302800114c0103d87a80001301833029302a0014bd701bac3009302637546016604c6ea8078c01000cdd7181398121baa001163007302337540366eb8c094c088dd500d899192999811180a18119baa00113375e6e98c02cdd5980618121baa3009302437540386e98c018cc098c09cc090dd5000998131ba93003002330264c010120004bd700b180398119baa01b375c604a60446ea806c8cc00922104000de14000001223371400400244464a666042602460446ea8004520001375a604c60466ea8004c94ccc084c048c088dd50008a60103d87a8000132330010013756604e60486ea8008894ccc098004530103d87a8000132323253330263371e00e6eb8c09c00c4c064cc0a8dd4000a5eb804cc014014008dd698138011815001181400099198008008021129998128008a6103d87a8000132323253330253371e00e6eb8c09800c4c060cc0a4dd3000a5eb804cc014014008dd59813001181480118138009199911299981018090008a5eb7bdb1804c8c8cc0040052f5bded8c044a66604c00226604e66ec0dd48031ba60034bd6f7b6300991919192999813980f1980780500109981599bb037520146e9801c01454ccc09ccdc780500109981599bb037520146e9801c00c4cc0accdd81ba9002374c0026600c00c0066eacc0a000cdd71813001181500118140009919800800a5eb7bdb180894ccc0940044cc098cdd81ba9004375000697adef6c601323232325333026301d3300e00800213302a337606ea4020dd40038028a99981319b8f00800213302a337606ea4020dd400380189981519bb037520046ea0004cc01801800cdd698138019bae302500230290023027001375c60080026eb8c00c004dd6980100091810981118110009181018108009180f80091299980d19b9000200114c103d87980001533301a3371e0040022980103d87a800014c103d87b80002323300100100222533301d00114bd6f7b630099191919299980f180a001080189981119bb037520046e98004cc01801800cdd5980f8019bae301d0023021002301f0012301c301d301d301d301d0013016375402029309b2b19299980a980380089919299980d180e8010a4c2c6eb8c06c004c05cdd50080a99980a98030008991919191919299980f181080109924c646464646eb8c08400cdd7180f801191bae3020003375c603c0046466ec0c088004c088c08c004dd6180f0031919bb03021001302130220013758603800a2c6eb4c07c004c07c008dd6980e800980e80119299980d180e980e800899bb0301c001301c301d0011637586036002602e6ea804054ccc054c0140044c8c94ccc068c07400852616375c6036002602e6ea804058c054dd500789991919191911919191299980f191919191919191919191919191919191919192999818981118191baa00113232323232533303630283037375403a264646464646464646464646464646464646464646464a66609866ebcc0b8c138dd50079822998281ba901b4bd7009919191919191919299982a1826000899191919191919191919191919191919191999999111111919191919191919191919191919191999999999980080080a80a009020240000b466646002002444a6660fa66e2400520001002153330800100214bd700999801801984180801183900082b240049000240009000111111111112999843808038a9998420099b8733700004002064264a66610a0266e1c0e8cdc00138008a999842809929998430099b87375a60a46110026ea8204040284c06c0044cdd79ba6001374c661140266ec0dd498189bae30683088013754102026ea0cdc08051bad305230880137541020297adef6c603253330860130773087013754002297adef6c60137566116026110026ea8004cc0bcc8cc004004180894ccc2280400452f5bded8c0264646464a66611602610202004200626611e0266ec0dd48011ba60013300600600337566118020066eb8c22804008c23804008c2300400415054ccc214054ccc21404c1dcc21804dd501c099191919299984480983d9845009baa00113232533308b01307d308c013754002266e3c008dd71848009846809baa0011633003005051375c611c026116026ea800458cc004170144c0040048894ccc23004008530103d87a800013232533308b01307d0031307e3308f01375200497ae01333005005001308001003309001003375c611c020046eb0c22804c21c04dd501c0a51132533308601323253330880130793089013754002264a6661120264a66611a026118020022a6661140260f6611602002294454ccc22804c1f0c22c040045280b0b1baa305b308b01375460d66116026ea817c4cdc4001800899b89003001375a611a026114026ea800452818349844809baa306930890137540ba6eb4c004c22004dd50408089919299984400991919299984580984080815099baf374ea6661160260fa01e2a6661160260fa0222a6661160260fa02026611e029810102003308f0137500806611e029810100003308f014c10101004bd700b0b09984780a610103003308f01375066e00100044cc23c04dd40081984780a6010101004bd701ba7333003300204d4bd709010000810100008101000081010000111929998470099b8f375c60e000605a266124026ea0004cc24804dd419b80375a60c00046eb4c16800ccc24804c168008cc24804c0200092f5c02a66611c02a66611c0266e3cdd71838001815899b8f375c60c000605429404cc24804dd40009984900983000119849009ba8337006eb4c168008dd6982d0019984900980400125eb8054ccc23804cdd79ba7003374e66124026ea4174cc24804dd498020271984900a6010101004bd70099849009ba8001330920130600023309201305a002330920137506104026eb4c0200092f5c02c6102026eb4c1bc0044cdd79ba7533308b01307d00f1533308b01307d0111533308b01307d01013308f014c10102003308f0137500806611e029810100003308f014c10100003308f014c10101004bd700b0b09984780a610104003308f0137500806611e026ea0044cc23c04dd40081984780a6010101004bd701ba7333003300204d4bd7090100008101000081010000810100008101000011192999847009842009bae307000313309201375000266124026ea0cdc01bad3060002375a60b4006661240260b4004661240260100046612402600e00497ae01533308e01533308e013371e6eb8c1c000c0b44cdc79bae306000302c14a0266124026ea0004cc24804c180008cc24804dd419b80375a60b40046eb4c16800ccc24804c020008cc24804c01c0092f5c02a66611c02a66611c0266e3cdd71838001815899b8f375c60c000605429404cc24804dd4000998490098300011984900982d00119849009ba8337006eb4c020008dd6982d0019984900980380125eb8054ccc23804cdd79ba7003374e66124026ea4174cc24804dd498020271984900a6010101004bd70099849009ba8001330920130600023309201305a00233092013008002330920137506104026eb4c01c0092f5c02c6102026eb4c1bc0048cc0dd220104000de140000012323300100100222533308f0100114bd70099199911191980080080191299984a8080088018991984b809ba73309701375200c6612e026ea4dd7184a008009984b809ba8375a612a0200297ae033003003309901002309701001375c611c020026eacc23c04004cc00c00cc24c04008c24404004888c8ccc00400401000c8894ccc2440400840044ccc00c00cc25004008cc010dd61849808010008a9998440099b8704400c15333088013370e07a66e000a801054ccc22004cdc79bae306a308a013754106020902a6661100266ebcdd3198460099299984600984780984780800899bb0308e01001308e01308f0100116375860b46114026ea820c052f5bded8c06e98cc230041192f5bded8c02a6661100266e1cdd698011845009baa0830104215333088013370e6eb4c004c22804dd5041808200a9998440099b87375a60066114026ea820c040f84cdd7982d1845009baa306a308a0137540b260b46114026ea812c5280a5014a029405280b0b0b118468098470098470098470098470080091846009846809846809846808008b11845809846009846009846009846009846009846008008b0b0b19b803370066e080c40c8cdc100101a19b8200103316132323232323232323232533308e01533308e01307f308f01375460e06120026ea8c1c0c24004dd50008a5114a0264a66611e026102026120026ea80044c8c8c8c8c8c8c8c94ccc25c04c94ccc26004c22804c26404dd5000899b8f375c613a026134026ea8004160528984e008030991919199119199980080080b003826911119299985080984980800899299985100984a009851809baa005133330060064c0103d87a80003232323232323253330a9013375e03a615c020082a66615202646464a6661580264a66615a02613c02615c026ea80044c94ccc2b804c94ccc2c804c2c40400454ccc2bc04c28004c2c0040045288a999857809850809858008008a50161637546100026160026ea8c24004c2c004dd5003899b8900100513371000200a6eb4c2c804c2bc04dd50008a51308e0130ae013754611c02615c026ea8014400452819299985600984e809856809baa00113253330ad013253330b10130b001001153330ae01309f0130af0100114a22a66615c02614002615e0200229405858dd5183f9857809baa307f30af01375400c266e2400c0044cdc40018009bad30b10130ae0137540022944c23404c2b404dd5183e9856809baa0043253330ab01309c0130ac013754002264a6661580264a66616002615e020022a66615a02613c02615c02002294454ccc2b404c27c04c2b8040045280b0b1baa307e30ae01375460fc615c026ea82080440044c28404004dd69858009856809baa0011483fa7ede1fa414c23004c2b004dd5183e1856009baa080013253330aa01309b0130ab013754002264a6661560264a66615e02615c020022a66615802613a02615a02002294454ccc2b004c27804c2b4040045280b0b1baa307d30ad013754611a02615a026ea82040440044c27c04004dd69857809856009baa001148000c22c04c2ac04dd51845809855809baa07f153330a901309b0130aa01375401026464a66615602613a026158026ea801c54ccc2ac04ccdca8010009bae30b00130ad01375400e20062c2c6ecc01cdd71857009855809baa008153330a901323233001001083012253330af0100114a0264a66615a0266ebc010c2b804c2c804008528899801801800985900800984e00998568098510099856809857009855809baa0084bd7025eb804004585858c2b404c2b804008c2b004004c2b004004c29c04dd50011854809855008011854008009852009baa30a70130a401375400a0a22c614c026146026ea800c54c8c8c8c8c8ccc29804c25c040184c8c8c8c8c94ccc2ac040184c8c8c8c8c8c8c8c8c8c8c94ccc2d8054ccc2d80404c4c8c94ccc2e004cdd7805185e80801099baf00700114a0617802617a020026170026ea80844c8c94ccc2e004cdd7805185e80801099baf00700114a0617802617a02617a020026170026ea80a454ccc2d8054ccc2d804cdc780202a899b8f00205414a02a66616c0266e3cdd7184c008070298a99985b0099b8f375c61100201c0a426666666666660840080040a60a407807609a02400201400c444a6661720266ebcdd30049ba6001153330b901337126eb4c2140404400c4cc038c060008cdc081f0018b0b0b0b0a99985b00a99985b0099b8f00405313371e0040a4294054ccc2d804cdc79bae30980100e055153330b6013371e6eb8c220040381504cccccccccccc1080100081541500ec0f01300480040280188894ccc2e404cdd79ba6009374c0022a6661720266e24dd698428080880189980719b8103f0033017002161616161616375a6174026176020046eb8c2e404004c2e404030dd7185b80805985b00985b808011bab30b50100130b50100230b30100130af0137540086eacc2c404c2c804c2b804dd500f9119998090010008188018b1858008151857008149bac30ad0130ae0100237586158020026150026ea802054ccc29804c258040184c8c8c94ccc2a4040104c8c8c94ccc2b004cdc79bae308e0100304b153330ac013371e6eb8c1f800c12854ccc2b004cdc79bae308e01002049153330ac013371e6eb8c1f80081204c94ccc2b404c0ec0044c8c8c8c8c8c94ccc2cc04c10400454ccc2cc04cdd7984280985a809baa00c374c666608c666608c666608c666608c0106eb8c25404028dd718428080518200019bae309501009375c610a02012608000491100488100304000f0820104c001153330b30153330b3010101323253330b5013375e612e02616e026ea8038c2e8040084cdd7984080985b809baa00e00114a0617202617402002616a026ea80784c8c94ccc2d404cdd7984b80985b809baa00e30ba0100213375e610202616e026ea8038004528185c80985d00985d00800985a809baa02613333018301200330110023370006e0020162c2c2c66e0ccdc100101b01c1bad30b301002375a616202002a66615e0266e2000c0044cdd81ba8003375061460266e0cc29004cdc101a00181a899bb037500026ea0008cdc199b820010340333303c375a60f20066660ac0046eb8c23c0400cdd7183f8018b1981d9bad3078003337026660aa0026eb8c2380400cdd7183f001a999856009851009bae308e010031337009040497a008040a40002c2c2c2c6eacc2c004c2c404c2b404dd500f1bac30ac0100437586154020062c615c0205061580204e6466ec0c2b004004c2b004c2b404004dd61855809854009baa008153330a601309501006132323253330a9010041323232323253330ae013371e00a0fa2a66615c0266e3c00c11c4c8c8c94ccc2c404cdd79841809859809baa00a374c666608866660886666088666608800801000c607c00691100488100303e00d05004f00204e04d001153330b10153330b10100e1323253330b3013375e612a02616a026ea8030c2e0040084cdd7983f985a809baa00c00114a0616e026170020026166026ea80704c8c94ccc2cc04cdd7984a80985a809baa00c30b80100213375e60fe616a026ea8030004528185b80985c00985c008009859809baa024133330163370206e00466e040d8004cdc081a8018048b0b19b833370400406a06866e0ccdc100081a8199981e80119982b8008028018b0b1bab30b20130b30130af0137540406eb4c2c404c2c804008dd71858008009858008021bae30ae010031630ae0102830ac0102737586156026150026ea802054ccc29804c250040184c8c8c94ccc2a4040104c8c8c8c8c8c8c8c8c8c8c94ccc2d004cdc78040298a99985a0099b8f006052153330b4013371e0080a22a6661680266e3c0081404c8c94ccc2d8054ccc2d804ccc2d8040052825114a22a66616c0266ebcc22004c2e004dd50079ba6002153330b6010131323253330b8013375e6134026174026ea8044c2f4040084cdd7984200985d009baa01100114a0617802617a020026170026ea80844c8c94ccc2e004cdd7984d00985d009baa01130bd0100213375e6108026174026ea8044004528185e00985e80985e80800985c009baa02914a026644a666170020062666603a0040020780202666603a004002078070602a6eb4c20804dd6185b80808180a1bad30820137586170020202c66616a0266ebcdd3000a6101a0004a0944cccc11ccccc11ccccc11c02d22010048810030410100080063041005004002304100116161616375a6170026172020046eb8c2dc04004c2dc04018dd7185a808029bad30b40130b501002375c6166020026166020066eb8c2c404008dd61856808029bac30ab010043756615c02615e026156026ea807058c2b8040a0c2b00409cc8cdd81856008009856009856808009bac30ab0130a80137540102646464a666152020082a66615202a6661520266ebcc1ecc2ac04dd50011ba6333303c333303c375660f66156026ea8071221004881003036005375c6154020066eb8c2ac0400d2002153330a90100613375e6116026156026ea8008c2b804c2ac04dd500a0a5014a02666601c05e05c05a0022c2c615c0205061580204e6466ec0c2b004004c2b004c2b404004dd61855809854009baa0083371200202466e00144014c25404c29004dd50071b80027370004e6142026ea8008dd59836184e009baa00d222233333333333025025004003002019309201018014001016006005375a6136020046eb4c264040054ccc25c04c22404c26004dd5000899bb0375002a6ea0c22c040504cdd81ba8308b0101537500282c6136026138020046134020026134020046eb4c26004004c26004c26004004c24c04dd50012999848009841009848809baa0011323232323232323232323232533309f0130a201002132323232498c21004018c94ccc27c04c244040044c8c8c8c94ccc29804c2a4040084c8c9263253330a501309701001153330a80130a70137540062930b0a99985280984b00800899192999855009856808010a4c2c6eb8c2ac04004c29c04dd50018a99985280984a80800899192999855009856808010a4c2c615602002614e026ea800c58c29404dd500118380018b1853808009853808011852808009850809baa0081533309f01309001001153330a20130a10137540102930b0b184f809baa00730870100a30820100b1630a00100130a001002309e01001309e01002309c01001309c01002375a613402002613402004613002002613002004612c020026124026ea800458c25004c24404dd50008b19192999848009841008008a60103d87a8000153330900130810100113232330010010652253330960100114c0103d87a800013232325333096013371e00c6eb8c25c0400c4c22404cc268040052f5c026600a00a004612e020046134020046130020026eb8c25404c24804dd500109841809984a00984a809849009baa0024bd701848009baa001305a30900137540022c612402612602004612202002611a026ea8c24004008c240040054ccc22404cdc480580189980880519b8100300b1330110690035333088013080010021323232533308b013371066e18028008cdc300080108008b19b80009002337049002000a99199844809800a4020260360062a6661120260029010099b824820010c06ccdc0001a401e2a6661120260029018099b82482020020c06ccdc0001a403e2a6661120260029020099b8248202020040c06ccdc0001a405e2a6661120260029028099b824820202020080c06ccdc0001a407e260320066e2000858c23004c2340400cdd69845808011845808041bac3089010073001001222533307a33712900f000899980180198400098400098400098400098400098400098400098400098400098400098400098400098400098400098400080119b800014807454ccc1e8cdc4a401c002266600600661000261000261000261000261000261000261000200466e00005200d13300400200130010012225333078306a00110021333003003307e002306d001222222222222323232533308301301100113232323232533308801301600115333088015333088013371000c018266e1ccdc199b8200500c3370000866e080300200044cdc38030060a9998440099b883370666e0400c014cdc08010040008999804800803199980d999980d999980d80580a009980a80324500488100301500d0120110011616163370600400266e00008cdc100200319b820020033370401890504e0099b8200a00316533308201307800e13370200200e200266e04ccc0a8010034030ccc0a800c034030cdc0a4141380200c6e0520003710900011299983999b880010021001100230010012253233307230014804054ccc1c8c00520001480004c01000854ccc1c8c00520401337049040021980180199b800024803c4cdc124101010100406600600666e00009203f37100026e392210801020408102040800022225333071306300110041323233001001006225333077001133078337606ea4018dd3001a5eb7bdb1804c8c8c8c94ccc1e0c1bccc0300280084cc1f0cdd81ba900a374c00e00a2a6660f066e3c0280084c94ccc1e4c1acc1e8dd500089983e99bb0375201660fc60f66ea80040104010c94ccc1e4c038004530103d87a80001306c3307d374c00297ae0323300100100222533307d00113307e337606ea402cdd400525eb7bdb1804c8c8c8c94ccc1f8c1d4cc04803c0084cc20804cdd81ba900f375001c00a2a6660fc66e3c03c0084c94ccc1fcc1c4c20004dd50008998418099bb037520206108026102026ea80040104010c94ccc1fcc1c40045300103d87a8000130723308301375000297ae03370000201c2661040266ec0dd48011ba800133006006003375a60fe0066eb8c1f4008c20404008c1fc0044cc1f0cdd81ba9002374c0026600c00c0066eacc1e400cdd7183b801183d801183c8009919001191980080080111299983b8008a4c264a6660f000229309919299983b9834983c1baa3300b375c60f060f80086eb8c1e00084cc014014cc1ec00800458c1f0008c1e8004c1e8004cc1d4cdd81ba9002375000297adef6c6022533306e337200040022980103d87980001533306e3371e0040022980103d87a800014c103d87b80002533306f00114a22940cdc09998071bab30373067375406c008006a6660ca60b6008200e290001998071bab30373067375406c00400260206eb8c1a8034dd698350051bad306a009375a60d40106eb8c198010dd718320019bae3064003375c60c40046466ec0c198004c198c19c004dd618310031919bb0306500130653066001375860c000a6eb4c18cc190c190c190004c18c004c188004c184008c8cdd81830000983018308009bac305f001305f001305a37540a644464a6660b6609860b86ea8004520001375a60c060ba6ea8004c94ccc16cc130c170dd50008a60103d87a800013233001001375660c260bc6ea8008894ccc180004530103d87a8000132323253330603371e00e6eb8c18400c4c14ccc190dd4000a5eb804cc014014008dd69830801183200118310009980200180111191980080080191299982e8008a60103d87a80001323232533305d3371e00c6eb8c17800c4c140cc184dd3000a5eb804cc014014008dd5982f0011830801182f800919801245040014df100000122337140040022c66e0cc120cdc01bad305800500100133230010012253330570011480044c94ccc154c118c158dd5181b982b9baa303730573754604e60ae6ea8c1680084c124cc00c00c0044cc00c00c004c1680040c8dd6982b182b8011bad3055001305500130543054002305200130523052305230523052304e375402e2c6eb4c140c144008dd69827800982798278011bad304d001304d002375a609600260960046eb4c124004c124008c8cdd81824000982418248009bac30470013047002375c608a00260826ea8c104010dd5982198220011821000981f1baa303d00132533303c302e303d375400226464a66607c605c607e6ea80044c8c8cdd80020011814000982198201baa001163009303f37540026082607c6ea8004594ccc0f805c5300103d87a80001302e3303f30400174bd701bac303f3040002375a607c002607c0046eb4c0f0004c0e0dd500e8991998008009bab303c303d303d303d303d303d303d303d303d303d30393754603260726ea806928111299981e00108008991998020021820001999119299981e9816981f1baa003132533303e3030303f3754002264a66607e606060806ea80044c94ccc1000205288800a99981f99b8f375c608860826ea80040f44c8cdc3992999820981918211baa001133223233300100100348000888c94ccc11ccdd7981498249baa304c00300510021333004004001303b002304c0023758604660866ea8c08cc10cdd5012182318219baa00116301230423754046a666080606260826ea80144dd6982298211baa0051375a608a608c608c60846ea8014c94ccc100c0c80044c8c8c8c8c8c94ccc124c13000852616375a609400260940046eb4c120004c120008dd6982300098211baa0051533304030310011323253330453048002149858dd6982300098211baa0051630403754008294000cc10cc100dd50008011821181f9baa0030011004303b001303c001303e002323232533303b303e00213253330393371e6eb8c0e80080d454ccc0e4cdd79ba60014c010ba14873657474696e67730100132533303a302a303b375400226464004a666076605a60786ea80044c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc158c1640084c8c8c8c8c8c8c9263304501123028001325333059304b00113232533305e3061002132498cc11c0048dd70008b1bac305f001305b37540262a6660b260940022a6660b860b66ea804c526161630593754024646eb4c168050dd6982c009981180a181f80a981080b181e80b8b182b800982b8011bad30550013055002375a60a600260a60046eb4c144004c144008dd6982780098278011bac304d001304d002304b001304b002325333048304b304b0011337606094002609460960022c6eb0c124004c124008c11c004c11c008c114004c114008c10c004c10c008c104004c0f4dd50008b181f981e1baa001163005303b37540082c2c6eacc0e800458c0f0004c0f0dd59804181c1baa001300730373754607402646074607660760024a666068604c606a6ea80044c8c8c8c94ccc0ecc0f80084c8c92632533303a302c00113232533303f3042002132498c94ccc0f4c0bc0044c8c94ccc108c1140084c926300d001163043001303f37540042a66607a605c0022646464646464a66608c60920042930b1bad30470013047002375a608a002608a0046eb4c10c004c0fcdd50010b181e9baa001163040001303c37540062a66607460560022a66607a60786ea800c5261616303a3754004600c0062c607800260780046074002606c6ea8004588c94ccc0d0c0980044c8c94ccc0e4c0f000852616375c6074002606c6ea800854ccc0d0c0940044c8c94ccc0e4c0f000852616375c6074002606c6ea800858c0d0dd50009bae3036303337540022c602460646ea8c048c0c8dd5000992999818181098189baa00113253330313023303237540022600660666ea8c0d8c0ccdd50008b1991191980080080191299981b8008a6103d87a80001323253330363375e603060706ea80080144c0a4cc0e80092f5c0266008008002607600460720026eb0c048c0c8dd5180918191baa0133035303237540022c600260626ea80488c0d0c0d4004dd59819181998198011bac30310013031002302f001302f0023756605a002605a605a0046eacc0ac004c0acc0ac008dd6181480098148011bac302700130270023758604a00260426ea8c004c084dd5001118120008a4c26cac6464a66603c60200022646464646464a66604e6054004264931980800091919191919192999817181880109924c64a666058603c00226464a6660626068004264932999817181018179baa0011323232325333035303800213232498c0640094ccc0c8c090c0ccdd500189919191919191919299981e9820001099191924c604200aa666076605a60786ea80184c8c8c8c94ccc108c1140084c8c9263024002302300316304300130430023041001303d375400c2ca666074605860766ea801c4c8c8c8c94ccc104c1100084c926533303e3030303f375400626464a666086608c0042930b1bae3044001304037540062c2c6eb4c108004c108008c100004c0f0dd50038b0b181f000981f001181e000981e001181d000981d001181c000981a1baa0031616303600130360023034001303037540022c2c6064002605c6ea801054ccc0b0c07400454ccc0bcc0b8dd50020a4c2c2c60586ea800c58dd698178009817801181680098168011bad302b00137580022c6eb0c0a0004c0a0008dd6981300098130011bad30240013020375400a2a66603c601e0022a66604260406ea80145261616301e37540084a66603a601e603c6ea80044c8c8c8c94ccc090c09c0084c926325333022301400115333025302437540082930b0a999811180980089919299981398150010a4c2c6eb4c0a0004c090dd50020a99981118090008a99981298121baa00414985858c088dd50018b19299981218118008a999810980918110008a51153330213013302200114a02c2c6ea8c094004c094008c08c004c07cdd50008b119299980e9807800899192999811181280109924c64a666040602400226464a66604a60500042930b1bae3026001302237540042a666040602200226464a66604a60500042930b1bae3026001302237540042c60406ea800458c08c004c07cdd50010a99980e9807000899191919299981218138010991924c6464646464a666054605a0042930b1bad302b001302b002375c605200260520066eb8c09c008c8c8c8c8c94ccc0a4c0b000852616375a605400260540046eb8c0a0004c0a0010dd718130018b1bac3025001302500237586046002603e6ea800854ccc074c0340044c8c94ccc088c0940084c9263232323232323232533302a302d002149858dd6981580098158011bae30290013029003375c604e0046464646464a66605260580042930b1bad302a001302a002375c605000260500066eb8c098008dd618110011bac3020001163253330223025302500113376060480026048604a0022c6eb0c08c004c07cdd50010a99980e9806000899192999811181280109924c6464646464a66604e60540042930b1bad30280013028002375c604c002604c0046eb8c09000458dd61811800980f9baa0021533301d300b0011323253330223025002132498c8c8c8c8c8c8c8c94ccc0a8c0b400852616375a605600260560046eb8c0a4004c0a400cdd718138011919191919299981498160010a4c2c6eb4c0a8004c0a8008dd7181400098140019bae3026002375860440046eb0c08000458c94ccc088c094c0940044cdd81812000981218128008b1bac3023001301f37540042a66603a601400226464a666044604a00426493191bae3022002375c60400022c64a666044604a604a002266ec0c090004c090c09400458dd61811800980f9baa00216301d3754002464a666038601c00226464a66604260480042930b1bae3022001301e37540042a666038601a0022a66603e603c6ea80085261616301c375400260020264a666030601460326ea80044c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc0acc0b80084c8c92632533302a301c00113232533302f3032002132498c05800458c0c0004c0b0dd50038a999815180d8008a99981698161baa00714985858c0a8dd5003191919191bae302e003375c6058004646eb8c0b400cdd718158011919bb0302f001302f30300013758605601c6466ec0c0b8004c0b8c0bc004dd618148068b1bad302c001302c002375a60540026054004605000260500046eb4c098004c098008dd6981200098120011bad3022001302200232533301f302230220011337606042002604260440022c6eb0c080004c080008dd7180f000980d1baa00116300100122325333018300a00113232533301d3020002149858dd7180f000980d1baa00215333018300900113232533301d3020002132498cc0180048cc01801800458dd6180f000980d1baa00215333018300800113232533301d3020002132498cc0180048cc01801800458dd6180f000980d1baa002153330183007001132323232533301f3022002132498cc0200048cc02002000458dd6181000098100011bad301e001301a37540042a666030600c00226464a66603a60400042930b1bad301e001301a37540042a666030600a00226464a66603a60400042930b1bad301e001301a37540042a66603066e1d200c00113232533301d3020002149858dd7180f000980d1baa002163018375400244646600200200644a66603600229309919801801980f8011801980e800980c980b1baa00e370e90051b8748020dc3a400c6e1d2004370e90011b8748000dd2a40006e012002370090009b8f488100375e980103d8798000371290001ba548008dd70009bae0015734aae7555cf2ab9f5740ae855d12611e581c0bf89b13dc30d812fd4fc25122325e8b02b48b7168e30202dcdda59a004c011e581c61ed2a57b7baece734dea4af48c089ac2d3d0fe09fd45023120cc2620001", + "hash": "bd4e886ee59548d9d6a2be480a4b468da8e8177f52ba6ce05b7b24a3" }, { "title": "pool_stake.stake", @@ -120,22 +121,8 @@ "$ref": "#/definitions/Data" } }, - "parameters": [ - { - "title": "settings_policy_id", - "schema": { - "$ref": "#/definitions/ByteArray" - } - }, - { - "title": "_instance", - "schema": { - "$ref": "#/definitions/Int" - } - } - ], - "compiledCode": "590887010000323232323232322322322253330073232323232323232323232323232323253323301833322232330010010042232533301e300b001132323300100100722533302400114a0264a66604466e3cdd718138010020a511330030030013027001375c604660406ea800854ccc078c0280044c8cc004004dd6181218109baa00322533302300114a2264a6660426600c00c604c0042660060060022940c09800454ccc078c0340044c8cc004004dd6181218109baa00322533302300114a0264a6660426600c00c604c00429444cc00c00c004c09800454ccc078c0300044c8cdc49bad3024001323330010013758604a604c004900011129998128010800899980180198140012999811198038039813801099b80001480084004c080dd50010a99980f19b87480200044c8c94ccc080c030c084dd5000899299981099299981298120008a999811180718118008a5115333022300f302300114a02c2c6ea8c048c08cdd5180918119baa007133712002006266e2000400cdd6981298111baa00114a0601260426ea8c040c084dd50029bad3023302037540042a66603c66e1d200a001132325333020300c30213754002264a66604264a66604a60480022a666044601c6046002294454ccc088c03cc08c0045280b0b1baa301230233754601660466ea801c4cdc4801800899b88003001375a604a60446ea8004528180498109baa30093021375400a6eb4c08cc080dd500109919198008008099129998120008a5013253330223375e0086046604e00429444cc00c00c004c09c004c01ccc088cdd2a400466044604660406ea80092f5c097ae0301e3754002601060346ea800cdd6180e980f005180e805099299980c98040008991919299980e1804980e9baa001132533301d3371200664a66603c6014603e6ea8004520001375a604660406ea8004c94ccc078c028c07cdd50008a6103d87a8000132330010013756604860426ea8008894ccc08c004530103d87a8000132323253330233371e91100375c6048006260186604e6ea00052f5c026600a00a0046eb4c090008c09c008c094004c8cc004004dd5980798101baa00222533302200114c103d87a8000132323253330223371e91100375c6046006260166604c6e980052f5c026600a00a0046eacc08c008c098008c0900044cdd79806980f9baa0014c0107d87b9fd87980ff00163021301e37540022c646600200202244a666040002298103d87a800013232533301f3375e601260426ea8008c090c094c094c094c084dd5005098041981180125eb804cc010010004c090008c088004cdc08009919b83337040046eb4c070c94ccc07cc088c0880044cdd81810800981098110008b1bac3001301d375400c6eb4c074c94ccc07cc088c0880044cdd81810800981098110008b1bac3001301d375400c4604060426042604260420026466600200201a9000111299980f801080089919980200218118019919b80375a6040004006603c00260420042a666032600e0022944528180c9baa010374a90000b1180e000991919191919191929998101811801099299980f19b8f375c603e0040382a66603c66ebcdd3000a610ba14873657474696e67730100132533301f300e3020375400226464004a666040601a60426ea80044c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc0ecc0f80084c8c8c8c8c8c8c926330280112302a00132533303e302b0011323253330433046002132498cc0a80048dd70008b1bac3044001304037540262a66607c60540022a66608260806ea804c5261616303e3754024646eb4c0fc050dd6981e809981200a181080a981100b180f80b8b181e000981e0011bad303a001303a002375a607000260700046eb4c0d8004c0d8008dd6981a000981a0011bac303200130320023030001303000232533302d30303030001133760605e002605e60600022c6eb0c0b8004c0b8008c0b0004c0b0008c0a8004c0a8008c0a0004c0a0008c098004c088dd50008b181218109baa00116300e302037540082c2c6eacc07c00458c084004c084dd59806180e9baa001300b301c3754603e6eb0c07c044c00400488c94ccc06cc0200044c8c94ccc080c08c00852616375c6042002603a6ea800854ccc06cc01c0044c8c94ccc080c08c0084c926330070012330060060011637586042002603a6ea800854ccc06cc0280044c8c94ccc080c08c0084c926330070012330060060011637586042002603a6ea800854ccc06cc0240044c8c8c8c94ccc088c0940084c92633009001233008008001163758604600260460046eb4c084004c074dd50010a99980d99b87480200044c8c94ccc080c08c00852616375a6042002603a6ea800854ccc06ccdc3a401400226464a66604060460042930b1bad3021001301d37540042a66603666e1d200c0011323253330203023002149858dd71810800980e9baa00216301b37540024a666030600a60326ea80044c8c8c8c94ccc07cc0880084c8c92632533301e300b0011323253330233026002132498c94ccc084c0380044c8c94ccc098c0a40084c926300e001163027001302337540042a666042601a0022646464646464a666054605a0042930b1bad302b001302b002375a605200260520046eb4c09c004c08cdd50010b18109baa001163024001302037540062a66603c60140022a66604260406ea800c5261616301e3754004600e0062c60400026040004603c00260346ea80045888c8cc00400400c894ccc0740045261323300300330210023003301f0012325333017300400113232533301c301f002149858dd7180e800980c9baa00215333017300300113232533301c301f002149858dd7180e800980c9baa00216301737540026e1d2002370e90001b8748018dc3a40084602c602e602e0024602a602c00260280046eacc048004c048c048c048c048008dd618080009808000980798059baa300e002300d300e0013009375400229309b2b1bad001375c002ae6955ceaab9e5573eae815d0aba201", - "hash": "5843f8c9138598fcaf0270c2bf2eb536fb46b03431cde64275811178" + "compiledCode": "5908af01000033323232323232322322322253330073232323232323232323232323232323253323301833322232330010010042232533301e300b001132323300100100722533302400114a0264a66604466e3cdd718138010020a511330030030013027001375c604660406ea800854ccc078c0280044c8cc004004dd6181218109baa00322533302300114a2264a6660426600c00c604c0042660060060022940c09800454ccc078c0340044c8cc004004dd6181218109baa00322533302300114a0264a6660426600c00c604c00429444cc00c00c004c09800454ccc078c0300044c8cdc49bad3024001323330010013758604a604c004900011129998128010800899980180198140012999811198038039813801099b80001480084004c080dd50010a99980f19b87480200044c8c94ccc080c030c084dd5000899299981099299981298120008a999811180718118008a5115333022300f302300114a02c2c6ea8c048c08cdd5180918119baa007133712002006266e2000400cdd6981298111baa00114a0601260426ea8c040c084dd50029bad3023302037540042a66603c66e1d200a001132325333020300c30213754002264a66604264a66604a60480022a666044601c6046002294454ccc088c03cc08c0045280b0b1baa301230233754601660466ea801c4cdc4801800899b88003001375a604a60446ea8004528180498109baa30093021375400a6eb4c08cc080dd500109919198008008099129998120008a5013253330223375e0086046604e00429444cc00c00c004c09c004c01ccc088cdd2a400466044604660406ea80092f5c097ae0301e3754002601060346ea800cdd6180e980f005180e805099299980c98040008991919299980e1804980e9baa001132533301d3371200664a66603c6014603e6ea8004520001375a604660406ea8004c94ccc078c028c07cdd50008a6103d87a8000132330010013756604860426ea8008894ccc08c004530103d87a8000132323253330233371e91100375c6048006260186604e6ea00052f5c026600a00a0046eb4c090008c09c008c094004c8cc004004dd5980798101baa00222533302200114c103d87a8000132323253330223371e91100375c6046006260166604c6e980052f5c026600a00a0046eacc08c008c098008c0900044cdd79806980f9baa0014c0107d87b9fd87980ff00163021301e37540022c646600200202244a666040002298103d87a800013232533301f3375e601260426ea8008c090c094c094c094c084dd5005098041981180125eb804cc010010004c090008c088004cdc08009919b83337040046eb4c070c94ccc07cc088c0880044cdd81810800981098110008b1bac3001301d375400c6eb4c074c94ccc07cc088c0880044cdd81810800981098110008b1bac3001301d375400c4604060426042604260420026466600200201a9000111299980f801080089919980200218118019919b80375a6040004006603c00260420042a666032600e0022944528180c9baa010374a90000b1180e000991919191919191929998101811801099299980f19b8f375c603e0040382a66603c66ebcdd3000a610ba14873657474696e67730100132533301f300e3020375400226464004a666040601a60426ea80044c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc0ecc0f80084c8c8c8c8c8c8c926330280112302a00132533303e302b0011323253330433046002132498cc0a80048dd70008b1bac3044001304037540262a66607c60540022a66608260806ea804c5261616303e3754024646eb4c0fc050dd6981e809981200a181080a981100b180f80b8b181e000981e0011bad303a001303a002375a607000260700046eb4c0d8004c0d8008dd6981a000981a0011bac303200130320023030001303000232533302d30303030001133760605e002605e60600022c6eb0c0b8004c0b8008c0b0004c0b0008c0a8004c0a8008c0a0004c0a0008c098004c088dd50008b181218109baa00116300e302037540082c2c6eacc07c00458c084004c084dd59806180e9baa001300b301c3754603e6eb0c07c044c00400488c94ccc06cc0200044c8c94ccc080c08c00852616375c6042002603a6ea800854ccc06cc01c0044c8c94ccc080c08c0084c926330070012330060060011637586042002603a6ea800854ccc06cc0280044c8c94ccc080c08c0084c926330070012330060060011637586042002603a6ea800854ccc06cc0240044c8c8c8c94ccc088c0940084c92633009001233008008001163758604600260460046eb4c084004c074dd50010a99980d99b87480200044c8c94ccc080c08c00852616375a6042002603a6ea800854ccc06ccdc3a401400226464a66604060460042930b1bad3021001301d37540042a66603666e1d200c0011323253330203023002149858dd71810800980e9baa00216301b37540024a666030600a60326ea80044c8c8c8c94ccc07cc0880084c8c92632533301e300b0011323253330233026002132498c94ccc084c0380044c8c94ccc098c0a40084c926300e001163027001302337540042a666042601a0022646464646464a666054605a0042930b1bad302b001302b002375a605200260520046eb4c09c004c08cdd50010b18109baa001163024001302037540062a66603c60140022a66604260406ea800c5261616301e3754004600e0062c60400026040004603c00260346ea80045888c8cc00400400c894ccc0740045261323300300330210023003301f0012325333017300400113232533301c301f002149858dd7180e800980c9baa00215333017300300113232533301c301f002149858dd7180e800980c9baa00216301737540026e1d2002370e90001b8748018dc3a40084602c602e602e0024602a602c00260280046eacc048004c048c048c048c048008dd618080009808000980798059baa300e002300d300e0013009375400229309b2b1bad001375c002ae6955ceaab9e5573eae815d0aba24c011e581c61ed2a57b7baece734dea4af48c089ac2d3d0fe09fd45023120cc262004c0101000001", + "hash": "1c6adb136a5c56547632cfff2db0fbdba4f77cc0a686db3b5c455c8a" }, { "title": "settings.spend", @@ -151,8 +138,8 @@ "$ref": "#/definitions/RedeemerWrapper$types~1settings~1SettingsRedeemer" } }, - "compiledCode": "59101f010000332323232323232222532323232323233300a3002300b375400e2a6660146464a6660186008601a6ea80044c8c8c8c8c8c8c8c8c94ccc060c06c0084c8c94ccc05cc04cc060dd5000899299980c0040a99980c00388018a5014a0664646464644a66603a602a603c6ea80044c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc0e0c0ec0084c8c8c8c8c8c8c926330230112302500132533303b30330011323253330403043002132498cc0940048dd70008b1bac3041001303d37540262a66607660640022a66607c607a6ea804c5261616303b3754024646eb4c0f0050dd6981d009980e80a180e80a980d80b180d80b8b181c800981c8011bad30370013037002375a606a002606a0046eb4c0cc004c0cc008dd6981880098188011bac302f001302f002302d001302d00232533302a302d302d00113376060580026058605a0022c6eb0c0ac004c0ac008c0a4004c0a4008c09c004c09c008c094004c094008c08c004c07cdd50008b1299980e180a180e9baa0011323232325333023302600213232498c94ccc088c0680044c8c94ccc09cc0a80084c926325333025301d00113232533302a302d002132498c04000458c0ac004c09cdd50010a999812980e0008991919191919299981718188010a4c2c6eb4c0bc004c0bc008dd6981680098168011bad302b001302737540042c604a6ea800458c0a0004c090dd50018a999811180c8008a99981298121baa00314985858c088dd500118048018b181200098120011811000980f1baa0011630010012232533301c30140011323253330213024002149858dd71811000980f1baa0021533301c30130011323253330213024002132498cc0180048cc01801800458dd61811000980f1baa0021533301c30180011323253330213024002132498cc0180048cc01801800458dd61811000980f1baa0021533301c301700113232323253330233026002132498cc0200048cc02002000458dd6181200098120011bad3022001301e37540042a666038602c00226464a66604260480042930b1bad3022001301e37540042a666038602a00226464a66604260480042930b1bad3022001301e37540042a66603866e1d200c0011323253330213024002149858dd71811000980f1baa00216301c375400244646600200200644a66603e00229309919801801981180118019810800919299980c980880089919299980f18108010a4c2c6eb8c07c004c06cdd50010a99980c980800089919299980f18108010a4c2c6eb8c07c004c06cdd50010b180c9baa001301c301937540022c600860306ea8008cdd79803980b9baa30073017375400266e95200233019375201297ae0163019001323300100137586004602c6ea8c018c058dd500891299980c0008a5eb804c8c94ccc05ccdd79ba6330083756601a60326ea800922100374c0142660360046600800800226600800800260380046034002460306032603200264660020026eb0c010c050dd51802180a1baa00f22533301600114a0264a66602866ebcc018c058dd5180c8010098a5113300300300130190013375e6e98cc004dd5980a980b180b180b180b18091baa30023012375401a910100374c00644646600200200644a66602c002297adef6c6013232323253330173371e00e004200626603666ec0dd48011ba600133006006003375660300066eb8c058008c068008c0600048c050004c94ccc038c015200014bd6f7b6300991919800800a5eb7bdb180894ccc0500044cc054cdd81ba9005374c00697adef6c6013232323253330153375e6601001200498103d8798000133019337606ea4024dd30038028a99980a99b8f009002133019337606ea4024dd300380189980c99bb037520046e98004cc01801800cdd5980b0019bae30140023018002301600132330010014bd6f7b63011299980980089980a19bb04c1094873657474696e6773004c010101004bd6f7b630099191919299980a19baf3300748810873657474696e6773000024c103d879800013301833760981094873657474696e6773004c01010100005153330143371e91010873657474696e677300002133018337609801094873657474696e6773004c01010100003133018337606ea4008dd4000998030030019bad3015003375c6026004602e004602a00244a66601e66e40008004530103d87980001533300f3371e0040022980103d87a800014c103d87b8000375c6022601c6ea800458c004c034dd50041180818088008a4c26cac26646464646464644644a66602864646464646464a666036602660386ea80044c94ccc070cdd79803980f1baa001004132533301d3019301e375400226464646464646464646464a666050604060526ea805c4c94ccc0a4cccc008c050c0acdd50139bac3003302b3754602860566ea8058c010c0acdd5180a18159baa0163756600a60566ea8c050c0acdd500b0a99981499baf00c00115333029009100714a0294052819191919180b19818181880219818181880199818181880119818180498171baa02a3303032374e66062605c00266062605e00297ae0325333030303330330011337606064002606460660022c6eb0c02cc0b8dd501519818181880099818180418171baa02a303230320013031303130310013030001302f001302a3754016264a6660526666004602060566ea809cdd6180198159baa3014302b375402c600860566ea8c050c0acdd500b1bab3005302b3754602860566ea805854ccc0a4cdd78060008a99981480488038a5014a02940c8c8c8c8c058cc0c0c0c4010cc0c0c0c400ccc0c0c0c4008cc0c0c024c0b8dd500799818191ba733031302e00133031302f0014bd7019299981818199819800899bb03032001303230330011637586016605c6ea803ccc0c0c0c4004cc0c0c020c0b8dd5007981918190009818981898188009818000981780098151baa026222232330010010052232533302e3026001132323300100100822533303400114a0264a66606466e3cdd7181b8010020a511330030030013037001375c606660606ea800854ccc0b8c0940044c8cc004004dd6181a18189baa00322533303300114a2264a6660626600c00c606c0042660060060022940c0d800454ccc0b8c0a80044c8cc004004dd6181a18189baa00322533303300114a0264a6660626600c00c606c00429444cc00c00c004c0d800454ccc0b8c0a40044c8cdc49bad3034001323330010013758606a606c0049000111299981a80108008999801801981c001299981919803803981b801099b80001480084004c0c0dd50010a9998171814000899192999818181398189baa00113253330313253330353034001153330323029303300114a22a6660646054606600229405858dd5180e98199baa301d30333754010266e2400400c4cdc40008019bad3035303237540022940c068c0c4dd5180d98189baa006375a606660606ea800854ccc0b8c09c0044c8c94ccc0c0c09cc0c4dd5000899299981899299981a981a0008a999819181498198008a5115333032302a303300114a02c2c6ea8c074c0ccdd5180e18199baa008133712006002266e2000c004dd6981a98191baa00114a0603460626ea8c068c0c4dd50031bad303330303754004264646600200200c44a66606800229404c94ccc0c8cdd78021819981b8010a5113300300300130370013018330323374a900119819181998181baa0024bd7025eb80c0b8dd50009181618169816981698169816981698169816800918159816181618161816181618161816000918151815981598159815981598158009181498151815181500099baf374c660066eacc004c090dd5180698121baa00f4881004c0101a000230273028302830283028001323375e6e98c004dd5980698119baa006374c60026eacc034c08cdd5005119801000a4410022323300100100322533302600114bd6f7b630099191919299981399b8f007002100313302b337606ea4008dd3000998030030019bab3028003375c604c00460540046050002601e0026044603e6ea800458c00cc078dd50008b1810180e9baa0011632533301e00114c0103d87a8000130053301f30200014bd701bac3001301c3754600a60386ea801c8c07cc080c080004c00cc068dd500099299980c1807980c9baa00113253330193011301a37540022600a60366ea8c078c06cdd50008b1991191980080080191299980f8008a6103d87a800013232533301e3375e601260406ea80080144c020cc0880092f5c0266008008002604600460420026eb0c00cc068dd51801980d1baa005301d301a37540022c600660326ea8010dd2a40004603600246034603600229309b2b19299980998058008a99980b180a9baa00214985854ccc04cc02800454ccc058c054dd50010a4c2c2c60266ea8004c00403894ccc040c020c044dd500089919191919191919191919191919191919191919191919192999815981700109919191919191924c660460224604a00264a66605c604c00226464a666066606c004264931981280091bae001163758606800260606ea804c54ccc0b8c09400454ccc0c4c0c0dd50098a4c2c2c605c6ea8048c8dd6981780a1bad302d013301d014301d015301b016301b01716302c001302c002375a605400260540046eb4c0a0004c0a0008dd6981300098130011bad302400130240023758604400260440046040002604000464a66603a60406040002266ec0c07c004c07cc08000458dd6180f000980f001180e000980e001180d000980d001180c000980c001180b00098091baa001162533300f300730103754002264646464a66602c6032004264649319299980a980680089919299980d180e80109924c64a666030602000226464a66603a60400042649318080008b180f000980d1baa00215333018300f001132323232323253330213024002149858dd6981100098110011bad30200013020002375a603c00260346ea800858c060dd50008b180d800980b9baa00315333015300c00115333018301737540062930b0b180a9baa002300900316301700130170023015001301137540022c60020024464a66601e600e00226464a666028602e0042930b1bae3015001301137540042a66601e600c00226464a666028602e00426493198030009198030030008b1bac3015001301137540042a66601e601600226464a666028602e00426493198030009198030030008b1bac3015001301137540042a66601e6014002264646464a66602c603200426493198040009198040040008b1bac30170013017002375a602a00260226ea800854ccc03cc0240044c8c94ccc050c05c00852616375a602a00260226ea800854ccc03cc0200044c8c94ccc050c05c00852616375a602a00260226ea800854ccc03ccdc3a401800226464a666028602e0042930b1bae3015001301137540042c601e6ea800488c8cc00400400c894ccc04800452613233003003301600230033014001232533300c30040011323253330113014002149858dd7180900098071baa0021533300c30030011323253330113014002149858dd7180900098071baa00216300c3754002601e60186ea801cdc3a40046e1d2000370e90051b8748020dc3a400c6e1d20045734aae7555cf2ab9f5740ae855d126012bd8799fd8799f5820ebcee8dcdbd7312f5e04a0033472465003617abe9935a6e56f007961897cfabbff01ff0001", - "hash": "445b77d214aa36d1b2edeedb8ddad49e0b62d80a1f4b08eb9c8b4c8c" + "compiledCode": "59101f010000332323232323232222532323232323233300a3002300b375400e2a6660146464a6660186008601a6ea80044c8c8c8c8c8c8c8c8c94ccc060c06c0084c8c94ccc05cc04cc060dd5000899299980c0040a99980c00388018a5014a0664646464644a66603a602a603c6ea80044c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc0e0c0ec0084c8c8c8c8c8c8c926330230112302500132533303b30330011323253330403043002132498cc0940048dd70008b1bac3041001303d37540262a66607660640022a66607c607a6ea804c5261616303b3754024646eb4c0f0050dd6981d009980e80a180e80a980d80b180d80b8b181c800981c8011bad30370013037002375a606a002606a0046eb4c0cc004c0cc008dd6981880098188011bac302f001302f002302d001302d00232533302a302d302d00113376060580026058605a0022c6eb0c0ac004c0ac008c0a4004c0a4008c09c004c09c008c094004c094008c08c004c07cdd50008b1299980e180a180e9baa0011323232325333023302600213232498c94ccc088c0680044c8c94ccc09cc0a80084c926325333025301d00113232533302a302d002132498c04000458c0ac004c09cdd50010a999812980e0008991919191919299981718188010a4c2c6eb4c0bc004c0bc008dd6981680098168011bad302b001302737540042c604a6ea800458c0a0004c090dd50018a999811180c8008a99981298121baa00314985858c088dd500118048018b181200098120011811000980f1baa0011630010012232533301c30140011323253330213024002149858dd71811000980f1baa0021533301c30130011323253330213024002132498cc0180048cc01801800458dd61811000980f1baa0021533301c30180011323253330213024002132498cc0180048cc01801800458dd61811000980f1baa0021533301c301700113232323253330233026002132498cc0200048cc02002000458dd6181200098120011bad3022001301e37540042a666038602c00226464a66604260480042930b1bad3022001301e37540042a666038602a00226464a66604260480042930b1bad3022001301e37540042a66603866e1d200c0011323253330213024002149858dd71811000980f1baa00216301c375400244646600200200644a66603e00229309919801801981180118019810800919299980c980880089919299980f18108010a4c2c6eb8c07c004c06cdd50010a99980c980800089919299980f18108010a4c2c6eb8c07c004c06cdd50010b180c9baa001301c301937540022c600860306ea8008cdd79803980b9baa30073017375400266e95200233019375201297ae0163019001323300100137586004602c6ea8c018c058dd500891299980c0008a5eb804c8c94ccc05ccdd79ba6330083756601a60326ea800922100374c0142660360046600800800226600800800260380046034002460306032603200264660020026eb0c010c050dd51802180a1baa00f22533301600114a0264a66602866ebcc018c058dd5180c8010098a5113300300300130190013375e6e98cc004dd5980a980b180b180b180b18091baa30023012375401a910100374c00644646600200200644a66602c002297adef6c6013232323253330173371e00e004200626603666ec0dd48011ba600133006006003375660300066eb8c058008c068008c0600048c050004c94ccc038c015200014bd6f7b6300991919800800a5eb7bdb180894ccc0500044cc054cdd81ba9005374c00697adef6c6013232323253330153375e6601001200498103d8798000133019337606ea4024dd30038028a99980a99b8f009002133019337606ea4024dd300380189980c99bb037520046e98004cc01801800cdd5980b0019bae30140023018002301600132330010014bd6f7b63011299980980089980a19bb04c1094873657474696e6773004c010101004bd6f7b630099191919299980a19baf3300748810873657474696e6773000024c103d879800013301833760981094873657474696e6773004c01010100005153330143371e91010873657474696e677300002133018337609801094873657474696e6773004c01010100003133018337606ea4008dd4000998030030019bad3015003375c6026004602e004602a00244a66601e66e40008004530103d87980001533300f3371e0040022980103d87a800014c103d87b8000375c6022601c6ea800458c004c034dd50041180818088008a4c26cac26646464646464644644a66602864646464646464a666036602660386ea80044c94ccc070cdd79803980f1baa001004132533301d3019301e375400226464646464646464646464a666050604060526ea805c4c94ccc0a4cccc008c050c0acdd50139bac3003302b3754602860566ea8058c010c0acdd5180a18159baa0163756600a60566ea8c050c0acdd500b0a99981499baf00c00115333029009100714a0294052819191919180b19818181880219818181880199818181880119818180498171baa02a3303032374e66062605c00266062605e00297ae0325333030303330330011337606064002606460660022c6eb0c02cc0b8dd501519818181880099818180418171baa02a303230320013031303130310013030001302f001302a3754016264a6660526666004602060566ea809cdd6180198159baa3014302b375402c600860566ea8c050c0acdd500b1bab3005302b3754602860566ea805854ccc0a4cdd78060008a99981480488038a5014a02940c8c8c8c8c058cc0c0c0c4010cc0c0c0c400ccc0c0c0c4008cc0c0c024c0b8dd500799818191ba733031302e00133031302f0014bd7019299981818199819800899bb03032001303230330011637586016605c6ea803ccc0c0c0c4004cc0c0c020c0b8dd5007981918190009818981898188009818000981780098151baa026222232330010010052232533302e3026001132323300100100822533303400114a0264a66606466e3cdd7181b8010020a511330030030013037001375c606660606ea800854ccc0b8c0940044c8cc004004dd6181a18189baa00322533303300114a2264a6660626600c00c606c0042660060060022940c0d800454ccc0b8c0a80044c8cc004004dd6181a18189baa00322533303300114a0264a6660626600c00c606c00429444cc00c00c004c0d800454ccc0b8c0a40044c8cdc49bad3034001323330010013758606a606c0049000111299981a80108008999801801981c001299981919803803981b801099b80001480084004c0c0dd50010a9998171814000899192999818181398189baa00113253330313253330353034001153330323029303300114a22a6660646054606600229405858dd5180e98199baa301d30333754010266e2400400c4cdc40008019bad3035303237540022940c068c0c4dd5180d98189baa006375a606660606ea800854ccc0b8c09c0044c8c94ccc0c0c09cc0c4dd5000899299981899299981a981a0008a999819181498198008a5115333032302a303300114a02c2c6ea8c074c0ccdd5180e18199baa008133712006002266e2000c004dd6981a98191baa00114a0603460626ea8c068c0c4dd50031bad303330303754004264646600200200c44a66606800229404c94ccc0c8cdd78021819981b8010a5113300300300130370013018330323374a900119819181998181baa0024bd7025eb80c0b8dd50009181618169816981698169816981698169816800918159816181618161816181618161816000918151815981598159815981598158009181498151815181500099baf374c660066eacc004c090dd5180698121baa00f4881004c0101a000230273028302830283028001323375e6e98c004dd5980698119baa006374c60026eacc034c08cdd5005119801000a4410022323300100100322533302600114bd6f7b630099191919299981399b8f007002100313302b337606ea4008dd3000998030030019bab3028003375c604c00460540046050002601e0026044603e6ea800458c00cc078dd50008b1810180e9baa0011632533301e00114c0103d87a8000130053301f30200014bd701bac3001301c3754600a60386ea801c8c07cc080c080004c00cc068dd500099299980c1807980c9baa00113253330193011301a37540022600a60366ea8c078c06cdd50008b1991191980080080191299980f8008a6103d87a800013232533301e3375e601260406ea80080144c020cc0880092f5c0266008008002604600460420026eb0c00cc068dd51801980d1baa005301d301a37540022c600660326ea8010dd2a40004603600246034603600229309b2b19299980998058008a99980b180a9baa00214985854ccc04cc02800454ccc058c054dd50010a4c2c2c60266ea8004c00403894ccc040c020c044dd500089919191919191919191919191919191919191919191919192999815981700109919191919191924c660460224604a00264a66605c604c00226464a666066606c004264931981280091bae001163758606800260606ea804c54ccc0b8c09400454ccc0c4c0c0dd50098a4c2c2c605c6ea8048c8dd6981780a1bad302d013301d014301d015301b016301b01716302c001302c002375a605400260540046eb4c0a0004c0a0008dd6981300098130011bad302400130240023758604400260440046040002604000464a66603a60406040002266ec0c07c004c07cc08000458dd6180f000980f001180e000980e001180d000980d001180c000980c001180b00098091baa001162533300f300730103754002264646464a66602c6032004264649319299980a980680089919299980d180e80109924c64a666030602000226464a66603a60400042649318080008b180f000980d1baa00215333018300f001132323232323253330213024002149858dd6981100098110011bad30200013020002375a603c00260346ea800858c060dd50008b180d800980b9baa00315333015300c00115333018301737540062930b0b180a9baa002300900316301700130170023015001301137540022c60020024464a66601e600e00226464a666028602e0042930b1bae3015001301137540042a66601e600c00226464a666028602e00426493198030009198030030008b1bac3015001301137540042a66601e601600226464a666028602e00426493198030009198030030008b1bac3015001301137540042a66601e6014002264646464a66602c603200426493198040009198040040008b1bac30170013017002375a602a00260226ea800854ccc03cc0240044c8c94ccc050c05c00852616375a602a00260226ea800854ccc03cc0200044c8c94ccc050c05c00852616375a602a00260226ea800854ccc03ccdc3a401800226464a666028602e0042930b1bae3015001301137540042c601e6ea800488c8cc00400400c894ccc04800452613233003003301600230033014001232533300c30040011323253330113014002149858dd7180900098071baa0021533300c30030011323253330113014002149858dd7180900098071baa00216300c3754002601e60186ea801cdc3a40046e1d2000370e90051b8748020dc3a400c6e1d20045734aae7555cf2ab9f5740ae855d126012bd8799fd8799f5820fad11baadca1e52bf34599746fb0152d9d10b31c2591b79deab34536a7998ea0ff01ff0001", + "hash": "61ed2a57b7baece734dea4af48c089ac2d3d0fe09fd45023120cc262" }, { "title": "settings.mint", @@ -162,8 +149,8 @@ "$ref": "#/definitions/Data" } }, - "compiledCode": "59101f010000332323232323232222532323232323233300a3002300b375400e2a6660146464a6660186008601a6ea80044c8c8c8c8c8c8c8c8c94ccc060c06c0084c8c94ccc05cc04cc060dd5000899299980c0040a99980c00388018a5014a0664646464644a66603a602a603c6ea80044c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc0e0c0ec0084c8c8c8c8c8c8c926330230112302500132533303b30330011323253330403043002132498cc0940048dd70008b1bac3041001303d37540262a66607660640022a66607c607a6ea804c5261616303b3754024646eb4c0f0050dd6981d009980e80a180e80a980d80b180d80b8b181c800981c8011bad30370013037002375a606a002606a0046eb4c0cc004c0cc008dd6981880098188011bac302f001302f002302d001302d00232533302a302d302d00113376060580026058605a0022c6eb0c0ac004c0ac008c0a4004c0a4008c09c004c09c008c094004c094008c08c004c07cdd50008b1299980e180a180e9baa0011323232325333023302600213232498c94ccc088c0680044c8c94ccc09cc0a80084c926325333025301d00113232533302a302d002132498c04000458c0ac004c09cdd50010a999812980e0008991919191919299981718188010a4c2c6eb4c0bc004c0bc008dd6981680098168011bad302b001302737540042c604a6ea800458c0a0004c090dd50018a999811180c8008a99981298121baa00314985858c088dd500118048018b181200098120011811000980f1baa0011630010012232533301c30140011323253330213024002149858dd71811000980f1baa0021533301c30130011323253330213024002132498cc0180048cc01801800458dd61811000980f1baa0021533301c30180011323253330213024002132498cc0180048cc01801800458dd61811000980f1baa0021533301c301700113232323253330233026002132498cc0200048cc02002000458dd6181200098120011bad3022001301e37540042a666038602c00226464a66604260480042930b1bad3022001301e37540042a666038602a00226464a66604260480042930b1bad3022001301e37540042a66603866e1d200c0011323253330213024002149858dd71811000980f1baa00216301c375400244646600200200644a66603e00229309919801801981180118019810800919299980c980880089919299980f18108010a4c2c6eb8c07c004c06cdd50010a99980c980800089919299980f18108010a4c2c6eb8c07c004c06cdd50010b180c9baa001301c301937540022c600860306ea8008cdd79803980b9baa30073017375400266e95200233019375201297ae0163019001323300100137586004602c6ea8c018c058dd500891299980c0008a5eb804c8c94ccc05ccdd79ba6330083756601a60326ea800922100374c0142660360046600800800226600800800260380046034002460306032603200264660020026eb0c010c050dd51802180a1baa00f22533301600114a0264a66602866ebcc018c058dd5180c8010098a5113300300300130190013375e6e98cc004dd5980a980b180b180b180b18091baa30023012375401a910100374c00644646600200200644a66602c002297adef6c6013232323253330173371e00e004200626603666ec0dd48011ba600133006006003375660300066eb8c058008c068008c0600048c050004c94ccc038c015200014bd6f7b6300991919800800a5eb7bdb180894ccc0500044cc054cdd81ba9005374c00697adef6c6013232323253330153375e6601001200498103d8798000133019337606ea4024dd30038028a99980a99b8f009002133019337606ea4024dd300380189980c99bb037520046e98004cc01801800cdd5980b0019bae30140023018002301600132330010014bd6f7b63011299980980089980a19bb04c1094873657474696e6773004c010101004bd6f7b630099191919299980a19baf3300748810873657474696e6773000024c103d879800013301833760981094873657474696e6773004c01010100005153330143371e91010873657474696e677300002133018337609801094873657474696e6773004c01010100003133018337606ea4008dd4000998030030019bad3015003375c6026004602e004602a00244a66601e66e40008004530103d87980001533300f3371e0040022980103d87a800014c103d87b8000375c6022601c6ea800458c004c034dd50041180818088008a4c26cac26646464646464644644a66602864646464646464a666036602660386ea80044c94ccc070cdd79803980f1baa001004132533301d3019301e375400226464646464646464646464a666050604060526ea805c4c94ccc0a4cccc008c050c0acdd50139bac3003302b3754602860566ea8058c010c0acdd5180a18159baa0163756600a60566ea8c050c0acdd500b0a99981499baf00c00115333029009100714a0294052819191919180b19818181880219818181880199818181880119818180498171baa02a3303032374e66062605c00266062605e00297ae0325333030303330330011337606064002606460660022c6eb0c02cc0b8dd501519818181880099818180418171baa02a303230320013031303130310013030001302f001302a3754016264a6660526666004602060566ea809cdd6180198159baa3014302b375402c600860566ea8c050c0acdd500b1bab3005302b3754602860566ea805854ccc0a4cdd78060008a99981480488038a5014a02940c8c8c8c8c058cc0c0c0c4010cc0c0c0c400ccc0c0c0c4008cc0c0c024c0b8dd500799818191ba733031302e00133031302f0014bd7019299981818199819800899bb03032001303230330011637586016605c6ea803ccc0c0c0c4004cc0c0c020c0b8dd5007981918190009818981898188009818000981780098151baa026222232330010010052232533302e3026001132323300100100822533303400114a0264a66606466e3cdd7181b8010020a511330030030013037001375c606660606ea800854ccc0b8c0940044c8cc004004dd6181a18189baa00322533303300114a2264a6660626600c00c606c0042660060060022940c0d800454ccc0b8c0a80044c8cc004004dd6181a18189baa00322533303300114a0264a6660626600c00c606c00429444cc00c00c004c0d800454ccc0b8c0a40044c8cdc49bad3034001323330010013758606a606c0049000111299981a80108008999801801981c001299981919803803981b801099b80001480084004c0c0dd50010a9998171814000899192999818181398189baa00113253330313253330353034001153330323029303300114a22a6660646054606600229405858dd5180e98199baa301d30333754010266e2400400c4cdc40008019bad3035303237540022940c068c0c4dd5180d98189baa006375a606660606ea800854ccc0b8c09c0044c8c94ccc0c0c09cc0c4dd5000899299981899299981a981a0008a999819181498198008a5115333032302a303300114a02c2c6ea8c074c0ccdd5180e18199baa008133712006002266e2000c004dd6981a98191baa00114a0603460626ea8c068c0c4dd50031bad303330303754004264646600200200c44a66606800229404c94ccc0c8cdd78021819981b8010a5113300300300130370013018330323374a900119819181998181baa0024bd7025eb80c0b8dd50009181618169816981698169816981698169816800918159816181618161816181618161816000918151815981598159815981598158009181498151815181500099baf374c660066eacc004c090dd5180698121baa00f4881004c0101a000230273028302830283028001323375e6e98c004dd5980698119baa006374c60026eacc034c08cdd5005119801000a4410022323300100100322533302600114bd6f7b630099191919299981399b8f007002100313302b337606ea4008dd3000998030030019bab3028003375c604c00460540046050002601e0026044603e6ea800458c00cc078dd50008b1810180e9baa0011632533301e00114c0103d87a8000130053301f30200014bd701bac3001301c3754600a60386ea801c8c07cc080c080004c00cc068dd500099299980c1807980c9baa00113253330193011301a37540022600a60366ea8c078c06cdd50008b1991191980080080191299980f8008a6103d87a800013232533301e3375e601260406ea80080144c020cc0880092f5c0266008008002604600460420026eb0c00cc068dd51801980d1baa005301d301a37540022c600660326ea8010dd2a40004603600246034603600229309b2b19299980998058008a99980b180a9baa00214985854ccc04cc02800454ccc058c054dd50010a4c2c2c60266ea8004c00403894ccc040c020c044dd500089919191919191919191919191919191919191919191919192999815981700109919191919191924c660460224604a00264a66605c604c00226464a666066606c004264931981280091bae001163758606800260606ea804c54ccc0b8c09400454ccc0c4c0c0dd50098a4c2c2c605c6ea8048c8dd6981780a1bad302d013301d014301d015301b016301b01716302c001302c002375a605400260540046eb4c0a0004c0a0008dd6981300098130011bad302400130240023758604400260440046040002604000464a66603a60406040002266ec0c07c004c07cc08000458dd6180f000980f001180e000980e001180d000980d001180c000980c001180b00098091baa001162533300f300730103754002264646464a66602c6032004264649319299980a980680089919299980d180e80109924c64a666030602000226464a66603a60400042649318080008b180f000980d1baa00215333018300f001132323232323253330213024002149858dd6981100098110011bad30200013020002375a603c00260346ea800858c060dd50008b180d800980b9baa00315333015300c00115333018301737540062930b0b180a9baa002300900316301700130170023015001301137540022c60020024464a66601e600e00226464a666028602e0042930b1bae3015001301137540042a66601e600c00226464a666028602e00426493198030009198030030008b1bac3015001301137540042a66601e601600226464a666028602e00426493198030009198030030008b1bac3015001301137540042a66601e6014002264646464a66602c603200426493198040009198040040008b1bac30170013017002375a602a00260226ea800854ccc03cc0240044c8c94ccc050c05c00852616375a602a00260226ea800854ccc03cc0200044c8c94ccc050c05c00852616375a602a00260226ea800854ccc03ccdc3a401800226464a666028602e0042930b1bae3015001301137540042c601e6ea800488c8cc00400400c894ccc04800452613233003003301600230033014001232533300c30040011323253330113014002149858dd7180900098071baa0021533300c30030011323253330113014002149858dd7180900098071baa00216300c3754002601e60186ea801cdc3a40046e1d2000370e90051b8748020dc3a400c6e1d20045734aae7555cf2ab9f5740ae855d126012bd8799fd8799f5820ebcee8dcdbd7312f5e04a0033472465003617abe9935a6e56f007961897cfabbff01ff0001", - "hash": "445b77d214aa36d1b2edeedb8ddad49e0b62d80a1f4b08eb9c8b4c8c" + "compiledCode": "59101f010000332323232323232222532323232323233300a3002300b375400e2a6660146464a6660186008601a6ea80044c8c8c8c8c8c8c8c8c94ccc060c06c0084c8c94ccc05cc04cc060dd5000899299980c0040a99980c00388018a5014a0664646464644a66603a602a603c6ea80044c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c8c94ccc0e0c0ec0084c8c8c8c8c8c8c926330230112302500132533303b30330011323253330403043002132498cc0940048dd70008b1bac3041001303d37540262a66607660640022a66607c607a6ea804c5261616303b3754024646eb4c0f0050dd6981d009980e80a180e80a980d80b180d80b8b181c800981c8011bad30370013037002375a606a002606a0046eb4c0cc004c0cc008dd6981880098188011bac302f001302f002302d001302d00232533302a302d302d00113376060580026058605a0022c6eb0c0ac004c0ac008c0a4004c0a4008c09c004c09c008c094004c094008c08c004c07cdd50008b1299980e180a180e9baa0011323232325333023302600213232498c94ccc088c0680044c8c94ccc09cc0a80084c926325333025301d00113232533302a302d002132498c04000458c0ac004c09cdd50010a999812980e0008991919191919299981718188010a4c2c6eb4c0bc004c0bc008dd6981680098168011bad302b001302737540042c604a6ea800458c0a0004c090dd50018a999811180c8008a99981298121baa00314985858c088dd500118048018b181200098120011811000980f1baa0011630010012232533301c30140011323253330213024002149858dd71811000980f1baa0021533301c30130011323253330213024002132498cc0180048cc01801800458dd61811000980f1baa0021533301c30180011323253330213024002132498cc0180048cc01801800458dd61811000980f1baa0021533301c301700113232323253330233026002132498cc0200048cc02002000458dd6181200098120011bad3022001301e37540042a666038602c00226464a66604260480042930b1bad3022001301e37540042a666038602a00226464a66604260480042930b1bad3022001301e37540042a66603866e1d200c0011323253330213024002149858dd71811000980f1baa00216301c375400244646600200200644a66603e00229309919801801981180118019810800919299980c980880089919299980f18108010a4c2c6eb8c07c004c06cdd50010a99980c980800089919299980f18108010a4c2c6eb8c07c004c06cdd50010b180c9baa001301c301937540022c600860306ea8008cdd79803980b9baa30073017375400266e95200233019375201297ae0163019001323300100137586004602c6ea8c018c058dd500891299980c0008a5eb804c8c94ccc05ccdd79ba6330083756601a60326ea800922100374c0142660360046600800800226600800800260380046034002460306032603200264660020026eb0c010c050dd51802180a1baa00f22533301600114a0264a66602866ebcc018c058dd5180c8010098a5113300300300130190013375e6e98cc004dd5980a980b180b180b180b18091baa30023012375401a910100374c00644646600200200644a66602c002297adef6c6013232323253330173371e00e004200626603666ec0dd48011ba600133006006003375660300066eb8c058008c068008c0600048c050004c94ccc038c015200014bd6f7b6300991919800800a5eb7bdb180894ccc0500044cc054cdd81ba9005374c00697adef6c6013232323253330153375e6601001200498103d8798000133019337606ea4024dd30038028a99980a99b8f009002133019337606ea4024dd300380189980c99bb037520046e98004cc01801800cdd5980b0019bae30140023018002301600132330010014bd6f7b63011299980980089980a19bb04c1094873657474696e6773004c010101004bd6f7b630099191919299980a19baf3300748810873657474696e6773000024c103d879800013301833760981094873657474696e6773004c01010100005153330143371e91010873657474696e677300002133018337609801094873657474696e6773004c01010100003133018337606ea4008dd4000998030030019bad3015003375c6026004602e004602a00244a66601e66e40008004530103d87980001533300f3371e0040022980103d87a800014c103d87b8000375c6022601c6ea800458c004c034dd50041180818088008a4c26cac26646464646464644644a66602864646464646464a666036602660386ea80044c94ccc070cdd79803980f1baa001004132533301d3019301e375400226464646464646464646464a666050604060526ea805c4c94ccc0a4cccc008c050c0acdd50139bac3003302b3754602860566ea8058c010c0acdd5180a18159baa0163756600a60566ea8c050c0acdd500b0a99981499baf00c00115333029009100714a0294052819191919180b19818181880219818181880199818181880119818180498171baa02a3303032374e66062605c00266062605e00297ae0325333030303330330011337606064002606460660022c6eb0c02cc0b8dd501519818181880099818180418171baa02a303230320013031303130310013030001302f001302a3754016264a6660526666004602060566ea809cdd6180198159baa3014302b375402c600860566ea8c050c0acdd500b1bab3005302b3754602860566ea805854ccc0a4cdd78060008a99981480488038a5014a02940c8c8c8c8c058cc0c0c0c4010cc0c0c0c400ccc0c0c0c4008cc0c0c024c0b8dd500799818191ba733031302e00133031302f0014bd7019299981818199819800899bb03032001303230330011637586016605c6ea803ccc0c0c0c4004cc0c0c020c0b8dd5007981918190009818981898188009818000981780098151baa026222232330010010052232533302e3026001132323300100100822533303400114a0264a66606466e3cdd7181b8010020a511330030030013037001375c606660606ea800854ccc0b8c0940044c8cc004004dd6181a18189baa00322533303300114a2264a6660626600c00c606c0042660060060022940c0d800454ccc0b8c0a80044c8cc004004dd6181a18189baa00322533303300114a0264a6660626600c00c606c00429444cc00c00c004c0d800454ccc0b8c0a40044c8cdc49bad3034001323330010013758606a606c0049000111299981a80108008999801801981c001299981919803803981b801099b80001480084004c0c0dd50010a9998171814000899192999818181398189baa00113253330313253330353034001153330323029303300114a22a6660646054606600229405858dd5180e98199baa301d30333754010266e2400400c4cdc40008019bad3035303237540022940c068c0c4dd5180d98189baa006375a606660606ea800854ccc0b8c09c0044c8c94ccc0c0c09cc0c4dd5000899299981899299981a981a0008a999819181498198008a5115333032302a303300114a02c2c6ea8c074c0ccdd5180e18199baa008133712006002266e2000c004dd6981a98191baa00114a0603460626ea8c068c0c4dd50031bad303330303754004264646600200200c44a66606800229404c94ccc0c8cdd78021819981b8010a5113300300300130370013018330323374a900119819181998181baa0024bd7025eb80c0b8dd50009181618169816981698169816981698169816800918159816181618161816181618161816000918151815981598159815981598158009181498151815181500099baf374c660066eacc004c090dd5180698121baa00f4881004c0101a000230273028302830283028001323375e6e98c004dd5980698119baa006374c60026eacc034c08cdd5005119801000a4410022323300100100322533302600114bd6f7b630099191919299981399b8f007002100313302b337606ea4008dd3000998030030019bab3028003375c604c00460540046050002601e0026044603e6ea800458c00cc078dd50008b1810180e9baa0011632533301e00114c0103d87a8000130053301f30200014bd701bac3001301c3754600a60386ea801c8c07cc080c080004c00cc068dd500099299980c1807980c9baa00113253330193011301a37540022600a60366ea8c078c06cdd50008b1991191980080080191299980f8008a6103d87a800013232533301e3375e601260406ea80080144c020cc0880092f5c0266008008002604600460420026eb0c00cc068dd51801980d1baa005301d301a37540022c600660326ea8010dd2a40004603600246034603600229309b2b19299980998058008a99980b180a9baa00214985854ccc04cc02800454ccc058c054dd50010a4c2c2c60266ea8004c00403894ccc040c020c044dd500089919191919191919191919191919191919191919191919192999815981700109919191919191924c660460224604a00264a66605c604c00226464a666066606c004264931981280091bae001163758606800260606ea804c54ccc0b8c09400454ccc0c4c0c0dd50098a4c2c2c605c6ea8048c8dd6981780a1bad302d013301d014301d015301b016301b01716302c001302c002375a605400260540046eb4c0a0004c0a0008dd6981300098130011bad302400130240023758604400260440046040002604000464a66603a60406040002266ec0c07c004c07cc08000458dd6180f000980f001180e000980e001180d000980d001180c000980c001180b00098091baa001162533300f300730103754002264646464a66602c6032004264649319299980a980680089919299980d180e80109924c64a666030602000226464a66603a60400042649318080008b180f000980d1baa00215333018300f001132323232323253330213024002149858dd6981100098110011bad30200013020002375a603c00260346ea800858c060dd50008b180d800980b9baa00315333015300c00115333018301737540062930b0b180a9baa002300900316301700130170023015001301137540022c60020024464a66601e600e00226464a666028602e0042930b1bae3015001301137540042a66601e600c00226464a666028602e00426493198030009198030030008b1bac3015001301137540042a66601e601600226464a666028602e00426493198030009198030030008b1bac3015001301137540042a66601e6014002264646464a66602c603200426493198040009198040040008b1bac30170013017002375a602a00260226ea800854ccc03cc0240044c8c94ccc050c05c00852616375a602a00260226ea800854ccc03cc0200044c8c94ccc050c05c00852616375a602a00260226ea800854ccc03ccdc3a401800226464a666028602e0042930b1bae3015001301137540042c601e6ea800488c8cc00400400c894ccc04800452613233003003301600230033014001232533300c30040011323253330113014002149858dd7180900098071baa0021533300c30030011323253330113014002149858dd7180900098071baa00216300c3754002601e60186ea801cdc3a40046e1d2000370e90051b8748020dc3a400c6e1d20045734aae7555cf2ab9f5740ae855d126012bd8799fd8799f5820fad11baadca1e52bf34599746fb0152d9d10b31c2591b79deab34536a7998ea0ff01ff0001", + "hash": "61ed2a57b7baece734dea4af48c089ac2d3d0fe09fd45023120cc262" }, { "title": "stake.stake", @@ -173,8 +160,8 @@ "$ref": "#/definitions/Data" } }, - "compiledCode": "5901420100003323232323232322322253330053253330063370e900218039baa300130083754004264a66600e66e1d2000300837540022646600200264a66601266e1d2002300a3754002297adef6c6013756601c60166ea8004c8cc004004dd5980218059baa300e300b375400644a66601a0022980103d87a80001323232533300d3371e0166eb8c03800c4cdd2a4000660226e980052f5c026600a00a0046eacc038008c044008c03c004894ccc030004528099299980519b873371c6eb8c02cc03c00920024806852889980180180098078008b1929998050008a6103d87a800013374a9000198059806000a5eb80dd618059806180618041baa300b3008375400429408c02cc03000452613656375c002ae6955ceaab9e5573eae815d0aba24c011e581c760318f4ced18f4983fc9bd63005ef187efb4d270520d47a076737510001", - "hash": "4387fbb60eacf2c0cd44188552a1be36cad9d2816432529e750be40d" + "compiledCode": "5901420100003323232323232322322253330053253330063370e900218039baa300130083754004264a66600e66e1d2000300837540022646600200264a66601266e1d2002300a3754002297adef6c6013756601c60166ea8004c8cc004004dd5980218059baa300e300b375400644a66601a0022980103d87a80001323232533300d3371e0166eb8c03800c4cdd2a4000660226e980052f5c026600a00a0046eacc038008c044008c03c004894ccc030004528099299980519b873371c6eb8c02cc03c00920024806852889980180180098078008b1929998050008a6103d87a800013374a9000198059806000a5eb80dd618059806180618041baa300b3008375400429408c02cc03000452613656375c002ae6955ceaab9e5573eae815d0aba24c011e581cbd4e886ee59548d9d6a2be480a4b468da8e8177f52ba6ce05b7b24a30001", + "hash": "637dc1c0f2f7e3eb672582dff481680a0a3d4ebc5a7ce67ce4eaf0a1" } ], "definitions": { @@ -543,6 +530,40 @@ } ] }, + "aiken/transaction/Datum": { + "title": "Datum", + "description": "An output `Datum`.", + "anyOf": [ + { + "title": "NoDatum", + "dataType": "constructor", + "index": 0, + "fields": [] + }, + { + "title": "DatumHash", + "description": "A datum referenced by its hash digest.", + "dataType": "constructor", + "index": 1, + "fields": [ + { + "$ref": "#/definitions/ByteArray" + } + ] + }, + { + "title": "InlineDatum", + "description": "A datum completely inlined in the output.", + "dataType": "constructor", + "index": 2, + "fields": [ + { + "$ref": "#/definitions/Data" + } + ] + } + ] + }, "aiken/transaction/OutputReference": { "title": "OutputReference", "description": "An `OutputReference` is a unique reference to an output on-chain. The `output_index`\n corresponds to the position in the output list of the transaction (identified by its id)\n that produced that output", @@ -749,6 +770,42 @@ } ] }, + "types/oracle/OracleDatum": { + "title": "OracleDatum", + "anyOf": [ + { + "title": "OracleDatum", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "owner", + "$ref": "#/definitions/sundae~1multisig~1MultisigScript" + }, + { + "title": "valid_range", + "$ref": "#/definitions/aiken~1interval~1Interval$Int" + }, + { + "title": "pool_ident", + "$ref": "#/definitions/ByteArray" + }, + { + "title": "reserve_a", + "$ref": "#/definitions/Tuple$ByteArray_ByteArray_Int" + }, + { + "title": "reserve_b", + "$ref": "#/definitions/Tuple$ByteArray_ByteArray_Int" + }, + { + "title": "circulating_lp", + "$ref": "#/definitions/Tuple$ByteArray_ByteArray_Int" + } + ] + } + ] + }, "types/oracle/OracleRedeemer": { "title": "OracleRedeemer", "anyOf": [ @@ -773,6 +830,36 @@ } ] }, + "types/order/Destination": { + "title": "Destination", + "description": "The destination where funds are to be sent after the order", + "anyOf": [ + { + "title": "Fixed", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "address", + "description": "The address to attach to the output (such as the users wallet, or another script)", + "$ref": "#/definitions/aiken~1transaction~1credential~1Address" + }, + { + "title": "datum", + "description": "The datum to attach to the output; Could be none in typical cases, but could also be used to compose with other protocols,\n such as paying the results of a swap back to a treasury contract", + "$ref": "#/definitions/aiken~1transaction~1Datum" + } + ] + }, + { + "title": "Self", + "description": "The result gets paid back to the exact same address and datum it came from; useful for strategies\n with unbounded legs", + "dataType": "constructor", + "index": 1, + "fields": [] + } + ] + }, "types/order/Order": { "title": "Order", "description": "The specific order details for executing an order", @@ -854,6 +941,49 @@ } ] }, + "types/order/OrderDatum": { + "title": "OrderDatum", + "description": "An order to execute within the SundaeSwap ecosystem", + "anyOf": [ + { + "title": "OrderDatum", + "dataType": "constructor", + "index": 0, + "fields": [ + { + "title": "pool_ident", + "description": "An optional pool identifier against which this order must be executed\n If set to none, the order is allowed to execute against any pool with the\n correct assets.", + "$ref": "#/definitions/Option$ByteArray" + }, + { + "title": "owner", + "description": "An canonical \"owner\" of this order, with the possibility of multisig\n schemes and script restrictions. Allows updates or cancellations of the order", + "$ref": "#/definitions/sundae~1multisig~1MultisigScript" + }, + { + "title": "max_protocol_fee", + "description": "The maximum amount of ADA that can be taken as a protocol fee\n For example, a user would typically set this to baseFee + incrementalFee\n which allows their order to execute as the only order in a batch; if it\n executes as a larger batch, the user may receive some of this ADA back as a rebate.", + "$ref": "#/definitions/Int" + }, + { + "title": "destination", + "description": "Where the output of executing an order should be sent", + "$ref": "#/definitions/types~1order~1Destination" + }, + { + "title": "details", + "description": "A description of how to actually execute the order", + "$ref": "#/definitions/types~1order~1Order" + }, + { + "title": "extension", + "description": "The pool contracts should work with any order contract that adheres to this datum;\n to aid in extensibility, we leave room here for arbitrary extension data that other\n order scripts might want to take advantage of.", + "$ref": "#/definitions/Data" + } + ] + } + ] + }, "types/order/OrderRedeemer": { "title": "OrderRedeemer", "description": "An order can be spent either to Scoop (execute) it, or to cancel it", @@ -884,7 +1014,7 @@ "index": 0, "fields": [ { - "title": "strategy", + "title": "execution", "description": "The details about how to execute the strategy for a given order", "$ref": "#/definitions/types~1order~1StrategyExecution" }, @@ -960,6 +1090,7 @@ }, "types/pool/ManageRedeemer": { "title": "ManageRedeemer", + "description": "Manage settings about a pool (used against the pool manage script)", "anyOf": [ { "title": "WithdrawFees", @@ -1019,12 +1150,12 @@ }, { "title": "bid_fees_per_10_thousand", - "description": "The basis points to charge on each trade for bid (A -> B) and ask (B -> A) orders\n For example, a 1% fee would be represented as 100 (out of 10,000), and a 0.3% fee would be represented as 30\n The two values represent the fees as of `market_open` and as of `fee_finalized`, respectively, with a linear\n decay from one to the other.\n The transaction uses the valid_from field to charge the largest fee the transaction *could* be obligated to pay", - "$ref": "#/definitions/Tuple$Int_Int" + "description": "The basis points to charge on each trade for bid (A -> B) and ask (B -> A) orders\n For example, a 1% fee would be represented as 100 (out of 10,000), and a 0.3% fee would be represented as 30", + "$ref": "#/definitions/Int" }, { "title": "ask_fees_per_10_thousand", - "$ref": "#/definitions/Tuple$Int_Int" + "$ref": "#/definitions/Int" }, { "title": "fee_manager", @@ -1035,11 +1166,6 @@ "description": "The UNIX millisecond timestamp at which trading against the pool should be allowed\n TODO: deposits and arguably withdrawals should be processed before the market open", "$ref": "#/definitions/Int" }, - { - "title": "fee_finalized", - "description": "The UNIX millisecond timestamp at which the fees reach their final resting state\n For example, a pool may be opened at a 20% fee, and decay gradually down to a 1% fee pool over the course of the first month.", - "$ref": "#/definitions/Int" - }, { "title": "protocol_fees", "description": "The amount of ADA on the UTXO that is set aside by collecting protocol fees\n This should be increased on each scoop to represent collecting fees; deducted from the reserve amount (if one of the tokens in the pair is ADA)\n to calculate the swap amounts, and decreased when some amount is withdrawn.\n Note that this also allows us to conveniently sidestep minUTXO woes, because the creator of the pool can set the initial protocol fees to whatever minUTXO is needed\n and withdrawals never have to be for the full amount.\n TODO: should we add a field to the settings object to set a minimum initial protocol_fees on pool mint?", diff --git a/validators/documentation.ak b/validators/documentation.ak new file mode 100644 index 0000000..03a2988 --- /dev/null +++ b/validators/documentation.ak @@ -0,0 +1,7 @@ +use types/order.{OrderDatum} + +validator { + fn spend(_d: OrderDatum, _r: Data, _ctx: Data) { + True + } +} diff --git a/validators/oracle.ak b/validators/oracle.ak index 523af93..b9349a8 100644 --- a/validators/oracle.ak +++ b/validators/oracle.ak @@ -1,16 +1,19 @@ use aiken/dict -use aiken/list use aiken/hash.{Blake2b_224, Hash} use aiken/interval -use aiken/transaction.{Transaction, TransactionId, Input, OutputReference, Output, ScriptContext, InlineDatum} +use aiken/list +use aiken/transaction.{ + InlineDatum, Input, Output, OutputReference, ScriptContext, Transaction, + TransactionId, +} use aiken/transaction/credential.{Address, Script, ScriptCredential} use aiken/transaction/value -use sundae/multisig use shared -use types/order.{OrderDatum, Fixed} +use sundae/multisig +use tests/examples/ex_shared.{mk_tx_hash, script_address} +use types/oracle.{Burn, Mint, OracleDatum, OracleRedeemer} +use types/order.{Fixed, OrderDatum} use types/pool.{PoolDatum} -use types/oracle.{OracleRedeemer, OracleDatum, Mint, Burn} -use tests/examples/ex_shared.{script_address, mk_tx_hash} // The oracle script holds an oracle token, and a snapshot of the pool price at the *end* of some scoop. // This allows other protocols to build integrations that read the pool price (for some confidence interval) without worrying about contention @@ -28,10 +31,10 @@ validator(pool_script_hash: Hash) { // This allows reclaiming funds that were accidentally locked at the script address, // while also enforcing that the oracle token is burned; this is important, as people // will be relying on the oracle token to authenticate the actual values - fn spend(datum: Data, _r: Data, ctx: ScriptContext) -> Bool { + fn spend(datum: OracleDatum, _r: Data, ctx: ScriptContext) -> Bool { let own_input = shared.spent_output(ctx) - expect ScriptCredential(own_script_hash) = own_input.address.payment_credential - expect datum: OracleDatum = datum + expect ScriptCredential(own_script_hash) = + own_input.address.payment_credential and { multisig.satisfied( datum.owner, @@ -42,11 +45,16 @@ validator(pool_script_hash: Hash) { list.all( ctx.transaction.outputs, fn(output) { - value.quantity_of(output.value, own_script_hash, shared.oracle_sft_name()) == 0 + value.quantity_of( + output.value, + own_script_hash, + shared.oracle_sft_name(), + ) == 0 }, - ) + ), } } + // In order to mint an orcale token, two things must be true: // - each oracle token on the outputs must be paid with a quantity of 1 to the oracle script // - the datum for each must have the correct timing and pricing information @@ -62,20 +70,31 @@ validator(pool_script_hash: Hash) { // Find the pool output, i.e. the one with the pool NFT, so we can record the prices expect Some(pool_output) = list.head(ctx.transaction.outputs) - expect pool_output.address.payment_credential == ScriptCredential(pool_script_hash) - expect value.quantity_of(pool_output.value, own_policy_id, pool_nft_name) == 1 + expect + pool_output.address.payment_credential == ScriptCredential( + pool_script_hash, + ) + expect + value.quantity_of(pool_output.value, own_policy_id, pool_nft_name) == 1 // Then unpack the pool datum expect InlineDatum(pool_datum) = pool_output.datum expect pool_datum: PoolDatum = pool_datum - let PoolDatum { - assets: (asset_a, asset_b), - circulating_lp, - .. - } = pool_datum + let PoolDatum { assets: (asset_a, asset_b), circulating_lp, .. } = + pool_datum - let reserve_a = (asset_a.1st, asset_a.2nd, value.quantity_of(pool_output.value, asset_a.1st, asset_a.2nd)) - let reserve_b = (asset_b.1st, asset_b.2nd, value.quantity_of(pool_output.value, asset_b.1st, asset_b.2nd)) + let reserve_a = + ( + asset_a.1st, + asset_a.2nd, + value.quantity_of(pool_output.value, asset_a.1st, asset_a.2nd), + ) + let reserve_b = + ( + asset_b.1st, + asset_b.2nd, + value.quantity_of(pool_output.value, asset_b.1st, asset_b.2nd), + ) let circulating_lp = (pool_script_hash, pool_lp_name, circulating_lp) let oracle_name = shared.oracle_sft_name() @@ -83,37 +102,47 @@ validator(pool_script_hash: Hash) { // For each output that produces an oracle, there should be an oracle // order in the inputs given by the nth item of the order_indices list // in the redeemer - let (_, no_duplicate_minted_oracles) = list.foldl( - ctx.transaction.outputs, - (0, True), - fn(output, state) { - let (oracle_minted_index, no_duplicates) = state - let qty = value.quantity_of(output.value, own_policy_id, oracle_name) - when qty is { - 0 -> (oracle_minted_index, no_duplicates) - 1 -> { - expect Some(this_order_index) = list.at(order_indices, oracle_minted_index) - expect Some(oracle_order) = list.at(ctx.transaction.inputs, this_order_index) - expect Some(oracle_order_datum) = shared.datum_of(ctx.transaction.datums, oracle_order.output) - expect oracle_order_datum: OrderDatum = oracle_order_datum - expect owner = oracle_order_datum.extension - expect owner: multisig.MultisigScript = owner + let (_, no_duplicate_minted_oracles) = + list.foldl( + ctx.transaction.outputs, + (0, True), + fn(output, state) { + let (oracle_minted_index, no_duplicates) = state + let qty = + value.quantity_of(output.value, own_policy_id, oracle_name) + when qty is { + 0 -> (oracle_minted_index, no_duplicates) + 1 -> { + expect Some(this_order_index) = + list.at(order_indices, oracle_minted_index) + expect Some(oracle_order) = + list.at(ctx.transaction.inputs, this_order_index) + expect Some(oracle_order_datum) = + shared.datum_of(ctx.transaction.datums, oracle_order.output) + expect oracle_order_datum: OrderDatum = oracle_order_datum + expect owner = oracle_order_datum.extension + expect owner: multisig.MultisigScript = owner - expect output.address.payment_credential == ScriptCredential(own_policy_id) - expect Some(oracle_datum) = shared.datum_of(ctx.transaction.datums, output) - expect oracle_datum: OracleDatum = oracle_datum - expect oracle_datum.valid_range == ctx.transaction.validity_range - expect oracle_datum.pool_ident == pool_ident - expect oracle_datum.owner == owner - expect reserve_a == oracle_datum.reserve_a - expect reserve_b == oracle_datum.reserve_b - expect circulating_lp == oracle_datum.circulating_lp - (oracle_minted_index + 1, no_duplicates) + expect + output.address.payment_credential == ScriptCredential( + own_policy_id, + ) + expect Some(oracle_datum) = + shared.datum_of(ctx.transaction.datums, output) + expect oracle_datum: OracleDatum = oracle_datum + expect + oracle_datum.valid_range == ctx.transaction.validity_range + expect oracle_datum.pool_ident == pool_ident + expect oracle_datum.owner == owner + expect reserve_a == oracle_datum.reserve_a + expect reserve_b == oracle_datum.reserve_b + expect circulating_lp == oracle_datum.circulating_lp + (oracle_minted_index + 1, no_duplicates) + } + _ -> (0, False) } - _ -> (0, False) - } - } - ) + }, + ) no_duplicate_minted_oracles } Burn -> True @@ -122,43 +151,21 @@ validator(pool_script_hash: Hash) { } test oracle_basic() { - mint_oracle( - identity, - identity, - identity, - ) + mint_oracle(identity, identity, identity) } test oracle_burn_mint() { - mint_oracle( - identity, - identity, - fn(_) { - Burn - } - ) + mint_oracle(identity, identity, fn(_) { Burn }) } test oracle_redeemer_indices_can_have_extras() { let pool_id = #"00" - mint_oracle( - identity, - identity, - fn(_) { - Mint(pool_id, [0, 1, 999, -1]) - } - ) + mint_oracle(identity, identity, fn(_) { Mint(pool_id, [0, 1, 999, -1]) }) } test oracle_redeemer_indices_must_match_up() fail { let pool_id = #"00" - mint_oracle( - identity, - identity, - fn(_) { - Mint(pool_id, [1, 0]) - } - ) + mint_oracle(identity, identity, fn(_) { Mint(pool_id, [1, 0]) }) } // Minting policy enforces that the reserves are correct @@ -184,9 +191,7 @@ test oracle_fake_token() { reserve_a: ("", "", 1_000_000_000_000_000_000), } }, - fn(_) { - "fake" - }, + fn(_) { "fake" }, identity, ) } @@ -196,136 +201,156 @@ fn mint_oracle( modify_oracle_name: fn(ByteArray) -> ByteArray, modify_redeemer: fn(OracleRedeemer) -> OracleRedeemer, ) { - let oracle_policy_id = #"00000000000000000000000000000000000000000000000000000000" - let oracle_address = Address { - payment_credential: ScriptCredential(oracle_policy_id), - stake_credential: None, - } - let order_address = Address { - payment_credential: ScriptCredential(#"1234"), - stake_credential: None, - } - let pool_script_hash = #"00000000000000000000000000000000000000000000000000000000" + let oracle_policy_id = + #"00000000000000000000000000000000000000000000000000000000" + let oracle_address = + Address { + payment_credential: ScriptCredential(oracle_policy_id), + stake_credential: None, + } + let order_address = + Address { + payment_credential: ScriptCredential(#"1234"), + stake_credential: None, + } + let pool_script_hash = + #"00000000000000000000000000000000000000000000000000000000" let pool_address = script_address(pool_script_hash) - let rberry_policy_id = #"9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77" + let rberry_policy_id = + #"9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77" let rberry_token_name = #"524245525259" let pool_id = #"00" let pool_lp_name = shared.pool_lp_name(pool_id) let pool_nft_name = shared.pool_nft_name(pool_id) // This looks like a fresh pool but pretend that we're scooping - let pool_output = Output { - address: pool_address, - value: value.from_lovelace(1_000_000_000) - |> value.add(rberry_policy_id, rberry_token_name, 1_000_000_000) - |> value.add(pool_script_hash, pool_nft_name, 1), - datum: InlineDatum(PoolDatum { - identifier: pool_id, - assets: ((#"", #""), (rberry_policy_id, rberry_token_name)), - circulating_lp: 1_000_000_000, - bid_fees_per_10_thousand: (5, 5), - ask_fees_per_10_thousand: (5, 5), - fee_manager: None, - market_open: 0, - fee_finalized: 0, - protocol_fees: 2_000_000, - }), - reference_script: None, - } + let pool_output = + Output { + address: pool_address, + value: value.from_lovelace(1_000_000_000) + |> value.add(rberry_policy_id, rberry_token_name, 1_000_000_000) + |> value.add(pool_script_hash, pool_nft_name, 1), + datum: InlineDatum( + PoolDatum { + identifier: pool_id, + assets: ((#"", #""), (rberry_policy_id, rberry_token_name)), + circulating_lp: 1_000_000_000, + bid_fees_per_10_thousand: 5, + ask_fees_per_10_thousand: 5, + fee_manager: None, + market_open: 0, + protocol_fees: 2_000_000, + }, + ), + reference_script: None, + } let user_1_multisig = multisig.Signature(#"01") let user_2_multisig = multisig.Signature(#"02") let oracle_name = modify_oracle_name(shared.oracle_sft_name()) - let oracle_order_input_1 = Input { - output_reference: OutputReference { - transaction_id: TransactionId { hash: #"00" }, - output_index: 0, - }, - output: Output { - address: order_address, - value: value.from_lovelace(1_000_000), - datum: InlineDatum(OrderDatum { - pool_ident: None, - owner: multisig.AnyOf([]), - max_protocol_fee: 1_000_000, - destination: Fixed(oracle_address, InlineDatum(multisig.AnyOf([]))), - details: order.Record((oracle_policy_id, oracle_name)), - extension: user_1_multisig, - }), - reference_script: None, - }, - } - let oracle_order_input_2 = Input { - output_reference: OutputReference { - transaction_id: TransactionId { hash: #"00" }, - output_index: 1, - }, - output: Output { - address: order_address, - value: value.from_lovelace(1_000_000), - datum: InlineDatum(OrderDatum { - pool_ident: None, - owner: multisig.AnyOf([]), - max_protocol_fee: 1_000_000, - destination: Fixed(oracle_address, InlineDatum(multisig.AnyOf([]))), - details: order.Record((oracle_policy_id, oracle_name)), - extension: user_2_multisig, - }), - reference_script: None, - }, - } - - let oracleMintRedeemer = modify_redeemer(Mint(pool_id, [0, 1])) - let oracle_output_1 = Output { - address: script_address(oracle_policy_id), - value: value.from_lovelace(1_000_000) - |> value.add(oracle_policy_id, oracle_name, 1), - datum: InlineDatum(modify_oracle_datum( - OracleDatum { - owner: user_1_multisig, - valid_range: interval.between(1, 2), - pool_ident: pool_id, - reserve_a: ("", "", 1_000_000_000), - reserve_b: (rberry_policy_id, rberry_token_name, 1_000_000_000), - circulating_lp: (pool_script_hash, pool_lp_name, 1_000_000_000), + let oracle_order_input_1 = + Input { + output_reference: OutputReference { + transaction_id: TransactionId { hash: #"00" }, + output_index: 0, }, - )), - reference_script: None, - } - let oracle_output_2 = Output { - address: script_address(oracle_policy_id), - value: value.from_lovelace(1_000_000) - |> value.add(oracle_policy_id, oracle_name, 1), - datum: InlineDatum(modify_oracle_datum( - OracleDatum { - owner: user_2_multisig, - valid_range: interval.between(1, 2), - pool_ident: pool_id, - reserve_a: ("", "", 1_000_000_000), - reserve_b: (rberry_policy_id, rberry_token_name, 1_000_000_000), - circulating_lp: (pool_script_hash, pool_lp_name, 1_000_000_000), + output: Output { + address: order_address, + value: value.from_lovelace(1_000_000), + datum: InlineDatum( + OrderDatum { + pool_ident: None, + owner: multisig.AnyOf([]), + max_protocol_fee: 1_000_000, + destination: Fixed(oracle_address, InlineDatum(multisig.AnyOf([]))), + details: order.Record((oracle_policy_id, oracle_name)), + extension: user_1_multisig, + }, + ), + reference_script: None, }, - )), - reference_script: None, - } - let ctx = ScriptContext { - transaction: Transaction { - inputs: [oracle_order_input_1, oracle_order_input_2], - outputs: [pool_output, oracle_output_1, oracle_output_2], - reference_inputs: [], - fee: value.from_lovelace(1_000_000), - mint: value.to_minted_value( - value.from_lovelace(0) - |> value.add(oracle_policy_id, oracle_name, 1) + } + let oracle_order_input_2 = + Input { + output_reference: OutputReference { + transaction_id: TransactionId { hash: #"00" }, + output_index: 1, + }, + output: Output { + address: order_address, + value: value.from_lovelace(1_000_000), + datum: InlineDatum( + OrderDatum { + pool_ident: None, + owner: multisig.AnyOf([]), + max_protocol_fee: 1_000_000, + destination: Fixed(oracle_address, InlineDatum(multisig.AnyOf([]))), + details: order.Record((oracle_policy_id, oracle_name)), + extension: user_2_multisig, + }, + ), + reference_script: None, + }, + } + + let oracleMintRedeemer = modify_redeemer(Mint(pool_id, [0, 1])) + let oracle_output_1 = + Output { + address: script_address(oracle_policy_id), + value: value.from_lovelace(1_000_000) + |> value.add(oracle_policy_id, oracle_name, 1), + datum: InlineDatum( + modify_oracle_datum( + OracleDatum { + owner: user_1_multisig, + valid_range: interval.between(1, 2), + pool_ident: pool_id, + reserve_a: ("", "", 1_000_000_000), + reserve_b: (rberry_policy_id, rberry_token_name, 1_000_000_000), + circulating_lp: (pool_script_hash, pool_lp_name, 1_000_000_000), + }, + ), ), - certificates: [], - withdrawals: dict.new(), - validity_range: interval.between(1, 2), - extra_signatories: [], - redeemers: dict.new(), - datums: dict.new(), - id: mk_tx_hash(1), - }, - purpose: transaction.Mint(oracle_policy_id), - } + reference_script: None, + } + let oracle_output_2 = + Output { + address: script_address(oracle_policy_id), + value: value.from_lovelace(1_000_000) + |> value.add(oracle_policy_id, oracle_name, 1), + datum: InlineDatum( + modify_oracle_datum( + OracleDatum { + owner: user_2_multisig, + valid_range: interval.between(1, 2), + pool_ident: pool_id, + reserve_a: ("", "", 1_000_000_000), + reserve_b: (rberry_policy_id, rberry_token_name, 1_000_000_000), + circulating_lp: (pool_script_hash, pool_lp_name, 1_000_000_000), + }, + ), + ), + reference_script: None, + } + let ctx = + ScriptContext { + transaction: Transaction { + inputs: [oracle_order_input_1, oracle_order_input_2], + outputs: [pool_output, oracle_output_1, oracle_output_2], + reference_inputs: [], + fee: value.from_lovelace(1_000_000), + mint: value.to_minted_value( + value.from_lovelace(0) + |> value.add(oracle_policy_id, oracle_name, 1), + ), + certificates: [], + withdrawals: dict.new(), + validity_range: interval.between(1, 2), + extra_signatories: [], + redeemers: dict.new(), + datums: dict.new(), + id: mk_tx_hash(1), + }, + purpose: transaction.Mint(oracle_policy_id), + } let result = mint(oracle_policy_id, oracleMintRedeemer, ctx) result } diff --git a/validators/order.ak b/validators/order.ak index 692329e..5b88503 100644 --- a/validators/order.ak +++ b/validators/order.ak @@ -40,17 +40,21 @@ validator(stake_script_hash: Hash) { ctx.transaction.withdrawals, ) } - Scoop -> { - dict.foldl(ctx.transaction.withdrawals, False, fn(withdrawal, _amt, acc) { - when withdrawal is { - // TODO: we could make this more efficient by CBOR encoding the `Inline(ScriptCredential())` into the `stake_script_hash` parameter - // or perhaps even the whole withdrawal list to compare it all at once! - // and just doing a direct equaltiy comparison. Since this runs for each order, this could represent significant savings! - Inline(ScriptCredential(script)) -> acc || script == stake_script_hash - _ -> acc - } - }) - } + Scoop -> + dict.foldl( + ctx.transaction.withdrawals, + False, + fn(withdrawal, _amt, acc) { + when withdrawal is { + // TODO: we could make this more efficient by CBOR encoding the `Inline(ScriptCredential())` into the `stake_script_hash` parameter + // or perhaps even the whole withdrawal list to compare it all at once! + // and just doing a direct equaltiy comparison. Since this runs for each order, this could represent significant savings! + Inline(ScriptCredential(script)) -> + acc || script == stake_script_hash + _ -> acc + } + }, + ) } } } diff --git a/validators/pool.ak b/validators/pool.ak index b0f8917..7445b49 100644 --- a/validators/pool.ak +++ b/validators/pool.ak @@ -4,21 +4,25 @@ use aiken/hash.{Blake2b_224, Hash} use aiken/interval use aiken/list use aiken/transaction.{ - InlineDatum, Input, Mint, Output, OutputReference, - ScriptContext, Transaction, TransactionId, WithdrawFrom, Spend, + InlineDatum, Input, Mint, Output, OutputReference, ScriptContext, Transaction, + TransactionId, WithdrawFrom, } -use aiken/transaction/credential.{ - Address, Inline, Script, ScriptCredential, +use aiken/transaction/credential.{Address, Inline, Script, ScriptCredential} +use aiken/transaction/value.{ + AssetName, MintedValue, PolicyId, Value, ada_policy_id, } -use aiken/transaction/value.{MintedValue, PolicyId, AssetName, Value, ada_policy_id} use calculation/process.{pool_input_to_state, process_orders} -use shared.{AssetClass, Ident, spent_output, pool_nft_name, pool_lp_name, count_orders} +use shared.{ + AssetClass, Ident, count_orders, own_input_index, pool_lp_name, pool_nft_name, + spent_output, +} use sundae/multisig use types/pool.{ - CreatePool, MintLP, PoolDatum, PoolMintRedeemer, PoolRedeemer, PoolScoop, - BurnPool, Manage, ManageRedeemer, WithdrawFees, UpdatePoolFees, + BurnPool, CreatePool, Manage, ManageRedeemer, MintLP, PoolDatum, + PoolMintRedeemer, PoolRedeemer, PoolScoop, UpdatePoolFees, WithdrawFees, } use types/settings.{SettingsDatum, find_settings_datum} + /// The core / base "pooled AMM" script for the SundaeSwap v3 protocol /// /// Parameterized by the Settings policy ID, which makes the script unique, as well as lets us validate / read global settings. @@ -45,9 +49,11 @@ use types/settings.{SettingsDatum, find_settings_datum} /// It is likely, then, that protocols converge on the per-order cost of batching being lower than un-batched variants, i.e. /// /// A + B*n + C < (A + B) * n -validator(manage_stake_script_hash: Hash, settings_policy_id: PolicyId) { +validator( + manage_stake_script_hash: Hash, + settings_policy_id: PolicyId, +) { pub fn spend(datum: PoolDatum, redeemer: PoolRedeemer, ctx: ScriptContext) { - // First, we destructure the transaction right upfront, because field access is O(n), // and we want access to these fields with just a single pass over the transaction // This will be a common pattern throughout the scripts @@ -70,26 +76,24 @@ validator(manage_stake_script_hash: Hash, settings_policy_i // And pattern match to get the pool script hash; in particular, this can be used to find the pool output, // *and* to know the policy ID of pool tokens, because this is a dual spending/minting validator. - expect ScriptCredential(pool_script_hash) = pool_input.address.payment_credential + expect ScriptCredential(pool_script_hash) = + pool_input.address.payment_credential // The protocol configures many global settings via a "settings" UTXO, updatable by certain administrators // This is included as a reference input, so we have a utility to check the reference inputs for the settings NFT // Note: it's important to check for the NFT, because checking just for the address would let someone pay random funds to the settings address. - let settings_datum = find_settings_datum(reference_inputs, settings_policy_id) + let settings_datum = + find_settings_datum(reference_inputs, settings_policy_id) // Then, there are two different actions that can be taken against a pool: // - Scooping a batch of orders // - Withdrawing protocol fees to the treasury when redeemer is { // In the case of the scoop, the redeemer indicates which scooper is doing the scoop, and the order in which the inputs should be processed - PoolScoop{ signatory_index, scooper_index, input_order } -> { + PoolScoop { signatory_index, scooper_index, input_order } -> { // Find the pool output, the output datum, and destructure it to access the fields we need to process the scoop let ( - Output { - address: pool_output_address, - value: pool_output_value, - .. - }, + Output { address: pool_output_address, value: pool_output_value, .. }, PoolDatum { identifier: actual_identifier, circulating_lp: actual_circulating_lp, @@ -99,7 +103,7 @@ validator(manage_stake_script_hash: Hash, settings_policy_i ask_fees_per_10_thousand: actual_ask_fees_per_10_thousand, market_open: actual_market_open, .. - } + }, ) = find_pool_output(outputs) // Ensure that the pool output is to the same payment credential; This is critical, because it ensures that the pool NFT @@ -107,11 +111,19 @@ validator(manage_stake_script_hash: Hash, settings_policy_i // Note that we check the stake credential is correctly updated (or not) in the various redeemer cases below. // We also check that the pool output has the correct output, which ensures it contains the pool NFT, // meaning this can't just be a "token output" with the correct payment credential, but everything paid elsewhere. - expect pool_output_address.payment_credential == ScriptCredential(pool_script_hash) + expect + pool_output_address.payment_credential == ScriptCredential( + pool_script_hash, + ) // Deconstruct the settings datum with the fields we need for a scoop - let SettingsDatum { authorized_scoopers, base_fee, simple_fee, strategy_fee, .. } = - settings_datum + 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 @@ -121,7 +133,8 @@ validator(manage_stake_script_hash: Hash, settings_policy_i // 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 + 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 @@ -131,39 +144,82 @@ validator(manage_stake_script_hash: Hash, settings_policy_i // (excluding protocol fees, which shouldn't factor into the price) // Note: this abomination is brought to you by the fact that constructing and destructuring structs // is expensive, so it's cheaper to have **massive** lambdas / continuations - let pool_policy_a, pool_asset_name_a, pool_quantity_a, - pool_policy_b, pool_asset_name_b, pool_quantity_b, - pool_policy_lp, pool_asset_name_lp, pool_quantity_lp, - bid_fees, ask_fees, initial_protocol_fees - <- pool_input_to_state(pool_script_hash, datum, pool_input, validity_range.lower_bound) + let + pool_policy_a, + pool_asset_name_a, + pool_quantity_a, + pool_policy_b, + pool_asset_name_b, + pool_quantity_b, + pool_policy_lp, + pool_asset_name_lp, + pool_quantity_lp, + bid_fees, + ask_fees, + initial_protocol_fees, + <- + pool_input_to_state( + pool_script_hash, + datum, + pool_input, + ) // Process the orders in order, and decide the final pool state we should see // This also counts up the number of simple / strategy orders, which let us compute the effective protocol fee. // for optimization purposes, there are quite a lot of parameters, and their interaction is quite subtle - let final_a, final_b, final_lp, simple_count, strategy_count <- + let + final_a, + final_b, + final_lp, + simple_count, + strategy_count, + <- process_orders( - actual_identifier, // The pool identifier, so we can check that each order is for this pool - validity_range, // The validity range of the transaction, so we can check strategies haven't expired - withdrawals, // Include the withdrawals, in case a strategy has some kind of attached script condition - datums, // The datums, so we can look up the datum of each order (which may be inline, but may also be in the datums dict) + actual_identifier, + // The pool identifier, so we can check that each order is for this pool + validity_range, + // The validity range of the transaction, so we can check strategies haven't expired + withdrawals, + // Include the withdrawals, in case a strategy has some kind of attached script condition + datums, + // The datums, so we can look up the datum of each order (which may be inline, but may also be in the datums dict) // The initial pool state, such as the reserves and circulating LP - pool_policy_a, pool_asset_name_a, pool_quantity_a, - pool_policy_b, pool_asset_name_b, pool_quantity_b, - pool_policy_lp, pool_asset_name_lp, pool_quantity_lp, - input_order, // The input ordering specified by the scooper - bid_fees, // The liquidity provider fee to charge for bids (A -> B), in parts per 10,000 (basis points) - ask_fees, // ... for Ask (swap B -> A) - amortized_base_fee, // The base fee split by the number of orders, paid for each user - simple_fee, // The fee to charge for each "simple" order (swap, deposit, withdrawal, etc.) - strategy_fee, // The fee to charge for each "strategy" order - 0, // The previous index we processed, intitially 0; this lets us detect if we need to "restart" the input list - inputs, // *All* inputs, so we can start over at the beginning of the list if we want - inputs, // *Remaining* inputs, so we can advance through the list one by one so long as the orders are in order - list.drop(outputs, 1), // The list of outputs we should be comparing orders against - 0, // A uniqueness bit-flag, to detect which orders have already been processed; see lib/calculation/InputSorting.md - 0, // The accumulated count of "simple" orders, for calculating the fee; set to 0 to start, but incremented in each recursion - 0, // The accumulated count of "strategy" orders, see line above. + pool_policy_a, + pool_asset_name_a, + pool_quantity_a, + pool_policy_b, + pool_asset_name_b, + pool_quantity_b, + pool_policy_lp, + pool_asset_name_lp, + pool_quantity_lp, + input_order, + // The input ordering specified by the scooper + bid_fees, + // The liquidity provider fee to charge for bids (A -> B), in parts per 10,000 (basis points) + ask_fees, + // ... for Ask (swap B -> A) + amortized_base_fee, + // The base fee split by the number of orders, paid for each user + simple_fee, + // The fee to charge for each "simple" order (swap, deposit, withdrawal, etc.) + strategy_fee, + // The fee to charge for each "strategy" order + 0, + // The previous index we processed, intitially 0; this lets us detect if we need to "restart" the input list + inputs, + // *All* inputs, so we can start over at the beginning of the list if we want + inputs, + // *Remaining* inputs, so we can advance through the list one by one so long as the orders are in order + list.drop(outputs, 1), + // The list of outputs we should be comparing orders against + 0, + // A uniqueness bit-flag, to detect which orders have already been processed; see lib/calculation/InputSorting.md + 0, + // The accumulated count of "simple" orders, for calculating the fee; set to 0 to start, but incremented in each recursion + 0, ) + // The accumulated count of "strategy" orders, see line above. // 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 expect simple_count + strategy_count == real_order_count @@ -172,36 +228,35 @@ validator(manage_stake_script_hash: Hash, settings_policy_i // 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 + amortized_base_fee * real_order_count + simple_count * simple_fee + strategy_count * strategy_fee // Make sure we actually increased the protocol fee by exactly this amount - expect actual_protocol_fees == initial_protocol_fees + expected_fees_collected + 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 // TODO: do we need to account for this? it seems to have gotten lost in some changes. - expect minted_correct_pool_tokens( - pool_script_hash, mint, datum, - final_lp, - ) + expect + minted_correct_pool_tokens(pool_script_hash, mint, datum, final_lp) // Check that the scooper is authorized; the protocol can allow *any* scoopers, or limit it to a set of actors // It's safe to use values provided in the redeemer to efficiently skip to the expected scooper / expected signature // because at the end of the day, we just care that the scooper has signed the transaction. If the scooper provides // anything but the correct indexes, it'll just fail the transaction. - expect when authorized_scoopers is { - Some(authorized_scoopers) -> { - // OPTIMIZATION: skip 10 entries at a time - // OPTIMIZATION: assume scooper is first extra_signatory? have to assume there will only ever be one extra_signatory - expect Some(scooper_sig) = list.at(extra_signatories, signatory_index) - expect Some(scooper) = list.at(authorized_scoopers, scooper_index) - // must be an authorized scooper - scooper_sig == scooper + expect + when authorized_scoopers is { + Some(authorized_scoopers) -> { + // OPTIMIZATION: skip 10 entries at a time + // OPTIMIZATION: assume scooper is first extra_signatory? have to assume there will only ever be one extra_signatory + expect Some(scooper_sig) = + list.at(extra_signatories, signatory_index) + expect Some(scooper) = list.at(authorized_scoopers, scooper_index) + // must be an authorized scooper + scooper_sig == scooper + } + _ -> True } - _ -> True - } // the market must have opened; this allows projects to pre-create their pool, potentially across multiple protocols, and allows // people to open orders ahead of time, and avoids things like sniping bots, etc. @@ -220,8 +275,13 @@ validator(manage_stake_script_hash: Hash, settings_policy_i pool_script_hash, actual_identifier, pool_output_value, - pool_policy_a, pool_asset_name_a, final_a, - pool_policy_b, pool_asset_name_b, final_b, + pool_policy_a, + pool_asset_name_a, + final_a, + pool_policy_b, + pool_asset_name_b, + final_b, + final_lp, actual_protocol_fees, ) // Now, we check various things about the output datum to ensure they're each correct. @@ -232,7 +292,8 @@ validator(manage_stake_script_hash: Hash, settings_policy_i expect actual_circulating_lp == final_lp // Make sure the protocol fees have been correctly updated - expect actual_protocol_fees == initial_protocol_fees + expected_fees_collected + expect + actual_protocol_fees == initial_protocol_fees + expected_fees_collected // And make sure each of these fields is unchanged and { @@ -245,31 +306,35 @@ validator(manage_stake_script_hash: Hash, settings_policy_i pool_input.address.stake_credential == pool_output_address.stake_credential, } } - Manage -> { - // There must be a redeemer for a withdrawal against the manage stake script, - // and the redeemer must be valid - dict.foldl(ctx.transaction.redeemers, False, fn(script_purpose, redeemer, acc) { - when script_purpose is { - WithdrawFrom(Inline(ScriptCredential(script))) -> { - let is_valid_manage_script_invoke = - if script == manage_stake_script_hash { - expect redeemer: ManageRedeemer = redeemer - let redeemer_pool_input = when redeemer is { - UpdatePoolFees { pool_input } -> pool_input - WithdrawFees { pool_input, .. } -> pool_input + Manage -> + // There must be a redeemer for a (stake-script) withdrawal against the manage stake script, + // and the redeemer must correctly point at the pool UTXO + dict.foldl( + ctx.transaction.redeemers, + False, + fn(script_purpose, redeemer, acc) { + when script_purpose is { + WithdrawFrom(Inline(ScriptCredential(script))) -> { + let is_valid_manage_script_invoke = + if script == manage_stake_script_hash { + expect redeemer: ManageRedeemer = redeemer + let redeemer_pool_input = + when redeemer is { + UpdatePoolFees { pool_input } -> pool_input + WithdrawFees { pool_input, .. } -> pool_input + } + let input_index = own_input_index(ctx) + // Manage redeemer must have the correct index of this pool input + input_index == redeemer_pool_input + } else { + False } - expect Spend(OutputReference { output_index, .. }) = ctx.purpose - // Manage redeemer must have the correct index of this pool input - output_index == redeemer_pool_input - } else { - False - } acc || is_valid_manage_script_invoke + } + _ -> acc } - _ -> acc - } - }) - } + }, + ) } } @@ -330,18 +395,19 @@ validator(manage_stake_script_hash: Hash, settings_policy_i |> bytearray.concat(#"23") // '#' character |> bytearray.concat(first_input_index) |> hash.blake2b_256 - |> bytearray.drop(4) + |> bytearray.drop(4) // With that pool identifier, we can attach 3 different CIP-68 pool identifiers: // - (100) indicates a tracking token, for the purposes of on-chain metadata read by off-chain infra, so we can provide a nice experience to the users wallet for example // - (222) indicates the pool NFT, which uniquely identifies the UTXO that holds pool assets // - (333) indicates the fungible LP token, which represents a percentage ownership of the pool - let (new_pool_ref_token, new_pool_nft_token, new_pool_lp_token) = shared.pool_token_names(new_pool_id) + let (new_pool_ref_token, new_pool_nft_token, new_pool_lp_token) = + shared.pool_token_names(new_pool_id) // Then, find the settings datum, so we can ensure the reference token is paid to the metadata admin let reference_inputs = ctx.transaction.reference_inputs - let settings_datum = find_settings_datum(reference_inputs, settings_policy_id) - + let settings_datum = + find_settings_datum(reference_inputs, settings_policy_id) // Grab the initial reserves of each token by looking at what's paid to the UTXO let coin_a_amt = @@ -350,7 +416,8 @@ validator(manage_stake_script_hash: Hash, settings_policy_i value.quantity_of(pool_output.value, asset_b.1st, asset_b.2nd) // Ensure that the pool pays the pool creation fee, if any, by ensuring that the initial protocol_fees value is greater than or equal to the fee - expect pool_output_datum.protocol_fees >= settings_datum.pool_creation_fee + expect + pool_output_datum.protocol_fees >= settings_datum.pool_creation_fee // Only ada has a null policy id. If coin A is ada, subtract the initial protocol_fees setting from the coin A amount // rider from the output to get the true amount in the pool. @@ -368,22 +435,34 @@ validator(manage_stake_script_hash: Hash, settings_policy_i // In particular, though, we don't calculate the sqrt here, which is an expensive function; we instead verify that the // amount minted is valid by checking that it squares to the correct product let initial_lq = pool_output_datum.circulating_lp - expect shared.is_sqrt(coin_a_amt_sans_protocol_fees * coin_b_amt, initial_lq) + expect + shared.is_sqrt(coin_a_amt_sans_protocol_fees * coin_b_amt, initial_lq) // And check that we mint the correct tokens, and nothing else. let expected_mint = - shared.to_value((own_policy_id, new_pool_ref_token, 1)) + shared.to_value((own_policy_id, new_pool_ref_token, 1)) |> value.merge(shared.to_value((own_policy_id, new_pool_nft_token, 1))) - |> value.merge(shared.to_value((own_policy_id, new_pool_lp_token, initial_lq))) + |> value.merge( + shared.to_value((own_policy_id, new_pool_lp_token, initial_lq)), + ) let mint_is_correct = value.from_minted_value(ctx.transaction.mint) == expected_mint // Confirm that the correct funds (asset A, asset B, the correct amount of ADA, and the pool NFT) get paid to the pool output - let funds_spent_to_pool = has_expected_pool_value(own_policy_id, new_pool_id, pool_output.value, - asset_a.1st, asset_a.2nd, coin_a_amt_sans_protocol_fees, - asset_b.1st, asset_b.2nd, coin_b_amt, - pool_output_datum.protocol_fees - ) + let funds_spent_to_pool = + has_expected_pool_value( + own_policy_id, + new_pool_id, + pool_output.value, + asset_a.1st, + asset_a.2nd, + coin_a_amt_sans_protocol_fees, + asset_b.1st, + asset_b.2nd, + coin_b_amt, + initial_lq, + pool_output_datum.protocol_fees, + ) // Make sure we send the pool metadata token to the metadata admin // We use an index from the redeemer to skip to the right output, in case there are multiple outputs to the metadata admin @@ -391,13 +470,18 @@ validator(manage_stake_script_hash: Hash, settings_policy_i expect Some(metadata_output) = list.at(ctx.transaction.outputs, metadata_output_ix) expect metadata_output.address == settings_datum.metadata_admin - expect value.quantity_of(metadata_output.value, own_policy_id, new_pool_ref_token) == 1 + expect + value.quantity_of( + metadata_output.value, + own_policy_id, + new_pool_ref_token, + ) == 1 + // We also check that the datum on the metadata output is void; It would be complex and in-flexible to enforce any particular structure on this, so we // instead leave it to the metadata admin to spend the output and provide it the correct datum; We also don't want to leave it unspecified, because // 1) the metadata admin might actually be a script address, in which case having no datum will permanently lock the metadata // 2) the pool minter might include malicious metadata, such as an icon pointing at hardcore porn; until the metadata admin spent it, this would appear in users wallets, // and potentially even on access UIs for the Sundae protocol - expect metadata_output.datum == InlineDatum(Void) // And check that the datum is initialized correctly; This is part of why we have a minting policy handling this, @@ -406,25 +490,31 @@ validator(manage_stake_script_hash: Hash, settings_policy_i // - the pool identifier is set correctly // - the assets is set correctly // - the initial circulating supply is set correctly - // - the market open time is before the fee finalized time; TODO: should we relax this? - // I'm not sure it's harmful if someone initializes this with a feeFinalized in the past // - the initial and final fees per 10,000 are both non-negative (>= 0%) // - the intitial and final fees per 10,000 are both less than or equal to 10000 (<= 100%) let pool_output_datum_correct = and { - pool_output_datum.identifier == new_pool_id, - pool_output_datum.assets == (asset_a, asset_b), - pool_output_datum.circulating_lp == initial_lq, - pool_output_datum.market_open <= pool_output_datum.fee_finalized, - shared.fees_in_legal_range(pool_output_datum.bid_fees_per_10_thousand), - shared.fees_in_legal_range(pool_output_datum.ask_fees_per_10_thousand), - } + pool_output_datum.identifier == new_pool_id, + pool_output_datum.assets == (asset_a, asset_b), + pool_output_datum.circulating_lp == initial_lq, + shared.fees_in_legal_range( + pool_output_datum.bid_fees_per_10_thousand, + ), + shared.fees_in_legal_range( + pool_output_datum.ask_fees_per_10_thousand, + ), + } // Make sure that the pool output is paid into own_policy_id (the pool script, remember this is a multivalidator) // and that one of the valid staking addresses is attached - expect pool_output.address.payment_credential == ScriptCredential(own_policy_id) - expect list.any(settings_datum.authorized_staking_keys, fn(a) { - pool_output.address.stake_credential == Some(Inline(a)) - }) + expect + pool_output.address.payment_credential == ScriptCredential( + own_policy_id, + ) + expect + list.any( + settings_datum.authorized_staking_keys, + fn(a) { pool_output.address.stake_credential == Some(Inline(a)) }, + ) // And then check each of the conditions above as the condition for minting and { @@ -454,8 +544,14 @@ validator(manage_stake_script_hash: Hash, settings_policy_i let pool_nft_name = shared.pool_nft_name(pool_ident) expect Some(pool_output) = list.head(ctx.transaction.outputs) and { - (pool_output.value |> value.quantity_of(own_policy_id, pool_nft_name)) == 1, - (ctx.transaction.mint |> value.from_minted_value |> value.quantity_of(own_policy_id, pool_nft_name)) == 0, + ( + pool_output.value |> value.quantity_of(own_policy_id, pool_nft_name) + ) == 1, + ( + ctx.transaction.mint + |> value.from_minted_value + |> value.quantity_of(own_policy_id, pool_nft_name) + ) == 0, } } BurnPool(pool_ident) -> { @@ -472,15 +568,15 @@ validator(manage_stake_script_hash: Hash, settings_policy_i } fn find_pool_output(outputs: List) -> (Output, PoolDatum) { - // Find the pool output; we can assume the pool output is the first output, because: - // - The ledger doesn't reorder outputs, just inputs - // - We check that the address is correct, so if the first output was to a different contract, we would fail - // - We check that the datum is the correct type, meaning we can't construct an invalid pool output - // - Later, we check that the pool output has the correct value, meaning it *must* contain the pool token, so we can't pay to the pool script multiple times - expect Some(pool_output) = list.head(outputs) - expect InlineDatum(output_datum) = pool_output.datum - expect output_datum: PoolDatum = output_datum - (pool_output, output_datum) + // Find the pool output; we can assume the pool output is the first output, because: + // - The ledger doesn't reorder outputs, just inputs + // - We check that the address is correct, so if the first output was to a different contract, we would fail + // - We check that the datum is the correct type, meaning we can't construct an invalid pool output + // - Later, we check that the pool output has the correct value, meaning it *must* contain the pool token, so we can't pay to the pool script multiple times + expect Some(pool_output) = list.head(outputs) + expect InlineDatum(output_datum) = pool_output.datum + expect output_datum: PoolDatum = output_datum + (pool_output, output_datum) } /// This is responsible for checking that the minting value on the transaction is valid @@ -505,10 +601,7 @@ fn minted_correct_pool_tokens( dict.is_empty(minted_tokens) } else { dict.to_list(minted_tokens) == [ - ( - pool_lp_name(datum.identifier), - quantity_lp - datum.circulating_lp, - ), + (pool_lp_name(datum.identifier), quantity_lp - datum.circulating_lp), ] } } @@ -525,16 +618,18 @@ pub fn has_expected_pool_value( pool_policy_b: PolicyId, pool_asset_name_b: AssetName, pool_quantity_b: Int, + final_lp: Int, final_protocol_fees: Int, ) -> Bool { // Asset A *could* be ADA; in which case there should be 3 tokens on the output // (ADA, Asset B, and the NFT) if pool_policy_a == ada_policy_id { - let actual = list.foldl( + let actual = + list.foldl( value.flatten(output_value), // (token count, lovelace amount, token b amount, pool nft amount) (0, 0, 0, 0), - fn (asset, acc) { + fn(asset, acc) { let token_count = acc.1st + 1 if asset.1st == pool_policy_a { (token_count, acc.2nd + asset.3rd, acc.3rd, acc.4th) @@ -544,34 +639,49 @@ pub fn has_expected_pool_value( expect asset == (pool_script_hash, pool_nft_name(identifier), 1) (token_count, acc.2nd, acc.3rd, acc.4th + 1) } - } + }, ) - let expected = (3, final_protocol_fees + pool_quantity_a, pool_quantity_b, 1) + // If we're withdrawing the last bit of liquidity, we just have ADA and the pool token + let expected = if final_lp == 0 { + expect pool_quantity_a == 0 + expect pool_quantity_b == 0 + (2, final_protocol_fees, 0, 1) + } else { + (3, final_protocol_fees + pool_quantity_a, pool_quantity_b, 1) + } // Rather than constructing a value directly (which can be expensive) // we can just compare the expected token count and amounts with a single pass over the value expected == actual } else { // Asset A isn't ADA, Asset B will *never* be ADA; in this case, there should be 4 tokens on the output: // ADA, the Pool NFT, Asset A, and Asset B - (4, final_protocol_fees, pool_quantity_a, pool_quantity_b, 1) == - list.foldl( - value.flatten(output_value), - // (token count, lovelace amount, token a amount, token b amount, pool nft amount) - (0, 0, 0, 0, 0), - fn (asset, acc) { - let token_count = acc.1st + 1 - if asset.1st == ada_policy_id { - (token_count, acc.2nd + asset.3rd, acc.3rd, acc.4th, acc.5th) - } else if asset.1st == pool_policy_a && asset.2nd == pool_asset_name_a { - (token_count, acc.2nd, acc.3rd + asset.3rd, acc.4th, acc.5th) - } else if asset.1st == pool_policy_b && asset.2nd == pool_asset_name_b { - (token_count, acc.2nd, acc.3rd, acc.4th + asset.3rd, acc.5th) - } else { - expect asset == (pool_script_hash, pool_nft_name(identifier), 1) - (token_count, acc.2nd, acc.3rd, acc.4th, acc.5th + 1) - } + let actual = list.foldl( + value.flatten(output_value), + // (token count, lovelace amount, token a amount, token b amount, pool nft amount) + (0, 0, 0, 0, 0), + fn(asset, acc) { + let token_count = acc.1st + 1 + if asset.1st == ada_policy_id { + (token_count, acc.2nd + asset.3rd, acc.3rd, acc.4th, acc.5th) + } else if asset.1st == pool_policy_a && asset.2nd == pool_asset_name_a { + (token_count, acc.2nd, acc.3rd + asset.3rd, acc.4th, acc.5th) + } else if asset.1st == pool_policy_b && asset.2nd == pool_asset_name_b { + (token_count, acc.2nd, acc.3rd, acc.4th + asset.3rd, acc.5th) + } else { + expect asset == (pool_script_hash, pool_nft_name(identifier), 1) + (token_count, acc.2nd, acc.3rd, acc.4th, acc.5th + 1) } - ) + }, + ) + // If we're withdrawing the last bit of liquidity, we just have ADA and the pool token + let expected = if final_lp == 0 { + expect pool_quantity_a == 0 + expect pool_quantity_b == 0 + (2, final_protocol_fees, 0, 0, 1) + } else { + (4, final_protocol_fees, pool_quantity_a, pool_quantity_b, 1) + } + expected == actual } } @@ -592,6 +702,9 @@ pub fn int_to_ident(n: Int) -> Ident { bytearray.push(#"", n) } +// In order to keep the script size small for the pool script, we defer some functions to a separate stake script; +// when the treasury administrator attempts to withdraw fees, or the fee manager attempts to update the pool fee, +// it only checks for this particular script hash. This script, using the withdraw 0 trick, then checks the correct invariants validator(settings_policy_id: PolicyId) { pub fn manage(redeemer: ManageRedeemer, ctx: ScriptContext) { let transaction = ctx.transaction @@ -605,26 +718,41 @@ validator(settings_policy_id: PolicyId) { withdrawals, .. } = transaction - let settings_datum = find_settings_datum(reference_inputs, settings_policy_id) + + let settings_datum = + find_settings_datum(reference_inputs, settings_policy_id) + when redeemer is { + // In order to withdraw `amount` fees into `treasury_output` utxo, looking at `pool_input` WithdrawFees { amount, treasury_output, pool_input } -> { + // Find the pool input; note that we don't look for the pool NFT here, because if someone + // spends with an unauthenticated UTXO, it will fail the spend script; and if someone + // spends with a different script address, this script can't do anything fishy, + // just enforces some things about the outputs + // We also can't pull this out of the when, because we don't have the pool_input index yet expect Some(pool_input) = list.at(inputs, pool_input) let pool_input = pool_input.output expect InlineDatum(datum) = pool_input.datum expect datum: PoolDatum = datum - expect ScriptCredential(pool_script_hash) = pool_input.address.payment_credential - let PoolDatum { circulating_lp: initial_circulating_lp, protocol_fees: initial_protocol_fees, .. } = datum + expect ScriptCredential(pool_script_hash) = + pool_input.address.payment_credential + let PoolDatum { + circulating_lp: initial_circulating_lp, + protocol_fees: initial_protocol_fees, + .. + } = datum // Make sure we withdraw *only* up to what we've earned // We allow less than, so that you can leave some behind for the minUTXO cost, or continuing to earn staking rewards, etc. expect amount <= initial_protocol_fees // Only the treasury administrator is allowed to withdraw the fees, to prevent DDOS, and because of the allowance below - expect multisig.satisfied( - settings_datum.treasury_admin, - extra_signatories, - validity_range, - withdrawals, - ) + expect + multisig.satisfied( + settings_datum.treasury_admin, + extra_signatories, + validity_range, + withdrawals, + ) // Asking the DAO to approve every single cost individually would be a small cognitive DDOS on the community // Instead, the DAO can set an "allowance", which is a percentage of each withdrawal that is entrusted to the @@ -632,7 +760,8 @@ validator(settings_policy_id: PolicyId) { // // In particular, it's a percentage, to ensure that splitting up the withdrawals into multiple transactions doesn't // allow them to game that withdrawal. - let allowance = amount * settings_datum.treasury_allowance.1st / settings_datum.treasury_allowance.2nd + let allowance = + amount * settings_datum.treasury_allowance.1st / settings_datum.treasury_allowance.2nd let to_treasury = amount - allowance // And, we must pay everything except the allowance amount to the treasury address @@ -656,50 +785,60 @@ validator(settings_policy_id: PolicyId) { // If circulating_lp is 0, all of the assets have been withdrawn, and so the UTXO will be // ADA (for the treasury fees) and the pool NFT; so we can very cleverly check that the pool // NFT is burned by negating the input, and stripping off the lovelace - expect value.from_minted_value(mint) == value.negate(value.without_lovelace(pool_input.value)) + expect + value.from_minted_value(mint) == value.negate( + value.without_lovelace(pool_input.value), + ) True } else { let ( - Output { - address: pool_output_address, - value: pool_output_value, - .. - }, - output_datum - ) = find_pool_output(outputs) - expect pool_output_address.payment_credential == ScriptCredential(pool_script_hash) + Output { + address: pool_output_address, + value: pool_output_value, + .. + }, + output_datum, + ) = find_pool_output(outputs) + expect + pool_output_address.payment_credential == ScriptCredential( + pool_script_hash, + ) // As part of withdrawing, we should decrease the protocol fees by the amount we're withdrawing // but, importantly, *nothing else*; so we construct a datum with everything from the initial datum, plus the protofol fees updated - let expected_datum = PoolDatum { - ..datum, - protocol_fees: initial_protocol_fees - amount, - } + let expected_datum = + PoolDatum { ..datum, protocol_fees: initial_protocol_fees - amount } expect output_datum == expected_datum // Now, check that the pool output decreases *only* by the amount we're withdrawing, and not by fewer or greater ADA - let expected_output_value = value.merge(pool_input.value, value.from_lovelace(-amount)) + let expected_output_value = + value.merge(pool_input.value, value.from_lovelace(-amount)) expect pool_output_value == expected_output_value - expect list.any(settings_datum.authorized_staking_keys, fn(a) { - pool_output_address.stake_credential == Some(Inline(a)) - }) + expect + list.any( + settings_datum.authorized_staking_keys, + fn(a) { pool_output_address.stake_credential == Some(Inline(a)) }, + ) True } } + // To update the pool fees for the pool at `pool_input`... UpdatePoolFees { pool_input } -> { + // Find the pool input; note that we don't look for the pool NFT here, because if someone + // spends with an unauthenticated UTXO, it will fail the spend script; and if someone + // spends with a different script address, this script can't do anything fishy, + // just enforces some things about the outputs + // This is duplicated code with the other branch, but only because we don't have pool_input yet expect Some(pool_input) = list.at(inputs, pool_input) let pool_input = pool_input.output expect InlineDatum(datum) = pool_input.datum expect datum: PoolDatum = datum - + // We need the pool output to check that only the fees or fee manager are updated let ( - Output { - address: pool_output_address, - value: pool_output_value, - .. - }, + Output { address: pool_output_address, value: pool_output_value, .. }, pool_output_datum, ) = find_pool_output(outputs) + let PoolDatum { bid_fees_per_10_thousand, ask_fees_per_10_thousand, @@ -707,28 +846,34 @@ validator(settings_policy_id: PolicyId) { .. } = pool_output_datum + // Make sure we don't update the fees to negative or above 100% expect shared.fees_in_legal_range(bid_fees_per_10_thousand) expect shared.fees_in_legal_range(ask_fees_per_10_thousand) - let expected_datum = PoolDatum { - ..datum, - bid_fees_per_10_thousand, - ask_fees_per_10_thousand, - fee_manager: output_fee_manager, - } + let expected_datum = + PoolDatum { + ..datum, + bid_fees_per_10_thousand: bid_fees_per_10_thousand, + ask_fees_per_10_thousand: ask_fees_per_10_thousand, + fee_manager: output_fee_manager, + } expect pool_output_datum == expected_datum + // Check that the *current* fee manager approves the update expect Some(fee_manager) = datum.fee_manager - expect multisig.satisfied( - fee_manager, - extra_signatories, - validity_range, - withdrawals, - ) + expect + multisig.satisfied( + fee_manager, + extra_signatories, + validity_range, + withdrawals, + ) - expect pool_output_address == pool_input.address - expect pool_output_value == pool_input.value - True + // And make sure we don't touch the assets on the pool input; they must be spent back into the same script + and { + pool_output_address == pool_input.address, + pool_output_value == pool_input.value, + } } } } diff --git a/validators/pool_stake.ak b/validators/pool_stake.ak index 9228908..31c25ca 100644 --- a/validators/pool_stake.ak +++ b/validators/pool_stake.ak @@ -1,9 +1,11 @@ use aiken/dict use aiken/list -use aiken/transaction.{Transaction, ScriptContext, WithdrawFrom, Publish, InlineDatum} +use aiken/transaction.{ + InlineDatum, Publish, ScriptContext, Transaction, WithdrawFrom, +} use aiken/transaction/value.{PolicyId} -use types/settings.{find_settings_datum} use sundae/multisig +use types/settings.{find_settings_datum} /// The pool stake validator is one example script staking validator that could be attached to each pool, to delegate to a stake pool operator /// @@ -32,34 +34,40 @@ validator(settings_policy_id: PolicyId, _instance: Int) { } = transaction // And find the settings datum; this ensures it exists, and lets us look at the settings datum - let settings_datum = find_settings_datum(reference_inputs, settings_policy_id) - + let settings_datum = + find_settings_datum(reference_inputs, settings_policy_id) // Regardless of what we're doing, the treasury administrator conditions must be satisfied (ex: multisig, DAO script, etc) - expect multisig.satisfied( - settings_datum.treasury_admin, - extra_signatories, - validity_range, - withdrawals, - ) + expect + multisig.satisfied( + settings_datum.treasury_admin, + extra_signatories, + validity_range, + withdrawals, + ) when purpose is { // To withdraw any amount of earned staking rewards, WithdrawFrom(_) -> { - // We calculate the amount withdrawn by summing up *all* withdrawals // This is to avoid a double satisfaction problem, where withdrawing 100 ADA of rewards from // two different scripts each believe that 100 ADA has been paid to the treasury - let amount_withdrawn = dict.foldl(withdrawals, 0, fn(_k, v, s) { v + s }) + let amount_withdrawn = + dict.foldl(withdrawals, 0, fn(_k, v, s) { v + s }) // Allow the treasury administrator to keep some portion of the withdrawn rewards, for administrative costs like paying the scoopers // We multiply first, then divide, for maximal precision - let allowance = amount_withdrawn * settings_datum.treasury_allowance.1st / settings_datum.treasury_allowance.2nd + let allowance = + amount_withdrawn * settings_datum.treasury_allowance.1st / settings_datum.treasury_allowance.2nd // The amount that must be sent to the treasury is the total amount withdrawn, minus the allowance that the adminsitrator can keep let to_treasury = amount_withdrawn - allowance // Find the first output to the treasury address; We assume there's only one output that receives the whole amount, // as there's not much benefit to splitting it up. TODO: is this true? could the treasury administrator want to earmark them separately or something? // If we find no treasury output, the transaction fails here. // We compare the *whole* address here, instead of the payment credential, because the treasury should also be earning staking rewards! - expect Some(treasury_output) = list.find(outputs, fn(o) { o.address == settings_datum.treasury_address }) + expect Some(treasury_output) = + list.find( + outputs, + fn(o) { o.address == settings_datum.treasury_address }, + ) // Make sure *at least* the amount we calculated is sent to the treasury; it can be larger, // if someone is feeling generous, or to deal with rounding for example, but it cannot be less expect value.lovelace_of(treasury_output.value) >= to_treasury @@ -76,4 +84,4 @@ validator(settings_policy_id: PolicyId, _instance: Int) { _ -> False } } -} \ No newline at end of file +} diff --git a/validators/settings.ak b/validators/settings.ak index eb73e36..2788df0 100644 --- a/validators/settings.ak +++ b/validators/settings.ak @@ -1,16 +1,23 @@ use aiken/list -use aiken/transaction.{InlineDatum, Mint, ScriptContext, OutputReference} +use aiken/transaction.{InlineDatum, Mint, OutputReference, ScriptContext} use aiken/transaction/credential.{ScriptCredential} use aiken/transaction/value -use sundae/multisig -use types/settings.{SettingsDatum, SettingsRedeemer, SettingsAdminUpdate, TreasuryAdminUpdate, settings_nft_name} use shared.{spent_output} +use sundae/multisig +use types/settings.{ + SettingsAdminUpdate, SettingsDatum, SettingsRedeemer, TreasuryAdminUpdate, + settings_nft_name, +} /// The settings validator lets the settings and treasury admins update global settings for the protocol /// /// It is parameterized by the protocol_boot_utxo, a constant to make it an NFT by the usual trick. validator(protocol_boot_utxo: OutputReference) { - pub fn spend(input_datum: SettingsDatum, redeemer: SettingsRedeemer, ctx: ScriptContext) { + pub fn spend( + input_datum: SettingsDatum, + redeemer: SettingsRedeemer, + ctx: ScriptContext, + ) { // Find our own input so we know the datum / our own address let own_input = spent_output(ctx) let own_address = own_input.address @@ -32,11 +39,12 @@ validator(protocol_boot_utxo: OutputReference) { // Note that this can only be spent by the SettingsAdmin or TreasuryAdmin, so we won't leak a small amount of ADA to arbitrary users // Also, it is not expected that the ADA ever be more than the minUTXO cost, so this doesn't expose hundreds of ADA (for example) to the treasury admin let value_not_changed = - value.without_lovelace(own_output.value) == value.without_lovelace(own_input.value) + value.without_lovelace(own_output.value) == value.without_lovelace( + own_input.value, + ) // Make sure we don't mint anything, otherwise someone might mint another settings token - let no_mint = - value.from_minted_value(ctx.transaction.mint) == value.zero() + let no_mint = value.from_minted_value(ctx.transaction.mint) == value.zero() // Then, depending on which admin is doing the updating, different settings are updatable when redeemer is { @@ -56,17 +64,18 @@ validator(protocol_boot_utxo: OutputReference) { ) // Settings admin can change any datum fields except for these - let allowed_datum = SettingsDatum { - // Most fields *can* be updated by the admin, so we start from the output datum - ..output_datum, - // But ensure that these fields haven't been changed - authorized_staking_keys: input_datum.authorized_staking_keys, - treasury_address: input_datum.treasury_address, - treasury_allowance: input_datum.treasury_allowance, - } + let allowed_datum = + SettingsDatum { + ..// Most fields *can* be updated by the admin, so we start from the output datum + output_datum, + authorized_staking_keys: // But ensure that these fields haven't been changed + input_datum.authorized_staking_keys, + treasury_address: input_datum.treasury_address, + treasury_allowance: input_datum.treasury_allowance, + } + // TODO: move base_fee, simple_fee, and strategy_fee to the treasury admin instead, maybe? // TODO: enforce maximum scooper keys to some large N, to prevent locking the datum? - and { signed_by_admin, output_datum == allowed_datum, @@ -85,16 +94,17 @@ validator(protocol_boot_utxo: OutputReference) { // Treasury admin can change any datum fields except for these // i.e. can change the treasury address, treasury allowance, and the authorized staking keys - let allowed_datum = SettingsDatum { - // Most of the fields can't change, so we start from the input datum - ..input_datum, - // These three can be updated, so we pull whatever is in the output datum - authorized_staking_keys: output_datum.authorized_staking_keys, - treasury_address: output_datum.treasury_address, - treasury_allowance: output_datum.treasury_allowance, - } - // TODO: enforce maximum staking keys to some large N, to prevent locking the Datum + let allowed_datum = + SettingsDatum { + ..// Most of the fields can't change, so we start from the input datum + input_datum, + authorized_staking_keys: // These three can be updated, so we pull whatever is in the output datum + output_datum.authorized_staking_keys, + treasury_address: output_datum.treasury_address, + treasury_allowance: output_datum.treasury_allowance, + } + // TODO: enforce maximum staking keys to some large N, to prevent locking the Datum and { signed_by_admin, output_datum == allowed_datum, @@ -117,25 +127,30 @@ validator(protocol_boot_utxo: OutputReference) { // And, like mentioned above, ensure that this is a true NFT let spends_protocol_boot_utxo = - list.any(ctx.transaction.inputs, fn(input) { - input.output_reference == protocol_boot_utxo - }) + list.any( + ctx.transaction.inputs, + fn(input) { input.output_reference == protocol_boot_utxo }, + ) // Make sure the output value contains no extra tokens, and is paid to the settings script itself - expect [settings_output] = list.filter(ctx.transaction.outputs, fn(output) { - value.without_lovelace(output.value) == expected_mint - }) - let pays_to_settings_script = settings_output.address.payment_credential == ScriptCredential(own_policy_id) + expect [settings_output] = + list.filter( + ctx.transaction.outputs, + fn(output) { value.without_lovelace(output.value) == expected_mint }, + ) + let pays_to_settings_script = + settings_output.address.payment_credential == ScriptCredential( + own_policy_id, + ) // Make sure the datum is an inline datum, and has a well-formed datum expect InlineDatum(settings_datum) = settings_output.datum expect _: SettingsDatum = settings_datum // TODO: require a signature from the 3 initial admins (or at least the settings admin) to prevent bricking? - and { mints_exactly_one_settings_nft, spends_protocol_boot_utxo, pays_to_settings_script, } } -} \ No newline at end of file +} diff --git a/validators/stake.ak b/validators/stake.ak index 6f07a82..a4928e6 100644 --- a/validators/stake.ak +++ b/validators/stake.ak @@ -13,10 +13,6 @@ use aiken/transaction/value /// It's parameterized by the pool_script_hash, so it knows what pool token to look for. validator(pool_script_hash: Hash) { fn stake(_r: Data, ctx: ScriptContext) -> Bool { - /// Note: we don't allow this address to be delegated to a pool, only withdrawals (which will always be zero) - /// because a very subtle attack vector would be to register the address, delegate to a pool, - /// and break any offchain code that was assuming the withdraw would be zero - /// because most off-chain code won't have access to the rewards calculation! when ctx.purpose is { WithdrawFrom(_) -> { // We can assume that the pool output is the first output, because outputs aren't reordered by the ledger, @@ -32,7 +28,13 @@ validator(pool_script_hash: Hash) { let pool_tokens_list = dict.to_list(pool_tokens) // And then check that it's specifically the pool NFT by taking advantage of the CIP-68 label let is_pool_nft = - fn(kvp: (ByteArray, Int)) { + fn( + /// Note: we don't allow this address to be delegated to a pool, only withdrawals (which will always be zero) + /// because a very subtle attack vector would be to register the address, delegate to a pool, + /// and break any offchain code that was assuming the withdraw would be zero + /// because most off-chain code won't have access to the rewards calculation! + kvp: (ByteArray, Int), + ) { // we use the 2nd byte here, because the first byte is zero as a "parenthesis" builtin.index_bytearray(kvp.1st, 1) == 0x0d } diff --git a/validators/tests/constants.ak b/validators/tests/constants.ak index 8efd1b8..c172a6d 100644 --- a/validators/tests/constants.ak +++ b/validators/tests/constants.ak @@ -1,26 +1,50 @@ // Script hashes -pub const settings_policy_id = #"00000000000000000000000000000000000000000000000000000000" -pub const pool_script_hash = #"00000000000000000000000000000000000000000000000000000001" -pub const order_script_hash = #"00000000000000000000000000000000000000000000000000000002" -pub const stake_script_hash = #"00000000000000000000000000000000000000000000000000000003" +pub const settings_policy_id = + #"00000000000000000000000000000000000000000000000000000000" -pub const manage_stake_script_hash = #"00000000000000000000000000000000000000000000000000000003" +pub const pool_script_hash = + #"00000000000000000000000000000000000000000000000000000001" -pub const random_hash = #"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513" -pub const other_hash = #"01010101010101010101010101010101010101010101010101010101" +pub const order_script_hash = + #"00000000000000000000000000000000000000000000000000000002" + +pub const stake_script_hash = + #"00000000000000000000000000000000000000000000000000000003" + +pub const manage_stake_script_hash = + #"00000000000000000000000000000000000000000000000000000003" + +pub const random_hash = + #"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513" + +pub const other_hash = + #"01010101010101010101010101010101010101010101010101010101" // Tokens -pub const rberry_policy = #"9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77" -pub const rberry_asset_name = #"524245525259" -pub const other_policy = #"fafafafafafafafafafafafafafafafafafafafafafafafafafafafa" -pub const other_asset_name = #"fafafafa" -pub const empty_asset_name = #"" +pub const rberry_policy = + #"9a9693a9a37912a5097918f97918d15240c92ab729a0b7c4aa144d77" + +pub const rberry_asset_name = #"524245525259" + +pub const other_policy = + #"fafafafafafafafafafafafafafafafafafafafafafafafafafafafa" + +pub const other_asset_name = #"fafafafa" + +pub const empty_asset_name = #"" // Identifiers -pub const pool_ident = #"00000000000000000000000000000000000000000000000000000003" +pub const pool_ident = + #"00000000000000000000000000000000000000000000000000000003" // Public keys -pub const payment_key = #"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513" -pub const stake_key = #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa024ad" -pub const scooper = #"00000000000000000000000000000000000000000000000000000004" -pub const not_a_scooper = #"11111111111111111111111111111111111111111111111111111114" +pub const payment_key = + #"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513" + +pub const stake_key = + #"725011d2c296eb3341e159b6c5c6991de11e81062b95108c9aa024ad" + +pub const scooper = #"00000000000000000000000000000000000000000000000000000004" + +pub const not_a_scooper = + #"11111111111111111111111111111111111111111111111111111114" diff --git a/validators/tests/order.ak b/validators/tests/order.ak index c7ae9ce..890d909 100644 --- a/validators/tests/order.ak +++ b/validators/tests/order.ak @@ -1,18 +1,15 @@ use aiken/dict.{Dict} use aiken/interval use aiken/transaction.{ - InlineDatum, Input, Output, - ScriptContext, Spend, Transaction, -} -use aiken/transaction/credential.{ - Inline, StakeCredential, ScriptCredential, + InlineDatum, Input, Output, ScriptContext, Spend, Transaction, } +use aiken/transaction/credential.{Inline, ScriptCredential, StakeCredential} use aiken/transaction/value -use tests/examples/ex_shared.{ - mk_output_reference, mk_tx_hash, script_address, compare_stake, -} use order as order_validator use tests/constants +use tests/examples/ex_shared.{ + compare_stake, mk_output_reference, mk_tx_hash, script_address, +} use types/order.{Scoop} test scoop_order_test() { @@ -51,7 +48,8 @@ test scoop_order_missing_stake_script_withdrawal() fail { fn scoop_order(withdrawals: Dict) { let order_address = script_address(constants.order_script_hash) - let order_datum = Void // Not needed by scoop + let order_datum = Void + // Not needed by scoop let order_redeemer = Scoop let order_input = Input { @@ -72,7 +70,7 @@ fn scoop_order(withdrawals: Dict) { fee: value.from_lovelace(1_000_000), mint: value.to_minted_value(value.from_lovelace(0)), certificates: [], - withdrawals: withdrawals, + withdrawals, validity_range: interval.between(1, 2), extra_signatories: [], redeemers: dict.new(), @@ -81,6 +79,12 @@ fn scoop_order(withdrawals: Dict) { }, purpose: Spend(order_input.output_reference), } - let result = order_validator.spend(constants.stake_script_hash, order_datum, order_redeemer, ctx) + let result = + order_validator.spend( + constants.stake_script_hash, + order_datum, + order_redeemer, + ctx, + ) result } diff --git a/validators/tests/pool.ak b/validators/tests/pool.ak index 20351ea..537decc 100644 --- a/validators/tests/pool.ak +++ b/validators/tests/pool.ak @@ -5,32 +5,38 @@ use aiken/hash use aiken/interval use aiken/option use aiken/transaction.{ - Datum, InlineDatum, Input, NoDatum, Output, OutputReference, - ScriptContext, Spend, Transaction, TransactionId, + Datum, InlineDatum, Input, NoDatum, Output, OutputReference, ScriptContext, + Spend, Transaction, TransactionId, WithdrawFrom, } use aiken/transaction/credential.{ - Inline, Address, StakeCredential, ScriptCredential, VerificationKeyCredential, from_verification_key, from_script, with_delegation_key -} -use aiken/transaction/value.{Value, ada_policy_id, ada_asset_name} -use shared.{ - pool_lp_name, + Address, Inline, ScriptCredential, StakeCredential, VerificationKeyCredential, + from_script, from_verification_key, with_delegation_key, } +use aiken/transaction/value.{Value, ada_asset_name, ada_policy_id} +use calculation/shared.{PoolState} as calc_shared +use pool as pool_validator +use shared.{pool_lp_name} use sundae/multisig -use tests/examples/ex_settings.{mk_valid_settings_input, mk_valid_settings_datum, example_treasury_admin, example_metadata_admin, example_treasury_address, example_settings_admin} +use tests/constants +use tests/examples/ex_settings.{ + example_metadata_admin, example_settings_admin, example_treasury_address, + example_treasury_admin, mk_valid_settings_datum, mk_valid_settings_input, +} use tests/examples/ex_shared.{ - mk_output_reference, mk_tx_hash, script_address, wallet_address, compare_stake, + compare_redeemer, compare_stake, mk_output_reference, mk_tx_hash, + script_address, wallet_address, +} +use tx_util/builder.{ + add_asset_to_tx_output, add_tx_input, add_tx_output, add_tx_ref_input, + build_txn_context, insert_redeemer, insert_withdrawal, mint_assets, + new_tx_input, new_tx_output, with_asset_of_tx_input, } -use types/order.{Deposit, Destination, Fixed, Self, OrderDatum, Order, Swap} +use types/order.{Deposit, Destination, Fixed, Order, OrderDatum, Self, Swap} use types/pool.{ - PoolMintRedeemer, CreatePool, PoolDatum, PoolScoop, - BurnPool, WithdrawFees, UpdatePoolFees, + BurnPool, CreatePool, Manage, PoolDatum, PoolMintRedeemer, PoolScoop, + UpdatePoolFees, WithdrawFees, } -use calculation/shared.{PoolState} as calc_shared use types/settings.{SettingsDatum, settings_nft_name} -use tx_util/builder.{add_asset_to_tx_output, add_tx_input, add_tx_output, add_tx_ref_input, build_txn_context, mint_assets, new_tx_input, new_tx_output, with_asset_of_tx_input} -use pool as pool_validator -use tests/constants - type ScoopTestOptions { edit_order_1_in_value: Option, @@ -42,8 +48,8 @@ type ScoopTestOptions { edit_order_intended_destination: Option, edit_order_actual_destination: Option, edit_fee: Option, - edit_swap_fees: Option<((Int,Int), (Int, Int))>, - edit_new_swap_fees: Option<((Int,Int), (Int, Int))>, + edit_swap_fees: Option<(Int, Int)>, + edit_new_swap_fees: Option<(Int, Int)>, edit_fee_admin: Option>, edit_withdrawals: Option>, edit_pool_input_address: Option
, @@ -89,55 +95,64 @@ test ok_scoop_swap_deposit() { } test ok_scoop_swap_with_surplus() { - let options = ScoopTestOptions { - ..default_scoop_test_options(), - edit_order_1_in_value: Some( - value.from_lovelace(4_500_000 + 20_000_000) - ), - edit_order_1_out_value: Some( - value.from_lovelace(2_000_000 + 10_000_000) - |> value.add(constants.rberry_policy, constants.rberry_asset_name, 9_896_088), - ) - } + let options = + ScoopTestOptions { + ..default_scoop_test_options(), + edit_order_1_in_value: Some(value.from_lovelace(4_500_000 + 20_000_000)), + edit_order_1_out_value: Some( + value.from_lovelace(2_000_000 + 10_000_000) + |> value.add( + constants.rberry_policy, + constants.rberry_asset_name, + 9_896_088, + ), + ), + } scoop(options) } + test ok_scoop_swap_with_over_rounding() { let pool_nft_name = shared.pool_nft_name(constants.pool_ident) let amt_1 = 408_367_450 let amt_2 = 425_387_016 - let options = ScoopTestOptions { - ..default_scoop_test_options(), - edit_pool_input_value: Some( - value.from_lovelace(20_000_000_000 + 2_000_000) - |> value.add(constants.rberry_policy, constants.rberry_asset_name, 50) - |> value.add(constants.pool_script_hash, pool_nft_name, 1) - ), - edit_pool_output_value: Some( - value.from_lovelace(amt_1 + amt_2 + 20_000_000_000 + 2_000_000 + 2_500_000 + 2_500_000) - |> value.add(constants.rberry_policy, constants.rberry_asset_name, 48) - |> value.add(constants.pool_script_hash, pool_nft_name, 1) - ), - edit_order_1_details: Some( - Swap((ada_policy_id, ada_asset_name, 799_000_000), (constants.rberry_policy, constants.rberry_asset_name, 0)), - ), - edit_order_1_in_value: Some( - value.from_lovelace(4_500_000 + 799_000_000) - ), - edit_order_1_out_value: Some( - value.from_lovelace(2_000_000 + 799_000_000 - amt_1) - |> value.add(constants.rberry_policy, constants.rberry_asset_name, 1), - ), - edit_order_2_details: Some( - Swap((ada_policy_id, ada_asset_name, 799_000_000), (constants.rberry_policy, constants.rberry_asset_name, 0)), - ), - edit_order_2_in_value: Some( - value.from_lovelace(4_500_000 + 799_000_000) - ), - edit_order_2_out_value: Some( - value.from_lovelace(2_000_000 + 799_000_000 - amt_2) - |> value.add(constants.rberry_policy, constants.rberry_asset_name, 1), - ), - } + let options = + ScoopTestOptions { + ..default_scoop_test_options(), + edit_pool_input_value: Some( + value.from_lovelace(20_000_000_000 + 2_000_000) + |> value.add(constants.rberry_policy, constants.rberry_asset_name, 50) + |> value.add(constants.pool_script_hash, pool_nft_name, 1), + ), + edit_pool_output_value: Some( + value.from_lovelace( + amt_1 + amt_2 + 20_000_000_000 + 2_000_000 + 2_500_000 + 2_500_000, + ) + |> value.add(constants.rberry_policy, constants.rberry_asset_name, 48) + |> value.add(constants.pool_script_hash, pool_nft_name, 1), + ), + edit_order_1_details: Some( + Swap( + (ada_policy_id, ada_asset_name, 799_000_000), + (constants.rberry_policy, constants.rberry_asset_name, 0), + ), + ), + edit_order_1_in_value: Some(value.from_lovelace(4_500_000 + 799_000_000)), + edit_order_1_out_value: Some( + value.from_lovelace(2_000_000 + 799_000_000 - amt_1) + |> value.add(constants.rberry_policy, constants.rberry_asset_name, 1), + ), + edit_order_2_details: Some( + Swap( + (ada_policy_id, ada_asset_name, 799_000_000), + (constants.rberry_policy, constants.rberry_asset_name, 0), + ), + ), + edit_order_2_in_value: Some(value.from_lovelace(4_500_000 + 799_000_000)), + edit_order_2_out_value: Some( + value.from_lovelace(2_000_000 + 799_000_000 - amt_2) + |> value.add(constants.rberry_policy, constants.rberry_asset_name, 1), + ), + } scoop(options) } @@ -158,11 +173,19 @@ test scoop_payouts_swapped() fail { ..default_scoop_test_options(), edit_order_1_out_value: Some( value.from_lovelace(2_000_000) - |> value.add(constants.rberry_policy, constants.rberry_asset_name, 9_702_095), + |> value.add( + constants.rberry_policy, + constants.rberry_asset_name, + 9_702_095, + ), ), edit_order_2_out_value: Some( value.from_lovelace(2_000_000) - |> value.add(constants.rberry_policy, constants.rberry_asset_name, 9_896_088), + |> value.add( + constants.rberry_policy, + constants.rberry_asset_name, + 9_896_088, + ), ), } scoop(options) @@ -183,22 +206,30 @@ test scoop_high_swap_fees() { let options = ScoopTestOptions { ..default_scoop_test_options(), - edit_swap_fees: Some(((swap_fee, swap_fee), (swap_fee, swap_fee))), + edit_swap_fees: Some((swap_fee, swap_fee)), edit_order_1_out_value: Some( value.from_lovelace(2_000_000) - |> value.add(constants.rberry_policy, constants.rberry_asset_name, 9_802_950), + |> value.add( + constants.rberry_policy, + constants.rberry_asset_name, + 9_802_950, + ), ), edit_order_2_out_value: Some( value.from_lovelace(2_000_000) - |> value.add(constants.rberry_policy, constants.rberry_asset_name, 9_611_678), + |> value.add( + constants.rberry_policy, + constants.rberry_asset_name, + 9_611_678, + ), ), edit_pool_output_value: Some( value.from_lovelace(1_000_000_000 + 20_000_000 + 5_000_000 + 2_000_000) |> value.add( - constants.rberry_policy, - constants.rberry_asset_name, - 1_000_000_000 - ( 9_802_950 + 9_611_678 ), - ) + constants.rberry_policy, + constants.rberry_asset_name, + 1_000_000_000 - ( 9_802_950 + 9_611_678 ), + ) |> value.add(constants.pool_script_hash, pool_nft_name, 1), ), } @@ -212,10 +243,10 @@ test output_missing_nft() fail { edit_pool_output_value: Some( value.from_lovelace(1_000_000_000 + 20_000_000 + 5_000_000 + 2_000_000) |> value.add( - constants.rberry_policy, - constants.rberry_asset_name, - 1_000_000_000 - ( 9_896_088 + 9_702_095 ), - ), + constants.rberry_policy, + constants.rberry_asset_name, + 1_000_000_000 - ( 9_896_088 + 9_702_095 ), + ), ), } scoop(options) @@ -225,10 +256,13 @@ test scoop_pool_output_wallet_address() fail { let options = ScoopTestOptions { ..default_scoop_test_options(), - edit_pool_output_address: Some(from_verification_key(constants.random_hash)), + edit_pool_output_address: Some( + from_verification_key(constants.random_hash), + ), } scoop(options) } + test scoop_pool_output_wrong_script() fail { let options = ScoopTestOptions { @@ -237,12 +271,19 @@ test scoop_pool_output_wrong_script() fail { } scoop(options) } + test scoop_pool_output_change_staking_credential() fail { let options = ScoopTestOptions { ..default_scoop_test_options(), - edit_pool_input_address: Some(from_script(constants.pool_script_hash) |> with_delegation_key(constants.random_hash)), - edit_pool_output_address: Some(from_script(constants.pool_script_hash) |> with_delegation_key(constants.other_hash)), + edit_pool_input_address: Some( + from_script(constants.pool_script_hash) + |> with_delegation_key(constants.random_hash), + ), + edit_pool_output_address: Some( + from_script(constants.pool_script_hash) + |> with_delegation_key(constants.other_hash), + ), } scoop(options) } @@ -287,29 +328,33 @@ test scooper_not_in_settings() fail { fn scoop(options: ScoopTestOptions) { let user_addr = wallet_address(constants.payment_key) let owner = multisig.Signature(constants.payment_key) - let fees = option.or_else(options.edit_swap_fees, ((5,5),(5,5))) + let fees = option.or_else(options.edit_swap_fees, (5, 5)) let pool_datum = PoolDatum { identifier: constants.pool_ident, - assets: ((ada_policy_id, ada_asset_name), (constants.rberry_policy, constants.rberry_asset_name)), + assets: ( + (ada_policy_id, ada_asset_name), + (constants.rberry_policy, constants.rberry_asset_name), + ), circulating_lp: 1_000_000_000, bid_fees_per_10_thousand: fees.1st, ask_fees_per_10_thousand: fees.2nd, fee_manager: None, market_open: 0, - fee_finalized: 100, protocol_fees: 2_000_000, } let pool_out_datum = PoolDatum { identifier: constants.pool_ident, - assets: ((ada_policy_id, ada_asset_name), (constants.rberry_policy, constants.rberry_asset_name)), + assets: ( + (ada_policy_id, ada_asset_name), + (constants.rberry_policy, constants.rberry_asset_name), + ), circulating_lp: 1_000_000_000, bid_fees_per_10_thousand: fees.1st, ask_fees_per_10_thousand: fees.2nd, fee_manager: None, market_open: 0, - fee_finalized: 0, protocol_fees: 7_000_000, } let pool_nft_name = shared.pool_nft_name(constants.pool_ident) @@ -320,20 +365,32 @@ fn scoop(options: ScoopTestOptions) { output: Output { address: option.or_else(options.edit_pool_input_address, pool_address), value: option.or_else( - options.edit_pool_input_value, - value.from_lovelace(1_000_000_000 + 2_000_000) - |> value.add(constants.rberry_policy, constants.rberry_asset_name, 1_000_000_000) + options.edit_pool_input_value, + value.from_lovelace(1_000_000_000 + 2_000_000) + |> value.add( + constants.rberry_policy, + constants.rberry_asset_name, + 1_000_000_000, + ) |> value.add(constants.pool_script_hash, pool_nft_name, 1), ), datum: InlineDatum(pool_datum), reference_script: None, }, } - let dest = option.or_else(options.edit_order_intended_destination, Fixed { address: user_addr, datum: NoDatum }) - let swap_1 = option.or_else( - options.edit_order_1_details, - Swap((ada_policy_id, ada_asset_name, 10_000_000), (constants.rberry_policy, constants.rberry_asset_name, 0)), - ) + let dest = + option.or_else( + options.edit_order_intended_destination, + Fixed { address: user_addr, datum: NoDatum }, + ) + let swap_1 = + option.or_else( + options.edit_order_1_details, + Swap( + (ada_policy_id, ada_asset_name, 10_000_000), + (constants.rberry_policy, constants.rberry_asset_name, 0), + ), + ) let order_1_datum = OrderDatum { pool_ident: None, @@ -351,16 +408,20 @@ fn scoop(options: ScoopTestOptions) { address: order_address, value: option.or_else( options.edit_order_1_in_value, - value.from_lovelace(4_500_000 + 10_000_000) + value.from_lovelace(4_500_000 + 10_000_000), ), datum: InlineDatum(order_1_datum), reference_script: None, }, } - let swap_2 = option.or_else( - options.edit_order_2_details, - Swap((ada_policy_id, ada_asset_name, 10_000_000), (constants.rberry_policy, constants.rberry_asset_name, 0)), - ) + let swap_2 = + option.or_else( + options.edit_order_2_details, + Swap( + (ada_policy_id, ada_asset_name, 10_000_000), + (constants.rberry_policy, constants.rberry_asset_name, 0), + ), + ) let order_2_datum = OrderDatum { pool_ident: None, @@ -377,7 +438,7 @@ fn scoop(options: ScoopTestOptions) { address: order_address, value: option.or_else( options.edit_order_2_in_value, - value.from_lovelace(4_500_000 + 10_000_000) + value.from_lovelace(4_500_000 + 10_000_000), ), datum: InlineDatum(order_2_datum), reference_script: None, @@ -393,35 +454,45 @@ fn scoop(options: ScoopTestOptions) { } Input { output_reference, output: updated_output } } - let (order1_out_addr, order1_out_datum) = when options.edit_order_actual_destination is { - Some(Fixed(dest, datum)) -> (dest, datum) - Some(Self) -> (order_address, InlineDatum(order_1_datum)) - None -> (user_addr, NoDatum) - } + let (order1_out_addr, order1_out_datum) = + when options.edit_order_actual_destination is { + Some(Fixed(dest, datum)) -> (dest, datum) + Some(Self) -> (order_address, InlineDatum(order_1_datum)) + None -> (user_addr, NoDatum) + } let order1_out = Output { address: order1_out_addr, value: option.or_else( options.edit_order_1_out_value, value.from_lovelace(2_000_000) - |> value.add(constants.rberry_policy, constants.rberry_asset_name, 9_896_088), + |> value.add( + constants.rberry_policy, + constants.rberry_asset_name, + 9_896_088, + ), ), datum: order1_out_datum, reference_script: None, } // TODO: manage separately? - let (order2_out_addr, order2_out_datum) = when options.edit_order_actual_destination is { - Some(Fixed(dest, datum)) -> (dest, datum) - Some(Self) -> (order_address, InlineDatum(order_2_datum)) - None -> (user_addr, NoDatum) - } + let (order2_out_addr, order2_out_datum) = + when options.edit_order_actual_destination is { + Some(Fixed(dest, datum)) -> (dest, datum) + Some(Self) -> (order_address, InlineDatum(order_2_datum)) + None -> (user_addr, NoDatum) + } let order2_out = Output { address: order2_out_addr, value: option.or_else( options.edit_order_2_out_value, value.from_lovelace(2_000_000) - |> value.add(constants.rberry_policy, constants.rberry_asset_name, 9_702_095), + |> value.add( + constants.rberry_policy, + constants.rberry_asset_name, + 9_702_095, + ), ), datum: order2_out_datum, reference_script: None, @@ -433,10 +504,10 @@ fn scoop(options: ScoopTestOptions) { options.edit_pool_output_value, value.from_lovelace(1_000_000_000 + 20_000_000 + 5_000_000 + 2_000_000) |> value.add( - constants.rberry_policy, - constants.rberry_asset_name, - 1_000_000_000 - ( 9_896_088 + 9_702_095 ), - ) + constants.rberry_policy, + constants.rberry_asset_name, + 1_000_000_000 - ( 9_896_088 + 9_702_095 ), + ) |> value.add(constants.pool_script_hash, pool_nft_name, 1), ), datum: InlineDatum(pool_out_datum), @@ -460,392 +531,590 @@ fn scoop(options: ScoopTestOptions) { }, purpose: Spend(pool_input.output_reference), } - let pool_redeemer = PoolScoop( - 0, - 0, - [ - (1, None, 0), - (2, None, 0), - ] - ) - let result = pool_validator.spend(constants.manage_stake_script_hash, constants.settings_policy_id, pool_datum, pool_redeemer, ctx) + let pool_redeemer = PoolScoop(0, 0, [(1, None, 0), (2, None, 0)]) + let result = + pool_validator.spend( + constants.manage_stake_script_hash, + constants.settings_policy_id, + pool_datum, + pool_redeemer, + ctx, + ) result } fn scoop_swap_deposit(options: ScoopTestOptions) { let user_addr = wallet_address(constants.payment_key) let owner = multisig.Signature(constants.payment_key) - let pool_fees = option.or_else(options.edit_swap_fees, ((5,5),(5,5))) - let pool_datum = PoolDatum { - identifier: constants.pool_ident, - assets: ( - (ada_policy_id, ada_asset_name), - (constants.rberry_policy, constants.rberry_asset_name), - ), - circulating_lp: 1_000_000_000, - bid_fees_per_10_thousand: pool_fees.1st, - ask_fees_per_10_thousand: pool_fees.2nd, - fee_manager: None, - market_open: 0, - fee_finalized: 0, - protocol_fees: 2_000_000, - } - let pool_out_datum = PoolDatum { - identifier: constants.pool_ident, - assets: ( - (ada_policy_id, ada_asset_name), - (constants.rberry_policy, constants.rberry_asset_name), - ), - circulating_lp: 1_009_900_990, - bid_fees_per_10_thousand: pool_fees.1st, - ask_fees_per_10_thousand: pool_fees.2nd, - fee_manager: None, - market_open: 0, - fee_finalized: 0, - protocol_fees: 7_000_000, - } + let pool_fees = option.or_else(options.edit_swap_fees, (5, 5)) + let pool_datum = + PoolDatum { + identifier: constants.pool_ident, + assets: ( + (ada_policy_id, ada_asset_name), + (constants.rberry_policy, constants.rberry_asset_name), + ), + circulating_lp: 1_000_000_000, + bid_fees_per_10_thousand: pool_fees.1st, + ask_fees_per_10_thousand: pool_fees.2nd, + fee_manager: None, + market_open: 0, + protocol_fees: 2_000_000, + } + let pool_out_datum = + PoolDatum { + identifier: constants.pool_ident, + assets: ( + (ada_policy_id, ada_asset_name), + (constants.rberry_policy, constants.rberry_asset_name), + ), + circulating_lp: 1_009_900_990, + bid_fees_per_10_thousand: pool_fees.1st, + ask_fees_per_10_thousand: pool_fees.2nd, + fee_manager: None, + market_open: 0, + protocol_fees: 7_000_000, + } let pool_nft_name = shared.pool_nft_name(constants.pool_ident) let pool_address = script_address(constants.pool_script_hash) - let pool_input = Input { - output_reference: mk_output_reference(0), - output: Output { - address: pool_address, - value: value.from_lovelace(1_000_000_000 + 2_000_000) - |> value.add(constants.rberry_policy, constants.rberry_asset_name, 1_000_000_000) - |> value.add(constants.pool_script_hash, pool_nft_name, 1), - datum: InlineDatum(pool_datum), - reference_script: None, - }, - } - let dest = options.edit_order_intended_destination |> option.or_else(Fixed { address: user_addr, datum: NoDatum }) + let pool_input = + Input { + output_reference: mk_output_reference(0), + output: Output { + address: pool_address, + value: value.from_lovelace(1_000_000_000 + 2_000_000) + |> value.add( + constants.rberry_policy, + constants.rberry_asset_name, + 1_000_000_000, + ) + |> value.add(constants.pool_script_hash, pool_nft_name, 1), + datum: InlineDatum(pool_datum), + reference_script: None, + }, + } + let dest = + options.edit_order_intended_destination + |> option.or_else(Fixed { address: user_addr, datum: NoDatum }) let swap = Swap( (ada_policy_id, ada_asset_name, 10_000_000), (constants.rberry_policy, constants.rberry_asset_name, 0), ) let deposit = - Deposit(( - (ada_policy_id, ada_asset_name, 10_000_000), - (constants.rberry_policy, constants.rberry_asset_name, 10_000_000), - )) - let order_datum_1 = OrderDatum { - pool_ident: None, - owner: owner, - max_protocol_fee: 2_500_000, - destination: dest, - details: swap, - extension: builtin.i_data(0), - } - let order_datum_2 = OrderDatum { - pool_ident: None, - owner: owner, - max_protocol_fee: 2_500_000, - destination: dest, - details: deposit, - extension: builtin.i_data(0), - } + Deposit( + ( + (ada_policy_id, ada_asset_name, 10_000_000), + (constants.rberry_policy, constants.rberry_asset_name, 10_000_000), + ), + ) + let order_datum_1 = + OrderDatum { + pool_ident: None, + owner, + max_protocol_fee: 2_500_000, + destination: dest, + details: swap, + extension: builtin.i_data(0), + } + let order_datum_2 = + OrderDatum { + pool_ident: None, + owner, + max_protocol_fee: 2_500_000, + destination: dest, + details: deposit, + extension: builtin.i_data(0), + } let order_address = script_address(constants.order_script_hash) - let order1_in = Input { - output_reference: mk_output_reference(2), - output: Output { - address: order_address, - value: value.from_lovelace(4_500_000 + 10_000_000), - datum: InlineDatum(order_datum_1), - reference_script: None, - }, - } - let order2_in = Input { - output_reference: mk_output_reference(3), - output: Output { - address: order_address, - value: value.from_lovelace(4_500_000 + 10_000_000) - |> value.add(constants.rberry_policy, constants.rberry_asset_name, 10_000_000), - datum: InlineDatum(order_datum_2), - reference_script: None, - }, - } - let settings_input = { - let Input {output_reference, output} = mk_valid_settings_input([constants.scooper], 1) - let updated_output = Output { - ..output, - datum: option.or_else(options.edit_settings_datum, output.datum) + let order1_in = + Input { + output_reference: mk_output_reference(2), + output: Output { + address: order_address, + value: value.from_lovelace(4_500_000 + 10_000_000), + datum: InlineDatum(order_datum_1), + reference_script: None, + }, } + let order2_in = Input { - output_reference: output_reference, - output: updated_output, + output_reference: mk_output_reference(3), + output: Output { + address: order_address, + value: value.from_lovelace(4_500_000 + 10_000_000) + |> value.add( + constants.rberry_policy, + constants.rberry_asset_name, + 10_000_000, + ), + datum: InlineDatum(order_datum_2), + reference_script: None, + }, } + let settings_input = { + let Input { output_reference, output } = + mk_valid_settings_input([constants.scooper], 1) + let updated_output = + Output { + ..output, + datum: option.or_else(options.edit_settings_datum, output.datum), + } + Input { output_reference, output: updated_output } } - let (order1_out_addr, order1_out_datum) = when options.edit_order_actual_destination is { - Some(Fixed(dest, datum)) -> (dest, datum) - Some(Self) -> (order_address, InlineDatum(order_datum_1)) - None -> (user_addr, NoDatum) - } - let order1_out = Output { - address: order1_out_addr, - value: option.or_else(options.edit_order_1_out_value, - value.from_lovelace(2_000_000) - |> value.add(constants.rberry_policy, constants.rberry_asset_name, 9_896_088)), - datum: order1_out_datum, - reference_script: None, - } - let (order2_out_addr, order2_out_datum) = when options.edit_order_actual_destination is { - Some(Fixed(dest, datum)) -> (dest, datum) - Some(Self) -> (order_address, InlineDatum(order_datum_2)) - None -> (user_addr, NoDatum) - } - let order2_out = Output { - address: order2_out_addr, - value: value.from_lovelace(2_000_000) - |> value.add(constants.pool_script_hash, pool_lp_name(constants.pool_ident), 9_900_990) - |> value.add(constants.rberry_policy, constants.rberry_asset_name, 196_990), - datum: order2_out_datum, - reference_script: None, - } - let pool_output = Output { - address: pool_address, - value: option.or_else(options.edit_pool_output_value, - value.from_lovelace(1_000_000_000 + 20_000_000 + 5_000_000 + 2_000_000) - |> value.add(constants.rberry_policy, constants.rberry_asset_name, 1_000_000_000 - 9_896_088 + 10_000_000 - 196_990) - |> value.add(constants.pool_script_hash, pool_nft_name, 1)), - datum: InlineDatum(pool_out_datum), - reference_script: None, - } - - let ctx = ScriptContext { - transaction: Transaction { - inputs: [pool_input, order1_in, order2_in], - reference_inputs: [settings_input], - outputs: [pool_output, order1_out, order2_out], - fee: option.or_else(options.edit_fee, value.from_lovelace(1_000_000)), - mint: value.to_minted_value( - value.from_lovelace(0) - |> value.add(constants.pool_script_hash, pool_lp_name(constants.pool_ident), 9_900_990) + let (order1_out_addr, order1_out_datum) = + when options.edit_order_actual_destination is { + Some(Fixed(dest, datum)) -> (dest, datum) + Some(Self) -> (order_address, InlineDatum(order_datum_1)) + None -> (user_addr, NoDatum) + } + let order1_out = + Output { + address: order1_out_addr, + value: option.or_else( + options.edit_order_1_out_value, + value.from_lovelace(2_000_000) + |> value.add( + constants.rberry_policy, + constants.rberry_asset_name, + 9_896_088, + ), ), - certificates: [], - withdrawals: dict.new(), - validity_range: interval.between(1, 2), - extra_signatories: [constants.scooper], - redeemers: dict.new(), - datums: dict.new(), - id: mk_tx_hash(1), - }, - purpose: Spend(pool_input.output_reference), - } - let pool_redeemer = PoolScoop( - 0, - 0, - [ - (1, None, 0), - (2, None, 0), - ] - ) - let result = pool_validator.spend(constants.manage_stake_script_hash, constants.settings_policy_id, pool_datum, pool_redeemer, ctx) + datum: order1_out_datum, + reference_script: None, + } + let (order2_out_addr, order2_out_datum) = + when options.edit_order_actual_destination is { + Some(Fixed(dest, datum)) -> (dest, datum) + Some(Self) -> (order_address, InlineDatum(order_datum_2)) + None -> (user_addr, NoDatum) + } + let order2_out = + Output { + address: order2_out_addr, + value: value.from_lovelace(2_000_000) + |> value.add( + constants.pool_script_hash, + pool_lp_name(constants.pool_ident), + 9_900_990, + ) + |> value.add(constants.rberry_policy, constants.rberry_asset_name, 196_990), + datum: order2_out_datum, + reference_script: None, + } + let pool_output = + Output { + address: pool_address, + value: option.or_else( + options.edit_pool_output_value, + value.from_lovelace(1_000_000_000 + 20_000_000 + 5_000_000 + 2_000_000) + |> value.add( + constants.rberry_policy, + constants.rberry_asset_name, + 1_000_000_000 - 9_896_088 + 10_000_000 - 196_990, + ) + |> value.add(constants.pool_script_hash, pool_nft_name, 1), + ), + datum: InlineDatum(pool_out_datum), + reference_script: None, + } + + let ctx = + ScriptContext { + transaction: Transaction { + inputs: [pool_input, order1_in, order2_in], + reference_inputs: [settings_input], + outputs: [pool_output, order1_out, order2_out], + fee: option.or_else(options.edit_fee, value.from_lovelace(1_000_000)), + mint: value.to_minted_value( + value.from_lovelace(0) + |> value.add( + constants.pool_script_hash, + pool_lp_name(constants.pool_ident), + 9_900_990, + ), + ), + certificates: [], + withdrawals: dict.new(), + validity_range: interval.between(1, 2), + extra_signatories: [constants.scooper], + redeemers: dict.new(), + datums: dict.new(), + id: mk_tx_hash(1), + }, + purpose: Spend(pool_input.output_reference), + } + let pool_redeemer = PoolScoop(0, 0, [(1, None, 0), (2, None, 0)]) + let result = + pool_validator.spend( + constants.manage_stake_script_hash, + constants.settings_policy_id, + pool_datum, + pool_redeemer, + ctx, + ) result } -fn withdraw_fees_transaction (options: ScoopTestOptions, withdraw_amount: Int) { - let withdraw_fees_redeemer = WithdrawFees { - amount: withdraw_amount, - treasury_output: 1, - pool_input: 0, - } - +fn withdraw_fees_transaction(options: ScoopTestOptions, withdraw_amount: Int, pool_input: Int) { + let withdraw_fees_redeemer = + WithdrawFees { amount: withdraw_amount, treasury_output: 1, pool_input: pool_input } + // Note: check that we're looking at the right input by making it not the first input let pool_nft_name = shared.pool_nft_name(constants.pool_ident) - let default_pool_output_address = Address { payment_credential: ScriptCredential(constants.pool_script_hash), stake_credential: Some(Inline(VerificationKeyCredential(example_settings_admin))) } - let pool_output_address = option.or_else(options.edit_pool_output_address, default_pool_output_address) - let pool_fees = option.or_else(options.edit_swap_fees, ((5,5),(5,5))) + let default_pool_output_address = + Address { + payment_credential: ScriptCredential(constants.pool_script_hash), + stake_credential: Some( + Inline(VerificationKeyCredential(example_settings_admin)), + ), + } + let pool_output_address = + option.or_else( + options.edit_pool_output_address, + default_pool_output_address, + ) + let pool_fees = option.or_else(options.edit_swap_fees, (5, 5)) let protocol_fees = 2_000_000 - let pool_datum = PoolDatum { - identifier: constants.pool_ident, - assets: ( - (ada_policy_id, ada_asset_name), - (constants.rberry_policy, constants.rberry_asset_name), - ), - circulating_lp: 1_000_000_000, - bid_fees_per_10_thousand: pool_fees.1st, - ask_fees_per_10_thousand: pool_fees.2nd, - fee_manager: None, - market_open: 0, - fee_finalized: 0, - protocol_fees, - } + let pool_datum = + PoolDatum { + identifier: constants.pool_ident, + assets: ( + (ada_policy_id, ada_asset_name), + (constants.rberry_policy, constants.rberry_asset_name), + ), + circulating_lp: 1_000_000_000, + bid_fees_per_10_thousand: pool_fees.1st, + ask_fees_per_10_thousand: pool_fees.2nd, + fee_manager: None, + market_open: 0, + protocol_fees, + } + let normal_input = + new_tx_input( + mk_tx_hash(0).hash, + // make a normal input that will sort before the pool input + wallet_address(constants.payment_key), + 1_000_000, + NoDatum, + ) // pool_test_tx_input deduplicate? - let pool_input = new_tx_input( - mk_tx_hash(0).hash, - script_address(constants.pool_script_hash), - 1_000_000_000 + protocol_fees, - InlineDatum(pool_datum)) - |> with_asset_of_tx_input(value.from_asset(constants.rberry_policy, constants.rberry_asset_name, 1_000_000_000)) - |> with_asset_of_tx_input(value.from_asset(constants.pool_script_hash, pool_nft_name, 1)) - - let pool_out_datum = PoolDatum { - ..pool_datum, - protocol_fees: pool_datum.protocol_fees - withdraw_amount, - } + let pool_input = + new_tx_input( + mk_tx_hash(1).hash, + script_address(constants.pool_script_hash), + 1_000_000_000 + protocol_fees, + InlineDatum(pool_datum), + ) + |> with_asset_of_tx_input( + value.from_asset( + constants.rberry_policy, + constants.rberry_asset_name, + 1_000_000_000, + ), + ) + |> with_asset_of_tx_input( + value.from_asset(constants.pool_script_hash, pool_nft_name, 1), + ) + let pool_redeemer = Manage + let pool_out_datum = + PoolDatum { + ..pool_datum, + protocol_fees: pool_datum.protocol_fees - withdraw_amount, + } - let pool_output = new_tx_output(pool_output_address, 0, InlineDatum(pool_out_datum)) - |> add_asset_to_tx_output(value.from_lovelace(1_000_000_000 + protocol_fees - withdraw_amount)) - |> add_asset_to_tx_output(value.from_asset(constants.rberry_policy, constants.rberry_asset_name, 1_000_000_000)) - |> add_asset_to_tx_output(value.from_asset(constants.pool_script_hash, pool_nft_name, 1)) - - let treasury_output = new_tx_output( - Address(VerificationKeyCredential(example_treasury_address), None), - 0, - InlineDatum(Void)) - |> add_asset_to_tx_output(value.from_lovelace(withdraw_amount)) - - let settings_datum = option.or_else(options.edit_settings_datum, InlineDatum(mk_valid_settings_datum([]))) - let settings_input = new_tx_input( - mk_tx_hash(1).hash, - script_address(constants.settings_policy_id), - 1, - settings_datum) |> with_asset_of_tx_input(value.from_asset(constants.settings_policy_id, settings_nft_name, 1)) - - let ctx = interval.between(1,2) - |> build_txn_context() - |> add_tx_ref_input(settings_input) - |> add_tx_input(pool_input) - |> add_tx_output(treasury_output) - |> add_tx_output(pool_output) - |> builder.add_signatory(example_treasury_admin) - |> builder.spend(pool_input.output_reference) - let result = pool_validator.manage(constants.settings_policy_id, withdraw_fees_redeemer, ctx) - result + let pool_output = + new_tx_output(pool_output_address, 0, InlineDatum(pool_out_datum)) + |> add_asset_to_tx_output( + value.from_lovelace(1_000_000_000 + protocol_fees - withdraw_amount), + ) + |> add_asset_to_tx_output( + value.from_asset( + constants.rberry_policy, + constants.rberry_asset_name, + 1_000_000_000, + ), + ) + |> add_asset_to_tx_output( + value.from_asset(constants.pool_script_hash, pool_nft_name, 1), + ) + + let treasury_output = + new_tx_output( + Address(VerificationKeyCredential(example_treasury_address), None), + 0, + InlineDatum(Void), + ) + |> add_asset_to_tx_output(value.from_lovelace(withdraw_amount)) + + let settings_datum = + option.or_else( + options.edit_settings_datum, + InlineDatum(mk_valid_settings_datum([])), + ) + let settings_input = + new_tx_input( + mk_tx_hash(1).hash, + script_address(constants.settings_policy_id), + 1, + settings_datum, + ) + |> with_asset_of_tx_input( + value.from_asset(constants.settings_policy_id, settings_nft_name, 1), + ) + + let ctx = + interval.between(1, 2) + |> build_txn_context() + |> add_tx_ref_input(settings_input) + |> add_tx_input(pool_input) + |> add_tx_input(normal_input) + |> add_tx_output(treasury_output) + |> add_tx_output(pool_output) + |> insert_withdrawal( + Inline(ScriptCredential(constants.manage_stake_script_hash)), + 0, + compare_stake, + ) + |> insert_redeemer( + Spend( + OutputReference { transaction_id: mk_tx_hash(1), output_index: 0 }, + ), + pool_redeemer, + compare_redeemer, + ) + |> insert_redeemer( + WithdrawFrom( + Inline(ScriptCredential(constants.manage_stake_script_hash)), + ), + withdraw_fees_redeemer, + compare_redeemer, + ) + |> builder.add_signatory(example_treasury_admin) + |> builder.spend(pool_input.output_reference) + let result_spend = + pool_validator.spend( + constants.manage_stake_script_hash, + constants.settings_policy_id, + pool_datum, + pool_redeemer, + ctx, + ) + let result_manage = + pool_validator.manage( + constants.settings_policy_id, + withdraw_fees_redeemer, + ctx, + ) + result_spend && result_manage } test withdraw_fees_transaction_test() { - withdraw_fees_transaction(default_scoop_test_options(), 100) + withdraw_fees_transaction(default_scoop_test_options(), 100, 1) +} +test withdraw_fees_transaction_wrong_pool_input() fail { + // Make sure that if we point to a different index, it'll fail + withdraw_fees_transaction(default_scoop_test_options(), 100, 0) } test withdraw_fees_transaction_change_pool_staking_address_valid_test() { - let example_address = VerificationKeyCredential( #"123456") - let options = ScoopTestOptions { - ..default_scoop_test_options(), - edit_settings_datum: Some(InlineDatum(SettingsDatum { - ..mk_valid_settings_datum([]), - authorized_staking_keys: [ - VerificationKeyCredential( - example_settings_admin, + let example_address = VerificationKeyCredential(#"123456") + let options = + ScoopTestOptions { + ..default_scoop_test_options(), + edit_settings_datum: Some( + InlineDatum( + SettingsDatum { + ..mk_valid_settings_datum([]), + authorized_staking_keys: [ + VerificationKeyCredential(example_settings_admin), + example_address, + ], + }, ), - example_address - ], - })), - edit_pool_output_address: Some(Address{payment_credential: ScriptCredential(constants.pool_script_hash), stake_credential: Some(Inline(example_address))}), - } - withdraw_fees_transaction(options, 100) + ), + edit_pool_output_address: Some( + Address { + payment_credential: ScriptCredential(constants.pool_script_hash), + stake_credential: Some(Inline(example_address)), + }, + ), + } + withdraw_fees_transaction(options, 100, 1) } test withdraw_fees_transaction_change_pool_staking_address_invalid_test() fail { - let example_address = VerificationKeyCredential( #"123456") - let thief_address = VerificationKeyCredential( #"654321") - - let options = ScoopTestOptions { - ..default_scoop_test_options(), - edit_settings_datum: Some(InlineDatum(SettingsDatum { - ..mk_valid_settings_datum([]), - authorized_staking_keys: [ - VerificationKeyCredential( - example_settings_admin, + let example_address = VerificationKeyCredential(#"123456") + let thief_address = VerificationKeyCredential(#"654321") + + let options = + ScoopTestOptions { + ..default_scoop_test_options(), + edit_settings_datum: Some( + InlineDatum( + SettingsDatum { + ..mk_valid_settings_datum([]), + authorized_staking_keys: [ + VerificationKeyCredential(example_settings_admin), + example_address, + ], + }, ), - example_address - ], - })), - edit_pool_output_address: Some(Address{payment_credential: ScriptCredential(constants.pool_script_hash), stake_credential: Some(Inline(thief_address))}), - } - withdraw_fees_transaction(options, 100) + ), + edit_pool_output_address: Some( + Address { + payment_credential: ScriptCredential(constants.pool_script_hash), + stake_credential: Some(Inline(thief_address)), + }, + ), + } + withdraw_fees_transaction(options, 100, 1) } test overdraw_test() fail { - let example_address = VerificationKeyCredential( #"123456") - let thief_address = VerificationKeyCredential( #"654321") - - let options = ScoopTestOptions { - ..default_scoop_test_options(), - edit_settings_datum: Some(InlineDatum(SettingsDatum { - ..mk_valid_settings_datum([]), - authorized_staking_keys: [ - VerificationKeyCredential( - example_settings_admin, + let example_address = VerificationKeyCredential(#"123456") + let thief_address = VerificationKeyCredential(#"654321") + + let options = + ScoopTestOptions { + ..default_scoop_test_options(), + edit_settings_datum: Some( + InlineDatum( + SettingsDatum { + ..mk_valid_settings_datum([]), + authorized_staking_keys: [ + VerificationKeyCredential(example_settings_admin), + example_address, + ], + }, ), - example_address - ], - })), - edit_pool_output_address: Some(Address{payment_credential: ScriptCredential(constants.pool_script_hash), stake_credential: Some(Inline(thief_address))}), - } - withdraw_fees_transaction(options, 5_000_000) + ), + edit_pool_output_address: Some( + Address { + payment_credential: ScriptCredential(constants.pool_script_hash), + stake_credential: Some(Inline(thief_address)), + }, + ), + } + withdraw_fees_transaction(options, 5_000_000, 1) } -fn update_pool_fees_transaction (options: ScoopTestOptions) { - - let update_fees_redeemer = UpdatePoolFees { - pool_input: 0, - } +fn update_pool_fees_transaction(options: ScoopTestOptions) { + let update_fees_redeemer = UpdatePoolFees { pool_input: 0 } let pool_nft_name = shared.pool_nft_name(constants.pool_ident) - let default_pool_output_address = Address { payment_credential: ScriptCredential(constants.pool_script_hash), stake_credential: Some(Inline(VerificationKeyCredential(example_settings_admin))) } - let pool_output_address = option.or_else(options.edit_pool_output_address, default_pool_output_address) - let pool_fees = option.or_else(options.edit_swap_fees, ((5,5),(5,5))) - let fee_manager = option.or_else(options.edit_fee_admin, Some(multisig.Signature(constants.pool_script_hash))) - let pool_datum = PoolDatum { - identifier: constants.pool_ident, - assets: ( - (ada_policy_id, ada_asset_name), - (constants.rberry_policy, constants.rberry_asset_name), - ), - circulating_lp: 1_000_000_000, - bid_fees_per_10_thousand: pool_fees.1st, - ask_fees_per_10_thousand: pool_fees.2nd, - fee_manager: fee_manager, - market_open: 0, - fee_finalized: 0, - protocol_fees: 2_000_000, - } + let default_pool_output_address = + Address { + payment_credential: ScriptCredential(constants.pool_script_hash), + stake_credential: Some( + Inline(VerificationKeyCredential(example_settings_admin)), + ), + } + let pool_output_address = + option.or_else( + options.edit_pool_output_address, + default_pool_output_address, + ) + let pool_fees = option.or_else(options.edit_swap_fees, (5, 5)) + let fee_manager = + option.or_else( + options.edit_fee_admin, + Some(multisig.Signature(constants.pool_script_hash)), + ) + let pool_datum = + PoolDatum { + identifier: constants.pool_ident, + assets: ( + (ada_policy_id, ada_asset_name), + (constants.rberry_policy, constants.rberry_asset_name), + ), + circulating_lp: 1_000_000_000, + bid_fees_per_10_thousand: pool_fees.1st, + ask_fees_per_10_thousand: pool_fees.2nd, + fee_manager, + market_open: 0, + protocol_fees: 2_000_000, + } let pool_rider = 2_000_000 // pool_test_tx_input deduplicate? - let pool_input_address = option.or_else(options.edit_pool_input_address, default_pool_output_address) - let pool_input = new_tx_input( - mk_tx_hash(0).hash, - pool_input_address, - 1_000_000_000 + pool_rider, - InlineDatum(pool_datum)) - |> with_asset_of_tx_input(value.from_asset(constants.rberry_policy, constants.rberry_asset_name, 1_000_000_000)) - |> with_asset_of_tx_input(value.from_asset(constants.pool_script_hash, pool_nft_name, 1)) - - let new_pool_fees = option.or_else(options.edit_new_swap_fees, ((10,10),(310,150))) - let pool_out_datum = PoolDatum { - ..pool_datum, - bid_fees_per_10_thousand: new_pool_fees.1st, - ask_fees_per_10_thousand: new_pool_fees.2nd, - } + let pool_input_address = + option.or_else(options.edit_pool_input_address, default_pool_output_address) + let pool_input = + new_tx_input( + mk_tx_hash(0).hash, + pool_input_address, + 1_000_000_000 + pool_rider, + InlineDatum(pool_datum), + ) + |> with_asset_of_tx_input( + value.from_asset( + constants.rberry_policy, + constants.rberry_asset_name, + 1_000_000_000, + ), + ) + |> with_asset_of_tx_input( + value.from_asset(constants.pool_script_hash, pool_nft_name, 1), + ) + + let new_pool_fees = + option.or_else(options.edit_new_swap_fees, (10, 10)) + let pool_out_datum = + PoolDatum { + ..pool_datum, + bid_fees_per_10_thousand: new_pool_fees.1st, + ask_fees_per_10_thousand: new_pool_fees.2nd, + } - let pool_output = new_tx_output(pool_output_address, 0, InlineDatum(pool_out_datum)) - |> add_asset_to_tx_output(value.from_lovelace(1_000_000_000 + pool_rider)) - |> add_asset_to_tx_output(value.from_asset(constants.rberry_policy, constants.rberry_asset_name, 1_000_000_000)) - |> add_asset_to_tx_output(value.from_asset(constants.pool_script_hash, pool_nft_name, 1)) - - let settings_datum = option.or_else(options.edit_settings_datum, InlineDatum(mk_valid_settings_datum([]))) - let settings_input = new_tx_input( - mk_tx_hash(1).hash, - script_address(constants.settings_policy_id), - 1, - settings_datum) |> with_asset_of_tx_input(value.from_asset(constants.settings_policy_id, settings_nft_name, 1)) - - let ctx = interval.between(1,2) - |> build_txn_context() - |> add_tx_ref_input(settings_input) - |> add_tx_input(pool_input) - |> add_tx_output(pool_output) - |> builder.add_signatory(constants.pool_script_hash) - |> builder.spend(pool_input.output_reference) + let pool_output = + new_tx_output(pool_output_address, 0, InlineDatum(pool_out_datum)) + |> add_asset_to_tx_output(value.from_lovelace(1_000_000_000 + pool_rider)) + |> add_asset_to_tx_output( + value.from_asset( + constants.rberry_policy, + constants.rberry_asset_name, + 1_000_000_000, + ), + ) + |> add_asset_to_tx_output( + value.from_asset(constants.pool_script_hash, pool_nft_name, 1), + ) + + let settings_datum = + option.or_else( + options.edit_settings_datum, + InlineDatum(mk_valid_settings_datum([])), + ) + let settings_input = + new_tx_input( + mk_tx_hash(1).hash, + script_address(constants.settings_policy_id), + 1, + settings_datum, + ) + |> with_asset_of_tx_input( + value.from_asset(constants.settings_policy_id, settings_nft_name, 1), + ) + + let ctx = + interval.between(1, 2) + |> build_txn_context() + |> add_tx_ref_input(settings_input) + |> add_tx_input(pool_input) + |> add_tx_output(pool_output) + |> builder.add_signatory(constants.pool_script_hash) + |> builder.spend(pool_input.output_reference) let withdrawals = option.or_else(options.edit_withdrawals, dict.new()) - let ctx = ScriptContext( - Transaction { - ..ctx.transaction, - withdrawals, - }, - ctx.purpose, - ) - let result = pool_validator.manage(constants.settings_policy_id, update_fees_redeemer, ctx) + let ctx = + ScriptContext( + Transaction { ..ctx.transaction, withdrawals: withdrawals }, + ctx.purpose, + ) + let result = + pool_validator.manage( + constants.settings_policy_id, + update_fees_redeemer, + ctx, + ) result } @@ -854,36 +1123,45 @@ test update_pool_fees_transaction_test() { } test illegal_new_pool_fees_test() fail { - let settings = ScoopTestOptions { - ..default_scoop_test_options(), - edit_new_swap_fees: Some(((10001,10001),(10001,10001))), - } + let settings = + ScoopTestOptions { + ..default_scoop_test_options(), + edit_new_swap_fees: Some((10001, 10001)), + } update_pool_fees_transaction(settings) } test cannot_update_pool_fees_transaction_test() fail { - let settings = ScoopTestOptions { - ..default_scoop_test_options(), - edit_fee_admin: Some(None), - } + let settings = + ScoopTestOptions { + ..default_scoop_test_options(), + edit_fee_admin: Some(None), + } update_pool_fees_transaction(settings) } test update_pool_fees_transaction_with_script_test() { - let settings = ScoopTestOptions { - ..default_scoop_test_options(), - edit_fee_admin: Some(Some(multisig.Script(#"1234"))), - edit_withdrawals: Some(dict.from_ascending_list([(Inline(ScriptCredential(#"1234")), 100)], compare_stake)), - } + let settings = + ScoopTestOptions { + ..default_scoop_test_options(), + edit_fee_admin: Some(Some(multisig.Script(#"1234"))), + edit_withdrawals: Some( + dict.from_ascending_list( + [(Inline(ScriptCredential(#"1234")), 100)], + compare_stake, + ), + ), + } update_pool_fees_transaction(settings) } test scoop_strategy_self() { - let options = ScoopTestOptions { - ..default_scoop_test_options(), - edit_order_intended_destination: Some(Self), - edit_order_actual_destination: Some(Self), - } + let options = + ScoopTestOptions { + ..default_scoop_test_options(), + edit_order_intended_destination: Some(Self), + edit_order_actual_destination: Some(Self), + } scoop(options) } @@ -891,11 +1169,13 @@ fn pool_test_tx_input() -> Input { let funds_input = new_tx_input( mk_tx_hash(0).hash, - wallet_address(#"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513"), + wallet_address( + #"6af53ff4f054348ad825c692dd9db8f1760a8e0eacf9af9f99306513", + ), 0, NoDatum, ) - funds_input + funds_input } test mint_test_two_nfts() fail { @@ -903,21 +1183,33 @@ test mint_test_two_nfts() fail { let (_, new_pool_nft_token, _) = shared.pool_token_names(pool_id) // if we add on another pool NFT token to the pool output, it should fail mint_test_modify( - fn(output) { Output { ..output, value: value.add(output.value, constants.pool_script_hash, new_pool_nft_token, 1) } }, - identity, - identity, - identity, - identity, - ) + fn(output) { + Output { + ..output, + value: value.add( + output.value, + constants.pool_script_hash, + new_pool_nft_token, + 1, + ), + } + }, + identity, + identity, + identity, + identity, + ) } -fn pool_ident_from_input (tx_input: Input) -> ByteArray { +fn pool_ident_from_input(tx_input: Input) -> ByteArray { tx_input.output_reference.transaction_id.hash - |> bytearray.concat(#"23") // '#' character - |> - bytearray.concat(pool_validator.int_to_ident(tx_input.output_reference.output_index)) - |> hash.blake2b_256 - |> bytearray.drop(4) + |> bytearray.concat(#"23") // '#' character + + |> bytearray.concat( + pool_validator.int_to_ident(tx_input.output_reference.output_index), + ) + |> hash.blake2b_256 + |> bytearray.drop(4) } fn mint_test_modify( @@ -927,36 +1219,53 @@ fn mint_test_modify( modify_datum: fn(Datum) -> Datum, modify_redeemer: fn(PoolMintRedeemer) -> PoolMintRedeemer, ) -> Bool { - let pool_address = script_address(constants.pool_script_hash) |> with_delegation_key(example_settings_admin) + let pool_address = + script_address(constants.pool_script_hash) + |> with_delegation_key(example_settings_admin) let user_address = wallet_address(constants.payment_key) let settings_input = mk_valid_settings_input([], 1) let funds_input = pool_test_tx_input() let pool_id = pool_ident_from_input(funds_input) - let (new_pool_ref_token, new_pool_nft_token, new_pool_lp_token) = shared.pool_token_names(pool_id) - let inline_pool_datum = modify_datum(InlineDatum( - PoolDatum { - identifier: pool_id, - assets: ((ada_policy_id, ada_asset_name), (constants.rberry_policy, constants.rberry_asset_name)), - circulating_lp: 1_000_000_000, - bid_fees_per_10_thousand: (5, 5), - ask_fees_per_10_thousand: (5, 5), - fee_manager: None, - market_open: 0, - fee_finalized: 0, - protocol_fees: 2_000_000, - } - )) + let (new_pool_ref_token, new_pool_nft_token, new_pool_lp_token) = + shared.pool_token_names(pool_id) + let inline_pool_datum = + modify_datum( + InlineDatum( + PoolDatum { + identifier: pool_id, + assets: ( + (ada_policy_id, ada_asset_name), + (constants.rberry_policy, constants.rberry_asset_name), + ), + circulating_lp: 1_000_000_000, + bid_fees_per_10_thousand: 5, + ask_fees_per_10_thousand: 5, + fee_manager: None, + market_open: 0, + protocol_fees: 2_000_000, + }, + ), + ) let pool_output_val = - value.from_asset(constants.rberry_policy, constants.rberry_asset_name, 1_000_000_000) + value.from_asset( + constants.rberry_policy, + constants.rberry_asset_name, + 1_000_000_000, + ) |> value.add(constants.pool_script_hash, new_pool_nft_token, 1) |> value.merge(value.from_lovelace(1_002_000_000)) - let pool_output = new_tx_output(pool_address, 0, inline_pool_datum) // 1_002_000_000 = 1_000_000_000 ADA for pool + 2_000_000 ADA for protocol_fees + let pool_output = + new_tx_output(pool_address, 0, inline_pool_datum) // 1_002_000_000 = 1_000_000_000 ADA for pool + 2_000_000 ADA for protocol_fees |> add_asset_to_tx_output(pool_output_val) |> modify_pool_output let lp_output_val = - value.from_asset(constants.pool_script_hash, pool_lp_name(pool_id), 1_000_000_000) + value.from_asset( + constants.pool_script_hash, + pool_lp_name(pool_id), + 1_000_000_000, + ) |> value.merge(value.from_lovelace(2_000_000)) let lp_output = new_tx_output(user_address, 0, NoDatum) // we can probably get rid of the rider, it gets auto added @@ -972,29 +1281,47 @@ fn mint_test_modify( |> add_asset_to_tx_output(ref_output_val) |> modify_ref_output - let pool_mint_redeemer = modify_redeemer(CreatePool { - assets: ((ada_policy_id, ada_asset_name), (constants.rberry_policy, constants.rberry_asset_name)), - pool_output: 0, - metadata_output: 2, - }) - - let ctx = interval.between(1,2) - |> build_txn_context() - |> mint_assets(constants.pool_script_hash, value.to_minted_value( - value.from_lovelace(0) - |> value.add(constants.pool_script_hash, new_pool_lp_token, 1_000_000_000) - |> value.add(constants.pool_script_hash, new_pool_nft_token, 1) - |> value.add(constants.pool_script_hash, new_pool_ref_token, 1) - )) - |> add_tx_input(funds_input) - |> add_tx_ref_input(settings_input) - - // these must be in reverse order like so, in order to get [pool_output, lp_output, ref_output] - |> add_tx_output(ref_output) - |> add_tx_output(lp_output) - |> add_tx_output(pool_output) - - let result = pool_validator.mint(constants.manage_stake_script_hash, constants.settings_policy_id, pool_mint_redeemer, ctx) + let pool_mint_redeemer = + modify_redeemer( + CreatePool { + assets: ( + (ada_policy_id, ada_asset_name), + (constants.rberry_policy, constants.rberry_asset_name), + ), + pool_output: 0, + metadata_output: 2, + }, + ) + + let ctx = + interval.between(1, 2) + |> build_txn_context() + |> mint_assets( + constants.pool_script_hash, + value.to_minted_value( + value.from_lovelace(0) + |> value.add( + constants.pool_script_hash, + new_pool_lp_token, + 1_000_000_000, + ) + |> value.add(constants.pool_script_hash, new_pool_nft_token, 1) + |> value.add(constants.pool_script_hash, new_pool_ref_token, 1), + ), + ) + |> add_tx_input(funds_input) + |> add_tx_ref_input(settings_input) // these must be in reverse order like so, in order to get [pool_output, lp_output, ref_output] + |> add_tx_output(ref_output) + |> add_tx_output(lp_output) + |> add_tx_output(pool_output) + + let result = + pool_validator.mint( + constants.manage_stake_script_hash, + constants.settings_policy_id, + pool_mint_redeemer, + ctx, + ) result } @@ -1013,165 +1340,255 @@ test mint_exotic_pair() { |> value.add(#"", #"", 2_000_000) mint_test_modify( - fn (output) { - Output { - ..output, - value: exotic_pair_value - } - }, + fn(output) { Output { ..output, value: exotic_pair_value } }, identity, identity, fn(pool_datum) { expect InlineDatum(pool_datum) = pool_datum expect pool_datum: PoolDatum = pool_datum - InlineDatum(PoolDatum { - ..pool_datum, - assets: ((#"01", #"54"), (#"02", #"55")), - }) + InlineDatum( + PoolDatum { ..pool_datum, assets: ((#"01", #"54"), (#"02", #"55")) }, + ) }, fn(redeemer) { when redeemer is { - CreatePool(_, ix, mx) -> CreatePool(((#"01", #"54"), (#"02", #"55")), ix, mx) - _ -> fail "expected create pool" + CreatePool(_, ix, mx) -> + CreatePool(((#"01", #"54"), (#"02", #"55")), ix, mx) + _ -> fail @"expected create pool" } - } + }, ) } // make sure pool_output.address is checked to be the pool address -test mint_test_wrong_address () fail { - let minted = mint_test_modify( - // change pool nft output address to destination that shouldn't be possible - fn (output) { - Output{ - ..output, - // TODO: move some of this stuff to constants? - address: from_verification_key(constants.random_hash) |> with_delegation_key(constants.stake_key) - } - }, - identity, - identity, - identity, - identity, - ) +test mint_test_wrong_address() fail { + let minted = + mint_test_modify( + // change pool nft output address to destination that shouldn't be possible + fn(output) { + Output { + ..output, + address: // TODO: move some of this stuff to constants? + from_verification_key(constants.random_hash) + |> with_delegation_key(constants.stake_key), + } + }, + identity, + identity, + identity, + identity, + ) minted } // make sure we can't include any spam on the datum test mint_test_nonvoid_datum() fail { - let minted = mint_test_modify( - identity, - identity, - fn (ref_metadata_output) { - Output { - ..ref_metadata_output, - datum: InlineDatum("Evil data") - } - }, - identity, - identity, - ) + let minted = + mint_test_modify( + identity, + identity, + fn(ref_metadata_output) { + Output { ..ref_metadata_output, datum: InlineDatum("Evil data") } + }, + identity, + identity, + ) minted } test has_expected_pool_value_test() { - let (_, pool_nft_token, pool_lp_token) = shared.pool_token_names(constants.pool_ident) - let pool_value = value.from_lovelace(102_000_000) - |> value.add(constants.rberry_policy, constants.rberry_asset_name, 100_000_000) - |> value.add(constants.pool_script_hash, pool_nft_token, 1) - let outcome = PoolState { - quantity_lp: (constants.pool_script_hash, pool_lp_token, 99), - quantity_a: (ada_policy_id, ada_asset_name, 100_000_000), - quantity_b: (constants.rberry_policy, constants.rberry_asset_name, 100_000_000) - } + let (_, pool_nft_token, pool_lp_token) = + shared.pool_token_names(constants.pool_ident) + let pool_value = + value.from_lovelace(102_000_000) + |> value.add( + constants.rberry_policy, + constants.rberry_asset_name, + 100_000_000, + ) + |> value.add(constants.pool_script_hash, pool_nft_token, 1) + let outcome = + PoolState { + quantity_lp: (constants.pool_script_hash, pool_lp_token, 99), + quantity_a: (ada_policy_id, ada_asset_name, 100_000_000), + quantity_b: ( + constants.rberry_policy, + constants.rberry_asset_name, + 100_000_000, + ), + } let protocol_fees = 2_000_000 pool_validator.has_expected_pool_value( constants.pool_script_hash, constants.pool_ident, pool_value, - outcome.quantity_a.1st, outcome.quantity_a.2nd, outcome.quantity_a.3rd, - outcome.quantity_b.1st, outcome.quantity_b.2nd, outcome.quantity_b.3rd, + outcome.quantity_a.1st, + outcome.quantity_a.2nd, + outcome.quantity_a.3rd, + outcome.quantity_b.1st, + outcome.quantity_b.2nd, + outcome.quantity_b.3rd, + 99, protocol_fees, ) } test has_expected_pool_value_test2() { - let (_, pool_nft_token, pool_lp_token) = shared.pool_token_names(constants.pool_ident) - let pool_value = value.from_lovelace(2_000_000) - |> value.add(constants.other_policy, constants.other_asset_name, 100_000_000) - |> value.add(constants.rberry_policy, constants.rberry_asset_name, 100_000_000) - |> value.add(constants.pool_script_hash, pool_nft_token, 1) - let outcome = PoolState { - quantity_lp: (constants.pool_script_hash, pool_lp_token, 99), - quantity_a: (constants.other_policy, constants.other_asset_name, 100_000_000), - quantity_b: (constants.rberry_policy, constants.rberry_asset_name, 100_000_000) - } + let (_, pool_nft_token, pool_lp_token) = + shared.pool_token_names(constants.pool_ident) + let pool_value = + value.from_lovelace(2_000_000) + |> value.add(constants.other_policy, constants.other_asset_name, 100_000_000) + |> value.add( + constants.rberry_policy, + constants.rberry_asset_name, + 100_000_000, + ) + |> value.add(constants.pool_script_hash, pool_nft_token, 1) + let outcome = + PoolState { + quantity_lp: (constants.pool_script_hash, pool_lp_token, 99), + quantity_a: ( + constants.other_policy, + constants.other_asset_name, + 100_000_000, + ), + quantity_b: ( + constants.rberry_policy, + constants.rberry_asset_name, + 100_000_000, + ), + } let protocol_fees = 2_000_000 pool_validator.has_expected_pool_value( constants.pool_script_hash, constants.pool_ident, pool_value, - outcome.quantity_a.1st, outcome.quantity_a.2nd, outcome.quantity_a.3rd, - outcome.quantity_b.1st, outcome.quantity_b.2nd, outcome.quantity_b.3rd, + outcome.quantity_a.1st, + outcome.quantity_a.2nd, + outcome.quantity_a.3rd, + outcome.quantity_b.1st, + outcome.quantity_b.2nd, + outcome.quantity_b.3rd, + 99, + protocol_fees, + ) +} + +test has_expected_pool_value_withdraw_all() { + let (_, pool_nft_token, pool_lp_token) = + shared.pool_token_names(constants.pool_ident) + let pool_value = + value.from_lovelace(3_000_000) + |> value.add(constants.pool_script_hash, pool_nft_token, 1) + let outcome = + PoolState { + quantity_lp: (constants.pool_script_hash, pool_lp_token, 0), + quantity_a: ( + constants.other_policy, + constants.other_asset_name, + 0, + ), + quantity_b: ( + constants.rberry_policy, + constants.rberry_asset_name, + 0, + ), + } + let protocol_fees = 3_000_000 + + pool_validator.has_expected_pool_value( + constants.pool_script_hash, + constants.pool_ident, + pool_value, + outcome.quantity_a.1st, + outcome.quantity_a.2nd, + outcome.quantity_a.3rd, + outcome.quantity_b.1st, + outcome.quantity_b.2nd, + outcome.quantity_b.3rd, + outcome.quantity_lp.3rd, protocol_fees, ) } fn evaporate_pool_tx(options: ScoopTestOptions, withdraw_amount: Int) { - let withdraw_fees_redeemer = WithdrawFees { - amount: withdraw_amount, - treasury_output: 0, - pool_input: 0, - } - + let withdraw_fees_redeemer = + WithdrawFees { amount: withdraw_amount, treasury_output: 0, pool_input: 0 } let pool_nft_name = shared.pool_nft_name(constants.pool_ident) - let pool_fees = option.or_else(options.edit_swap_fees, ((5,5),(5,5))) - let pool_datum = PoolDatum { - identifier: constants.pool_ident, - assets: ( - (ada_policy_id, ada_asset_name), - (constants.rberry_policy, constants.rberry_asset_name), - ), - circulating_lp: 0, - bid_fees_per_10_thousand: pool_fees.1st, - ask_fees_per_10_thousand: pool_fees.2nd, - fee_manager: None, - market_open: 0, - fee_finalized: 0, - protocol_fees: 18_000_000, - } + let pool_fees = option.or_else(options.edit_swap_fees, (5, 5)) + let pool_datum = + PoolDatum { + identifier: constants.pool_ident, + assets: ( + (ada_policy_id, ada_asset_name), + (constants.rberry_policy, constants.rberry_asset_name), + ), + circulating_lp: 0, + bid_fees_per_10_thousand: pool_fees.1st, + ask_fees_per_10_thousand: pool_fees.2nd, + fee_manager: None, + market_open: 0, + protocol_fees: 18_000_000, + } // pool_test_tx_input deduplicate? - let pool_input = new_tx_input( - mk_tx_hash(0).hash, - script_address(constants.pool_script_hash), - 18_000_000, - InlineDatum(pool_datum)) - |> with_asset_of_tx_input(value.from_asset(constants.pool_script_hash, pool_nft_name, 1)) - - let treasury_output = new_tx_output( - Address(VerificationKeyCredential(example_treasury_address), None), - 0, - InlineDatum(Void)) - |> add_asset_to_tx_output(value.from_lovelace(withdraw_amount)) - - let settings_datum = option.or_else(options.edit_settings_datum, InlineDatum(mk_valid_settings_datum([]))) - let settings_input = new_tx_input( - mk_tx_hash(1).hash, - script_address(constants.settings_policy_id), - 1, - settings_datum) |> with_asset_of_tx_input(value.from_asset(constants.settings_policy_id, settings_nft_name, 1)) - - let ctx = interval.between(1,2) - |> build_txn_context() - |> add_tx_ref_input(settings_input) - |> add_tx_input(pool_input) - |> add_tx_output(treasury_output) - |> mint_assets(constants.pool_script_hash, value.to_minted_value(value.from_asset(constants.pool_script_hash, pool_nft_name, -1))) - |> builder.add_signatory(example_treasury_admin) - |> builder.spend(pool_input.output_reference) - let result = pool_validator.manage(constants.settings_policy_id, withdraw_fees_redeemer, ctx) + let pool_input = + new_tx_input( + mk_tx_hash(0).hash, + script_address(constants.pool_script_hash), + 18_000_000, + InlineDatum(pool_datum), + ) + |> with_asset_of_tx_input( + value.from_asset(constants.pool_script_hash, pool_nft_name, 1), + ) + + let treasury_output = + new_tx_output( + Address(VerificationKeyCredential(example_treasury_address), None), + 0, + InlineDatum(Void), + ) + |> add_asset_to_tx_output(value.from_lovelace(withdraw_amount)) + + let settings_datum = + option.or_else( + options.edit_settings_datum, + InlineDatum(mk_valid_settings_datum([])), + ) + let settings_input = + new_tx_input( + mk_tx_hash(1).hash, + script_address(constants.settings_policy_id), + 1, + settings_datum, + ) + |> with_asset_of_tx_input( + value.from_asset(constants.settings_policy_id, settings_nft_name, 1), + ) + + let ctx = + interval.between(1, 2) + |> build_txn_context() + |> add_tx_ref_input(settings_input) + |> add_tx_input(pool_input) + |> add_tx_output(treasury_output) + |> mint_assets( + constants.pool_script_hash, + value.to_minted_value( + value.from_asset(constants.pool_script_hash, pool_nft_name, -1), + ), + ) + |> builder.add_signatory(example_treasury_admin) + |> builder.spend(pool_input.output_reference) + let result = + pool_validator.manage( + constants.settings_policy_id, + withdraw_fees_redeemer, + ctx, + ) result } @@ -1183,77 +1600,93 @@ test dont_evaporate_pool_test() fail { evaporate_pool_tx(default_scoop_test_options(), 17_000_000) } - test attempt_evaporate_pool_test() { - let withdraw_fees_redeemer = WithdrawFees { - amount: 18_000_000, - treasury_output: 0, - pool_input: 0, - } - + let withdraw_fees_redeemer = + WithdrawFees { amount: 18_000_000, treasury_output: 0, pool_input: 0 } let pool_nft_name = shared.pool_nft_name(constants.pool_ident) - let pool_fees = ((5,5),(5,5)) - let pool_datum = PoolDatum { - identifier: constants.pool_ident, - assets: ( - (ada_policy_id, ada_asset_name), - (constants.rberry_policy, constants.rberry_asset_name), - ), - circulating_lp: 0, - bid_fees_per_10_thousand: pool_fees.1st, - ask_fees_per_10_thousand: pool_fees.2nd, - fee_manager: None, - market_open: 0, - fee_finalized: 0, - protocol_fees: 18_000_000, - } + let pool_fees = (5, 5) + let pool_datum = + PoolDatum { + identifier: constants.pool_ident, + assets: ( + (ada_policy_id, ada_asset_name), + (constants.rberry_policy, constants.rberry_asset_name), + ), + circulating_lp: 0, + bid_fees_per_10_thousand: pool_fees.1st, + ask_fees_per_10_thousand: pool_fees.2nd, + fee_manager: None, + market_open: 0, + protocol_fees: 18_000_000, + } // pool_test_tx_input deduplicate? - let pool_input = new_tx_input( - mk_tx_hash(0).hash, - script_address(constants.pool_script_hash), - 18_000_000, - InlineDatum(pool_datum)) - |> with_asset_of_tx_input( - value.from_asset(constants.pool_script_hash, pool_nft_name, 1) + let pool_input = + new_tx_input( + mk_tx_hash(0).hash, + script_address(constants.pool_script_hash), + 18_000_000, + InlineDatum(pool_datum), ) + |> with_asset_of_tx_input( + value.from_asset(constants.pool_script_hash, pool_nft_name, 1), + ) - let treasury_output = new_tx_output( - Address(VerificationKeyCredential(example_treasury_address), None), - 0, - InlineDatum(Void)) - |> add_asset_to_tx_output(value.from_lovelace(18_000_000)) + let treasury_output = + new_tx_output( + Address(VerificationKeyCredential(example_treasury_address), None), + 0, + InlineDatum(Void), + ) + |> add_asset_to_tx_output(value.from_lovelace(18_000_000)) let settings_datum = InlineDatum(mk_valid_settings_datum([])) - let settings_input = new_tx_input( - mk_tx_hash(1).hash, - script_address(constants.settings_policy_id), - 1, - settings_datum) |> with_asset_of_tx_input(value.from_asset(constants.settings_policy_id, settings_nft_name, 1)) - - let ctx = interval.between(1,2) - |> build_txn_context() - |> add_tx_ref_input(settings_input) - |> add_tx_input(pool_input) - |> add_tx_output(treasury_output) - |> mint_assets(constants.pool_script_hash, value.to_minted_value(value.from_asset(constants.pool_script_hash, pool_nft_name, -1))) - |> builder.add_signatory(example_treasury_admin) - |> builder.spend(pool_input.output_reference) - pool_validator.manage(constants.settings_policy_id, withdraw_fees_redeemer, ctx) + let settings_input = + new_tx_input( + mk_tx_hash(1).hash, + script_address(constants.settings_policy_id), + 1, + settings_datum, + ) + |> with_asset_of_tx_input( + value.from_asset(constants.settings_policy_id, settings_nft_name, 1), + ) + + let ctx = + interval.between(1, 2) + |> build_txn_context() + |> add_tx_ref_input(settings_input) + |> add_tx_input(pool_input) + |> add_tx_output(treasury_output) + |> mint_assets( + constants.pool_script_hash, + value.to_minted_value( + value.from_asset(constants.pool_script_hash, pool_nft_name, -1), + ), + ) + |> builder.add_signatory(example_treasury_admin) + |> builder.spend(pool_input.output_reference) + pool_validator.manage( + constants.settings_policy_id, + withdraw_fees_redeemer, + ctx, + ) } test burn_pool() { let user_addr = wallet_address(constants.payment_key) - let fees = ((5,5),(5,5)) + let fees = (5, 5) let pool_datum = PoolDatum { identifier: constants.pool_ident, - assets: ((ada_policy_id, ada_asset_name), (constants.rberry_policy, constants.rberry_asset_name)), + assets: ( + (ada_policy_id, ada_asset_name), + (constants.rberry_policy, constants.rberry_asset_name), + ), circulating_lp: 0, bid_fees_per_10_thousand: fees.1st, ask_fees_per_10_thousand: fees.2nd, fee_manager: None, market_open: 0, - fee_finalized: 0, protocol_fees: 2_000_000, } let pool_nft_name = shared.pool_nft_name(constants.pool_ident) @@ -1283,17 +1716,27 @@ test burn_pool() { } let (_, pool_nft_token, _) = shared.pool_token_names(constants.pool_ident) - let ctx = interval.between(1,2) - |> build_txn_context() - |> mint_assets(constants.pool_script_hash, value.to_minted_value( - value.from_lovelace(0) - |> value.add(constants.pool_script_hash, pool_nft_token, -1) - )) - |> add_tx_input(pool_input) - |> add_tx_ref_input(settings_input) - |> add_tx_output(change_output) + let ctx = + interval.between(1, 2) + |> build_txn_context() + |> mint_assets( + constants.pool_script_hash, + value.to_minted_value( + value.from_lovelace(0) + |> value.add(constants.pool_script_hash, pool_nft_token, -1), + ), + ) + |> add_tx_input(pool_input) + |> add_tx_ref_input(settings_input) + |> add_tx_output(change_output) let pool_mint_redeemer = BurnPool(constants.pool_ident) - let result = pool_validator.mint(constants.manage_stake_script_hash, constants.settings_policy_id, pool_mint_redeemer, ctx) + let result = + pool_validator.mint( + constants.manage_stake_script_hash, + constants.settings_policy_id, + pool_mint_redeemer, + ctx, + ) result } diff --git a/validators/tests/settings.ak b/validators/tests/settings.ak index 56286ee..c96fa27 100644 --- a/validators/tests/settings.ak +++ b/validators/tests/settings.ak @@ -1,51 +1,72 @@ use aiken/interval use aiken/transaction.{InlineDatum, NoDatum, OutputReference, TransactionId} -use aiken/transaction/credential.{VerificationKeyCredential, Address, from_script} +use aiken/transaction/credential.{ + Address, VerificationKeyCredential, from_script, +} use aiken/transaction/value +use settings as settings_validator use sundae/multisig -use types/settings.{SettingsDatum, SettingsAdminUpdate, settings_nft_name} +use tests/constants +use tests/examples/ex_settings.{ + example_metadata_admin, example_settings_admin, example_treasury_admin, +} use tx_util/builder.{ - build_txn_context, - add_tx_input, - add_tx_output, - new_tx_output, - new_tx_input, - with_asset_of_tx_input, - add_asset_to_tx_output, - mint_assets + add_asset_to_tx_output, add_tx_input, add_tx_output, build_txn_context, + mint_assets, new_tx_input, new_tx_output, with_asset_of_tx_input, } -use tests/examples/ex_settings.{example_settings_admin, example_metadata_admin, example_treasury_admin} -use settings as settings_validator -use tests/constants +use types/settings.{SettingsAdminUpdate, SettingsDatum, settings_nft_name} fn test_mint_settings(settings_nfts_count: Int) { - let settings_nft = value.to_minted_value(value.from_asset(constants.settings_policy_id, settings_nft_name, settings_nfts_count)) - - let settings_datum = mk_valid_settings_datum([]) // Some([]) for authorized_scoopers means no one can scoop - - let settings_output = new_tx_output( - from_script(constants.settings_policy_id), - 2_000_000, - InlineDatum(settings_datum) - ) |> add_asset_to_tx_output(value.from_asset(constants.settings_policy_id, settings_nft_name, settings_nfts_count)) - - let protocol_boot_utxo = OutputReference { transaction_id: TransactionId { hash: #"00"}, output_index: 0 } + let settings_nft = + value.to_minted_value( + value.from_asset( + constants.settings_policy_id, + settings_nft_name, + settings_nfts_count, + ), + ) + + let settings_datum = mk_valid_settings_datum([]) + + // Some([]) for authorized_scoopers means no one can scoop + let settings_output = + new_tx_output( + from_script(constants.settings_policy_id), + 2_000_000, + InlineDatum(settings_datum), + ) + |> add_asset_to_tx_output( + value.from_asset( + constants.settings_policy_id, + settings_nft_name, + settings_nfts_count, + ), + ) + + let protocol_boot_utxo = + OutputReference { + transaction_id: TransactionId { hash: #"00" }, + output_index: 0, + } let protocol_boot_utxo_policy = #"00" - let protocol_boot_utxo_input = new_tx_input( - protocol_boot_utxo.transaction_id.hash, - from_script(protocol_boot_utxo_policy), - 2_000_000, - NoDatum, - ) |> with_asset_of_tx_input(value.from_asset(protocol_boot_utxo_policy, "boot utxo name", 1)) - let ctx = + let protocol_boot_utxo_input = + new_tx_input( + protocol_boot_utxo.transaction_id.hash, + from_script(protocol_boot_utxo_policy), + 2_000_000, + NoDatum, + ) + |> with_asset_of_tx_input( + value.from_asset(protocol_boot_utxo_policy, "boot utxo name", 1), + ) + let ctx = interval.between(1, 2) |> build_txn_context() |> mint_assets(constants.settings_policy_id, settings_nft) |> add_tx_input(protocol_boot_utxo_input) |> add_tx_output(settings_output) - let minted = settings_validator.mint(protocol_boot_utxo, Void, ctx) minted } @@ -58,9 +79,7 @@ test mint_valid_settings() { test_mint_settings(1) } -fn mk_valid_settings_datum( - scoopers: List, -) -> SettingsDatum { +fn mk_valid_settings_datum(scoopers: List) -> SettingsDatum { SettingsDatum { settings_admin: multisig.Signature(example_settings_admin), metadata_admin: Address( @@ -74,9 +93,7 @@ fn mk_valid_settings_datum( ), treasury_allowance: (1, 10), authorized_scoopers: Some(scoopers), - authorized_staking_keys: [ - VerificationKeyCredential(constants.stake_key), - ], + authorized_staking_keys: [VerificationKeyCredential(constants.stake_key)], base_fee: 0, simple_fee: 2_500_000, strategy_fee: 5_000_000, @@ -87,73 +104,111 @@ fn mk_valid_settings_datum( // Test that we can spend the settings NFT and do a no-op change, except for a new ada lovelace rider value test test_spend_settings_change_ada_rider() { - let first_settings_utxo = OutputReference { transaction_id: TransactionId { hash: #"01"}, output_index: 0 } + let first_settings_utxo = + OutputReference { + transaction_id: TransactionId { hash: #"01" }, + output_index: 0, + } let first_settings_rider = 2_000_000 - let first_settings = new_tx_input( - first_settings_utxo.transaction_id.hash, - from_script(constants.settings_policy_id), - first_settings_rider, - InlineDatum(mk_valid_settings_datum([])), - ) |> with_asset_of_tx_input(value.from_asset(constants.settings_policy_id, settings_nft_name, 1)) - - let protocol_boot_utxo = OutputReference { transaction_id: TransactionId { hash: #"00"}, output_index: 0 } + let first_settings = + new_tx_input( + first_settings_utxo.transaction_id.hash, + from_script(constants.settings_policy_id), + first_settings_rider, + InlineDatum(mk_valid_settings_datum([])), + ) + |> with_asset_of_tx_input( + value.from_asset(constants.settings_policy_id, settings_nft_name, 1), + ) + + let protocol_boot_utxo = + OutputReference { + transaction_id: TransactionId { hash: #"00" }, + output_index: 0, + } let second_settings_datum = mk_valid_settings_datum([]) - let second_settings_redeemer = SettingsAdminUpdate - let second_settings_output = new_tx_output( - from_script(constants.settings_policy_id), - first_settings_rider+1, - InlineDatum(second_settings_datum) - ) |> add_asset_to_tx_output(value.from_asset(constants.settings_policy_id, settings_nft_name, 1)) - let ctx = + let second_settings_output = + new_tx_output( + from_script(constants.settings_policy_id), + first_settings_rider + 1, + InlineDatum(second_settings_datum), + ) + |> add_asset_to_tx_output( + value.from_asset(constants.settings_policy_id, settings_nft_name, 1), + ) + let ctx = interval.between(1, 2) |> build_txn_context() |> add_tx_input(first_settings) |> add_tx_output(second_settings_output) |> builder.add_signatory(example_settings_admin) |> builder.spend(first_settings.output_reference) - - settings_validator.spend(protocol_boot_utxo, second_settings_datum, second_settings_redeemer, ctx) + settings_validator.spend( + protocol_boot_utxo, + second_settings_datum, + second_settings_redeemer, + ctx, + ) } // Test that we can spend the settings NFT and CAN'T change a non-ADA value while changing rider test test_spend_settings_change_value() fail { - let first_settings_utxo = OutputReference { transaction_id: TransactionId { hash: #"01"}, output_index: 0 } + let first_settings_utxo = + OutputReference { + transaction_id: TransactionId { hash: #"01" }, + output_index: 0, + } let first_settings_rider = 2_000_000 - let first_settings = new_tx_input( - first_settings_utxo.transaction_id.hash, - from_script(constants.settings_policy_id), - first_settings_rider, - InlineDatum(mk_valid_settings_datum([])), - ) |> with_asset_of_tx_input(value.from_asset(constants.settings_policy_id, settings_nft_name, 1)) - - let protocol_boot_utxo = OutputReference { transaction_id: TransactionId { hash: #"00"}, output_index: 0 } + let first_settings = + new_tx_input( + first_settings_utxo.transaction_id.hash, + from_script(constants.settings_policy_id), + first_settings_rider, + InlineDatum(mk_valid_settings_datum([])), + ) + |> with_asset_of_tx_input( + value.from_asset(constants.settings_policy_id, settings_nft_name, 1), + ) + + let protocol_boot_utxo = + OutputReference { + transaction_id: TransactionId { hash: #"00" }, + output_index: 0, + } let second_settings_datum = mk_valid_settings_datum([]) - let second_settings_redeemer = SettingsAdminUpdate - let second_settings_output = new_tx_output( - from_script(constants.settings_policy_id), - first_settings_rider+1, - InlineDatum(second_settings_datum) - ) |> add_asset_to_tx_output(value.from_asset(constants.settings_policy_id, settings_nft_name, 1)) + let second_settings_output = + new_tx_output( + from_script(constants.settings_policy_id), + first_settings_rider + 1, + InlineDatum(second_settings_datum), + ) + |> add_asset_to_tx_output( + value.from_asset(constants.settings_policy_id, settings_nft_name, 1), + ) let junk_policy = "junk policy" let junk_name = "junk name" - let junk_utxo = OutputReference { transaction_id: TransactionId { hash: #"99"}, output_index: 0 } - let junk_input = new_tx_input( - junk_utxo.transaction_id.hash, - from_script(junk_policy), - 1, - InlineDatum(Void)) |> with_asset_of_tx_input(value.from_asset(junk_policy, junk_name, 1)) - - let junk_output = new_tx_output( - from_script(junk_policy), - 1, - InlineDatum(Void) - ) |> add_asset_to_tx_output(value.from_asset(junk_policy, junk_name, 1)) - let ctx = + let junk_utxo = + OutputReference { + transaction_id: TransactionId { hash: #"99" }, + output_index: 0, + } + let junk_input = + new_tx_input( + junk_utxo.transaction_id.hash, + from_script(junk_policy), + 1, + InlineDatum(Void), + ) + |> with_asset_of_tx_input(value.from_asset(junk_policy, junk_name, 1)) + let junk_output = + new_tx_output(from_script(junk_policy), 1, InlineDatum(Void)) + |> add_asset_to_tx_output(value.from_asset(junk_policy, junk_name, 1)) + let ctx = interval.between(1, 2) |> build_txn_context() |> add_tx_input(first_settings) @@ -162,7 +217,12 @@ test test_spend_settings_change_value() fail { |> add_tx_output(junk_output) |> builder.add_signatory(example_settings_admin) |> builder.spend(first_settings.output_reference) - - let second_settings = settings_validator.spend(protocol_boot_utxo, second_settings_datum, second_settings_redeemer, ctx) + let second_settings = + settings_validator.spend( + protocol_boot_utxo, + second_settings_datum, + second_settings_redeemer, + ctx, + ) second_settings -} \ No newline at end of file +}