Skip to content

Latest commit

 

History

History
166 lines (152 loc) · 7.28 KB

SushiToken.md

File metadata and controls

166 lines (152 loc) · 7.28 KB

SushiToken合约

没有构造函数

ERC20标准方法略

状态变量,只读方法

  • checkpoints(address 用户地址, uint32 索引) 返回检查点构造体
  • numCheckpoints(address 用户地址) 每个帐户的检查点数映射,地址=>数额
  • DOMAIN_TYPEHASH() EIP-712的合约域hash
  • DELEGATION_TYPEHASH() EIP-712的代理人构造体的hash
  • nonces(address 用户地址) 返回用于签名/验证签名的状态记录(nonce值)
  • delegates(address 被委托的地址) 查询被委托的地址的委托人

易混淆的重要变量

检查点构造体

  • 一个检查点,用于标记给定块中的投票数
struct Checkpoint {
    uint32 fromBlock; // 开始区块号
    uint256 votes; // 票数
}

检查点数映射

  • 账户地址 => 检查点的数量
  • 检查点数映射,用于记录检查点映射中用户有多少个检查点
  • 检查点数映射中的数量从1开始,检查点映射中用户的检查点索引值从0开始
mapping (address => uint32) public numCheckpoints

检查点映射

  • 账户地址 => 检查点索引 => 检查点构造体
  • 检查点映射,用于保存用户的每一个检查点构造体
  • 检查点映射中用户的检查点索引值从0开始
mapping (address => mapping (uint32 => Checkpoint)) public checkpoints;

下文中注意区别检查点映射和检查点数映射,还有检查点构造体

合约方法

mint 铸造方法

  • 只能由所有者(主厨合约)调用
参数
address _to //接收地址
uint256 _amount //数额
  1. 调用ERC20的铸造方法
  2. 调用移动委托方法,将铸造出来的数量添加到委托人的票数中

delegate 转移当然用户的委托人

参数
address delegatee //委托人地址
  1. 调用私有的转移委托人方法,参数为调用者账户和委托人地址

delegateBySig 从签署人到delegatee的委托投票

  • 这个方法和delegate方法的区别是:delegate将修改调用者的委托人,delegateBySig方法可以让一个用户通过签名的方法让另一个账户修改自己的委托人
参数
address delegatee //委托人地址
uint nonce //nonce值,匹配签名所需的合同状态
uint expiry //签名到期的时间 
uint8 v //签名的恢复字节
bytes32 r //ECDSA签名对的一半
bytes32 s //ECDSA签名对的一半
  1. 将域hash + 名字hash + chainId + 当前合约地址打包哈希得到域分割
  2. 将构造体的hash + 委托人地址 + nonce值 + 过期时间打包哈希得到构造体hash
  3. 将域分割 + 构造体hash打包哈希得到签名前数据
  4. 通过v,r,s和签名前数据使用ecrecover方法恢复签名地址
  5. 验证签名地址和nonce值,过期时间都正确
  6. 调用并返回更换委托人方法

getCurrentVotes 获取给定账户地址的当前剩余票数

  • 这个方法返回检查点映射中用户最后一个检查点的票数
参数
address account //账户地址
  1. 通过检查点数映射查询账户地址的检查点
  2. 如果检查点数量大于0
    • 返回选票检查点映射中账户地址最后一个检查点的票数
  3. 否则返回0

getPriorVotes 确定帐户在指定区块前的投票数

  • 账户在指定区块的票数保存在检查点映射中
  • 判断如果检查点数量为0,返回0
  • 如果检查点映射中最后一个检查点构造体中的区块号比给入区块号小,则返回检查点映射中最后一个检查点构造体中的票数
  • 如果检查点映射中第一个检查点构造体中的区块号比给入区块号大,则返回0
  • 其他情况:检查点映射中最后一个检查点构造体中的区块号大于给入区块号,并且检查点数量不为0
  • 则找到检查点映射中from区块为给入区块号的检查点构造体
  • 如果没有则返回检查点映射中给定区块之前最后一个有记录的检查点构造体中的票数
参数
address account //账户地址
uint blockNumber //区块号
  1. 确认区块号小于当前区块号
  2. 通过检查点数映射查询账户地址的检查点数量
  3. 如果检查点数量 == 0 返回 0(终止运行)
  4. 如果检查点映射中账户地址最后一个记录中from块号小于等于区块号
    • 返回 检查点映射中账户地址最后一格记录中的票数(终止运行)
  5. 如果检查点映射中账户地址第一个记录中from块号大于给入区块号,则返回0(终止运行)
  6. 通过二分查找找到检查点映射中from区块为给入区块号的检查点构造体中的票数(终止运行)
  7. 如果没有则返回给入区块号之前最临近区块的检查点构造体检查点索引
  8. 返回检查点映射中用户索引值检查点索引检查点构造体中的票数

_delegate 更换委托人

  • 内部方法,由内部调用
  • 这个方法除了修改委托人映射以外,还要将被委托人的余额对应的票数转移给新委托人
参数
address delegator //被委托人
address delegator //新委托人
  1. 获取被委托人的当前委托人
  2. 获取被委托人当前的sushi余额
  3. 修改委托人映射,将被委托人的委托人替换成新委托人
  4. 触发委托人更改事件
  5. 调用转移投票数方法,将被委托人的余额数量的票数转移到新委托人

_moveDelegates 转移投票数

  • 这个方法是将源地址的检查点映射中的票数减去转移的票数,目标地址的检查点映射中的票数加上转移的票数
参数
address srcRep //源地址
address dstRep //目标地址
uint256 amount //转移的票数
  1. 首先确认源地址和目标地址不能一致,并且转移的数额不能为0
  2. 如果源地址不为零的情况,即说明不是铸造方法
    • 查询源地址的检查点数
    • 判断源地址的检查点数如果大于0
      • 源地址的旧票数等于检查点映射中最后一个检查点的票数
      • 否则源地址的旧票等于0
    • 源地址新的票数等于源地址旧票数减去这次转移的票数
    • 写入检查点
  3. 如果目标地址不为零的情况,即说明不是销毁方法
    • 查询目标地址的检查点数
    • 判断目标地址的检查点数如果大于0
      • 目标地址的旧票数等于检查点映射中最后一个检查点的票数
      • 否则目标地址的旧票等于0
    • 目标地址新的票数等于目标地址旧票数加上这次转移的票数
    • 写入检查点

_writeCheckpoint 写入检查点

参数
address delegatee //委托人地址
uint32 nCheckpoints //检查点
uint256 oldVotes //旧票数
uint256 newVotes //新票数
  1. 将区块号限制在32位2进制之内(防止溢出)
  2. 如果检查点数大于零,并且检查点映射委托人最后一个检查点中的检查点构造体中的from块号等于当前区块号
    • 修改检查点映射中委托人最后一个检查点中的检查点构造体中的票数为新票数
  3. 否则
    • 定义检查点映射中委托人给入的检查点中的检查点构造体为新建检查点构造体,参数为当前区块号和新票数
    • 委托人检查点数映射中将检查点数量加1