本文小编为大家详细介绍“以太坊DAO时间锁定Multisig怎么运用”,内容详细,步骤清晰,细节处理妥当,希望这篇“以太坊DAO时间锁定Multisig怎么运用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。
Decentralized Autonomous Organization,简称DAO,以太坊中重要的概念。一般翻译为去中心化的自治组织。
有时候,时间也可以用作一种很好的安全机制。以下代码基于DAO区块链大会,但有不同的变化。不是每个操作需要X个成员批准,而是任何交易都可以由单个成员发起,但它们在执行之前都需要最少的延迟,这取决于交易的支持。提案的批准越多,就越早执行。会员可以对交易进行投票,这意味着它将取消其他一个已批准的签名。
这意味着如果你没有紧急程度,则执行任何交易可能只需要一个或两个签名。但是,如果单个密钥被泄露,其他密钥可以将该交易延迟数月或数年,甚至可以阻止其执行。
所有密钥都已批准的交易可以在十分钟后执行(此金额是可配置的),并且每5%未投票的成员每次需要的时间加倍(如果他们主动投票,则为四倍)反对)。如果它是一个简单的ether交易,只要支持投票将其置于所需的时间内,就会执行交易,但更复杂的交易将要求使用正确的字节码手动执行交易。这些是默认值,但在创建合约时可以设置不同的值:
批准交易的成员数量:近似时间延迟
100%批准:10分钟(最低默认值)
90%批准:40分钟
80%:2小时40分钟
50%:大约一周
40%:1个月
30%:4个月
20%:超过一年
10%或更少:5年或从不 一旦最短的时间过去,任何人都可以执行交易(参见“国会”以获得更完整的步行)。这是故意的,因为它允许某人安排交易或雇用其他人来执行交易。
代码:
pragma solidity >=0.4.22 <0.6.0;
contract owned {
address public owner;
constructor() public {
owner = msg.sender;
}
modifier onlyOwner {
require(msg.sender == owner);
_;
}
function transferOwnership(address newOwner) onlyOwner public {
owner = newOwner;
}
}
contract tokenRecipient {
event receivedEther(address sender, uint amount);
event receivedTokens(address _from, uint256 _value, address _token, bytes _extraData);
function receiveApproval(address _from, uint256 _value, address _token, bytes memory _extraData) public {
Token t = Token(_token);
require(t.transferFrom(_from, address(this), _value));
emit receivedTokens(_from, _value, _token, _extraData);
}
function () payable external {
emit receivedEther(msg.sender, msg.value);
}
}
interface Token {
function transferFrom(address _from, address _to, uint256 _value) external returns (bool success);
}
contract TimeLockMultisig is owned, tokenRecipient {
Proposal[] public proposals;
uint public numProposals;
mapping (address => uint) public memberId;
Member[] public members;
uint minimumTime = 10;
event ProposalAdded(uint proposalID, address recipient, uint amount, string description);
event Voted(uint proposalID, bool position, address voter, string justification);
event ProposalExecuted(uint proposalID, int result, uint deadline);
event MembershipChanged(address member, bool isMember);
struct Proposal {
address recipient;
uint amount;
string description;
bool executed;
int currentResult;
bytes32 proposalHash;
uint creationDate;
Vote[] votes;
mapping (address => bool) voted;
}
struct Member {
address member;
string name;
uint memberSince;
}
struct Vote {
bool inSupport;
address voter;
string justification;
}
// Modifier that allows only shareholders to vote and create new proposals
modifier onlyMembers {
require(memberId[msg.sender] != 0);
_;
}
/**
* Constructor
*
* First time setup
*/
constructor(
address founder,
address[] memory initialMembers,
uint minimumAmountOfMinutes
) payable public {
if (founder != address(0)) owner = founder;
if (minimumAmountOfMinutes !=0) minimumTime = minimumAmountOfMinutes;
// It’s necessary to add an empty first member
addMember(address(0), '');
// and let's add the founder, to save a step later
addMember(owner, 'founder');
changeMembers(initialMembers, true);
}
/**
* Add member
*
* @param targetMember address to add as a member
* @param memberName label to give this member address
*/
function addMember(address targetMember, string memory memberName) onlyOwner public
{
uint id;
if (memberId[targetMember] == 0) {
memberId[targetMember] = members.length;
id = members.length++;
} else {
id = memberId[targetMember];
}
members[id] = Member({member: targetMember, memberSince: now, name: memberName});
emit MembershipChanged(targetMember, true);
}
/**
* Remove member
*
* @param targetMember the member to remove
*/
function removeMember(address targetMember) onlyOwner public {
require(memberId[targetMember] != 0);
for (uint i = memberId[targetMember]; i<members.length-1; i++){
members[i] = members[i+1];
memberId[members[i].member] = i;
}
memberId[targetMember] = 0;
delete members[members.length-1];
members.length--;
}
/**
* Edit existing members
*
* @param newMembers array of addresses to update
* @param canVote new voting value that all the values should be set to
*/
function changeMembers(address[] memory newMembers, bool canVote) public {
for (uint i = 0; i < newMembers.length; i++) {
if (canVote)
addMember(newMembers[i], '');
else
removeMember(newMembers[i]);
}
}
/**
* Add Proposal
*
* Propose to send `weiAmount / 1e18` ether to `beneficiary` for `jobDescription`. `transactionBytecode ? Contains : Does not contain` code.
*
* @param beneficiary who to send the ether to
* @param weiAmount amount of ether to send, in wei
* @param jobDescription Description of job
* @param transactionBytecode bytecode of transaction
*/
function newProposal(
address beneficiary,
uint weiAmount,
string memory jobDescription,
bytes memory transactionBytecode
)
onlyMembers public
returns (uint proposalID)
{
proposalID = proposals.length++;
Proposal storage p = proposals[proposalID];
p.recipient = beneficiary;
p.amount = weiAmount;
p.description = jobDescription;
p.proposalHash = keccak256(abi.encodePacked(beneficiary, weiAmount, transactionBytecode));
p.executed = false;
p.creationDate = now;
emit ProposalAdded(proposalID, beneficiary, weiAmount, jobDescription);
numProposals = proposalID+1;
vote(proposalID, true, '');
return proposalID;
}
/**
* Add proposal in Ether
*
* Propose to send `etherAmount` ether to `beneficiary` for `jobDescription`. `transactionBytecode ? Contains : Does not contain` code.
* This is a convenience function to use if the amount to be given is in round number of ether units.
*
* @param beneficiary who to send the ether to
* @param etherAmount amount of ether to send
* @param jobDescription Description of job
* @param transactionBytecode bytecode of transaction
*/
function newProposalInEther(
address beneficiary,
uint etherAmount,
string memory jobDescription,
bytes memory transactionBytecode
)
onlyMembers public
returns (uint proposalID)
{
return newProposal(beneficiary, etherAmount * 1 ether, jobDescription, transactionBytecode);
}
/**
* Check if a proposal code matches
*
* @param proposalNumber ID number of the proposal to query
* @param beneficiary who to send the ether to
* @param weiAmount amount of ether to send
* @param transactionBytecode bytecode of transaction
*/
function checkProposalCode(
uint proposalNumber,
address beneficiary,
uint weiAmount,
bytes memory transactionBytecode
)
view public
returns (bool codeChecksOut)
{
Proposal storage p = proposals[proposalNumber];
return p.proposalHash == keccak256(abi.encodePacked(beneficiary, weiAmount, transactionBytecode));
}
/**
* Log a vote for a proposal
*
* Vote `supportsProposal? in support of : against` proposal #`proposalNumber`
*
* @param proposalNumber number of proposal
* @param supportsProposal either in favor or against it
* @param justificationText optional justification text
*/
function vote(
uint proposalNumber,
bool supportsProposal,
string memory justificationText
)
onlyMembers public
{
Proposal storage p = proposals[proposalNumber]; // Get the proposal
require(p.voted[msg.sender] != true); // If has already voted, cancel
p.voted[msg.sender] = true; // Set this voter as having voted
if (supportsProposal) { // If they support the proposal
p.currentResult++; // Increase score
} else { // If they don't
p.currentResult--; // Decrease the score
}
// Create a log of this event
emit Voted(proposalNumber, supportsProposal, msg.sender, justificationText);
// If you can execute it now, do it
if ( now > proposalDeadline(proposalNumber)
&& p.currentResult > 0
&& p.proposalHash == keccak256(abi.encodePacked(p.recipient, p.amount, ''))
&& supportsProposal) {
executeProposal(proposalNumber, '');
}
}
function proposalDeadline(uint proposalNumber) public view returns(uint deadline) {
Proposal storage p = proposals[proposalNumber];
uint factor = calculateFactor(uint(p.currentResult), (members.length - 1));
return p.creationDate + uint(factor * minimumTime * 1 minutes);
}
function calculateFactor(uint a, uint b) public pure returns (uint factor) {
return 2**(20 - (20 * a)/b);
}
/**
* Finish vote
*
* Count the votes proposal #`proposalNumber` and execute it if approved
*
* @param proposalNumber proposal number
* @param transactionBytecode optional: if the transaction contained a bytecode, you need to send it
*/
function executeProposal(uint proposalNumber, bytes memory transactionBytecode) public {
Proposal storage p = proposals[proposalNumber];
require(now >= proposalDeadline(proposalNumber) // If it is past the voting deadline
&& p.currentResult > 0 // and a minimum quorum has been reached
&& !p.executed // and it is not currently being executed
&& checkProposalCode(proposalNumber, p.recipient, p.amount, transactionBytecode)); // and the supplied code matches the proposal...
p.executed = true;
(bool success, ) = p.recipient.call.value(p.amount)(transactionBytecode);
require(success);
// Fire Events
emit ProposalExecuted(proposalNumber, p.currentResult, proposalDeadline(proposalNumber));
}
}
像以前一样在这些教程上部署该代码。在部署参数上,将最小时间留空将默认为30分钟,如果你想要更快的锁定时间,则放1分钟。上传后,执行“添加成员”功能以添加组的新成员,他们可以是你认识的其他人,也可以是不同计算机上的帐户或离线存储。
设置为所有者owner的帐户非常强大,因为它可以随意添加或删除成员。因此,在添加主成员后,我们建议你通过执行Transfer Membership
功能将owner
设置为另一个帐户。如果你希望对所有成员的添加或删除进行投票,则将其设置为multisig本身,就像任何其他交易一样。另一种方法是将其设置为另一个受信任的multisig
钱包,如果你希望永久修复成员数,则可以设置为0x000。请记住,此合约上的资金仅与“所有者”帐户一样安全。
与上述任何DAO一样,此合约可以持有以太币,任何基于以太坊的代币并执行任何合约。为此,请检查如何在国会DAO上执行复杂的提案。
为简单起见,对提案的投票仅仅算得少一点支持。如果你愿意,你可以玩弄负面投票更重要的想法,但这意味着少数成员可以对任何提议的交易拥有有效的否决权!
读到这里,这篇“以太坊DAO时间锁定Multisig怎么运用”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注亿速云行业资讯频道。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:https://my.oschina.net/u/2472105/blog/2988352