Skip to content

Commit

Permalink
task 5 by cryptoctl
Browse files Browse the repository at this point in the history
chin xyz
  • Loading branch information
cryptoctl committed Nov 24, 2024
1 parent f741f14 commit 13497f3
Show file tree
Hide file tree
Showing 7 changed files with 399 additions and 4 deletions.
2 changes: 1 addition & 1 deletion mover/cryptoctl/code/task2/Move.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-fram
# mainnet
task2 = "0x595755e12a700673fd174e05eac9a6e22cfb5d202de027d5830c256bd20d5b3a"
# testnet
# task2 = "0x260cf370e2f907c25e21cdf2b285224a88b3b839f74fb3b25fa3e0fb063f14bd"
#task2 = "0x260cf370e2f907c25e21cdf2b285224a88b3b839f74fb3b25fa3e0fb063f14bd"

# Named addresses will be accessible in Move as `@name`. They're also exported:
# for example, `std = "0x1"` is exported by the Standard Library.
Expand Down
49 changes: 49 additions & 0 deletions mover/cryptoctl/code/task5/Move.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# @generated by Move, please check-in and do not edit manually.

[move]
version = 3
manifest_digest = "78A06328FAC15603CECC783B0829EA43C3927F4B977E8A244F71485E1BC7B312"
deps_digest = "3C4103934B1E040BB6B23F1D610B4EF9F2F1166A50A104EADCF77467C004C600"
dependencies = [
{ id = "Sui", name = "Sui" },
{ id = "task2", name = "task2" },
]

[[move.package]]
id = "MoveStdlib"
source = { git = "https://github.com/MystenLabs/sui.git", rev = "framework/testnet", subdir = "crates\\sui-framework\\packages\\move-stdlib" }

[[move.package]]
id = "Sui"
source = { git = "https://github.com/MystenLabs/sui.git", rev = "framework/testnet", subdir = "crates/sui-framework/packages/sui-framework" }

dependencies = [
{ id = "MoveStdlib", name = "MoveStdlib" },
]

[[move.package]]
id = "task2"
source = { local = "..\\task2" }

dependencies = [
{ id = "Sui", name = "Sui" },
]

[move.toolchain-version]
compiler-version = "1.37.2"
edition = "2024.beta"
flavor = "sui"

[env]

[env.testnet]
chain-id = "4c78adac"
original-published-id = "0xea3ff702e517d12afa3e8bfd0b3edb5074a567b278854dddfbd4147cdae69b7f"
latest-published-id = "0xea3ff702e517d12afa3e8bfd0b3edb5074a567b278854dddfbd4147cdae69b7f"
published-version = "1"

[env.mainnet]
chain-id = "35834a8a"
original-published-id = "0x298b0a658fd4bffd431f73e54fb5737054d41ea6132e41ca084ffc8d472c13bf"
latest-published-id = "0x298b0a658fd4bffd431f73e54fb5737054d41ea6132e41ca084ffc8d472c13bf"
published-version = "1"
38 changes: 38 additions & 0 deletions mover/cryptoctl/code/task5/Move.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
[package]
name = "cryptoctl"
edition = "2024.beta" # edition = "legacy" to use legacy (pre-2024) Move
# license = "" # e.g., "MIT", "GPL", "Apache 2.0"
# authors = ["..."] # e.g., ["Joe Smith ([email protected])", "John Snow ([email protected])"]

[dependencies]
Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "framework/testnet" }
task2 = { local="../task2" }

# For remote import, use the `{ git = "...", subdir = "...", rev = "..." }`.
# Revision can be a branch, a tag, and a commit hash.
# MyRemotePackage = { git = "https://some.remote/host.git", subdir = "remote/path", rev = "main" }

# For local dependencies use `local = path`. Path is relative to the package root
# Local = { local = "../path/to" }

# To resolve a version conflict and force a specific version for dependency
# override use `override = true`
# Override = { local = "../conflicting/version", override = true }

[addresses]
cryptoctl = "0x0"

# Named addresses will be accessible in Move as `@name`. They're also exported:
# for example, `std = "0x1"` is exported by the Standard Library.
# alice = "0xA11CE"

[dev-dependencies]
# The dev-dependencies section allows overriding dependencies for `--test` and
# `--dev` modes. You can introduce test-only dependencies here.
# Local = { local = "../path/to/dev-build" }

[dev-addresses]
# The dev-addresses section allows overwriting named addresses for the `--test`
# and `--dev` modes.
# alice = "0xB0B"

280 changes: 280 additions & 0 deletions mover/cryptoctl/code/task5/sources/cryptoctl.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,280 @@
/*
/// Module: task5
*/
module cryptoctl::swap;
use std::u64::sqrt;
use std::u64::min as u64Min;
use sui::coin;
use sui::coin::{Coin};
use sui::balance;
use sui::balance::{Supply, Balance};

/// For when supplied Coin is zero.
const EZeroAmount: u64 = 0;

/// For when someone tries to swap in an empty pool.
const EReservesEmpty: u64 = 2;

/// For when someone attempts to add more liquidity than u128 Math allows.
const EPoolFull: u64 = 4;

/// The integer scaling setting for fees calculation.
const FEE_SCALING: u128 = 10000;

/// The fee percent that will be taken from the swap.
/// Set to 0.3%.
const FEE_PERCENT: u128 = 30;

/// The max value that can be held in one of the Balances of
/// a Pool. U64 MAX / FEE_SCALING
const MAX_POOL_VALUE: u64 = {
18446744073709551615 / 10000
};

/// The Pool token that will be used to mark the pool share
/// of a liquidity provider.
/// The first type parameter stands for the witness type of a pool.
/// The seconds and thirds is for the coin held in the pool.
public struct LSP<phantom TA, phantom TB> has drop {}


public struct Pool<phantom TA, phantom TB> has key {
id: UID,
token_a: Balance<TA>,
token_b: Balance<TB>,
lsp_supply: Supply<LSP<TA, TB>>,
fee_percent: u64
}


/// Module initializer is empty - to publish a new Pool one has
/// to create a type which will mark LSPs.
fun init(_: &mut TxContext) {

}

entry fun create_pool<TA, TB> (
token_a: Coin<TA>,
token_b: Coin<TB>,
ctx: &mut TxContext
) {

let fee_percent = (FEE_PERCENT as u64);

let token_a_amt = token_a.value();
let token_b_amt = token_b.value();

assert!(token_a_amt > 0 && token_b_amt > 0, EZeroAmount);
assert!(token_a_amt < MAX_POOL_VALUE && token_b_amt < MAX_POOL_VALUE, EPoolFull);

let share = sqrt(token_a_amt) * sqrt(token_b_amt);
let mut lsp_supply = balance::create_supply(LSP<TA, TB> {});

//let lsp = balance::increase_supply(&mut lsp_supply, share);
let lsp = lsp_supply.increase_supply(share);

transfer::share_object(Pool {
id: object::new(ctx),
token_a: coin::into_balance(token_a),
token_b: coin::into_balance(token_b),
lsp_supply,
fee_percent,
});

transfer::public_transfer(
coin::from_balance(lsp, ctx),
tx_context::sender(ctx)
);
}


entry fun add_liquidity<TA, TB> (
pool: &mut Pool<TA, TB>,
token_a: Coin<TA>,
token_b: Coin<TB>,
ctx: &mut TxContext
) {
assert!(token_a.value() > 0 && token_b.value() > 0, EZeroAmount);

let (token_a_amt, token_b_amt, lsp_supply) = get_amounts(pool);
assert!(token_a_amt > 0 && token_b_amt > 0, EReservesEmpty);

let token_a_balance = coin::into_balance(token_a);
let token_b_balance = coin::into_balance(token_b);

let token_a_added = token_a_balance.value();
let token_b_added = token_b_balance.value();

// XXX - 可以对新增的流动性进行计算,查看比值是否和原来的比值一致
// assert!(token_a_added * token_b_amt == token_b_added * token_a_amt, EWrongFee);
// assert!(math::abs_diff(token_a_added * token_b_amt, token_b_added * token_a_amt) < 100, EWrongFee);

let share_minted = u64Min(
(token_a_added * lsp_supply) / token_a_amt,
(token_b_added * lsp_supply) / token_b_amt
);

let token_a_amt = pool.token_a.join(token_a_balance);
let token_b_amt = pool.token_b.join(token_b_balance);

assert!(token_a_amt < MAX_POOL_VALUE && token_b_amt < MAX_POOL_VALUE, EPoolFull);

let balance = pool.lsp_supply.increase_supply(share_minted);

transfer::public_transfer(
coin::from_balance(balance, ctx),
tx_context::sender(ctx)
)
}


entry fun remove_liquidity<TA, TB> (
pool: &mut Pool<TA, TB>,
lsp: Coin<LSP<TA, TB>>,
ctx: &mut TxContext
) {
let (token_a, token_b) = remove_liquidity_inner(pool, lsp, ctx);
let sender = tx_context::sender(ctx);

transfer::public_transfer(token_a, sender);
transfer::public_transfer(token_b, sender);
}

fun remove_liquidity_inner<TA, TB> (
pool: &mut Pool<TA, TB>,
lsp: Coin<LSP<TA, TB>>,
ctx: &mut TxContext
): (Coin<TA>, Coin<TB>) {
let lsp_amount = lsp.value();
assert!(lsp_amount > 0, EZeroAmount);

let (token_a_amt, token_b_amt, total_supply) = get_amounts(pool);

let token_a = (token_a_amt * lsp_amount) / total_supply;
let token_b = (token_b_amt * lsp_amount) / total_supply;

pool.lsp_supply.decrease_supply(coin::into_balance(lsp));

(
coin::take(&mut pool.token_a, token_a, ctx),
coin::take(&mut pool.token_b, token_b, ctx),
)
}

entry fun swap_a_to_b<TA, TB> (pool: &mut Pool<TA, TB>, token_a: Coin<TA>, ctx: &mut TxContext) {

transfer::public_transfer(
swap_a_to_b_inner(pool, token_a, ctx),
tx_context::sender(ctx)
)
}

fun swap_a_to_b_inner<TA, TB> (
pool: &mut Pool<TA, TB>,
token_a: Coin<TA>,
ctx: &mut TxContext
): Coin<TB> {
let token_a_amt = token_a.value();
assert!(token_a_amt > 0, EZeroAmount);

let (token_a_amt, token_b_amt, _) = get_amounts(pool);
assert!(token_a_amt > 0 && token_b_amt > 0, EReservesEmpty);

let token_b_amt = sell_token_a(pool, token_a_amt);

pool.token_a.join(coin::into_balance(token_a));

coin::take(&mut pool.token_b, token_b_amt, ctx)
}

entry fun swap_b_to_a<TA, TB> (
pool: &mut Pool<TA, TB>,
token_b: Coin<TB>,
ctx: &mut TxContext
) {
transfer::public_transfer(
swap_b_to_a_inner(pool, token_b, ctx),
tx_context::sender(ctx)
)
}

fun swap_b_to_a_inner<TA, TB> (
pool: &mut Pool<TA, TB>,
token_b: Coin<TB>,
ctx: &mut TxContext
): Coin<TA> {
let token_b_amt = token_b.value();
assert!(token_b_amt > 0, EZeroAmount);

let (token_a_amt, token_b_amt, _) = get_amounts(pool);
assert!(token_a_amt > 0 && token_b_amt > 0, EReservesEmpty);

let token_a_amt = sell_token_b(pool, token_b_amt);

pool.token_b.join(coin::into_balance(token_b));

coin::take(&mut pool.token_a, token_a_amt, ctx)
}

/// 计算售出指定数量的 Token A,会得到多少数量的 Token B
public fun sell_token_a<TA, TB>(pool: &Pool<TA, TB>, to_sell: u64): u64 {
let (token_a_amt, token_b_amt, _) = get_amounts(pool);
calc_output_amount(
to_sell,
token_a_amt,
token_b_amt,
pool.fee_percent
)
}

/// 计算售出指定数量的 Token B,会得到多少数量的 Token A
public fun sell_token_b<TA, TB>(pool: &Pool<TA, TB>, to_sell: u64): u64 {
let (token_a_amt, token_b_amt, _) = get_amounts(pool);
calc_output_amount(
to_sell,
token_b_amt,
token_a_amt,
pool.fee_percent
)
}

/// Get most used values in a handy way:
/// - amount of token a
/// - amount of token b
/// - total supply of LSP
public fun get_amounts<TA, TB>(pool: &Pool<TA, TB>): (u64, u64, u64) {
(
pool.token_a.value(),
pool.token_b.value(),
balance::supply_value(&pool.lsp_supply),
)
}

public fun calc_output_amount(
input_amount: u64,
input_reserve: u64,
output_reserve: u64,
fee_percent: u64
): u64 {
let (
input_amount,
input_reserve,
output_reserve,
fee_percent
) = (
(input_amount as u128),
(input_reserve as u128),
(output_reserve as u128),
(fee_percent as u128),
);

// 计算手续费后的输入数量
let input_with_fee = input_amount * FEE_SCALING / (FEE_SCALING - fee_percent);

// 根据公式 (x + dx) * (y - dy) = k
// 得到 dy = y - k / (x + dx)
let total = input_reserve * output_reserve;
let output_amount = output_reserve - total / (input_reserve + input_with_fee);

(output_amount as u64)
}
18 changes: 18 additions & 0 deletions mover/cryptoctl/code/task5/tests/task5_tests.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
#[test_only]
module task5::task5_tests;
// uncomment this line to import the module
// use task5::task5;
const ENotImplemented: u64 = 0;
#[test]
fun test_task5() {
// pass
}
#[test, expected_failure(abort_code = ::task5::task5_tests::ENotImplemented)]
fun test_task5_fail() {
abort ENotImplemented
}
*/
Loading

0 comments on commit 13497f3

Please sign in to comment.