Sui Move 实现一个简单的店铺买卖模型 —— Simple Buy-Sell Module
一个简单的店铺买卖只涉及了买家和卖家,买家只有购买这一个动作,而卖家则需要支持货品上架、更新、产品迭代等基础功能。
商店的部分信息应当是公开透明的,尤其是产品相关,甚至是营业额,但是这个权限又不能放得太开,否则所有人都可以操作这家店铺。<br>所以,我们用ShopCap
来限定权限,其所有者就是店铺拥有者,只有手握对应令牌的人,才可以对店铺进行深度操作(货品上架、下架、信息修改、提现等);而Shop
的相关信息则是直接面向所有人,所有人都可以查看店铺信息,特别是其中的产品信息,而这些人没有ShopCap
,所以不用担心他人提现等安全问题。
ShopCap
结构当中不需要过多的内容,只要有一个UID
让其能够被拥有即可。<br>Shop
当中最为关键的自然是余额balance
以及产品commodity
如何进行存储的问题,前者有 $\mathit {Sui}\ \mathit {Move}$ 提供的货币相关的库,而后者我们在这里选用动态数组 $\mathit {vector}$ 来存储产品信息。这里应该有更好的选择,但本着学习实践的原则还是选择了它,因为其它的一些数据结构,像是table甚至是linked_table在前篇都有用过
public struct ShopCap has key {
id: UID,
}
public struct Shop has key {
id: UID,
name: String,
balance: Balance<SUI>,
commodity: vector<Item>,
}
在vector
当中的每一个元素都是Item
类型,这是我们自定义的一个结构,它存储了每一个产品的信息,这里最主要的是库存和价格。<br>它只需要被存储,所以赋予store
能力,由于其中的属性都很简单,所以加上了drop
能力使其能够在被抛弃时自动解构。<br>id
作为每一个产品的唯一标识,同时也是顾客购买时用来对应自己想要买的究竟是哪一个产品的唯一途径。
public struct Item has store, drop {
id: ID,
name: String,
introduction: String,
stock: u64,
price: u64,
}
顾客的信息其实没什么需要记录的,在本篇内容当中,我们只需要一个新建一个Product
并将其所有权传给顾客,以此来代表该顾客购买了某一件产品,当然,Product
结构当中需要存储对应产品的相关信息。
public struct Product has key {
id: UID,
item_id: ID,
name: String,
introduction: String,
}
不仅要创建Shop
,同时还要创建ShopCap
,前者所有人共享可见,而后者只属于店主。
entry fun create_shop(name: String, ctx: &mut TxContext) {
// only ShopCap holders can make subsequent modifications to the shop
transfer::transfer(ShopCap {id: object::new(ctx)}, tx_context::sender(ctx));
// anyone can view shop information
transfer::share_object(Shop {
id: object::new(ctx),
name,
balance: balance::zero(),
commodity: vector::empty<Item>(),
});
}
只有拥有对应ShopCap
的店家才可以进行提现,前提是店铺当中的余额balance
大于零。
entry fun withdraw(_shop_cap: &ShopCap, shop: &mut Shop, ctx: &mut TxContext) {
// assert the balance
assert!(shop.balance.value() > 0, ErrNotBalance);
// take all balance
let all = shop.balance.withdraw_all();
// transfer the coin
transfer::public_transfer(coin::from_balance(all, ctx), tx_context::sender(ctx));
}
注销店铺时需要注意,ShopCap
也需要注销,因为店铺不存在了,其对应的凭证权限也没了用处,与此同时,在处理Shop
的时候别忘记摧毁balance
和vector
,其中如果仍有值,需要先进行处理,使其为空。<br>在其它大多数情况下,如果不满足空的条件可以直接assert
进行报错,得益于交易的原子性,一切都会恢复到交易之前的状态,而在本篇当中,一切都很简单,所以可以直接处理。
entry fun destroy_shop(shop_cap: ShopCap, mut shop: Shop, ctx: &mut TxContext) {
// withdraw
if (shop.balance.value() > 0) {
withdraw(&shop_cap, &mut shop, ctx);
};
// destroy ShopCap
let ShopCap {id} = shop_cap;
object::delete(id);
// destroy Shop
let Shop {
id,
name: _,
balance,
mut commodity,
} = shop;
object::delete(id);
// destroy balance
balance.destroy_zero();
// destroy vector
while (commodity.length() > 0) {
commodity.pop_back();
};
commodity.destroy_empty();
}
提供新品信息,将其存入Shop
当中的commodity
里,顾客后续就可以通过Shop
进行查看。<br>这里的关键是ID
如何进行获取,我们采用源码当中UID
生成的类似方式,借助tx_context
库中的fresh_object_address
函数,根据ctx
生成唯一的address
,再用address
自带的to_id
函数来将其转变为ID
。
entry fun create_item(
_shop_cap: &ShopCap,
shop: &mut Shop,
name: String,
introduction: String,
stock: u64,
price: u64,
ctx: &mut TxContext
) {
// create Item
let item = Item {
id: tx_context::fresh_object_address(ctx).to_id(), // address.to_id()
name,
introduction,
stock,
price,
};
// store it
shop.commodity.push_back(item);
}
根据ID
来确定究竟需要更新的是哪一个产品,通过遍历vector
来确认。<br>当货架上的品类很多很多的时候,遍历这一操作可能会消耗大量的gas
,这也是上面提到的,可以使用更适配的数据结构的原因之一,不过在初学者阶段,多用用相关的结构调用也是必要的。
entry fun modify_stock(_shop_cap: &ShopCap, shop: &mut Shop, id: ID, stock: u64) {
let mut i = 0;
let mut modify_success = false;
while (i < shop.commodity.length()) {
let item = &mut shop.commodity[i];
// check if the correct item
if (id != item.id) {
i = i + 1;
continue
};
// modify the stock and break this while
modify_success = true;
item.stock = stock;
break
};
// assert success
assert!(modify_success, ErrNotItem);
}
类似的,也是通过ID
来匹配删除。
entry fun remove_item(_shop_cap: &ShopCap, shop: &mut Shop, id: ID) {
let mut i = 0;
let mut modify_success = false;
while (i < shop.commodity.length()) {
let item = &mut shop.commodity[i];
// check if the correct item
if (id != item.id) {
i = i + 1;
continue
};
// remove the item and break this while
modify_success = true;
shop.commodity.remove(i);
break
};
// assert success
assert!(modify_success, ErrNotItem);
}
在这里,顾客单独写了一个module
,不要忘记在里面通过use simple_buy_sell::shop::Shop
将上述的shop
引入。<br>为了更好地撰写顾客的购买功能,我们先在shop.move
当中添加两个辅助函数,也就是下面的 $\text {3.2.1}$ 和 $\text {3.2.2}$,至于原因呢,就是在不同的module
中,不可以直接通过.
的方式来获取对应结构体对象当中的值。如果你在自主实现的时候写在用一份文件当中,可以忽略这一点
根据顾客挑选的ID
匹配后返回对应商品的信息,在本篇当中最重要的就是其价格,当然,前提是对应的商品库存非零,同时令对应的库存减一。<br>当返回的值不只一个的时候,用()
将它们括起来,中间用逗号分隔。
public fun get(shop: &mut Shop, id: ID): (String, String, u64) {
let mut i = 0;
while (i < shop.commodity.length() && shop.commodity[i].id != id) {
i = i + 1;
};
// assert the correct item id
assert!(i < shop.commodity.length(), ErrNotItem);
let item = &mut shop.commodity[i];
// assert the stock
assert!(item.stock > 0, ErrNotEnoughItem);
// decrease the stock
item.stock = item.stock - 1;
// return
(item.name, item.introduction, item.price)
}
当用户提供的Coin<SUI>
充足的时候(大于产品价格),将其分割出对应price
的值合并到Shop
当中的余额。
public fun join(shop: &mut Shop, coin: Coin<SUI>) {
shop.balance.join(coin.into_balance());
}
有了上面两个辅助函数,购买功能的实现就只剩下了Product
创建并移交所有权,当然,过程当中传入的Coin<SUI>
需要做后续处理(剩余余额为零时摧毁,否则交还给顾客)。
entry fun buy(shop: &mut Shop, item_id: ID, mut sui: Coin<SUI>, ctx: &mut TxContext) {
let (name, introduction, price) = shop.get(item_id);
// assert the coin value
assert!(sui.value() >= price, ErrNotEnoughPrice);
// transfer coin
let pay_coin = sui.split(price, ctx);
shop.join(pay_coin);
// deal with remaining currency
if (sui.value() == 0) {
sui.destroy_zero();
} else {
transfer::public_transfer(sui, tx_context::sender(ctx));
};
// get the product
transfer::transfer(Product {
id: object::new(ctx),
item_id,
name,
introduction,
}, tx_context::sender(ctx));
}
在老版本的 $\mathit {Sui}\ \mathit {Move}$ 当中,这个写法sui: Coin<SUI>
得到的传入的值是可变的,但是在 $\text {2024}$ 新版本当中是不可变的,所以才需要在前面加mut
来修饰。<br>类似的,在变量赋值的时候也是这样,例如:let i = 0
以及let mut i = 0
,在前面的循环当中为什么用后者就是这个原因。<br>不过,这个mut
并不会让所有权变得更加复杂,还是如老版本一致。
sui client publish --gas-budget 100000000
╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Object Changes │
├──────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Created Objects: │
│ ┌── │
│ │ ObjectID: 0xd1e438b61bc067fe1dd982b0a0d0d7ec8a4e5b14d70fb0bdc181f53d5cb49845 │
│ │ Sender: 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67 │
│ │ Owner: Account Address ( 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67 ) │
│ │ ObjectType: 0x2::package::UpgradeCap │
│ │ Version: 28131879 │
│ │ Digest: 84ZDVcf2Sj4orHDK7xx9YqKqJHHaKiSoSdjy8vCMzUUv │
│ └── │
│ Mutated Objects: │
│ ┌── │
│ │ ObjectID: 0x266848e4e91a7a43a72b63f20760e1341e81f8970d8201a792a48959dfe2e0b9 │
│ │ Sender: 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67 │
│ │ Owner: Account Address ( 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67 ) │
│ │ ObjectType: 0x2::coin::Coin<0x2::sui::SUI> │
│ │ Version: 28131879 │
│ │ Digest: 8bs9kriYfaUafxLRQ9iH8q584UHdQjxkWAZQ1u1xXwxH │
│ └── │
│ Published Objects: │
│ ┌── │
│ │ PackageID: 0xb36940dff6fcbda820ceec457fff1f8cb401cb75aa07e7c9a36928949781a8ad │
│ │ Version: 1 │
│ │ Digest: 5kHUEVJQKee9uBf1m6AuT27EBGuRizKzjRMhVwbA8swe │
│ │ Modules: cuntomer, shop │
│ └── │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
export PACKAGE_ID=0xb36940dff6fcbda820ceec457fff1f8cb401cb75aa07e7c9a36928949781a8ad
sui client call --package $PACKAGE_ID --module shop --function create_shop --args my_first_shop --gas-budget 10000000
╭───────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Object Changes │
├───────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Created Objects: │
│ ┌── │
│ │ ObjectID: 0x1168e00b20902a8c3148794c72c526677aaded597c823f6245ccc455ea11d1e4 │
│ │ Sender: 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67 │
│ │ Owner: Account Address ( 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67 ) │
│ │ ObjectType: 0xb36940dff6fcbda820ceec457fff1f8cb401cb75aa07e7c9a36928949781a8ad::shop::ShopCap │
│ │ Version: 28131880 │
│ │ Digest: 3MZNgei3UmzZWRBoLgTh2z313Rt8HF9Whs6P1xrhLFwh │
│ └── │
│ ┌── │
│ │ ObjectID: 0xf7ccf14adeb8557862ea435c57c403646750793e28207776ae8a86c08e5ba779 │
│ │ Sender: 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67 │
│ │ Owner: Shared │
│ │ ObjectType: 0xb36940dff6fcbda820ceec457fff1f8cb401cb75aa07e7c9a36928949781a8ad::shop::Shop │
│ │ Version: 28131880 │
│ │ Digest: JABUj677UPKV8HKy11Bc8F9qhobi97mmsa1eRzZWPWfB │
│ └── │
│ Mutated Objects: │
│ ┌── │
│ │ ObjectID: 0x266848e4e91a7a43a72b63f20760e1341e81f8970d8201a792a48959dfe2e0b9 │
│ │ Sender: 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67 │
│ │ Owner: Account Address ( 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67 ) │
│ │ ObjectType: 0x2::coin::Coin<0x2::sui::SUI> │
│ │ Version: 28131880 │
│ │ Digest: 8s7n8Puq6GZQRUyHArdh7GJzHB6G44XUgiKggwQgw6E7 │
│ └── │
╰───────────────────────────────────────────────────────────────────────────────────────────────────╯
export SHOPCAP=0x1168e00b20902a8c3148794c72c526677aaded597c823f6245ccc455ea11d1e4
export SHOP=0xf7ccf14adeb8557862ea435c57c403646750793e28207776ae8a86c08e5ba779
sui client call --package $PACKAGE_ID --module shop --function create_item --args $SHOPCAP $SHOP my_first_product first_product_desc 1 369963 --gas-budget 10000000
╭───────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Object Changes │
├───────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Mutated Objects: │
│ ┌── │
│ │ ObjectID: 0x1168e00b20902a8c3148794c72c526677aaded597c823f6245ccc455ea11d1e4 │
│ │ Sender: 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67 │
│ │ Owner: Account Address ( 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67 ) │
│ │ ObjectType: 0xb36940dff6fcbda820ceec457fff1f8cb401cb75aa07e7c9a36928949781a8ad::shop::ShopCap │
│ │ Version: 28131881 │
│ │ Digest: 8MjbJQRSDTRbyyNWt5AVEA2itSbbuAixZmqPnnxM775B │
│ └── │
│ ┌── │
│ │ ObjectID: 0x266848e4e91a7a43a72b63f20760e1341e81f8970d8201a792a48959dfe2e0b9 │
│ │ Sender: 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67 │
│ │ Owner: Account Address ( 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67 ) │
│ │ ObjectType: 0x2::coin::Coin<0x2::sui::SUI> │
│ │ Version: 28131881 │
│ │ Digest: Gz8L5KXeDGveZVW7icq8Ew9qdZSKTUKkfh4QZsvoM2dc │
│ └── │
│ ┌── │
│ │ ObjectID: 0xf7ccf14adeb8557862ea435c57c403646750793e28207776ae8a86c08e5ba779 │
│ │ Sender: 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67 │
│ │ Owner: Shared │
│ │ ObjectType: 0xb36940dff6fcbda820ceec457fff1f8cb401cb75aa07e7c9a36928949781a8ad::shop::Shop │
│ │ Version: 28131881 │
│ │ Digest: DbpXTbKxnFccBTZswxDJz9cLPVbQnesF3dEqzkUFE7RB │
│ └── │
╰───────────────────────────────────────────────────────────────────────────────────────────────────╯
Shop
sui client object $SHOP
# output:
╭───────────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ objectId │ 0xf7ccf14adeb8557862ea435c57c403646750793e28207776ae8a86c08e5ba779 │
│ version │ 28131881 │
│ digest │ DbpXTbKxnFccBTZswxDJz9cLPVbQnesF3dEqzkUFE7RB │
│ objType │ 0xb36940dff6fcbda820ceec457fff1f8cb401cb75aa07e7c9a36928949781a8ad::shop::Shop │
│ owner │ ╭────────┬─────────────────────────────────────────╮ │
│ │ │ Shared │ ╭────────────────────────┬────────────╮ │ │
│ │ │ │ │ initial_shared_version │ 28131880 │ │ │
│ │ │ │ ╰────────────────────────┴────────────╯ │ │
│ │ ╰────────┴─────────────────────────────────────────╯ │
│ prevTx │ 4ctXs8jppLhFYFAtidr2YgAmT6VHNrgu6W34MTJTeSRo │
│ storageRebate │ 2067200 │
│ content │ ╭───────────────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │
│ │ │ dataType │ moveObject │ │
│ │ │ type │ 0xb36940dff6fcbda820ceec457fff1f8cb401cb75aa07e7c9a36928949781a8ad::shop::Shop │ │
│ │ │ hasPublicTransfer │ false │ │
│ │ │ fields │ ╭───────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ │
│ │ │ │ │ balance │ 0 │ │ │
│ │ │ │ │ commodity │ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ │ │
│ │ │ │ │ │ │ ╭────────┬─────────────────────────────────────────────────────────────────────────────────────────╮ │ │ │ │
│ │ │ │ │ │ │ │ type │ 0xb36940dff6fcbda820ceec457fff1f8cb401cb75aa07e7c9a36928949781a8ad::shop::Item │ │ │ │ │
│ │ │ │ │ │ │ │ fields │ ╭──────────────┬──────────────────────────────────────────────────────────────────────╮ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │ id │ 0x3b808241908b5d2cf4dbbc66cfc0b519eb9bd7ed7f8974d833dc2c085c07340d │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │ introduction │ first_product_desc │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │ name │ my_first_product │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │ price │ 369963 │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │ stock │ 1 │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ ╰──────────────┴──────────────────────────────────────────────────────────────────────╯ │ │ │ │ │
│ │ │ │ │ │ │ ╰────────┴─────────────────────────────────────────────────────────────────────────────────────────╯ │ │ │ │
│ │ │ │ │ │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯ │ │ │
│ │ │ │ │ id │ ╭────┬──────────────────────────────────────────────────────────────────────╮ │ │ │
│ │ │ │ │ │ │ id │ 0xf7ccf14adeb8557862ea435c57c403646750793e28207776ae8a86c08e5ba779 │ │ │ │
│ │ │ │ │ │ ╰────┴──────────────────────────────────────────────────────────────────────╯ │ │ │
│ │ │ │ │ name │ my_first_shop │ │ │
│ │ │ │ ╰───────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────╯ │ │
│ │ ╰───────────────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ │
╰───────────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
ID
export ITEMID=0x3b808241908b5d2cf4dbbc66cfc0b519eb9bd7ed7f8974d833dc2c085c07340d
sui client switch --address <alias>
Coin
sui client gas
# choose one of the CoinIDs which the balance is enough to purchase
╭────────────────────────────────────────────────────────────────────┬────────────────────┬──────────────────╮
│ gasCoinId │ mistBalance (MIST) │ suiBalance (SUI) │
├────────────────────────────────────────────────────────────────────┼────────────────────┼──────────────────┤
│ 0x516586df0c5e9c9567696840981f720d64335ac6e8ad409f4ba4843b8dc2274a │ 100 │ 0.00 │
│ 0x82ec01655d746b42dba5c5951841472e5d1715e74238a5ef8e39d0b0566dc3be │ 996585540 │ 0.99 │
│ 0x8ef6503cb330c4114bc7995a403adf4015190d8effc02504fd849377caa6499b │ 967262964 │ 0.96 │
│ 0xad3fa2545f5db01bd4d349871df5af4d6de913600e7e3e032d5229c006d35851 │ 100 │ 0.00 │
│ 0xcb24b30fe196f4f2ca6d5f8d87a273bf168f7f86f6b7ae3f1f20fc5cf447e557 │ 990920960 │ 0.99 │
│ 0xe4f2d7831241583d534271d8d777d7558290124779e98e03b059a2fe108d37b0 │ 989 │ 0.00 │
╰────────────────────────────────────────────────────────────────────┴────────────────────┴──────────────────╯
# export it
export COIN=0x82ec01655d746b42dba5c5951841472e5d1715e74238a5ef8e39d0b0566dc3be
sui client call --package $PACKAGE_ID --module cuntomer --function buy --args $SHOP $ITEMID $COIN --gas-budget 10000000
注意: 到这里才发现顾客代码最上面的模块名customer
打成了cuntomer
,既然事已至此,只能先吃饭了哦不,先调用了┭┮﹏┭┮(以后注意)
╭───────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Object Changes │
├───────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Created Objects: │
│ ┌── │
│ │ ObjectID: 0x254bf6a1d6eba45c4c46493c416d743c616d7d8839dafd21c6ea55fa0fa20a43 │
│ │ Sender: 0xf6029b82e355f627b0e3d8941d63e139c4b73b495a2017ef48aaf17cc377457b │
│ │ Owner: Account Address ( 0xf6029b82e355f627b0e3d8941d63e139c4b73b495a2017ef48aaf17cc377457b ) │
│ │ ObjectType: 0xb36940dff6fcbda820ceec457fff1f8cb401cb75aa07e7c9a36928949781a8ad::cuntomer::Product │
│ │ Version: 28131882 │
│ │ Digest: 56giajkY6hdUFxLd5jrdjquWYV4ZypLLuJFQvVk6rAgj │
│ └── │
│ Mutated Objects: │
│ ┌── │
│ │ ObjectID: 0x82ec01655d746b42dba5c5951841472e5d1715e74238a5ef8e39d0b0566dc3be │
│ │ Sender: 0xf6029b82e355f627b0e3d8941d63e139c4b73b495a2017ef48aaf17cc377457b │
│ │ Owner: Account Address ( 0xf6029b82e355f627b0e3d8941d63e139c4b73b495a2017ef48aaf17cc377457b ) │
│ │ ObjectType: 0x2::coin::Coin<0x2::sui::SUI> │
│ │ Version: 28131882 │
│ │ Digest: DKfyM1wsnx4u9zDMqqBeLbW8nctRhPyhJqgxcjgHQLzy │
│ └── │
│ ┌── │
│ │ ObjectID: 0x8ef6503cb330c4114bc7995a403adf4015190d8effc02504fd849377caa6499b │
│ │ Sender: 0xf6029b82e355f627b0e3d8941d63e139c4b73b495a2017ef48aaf17cc377457b │
│ │ Owner: Account Address ( 0xf6029b82e355f627b0e3d8941d63e139c4b73b495a2017ef48aaf17cc377457b ) │
│ │ ObjectType: 0x2::coin::Coin<0x2::sui::SUI> │
│ │ Version: 28131882 │
│ │ Digest: 8oHBrgmZKnp69nkivc7xTB8kEHde9cMchyVGh1A3tjAS │
│ └── │
│ ┌── │
│ │ ObjectID: 0xf7ccf14adeb8557862ea435c57c403646750793e28207776ae8a86c08e5ba779 │
│ │ Sender: 0xf6029b82e355f627b0e3d8941d63e139c4b73b495a2017ef48aaf17cc377457b │
│ │ Owner: Shared │
│ │ ObjectType: 0xb36940dff6fcbda820ceec457fff1f8cb401cb75aa07e7c9a36928949781a8ad::shop::Shop │
│ │ Version: 28131882 │
│ │ Digest: 9We2z3NPJqwwqCoyhBVWsvMEqv5ZpuPQgHcAVXjXmxwL │
│ └── │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────╯
可以通过sui client object <ObjectID>
来查看Product
信息是否是自己想要购买的那一个产品,以及Shop
当中对应产品的库存是否减少了 $\text 1$。
Error executing transaction: Failure {
error: "MoveAbort(MoveLocation { module: ModuleId { address: b36940dff6fcbda820ceec457fff1f8cb401cb75aa07e7c9a36928949781a8ad, name: Identifier(\"shop\") }, function: 6, instruction: 54, function_name: Some(\"get\") }, 2) in command 0",
}
原因是库存不足。
sui client call --package $PACKAGE_ID --module shop --function modify_stock --args $SHOPCAP $SHOP $ITEMID 1000 --gas-budget 10000000
RPC call failed: ErrorObject { code: ServerError(-32002), message: "Transaction execution failed due to issues with transaction inputs, please review the errors and try again: Transaction was not signed by the correct sender: Object 0x1168e00b20902a8c3148794c72c526677aaded597c823f6245ccc455ea11d1e4 is owned by account address 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67, but given owner/signer address is 0xf6029b82e355f627b0e3d8941d63e139c4b73b495a2017ef48aaf17cc377457b.", data: None }
Caused by:
RPC call failed: ErrorObject { code: ServerError(-32002), message: "Transaction execution failed due to issues with transaction inputs, please review the errors and try again: Transaction was not signed by the correct sender: Object 0x1168e00b20902a8c3148794c72c526677aaded597c823f6245ccc455ea11d1e4 is owned by account address 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67, but given owner/signer address is 0xf6029b82e355f627b0e3d8941d63e139c4b73b495a2017ef48aaf17cc377457b.", data: None }
因为当前用户(顾客)并没有ShopCap
的所有权,所以我们切换回店主再次调用。
Shop
╭───────────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ objectId │ 0xf7ccf14adeb8557862ea435c57c403646750793e28207776ae8a86c08e5ba779 │
│ version │ 28131884 │
│ digest │ DkahtiGN2WDFa5zwus62oRGk8pXtgwvLo5FHdHc8pNip │
│ objType │ 0xb36940dff6fcbda820ceec457fff1f8cb401cb75aa07e7c9a36928949781a8ad::shop::Shop │
│ owner │ ╭────────┬─────────────────────────────────────────╮ │
│ │ │ Shared │ ╭────────────────────────┬────────────╮ │ │
│ │ │ │ │ initial_shared_version │ 28131880 │ │ │
│ │ │ │ ╰────────────────────────┴────────────╯ │ │
│ │ ╰────────┴─────────────────────────────────────────╯ │
│ prevTx │ 8Js8x4Cq9J1M7cUhEWS8BC2KuM6DVHzXeVos2MW9pQY1 │
│ storageRebate │ 2067200 │
│ content │ ╭───────────────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │
│ │ │ dataType │ moveObject │ │
│ │ │ type │ 0xb36940dff6fcbda820ceec457fff1f8cb401cb75aa07e7c9a36928949781a8ad::shop::Shop │ │
│ │ │ hasPublicTransfer │ false │ │
│ │ │ fields │ ╭───────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ │
│ │ │ │ │ balance │ 369963 │ │ │
│ │ │ │ │ commodity │ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ │ │
│ │ │ │ │ │ │ ╭────────┬─────────────────────────────────────────────────────────────────────────────────────────╮ │ │ │ │
│ │ │ │ │ │ │ │ type │ 0xb36940dff6fcbda820ceec457fff1f8cb401cb75aa07e7c9a36928949781a8ad::shop::Item │ │ │ │ │
│ │ │ │ │ │ │ │ fields │ ╭──────────────┬──────────────────────────────────────────────────────────────────────╮ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │ id │ 0x3b808241908b5d2cf4dbbc66cfc0b519eb9bd7ed7f8974d833dc2c085c07340d │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │ introduction │ first_product_desc │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │ name │ my_first_product │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │ price │ 369963 │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │ stock │ 1000 │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ ╰──────────────┴──────────────────────────────────────────────────────────────────────╯ │ │ │ │ │
│ │ │ │ │ │ │ ╰────────┴─────────────────────────────────────────────────────────────────────────────────────────╯ │ │ │ │
│ │ │ │ │ │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────╯ │ │ │
│ │ │ │ │ id │ ╭────┬──────────────────────────────────────────────────────────────────────╮ │ │ │
│ │ │ │ │ │ │ id │ 0xf7ccf14adeb8557862ea435c57c403646750793e28207776ae8a86c08e5ba779 │ │ │ │
│ │ │ │ │ │ ╰────┴──────────────────────────────────────────────────────────────────────╯ │ │ │
│ │ │ │ │ name │ my_first_shop │ │ │
│ │ │ │ ╰───────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────╯ │ │
│ │ ╰───────────────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ │
╰───────────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
可以发现,库存已经由 $\text 0$ 变成了 $\text {1000}$。
sui client call --package $PACKAGE_ID --module shop --function remove_item --args $SHOPCAP $SHOP $ITEMID --gas-budget 10000000
Shop
可以发现货架空了╭───────────────┬───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ objectId │ 0xf7ccf14adeb8557862ea435c57c403646750793e28207776ae8a86c08e5ba779 │
│ version │ 28131885 │
│ digest │ BZxb2tchuVEfoqRr1GAYi3xTHajsHiqovpoPBMh4MpTd │
│ objType │ 0xb36940dff6fcbda820ceec457fff1f8cb401cb75aa07e7c9a36928949781a8ad::shop::Shop │
│ owner │ ╭────────┬─────────────────────────────────────────╮ │
│ │ │ Shared │ ╭────────────────────────┬────────────╮ │ │
│ │ │ │ │ initial_shared_version │ 28131880 │ │ │
│ │ │ │ ╰────────────────────────┴────────────╯ │ │
│ │ ╰────────┴─────────────────────────────────────────╯ │
│ prevTx │ DLQpLwJEqpA5jCZcqddm7ArZmqKc3cRBZNRqtW7tKi9R │
│ storageRebate │ 1428800 │
│ content │ ╭───────────────────┬───────────────────────────────────────────────────────────────────────────────────────────────╮ │
│ │ │ dataType │ moveObject │ │
│ │ │ type │ 0xb36940dff6fcbda820ceec457fff1f8cb401cb75aa07e7c9a36928949781a8ad::shop::Shop │ │
│ │ │ hasPublicTransfer │ false │ │
│ │ │ fields │ ╭───────────┬───────────────────────────────────────────────────────────────────────────────╮ │ │
│ │ │ │ │ balance │ 369963 │ │ │
│ │ │ │ │ commodity │ │ │ │
│ │ │ │ │ id │ ╭────┬──────────────────────────────────────────────────────────────────────╮ │ │ │
│ │ │ │ │ │ │ id │ 0xf7ccf14adeb8557862ea435c57c403646750793e28207776ae8a86c08e5ba779 │ │ │ │
│ │ │ │ │ │ ╰────┴──────────────────────────────────────────────────────────────────────╯ │ │ │
│ │ │ │ │ name │ my_first_shop │ │ │
│ │ │ │ ╰───────────┴───────────────────────────────────────────────────────────────────────────────╯ │ │
│ │ ╰───────────────────┴───────────────────────────────────────────────────────────────────────────────────────────────╯ │
╰───────────────┴───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
sui client call --package $PACKAGE_ID --module shop --function withdraw --args $SHOPCAP $SHOP --gas-budget 10000000
sui client gas
# output:
╭────────────────────────────────────────────────────────────────────┬────────────────────┬──────────────────╮
│ gasCoinId │ mistBalance (MIST) │ suiBalance (SUI) │
├────────────────────────────────────────────────────────────────────┼────────────────────┼──────────────────┤
│ 0x03335f68ff3616af7e000b113c56a5ad53e8e8209784ca0a5623f70997c8d948 │ 10 │ 0.00 │
│ 0x266848e4e91a7a43a72b63f20760e1341e81f8970d8201a792a48959dfe2e0b9 │ 659262424 │ 0.65 │
│ 0x2b057028a2ce30115dfddf330f3d25e5bb72dad28421a61d1ee6b3c98c81e900 │ 369963 │ 0.00 │
│ 0x2b58970568741e980b433ab092da5a1f08317b53b5b4724cc6fc45435f80ea34 │ 11 │ 0.00 │
│ 0x3309da2eb2919265feff786cd9167cdee8055fea52649bd33b92adfb3732e4c5 │ 10 │ 0.00 │
│ 0x47b46755e4603b0479ca251a23d35d8bb09f370eec11c9113b284eb318566b59 │ 990 │ 0.00 │
│ 0x8395ab2385bd34aa1275a0eb6e9e9253fcb6aa67c5216a9c58cbeedb3f12941a │ 763788220 │ 0.76 │
│ 0x86c7602927f18a8887f814c75a2201ee45e6b56eeba7de77c6587fd5882cce9f │ 0 │ 0.00 │
│ 0xb3968ae4bf71a60d2ed4d39b2dc89cd184fca813a0a6e4d5abea26492f953ef2 │ 990 │ 0.00 │
│ 0xe24536eec6d0289205e19571169fac8b3b29c8148545184a243e22d34a8ee07e │ 855053848 │ 0.85 │
╰────────────────────────────────────────────────────────────────────┴────────────────────┴──────────────────╯
其中的 $\text {369963}$ 就是我们的收入,它对应的gasCoinId
跟我们调用后输出的信息当中的新建的Coin<SUI>
也能够对应上。
sui client call --package $PACKAGE_ID --module shop --function destroy_shop --args $SHOPCAP $SHOP --gas-budget 10000000
这个时候,再通过sui client object <ObjectID>
查看Shop
或者ShopCap
,会报错提示这两个对象已经不存在了。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!