iT邦幫忙

2023 iThome 鐵人賽

DAY 21
0
Web 3

Web3新手初探筆記系列 第 21

實作簡易多簽錢包

  • 分享至 

  • xImage
  •  

需要的結構及功能

//接收代幣的事件
    event Deposit(address sender, uint amount, uint balance);
    //發起交易的事件
    event SubmitTransaction(
        address owner,
        uint txIndex,
        address to,
        uint value,
        bytes data
    );
		//確認交易的事件
    event ConfirmTransaction(address owner, uint txIndex);
		//撤銷確認的事件
    event RevokeConfirmation(address owner, uint txIndex);
		//執行交易的事件
    event ExecuteTransaction(address owner, uint txIndex);
    //交易類型
    struct Transaction{
        address to;
        uint value;
        bytes data;
        bool executed;
        uint numConfirmation;
    }
    //交易列
    Transaction[] public transactions;
    //擁有者是否確認
    mapping(uint => mapping(address => bool)) public isConfirmed;
    //擁有者列
    address[] public owners;
    //確認是否為擁有者
    mapping(address => bool) public isOwner;
    //需要簽名數
    uint public numConfirmationRequired;
    //只有擁有者可以使用
    modifier onlyOwner(){
        require(isOwner[msg.sender] == true, "Only owner can use");
        _;
    }
    //交易未確認
    modifier unconfirmed(uint _id){
        require(isConfirmed[_id][msg.sender] == false,"Transaction already confirmed");
        _;
    }
    //交易確認
    modifier confirmed(uint _id){
        require(isConfirmed[_id][msg.sender] == true,"Transaction already confirmed");
        _;
    }
    //交易未執行
    modifier unexecute(uint _id){
        require(transactions[_id].executed == false,"Transaction already executed");
        _;
    }

創建合約的條件

首先錢包的擁有地址必須大於零,第二最低確認數必須大於一半的擁有者數且不超過擁有者數,依序將地址填入擁有者的array中

constructor(address[] memory _owners,uint _ownerNum){
      require(_owners.length > 0,"Owners can not be empty");
      require(_owners.length < _ownerNum*2 && _ownerNum <= _owners.length,"Number should more bigger");
      for(uint i; i < _owners.length; i++){
          owners.push(_owners[i]);
          isOwner[_owners[i]] = true;
      }
      numConfirmationRequired = _ownerNum;
  }

合約函式

接收ETH的函式

//接收函數
    receive()external payable{
        emit Deposit(msg.sender, msg.value, address(this).balance);
    }

發起交易

發起交易時,發起者同時確認,並生成交易寫入交易列中

//發起交易
    function submit(address _to, uint _value, bytes memory _data) public onlyOwner{
        uint txId = transactions.length;
        isConfirmed[txId][msg.sender] = true;
        Transaction memory newone = Transaction({
            to: _to,
            value: _value,
            data: _data,
            executed: false,
            numConfirmation: 1
        });
        transactions.push(newone);
        emit SubmitTransaction(msg.sender, txId, _to, _value, _data);
    }

確認及取消

//確認交易
    function comfirm(uint _id) public onlyOwner unconfirmed(_id) unexecute(_id){
        isConfirmed[_id][msg.sender] = true;
        transactions[_id].numConfirmation += 1;
        emit ConfirmTransaction(msg.sender, _id);
    }
    //取消確認交易
    function cancel(uint _id) public onlyOwner confirmed(_id) unexecute(_id){
        isConfirmed[_id][msg.sender] = false;
        transactions[_id].numConfirmation -= 1;
        emit RevokeConfirmation(msg.sender, _id);
    }

執行交易

先確認簽名數是否足夠,接著執行轉帳,最後標記交易已執行

//執行交易
    function executeTx(uint _id) public onlyOwner unexecute(_id){
        require(transactions[_id].numConfirmation >= numConfirmationRequired,"Not enough confirmation");
        (bool success,) = payable(transactions[_id].to).call{value:transactions[_id].value}("");
        if(!success){
            revert("Not success");
        }
        transactions[_id].executed = true;
        emit ExecuteTransaction(msg.sender, _id);
    }

上一篇
實作簡易DEX ep.3
下一篇
穩定幣
系列文
Web3新手初探筆記32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言