Dacade平台SUI Move挑战者合约实践——去中心化市场DApp(Sui Move Marketplace DApp)
本合约是基于Sui
区块链构建的去中心化市场dApp,允许卖家上架商品,允许买家使用SUI购买物品。
功能如下:
SUI
代币支付https://github.com/icis-04/dacademarket/blob/main/dacademarket/sources/marketplace.move
成员变量说明:
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>>
}
成员变量说明:
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
}
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
})
}
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)
}
delist_and_take
) // 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));
}
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)
)
}
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))
}
别名 | 地址 | 角色 |
---|---|---|
Jason | 0x5c5882d73a6e5b6ea1743fb028eff5e0d7cc8b7ae123d27856c5fe666d91569a |
市场创建者 |
Alice | 0x2d178b9704706393d2630fe6cf9415c2c50b181e9e3c7a977237bb2929f82d19 |
卖家 |
Bob | 0xf2e6ffef7d0543e258d4c47a53d6fa9872de4630cc186950accbd83415b009f0 |
买家 |
export JASON=0x5c5882d73a6e5b6ea1743fb028eff5e0d7cc8b7ae123d27856c5fe666d91569a
export ALICE=0x2d178b9704706393d2630fe6cf9415c2c50b181e9e3c7a977237bb2929f82d19
export BOB=0xf2e6ffef7d0543e258d4c47a53d6fa9872de4630cc186950accbd83415b009f0
切换到Jason账号
sui client publish --gas-budget 100000000
export PACKAGE_ID=0xa21284aefacf47f76f65e3b0167cab4b88cfd3b00990c93e4d0eab17f17fb590
create
)sui client call --function create --package $PACKAGE_ID --module marketplace --type-args 0x2::sui::SUI --gas-budget 10000000
export MARKETPLACE=0x335f3b2a8470a1fbdb258172c446a93eddc4d78bb06a5f3becc9c03f20e99677
sui client object $MARKETPLACE
切换到Alice
sui client call --function mint --package $PACKAGE_ID --module widget --gas-budget 10000000
export ITEM=0x5e1c11052911d4c00dee1ae79569bec47af03793225c047212e34ccbc5379fb3
export ITEM_TYPE=$PACKAGE_ID::widget::Widget
sui client call --function mint --package $PACKAGE_ID --module widget --gas-budget 10000000
export ITEM2=0xd7fbf5311c38b9a479323d280b3a389cf83894170b123c29b4d3d3289b05266e
list
)切换到Alice
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
sui client object 0x8fdfef168028797421c63aabddbd665dc09912dd00776188b3c6fb6a8d6a7fb6
sui client object 0x9a52b966a582843c843dbd804445c61258d3a39433fbfa4338a0685a2522a105
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
sui client object $MARKETPLACE
可见已经发布了2件商品
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
sui client object $MARKETPLACE
可见商品数量已减少一件,卖家地址下的收益增加
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
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
可见商品已经转移到新地址上:
欢迎关注微信公众号:Move中文,以及参与星航计划🚀,开启你的 Sui Move 之旅!
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!