Skip to content

Commit

Permalink
[sui-framework] Removes NFT module from Sui framework (MystenLabs#1494)
Browse files Browse the repository at this point in the history
* removes NFT module everywhere
  • Loading branch information
damirka authored Apr 20, 2022
1 parent cf53ad5 commit 1f12b3b
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 134 deletions.
7 changes: 4 additions & 3 deletions sui/src/unit_tests/cli_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,13 +205,14 @@ async fn test_cross_chain_airdrop() -> Result<(), anyhow::Error> {
// Claim the airdrop
let token = airdrop_call_move_and_get_created_object(args, gas_object_id, &mut context).await?;

dbg!(&token);

// Verify the airdrop token
assert_eq!(
token["contents"]["type"],
("0x2::NFT::NFT<0x2::CrossChainAirdrop::ERC721>")
("0x2::CrossChainAirdrop::ERC721")
);
let nft_data = &token["contents"]["fields"]["data"];
let erc721_metadata = &nft_data["fields"]["metadata"];
let erc721_metadata = &token["contents"]["fields"]["metadata"];
assert_eq!(
erc721_metadata["fields"]["token_id"]["fields"]["id"],
AIRDROP_SOURCE_TOKEN_ID
Expand Down
35 changes: 18 additions & 17 deletions sui_programmability/examples/nfts/sources/DiscountCoupon.move
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

module NFTs::DiscountCoupon {
use Sui::Coin;
use Sui::NFT::{Self, NFT};
use Sui::SUI::SUI;
use Sui::ID::{Self, VersionedID};
use Sui::SUI::{Self, SUI};
use Sui::Transfer;
use Sui::TxContext::{Self, TxContext};

Expand All @@ -15,7 +15,8 @@ module NFTs::DiscountCoupon {
const EOUT_OF_RANGE_DISCOUNT: u64 = 1;

/// Discount coupon NFT.
struct DiscountCoupon has store {
struct DiscountCoupon has key, store {
id: VersionedID,
// coupon issuer
issuer: address,
// percentage discount [1-100]
Expand All @@ -38,27 +39,27 @@ module NFTs::DiscountCoupon {
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);
let coupon = DiscountCoupon {
id: TxContext::new_id(ctx),
issuer: TxContext::sender(ctx),
discount,
expiration,
};
Transfer::transfer(coupon, recipient);
SUI::transfer(coin, recipient, ctx);
}

/// Burn DiscountCoupon.
public(script) fun burn(nft: NFT<DiscountCoupon>, _ctx: &mut TxContext) {
let DiscountCoupon { issuer: _, discount: _, expiration: _ } = NFT::burn(nft);
public(script) fun burn(nft: DiscountCoupon, _ctx: &mut TxContext) {
let DiscountCoupon { id, issuer: _, discount: _, expiration: _ } = nft;
ID::delete(id);
}

/// 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(script) fun transfer(nft: NFT<DiscountCoupon>, recipient: address, _ctx: &mut TxContext) {
assert!(NFT::data(&nft).issuer == recipient, EWRONG_RECIPIENT);
NFT::transfer(nft, recipient)
public(script) fun transfer(coupon: DiscountCoupon, recipient: address, _ctx: &mut TxContext) {
assert!(&coupon.issuer == &recipient, EWRONG_RECIPIENT);
Transfer::transfer(coupon, recipient);
}
}
62 changes: 35 additions & 27 deletions sui_programmability/examples/nfts/sources/Marketplace.move
Original file line number Diff line number Diff line change
Expand Up @@ -130,17 +130,19 @@ module NFTs::Marketplace {

#[test_only]
module NFTs::MarketplaceTests {
use Sui::ID::{Self, VersionedID};
use Sui::Bag::Bag;
use Sui::Transfer;
use Sui::NFT::{Self, NFT};
use Sui::Coin::{Self, Coin};
use Sui::SUI::SUI;
use Sui::TxContext;
use Sui::TestScenario::{Self, Scenario};
use NFTs::Marketplace::{Self, Marketplace, Listing};

// Simple KITTY-NFT data structure.
struct KITTY has store, drop {
id: u8
// Simple Kitty-NFT data structure.
struct Kitty has key, store {
id: VersionedID,
kitty_id: u8
}

const ADMIN: address = @0xA55;
Expand All @@ -160,21 +162,21 @@ module NFTs::MarketplaceTests {
Transfer::transfer(coin, BUYER);
}

/// Mint KITTY NFT and send it to SELLER.
/// Mint Kitty NFT and send it to SELLER.
fun mint_kitty(scenario: &mut Scenario) {
TestScenario::next_tx(scenario, &ADMIN);
let nft = NFT::mint(KITTY { id: 1 }, TestScenario::ctx(scenario));
NFT::transfer(nft, SELLER);
let nft = Kitty { id: TxContext::new_id(TestScenario::ctx(scenario)), kitty_id: 1 };
Transfer::transfer(nft, SELLER);
}

// SELLER lists KITTY at the Marketplace for 100 SUI.
// SELLER lists Kitty at the Marketplace for 100 SUI.
public(script) fun list_kitty(scenario: &mut Scenario) {
TestScenario::next_tx(scenario, &SELLER);
let mkp = TestScenario::take_object<Marketplace>(scenario);
let bag = TestScenario::take_nested_object<Marketplace, Bag>(scenario, &mkp);
let nft = TestScenario::take_object<NFT<KITTY>>(scenario);
let nft = TestScenario::take_object<Kitty>(scenario);

Marketplace::list<NFT<KITTY>, SUI>(&mkp, &mut bag, nft, 100, TestScenario::ctx(scenario));
Marketplace::list<Kitty, SUI>(&mkp, &mut bag, nft, 100, TestScenario::ctx(scenario));
TestScenario::return_object(scenario, mkp);
TestScenario::return_object(scenario, bag);
}
Expand All @@ -191,13 +193,13 @@ module NFTs::MarketplaceTests {
{
let mkp = TestScenario::take_object<Marketplace>(scenario);
let bag = TestScenario::take_nested_object<Marketplace, Bag>(scenario, &mkp);
let listing = TestScenario::take_nested_object<Bag, Listing<NFT<KITTY>, SUI>>(scenario, &bag);
let listing = TestScenario::take_nested_object<Bag, Listing<Kitty, SUI>>(scenario, &bag);

// Do the delist operation on a Marketplace.
let nft = Marketplace::delist<NFT<KITTY>, SUI>(&mkp, &mut bag, listing, TestScenario::ctx(scenario));
let kitten = NFT::burn<KITTY>(nft);
let nft = Marketplace::delist<Kitty, SUI>(&mkp, &mut bag, listing, TestScenario::ctx(scenario));
let kitty_id = burn_kitty(nft);

assert!(kitten.id == 1, 0);
assert!(kitty_id == 1, 0);

TestScenario::return_object(scenario, mkp);
TestScenario::return_object(scenario, bag);
Expand All @@ -214,16 +216,16 @@ module NFTs::MarketplaceTests {
mint_kitty(scenario);
list_kitty(scenario);

// BUYER attempts to delist KITTY and he has no right to do so. :(
// BUYER attempts to delist Kitty and he has no right to do so. :(
TestScenario::next_tx(scenario, &BUYER);
{
let mkp = TestScenario::take_object<Marketplace>(scenario);
let bag = TestScenario::take_nested_object<Marketplace, Bag>(scenario, &mkp);
let listing = TestScenario::take_nested_object<Bag, Listing<NFT<KITTY>, SUI>>(scenario, &bag);
let listing = TestScenario::take_nested_object<Bag, Listing<Kitty, SUI>>(scenario, &bag);

// Do the delist operation on a Marketplace.
let nft = Marketplace::delist<NFT<KITTY>, SUI>(&mkp, &mut bag, listing, TestScenario::ctx(scenario));
let _ = NFT::burn<KITTY>(nft);
let nft = Marketplace::delist<Kitty, SUI>(&mkp, &mut bag, listing, TestScenario::ctx(scenario));
let _ = burn_kitty(nft);

TestScenario::return_object(scenario, mkp);
TestScenario::return_object(scenario, bag);
Expand All @@ -239,20 +241,20 @@ module NFTs::MarketplaceTests {
mint_kitty(scenario);
list_kitty(scenario);

// BUYER takes 100 SUI from his wallet and purchases KITTY.
// BUYER takes 100 SUI from his wallet and purchases Kitty.
TestScenario::next_tx(scenario, &BUYER);
{
let coin = TestScenario::take_object<Coin<SUI>>(scenario);
let mkp = TestScenario::take_object<Marketplace>(scenario);
let bag = TestScenario::take_nested_object<Marketplace, Bag>(scenario, &mkp);
let listing = TestScenario::take_nested_object<Bag, Listing<NFT<KITTY>, SUI>>(scenario, &bag);
let listing = TestScenario::take_nested_object<Bag, Listing<Kitty, SUI>>(scenario, &bag);
let payment = Coin::withdraw(&mut coin, 100, TestScenario::ctx(scenario));

// Do the buy call and expect successful purchase.
let nft = Marketplace::buy<NFT<KITTY>, SUI>(&mut bag, listing, payment);
let kitten = NFT::burn<KITTY>(nft);
let nft = Marketplace::buy<Kitty, SUI>(&mut bag, listing, payment);
let kitty_id = burn_kitty(nft);

assert!(kitten.id == 1, 0);
assert!(kitty_id == 1, 0);

TestScenario::return_object(scenario, mkp);
TestScenario::return_object(scenario, bag);
Expand All @@ -270,24 +272,30 @@ module NFTs::MarketplaceTests {
mint_kitty(scenario);
list_kitty(scenario);

// BUYER takes 100 SUI from his wallet and purchases KITTY.
// BUYER takes 100 SUI from his wallet and purchases Kitty.
TestScenario::next_tx(scenario, &BUYER);
{
let coin = TestScenario::take_object<Coin<SUI>>(scenario);
let mkp = TestScenario::take_object<Marketplace>(scenario);
let bag = TestScenario::take_nested_object<Marketplace, Bag>(scenario, &mkp);
let listing = TestScenario::take_nested_object<Bag, Listing<NFT<KITTY>, SUI>>(scenario, &bag);
let listing = TestScenario::take_nested_object<Bag, Listing<Kitty, SUI>>(scenario, &bag);

// AMOUNT here is 10 while expected is 100.
let payment = Coin::withdraw(&mut coin, 10, TestScenario::ctx(scenario));

// Attempt to buy and expect failure purchase.
let nft = Marketplace::buy<NFT<KITTY>, SUI>(&mut bag, listing, payment);
let _ = NFT::burn<KITTY>(nft);
let nft = Marketplace::buy<Kitty, SUI>(&mut bag, listing, payment);
let _ = burn_kitty(nft);

TestScenario::return_object(scenario, mkp);
TestScenario::return_object(scenario, bag);
TestScenario::return_object(scenario, coin);
};
}

fun burn_kitty(kitty: Kitty): u8 {
let Kitty{ id, kitty_id } = kitty;
ID::delete(id);
kitty_id
}
}
15 changes: 8 additions & 7 deletions sui_programmability/examples/nfts/sources/Num.move
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
// SPDX-License-Identifier: Apache-2.0

module NFTs::Num {
use Sui::ID::VersionedID;
use Sui::NFT::{Self, NFT};
use Sui::ID::{Self, VersionedID};
use Sui::Transfer;
use Sui::TxContext::{Self, TxContext};

/// Very silly NFT: a natural number!
struct Num has store {
struct Num has key, store {
id: VersionedID,
n: u64
}

Expand Down Expand Up @@ -39,21 +39,22 @@ module NFTs::Num {
}

/// Create a new `Num` NFT. Aborts if `MAX_SUPPLY` NFT's have already been issued
public fun mint(cap: &mut NumIssuerCap, ctx: &mut TxContext): NFT<Num> {
public fun mint(cap: &mut NumIssuerCap, ctx: &mut TxContext): Num {
let n = cap.issued_counter;
cap.issued_counter = n + 1;
cap.supply = cap.supply + 1;
assert!(n <= MAX_SUPPLY, ETOO_MANY_NUMS);
NFT::mint(Num { n }, ctx)
Num { id: TxContext::new_id(ctx), n }
}

/// Burn `nft`. This reduces the supply.
/// Note: if we burn (e.g.) the NFT<Num> for 7, that means
/// no Num with the value 7 can exist again! But if the supply
/// is maxed out, burning will allow us to mint new Num's with
/// higher values.
public fun burn(cap: &mut NumIssuerCap, nft: NFT<Num>) {
let Num { n: _ } = NFT::burn(nft);
public fun burn(cap: &mut NumIssuerCap, nft: Num) {
let Num { id, n: _ } = nft;
cap.supply = cap.supply - 1;
ID::delete(id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
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;
Expand Down Expand Up @@ -41,9 +40,9 @@ module NFTs::DiscountCouponTests {

TestScenario::next_tx(scenario, &USER1_ADDRESS);
{
assert!(TestScenario::can_take_object<NFT<DiscountCoupon>>(scenario), 0);
let nft_coupon = TestScenario::take_object<NFT<DiscountCoupon>>(scenario); // if can remove, object exists
assert!(DiscountCoupon::issuer(NFT::data(&nft_coupon)) == ISSUER_ADDRESS, 0);
assert!(TestScenario::can_take_object<DiscountCoupon>(scenario), 0);
let nft_coupon = TestScenario::take_object<DiscountCoupon>(scenario); // if can remove, object exists
assert!(DiscountCoupon::issuer(&nft_coupon) == ISSUER_ADDRESS, 0);
TestScenario::return_object(scenario, nft_coupon);
}
}
Expand Down
16 changes: 7 additions & 9 deletions sui_programmability/framework/sources/CrossChainAirdrop.move
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ module Sui::CrossChainAirdrop {
use Std::Vector;
use Sui::ERC721Metadata::{Self, ERC721Metadata, TokenID};
use Sui::ID::{VersionedID};
use Sui::NFT;
use Sui::Transfer;
use Sui::TxContext::{Self, TxContext};

Expand Down Expand Up @@ -39,7 +38,8 @@ module Sui::CrossChainAirdrop {
}

/// The Sui representation of the original ERC721 NFT on Eth
struct ERC721 has store {
struct ERC721 has key, store {
id: VersionedID,
/// The address of the source contract, e.g, the Ethereum contract address
source_contract_address: SourceContractAddress,
/// The metadata associated with this NFT
Expand Down Expand Up @@ -76,13 +76,11 @@ module Sui::CrossChainAirdrop {
let token_id = ERC721Metadata::new_token_id(source_token_id);
// NOTE: this is where the globally uniqueness check happens
assert!(!is_token_claimed(contract, &token_id), ETOKEN_ID_CLAIMED);
let nft = NFT::mint(
ERC721 {
source_contract_address: SourceContractAddress { address: source_contract_address },
metadata: ERC721Metadata::new(token_id, name, token_uri),
},
ctx
);
let nft = ERC721 {
id: TxContext::new_id(ctx),
source_contract_address: SourceContractAddress { address: source_contract_address },
metadata: ERC721Metadata::new(token_id, name, token_uri),
};
Vector::push_back(&mut contract.claimed_source_token_ids, token_id);
Transfer::transfer(nft, recipient)
}
Expand Down
Loading

0 comments on commit 1f12b3b

Please sign in to comment.