Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use Withdrawal Script for apply order transaction and use LP Minting Policy to validate Pool Creation #8

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions aiken.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@

[[requirements]]
name = "aiken-lang/stdlib"
version = "1.6.0"
version = "1.7.0"
source = "github"

[[packages]]
name = "aiken-lang/stdlib"
version = "1.6.0"
version = "1.7.0"
requirements = []
source = "github"

Expand Down
2 changes: 1 addition & 1 deletion aiken.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ platform = "github"

[[dependencies]]
name = "aiken-lang/stdlib"
version = "1.6.0"
version = "1.7.0"
source = "github"
8 changes: 7 additions & 1 deletion lib/stableswap/pool_utils.ak
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,13 @@ fn do_get_y_converging(

pub fn get_y(i: Int, j: Int, x: Int, xp: List<Int>, amp: Int) -> Int {
let n = list.length(xp)
expect i != j && i >= 0 && j >= 0 && i < n && j < n
expect and {
i != j,
i >= 0,
j >= 0,
i < n,
j < n,
}
let d = get_d(xp, amp)
let ann = amp * n
let (_, s, init_c) =
Expand Down
33 changes: 33 additions & 0 deletions lib/stableswap/pool_validation.ak
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use aiken/dict
use aiken/interval.{Finite, Interval, IntervalBound}
use aiken/transaction.{Input, Output, ValidityRange}
use aiken/transaction/value.{PolicyId}
use stableswap/utils

pub fn validate_batcher_license(
license_input: Input,
validity_range: ValidityRange,
license_policy_id: PolicyId,
maximum_deadline_range: Int,
) -> Bool {
let Input { output: Output { value: license_value, .. }, .. } = license_input
expect [(license_asset_name, license_amount)] =
license_value
|> value.tokens(license_policy_id)
|> dict.to_list()
let license_deadline = utils.bytearray_to_int(license_asset_name)
let Interval {
lower_bound: IntervalBound { bound_type: lower_bound_type, .. },
upper_bound: IntervalBound { bound_type: upper_bound_type, .. },
} = validity_range
expect Finite(start_valid_time_range) = lower_bound_type
expect Finite(end_valid_time_range) = upper_bound_type
// - Only Batcher with valid license token can trigger @ApplyPool redeemer validation.
// - A valid license token is the token with @tokenName (representing for expired milliseconds)
// and must be within the time range from current_time to current_time + maximum_deadline_range
and {
license_amount == 1,
license_deadline >= end_valid_time_range,
license_deadline <= start_valid_time_range + maximum_deadline_range,
}
}
19 changes: 14 additions & 5 deletions lib/stableswap/types.ak
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use aiken/dict.{Dict}
use aiken/hash.{Blake2b_224, Blake2b_256, Hash}
use aiken/transaction/credential.{Address, Script, VerificationKey}
use aiken/transaction/value.{AssetName, PolicyId}
Expand All @@ -16,6 +17,9 @@ pub type ValidatorHash =
pub type PubKeyHash =
Hash<Blake2b_224, VerificationKey>

pub type DatumMap =
Dict<Hash<Blake2b_256, Data>, Data>

pub type OrderStep {
Exchange { asset_in_index: Int, asset_out_index: Int, minimum_asset_out: Int }
Deposit { minimum_lp: Int }
Expand All @@ -40,7 +44,6 @@ pub type OrderRedeemer {

pub type PoolDatum {
balances: List<Int>,
total_liquidity: Int,
amp: Int,
order_hash: ValidatorHash,
}
Expand All @@ -51,14 +54,15 @@ pub type PoolRedeemer {
input_indexes: List<Int>,
license_index: Int,
}
WithdrawAdminFee { admin_index: Int, fee_to_index: Int }
WithdrawAdminFee { admin_index: Int }
UpdateAmpOrStakeCredential { admin_index: Int }
}

pub type PoolParams {
nft_asset: Asset,
lp_asset: Asset,
license_symbol: PolicyId,
lp_policy_id: PolicyId,
nft_asset_name: AssetName,
lp_asset_name: AssetName,
batcher_license_policy_id: PolicyId,
admin_asset: Asset,
maximum_deadline_range: Int,
assets: List<Asset>,
Expand All @@ -67,3 +71,8 @@ pub type PoolParams {
admin_fee: Int,
fee_denominator: Int,
}

pub type OrderBatchingRedeemer {
// it's used for finding Pool Input faster
pool_input_index: Int,
}
178 changes: 169 additions & 9 deletions lib/stableswap/utils.ak
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
use aiken/builtin
use aiken/bytearray
use aiken/cbor
use aiken/dict
use aiken/list
use aiken/string
use aiken/transaction.{Datum, DatumHash, InlineDatum, NoDatum}
use stableswap/types.{DatumMap}

pub const max_lp_supply = 9223372036854775807

const minus_ascii_code = 45

Expand Down Expand Up @@ -65,6 +71,8 @@ test test_bytearray_to_int() {
r1 == 123 && r2 == 111
}

// This function with zip 2 list with @predicate condition
// It expects 2 lists must having the same length, otherwise it will throw error
pub fn zip_with(
arr1: List<a>,
arr2: List<a>,
Expand All @@ -79,8 +87,7 @@ pub fn zip_with(
}
[x, ..xs] ->
when arr2 is {
[] ->
[]
[] -> fail
[y, ..ys] ->
[predicate(x, y), ..zip_with(xs, ys, predicate)]
}
Expand All @@ -97,12 +104,76 @@ test test_zip_with() {
z1 == [5, 7, 9] && z2 == [4, 10, 18]
}

test test_zip_with_throw_err() fail {
test test_zip_with_throw_err_1() fail {
let arr1 =
[1, 2, 3]
let arr2 =
[4, 5, 6, 6]
zip_with(arr1, arr2, fn(a1, a2) { a1 + a2 }) == []
let x = zip_with(arr1, arr2, fn(a1, a2) { a1 + a2 })
trace cbor.diagnostic(x)
True
}

test test_zip_with_throw_err_2() fail {
let arr1 =
[1, 2, 3]
let arr2 =
[4, 5, 6, 6]
let x = zip_with(arr2, arr1, fn(a1, a2) { a1 + a2 })
trace cbor.diagnostic(x)
True
}

// This function with zip 2 list with @predicate condition and initial variable
// It expects 2 lists must having the same length, otherwise it will throw error
pub fn zip_with_zero(
arr1: List<a>,
arr2: List<b>,
zero: c,
predicate: fn(a, b, c) -> c,
) -> c {
when arr1 is {
[] ->
when arr2 is {
[] -> zero
_ -> fail
}
[x, ..xs] ->
when arr2 is {
[] -> fail
[y, ..ys] -> zip_with_zero(xs, ys, predicate(x, y, zero), predicate)
}
}
}

test test_zip_with_zero() {
let arr1 =
[1, 2, 3]
let arr2 =
[4, 5, 6]
let z1 = zip_with_zero(arr1, arr2, 0, fn(a1, a2, c) { c + a1 + a2 })
let z2 = zip_with_zero(arr1, arr2, 1, fn(a1, a2, c) { c * a1 * a2 })
z1 == 21 && z2 == 720
}

test test_zip_with_zero_throw_err_1() fail {
let arr1 =
[1, 2, 3]
let arr2 =
[4, 5, 6, 6]
let x = zip_with_zero(arr1, arr2, 0, fn(a1, a2, c) { c + a1 + a2 })
trace cbor.diagnostic(x)
True
}

test test_zip_with_zero_throw_err_2() fail {
let arr1 =
[1, 2, 3]
let arr2 =
[4, 5, 6, 6]
let x = zip_with_zero(arr2, arr1, 0, fn(a1, a2, c) { c + a1 + a2 })
trace cbor.diagnostic(x)
True
}

pub fn verify_positive_ints(arr: List<Int>) -> Bool {
Expand Down Expand Up @@ -194,11 +265,6 @@ test test_compare_list_with() {
r1 && r2 && !r3 && !not_over_slippage && !r4
}

pub fn must_parse_option(op: Option<a>) -> a {
expect Some(t) = op
t
}

pub fn list_at_index(outputs: List<a>, payout_outputs_offset: Int) -> a {
if payout_outputs_offset >= 5 {
outputs
Expand Down Expand Up @@ -285,3 +351,97 @@ test test_list_at_index_index_higher_length_err() fail {
[0, 1, 2]
list_at_index(arr, 3) == 0
}

pub fn compare_list_length(arr1: List<a>, arr2: List<b>) -> Bool {
when arr1 is {
[] -> arr2 == []
_ ->
when arr2 is {
[] -> False
_ ->
compare_list_length(
arr1 |> builtin.tail_list,
arr2 |> builtin.tail_list,
)
}
}
}

test test_compare_list_length() {
let arr1 =
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]
let arr2 =
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]
compare_list_length(arr1, arr2)
}

test test_compare_list_length_1() {
let arr1 =
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]
let arr2 =
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]
and {
!compare_list_length(arr1, arr2),
!compare_list_length(arr2, arr1),
}
}

test test_compare_list_length_2() {
compare_list_length([], [])
}

test test_compare_list_length_3() {
let arr1 =
[1]
let arr2 =
[]
and {
!compare_list_length(arr1, arr2),
!compare_list_length(arr2, arr1),
}
}

fn contains_element(list: List<a>, elem: a) -> Bool {
when list is {
[] -> False
[x, ..xs] -> elem == x || contains_element(xs, elem)
}
}

pub fn is_list_unique(list: List<a>) -> Bool {
when list is {
[] -> True
[_] -> True
[x, ..xs] -> !contains_element(xs, x) && is_list_unique(xs)
}
}

test test_is_list_unique() {
let arr1 =
[]
let arr2 =
[10]
let arr3 =
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
let arr4 =
[0, 0, 2, 3, 4, 5, 6, 7, 8, 9]
and {
is_list_unique(arr1),
is_list_unique(arr2),
is_list_unique(arr3),
!is_list_unique(arr4),
}
}

pub fn must_find_script_datum(datums: DatumMap, datum: Datum) -> Data {
let datum_opt =
when datum is {
NoDatum -> None
DatumHash(dh) ->
datums
|> dict.get(dh)
InlineDatum(dat) -> Some(dat)
}
expect Some(datum) = datum_opt
datum
}
Loading