NFT를 커피로 전환하기

타이페이 스마트시티 서밋 및 엑스포에서 진행된 시연에서는 대체 불가능한 토큰을 사용해 커피 한 잔을 구매하는 시스템을 선보였습니다.

NFT를 커피로 전환하기

2023년 3월 28일부터 31일까지 진행된 타이베이 스마트시티 서밋 및 엑스포에서 참석자들은 NFT를 신선한 커피 한 잔으로 교환했습니다. 이 교환을 가능하게 하는 시스템은 Sui 재단이 MomentXSuia와 함께 만든 것으로, Sui 에서 NFT를 상품이나 서비스로 교환할 수 있는 방법을 보여줍니다.

실제로 엑스포 참가자들은 가상의 AI 어시스턴트와 채팅을 시작했고, 어시스턴트는 참가자에게 커피 한 잔을 원하는지 물었습니다. 참석자가 '예'라고 대답하면 어시스턴트는 QR 코드를 제시했습니다. 스캔이 완료되면 시스템은 참석자를 위한 새 지갑과 NFT를 생성했습니다. 해당 NFT는 근처 커피 매점으로 가져가 커피 한 잔으로 교환할 수 있었습니다.

엑스포의 스마트 시티 커피숍 사진
타이페이 스마트시티 서밋 및 엑스포에 있는 이 커피숍은 상환 가능한 NFT를 결제 수단으로 허용했습니다.

가장 중요한 것은 참석자가 커피를 받았을 때 시스템이 Sui 네트워크로 또 다른 트랜잭션을 전송하여 NFT의 상태를 미사용에서 사용으로 변경했다는 것입니다.

물체를 커피로 바꾸기

Sui 에서 모든 NFT는 실제로는 객체에 불과하지만 객체는 강력합니다. 이 예시에서 객체 코드의 URL은 이미지를 가리킵니다. 해당 URL은 NFT의 상환 여부에 따라 변경됩니다. 아래 코드는 CoffeeNFT 객체를 보여줍니다.

struct CoffeeNFT has key, store {
		id: UID,
		name: String,
		description: String,
		url: String,
		redeemed: bool,
	}

이 코드는 Sui 에서 꽤 표준적인 NFT 구현을 나타냅니다. 일반적인 객체와 비교했을 때 가장 눈에 띄는 차이점은 상환된 필드입니다. 이 필드를 사용하여 NFT가 상환되었는지 여부를 설정합니다. 이 필드의 상태에 따라 NFT 이미지를 가리키는 URL이 변경됩니다.

커피 한 잔을 보여주는 NFT
타이페이 스마트시티 서밋 및 엑스포 참석자들은 이 NFT를 커피 한 잔으로 교환할 수 있으며, 그 이후에는 NFT가 사용 상태로 변경됩니다.

이 오브젝트는 다른 블록체인의 NFT처럼 이미지 파일을 가리키는 URL을 포함하는 대신, Sui 에서 지원하는 기능인 온체인 이미지 파일을 사용해 영속성을 향상시켰을 수 있다는 점에 유의하시기 바랍니다. 또한 이 오브젝트 코드는 .28 릴리스와 오브젝트 디스플레이 표준이 도입되기 전의 이전 버전 Move 을 사용합니다. 이 글의 마지막에 이 코드를 어떻게 작성할 수 있는지에 대한 업데이트된 예제를 제공합니다.

NFT 선물하기

이 시스템은 gift_nft 함수를 호출하여 참석자에게 원본 NFT를 전달할 수 있습니다. 이 함수는 사용자가 가상 어시스턴트가 제시하는 QR 코드를 스캔할 때 호출됩니다.

public entry fun gift_nft(
		global: &mut Global,
		to: address,
		name: vector<u8>,
		description: vector<u8>,
		ctx: &mut TxContext,
	) {
		assert!(tx_context::sender(ctx) == global.admin, ENOT_AUTHORIZED);
		let nft = CoffeeNFT {
			id: object::new(ctx),
			name: utf8(name),
			description: utf8(description),
			url: global.url_init,
			redeemed: false,
		};
		let coffee_nft_config = CoffeeNFTConfig {
			merchant_white_list: vec_set::empty(),
			merchant_redeemed: none(),
		};
		table::add(&mut global.nfts, object::id(&nft), coffee_nft_config);
		transfer(nft, to)
	}

시스템이 코드를 사용하여 NFT를 초기화할 때 let nft = CoffeeNFT { ... }로 설정하면 URL이 global.url_init 로 교환된 세트는 false. 이 모듈에는 사용자가 더 이상 존재하지 않을 수 있는 커피를 교환할 수 없는지 확인하는 검사도 포함되어 있습니다. 리딤_요청 함수를 사용하세요.

public entry fun redeem_request(
		global: &mut Global,
		nft_id: ID,
		ctx: &mut TxContext,
	) {
		let merchant = tx_context::sender(ctx);
		assert!(vec_set::contains(&global.merchants, &merchant), EMERCHANT_NOT_AUTHORIZED);
		let nft_config = table::borrow_mut(&mut global.nfts, nft_id);
		assert!(option::is_none(&nft_config.merchant_redeemed), ENFT_ALREADY_REDEEMED);
		assert!(!vec_set::contains(&nft_config.merchant_allow_list, &merchant), EMERCHANT_ALREADY_AUTHORIZED);
		vec_set::insert(&mut nft_config.merchant_allow_list, merchant);
	}

이 함수에는 세 가지 어설션이 포함됩니다. 첫 번째, EMERCHANT_NOT_AUTHORIZED는 이 함수를 호출하는 사용자가 관리자가 결정한 허용 목록에 있는 판매자임을 확인합니다. 두 번째, ENFT_ALREADY_REDEMED는 NFT가 아직 상환되지 않았다고 주장합니다. 세 번째이자 마지막 주장입니다, 판매자_이미_승인됨는 해당 NFT가 아직 판매자의 승인을 받지 않았음을 나타냅니다. 이 세 가지 조건이 모두 충족되면 리딤_요청 함수가 성공적으로 실행됩니다.

커피 공장을 보여주는 NFT
NFT가 커피 한 잔으로 교환되면 CoffeeNFT 객체에 새 이미지가 표시됩니다.

사용 가능한 재고 계정

광고에서는 때때로 "재고 소진 시까지"라는 경고 문구와 함께 특가 상품을 광고하기도 합니다. 이러한 방식으로 NFT를 사용하면 온체인에서 제한된 공급 개념을 완전히 시행할 수 있습니다!

마지막으로, 사용 가능한 재고가 남아 있고 사용자가 NFT를 사용하고자 하는 경우, 시스템에서는 redeem_nft 함수를 호출합니다.

public entry fun redeem_confirm(
		global: &mut Global,
		nft: &mut CoffeeNFT,
		merchant: address,
		_ctx: &mut TxContext,
	) {
		// check if the merchant authorized to redeem
		let nft_config = table::borrow_mut(&mut global.nfts, object::id(nft));
		assert!(vec_set::contains(&nft_config.merchant_white_list, &merchant), EMERCHANT_NOT_AUTHORIZED);
		// check stock
		let stock = vec_map::get_mut(&mut global.stocks, &merchant);
		assert!(*stock > 0, ENOT_ENOUGH_STOCK);
 
        // redeem
		// update nft config
		nft_config.merchant_redeemed = some(merchant);
		// update stock
		*stock = *stock - 1;
		// update nft
		nft.redeemed = true;
		nft.url = global.url_redeemed;
	}

위의 함수는 재고량을 1만큼 감소시키고, NFT의 상태를 다음과 같이 변경합니다. 상환를 클릭하고 새 이미지 URL을 표시합니다. 이러한 방식으로 NFT는 참석자와 커피 스탠드에 NFT가 사용되었음을 시각적으로 확인할 수 있습니다.

개체 표시 업데이트

위에서 언급했듯이, 엑스포에서 사용된 프로그램 코드는 특히 객체 표시와 관련하여 이전 버전의 Move 에 의존했습니다. 현재 객체 표시 표준을 기반으로 이 프로그램을 작성하면 아래 코드 스니펫과 같이 보일 수 있습니다.

module momentx::coffee_nft {
	use sui::tx_context::{sender, TxContext};
	use std::string::{utf8, String};
	use sui::transfer;
	use sui::object::UID;
    
	use sui::package;
	use sui::display;
	
    struct CoffeeNFT has key, store {
		id: UID,
		name: String,
		description: String,
		img_url: String,
		redeemed: bool,
	}
    
	struct COFFEE_NFT has drop {}
    
	fun init(otw: COFFEE_NFT, ctx: &mut TxContext) {
		let keys = vector[
			utf8(b"name"),
			utf8(b"description"),
			utf8(b"image_url"),
			utf8(b"redeemed")
		];
        
		let values = vector[
			utf8(b"{name}"),
			utf8(b"{description}"),
			utf8(b"ipfs://{img_url}"),
			utf8(b"{redeemed}"),
		];
        
		let publisher = package::claim(otw, ctx);
        
		let display = display::new_with_fields<CoffeeNFT>(
			&publisher, keys, values, ctx
		);
        
		display::update_version(&mut display);
        
		transfer::public_transfer(publisher, sender(ctx));
		transfer::public_transfer(display, sender(ctx));
	}
    
}

NFT를 진정으로 유용하게 만들기

위의 예시에서는 NFT에 실제 소비 가치인 커피 한 잔을 할당하고, NFT가 할당된 가치로 교환되었는지 여부를 표시하는 메커니즘을 만들었습니다. 이러한 사용법은 블록체인의 일반적인 NFT 거래를 넘어 실제 사용 사례를 보여줍니다. 또한, 저희는 실제 아이템의 수량이 제한되어 있는 현실을 인식하여 재고 또는 인벤토리라는 개념을 시스템에 내장했습니다.

더 넓은 개념으로, 위의 예시( Sui )는 오늘날 영화관, 콘서트, 비행기 등에서 사용되는 디지털 티켓이나 패스를 훨씬 뛰어넘는 인터랙티브 기능을 갖춘 디지털 티켓이 어떻게 NFT가 될 수 있는지 보여줍니다. 저희의 NFT 티켓은 보안이 내장되어 있고, 전송이 통제되며, 프로그래밍이 가능한 디스플레이를 갖추고 있습니다.

Sui/Move 학습 리소스를 추가로 확인하려면 아래 링크를 확인하세요!