Skip to content

Commit

Permalink
[move] Add DiscountCoupon example (MystenLabs#1222)
Browse files Browse the repository at this point in the history
  • Loading branch information
kchalkias authored Apr 5, 2022
1 parent d463746 commit 2e10bbc
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 0 deletions.
64 changes: 64 additions & 0 deletions sui_programmability/examples/nfts/sources/DiscountCoupon.move
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 sui_programmability/examples/nfts/tests/DiscountCouponTests.move
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);
}
}
}

0 comments on commit 2e10bbc

Please sign in to comment.