Let's move - Sui Coin合约发布实例

  • stom698
  • 更新于 2024-03-28 16:23
  • 阅读 1066

本文转自本人微信公众号的文章,所以带有wx水印,希望大家能理解一下。后续新文会自己留存不带水印。

1.1 move Generics

创建合约项目

sui move new generics && cd generics

新建generics.move

module generics::generics {
    use sui::transfer;
    use sui::object::{Self, UID};
    use sui::tx_context::{Self, TxContext};
​
    struct Box<T: store> has key, store {
        id: UID,
        value: T
    }
​
    struct SimpleBox has key, store {
        id: UID,
        value: u8
    }
​
    struct PhantomBox<phantom T: drop> has key {
        id: UID,
    }
​
    public fun create_box<T: store>(value: T,  ctx: &mut TxContext){
        transfer::transfer(Box<T> {id: object::new(ctx), value }, tx_context::sender(ctx))
    }
​
    public fun create_simple_box(value: u8,  ctx: &mut TxContext){
        transfer::transfer(SimpleBox {id: object::new(ctx), value }, tx_context::sender(ctx))
    }
​
    public fun create_phantom_box<T: drop >(_value: T,  ctx: &mut TxContext){
        transfer::transfer(PhantomBox<T> {id: object::new(ctx)}, tx_context::sender(ctx))
    }
​
}

部署合约

sui client publish --gas-budget 100000000 --skip-dependency-verification
│ Published Objects:                                                                               │
│  ┌──                                                                                             │
│  │ PackageID: 0xab619c63c6ad6d3e5cc94875913f85b6957bc77d8706b54a95f4f6fd5d72bd13                 │
│  │ Version: 1                                                                                    │
│  │ Digest: ASCqHLXCydiDt6Rr6siviwwG27shmWsVJKb34BjXG7ts                                          │
│  │ Modules: generics  

调用create_box创建box

将之前创建的helloworld存储到box

sui client call --package 0xab619c63c6ad6d3e5cc94875913f85b6957bc77d8706b54a95f4f6fd5d72bd13 --module generics --function create_box --args 0x0496c2f2fccf89ebab659324f4735297a06d0c45a54348babf1443ced89ea796 --type-args "0x2ddc2bd1445a8046487b645cb4626764ea812f62bdaef8253182719a96c81426::hello_world::HelloWorldObject" --gas-budget 1000000

img

将sui代币存储到box

sui client call --package 0xab619c63c6ad6d3e5cc94875913f85b6957bc77d8706b54a95f4f6fd5d72bd13 --module generics --function create_box --args 0xb4fbb54b7ee3d76b6d04787f48b44113efc4228e7803aa3b0b8bea410b9c43b3 --type-args "0x2::coin::Coin<0x2::sui::SUI>" --gas-budget 10000000

img

但是如果放入的类型本身不拥有 store 能力,则无法被存储

sui client call --package 0xab619c63c6ad6d3e5cc94875913f85b6957bc77d8706b54a95f4f6fd5d72bd13 --module generics --function create_box --args 0x6b2a315363bb27da5628a2271b161c78eeb364826f68c0b84cc34e750cbcb0e5 --type-args "0x86cac9f3c094c7e0bfed3aae880a4400130626d4aacc2ada137554b6b7ae50c3::transcript::Folder" --gas-budget 10000000

img

查看之前的代码,Folder只拥有key的能力

    struct Folder has key {
        id: UID,
        transcript: WrappableTranscript,
        intended_address: address
    }

1.2 Generics解封装

解封装拿出sui,新增transfer_value函数

public fun transfer_value<T: key + store>(box: Box<T>, ctx: &mut TxContext) {
    let Box{
        id,
        value
    }= box;
    transfer::public_transfer<T>(value, tx_context::sender(ctx));
    object::delete(id)
}

然后需要进行合约upgrade,需要先获取第一次发布合约时获取的UpgradeCap

0xa4238a21ba7c9832d4e3b3b4a5a814fbb234a60309b5cc2259b501a81f6235a4

然后修改move.toml文件,新增publish-at参数填入已发布合约的packageid

[package]
name = "generics"
version = "0.0.1"
published-at = "0xab619c63c6ad6d3e5cc94875913f85b6957bc77d8706b54a95f4f6fd5d72bd13"
​
[dependencies]
Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/sui-framework", rev = "framework/mainnet" }
​
[addresses]
generics = "0x0"

然后执行upgrade命令,这里面填入的就是UpgradeCap objectid

sui client upgrade --upgrade-capability 0x560bf0c92d904b64dc6988c6267b7c869b31e411684e8657ae065b3707d643ad --gas-budget 100000000 --skip-dependency-verification

然后更新合约之后执行解封装

sui client call --package 0x3a00c46eb80db77c807af34b37e8a10c8df5285d6d66b8741a755c73886c566e --module generics --function transfer_value  --args 0xfe8f1d8d3ef7b2da414084a331c8f50ab138cd2483dcd2f82500cb1c382a0b39 --type-args "0x2::coin::Coin<0x2::sui::SUI>" --gas-budget 10000000

然后查看钱包地址,sui已经转移回来了

img

1.3 Witness设计模式

witness合约创建

sui move new witness && cd witnes

新建witness.move

module witness::peace {
        use sui::object::{Self, UID};
        use sui::transfer;
        use sui::tx_context::{Self, TxContext};
​
        /// Phantom parameter T can only be initialized in the `create_guardian`
        /// function. But the types passed here must have `drop`.
        struct Guardian<phantom T: drop> has key, store {
            id: UID
        }
​
        /// This type is the witness resource and is intended to be used only once.
        struct PEACE has drop {}
​
        /// The first argument of this function is an actual instance of the
        /// type T with `drop` ability. It is dropped as soon as received.
        public fun create_guardian<T: drop>(
            _witness: T, ctx: &mut TxContext
        ): Guardian<T> {
            Guardian { id: object::new(ctx) }
        }
​
        /// Module initializer is the best way to ensure that the
        /// code is called only once. With `Witness` pattern it is
        /// often the best practice.
        fun init(witness: PEACE, ctx: &mut TxContext) {
            transfer::transfer(
                create_guardian(witness, ctx),
                tx_context::sender(ctx)
            )
        }
    }

合约部署后init调用create_guardian创建一个Guardian<T>资源实例,即Guardian<PEACE>,_witness 参数:这是一个类型为 T 的参数,传入函数时立即被放弃,这符合传入类型必须具备的 drop 能力。

│  ┌──                                                                                                                                                                                  │
│  │ ObjectID: 0x7197997621b1f8eb4982de7ef39ef5cf9eaa5cdcaea602d5ae57fbd9632c9f03                                                                                                       │
│  │ Sender: 0x21f62d821142d1a72d2b78ce0e3fee2ae01f38293e583c46e9a4be3f91544767                                                                                                         │
│  │ Owner: Account Address ( 0x21f62d821142d1a72d2b78ce0e3fee2ae01f38293e583c46e9a4be3f91544767 )                                                                                      │
│  │ ObjectType: 0x6021c10099a3922849af2a46b8aad983b9e7f66344fa6e5de4d8a59b2b3a43b8::peace::Guardian&lt;0x6021c10099a3922849af2a46b8aad983b9e7f66344fa6e5de4d8a59b2b3a43b8::peace::PEACE>  │
│  │ Version: 1125852                                                                                                                                                                   │
│  │ Digest: 43p1huAqh9gWMNARdpoaA9ThzAPXj2P2h67cSDZBSa5Y                                                                                                                               │
│  └──                                                                                                                                                                                  │

然后查询也可以看到根据代码存储了新建的objectid

        struct Guardian&lt;phantom T: drop> has key, store {
            id: UID
        }

img

在该模式中,可以确保某些行为(比如合约的初始化过程)只被执行一次。

1.4 发布STOMCOIN

新建stomcoin项目,然后新建stomcoin.move

module stomcoin::stomcoin{
    use std::option;
    use sui::coin::{Self, Coin, TreasuryCap};
    use sui::transfer;
    use sui::tx_context::{Self, TxContext};
​
    //coin's name
    struct STOMCOIN has drop {}
​
    //init
    fun init(witness: STOMCOIN,ctx: &mut TxContext) {
        let (treasury_cap,metadata) = coin::create_currency&lt;STOMCOIN>(witness, 2, b"STOMCOIN", b"SC", b"", option::none(), ctx);
        transfer::public_freeze_object(metadata);
        transfer::public_transfer(treasury_cap, tx_context::sender(ctx))
    }
​
    //mint new coins
    public fun mint(
        treasury_cap: &mut TreasuryCap&lt;STOMCOIN>, amount: u64, recipient: address, ctx: &mut TxContext
    ) {
        coin::mint_and_transfer(treasury_cap, amount, recipient, ctx)
    }
​
    //burn coins
    public fun burn(treasury_cap: &mut TreasuryCap&lt;STOMCOIN>, coin: Coin&lt;STOMCOIN>) {
        coin::burn(treasury_cap, coin);
    }
​
    #[test_only]
    // Wrapper of module initializer for testing
    public fun test_init(ctx: &mut TxContext) {
        init(STOMCOIN {}, ctx)
    }
}

部署合约后获取TreacuryCap和packageid

│  ┌──                                                                                                                            │
│  │ ObjectID: 0x10c003a1dbd584a81a3929db3b530e86404c7853b60385227e78bfd61ee49040                                                 │
│  │ Sender: 0x21f62d821142d1a72d2b78ce0e3fee2ae01f38293e583c46e9a4be3f91544767                                                   │
│  │ Owner: Account Address ( 0x21f62d821142d1a72d2b78ce0e3fee2ae01f38293e583c46e9a4be3f91544767 )                                │
│  │ ObjectType: 0x2::coin::TreasuryCap&lt;0x33b47e6048ab066bc17bc444b5593e93e423e685bc17a6576f49aa98948d176f::stomcoin::STOMCOIN>   │
│  │ Version: 1125857                                                                                                             │
│  │ Digest: 9mb2NRB4eyeNEJQPK4WYsDevUnohztkQ5KSU6q4Lf2qr                                                                         │
│  └──
│ Published Objects:                                                                                                              │
│  ┌──                                                                                                                            │
│  │ PackageID: 0x33b47e6048ab066bc17bc444b5593e93e423e685bc17a6576f49aa98948d176f                                                │
│  │ Version: 1                                                                                                                   │
│  │ Digest: E8tcFZCBCAjgRGDtdcjNfsKJgBdNbzEHjuVQrMCweEMq                                                                         │
│  │ Modules: stomcoin                                                                                                            │
│  └──                   

然后通过mint铸造代币

sui client call --package 0x33b47e6048ab066bc17bc444b5593e93e423e685bc17a6576f49aa98948d176f --module stomcoin --function mint --args 0x10c003a1dbd584a81a3929db3b530e86404c7853b60385227e78bfd61ee49040 100000000 0x21f62d821142d1a72d2b78ce0e3fee2ae01f38293e583c46e9a4be3f91544767 --gas-budget 10000000
Transaction Digest: EXMiYy4E4W7sgEes79vbo2HjfpicTsqnzFs9U9W22CYK

然后账户地址下就有了自己发布的代币

img

1.5 发布STOMLOCKCOIN

module stomlockcoin::stomlockcoin{
    use std::option;
    use sui::transfer;
    use sui::object::{Self, UID};
    use sui::tx_context::{sender, TxContext};
    use sui::coin::{Self, TreasuryCap};
    use sui::balance::{Self, Balance};
    use sui::clock::{Self, Clock};

    // Transferrable object for storing the vesting coins
​
    struct Locker has key, store {
        id: UID,
        start_date: u64,
        final_date: u64,
        original_balance: u64,
        current_balance: Balance&lt;STOMLOCKCOIN>
​
    }
​
    // Witness
    struct STOMLOCKCOIN has drop {}
​
    // Withdraw the available vested amount assuming linear vesting
    #[lint_allow(self_transfer)]
    public fun withdraw_vested(locker: &mut Locker, clock: &Clock, ctx: &mut TxContext){
        let total_duration = locker.final_date - locker.start_date;
        let elapsed_duration = clock::timestamp_ms(clock) - locker.start_date;
        let total_vested_amount = if (elapsed_duration > total_duration) {
            locker.original_balance
        } else {
            locker.original_balance * elapsed_duration / total_duration
        };
        let available_vested_amount = total_vested_amount - (locker.original_balance-balance::value(&locker.current_balance));
        transfer::public_transfer(coin::take(&mut locker.current_balance, available_vested_amount, ctx), sender(ctx))
    }
​
    fun init(otw: STOMLOCKCOIN, ctx: &mut TxContext){
        let (treasury_cap, metadata) = coin::create_currency&lt;STOMLOCKCOIN>(otw, 8, b"STOMLOCKCOIN", b"SLC", b"", option::none(), ctx);
        transfer::public_freeze_object(metadata);
        transfer::public_transfer(treasury_cap, sender(ctx))
    }
​
    // Mints and transfers a locker object with the input amount of coins and specified vesting schedule
​
    public fun locked_mint(treasury_cap: &mut TreasuryCap&lt;STOMLOCKCOIN>, recipient: address, amount: u64, lock_up_duration: u64, clock: &Clock, ctx: &mut TxContext){

        let coin = coin::mint(treasury_cap, amount, ctx);
        let start_date = clock::timestamp_ms(clock);
        let final_date = start_date + lock_up_duration;
​
        transfer::public_transfer(Locker {
            id: object::new(ctx),
            start_date: start_date,
            final_date: final_date,
            original_balance: amount,
            current_balance: coin::into_balance(coin)
        }, recipient);
    }
​

    #[test_only]
    public fun test_init(ctx: &mut TxContext) {
        init(STOMLOCKCOIN {}, ctx)
    }
​
​
}

部署合约

│ Published Objects:                                                                                                                      │
│  ┌──                                                                                                                                    │
│  │ PackageID: 0x61bb5e5be66748013c6b65f1096329cbcaa29c537cbe12b1fa28d2dcb9e2c3c2                                                        │
│  │ Version: 1                                                                                                                           │
│  │ Digest: 2JdGqWfBaGDJL2F7VuP7h5wMaRozhEzjMHLi9ZVGjsHY                                                                                 │
│  │ Modules: stomlockcoin                                                                                                                │
│  └──                                                                                                                                    │

然后铸造代币

│  ┌──                                                                                                                                    │
│  │ ObjectID: 0x34fcaad32fb7672767d571109803f143392c62aeaee9c99dd084e36174f67015                                                         │
│  │ Sender: 0x21f62d821142d1a72d2b78ce0e3fee2ae01f38293e583c46e9a4be3f91544767                                                           │
│  │ Owner: Account Address ( 0x21f62d821142d1a72d2b78ce0e3fee2ae01f38293e583c46e9a4be3f91544767 )                                        │
│  │ ObjectType: 0x2::coin::TreasuryCap&lt;0x61bb5e5be66748013c6b65f1096329cbcaa29c537cbe12b1fa28d2dcb9e2c3c2::stomlockcoin::STOMLOCKCOIN>   │
│  │ Version: 1125859                                                                                                                     │
│  │ Digest: 4hQKwVjK4Wq1ouTwwrgY1MtLB53w3Eq8qAwGddqDQsa8                                                                                 │
│  └──                                                                                                                                    │

调用后会创建一个Locker,这里我设置的是10ms的锁定时间,锁定了数量balance:100000000

img

然后时间到了之后提取锁定的STOMLOCKCOIN

sui client call --package 0x61bb5e5be66748013c6b65f1096329cbcaa29c537cbe12b1fa28d2dcb9e2c3c2 --module stomlockcoin --function locked_mint --args 0x34fcaad32fb7672767d571109803f143392c62aeaee9c99dd084e36174f67015 0x21f62d821142d1a72d2b78ce0e3fee2ae01f38293e583c46e9a4be3f91544767 100000000 10 0x6 --gas-budget 10000000
│                                                                                                                                        │
│ Created Objects:                                                                                                                       │
│  ┌──                                                                                                                                   │
│  │ ObjectID: 0xbdfe2a3e1d1e1a4ec1ff4bb1635ed93966c6e2d2e0894cdbc18ebbf92691bbd3                                                        │
│  │ Sender: 0x21f62d821142d1a72d2b78ce0e3fee2ae01f38293e583c46e9a4be3f91544767                                                          │
│  │ Owner: Account Address ( 0x21f62d821142d1a72d2b78ce0e3fee2ae01f38293e583c46e9a4be3f91544767 )                                       │
│  │ ObjectType: 0x61bb5e5be66748013c6b65f1096329cbcaa29c537cbe12b1fa28d2dcb9e2c3c2::stomlockcoin::Locker                                │
│  │ Version: 22846350                                                                                                                   │
│  │ Digest: 9zBL51hBKP4ZnDwhdH6ndsmL9u3a1WRtT4iMbBsu3Fnm  

查询账户下已经有了刚才被锁定的代币

img

Sui move_cn社交账号

telegram: https://t.me/move_cn

X(twitter): https://twitter.com/move_cn

QQ群: 79489587

微信公众号:Move中文

Sui中文开发群: https://t.me/sui_dev_cn

  • 原创
  • 学分: 8
  • 分类: Sui
  • 标签:
点赞 1
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。
5 订阅 9 篇文章

0 条评论

请先 登录 后评论
stom698
stom698
0x06CC...099B
努力提升