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

Adding Kiosk Unit #73

Merged
merged 16 commits into from
Apr 12, 2024
Merged
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ unit-three/example_projects/generics/build/
unit-three/example_projects/locked_coin/build/
unit-four/example_projects/collections/build/
unit-four/example_projects/marketplace/build/
unit-five/example_projects/flashloan/build/
unit-five/example_projects/kiosk/build/
advanced-topics/BCS_encoding/example_projects/bcs_move/build/
advanced-topics/BCS_encoding/example_projects/bcs_js/node_modules/
advanced-topics/closed_loop_token/example_projects/closed_loop_token/build/
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ Introductory course to the Move language maintained by [Sui Foundation](https://
- [Heterogeneous Collections](./unit-four/lessons/3_heterogeneous_collections.md)
- [Marketplace Contract](./unit-four/lessons/4_marketplace_contract.md)
- [Deployment and Testing](./unit-four/lessons/5_deployment_and_testing.md)
- **Unit Five: Sui Kiosk**
- [Programmable Transaction Block](./unit-five/lessons/1_programmable_transaction_block.md)
- [Hot Potato Design Pattern](./unit-five/lessons/2_hot_potato_pattern.md)
- [Sui Kiosk Basic Concepts](./unit-five/lessons/3_kiosk_basics.md)
- [Sui Kiosk Basic Usage](./unit-five/lessons/4_kiosk_basic_usage.md)
- [Transfer Policy](./unit-five/lessons/5_transfer_policy.md)
- **Advanced Topics**
- [BCS Encoding](./advanced-topics/BCS_encoding/lessons/BCS_encoding.md)

Expand Down
27 changes: 27 additions & 0 deletions unit-five/example_projects/flashloan/Move.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# @generated by Move, please check-in and do not edit manually.

[move]
version = 0
manifest_digest = "FC84CCD33DE1E9661DA31B49398152B41FB6772CFBCD634619716A9823846811"
deps_digest = "F8BBB0CCB2491CA29A3DF03D6F92277A4F3574266507ACD77214D37ECA3F3082"

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

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

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

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

[move.toolchain-version]
compiler-version = "1.21.0"
edition = "legacy"
flavor = "sui"
40 changes: 40 additions & 0 deletions unit-five/example_projects/flashloan/Move.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
[package]
name = "flashloan"
version = "0.0.1"

# edition = "2024.alpha" # To use the Move 2024 edition, currently in alpha
# 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" }

# 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]
flashloan = "0x0"
sui = "0x2"

# 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"

93 changes: 93 additions & 0 deletions unit-five/example_projects/flashloan/sources/flashloan.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright (c) Sui Foundation, Inc.
// SPDX-License-Identifier: Apache-2.0

module flashloan::flashloan {
// === Imports ===
use sui::sui::SUI;
use sui::coin::{Self, Coin};
use sui::balance::{Self, Balance};
use sui::object::{Self, UID};
use sui::tx_context::{TxContext};
use sui::transfer::{Self};

// === Errors ===

/// For when the loan amount exceed the pool amount
const ELoanAmountExceedPool: u64 = 0;
/// For when the repay amount do not match the initial loan amount
const ERepayAmountInvalid: u64 = 1;

// === Structs ===

/// A "shared" loan pool.
/// For demonstration purpose, we assume the loan pool only allows SUI.
struct LoanPool has key {
id: UID,
amount: Balance<SUI>,
}

/// A loan position.
/// This is a hot potato struct, it enforces the users
/// to repay the loan in the end of the transaction or within the same PTB.
struct Loan {
amount: u64,
}

/// A dummy NFT to represent the flashloan functionality
struct NFT has key{
id: UID,
price: Balance<SUI>,
}

fun init(ctx: &mut TxContext) {
let pool = LoanPool {
id: object::new(ctx),
amount: balance::zero()
};
transfer::share_object(pool);
}
// === Public-Mutative Functions ===

/// Deposit money into loan pool
public fun deposit_pool(pool: &mut LoanPool, deposit: Coin<SUI>) {
balance::join(&mut pool.amount, coin::into_balance(deposit));
}

/// Function allows users to borrow from the loan pool.
/// It returns the borrowed [`Coin<SUI>`] and the [`Loan`] position
/// enforcing users to fulfill before the PTB ends.
public fun borrow(pool: &mut LoanPool, amount: u64, ctx: &mut TxContext): (Coin<SUI>, Loan) {
assert!(amount <= balance::value(&pool.amount), ELoanAmountExceedPool);

(
coin::from_balance(balance::split(&mut pool.amount, amount), ctx),
Loan {
amount
}
)
}

/// Repay the loan
/// Users must execute this function to ensure the loan is repaid before the transaction ends.
public fun repay(pool: &mut LoanPool, loan: Loan, payment: Coin<SUI>) {
let Loan { amount } = loan;
assert!(coin::value(&payment) == amount, ERepayAmountInvalid);

balance::join(&mut pool.amount, coin::into_balance(payment));
}

/// Mint NFT
public fun mint_nft(payment: Coin<SUI>, ctx: &mut TxContext): NFT {
NFT {
id: object::new(ctx),
price: coin::into_balance(payment),
}
}

/// Sell NFT
public fun sell_nft(nft: NFT, ctx: &mut TxContext): Coin<SUI> {
let NFT {id, price} = nft;
object::delete(id);
coin::from_balance(price, ctx)
}
}
27 changes: 27 additions & 0 deletions unit-five/example_projects/kiosk/Move.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# @generated by Move, please check-in and do not edit manually.

[move]
version = 0
manifest_digest = "1FF626947D27118D75E5892ECC965B6EA5D58EF40C92513A237A9F1A2B5F5DDB"
deps_digest = "F8BBB0CCB2491CA29A3DF03D6F92277A4F3574266507ACD77214D37ECA3F3082"

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

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

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

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

[move.toolchain-version]
compiler-version = "1.21.0"
edition = "legacy"
flavor = "sui"
40 changes: 40 additions & 0 deletions unit-five/example_projects/kiosk/Move.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
[package]
name = "kiosk"
version = "0.0.1"

# edition = "2024.alpha" # To use the Move 2024 edition, currently in alpha
# 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" }

# 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]
kiosk = "0x0"
sui = "0x2"

# 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"

50 changes: 50 additions & 0 deletions unit-five/example_projects/kiosk/sources/dummy_policy.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) Sui Foundation, Inc.
// SPDX-License-Identifier: Apache-2.0

// The code is taken here https://github.com/MystenLabs/apps/blob/main/kiosk/docs/creating_a_rule_guide.md#rule-structure-dummy

module kiosk::dummy_rule {
use sui::coin::Coin;
use sui::sui::SUI;
use sui::transfer_policy::{
Self as policy,
TransferPolicy,
TransferPolicyCap,
TransferRequest
};

/// The Rule Witness; has no fields and is used as a
/// static authorization method for the rule.
struct Rule has drop {}

/// Configuration struct with any fields (as long as it
/// has `drop`). Managed by the Rule module.
struct Config has store, drop {}

/// Function that adds a Rule to the `TransferPolicy`.
/// Requires `TransferPolicyCap` to make sure the rules are
/// added only by the publisher of T.
public fun set<T>(
policy: &mut TransferPolicy<T>,
cap: &TransferPolicyCap<T>
) {
policy::add_rule(Rule {}, policy, cap, Config {})
}

/// Action function - perform a certain action (any, really)
/// and pass in the `TransferRequest` so it gets the Receipt.
/// Receipt is a Rule Witness, so there's no way to create
/// it anywhere else but in this module.
///
/// This example also illustrates that Rules can add Coin<SUI>
/// to the balance of the TransferPolicy allowing creators to
/// collect fees.
public fun pay<T>(
policy: &mut TransferPolicy<T>,
request: &mut TransferRequest<T>,
payment: Coin<SUI>
) {
policy::add_to_balance(Rule {}, policy, payment);
policy::add_receipt(Rule {}, request);
}
}
77 changes: 77 additions & 0 deletions unit-five/example_projects/kiosk/sources/fixed_royalty_rule.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright (c) Sui Foundation, Inc.
// SPDX-License-Identifier: Apache-2.0

// The code is modified from here https://github.com/MystenLabs/apps/blob/main/kiosk/sources/rules/royalty_rule.move

module kiosk::fixed_royalty_rule {
use sui::sui::SUI;
use sui::coin::{Self, Coin};
use sui::transfer_policy::{
Self,
TransferPolicy,
TransferPolicyCap,
TransferRequest
};

/// The `amount_bp` passed is more than 100%.
const EIncorrectArgument: u64 = 0;
/// The `Coin` used for payment is not enough to cover the fee.
const EInsufficientAmount: u64 = 1;

/// Max value for the `amount_bp`.
const MAX_BPS: u16 = 10_000;

/// The Rule Witness to authorize the policy
struct Rule has drop {}

/// Configuration for the Rule
struct Config has store, drop {
/// Percentage of the transfer amount to be paid as royalty fee
amount_bp: u16,
/// This is used as royalty fee if the calculated fee is smaller than `min_amount`
min_amount: u64,
}

/// Function that adds a Rule to the `TransferPolicy`.
/// Requires `TransferPolicyCap` to make sure the rules are
/// added only by the publisher of T.
public fun add<T>(
policy: &mut TransferPolicy<T>,
cap: &TransferPolicyCap<T>,
amount_bp: u16,
min_amount: u64

) {
assert!(amount_bp <= MAX_BPS, EIncorrectArgument);
transfer_policy::add_rule(Rule {}, policy, cap, Config { amount_bp, min_amount })
}

/// Buyer action: Pay the royalty fee for the transfer.
public fun pay<T: key + store>(
policy: &mut TransferPolicy<T>,
request: &mut TransferRequest<T>,
payment: Coin<SUI>
) {
let paid = transfer_policy::paid(request);
let amount = fee_amount(policy, paid);

assert!(coin::value(&payment) == amount, EInsufficientAmount);

transfer_policy::add_to_balance(Rule {}, policy, payment);
transfer_policy::add_receipt(Rule {}, request)
}

/// Helper function to calculate the amount to be paid for the transfer.
/// Can be used dry-runned to estimate the fee amount based on the Kiosk listing price.
public fun fee_amount<T: key + store>(policy: &TransferPolicy<T>, paid: u64): u64 {
let config: &Config = transfer_policy::get_rule(Rule {}, policy);
let amount = (((paid as u128) * (config.amount_bp as u128) / 10_000) as u64);

// If the amount is less than the minimum, use the minimum
if (amount < config.min_amount) {
amount = config.min_amount
};

amount
}
}
Loading
Loading