{"content":{"title":"sui move 动态字段练习(4)","body":"## 引言\r\n学习了sui move中的动态字段，table，bag，作为练习，我准备使用它们模拟solidity中的映射类型，在sui move实现一个**类似**erc20的同质化代币作为之前学习的实践与巩固。本文分享了练习过程中的重构，事件和错误。\r\n注：本例实现仅用于学习动态字段，由于访问gas和便捷性不强，无法用于生产。在sui move中使用的同质化代币请使用官方标准库中内置的coin  \r\n\r\n## 事件和错误\r\n我们需要定义一些事件，在资产转移的时候触发，以便链下能够快速监控  \r\n### Transfer事件  \r\n```rust\r\n    struct Transfer has copy, drop {\r\n        from: address,\r\n        to: address,\r\n        value: u64,\r\n    }\r\n```\r\n\r\nTransfer事件将会在转账，铸造和销毁交易中被触发  \r\n1. 在转账交易中，from，to均不能为0  \r\n2. 在铸币交易中，from为0地址  \r\n3. 在销毁交易中，to为0地址  \r\n\r\n### Approve事件\r\n```rust\r\n    struct Approve has copy, drop {\r\n        owner: address,\r\n        spender: address,\r\n        value: u64,\r\n    }\r\n```\r\nApprove事件将会在授权被变更时被触发  \r\n\r\n### error\r\n我们需要一些错误，使交易抛出异常时，保证交易者快速确定原因。\r\n```rust\r\n    const EBadWitnessErr: u64 = 0;\r\n    const AlreadlyInitlizeErr: u64 = 1;\r\n    const BadTypeOrNotInitlizeErr: u64 = 2;\r\n    const OverFlowErr: u64 = 3;\r\n    const NotEnoughBalanceErr: u64 = 4;\r\n    const AddressZeroErr: u64 = 5;\r\n    const NotEnoughAllowanceErr: u64 = 6;\r\n```\r\n\r\n\r\n## 重构函数\r\ntransfer函数和transferFrom函数存在部分相同的函数逻辑，所以我们可以进行提取重构  \r\n1. 定义transfer_in内部函数\r\n```rust\r\n    fun transfer_in<T>(balance_table:&mut BalanceData<T>, from: address, to:address, value: u64){\r\n        assert!(table::contains(&balance_table.balance,from), NotEnoughBalanceErr);\r\n\r\n        let balance_from = table::borrow_mut(&mut balance_table.balance, from);\r\n        assert!(*balance_from >= value , NotEnoughBalanceErr);\r\n        if(*balance_from > value){\r\n            *balance_from = *balance_from - value;\r\n        }\r\n        else{\r\n            table::remove(&mut balance_table.balance ,from);\r\n        };\r\n        event::emit(\r\n            Transfer {\r\n                from: from,\r\n                to: to,\r\n                value: value,\r\n            }\r\n        );\r\n        if(table::contains(&balance_table.balance, to)){\r\n            let balance_to = table::borrow_mut(&mut balance_table.balance,to);\r\n            assert!(*balance_to + value >= *balance_to, OverFlowErr);\r\n            *balance_to = *balance_to + value;\r\n        }else{\r\n            table::add(&mut balance_table.balance, to, value);\r\n        };\r\n\r\n    }\r\n```\r\n\r\n2. 定义花费授权代币内部函数  \r\n\r\n```rust\r\n    fun spender_allowance<T>(allowance_table:&mut AllowanceData<T>, from:address ,spender: address, value: u64){\r\n        assert!(table::contains(&allowance_table.allowance, from), NotEnoughAllowanceErr);\r\n        let allowance = table::borrow_mut(&mut allowance_table.allowance, from);\r\n        \r\n        assert!(table::contains(&allowance.allowance_amount, spender),NotEnoughAllowanceErr);\r\n        let amount = table::borrow_mut(&mut allowance.allowance_amount, spender);\r\n\r\n        assert!(*amount >= value, 7);\r\n        let new_amount = *amount - value;\r\n        event::emit(\r\n            Approve {\r\n                owner: from,\r\n                spender: spender,\r\n                value: new_amount,\r\n            }\r\n        );\r\n        if(new_amount > 0){\r\n            *amount = new_amount;\r\n        }\r\n        else{\r\n            *amount = new_amount;\r\n            table::remove(&mut allowance.allowance_amount, spender);\r\n        };\r\n    }\r\n```\r\n\r\n\r\n## 重构后的函数  \r\n### transfer\r\n```rust\r\n    public fun transfer<T>(_:& TokenCap<T>, balance_list: &mut BalanceList, to:address, value: u64, ctx:&mut TxContext):bool{\r\n        assert!(to != AddressZero, AddressZeroErr);\r\n        if(value == 0){\r\n            return true\r\n        };\r\n        let type = ascii::into_bytes(type_name::into_string(type_name::get_with_original_ids<T>()));\r\n        assert!(bag::contains(&balance_list.balance_list, type), BadTypeOrNotInitlizeErr);\r\n        transfer_in(bag::borrow_mut<vector<u8>, BalanceData<T>>(&mut balance_list.balance_list, type), tx_context::sender(ctx), to, value);\r\n        return true\r\n    }\r\n```\r\n\r\n### transfer\r\n```rust\r\n    public fun transferFrom<T>(_:& TokenCap<T>, allowance_list: &mut AllowanceList,balance_list: &mut BalanceList,from: address, to: address, value: u64, ctx:&mut TxContext):bool{\r\n        assert!(from != AddressZero, AddressZeroErr);\r\n        assert!(to != AddressZero, AddressZeroErr);\r\n        if(value == 0){\r\n            return true\r\n        };\r\n        let type = ascii::into_bytes(type_name::into_string(type_name::get_with_original_ids<T>()));\r\n        assert!(bag::contains(&allowance_list.allowance_list, type), BadTypeOrNotInitlizeErr);\r\n        assert!(bag::contains(&balance_list.balance_list, type), BadTypeOrNotInitlizeErr);\r\n\r\n        spender_allowance(bag::borrow_mut<vector<u8>, AllowanceData<T>>(&mut allowance_list.allowance_list, type), from, tx_context::sender(ctx), value);\r\n\r\n        transfer_in(bag::borrow_mut<vector<u8>, BalanceData<T>>(&mut balance_list.balance_list, type), from ,to,value);\r\n        return true\r\n    }\r\n```"},"author":{"user":"https://learnblockchain.cn/people/18488","address":null},"history":null,"timestamp":1710431572,"version":1}