Coin & ERC20
很多学过其他智能合约编程语言的,或者对以太坊比较了解的,学习Sui Move的时候 经常会问,Sui Move的REC20,简单么,怎么实现?
什么是ERC20
-
ERC-20就是一套基于以太坊网络的标准代币发行协议。 其中的ERC是"EthereumRequest for Comment"也就是“以太坊征求意见协议”的缩写。 和其他的开源社区一样,以太坊会使用这样的方式收集开发者的反馈、并在批准后作为后续开发的执行标准。 正是因为有了ERC-20,开发者们得以高效、可靠、低成本地创造专属自己项目的代币。
-
如果我们把众多区块链项目的开发者,看作是在一个小区门口商铺里,经营不同业态的众多商户。 这些商户根据自己的专长提供各自不同的商品和服务,也都希望发行自己店铺专属的消费储值卡。方便消费者光顾的同时,也能提升用户的体验和粘性。 如果我们把众多区块链项目的开发者,看作是在一个小区门口商铺里,经营不同业态的众多商户。这些商户根据自己的专长提供各自不同的商品和服务,也都希望发行自己店铺专属的消费储值卡。
-
方便消费者光顾的同时,也能提升用户的体验和粘性。
-
它提供一整套标准化的储值卡发放协议和配套服务。借助这套叫做ERC-20的整体解决方案,
-
每个商户(开发者)都可以傻瓜式地发行专属于自己店铺的消费储值卡,同时由于这种储值卡采用了统一的协议,可以非常方便地和其他商户的储值卡做无缝兑换。
-
于是借助ERC-20,用户可以通过持有其中一种储值卡(token)很方便地享受整个生态的各种服务;商户(开发者)则节约了开发运营成本、同时提升了获取用户的效率;而物业公司(以太坊基金会和矿工)则可以通过做大生态体量实现更多的租金(ETH增值)和储值卡结算手续费(Gas费用)收入。
-
ERC-20就是用这种做大生态价值的方式,实现了用户、开发者和以太坊网络三方面的共赢
Sui Move Coin
- 正式因为ERC20的影响力非常的大,后续出现的公链或多或少的都受到了以太坊ERC20的影响,Sui Move也buliw ,但是Move面向资产和所有权的模型,还有很多Sui Move 独有的东西比如object,让ERC20来Sui上对应的Coin协议 有了很大创新和不同,总结起来就是使用的时候更简单,和更加通用了
发行一个Sui Move Coin
很多人没有接触过Move的coin协议 (类似ERC20),我们先不关注里面的概念先从第一个Sui Move Coin的例子开始学习Sui Move的coin协议
module examples::mycoin {
use std::option;
use sui::coin;
use sui::transfer;
use sui::tx_context::{Self, TxContext};
/// The type identifier of coin. The coin will have a type
/// tag of kind: `Coin<package_object::mycoin::MYCOIN>`
/// Make sure that the name of the type matches the module's name.
public struct MYCOIN has drop {}
/// Module initializer is called once on module publish. A treasury
/// cap is sent to the publisher, who then controls minting and burning
fun init(witness: MYCOIN, ctx: &mut TxContext) {
let (treasury, metadata) = coin::create_currency(witness, 6, b"MYCOIN", b"", b"", option::none(), ctx);
transfer::public_freeze_object(metadata);
transfer::public_transfer(treasury, tx_context::sender(ctx))
}
}
- from https://examples.sui.io mycoin
module sui::coin {
/// A coin of type `T` worth `value`. Transferable and storable
struct Coin<phantom T> has key, store {
id: UID,
balance: Balance<T>
}
public struct CoinMetadata<phantom T> has key, store {
id: UID,
/// Number of decimal places the coin uses.
/// A coin with `value ` N and `decimals` D should be shown as N / 10^D
/// E.g., a coin with `value` 7002 and decimals 3 should be displayed as 7.002
/// This is metadata for display usage only.
decimals: u8,
/// Name for the token
name: string::String,
/// Symbol for the token
symbol: ascii::String,
/// Description of the token
description: string::String,
/// URL for the token logo
icon_url: Option<Url>
}
/// Capability allowing the bearer to mint and burn
/// coins of type `T`. Transferable
public struct TreasuryCap<phantom T> has key, store {
id: UID,
total_supply: Supply<T>
}
public fun treasury_into_supply<T>(treasury: TreasuryCap<T>): Supply<T> {
let TreasuryCap { id, total_supply } = treasury;
object::delete(id);
total_supply
}
public fun create_currency<T: drop>(
witness: T,
decimals: u8,
symbol: vector<u8>,
name: vector<u8>,
description: vector<u8>,
icon_url: Option<Url>,
ctx: &mut TxContext
): (TreasuryCap<T>, CoinMetadata<T>) {
// Make sure there's only one instance of the type T
assert!(sui::types::is_one_time_witness(&witness), EBadWitness);
(
TreasuryCap {
id: object::new(ctx),
total_supply: balance::create_supply(witness)
},
CoinMetadata {
id: object::new(ctx),
decimals,
name: string::utf8(name),
symbol: ascii::string(symbol),
description: string::utf8(description),
icon_url
}
)
}
/// Create a coin worth `value`. and increase the total supply
/// in `cap` accordingly.
public fun mint<T>(
cap: &mut TreasuryCap<T>, value: u64, ctx: &mut TxContext,
): Coin<T> {
Coin {
id: object::new(ctx),
balance: balance::increase_supply(&mut cap.total_supply, value)
}
}
/// Destroy the coin `c` and decrease the total supply in `cap`
/// accordingly.
public entry fun burn<T>(cap: &mut TreasuryCap<T>, c: Coin<T>): u64 {
let Coin { id, balance } = c;
object::delete(id);
balance::decrease_supply(&mut cap.total_supply, balance)
}
}
module sui::balance {
use sui::tx_context::{Self, TxContext};
/// For when trying to destroy a non-zero balance.
const ENonZero: u64 = 0;
/// For when an overflow is happening on Supply operations.
const EOverflow: u64 = 1;
/// A Supply of T. Used for minting and burning.
/// Wrapped into a `TreasuryCap` in the `Coin` module.
public struct Supply<phantom T> has store {
value: u64
}
/// Storable balance - an inner struct of a Coin type.
/// Can be used to store coins which don't need the key ability.
public struct Balance<phantom T> has store {
value: u64
}
/// Create a new supply for type T.
public fun create_supply<T: drop>(_: T): Supply<T> {
Supply { value: 0 }
}
/// Increase supply by `value` and create a new `Balance<T>` with this value.
public fun increase_supply<T>(self: &mut Supply<T>, value: u64): Balance<T> {
assert!(value < (18446744073709551615u64 - self.value), EOverflow);
self.value = self.value + value;
Balance { value }
}
/// Burn a Balance<T> and decrease Supply<T>.
public fun decrease_supply<T>(self: &mut Supply<T>, balance: Balance<T>): u64 {
let Balance { value } = balance;
assert!(self.value >= value, EOverflow);
self.value = self.value - value;
value
}
}
如何发行一个由一个地址控制mint和销毁的 Coin
初始化
module examples::mycoin {
use std::option;
use sui::coin;
use sui::transfer;
use sui::tx_context::{Self, TxContext};
/// The type identifier of coin. The coin will have a type
/// tag of kind: `Coin<package_object::mycoin::MYCOIN>`
/// Make sure that the name of the type matches the module's name.
public struct MYCOIN has drop {}
/// Module initializer is called once on module publish. A treasury
/// cap is sent to the publisher, who then controls minting and burning
fun init(witness: MYCOIN, ctx: &mut TxContext) {
let (treasury, metadata) = coin::create_currency(witness, 6, b"MYCOIN", b"", b"", option::none(), ctx);
transfer::public_freeze_object(metadata);
transfer::public_transfer(treasury, tx_context::sender(ctx))
}
}
上述代码将 treasury cap 发送给发行者,发行者可以mint和burn
铸造 mint
public entry fun mint(
treasury_cap: &mut TreasuryCap<MYCOIN>,
amount: u64,
recipient: address,
ctx: &mut TxContext,
) {
let coin = coin::mint(treasury_cap, amount, ctx);
transfer::public_transfer(coin, recipient)
}
销毁 Coin
需要传入之前生成的 treasury cap id
函数原型
public entry fun burn<T>(cap: &mut TreasuryCap<T>, c: Coin<T>): u64 {
let Coin { id, balance } = c;
id.delete();
cap.total_supply.decrease_supply(balance)
}
如何发行一个水龙头Coin
module examples::mycoin {
use std::option;
use sui::coin;
use sui::transfer;
use sui::tx_context::{Self, TxContext};
/// The type identifier of coin. The coin will have a type
/// tag of kind: `Coin<package_object::mycoin::MYCOIN>`
/// Make sure that the name of the type matches the module's name.
public struct MYCOIN has drop {}
/// Module initializer is called once on module publish. A treasury
/// cap is sent to the publisher, who then controls minting and burning
fun init(witness: MYCOIN, ctx: &mut TxContext) {
let (treasury, metadata) = coin::create_currency(witness, 6, b"MYCOIN", b"", b"", option::none(), ctx);
transfer::public_freeze_object(metadata);
transfer::public_share_object(treasury)
}
public fun mint(
treasury_cap: &mut TreasuryCap<MYCOIN>,
amount: u64,
recipient: address,
ctx: &mut TxContext,
) {
let coin = coin::mint(treasury_cap, amount, ctx);
transfer::public_transfer(coin, recipient)
}
}
如何限制最大供应量
我们用SUI Token发行的例子来说说明
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0
/// Coin<SUI> is the token used to pay for gas in Sui.
/// It has 9 decimals, and the smallest unit (10^-9) is called "mist".
module sui::sui {
use std::option;
use sui::tx_context::{Self, TxContext};
use sui::balance::{Self, Balance};
use sui::transfer;
use sui::coin;
const EAlreadyMinted: u64 = 0;
/// Sender is not @0x0 the system address.
const ENotSystemAddress: u64 = 1;
/// The total supply of Sui denominated in Mist (10 Billion * 10^9)
const TOTAL_SUPPLY_MIST: u64 = 10_000_000_000_000_000_000;
/// Name of the coin
public struct SUI has drop {}
/// Register the `SUI` Coin to acquire its `Supply`.
/// This should be called only once during genesis creation.
fun new(ctx: &mut TxContext): Balance<SUI> {
assert!(tx_context::sender(ctx) == @0x0, ENotSystemAddress);
assert!(tx_context::epoch(ctx) == 0, EAlreadyMinted);
let (treasury, metadata) = coin::create_currency(
SUI {},
9,
b"SUI",
b"Sui",
// TODO: add appropriate description and logo url
b"",
option::none(),
ctx
);
transfer::public_freeze_object(metadata);
let supply = coin::treasury_into_supply(treasury);
let total_sui = balance::increase_supply(&mut supply, TOTAL_SUPPLY_MIST);
balance::destroy_supply(supply);
total_sui
}
}
如何按经济模型锁仓
-
涉及到锁仓的操作一般都会吧Coin 转成 Balance 存储在合约里面
-
涉及动态mint挖矿的一把都会把 TreasuryCap 转成 Supply 把 Supply 锁定在合约里面 并且做好限制
通用的锁仓例子