基於以太坊開發的賞金激勵畢業系統設計

1.基本原理

獎勵是激勵機制的最簡單形式:爲人們提供完成任務的令牌。以太坊區塊鏈提供了許多好處來支持以下激勵機制:

  • 與世界各地的個人進行廉價交易的能力
  • 能夠將資金鎖定在代管合同(賞金)中的功能,當接受任務完成或可交付證明時,便可以支配資金
  • 以開放且可互操作的方式託管這些賞金的能力,因此可以使用許多不同類型的應用程序從共享的流動資金池(沒有人控制)中創建,探索和完成賞金。通過這種方式,StandardBounties使團隊能夠通過一個應用程序(例如其DAO)創建賞金,並立即將賞金立即在多個賞金市場上列出,以最大程度地擴大賞金的覆蓋面並提高市場效率。

2.實施

賞金中有幾種關鍵類型的用戶:

  • Bounty Issuers 是有權刪除賞金並編輯與賞金相關的詳細信息的地址列表。
  • Bounty Approvers是有權接收賞金提交地址的地址列表。(注意:發佈者不被認爲也是批准者,但可以根據需要添加自己
  • Bounty Contributors 是對給定賞金有貢獻的任何地址
  • Bounty Fulfillers 是任何對給定賞金提交內容的貢獻者地址
  • Bounty Submitters 是代表自己或他人提交成就的任何地址

這些參與者共同努力,通過激勵的力量來部署資金並塑造人類行爲。

賞金生命週期中有幾個核心動作,某些用戶可以執行:

  • 任何人都可以issue賞金,指定賞金的詳細信息,並將關聯的IPFS哈希錨定在StandardBounties智能合約內的鏈上
  • 任何人都可以contribute懸賞,指定他們想要添加到端口的令牌數量。
  • 任何人都可以fulfill懸賞,提交貢獻者列表以及詳細信息和可交付成果的IPFS哈希。
  • 賞金的任何批准者都可以accept兌現,提交他們希望每個貢獻者獲得的代幣數量。

這些行動構成了賞金的核心生命週期,支持資金流入各種賞金,並隨着任務完成而流出。

各種用戶可以執行一些其他操作:

  • 只要賞金的期限已過且未接受任何提交,任何貢獻者都可以將其捐款退還給賞金。
  • 任何發行人都可以根據需要退還其他用戶的捐款(即使還沒有截止日期或賞金已經支付了一部分資金)
  • 任何發行人都可以耗盡賞金中一部分資金的賞金
  • 任何人都可以執行概括化的操作action,提交IPFS哈希表,該哈希表存儲其操作的詳細信息(例如,評論,提交其完成賞金的意圖等)
  • 任何提交者都可以更新其提交內容,並對提交數據或貢獻者列表進行更改
  • 任何批准者都可以同時提交併接受鏈下履行,一成不變地記錄交換,同時省去了先行提交鏈上履行的需求
  • 任何發行人都可以更改賞金的任何細節,但與賞金相關的代幣合約不可更改

合約寫法

pragma solidity 0.5.12;
pragma experimental ABIEncoderV2;

import "./StandardBounties.sol";



contract BountiesMetaTxRelayer {

  // This contract serves as a relayer for meta txns being sent to the Bounties contract

  StandardBounties public bountiesContract;
  mapping(address => uint) public replayNonce;


  constructor(address _contract) public {
    bountiesContract = StandardBounties(_contract);
  }

  function metaIssueBounty(
    bytes memory signature,
    address payable[] memory _issuers,
    address[] memory _approvers,
    string memory _data,
    uint _deadline,
    address _token,
    uint _tokenVersion,
    uint _nonce)
    public
    returns (uint)
    {
    bytes32 metaHash = keccak256(abi.encode(address(this),
                                                  "metaIssueBounty",
                                                  _issuers,
                                                  _approvers,
                                                  _data,
                                                  _deadline,
                                                  _token,
                                                  _tokenVersion,
                                                  _nonce));
    address signer = getSigner(metaHash, signature);

    //make sure signer doesn't come back as 0x0
    require(signer != address(0));
    require(_nonce == replayNonce[signer]);

    //increase the nonce to prevent replay attacks
    replayNonce[signer]++;
    return bountiesContract.issueBounty(address(uint160(signer)),
                                         _issuers,
                                         _approvers,
                                         _data,
                                         _deadline,
                                         _token,
                                         _tokenVersion);
  }

  function metaIssueAndContribute(
    bytes memory signature,
    address payable[] memory _issuers,
    address[] memory _approvers,
    string memory _data,
    uint _deadline,
    address _token,
    uint _tokenVersion,
    uint _depositAmount,
    uint _nonce)
    public
    payable
    returns (uint)
    {
    bytes32 metaHash = keccak256(abi.encode(address(this),
                                                  "metaIssueAndContribute",
                                                  _issuers,
                                                  _approvers,
                                                  _data,
                                                  _deadline,
                                                  _token,
                                                  _tokenVersion,
                                                  _depositAmount,
                                                  _nonce));
    address signer = getSigner(metaHash, signature);

    //make sure signer doesn't come back as 0x0
    require(signer != address(0));
    require(_nonce == replayNonce[signer]);

    //increase the nonce to prevent replay attacks
    replayNonce[signer]++;

    if (msg.value > 0){
      return bountiesContract.issueAndContribute.value(msg.value)(address(uint160(signer)),
                                                 _issuers,
                                                 _approvers,
                                                 _data,
                                                 _deadline,
                                                 _token,
                                                 _tokenVersion,
                                                 _depositAmount);
    } else {
      return bountiesContract.issueAndContribute(address(uint160(signer)),
                                                 _issuers,
                                                 _approvers,
                                                 _data,
                                                 _deadline,
                                                 _token,
                                                 _tokenVersion,
                                                 _depositAmount);
    }

  }

  function metaContribute(
    bytes memory _signature,
    uint _bountyId,
    uint _amount,
    uint _nonce)
    public
    payable
    {
    bytes32 metaHash = keccak256(abi.encode(address(this),
                                                  "metaContribute",
                                                  _bountyId,
                                                  _amount,
                                                  _nonce));
    address signer = getSigner(metaHash, _signature);

    //make sure signer doesn't come back as 0x0
    require(signer != address(0));
    require(_nonce == replayNonce[signer]);

    //increase the nonce to prevent replay attacks
    replayNonce[signer]++;

    if (msg.value > 0){
      bountiesContract.contribute.value(msg.value)(address(uint160(signer)), _bountyId, _amount);
    } else {
      bountiesContract.contribute(address(uint160(signer)), _bountyId, _amount);
    }
  }


  function metaRefundContribution(
    bytes memory _signature,
    uint _bountyId,
    uint _contributionId,
    uint _nonce)
    public
    {
    bytes32 metaHash = keccak256(abi.encode(address(this),
                                                  "metaRefundContribution",
                                                  _bountyId,
                                                  _contributionId,
                                                  _nonce));
    address signer = getSigner(metaHash, _signature);

    //make sure signer doesn't come back as 0x0
    require(signer != address(0));
    require(_nonce == replayNonce[signer]);

    //increase the nonce to prevent replay attacks
    replayNonce[signer]++;

    bountiesContract.refundContribution(signer, _bountyId, _contributionId);
  }

  function metaRefundMyContributions(
    bytes memory _signature,
    uint _bountyId,
    uint[] memory _contributionIds,
    uint _nonce)
    public
    {
    bytes32 metaHash = keccak256(abi.encode(address(this),
                                                  "metaRefundMyContributions",
                                                  _bountyId,
                                                  _contributionIds,
                                                  _nonce));
    address signer = getSigner(metaHash, _signature);

    //make sure signer doesn't come back as 0x0
    require(signer != address(0));
    require(_nonce == replayNonce[signer]);

    //increase the nonce to prevent replay attacks
    replayNonce[signer]++;

    bountiesContract.refundMyContributions(signer, _bountyId, _contributionIds);
  }

  function metaRefundContributions(
    bytes memory _signature,
    uint _bountyId,
    uint _issuerId,
    uint[] memory _contributionIds,
    uint _nonce)
    public
    {
    bytes32 metaHash = keccak256(abi.encode(address(this),
                                                  "metaRefundContributions",
                                                  _bountyId,
                                                  _issuerId,
                                                  _contributionIds,
                                                  _nonce));
    address signer = getSigner(metaHash, _signature);

    //make sure signer doesn't come back as 0x0
    require(signer != address(0));
    require(_nonce == replayNonce[signer]);

    //increase the nonce to prevent replay attacks
    replayNonce[signer]++;

    bountiesContract.refundContributions(signer, _bountyId, _issuerId, _contributionIds);
  }

  function metaDrainBounty(
    bytes memory _signature,
    uint _bountyId,
    uint _issuerId,
    uint[] memory _amounts,
    uint _nonce)
    public
    {
    bytes32 metaHash = keccak256(abi.encode(address(this),
                                                  "metaDrainBounty",
                                                  _bountyId,
                                                  _issuerId,
                                                  _amounts,
                                                  _nonce));
    address payable signer = address(uint160(getSigner(metaHash, _signature)));

    //make sure signer doesn't come back as 0x0
    require(signer != address(0));
    require(_nonce == replayNonce[signer]);

    //increase the nonce to prevent replay attacks
    replayNonce[signer]++;

    bountiesContract.drainBounty(signer, _bountyId, _issuerId, _amounts);
  }

  function metaPerformAction(
    bytes memory _signature,
    uint _bountyId,
    string memory _data,
    uint256 _nonce)
    public
    {
    bytes32 metaHash = keccak256(abi.encode(address(this),
                                                  "metaPerformAction",
                                                  _bountyId,
                                                  _data,
                                                  _nonce));
    address signer = getSigner(metaHash, _signature);
    //make sure signer doesn't come back as 0x0
    require(signer != address(0));
    require(_nonce == replayNonce[signer]);

    //increase the nonce to prevent replay attacks
    replayNonce[signer]++;

    bountiesContract.performAction(signer, _bountyId, _data);
  }

  function metaFulfillBounty(
    bytes memory _signature,
    uint _bountyId,
    address payable[] memory  _fulfillers,
    string memory _data,
    uint256 _nonce)
    public
    {
    bytes32 metaHash = keccak256(abi.encode(address(this),
                                                  "metaFulfillBounty",
                                                  _bountyId,
                                                  _fulfillers,
                                                  _data,
                                                  _nonce));
    address signer = getSigner(metaHash, _signature);
    //make sure signer doesn't come back as 0x0
    require(signer != address(0));
    require(_nonce == replayNonce[signer]);

    //increase the nonce to prevent replay attacks
    replayNonce[signer]++;

    bountiesContract.fulfillBounty(signer, _bountyId, _fulfillers, _data);
  }

  function metaUpdateFulfillment(
    bytes memory _signature,
    uint _bountyId,
    uint _fulfillmentId,
    address payable[] memory  _fulfillers,
    string memory _data,
    uint256 _nonce)
    public
    {
    bytes32 metaHash = keccak256(abi.encode(address(this),
                                                  "metaUpdateFulfillment",
                                                  _bountyId,
                                                  _fulfillmentId,
                                                  _fulfillers,
                                                  _data,
                                                  _nonce));
    address signer = getSigner(metaHash, _signature);
    //make sure signer doesn't come back as 0x0
    require(signer != address(0));
    require(_nonce == replayNonce[signer]);

    //increase the nonce to prevent replay attacks
    replayNonce[signer]++;

    bountiesContract.updateFulfillment(signer, _bountyId, _fulfillmentId, _fulfillers, _data);
  }

  function metaAcceptFulfillment(
    bytes memory _signature,
    uint _bountyId,
    uint _fulfillmentId,
    uint _approverId,
    uint[] memory _tokenAmounts,
    uint256 _nonce)
    public
    {
    bytes32 metaHash = keccak256(abi.encode(address(this),
                                                  "metaAcceptFulfillment",
                                                  _bountyId,
                                                  _fulfillmentId,
                                                  _approverId,
                                                  _tokenAmounts,
                                                  _nonce));
    address signer = getSigner(metaHash, _signature);
    //make sure signer doesn't come back as 0x0
    require(signer != address(0));
    require(_nonce == replayNonce[signer]);

    //increase the nonce to prevent replay attacks
    replayNonce[signer]++;

    bountiesContract.acceptFulfillment(signer,
                       _bountyId,
                       _fulfillmentId,
                       _approverId,
                       _tokenAmounts);
  }

  function metaFulfillAndAccept(
    bytes memory _signature,
    uint _bountyId,
    address payable[] memory _fulfillers,
    string memory _data,
    uint _approverId,
    uint[] memory _tokenAmounts,
    uint256 _nonce)
    public
    {
    bytes32 metaHash = keccak256(abi.encode(address(this),
                                                  "metaFulfillAndAccept",
                                                  _bountyId,
                                                  _fulfillers,
                                                  _data,
                                                  _approverId,
                                                  _tokenAmounts,
                                                  _nonce));
    address signer = getSigner(metaHash, _signature);
    //make sure signer doesn't come back as 0x0
    require(signer != address(0));
    require(_nonce == replayNonce[signer]);

    //increase the nonce to prevent replay attacks
    replayNonce[signer]++;

    bountiesContract.fulfillAndAccept(signer,
                      _bountyId,
                      _fulfillers,
                      _data,
                      _approverId,
                      _tokenAmounts);
  }

  function metaChangeBounty(
    bytes memory _signature,
    uint _bountyId,
    uint _issuerId,
    address payable[] memory _issuers,
    address payable[] memory _approvers,
    string memory _data,
    uint _deadline,
    uint256 _nonce)
    public
    {
    bytes32 metaHash = keccak256(abi.encode(address(this),
                                                  "metaChangeBounty",
                                                  _bountyId,
                                                  _issuerId,
                                                  _issuers,
                                                  _approvers,
                                                  _data,
                                                  _deadline,
                                                  _nonce));
    address signer = getSigner(metaHash, _signature);
    //make sure signer doesn't come back as 0x0
    require(signer != address(0));
    require(_nonce == replayNonce[signer]);

    //increase the nonce to prevent replay attacks
    replayNonce[signer]++;

    bountiesContract.changeBounty(signer,
                  _bountyId,
                  _issuerId,
                  _issuers,
                  _approvers,
                  _data,
                  _deadline);
  }

  function metaChangeIssuer(
    bytes memory _signature,
    uint _bountyId,
    uint _issuerId,
    uint _issuerIdToChange,
    address payable _newIssuer,
    uint256 _nonce)
    public
    {
    bytes32 metaHash = keccak256(abi.encode(address(this),
                                                  "metaChangeIssuer",
                                                  _bountyId,
                                                  _issuerId,
                                                  _issuerIdToChange,
                                                  _newIssuer,
                                                  _nonce));
    address signer = getSigner(metaHash, _signature);
    //make sure signer doesn't come back as 0x0
    require(signer != address(0));
    require(_nonce == replayNonce[signer]);

    //increase the nonce to prevent replay attacks
    replayNonce[signer]++;

    bountiesContract.changeIssuer(signer,
                  _bountyId,
                  _issuerId,
                  _issuerIdToChange,
                  _newIssuer);
  }

  function metaChangeApprover(
    bytes memory _signature,
    uint _bountyId,
    uint _issuerId,
    uint _approverId,
    address payable _approver,
    uint256 _nonce)
    public
    {
    bytes32 metaHash = keccak256(abi.encode(address(this),
                                                  "metaChangeApprover",
                                                  _bountyId,
                                                  _issuerId,
                                                  _approverId,
                                                  _approver,
                                                  _nonce));
    address signer = getSigner(metaHash, _signature);
    //make sure signer doesn't come back as 0x0
    require(signer != address(0));
    require(_nonce == replayNonce[signer]);

    //increase the nonce to prevent replay attacks
    replayNonce[signer]++;

    bountiesContract.changeApprover(signer,
                  _bountyId,
                  _issuerId,
                  _approverId,
                  _approver);
  }

  function metaChangeData(
    bytes memory _signature,
    uint _bountyId,
    uint _issuerId,
    string memory _data,
    uint256 _nonce)
    public
    {
    bytes32 metaHash = keccak256(abi.encode(address(this),
                                                  "metaChangeData",
                                                  _bountyId,
                                                  _issuerId,
                                                  _data,
                                                  _nonce));
    address signer = getSigner(metaHash, _signature);
    //make sure signer doesn't come back as 0x0
    require(signer != address(0));
    require(_nonce == replayNonce[signer]);

    //increase the nonce to prevent replay attacks
    replayNonce[signer]++;

    bountiesContract.changeData(signer,
                _bountyId,
                _issuerId,
                _data);
  }

  function metaChangeDeadline(
    bytes memory _signature,
    uint _bountyId,
    uint _issuerId,
    uint  _deadline,
    uint256 _nonce)
    public
    {
    bytes32 metaHash = keccak256(abi.encode(address(this),
                                                  "metaChangeDeadline",
                                                  _bountyId,
                                                  _issuerId,
                                                  _deadline,
                                                  _nonce));
    address signer = getSigner(metaHash, _signature);
    //make sure signer doesn't come back as 0x0
    require(signer != address(0));
    require(_nonce == replayNonce[signer]);

    //increase the nonce to prevent replay attacks
    replayNonce[signer]++;

    bountiesContract.changeDeadline(signer,
                    _bountyId,
                    _issuerId,
                    _deadline);
  }

  function metaAddIssuers(
    bytes memory _signature,
    uint _bountyId,
    uint _issuerId,
    address payable[] memory _issuers,
    uint256 _nonce)
    public
    {
    bytes32 metaHash = keccak256(abi.encode(address(this),
                                                  "metaAddIssuers",
                                                  _bountyId,
                                                  _issuerId,
                                                  _issuers,
                                                  _nonce));
    address signer = getSigner(metaHash, _signature);
    //make sure signer doesn't come back as 0x0
    require(signer != address(0));
    require(_nonce == replayNonce[signer]);

    //increase the nonce to prevent replay attacks
    replayNonce[signer]++;

    bountiesContract.addIssuers(signer,
                _bountyId,
                _issuerId,
                _issuers);
  }

  function metaAddApprovers(
    bytes memory _signature,
    uint _bountyId,
    uint _issuerId,
    address[] memory _approvers,
    uint256 _nonce)
    public
    {
    bytes32 metaHash = keccak256(abi.encode(address(this),
                                                  "metaAddApprovers",
                                                  _bountyId,
                                                  _issuerId,
                                                  _approvers,
                                                  _nonce));
    address signer = getSigner(metaHash, _signature);
    //make sure signer doesn't come back as 0x0
    require(signer != address(0));
    require(_nonce == replayNonce[signer]);

    //increase the nonce to prevent replay attacks
    replayNonce[signer]++;

    bountiesContract.addApprovers(signer,
                _bountyId,
                _issuerId,
                _approvers);
  }

  function getSigner(
    bytes32 _hash,
    bytes memory _signature)
    internal
    pure
    returns (address)
  {
    bytes32 r;
    bytes32 s;
    uint8 v;
    if (_signature.length != 65){
      return address(0);
    }
    assembly {
      r := mload(add(_signature, 32))
      s := mload(add(_signature, 64))
      v := byte(0, mload(add(_signature, 96)))
    }
    if (v < 27){
      v += 27;
    }
    if (v != 27 && v != 28){
      return address(0);
    } else {
        return ecrecover(keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _hash)), v, r, s );
    }
  }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章