github.com/inklabsfoundation/inkchain@v0.17.1-0.20181025012015-c3cef8062f19/examples/xc/eth-v1.0.3/XCPlugin.sol (about)

     1  pragma solidity ^0.4.19;
     2  
     3  import "./XCPluginInterface.sol";
     4  
     5  contract XCPlugin is XCPluginInterface {
     6  
     7      /**
     8       * Contract Administrator
     9       * @field status Contract external service status.
    10       * @field platformName Current contract platform name.
    11       * @field tokenSymbol token Symbol.
    12       * @field account Current contract administrator.
    13       */
    14      struct Admin {
    15          bool status;
    16          bytes32 platformName;
    17          bytes32 tokenSymbol;
    18          address account;
    19          string version;
    20      }
    21  
    22      /**
    23       * Transaction Proposal
    24       * @field status Transaction proposal status(false:pending,true:complete).
    25       * @field fromAccount Account of form platform.
    26       * @field toAccount Account of to platform.
    27       * @field value Transfer amount.
    28       * @field tokenSymbol token Symbol.
    29       * @field voters Proposers.
    30       * @field weight The weight value of the completed time.
    31       */
    32      struct Proposal {
    33          bool status;
    34          address fromAccount;
    35          address toAccount;
    36          uint value;
    37          address[] voters;
    38          uint weight;
    39      }
    40  
    41      /**
    42       * Trusted Platform
    43       * @field status Trusted platform state(false:no trusted,true:trusted).
    44       * @field weight weight of platform.
    45       * @field publicKeys list of public key.
    46       * @field proposals list of proposal.
    47       */
    48      struct Platform {
    49          bool status;
    50          bytes32 name;
    51          uint weight;
    52          address[] publicKeys;
    53          mapping(string => Proposal) proposals;
    54      }
    55  
    56      Admin private admin;
    57  
    58      address[] private callers;
    59  
    60      Platform private platform;
    61  
    62  
    63      constructor() public {
    64          init();
    65      }
    66  
    67      /**
    68       * TODO Parameters that must be set before compilation
    69       * $Init admin.status
    70       * $Init admin.platformName
    71       * $Init admin.tokenSymbol
    72       * $Init admin.account
    73       * $Init admin.version
    74       * $Init platform.status
    75       * $Init platform.name
    76       * $Init platform.weight
    77       * $Init platform.publicKeys
    78       */
    79      function init() internal {
    80          // Admin { status | platformName | tokenSymbol | account}
    81          admin.status = true;
    82          admin.platformName = "ETH";
    83          admin.tokenSymbol = "INK";
    84          admin.account = msg.sender;
    85          admin.version = "1.0";
    86          platform.status = true;
    87          platform.name = "INK";
    88          platform.weight = 3;
    89          platform.publicKeys.push(0x80aa17b21c16620a4d7dd06ec1dcc44190b02ca0);
    90          platform.publicKeys.push(0xd2e40bb4967b355da8d70be40c277ebcf108063c);
    91          platform.publicKeys.push(0x1501e0f09498aa95cb0c2f1e3ee51223e5074720);
    92      }
    93  
    94      function start() onlyAdmin external {
    95          if (!admin.status) {
    96              admin.status = true;
    97          }
    98      }
    99  
   100      function stop() onlyAdmin external {
   101          if (admin.status) {
   102              admin.status = false;
   103          }
   104      }
   105  
   106      function getStatus() external view returns (bool) {
   107          return admin.status;
   108      }
   109  
   110      function getPlatformName() external view returns (bytes32) {
   111          return admin.platformName;
   112      }
   113  
   114      function setAdmin(address account) onlyAdmin nonzeroAddress(account) external {
   115          if (admin.account != account) {
   116              admin.account = account;
   117          }
   118      }
   119  
   120      function getAdmin() external view returns (address) {
   121          return admin.account;
   122      }
   123  
   124      function getTokenSymbol() external view returns (bytes32) {
   125          return admin.tokenSymbol;
   126      }
   127  
   128      function addCaller(address caller) onlyAdmin nonzeroAddress(caller) external {
   129          if (!_existCaller(caller)) {
   130              callers.push(caller);
   131          }
   132      }
   133  
   134      function deleteCaller(address caller) onlyAdmin nonzeroAddress(caller) external {
   135          for (uint i = 0; i < callers.length; i++) {
   136              if (callers[i] == caller) {
   137                  if (i != callers.length - 1 ) {
   138                      callers[i] = callers[callers.length - 1];
   139                  }
   140                  callers.length--;
   141                  return;
   142              }
   143          }
   144      }
   145  
   146      function existCaller(address caller) external view returns (bool) {
   147          return _existCaller(caller);
   148      }
   149  
   150      function getCallers() external view returns (address[]) {
   151          return callers;
   152      }
   153  
   154      function getTrustPlatform() external view returns (bytes32 name){
   155          return platform.name;
   156      }
   157  
   158      function setWeight(uint weight) onlyAdmin external {
   159          require(weight > 0);
   160          if (platform.weight != weight) {
   161              platform.weight = weight;
   162          }
   163      }
   164  
   165      function getWeight() external view returns (uint) {
   166          return platform.weight;
   167      }
   168  
   169      function addPublicKey(address publicKey) onlyAdmin nonzeroAddress(publicKey) external {
   170          address[] storage publicKeys = platform.publicKeys;
   171          for (uint i; i < publicKeys.length; i++) {
   172              if (publicKey == publicKeys[i]) {
   173                  return;
   174              }
   175          }
   176          publicKeys.push(publicKey);
   177      }
   178  
   179      function deletePublicKey(address publicKey) onlyAdmin nonzeroAddress(publicKey) external {
   180          address[] storage publicKeys = platform.publicKeys;
   181          for (uint i = 0; i < publicKeys.length; i++) {
   182              if (publicKeys[i] == publicKey) {
   183                  if (i != publicKeys.length - 1 ) {
   184                      publicKeys[i] = publicKeys[publicKeys.length - 1];
   185                  }
   186                  publicKeys.length--;
   187                  return;
   188              }
   189          }
   190      }
   191  
   192      function existPublicKey(address publicKey) external view returns (bool) {
   193          return _existPublicKey(publicKey);
   194      }
   195  
   196      function countOfPublicKey() external view returns (uint){
   197          return platform.publicKeys.length;
   198      }
   199  
   200      function publicKeys() external view returns (address[]){
   201          return platform.publicKeys;
   202      }
   203  
   204      function voteProposal(address fromAccount, address toAccount, uint value, string txid, bytes sig) opened external {
   205          bytes32 msgHash = hashMsg(platform.name, fromAccount, admin.platformName, toAccount, value, admin.tokenSymbol, txid,admin.version);
   206          address publicKey = recover(msgHash, sig);
   207          require(_existPublicKey(publicKey));
   208          Proposal storage proposal = platform.proposals[txid];
   209          if (proposal.value == 0) {
   210              proposal.fromAccount = fromAccount;
   211              proposal.toAccount = toAccount;
   212              proposal.value = value;
   213          } else {
   214              require(proposal.fromAccount == fromAccount && proposal.toAccount == toAccount && proposal.value == value);
   215          }
   216          changeVoters(publicKey, txid);
   217      }
   218  
   219      function verifyProposal(address fromAccount, address toAccount, uint value, string txid) external view returns (bool, bool) {
   220          Proposal storage proposal = platform.proposals[txid];
   221          if (proposal.status) {
   222              return (true, (proposal.voters.length >= proposal.weight));
   223          }
   224          if (proposal.value == 0) {
   225              return (false, false);
   226          }
   227          require(proposal.fromAccount == fromAccount && proposal.toAccount == toAccount && proposal.value == value);
   228          return (false, (proposal.voters.length >= platform.weight));
   229      }
   230  
   231      function commitProposal(string txid) external returns (bool) {
   232          require((admin.status &&_existCaller(msg.sender)) || msg.sender == admin.account);
   233          require(!platform.proposals[txid].status);
   234          platform.proposals[txid].status = true;
   235          platform.proposals[txid].weight = platform.proposals[txid].voters.length;
   236          return true;
   237      }
   238  
   239      function getProposal(string txid) external view returns (bool status, address fromAccount, address toAccount, uint value, address[] voters, uint weight){
   240          fromAccount = platform.proposals[txid].fromAccount;
   241          toAccount = platform.proposals[txid].toAccount;
   242          value = platform.proposals[txid].value;
   243          voters = platform.proposals[txid].voters;
   244          status = platform.proposals[txid].status;
   245          weight = platform.proposals[txid].weight;
   246          return;
   247      }
   248  
   249      function deleteProposal(string txid) onlyAdmin external {
   250          delete platform.proposals[txid];
   251      }
   252  
   253      /**
   254       *   ######################
   255       *  #  private function  #
   256       * ######################
   257       */
   258  
   259      function hashMsg(bytes32 fromPlatform, address fromAccount, bytes32 toPlatform, address toAccount, uint value, bytes32 tokenSymbol, string txid,string version) internal pure returns (bytes32) {
   260          return sha256(bytes32ToStr(fromPlatform), ":0x", uintToStr(uint160(fromAccount), 16), ":", bytes32ToStr(toPlatform), ":0x", uintToStr(uint160(toAccount), 16), ":", uintToStr(value, 10), ":", bytes32ToStr(tokenSymbol), ":", txid, ":", version);
   261      }
   262  
   263      function changeVoters(address publicKey, string txid) internal {
   264          address[] storage voters = platform.proposals[txid].voters;
   265          for (uint i = 0; i < voters.length; i++) {
   266              if (voters[i] == publicKey) {
   267                  return;
   268              }
   269          }
   270          voters.push(publicKey);
   271      }
   272  
   273      function bytes32ToStr(bytes32 b) internal pure returns (string) {
   274          uint length = b.length;
   275          for (uint i = 0; i < b.length; i++) {
   276              if (b[b.length - 1 - i] != "") {
   277                  length -= i;
   278                  break;
   279              }
   280          }
   281          bytes memory bs = new bytes(length);
   282          for (uint j = 0; j < length; j++) {
   283              bs[j] = b[j];
   284          }
   285          return string(bs);
   286      }
   287  
   288      function uintToStr(uint value, uint base) internal pure returns (string) {
   289          uint _value = value;
   290          uint length = 0;
   291          bytes16 tenStr = "0123456789abcdef";
   292          while (true) {
   293              if (_value > 0) {
   294                  length ++;
   295                  _value = _value / base;
   296              } else {
   297                  break;
   298              }
   299          }
   300          if (base == 16) {
   301              length = 40;
   302          }
   303          bytes memory bs = new bytes(length);
   304          for (uint i = 0; i < length; i++) {
   305              bs[length - 1 - i] = tenStr[value % base];
   306              value = value / base;
   307          }
   308          return string(bs);
   309      }
   310  
   311      function _existCaller(address caller) internal view returns (bool) {
   312          for (uint i = 0; i < callers.length; i++) {
   313              if (callers[i] == caller) {
   314                  return true;
   315              }
   316          }
   317          return false;
   318      }
   319  
   320      function _existPublicKey(address publicKey) internal view returns (bool) {
   321          address[] memory publicKeys = platform.publicKeys;
   322          for (uint i = 0; i < publicKeys.length; i++) {
   323              if (publicKeys[i] == publicKey) {
   324                  return true;
   325              }
   326          }
   327          return false;
   328      }
   329  
   330      function recover(bytes32 hash, bytes sig) internal pure returns (address) {
   331          bytes32 r;
   332          bytes32 s;
   333          uint8 v;
   334          assembly {
   335              r := mload(add(sig, 32))
   336              s := mload(add(sig, 64))
   337              v := byte(0, mload(add(sig, 96)))
   338          }
   339          if (v < 27) {
   340              v += 27;
   341          }
   342          return ecrecover(hash, v, r, s);
   343      }
   344  
   345      modifier onlyAdmin {
   346          require(admin.account == msg.sender);
   347          _;
   348      }
   349  
   350      modifier nonzeroAddress(address account) {
   351          require(account != address(0));
   352          _;
   353      }
   354  
   355      modifier opened() {
   356          require(admin.status);
   357          _;
   358      }
   359  }