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