Dacade平台SUI Move挑战者合约实践——去中心化市场DApp(Sui Move Marketplace DApp)

  • rzexin
  • 更新于 2024-03-07 00:37
  • 阅读 1643

Dacade平台SUI Move挑战者合约实践——去中心化市场DApp(Sui Move Marketplace DApp)

Dacade平台SUI Move挑战者合约实践——去中心化市场DApp(Sui Move Marketplace DApp)

1 合约说明

1.1 功能介绍

本合约是基于Sui区块链构建的去中心化市场dApp,允许卖家上架商品,允许买家使用SUI购买物品。

功能如下:

  • 卖家可以上架任何类型的商品
  • 市场接受SUI代币支付
  • 买家可以购买列出的商品

1.2 合约代码

1.2.1 合约源码地址

https://github.com/icis-04/dacademarket/blob/main/dacademarket/sources/marketplace.move

1.2.2 数据结构说明

(1)市场对象

成员变量说明:

  • items:存储市场上架的所有商品
  • payments:记录每位顾客支付的代币总数,仅能支持一种类型的代币
    // shared object, one instance of marketplace accepts only 1 type of coin for all listings
    struct Marketplace<phantom COIN> has key {
        id: UID,
        items: Bag,
        payments: Table<address, Coin<COIN>>
    }
(2)上架商品对象

成员变量说明:

  • ask:售价
  • owner:商品所有者
    // single listing which contains listed item and its price in COIN
    // attach actual item as dynamic object field, so we dont define any item field here
    struct Listing has key, store {
        id: UID,
        ask: u64,
        owner: address
    }

1.2.3 接口说明

(1)创建市场(create
  • 使用初始化参数,创建市场共享对象
  • 使用泛型<COIN>,表示只能接受一种类型的代币,在创建市场时,通过泛型参数指定
    #[allow(unused_function)]
    // create new shared marketplace
    public entry fun create<COIN>(ctx: &mut TxContext) {
        let id = object::new(ctx);
        let items = bag::new(ctx);
        let payments = table::new<address, Coin<COIN>>(ctx);
        transfer::share_object(Marketplace<COIN> { 
            id, 
            items,
            payments
        })
    }
(2)上架商品(list
  • 任何人都可以上架商品到市场
    // listing an item at the marketplace
    public entry fun list<T: key + store, COIN>(
        marketplace: &mut Marketplace<COIN>,
        item: T,
        ask: u64,
        ctx: &mut TxContext
    ) {
        let item_id = object::id(&item);
        let listing = Listing {
            id: object::new(ctx),
            ask: ask,
            owner: tx_context::sender(ctx),
        };

        ofield::add(&mut listing.id, true, item);
        bag::add(&mut marketplace.items, item_id, listing)
    }
(3)下架商品(delist_and_take
  • 商品所有者通过指定市场对象和商品ID可以下架该商品,商品对象会转发给商品所有者
    // internal function to remove listing and get item back, only owner can do
    fun delist<T: key + store, COIN>(
        marketplace: &mut Marketplace<COIN>,
        item_id: ID,
        ctx: &TxContext
    ): T {
        let Listing { id, owner, ask: _ } = bag::remove(&mut marketplace.items, item_id);

        assert!(tx_context::sender(ctx) == owner, ENotOwner);

        let item = ofield::remove(&mut id, true);
        object::delete(id);
        item
    }

    // call delist function and transfer item to sender
    public entry fun delist_and_take<T: key + store, COIN>(
        marketplace: &mut Marketplace<COIN>,
        item_id: ID,
        ctx: &mut TxContext
    ) {
        let item = delist<T, COIN>(marketplace, item_id, ctx);
        transfer::public_transfer(item, tx_context::sender(ctx));
    }
(4)购买商品(buy_and_take
  • 买家支付的金额,会记录到市场对象中商品所有者的地址下,如果商品所有者已经在该市场中出售过商品,本次支付的金额将会累计到商品所有者地址上
  • 购买的商品会转发到买家的地址上
    // internal function to purchase item using known Listing
    // payment is done in Coin<C>
    // if conditions are correct, owner of item gets payment and buyer receives item
    fun buy<T: key + store, COIN>(
        marketplace: &mut Marketplace<COIN>,
        item_id: ID,
        paid: Coin<COIN>,
    ): T {
        let Listing { id, ask, owner } = bag::remove(&mut marketplace.items, item_id);

        assert!(ask == coin::value(&paid), EAmountIncorrect);

        // check if theres alr a Coin hanging, if yes, merge paid with it
        // otherwise, attach paid to Marketplace under owner's address
        if (table::contains<address, Coin<COIN>>(&marketplace.payments, owner)) {
            coin::join(
                table::borrow_mut<address, Coin<COIN>>(&mut marketplace.payments, owner),
                paid
            )
        } else {
            table::add(&mut marketplace.payments, owner, paid)
        };

        let item = ofield::remove(&mut id, true);
        object::delete(id);
        item
    }

    // call buy function and transfer item to sender
    public entry fun buy_and_take<T: key + store, COIN>(
        marketplace: &mut Marketplace<COIN>,
        item_id: ID,
        paid: Coin<COIN>,
        ctx: &mut TxContext
    ) {
        transfer::public_transfer(
            buy<T, COIN>(marketplace, item_id, paid),
            tx_context::sender(ctx)
        )
    }
(5)提取收益(take_profits_and_keep
  • 商品所有者可以从市场中提取收益
    // internal function to take profits from selling items on marketplace
    fun take_profits<COIN>(
        marketplace: &mut Marketplace<COIN>,
        ctx: &TxContext
    ): Coin<COIN> {
        table::remove<address, Coin<COIN>>(&mut marketplace.payments, tx_context::sender(ctx))
    }

    // call take_profits function and transfers Coin object to sender
    public entry fun take_profits_and_keep<COIN>(
        marketplace: &mut Marketplace<COIN>,
        ctx: &mut TxContext
    ) {
        transfer::public_transfer(take_profits(marketplace, ctx), tx_context::sender(ctx))
    }

2 前置准备

2.1 帐号准备及角色分配

别名 地址 角色
Jason 0x5c5882d73a6e5b6ea1743fb028eff5e0d7cc8b7ae123d27856c5fe666d91569a 市场创建者
Alice 0x2d178b9704706393d2630fe6cf9415c2c50b181e9e3c7a977237bb2929f82d19 卖家
Bob 0xf2e6ffef7d0543e258d4c47a53d6fa9872de4630cc186950accbd83415b009f0 买家
  • 将地址添加到环境变量
export JASON=0x5c5882d73a6e5b6ea1743fb028eff5e0d7cc8b7ae123d27856c5fe666d91569a
export ALICE=0x2d178b9704706393d2630fe6cf9415c2c50b181e9e3c7a977237bb2929f82d19
export BOB=0xf2e6ffef7d0543e258d4c47a53d6fa9872de4630cc186950accbd83415b009f0

3 合约部署

切换到Jason账号

sui client publish --gas-budget 100000000
  • 命令输出关键信息截图

image.png

  • 将关键的对象ID记录到环境变量,方便后续调用使用
export PACKAGE_ID=0xa21284aefacf47f76f65e3b0167cab4b88cfd3b00990c93e4d0eab17f17fb590

4 合约交互

4.1 创建市场(create

sui client call --function create --package $PACKAGE_ID --module marketplace --type-args 0x2::sui::SUI --gas-budget 10000000
  • 得到市场对象
export MARKETPLACE=0x335f3b2a8470a1fbdb258172c446a93eddc4d78bb06a5f3becc9c03f20e99677

image.png

  • 查看市场对象
sui client object $MARKETPLACE

image.png

4.2 创建商品(mint)

切换到Alice

  • 创建商品1
sui client call --function mint --package $PACKAGE_ID --module widget --gas-budget 10000000

image.png

export ITEM=0x5e1c11052911d4c00dee1ae79569bec47af03793225c047212e34ccbc5379fb3
export ITEM_TYPE=$PACKAGE_ID::widget::Widget
  • 创建商品2
sui client call --function mint --package $PACKAGE_ID --module widget --gas-budget 10000000

image.png

export ITEM2=0xd7fbf5311c38b9a479323d280b3a389cf83894170b123c29b4d3d3289b05266e

4.3 上架商品(list

切换到Alice

  • 上架商品1,售价100
export ASK=100
sui client call --function list --package $PACKAGE_ID --module marketplace --type-args $ITEM_TYPE 0x2::sui::SUI --args $MARKETPLACE $ITEM $ASK --gas-budget 10000000

image.png

sui client object 0x8fdfef168028797421c63aabddbd665dc09912dd00776188b3c6fb6a8d6a7fb6

image.png

sui client object 0x9a52b966a582843c843dbd804445c61258d3a39433fbfa4338a0685a2522a105

image.png

  • 上架商品2,售价200
export ASK=200
sui client call --function list --package $PACKAGE_ID --module marketplace --type-args $ITEM_TYPE 0x2::sui::SUI --args $MARKETPLACE $ITEM2 $ASK --gas-budget 10000000

# 0xca9d317d421ce1635243fb11e37c8c3a862a6f2f411c1f2a0534bd6682870edb
# 0xee88a08c724332d616925edcc7a40259e44e2a457a9fd9bcc2f3b5c18ec4b0ec

image.png

  • 查看当前市场对象
sui client object $MARKETPLACE

可见已经发布了2件商品

image.png

4.4 购买商品(buy_and_take

切换到Bob,使用100元购买商品1

# 从Bob的地址中拆分出100
sui client gas --json | jq '.[] | select(.gasBalance > 100000) | .gasCoinId' -r > output.txt
GAS=$(sed -n '1p' output.txt)
SPLIT_COIN=$(sed -n '2p' output.txt)

export COIN=`sui client split-coin --coin-id $SPLIT_COIN --amounts 100 --gas $GAS --gas-budget $GAS_BUDGET --json | jq -r '.objectChanges[] | select(.objectType=="0x2::coin::Coin<0x2::sui::SUI>" and .type=="created") | .objectId'`

# 使用拆分出的COIN,进行商品1购买
sui client call --function buy_and_take --package $PACKAGE_ID --module marketplace --type-args $ITEM_TYPE 0x2::sui::SUI --args $MARKETPLACE $ITEM $COIN --gas-budget 10000000

# 0x82eddefa68d0089a7c3b73038818fbf98d543e33ea44637d78493ce0a3ab7654

image.png

  • 查看当前市场对象
sui client object $MARKETPLACE

可见商品数量已减少一件,卖家地址下的收益增加

image.png

4.5 下架商品(delist_and_take

切换到Alice

sui client call --function delist_and_take --package $PACKAGE_ID --module marketplace --type-args $ITEM_TYPE 0x2::sui::SUI --args $MARKETPLACE $ITEM2 --gas-budget 10000000

4.6 提取收益(take_profits_and_keep

sui client call --function take_profits_and_keep --package $PACKAGE_ID --module marketplace --type-args 0x2::sui::SUI --args $MARKETPLACE --gas-budget 10000000

5 前端交互

5.1 初始化参数

image.png

5.2 绑定钱包

image.png

5.3 创建商品

image.png

5.4 上架商品

image.png

5.5 购买商品

image.png

可见商品已经转移到新地址上:

image.png

5.6 提取受益

image.png

6 更多

欢迎关注微信公众号:Move中文,以及参与星航计划🚀,开启你的 Sui Move 之旅!

image.png

点赞 2
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
rzexin
rzexin
0x6Fa5...8165
江湖只有他的大名,没有他的介绍。