ink合约-主要协议汇总(1)

对标以太坊的一些应用协议,方便辅助ink!合约的实现。这些协议均已在openbrush-contracts 中实现

1. 概述

  1. Ownerable:权限,主要是针对超级管理员的行为管理
  2. AccessControl:账户角色控制,链上角色管理。满足通过角色控制方法的需要。
  3. PaymentSplitter:用来实现给某一个群体进行链token支付
  4. Pausable:可控制全局暂停或启动
  5. TimelockController:时间锁
  6. Proxy:用于更新合约的协议
  7. Diamond:用于更新合约的另一种协议,可以同时集成多种合约和指定方法
  8. ReentrancyGuard:防止调用合约的重入攻击
  9. Flashmint:闪电贷-贷款放贷方以及贷款接收方

2. 协议说明

1. Ownerable协议

  1. ownable::owner()
    作用:
    获取当前合约管理人地址
    参数说明:
    无参数

  2. ownable::transferOwnership(newOwnerAccountId)
    作用:
    变更合约账户所有权
    参数说明:
    newOwnerAccountId:新的管理账户ID

  3. ownable::renounceOwnership()
    作用:
    放弃合约所有权
    参数说明:

2. AccessControl协议

备注:默认role=0表示内置管理员账户

  1. accessControl::hasRole(roleType,accountId)
    作用:
    指定账户A是否设置了指定角色R
    参数说明:
    roleType:指定角色R
    accountId:指定账户A

  2. accessControl::getRoleAdmin(roleType)
    作用:
    获取指定role的上级管理员角色
    参数说明:
    roleType:指定role

  3. accessControl::grantRole(roleType,accountId)
    作用:
    为指定账户A设置角色R,拥有角色的人,才可以使用该方法,安全起见,该方法需要做严格检测,可以为一个账户设置多个不同角色
    参数说明:
    roleType:指定角色R
    accountId:指定账户A
    注:该方法要么仅可初始化调用,要么对外开放时,限制只有ownerable或者admin可用

  4. accessControl::revokeRole(roleType,accountId)
    作用:
    撤销账户A角色R,拥有角色的人,才可以使用该方法,安全起见,该方法需要做严格检测
    参数说明:
    roleType:指定角色R
    accountId:指定账户A

  5. accessControl::renounceRole(roleType,accountId)
    作用:
    撤销当前账户的角色,主要是由于自己账号导致合约危险时,可快速撤销自己的角色R
    参数说明:
    roleType:指定角色R
    accountId:当前正在操作该方法的账户(caller)

3. Pausable协议

备注:可控制全局暂停或启动,如使用#[openbrush::modifiers(when_not_paused)]则只有暂停时才能调用该宏之后的方法

  1. pausable::pause()
    作用:
    暂停
    参数说明:

  2. pausable::unpause()
    作用:
    取消暂停
    参数说明:

  3. pausable::changeState()
    作用:
    变更状态
    参数说明:

4. PaymentSplitter协议

4.1 功能说明

caller用来实现给某一个群体进行链token支付(合约初始化时,传入多个账户以及对应的份额,根据所占有的份额比例进行分配链token)。合约构建时需要指定payees(即支付的所有对象),以及shares(即每个payee的支付份额)。支付使用pull的形式,即payee地址需要自己调用release函数来获得支付:

  1. 需要先通过receive方法将链token充值到合约中,可以重复多次充入
  2. 使用release方法将合约中的链token按合约初始化时账户的分配比例进行支付,为防止理解错误,这里做详细解释
    1. 假如receive了3次,分别是:10、20、30,同时假设账户A份额所占比例为20%,则对账户A调用release后,账户A可一次性获得token数量为:2+4+6=12个
    2. 假如receive了1次,充入10,同时假设账户A份额所占比例为20%,则对账户A调用release后,账户A可一次性获得token数量为:2个;然后继续receive了2次,分别充入20,30,则对账户A调用release后,账户A可一次性获得token数量为:4+6=10个;也就是说,第一次充入的不再参与分配,最终账户A依旧拿到12个
  3. 注意,份额不是token数量,只是用于区分所有账户中,不同账户分别占有多少比例,用于后续按比例分配token

4.2 涉及方法

  1. paymentSplitter::totalShares()
    作用:
    获取所有用户要支付的份额
    参数说明:

  2. paymentSplitter::totalReleased()
    作用:
    所有已经分配出去的链token数量
    参数说明:

  3. paymentSplitter::shares(accountId)
    作用:
    获取账户A应该所占有的份额
    参数说明:
    accountId:账户A

  4. paymentSplitter::released(accountId)
    作用:
    查看账户A已接收到多少链token
    参数说明:
    accountId:账户A

  5. paymentSplitter::payee(index)
    作用:
    根据集合(一般合约初始化会传入一个数据集合,其中包含账户和份额)索引号获取当前索引号对应的账户地址
    参数说明:
    index:索引号

  6. paymentSplitter::receive()
    作用:
    使用caller将链token传入合约账户
    参数说明:

  7. paymentSplitter::release(accountId)
    作用:
    caller根据账户A份额所占有的比例,将合约中的token一次性支付给账户A
    参数说明:
    accountId:账户A

5. TimelockController协议

5.1 功能说明

  1. TimelockController是一个被提议者和执行者管理的代理。它能确保操作被延迟。这种延迟可以确保用户对智能合约的操作被审计或检查。
  2. 默认情况下,TimelockController已部署的地址通过时间同步获得管理员权限。这个角色授权指派到提议者、执行者或其他管理员。
  3. TimelockController配置中指派至少一个提议者和一个执行者。可以在构造时执行,也可以稍后通过任何管理员角色指定。这些角色不是独占的,意味着一个账户可以同时有两个角色。
  4. 可以合约初始化时,传入:minDelay(最小延迟时间)、proposers(提议者)、executors(执行者)
  5. 需要依赖AccessControl扩展,该扩展在上文已经介绍过了,本节只讲解TimelockController
  6. 大体逻辑:一笔待交易数据生成一个id,叫做活动ID,给活动设置时间,然后启动执行等。

5.2 涉及方法

  1. timelockController::isOperation(OperationId)
    作用:
    根据活动ID检查该交易执行设置的时间是否大于0,若大于0则是一个正常的活动
    参数说明:
    OperationId:活动ID

  2. timelockController::isOperationPending(OperationId)
    作用:
    根据活动ID检查交易是否在pending状态,若该交易执行设置的时间大于1,则该活动pending状态
    参数说明:
    OperationId:活动ID

  3. timelockController::isOperationReady(OperationId)
    作用:
    根据活动ID检查交易是否在ready状态,若该交易执行设置的时间大于等于当前块时间,则该活动ready状态
    参数说明:
    OperationId:活动ID

  4. timelockController::isOperationDone(OperationId)
    作用:
    根据活动ID检查交易是否执行完毕,若为1则表示执行完毕。注:活动执行完毕后,该活动的执行时间会被设置为1。
    参数说明:
    OperationId:活动ID

  5. timelockController::getTimestamp(OperationId)
    作用:
    获取要执行活动的时间
    参数说明:
    OperationId:活动ID

  6. timelockController::getMinDelay()
    作用:
    获取最小延迟时间
    参数说明:

  7. timelockController::hashOperation(transaction,predecessor,salt)
    作用:
    将一笔待执行的交易信息生成一个hash值,也就是活动ID
    参数说明:
    transaction:一笔交易信息
    predecessor:未知,也是生成hash必要的
    salt:生成hash的参数

  8. timelockController::hashOperationBatch(transactions,predecessor,salt)
    作用:
    将多笔待执行的交易信息对应生成多个hash值,也就是对应多个活动ID
    参数说明:
    transactions:批量交易信息
    predecessor:未知,也是生成hash必要的
    salt:生成hash的参数
    :参数用于实时生成活动ID

  9. timelockController::schedule(transaction,predecessor,salt,delay)
    作用:
    为要执行的一笔交易定时,也就是设置日程
    参数说明:
    transaction:一笔交易信息
    predecessor:未知,也是生成hash必要的
    salt:生成hash的参数
    delay:设置延迟时间,要比minDelay大
    :参数用于实时生成活动ID

  10. timelockController::scheduleBatch(transactions,predecessor,salt,delay)
    作用:
    为要执行的批量交易定时,也就是设置日程,进入pending状态
    参数说明:
    transactions:批量交易信息
    predecessor:未知,也是生成hash必要的
    salt:生成hash的参数
    delay:设置延迟时间,要比minDelay大
    :参数用于实时生成活动ID

  11. timelockController::cancel(OperationId)
    作用:
    取消要执行的交易,该交易必须在pending状态
    参数说明:
    OperationId:由交易生成的ID

  12. timelockController::execute(transaction,predecessor,salt)
    作用:
    执行一笔pending状态的交易
    参数说明:
    transaction:交易数据
    predecessor:未知,也是生成hash必要的
    salt:生成hash的参数
    :参数用于实时生成活动ID

  13. timelockController::executeBatch(transactions,predecessor,salt)
    作用:
    批量执行pending状态的交易
    参数说明:
    transactions:批量交易数据
    predecessor:未知,也是生成hash必要的
    salt:生成hash的参数
    :参数用于实时生成活动ID

  14. timelockController::updateDelay(newDelay)
    作用:
    更新最小延迟时间。内部提供的默认方法中,只有合约自身的账户(不是创建合约的账户)可以调用该方法,可防止外部合约攻击。
    参数说明:
    newDelay:更新最小延迟时间

6. Proxy协议

可升级的合约,入口为proxy的合约地址,通过来回切换proxy合约的abi以及业务合约的abi,来升级合约。
可以确保数据不丢失,也不用迁移。
每个合约文件都必须传到链上,proxy的changeDelegateCode传入需要执行的合约hash,然后传入abi,才能正常执行代理合约

6.1 使用说明

需要在polkadot-app中使用:
Steps I followed:

  1. upload and deploy psp22_upgradeable contract ( contract-to-be-proxied v1)
  2. upload and deploy proxy with code hash from step1 as constructor argument (one could set it using the proxy’s method as well)
  3. use a “Add existing contract” button to swap Proxy’s ABI (input proxy’s address + contract-to-be-proxied v1 address)
  4. boom - it works

To upgrade contract:

  1. upload new code
  2. change proxy’s ABI via “Add an existing contract” button
  3. use change_delegate_code (or sth like that) to enter new contract’s code hash
  4. change proxy’s ABI again via “Add an existing contract” button
  5. boom it works

6.2 方法说明

  1. proxy::getDelegateCode()
    作用:
    获取当前代理合约码
    参数说明:

  2. proxy::changeDelegateCode(newCodeHash)
    作用:
    修改代理合约码
    参数说明:
    newCodeHash:新的合约码

7. Diamond协议

7.1 概述

diamondCut函数是用来合约升级的函数,可以增加,替代和删除钻石合约里的任意函数 。它接收一个bytes[]类型的参数输入,指明修改内部映射表所需要的方法-钻石面对。比如,调用diamondCut函数可以一次性在一个交易里增加2个新函数,替换3个函数并且删除4个函数。同时diamondCut函数可以触发事件,记录所有的增加,替换和删除。

放大镜(The Loupe)是用来查询钻石合约的内部状况。钻石合约提供4个函数来提供钻石合约当前存储的函数和钻石面。这些函数被统称为放大镜。所有的钻石合约都必须实现这些函数

一个钻石面:可以理解成是一个合约

7.2 方法说明

  1. diamond::diamondCut (cuts, init)
    作用:
    增加,替代和删除钻石合约里的任意函数
    参数说明:
    cuts:FacetCut集合,一个FacetCut(钻石面)中,包含有一个合约hash,以及多个selector(即方法对应的编号,可以在metadata.json中找到)
    init:可以初始化cuts中传入的合约的方法

  2. diamondLoupe::facets()
    作用:
    返回所有的钻石面的结构,就是FacetCut集合
    参数说明:

  3. diamondLoupe::facetFunctionSelectors(facet)
    作用:
    返回指定钻石面(合约)的方法
    参数说明:
    facet:指定的钻石面hash值(即合约的hash值)

  4. diamondLoupe::facetCodeHashes()
    作用:
    返回所有钻石面的地址,即所有合约的地址
    参数说明:

  5. diamondLoupe::facetCodeHash(selector)
    作用:
    返回selector所对应的钻石面的hash,即对应合约的hash
    参数说明:
    selector:合约中对应的一个方法的编号

8. ReentrancyGuard协议

8.1 概述

重入攻击是由于智能合约调用了外部不安全合约,或者对外发送以太币,使得合约的外部调用能够被劫持,导致合约内的方法被外部合约递归调用
形成重入攻击有如下条件:

  1. 调用了外部不安全合约
  2. 使用了不安全的转账方式,未进行gas限制。
  3. 状态变量修改在合约交互之后

用openbrush的话来说,就是防止合约直接或者间接的调用自身。不允许被标记non_reentrant的方法去调用另一个被标记non_reentrant的方法

8.2 方法说明

其实只是宏注解,在需要防止重入攻击的方法上面加上#[openbrush::modifiers(non_reentrant)]

9. Flashmint闪电贷协议

分为贷款放贷方和贷款发起方,看着不怎么好用。就是快速交换资产。要在一个块中完成交易,也就是短时间内完成交易。
闪电贷是一种关于 DeFi无抵押贷款的新思路,所有操作都在一笔交易(一个区块)中完成,它允许借款人无需抵押资产即可实现借贷(但需支付额外较少费用)
备注:虽然这里记录了闪电贷的主要方法,但我还是没看懂怎么个用法,暂时先不管了,后续理解了,再详细描述

9.1 贷款放贷方须实现

  1. flashLender::flashloan(receiverAccountId, tokenAccountId, balance)
    作用:
    账户A账户B闪电贷指定余额,该函数必须包括对FlashBorrower(贷款接收方)合约中onFlashLoan()的回调。
    参数说明:
    receiverAccountId:账户A
    tokenAccountId:账户B
    balance:借贷指定余额

  2. flashLender::maxFlashloan(tokenAccountId)
    作用:
    账户A最大可借贷数量。返回对应账户A可闪电贷的最大数量,如果对应账户A不支持闪电贷,那么返回0
    参数说明:
    tokenAccountId:账户A

  3. flashLender::flashFee(tokenAccountId, balance)
    作用:
    账户A闪电贷金额所需要收取的手续费,该方法调用后,方可放行贷款
    参数说明:
    tokenAccountId:账户A
    balance:贷款金额

9.2 贷款接收方须实现

  1. flashBorrower::onFlashloan(initiatorAccountId,tokenAccountId,amountBalance,feeBalance,data)
    作用:贷款发起方发起借贷,使用账户A账户B借贷指定余额amountBalance,约定还款时额外支付利息feeBalance
    参数说明:
    initiatorAccountId:账户A
    tokenAccountId:账户B
    amountBalance:借贷余额
    feeBalance:总利息
    data:额外数据(类似备注)

总结

本文编辑完毕

参考

[1] openbrush-contracts合约开源框架
[2] openbrush-contracts文档
[4] 从The Saudis NFT事件浅析EIP-2535钻石协议
[5] 钻石标准–Diamond Standard
[6] 智能合约安全之重入攻击浅析
[7] EIP-3156: Flash Loans
[8] 去中心化金融(DeFi)和闪电贷(Flash Loan)

Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2017-2023 Jason
  • Visitors: | Views:

谢谢打赏~

微信