forked from MystenLabs/sui
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[move] Add DiscountCoupon example (MystenLabs#1222)
- Loading branch information
Showing
2 changed files
with
114 additions
and
0 deletions.
There are no files selected for viewing
64 changes: 64 additions & 0 deletions
64
sui_programmability/examples/nfts/sources/DiscountCoupon.move
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
// Copyright (c) 2022, Mysten Labs, Inc. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
module NFTs::DiscountCoupon { | ||
use Sui::Coin; | ||
use Sui::NFT::{Self, NFT}; | ||
use Sui::SUI::SUI; | ||
use Sui::Transfer; | ||
use Sui::TxContext::{Self, TxContext}; | ||
|
||
/// Sending to wrong recipient. | ||
const EWRONG_RECIPIENT: u64 = 0; | ||
|
||
/// Percentage discount out of range. | ||
const EOUT_OF_RANGE_DISCOUNT: u64 = 1; | ||
|
||
/// Discount coupon NFT. | ||
struct DiscountCoupon has store { | ||
// coupon issuer | ||
issuer: address, | ||
// percentage discount [1-100] | ||
discount: u8, | ||
// expiration timestamp (UNIX time) - app specific | ||
expiration: u64, | ||
} | ||
|
||
/// Simple issuer getter. | ||
public fun issuer(coupon: &DiscountCoupon): address { | ||
coupon.issuer | ||
} | ||
|
||
/// Mint then transfer a new `DiscountCoupon` NFT, and top up recipient with some SUI. | ||
public fun mint_and_topup( | ||
coin: Coin::Coin<SUI>, | ||
discount: u8, | ||
expiration: u64, | ||
recipient: address, | ||
ctx: &mut TxContext, | ||
) { | ||
assert!(discount > 0 && discount <= 100, EOUT_OF_RANGE_DISCOUNT); | ||
let nft = NFT::mint( | ||
DiscountCoupon { | ||
issuer: TxContext::sender(ctx), | ||
discount, | ||
expiration, | ||
}, | ||
ctx); | ||
Transfer::transfer(nft, recipient); | ||
Sui::SUI::transfer(coin, recipient, ctx); | ||
} | ||
|
||
/// Burn DiscountCoupon. | ||
public fun burn(nft: NFT<DiscountCoupon>, _ctx: &mut TxContext) { | ||
let DiscountCoupon { issuer: _, discount: _, expiration: _ } = NFT::burn(nft); | ||
} | ||
|
||
/// Transfer DiscountCoupon to issuer only. | ||
// TODO: Consider adding more valid recipients. | ||
// If we stick with issuer-as-receiver only, then `recipient` input won't be required). | ||
public fun transfer(nft: NFT<DiscountCoupon>, recipient: address, _ctx: &mut TxContext) { | ||
assert!(NFT::data(&nft).issuer == recipient, EWRONG_RECIPIENT); | ||
NFT::transfer(nft, recipient) | ||
} | ||
} |
50 changes: 50 additions & 0 deletions
50
sui_programmability/examples/nfts/tests/DiscountCouponTests.move
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
// Copyright (c) 2022, Mysten Labs, Inc. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
#[test_only] | ||
module NFTs::DiscountCouponTests { | ||
use NFTs::DiscountCoupon::{Self, DiscountCoupon}; | ||
use Sui::Coin::{Self, Coin}; | ||
use Sui::NFT::{Self, NFT}; | ||
use Sui::SUI::SUI; | ||
use Sui::TestScenario::Self; | ||
use Sui::TxContext::TxContext; | ||
|
||
const ISSUER_ADDRESS: address = @0xA001; | ||
const USER1_ADDRESS: address = @0xB001; | ||
|
||
// Error codes. | ||
// const MINT_FAILED: u64 = 0; | ||
// const TRANSFER_FAILED: u64 = 1; | ||
|
||
// Initializes the "state of the world" that mimics what should | ||
// be available in Sui genesis state (e.g., mints and distributes | ||
// coins to users). | ||
fun init(ctx: &mut TxContext) { | ||
let coin = Coin::mint_for_testing(100, ctx); | ||
Coin::transfer<SUI>(coin, ISSUER_ADDRESS); | ||
} | ||
|
||
#[test] | ||
public fun test_mint_then_transfer() { | ||
let scenario = &mut TestScenario::begin(&ISSUER_ADDRESS); | ||
{ | ||
init(TestScenario::ctx(scenario)); | ||
}; | ||
|
||
// Mint and transfer NFT + top up recipient's address. | ||
TestScenario::next_tx(scenario, &ISSUER_ADDRESS); | ||
{ | ||
let coin = TestScenario::remove_object<Coin<SUI>>(scenario); | ||
DiscountCoupon::mint_and_topup(coin, 10, 1648820870, USER1_ADDRESS, TestScenario::ctx(scenario)); | ||
}; | ||
|
||
TestScenario::next_tx(scenario, &USER1_ADDRESS); | ||
{ | ||
assert!(TestScenario::can_remove_object<NFT<DiscountCoupon>>(scenario), 0); | ||
let nft_coupon = TestScenario::remove_object<NFT<DiscountCoupon>>(scenario); // if can remove, object exists | ||
assert!(DiscountCoupon::issuer(NFT::data(&nft_coupon)) == ISSUER_ADDRESS, 0); | ||
TestScenario::return_object(scenario, nft_coupon); | ||
} | ||
} | ||
} |