## Gear 合约开发案例解析 - Fungible Token <p align="center"> <a href="https://gitpod.io/#https://github.com/gear-dapps/fungible-token"> <img src="https://gitpod.io/button/open-in-gitpod.svg" width="240" alt="GEAR"> </a> </p> https://github.com/gear-dapps/fungible-token <!-- - https://github.com/gear-dapps/sharded-fungible-token --> --- ![](https://hackmd.io/_uploads/rk89tGEHh.png) --- ## ERC20 标准 https://eips.ethereum.org/EIPS/eip-20 - name: `My Token` - symbol: `HEX` - decimals: `10` - totalSupply: 10000000000 - balanceOf(address _owner) - allowance(address _owner, address _spender) - transferFrom(address _from, address _to, uint256 _value) - approve(address _spender, uint256 _value) --- <p align="center"> <a href="https://gitpod.io/#https://github.com/gear-dapps/fungible-token"> <img src="https://gitpod.io/button/open-in-gitpod.svg" width="240" alt="GEAR"> </a> </p> --- ## build ``` $ make init $ make build ``` ## download ``` ./target/wasm32-unknown-unknown/release/ft_state.meta.wasm ./target/wasm32-unknown-unknown/release/fungible_token.opt.wasm ./fungible_token.meta.txt ``` ## deploy https://idea.gear-tech.io/ --- [![](https://hackmd.io/_uploads/HkUh-QNHh.png)](https://idea.gear-tech.io/programs/0x5217fc6ef47a7779033835148f76a4da73ae53eca50626471a95ac17f2113efd?node=wss%3A%2F%2Frpc-node.gear-tech.io) --- [![](https://hackmd.io/_uploads/SyG_XQEH2.png)](https://idea.gear-tech.io/send/message/0x5217fc6ef47a7779033835148f76a4da73ae53eca50626471a95ac17f2113efd?node=wss%3A%2F%2Frpc-node.gear-tech.io) --- [![](https://hackmd.io/_uploads/SJy7QXVBn.png)](https://idea.gear-tech.io/state/full/0x5217fc6ef47a7779033835148f76a4da73ae53eca50626471a95ac17f2113efd?node=wss%3A%2F%2Frpc-node.gear-tech.io) --- ## State ./src/contract.rs ``` static mut FUNGIBLE_TOKEN: Option<FungibleToken> = None; struct FungibleToken { /// Name of the token. name: String, /// Symbol of the token. symbol: String, /// Total supply of the token. total_supply: u128, /// Map to hold balances of token holders. balances: HashMap<ActorId, u128>, /// Map to hold allowance information of token holders. allowances: HashMap<ActorId, HashMap<ActorId, u128>>, /// Token's decimals. pub decimals: u8, } ``` --- ## Metadata ./io/src/lib.rs ``` pub struct FungibleTokenMetadata; impl Metadata for FungibleTokenMetadata { type Init = In<InitConfig>; type Handle = InOut<FTAction, FTEvent>; ... } ``` --- ## Init ./io/src/lib.rs ``` pub struct InitConfig { pub name: String, pub symbol: String, pub decimals: u8, } ``` --- ./src/lib.rs ``` #[no_mangle] extern "C" fn init() { let config: InitConfig = msg::load().expect("Unable to decode InitConfig"); let ft = FungibleToken { name: config.name, symbol: config.symbol, decimals: config.decimals, ..Default::default() }; unsafe { FUNGIBLE_TOKEN = Some(ft) }; } ``` --- ## Handle ./io/src/lib.rs ``` pub enum FTAction { Mint(u128), Burn(u128), Transfer { from: ActorId, to: ActorId, amount: u128, }, Approve { to: ActorId, amount: u128, }, TotalSupply, BalanceOf(ActorId), } ``` --- ./io/src/lib.rs ``` pub enum FTEvent { Transfer { from: ActorId, to: ActorId, amount: u128, }, Approve { from: ActorId, to: ActorId, amount: u128, }, TotalSupply(u128), Balance(u128), } ``` --- ./src/contract.rs ``` #[no_mangle] extern "C" fn handle() { let action: FTAction = msg::load().expect("Could not load Action"); let ft: &mut FungibleToken = unsafe { FUNGIBLE_TOKEN.get_or_insert(Default::default()) }; match action { FTAction::Mint(amount) => { ft.mint(amount); } FTAction::Burn(amount) => { ft.burn(amount); } FTAction::Transfer { from, to, amount } => { ft.transfer(&from, &to, amount); } FTAction::Approve { to, amount } => { ft.approve(&to, amount); } FTAction::TotalSupply => { msg::reply(FTEvent::TotalSupply(ft.total_supply), 0).unwrap(); } FTAction::BalanceOf(account) => { let balance = ft.balances.get(&account).unwrap_or(&0); msg::reply(FTEvent::Balance(*balance), 0).unwrap(); } } } ``` --- ## Contract ./src/contract.rs ``` impl FungibleToken { /// Executed on receiving `fungible-token-messages::MintInput`. fn mint(&mut self, amount: u128) { ... } /// Executed on receiving `fungible-token-messages::BurnInput`. fn burn(&mut self, amount: u128) { ... } /// Executed on receiving `fungible-token-messages::TransferInput` or `fungible-token-messages::TransferFromInput`. /// Transfers `amount` tokens from `sender` account to `recipient` account. fn transfer(&mut self, from: &ActorId, to: &ActorId, amount: u128) { ... } /// Executed on receiving `fungible-token-messages::ApproveInput`. fn approve(&mut self, to: &ActorId, amount: u128) { ... } fn can_transfer(&mut self, from: &ActorId, amount: u128) -> bool { ... } } ``` --- ## 课后作业 Fork https://github.com/gear-dapps/fungible-token 实现: ``` - 限制任意账户调用 mint 方法 - 为 `FungibleToken` 添加 admin 字段 - 在合约 init 函数中设置 admin = msg::source() - 在 `FungibleToken` 的 init 方法中确保用户为 admin,否则 panic ``` 在 [Gear IDEA](https://idea.gear-tech.io/) 上部署你的 Fork 提交 Fork 仓库地址及合约访问链接 作业提交频道: https://t.me/Gear_CN
{"metaMigratedAt":"2023-06-18T04:38:31.032Z","metaMigratedFrom":"YAML","title":"Untitled","breaks":false,"slideOptions":"{\"theme\":\"moon\",\"spotlight\":{\"enabled\":false}}","contributors":"[{\"id\":\"94262fbf-81ae-4ed7-933c-561a41bd977a\",\"add\":10250,\"del\":5951}]"}
    211 views