在本文中,我将描述如何使用称为目标模式的东西来模块化智能合约。使用标准的solidity,您将学习如何使用abi.encodeSelector和target.call(data)重写脆弱、耦合的调用,以清除模块和分离关...
本文标题如何在Solidity中设计模块化智能合约,作者:知世,本文有1618个文字,大小约为7KB,预计阅读时间5分钟,请您欣赏。知世金融网众多优秀文章,如果想要浏览更多相关文章,请使用网站导航的搜索进行搜索。本站虽然不乏优秀之作,但仅作为投资者学习参考。
在本文中,我将描述如何使用称为目标模式的东西来模块化智能合约。使用标准的solidity,您将学习如何使用abi.encodeSelector和target.call(data)重写脆弱、耦合的调用,以清除模块和分离关注点。为此,我们将以HumanityDAO为例 - 以及他们如何使用目标模式将治理与注册表分开。
HumanityDAO:介绍
HumanityDAO是一个DAO,其目的是人类验证。维护一个说“你是真的”的注册表。它既能让人安心,又在对抗Sybil攻击方面也非常有用。在我目前的工作中,我正在 使用注册表构建像分散式reddit这样的东西,你可以捎带其他DAO所做的工作来打击垃圾邮件(作为一个基本的例子)。一旦我们开始采用这些模式,您就可以看到整个生态系统如何蓬勃发展。
但除了HumanityDAO是一个伟大的dapp,它也是我看到的模块化Solidity设计的第一个例子。但是在这种情况下模块化指的是什么?我们如何实现它?
HumanityDAO中的模块
HumanityDAO维护一个您添加和查询的人的注册表,称为HumanityRegology。注册表本身仅对单个映射(address=>bool)公共人员上操作。以下是添加条目的主要功能:
function add(address who) public {
require(msg.sender == governance,
"HumanityRegistry::add: Only governance can add an identity");
require(humans[who] == false,
"HumanityRegistry::add: Address is already on the registry");
_reward(who);
humans[who] = true;
}
治理是我们将要研究的下一个模块,它涉及提案和投票。这是基本流程:
1. Propose(address target, bytes memory data)开始一个新的提议。它会创建一个Proposal,将其添加到列表中,然后发出一个事件。
2. 用户调用voteyes(uint proposalid)和voteno(uint proposalid)在通过/失败提案时使用其令牌。
3. 投票期过后,可以调用finalize(uint proposalId)。如果proposal.yesCount> proposal.noCount,则使用数据调用target
为了简单起见,最后一步我将在本指南中引用为目标模式。这不是一种新的编程模式.
EVM:调用合同,发送消息
简要说明 - 以太坊合约在EVM中执行,这是一个消息传递执行环境。因此,当您向地址发送10个wei时,您发送的消息显示{from:me,to:0x123456789,value:10}。当我们在合同上执行调用时,除了附加数据之外我们也是这样做的 - 所以现在消息看起来像{from:me,to:0x123456789,data:“0xcafebabe”,value:10}。这是什么数据?嗯,这是根据Solidity应用程序二进制接口(或简称ABI)编码的调用。
消息构造很好,因为它意味着发送以太和调用智能合约没有什么不同。将钱汇入用户的钱包地址,并将钱汇入合同,看起来一样。唯一的区别是,合同的地址不是从公钥生成的(而是从nonce生成)。
因为我们在区块链中,而且我们更愿意以不变的方式进行引用,所以智能合约中的方法由它们的选择器引用。选择器只是函数签名哈希的一部分。
target模式
目标模式非常简单,但尚未被广泛使用,因为Solidity具有这些特殊名称。它也可以称为动态调度(Ruby,Obj-C),回调(JS),无论你想要什么;
它基本上包括:
· 你正在构建的模块,例如治理
· 你正在实施的事情,例如注册表
· 目标整合点- 即传递提案将添加到注册表
我们将从HumanityDAO的例子中学习如何实现这一目标。
综上所述,我们的目标是:在通过治理投票之后,在注册表中添加一个条目。
在我们将它们组合在一起之前,下面是两个难题,治理和注册模块:
contract Registry {
mapping (address => bool) public humans
function add(address who) public {
require(msg.sender == governance, "HumanityRegistry::add: Only governance can add an identity");
humans[who] = true;
}
}
contract Governance {
function propose(address target, bytes memory data)
public returns (uint) {
uint proposalId = proposals.length;
Proposal memory proposal;
proposal.target = target;
proposal.data = data;
proposals.push(proposal);
}
function vote() public { /* ... */ }
function finalize(uint proposalId) public {
Proposal storage proposal = proposals[proposalId];
require(proposal.result == Result.Pending,
"Governance::finalize: Proposal is already finalized");
if (proposal.yesCount > proposal.noCount) {
// Call the target contract with the data
proposal.target.call(proposal.data);
}
}
}
我们可以使用Registry.add添加到注册表中。治理的基础是提交一份提案,对提案进行投票,然后调用finalize并通过/失败。如果提案通过,我们将数据中的calldata调用target合同。
那么我们如何构建这个calldata呢? 你会认为这是非常复杂的,即Solidity
不! 我们可以通过一个名为abi.encodeWithSelector的东西来做到这一点:
bytes memory data = abi.encodeWithSelector(registry.add.selector, who);
governance.propose(address(registry), data)
就像那样,目标被设置为注册表合同,并且看起来像Registry.add(who)的调用被编码并存储在提议中。 这真的很简单。
使用wrapper
还有一件事 - 因为我们已经在谈论良好的设计和可组合性 - 我建议在一个单独的合同中用一种方法wrapper这个调用。 这个wrapper智能合约是一个可以在前端调用的简单方法。
我们将建议的代码流命名为什么,并可能将某人添加到注册表中? HumanityDAO称之为HumanityApplicant:
contract HumanityApplicant {
Governance governance;
Registry registry;
constructor(Governance _Governance, Registry _Registry) {
governance = Governance(_Governance);
registry = Registry(_Registry);
}
function addToRegistry(address who) {
bytes memory data = abi.encodeWithSelector(registry.add.selector, who);
return governance.propose(msg.sender, address(registry), data);
}
}
结论
就是这样! 使用此功能,您可以轻松获取治理合同并在您自己的设计中使用它。
本文相关推荐: 永续合约的杠杆倍数
以上便是知世金融网给大家分享的关于如何在Solidity中设计模块化智能合约/qkl/27177.html的相关信息了,希望能帮助到大家,更多金融相关信息,敬请关注知世金融网!
网站内容均来自互联网,如侵害您的利益联系客服进行删除!
下一篇:发行人民币稳定币,Tether公司“疯”了吗?是在给USDT暴雷留后路?
本文标题:如何在Solidity中设计模块化智能合约
本文地址:/index.php?s=article&c=search&keyword=%E5%90%88%E7%BA%A6