Skip to content

Commit

Permalink
Merge pull request #73 from sui-foundation/daniel/adding-kiosk-basics
Browse files Browse the repository at this point in the history
Adding Kiosk Unit
  • Loading branch information
hyd628 authored Apr 12, 2024
2 parents a4a5f19 + 5aca07f commit 6e48467
Show file tree
Hide file tree
Showing 16 changed files with 923 additions and 0 deletions.
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

0 comments on commit 6e48467

Please sign in to comment.