Try   HackMD

IPFS介紹

我們這次要使用IPFS(Pinata)來存放我們的Coin圖示。

有關IPFS以及Pinata介紹,請看這篇文章 IPFS介紹

上傳圖片至Pinata

我們使用Pinata當作我們儲存圖片的IPFS系統。

Pinata上傳圖片頁面

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

首先我們點選右上角的 "Add Files" 按鈕,然後點選 "File",會有上傳視窗讓你選擇圖片。

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

這邊可以隨意上傳隨便一張圖片,GIF檔也可以。
這邊我用Co-Sui讀書會的icon當作Coin的圖示。

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

上傳好後,我們可以看到有出現我們剛剛上傳的檔案,待會會用到。

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

智能合約程式範例

TODO部分可以自定義

module workshop::mycoin {
    use std::option;
    use sui::coin::{Self, Coin, TreasuryCap};
    use sui::transfer;
    use sui::tx_context::{Self, TxContext};
    use sui::url::{Self};

    // One Time Witness
    struct MYCOIN has drop {}

    fun init(witness: MYCOIN, ctx: &mut TxContext) {

        // TODO
        let decimals = 9;
        let symbol = b"RC";
        let name = b"Ryan Coin";
        let description = b"Ryan Coin Demo Test";
        let icon_url = url::new_unsafe_from_bytes(b"https://pin.ski/3PKHM4G");

        let (treasury, metadata) = coin::create_currency(witness, decimals, symbol, name, description, option::some(icon_url), ctx);
        transfer::public_freeze_object(metadata);
        // transfer::public_share_object(metadata);
        transfer::public_transfer(treasury, tx_context::sender(ctx));
    }

    public entry fun mint(
        treasury_cap: &mut TreasuryCap<MYCOIN>, amount: u64, recipient: address, ctx: &mut TxContext
    ) {
        coin::mint_and_transfer(treasury_cap, amount, recipient, ctx)
    }

    public entry fun burn(treasury_cap: &mut TreasuryCap<MYCOIN>, coin: Coin<MYCOIN>) {
        coin::burn(treasury_cap, coin);
    }
}

編譯程式(查看有沒有Error)

PS D:\vscode\workspace\workshop> sui move build
UPDATING GIT DEPENDENCY https://github.com/MystenLabs/sui.git
INCLUDING DEPENDENCY Sui
INCLUDING DEPENDENCY MoveStdlib
BUILDING workshop

部署程式

PS D:\vscode\workspace\workshop> sui client publish --gas-budget 100000000
UPDATING GIT DEPENDENCY https://github.com/MystenLabs/sui.git
INCLUDING DEPENDENCY Sui
INCLUDING DEPENDENCY MoveStdlib
BUILDING workshop
Successfully verified dependencies on-chain against source.
----- Transaction Digest ----
EjJdQhCvzP5gaWGuTCM1BAyJdn1nYRE22L86DDWFmTnr
----- Transaction Data ----
Transaction Signature: [Signature(Ed25519SuiSignature(Ed25519SuiSignature([0, 253, 145, 79, 231, 142, 0, 169, 64, 119, 206, 209, 206, 44, 47, 30, 185, 82, 13, 76, 233, 184, 193, 68, 128, 69, 178, 57, 216, 174, 120, 201, 157, 74, 78, 33, 141, 32, 147, 190, 228, 43, 250, 60, 64, 35, 69, 34, 155, 180, 50, 202, 136, 150, 13, 100, 219, 15, 180, 145, 238, 20, 75, 179, 5, 247, 100, 111, 221, 105, 109, 168, 119, 191, 214, 73, 60, 87, 207, 170, 217, 25, 125, 35, 32, 56, 114, 200, 3, 129, 122, 80, 229, 159, 146, 202, 222])))]
Transaction Kind : Programmable
Inputs: [Pure(SuiPureValue { value_type: Some(Address), value: "0xd1c4d5d9115d8aa9de808eb59c0f2cf614a67ca26f9759b1d07b56fe9fc612c7" })]
Commands: [
  Publish(<modules>,0x0000000000000000000000000000000000000000000000000000000000000001,0x0000000000000000000000000000000000000000000000000000000000000002),
  TransferObjects([Result(0)],Input(0)),
]

Sender: 0xd1c4d5d9115d8aa9de808eb59c0f2cf614a67ca26f9759b1d07b56fe9fc612c7
Gas Payment: Object ID: 0x8a371ba703f4f23b2b72059a8bdcd5b051797e4bba1d46e080b35e89c2cfe298, version: 0x10d4e7, digest: 2kjVgy9FxuV8yfbv17hnLZixrWGqshXQtuWSJHqhZLXB
Gas Owner: 0xd1c4d5d9115d8aa9de808eb59c0f2cf614a67ca26f9759b1d07b56fe9fc612c7
Gas Price: 1000
Gas Budget: 100000000

----- Transaction Effects ----
Status : Success
Created Objects:
  - ID: 0x5c9ee5742dc91d70ca2eb770d7b4163f2c15f5110ecbdeed80169d0048214a8e , Owner: Account Address ( 0xd1c4d5d9115d8aa9de808eb59c0f2cf614a67ca26f9759b1d07b56fe9fc612c7 )
  - ID: 0xa555e59ec6b991743704ddf9c76dd4f010b1e128a1e248c433ffea93071adcc1 , Owner: Account Address ( 0xd1c4d5d9115d8aa9de808eb59c0f2cf614a67ca26f9759b1d07b56fe9fc612c7 )
  - ID: 0xda67a492f9a8132e85a985b7853f70b008877f04439a62a55b75da27b2879a2e , Owner: Immutable
  - ID: 0xee7e173dc96e999bccb34c11ac445d2bae82605ee14c1d93abadbefc706fcfa0 , Owner: Immutable
Mutated Objects:
  - ID: 0x8a371ba703f4f23b2b72059a8bdcd5b051797e4bba1d46e080b35e89c2cfe298 , Owner: Account Address ( 0xd1c4d5d9115d8aa9de808eb59c0f2cf614a67ca26f9759b1d07b56fe9fc612c7 )

----- Events ----
Array []
----- Object changes ----
Array [
    Object {
        "type": String("mutated"),
        "sender": String("0xd1c4d5d9115d8aa9de808eb59c0f2cf614a67ca26f9759b1d07b56fe9fc612c7"),
        "owner": Object {
            "AddressOwner": String("0xd1c4d5d9115d8aa9de808eb59c0f2cf614a67ca26f9759b1d07b56fe9fc612c7"),
        },
        "objectType": String("0x2::coin::Coin<0x2::sui::SUI>"),
        "objectId": String("0x8a371ba703f4f23b2b72059a8bdcd5b051797e4bba1d46e080b35e89c2cfe298"),
        "version": String("1103080"),
        "previousVersion": String("1103079"),
        "digest": String("5E5D7ued9SMTLZGPedufV3sDVCXUAi6b8tGCrPbxcTCX"),
    },
    Object {
        "type": String("created"),
        "sender": String("0xd1c4d5d9115d8aa9de808eb59c0f2cf614a67ca26f9759b1d07b56fe9fc612c7"),
        "owner": Object {
            "AddressOwner": String("0xd1c4d5d9115d8aa9de808eb59c0f2cf614a67ca26f9759b1d07b56fe9fc612c7"),
        },
        "objectType": String("0x2::coin::TreasuryCap<0xee7e173dc96e999bccb34c11ac445d2bae82605ee14c1d93abadbefc706fcfa0::mycoin::MYCOIN>"),
        "objectId": String("0x5c9ee5742dc91d70ca2eb770d7b4163f2c15f5110ecbdeed80169d0048214a8e"),
        "version": String("1103080"),
        "digest": String("7DTUyYZ7KTfVpZRVLw8RGQTYWnAfgTCzGZTZ8J6DVomd"),
    },
    Object {
        "type": String("created"),
        "sender": String("0xd1c4d5d9115d8aa9de808eb59c0f2cf614a67ca26f9759b1d07b56fe9fc612c7"),
        "owner": Object {
            "AddressOwner": String("0xd1c4d5d9115d8aa9de808eb59c0f2cf614a67ca26f9759b1d07b56fe9fc612c7"),
        },
        "objectType": String("0x2::package::UpgradeCap"),
        "objectId": String("0xa555e59ec6b991743704ddf9c76dd4f010b1e128a1e248c433ffea93071adcc1"),
        "version": String("1103080"),
        "digest": String("CNehnr5PwZXnZ9bsoTmaBo9Fjn2EovX52h6w6siYPbqX"),
    },
    Object {
        "type": String("created"),
        "sender": String("0xd1c4d5d9115d8aa9de808eb59c0f2cf614a67ca26f9759b1d07b56fe9fc612c7"),
        "owner": String("Immutable"),
        "objectType": String("0x2::coin::CoinMetadata<0xee7e173dc96e999bccb34c11ac445d2bae82605ee14c1d93abadbefc706fcfa0::mycoin::MYCOIN>"),
        "objectId": String("0xda67a492f9a8132e85a985b7853f70b008877f04439a62a55b75da27b2879a2e"),
        "version": String("1103080"),
        "digest": String("ChNW1XZpgaU6F6PYaWGjXiu2ivK8FkQuN86kyLc6F9Ms"),
    },
    Object {
        "type": String("published"),
        "packageId": String("0xee7e173dc96e999bccb34c11ac445d2bae82605ee14c1d93abadbefc706fcfa0"),
        "version": String("1"),
        "digest": String("KZ7sctkfzAC44d26oYfQcJRLPpUfEF551XEZ4WzEab4"),
        "modules": Array [
            String("mycoin"),
        ],
    },
]
----- Balance changes ----
Array [
    Object {
        "owner": Object {
            "AddressOwner": String("0xd1c4d5d9115d8aa9de808eb59c0f2cf614a67ca26f9759b1d07b56fe9fc612c7"),
        },
        "coinType": String("0x2::sui::SUI"),
        "amount": String("-14644280"),
    },
]

使用 Sui 瀏覽器 查看我們剛剛所建立的CoinMetadata

Object {
        "type": String("created"),
        "sender": String("0xd1c4d5d9115d8aa9de808eb59c0f2cf614a67ca26f9759b1d07b56fe9fc612c7"),
        "owner": String("Immutable"),
        "objectType": String("0x2::coin::CoinMetadata<0xee944f1737dd012eddb5d4860e1363bed3b70c5b8faeb9daddbcb25511e222f9::mycoin::MYCOIN>"),
        "objectId": String("0x45ee1c055e175876a994f2db6cdf4e252f2f117c91c8a192feb5cd9b9a5423cc"),
        "version": String("1103081"),
        "digest": String("7MfpJNWRNka6UHwXWCysSDF4M2NwRQ29NevWRfrVBREF"),
    },

找到objectType為 0x2:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
:CoinMetadata
使用objectId查該物件的詳細資料

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

可以發現我們剛剛建立的同質化代幣的詳細資料,該Object是被公開且不可更改的。

接下來我們去查剛剛部署的合約,Mint Token給自己。

Object {
        "type": String("published"),
        "packageId": String("0xee944f1737dd012eddb5d4860e1363bed3b70c5b8faeb9daddbcb25511e222f9"),
        "version": String("1"),
        "digest": String("D2h9P8rr7v5Rv7KWbBFDr1dfubWrttenZWy8zZNdHcWB"),
        "modules": Array [
            String("mycoin"),
        ],
    },

找到type為 String("published")
使用packageId查該合約的詳細資料

接下來使用mint這個方法

Arg0帶入TreasuryCap的objectId

Object {
        "type": String("created"),
        "sender": String("0xd1c4d5d9115d8aa9de808eb59c0f2cf614a67ca26f9759b1d07b56fe9fc612c7"),
        "owner": Object {
            "AddressOwner": String("0xd1c4d5d9115d8aa9de808eb59c0f2cf614a67ca26f9759b1d07b56fe9fc612c7"),
        },
        "objectType": String("0x2::coin::TreasuryCap<0xee944f1737dd012eddb5d4860e1363bed3b70c5b8faeb9daddbcb25511e222f9::mycoin::MYCOIN>"),
        "objectId": String("0x52c28b8067f800286b4c9fb50a871212694203c26bf06861fb2309d40d08edf6"),
        "version": String("1103081"),
        "digest": String("BnGax56XVN8GkC6biqxWzqY5TrZ3SaveTpjTFLhZR1o7"),
    },

Arg1帶入要mint的金額,因為上面設定1個Token為1x10的9次方,所以假如要mint 20個Token給自己,要輸入20然後後面9個0,也就是20000000000。

Arg2帶入要Mint給哪個錢包地址。

可以看到Ryan Coin(name) +20 RC(symbol),以及icon圖示

錢包也可以看到Ryan Coin目前有20個RC

銷毀Token

Arg0帶入TreasuryCap的objectId

Object {
        "type": String("created"),
        "sender": String("0xd1c4d5d9115d8aa9de808eb59c0f2cf614a67ca26f9759b1d07b56fe9fc612c7"),
        "owner": Object {
            "AddressOwner": String("0xd1c4d5d9115d8aa9de808eb59c0f2cf614a67ca26f9759b1d07b56fe9fc612c7"),
        },
        "objectType": String("0x2::coin::TreasuryCap<0xee944f1737dd012eddb5d4860e1363bed3b70c5b8faeb9daddbcb25511e222f9::mycoin::MYCOIN>"),
        "objectId": String("0x52c28b8067f800286b4c9fb50a871212694203c26bf06861fb2309d40d08edf6"),
        "version": String("1103081"),
        "digest": String("BnGax56XVN8GkC6biqxWzqY5TrZ3SaveTpjTFLhZR1o7"),
    },

Arg1要帶入要銷毀Coin的objectId

會發現我們錢包已經把那20個Ryan Coin銷毀了