github.com/inklabsfoundation/inkchain@v0.17.1-0.20181025012015-c3cef8062f19/examples/xc/eth/contracts/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 account Current contract administrator. 12 */ 13 struct Admin { 14 15 bool status; 16 17 bytes32 platformName; 18 19 address account; 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 voters Proposers. 29 * @field weight The weight value of the completed time. 30 */ 31 struct Proposal { 32 33 bool status; 34 35 address fromAccount; 36 37 address toAccount; 38 39 uint value; 40 41 address[] voters; 42 43 uint weight; 44 } 45 46 /** 47 * Trusted Platform 48 * @field status Trusted platform state(false:no trusted,true:trusted). 49 * @field weight weight of platform. 50 * @field publicKeys list of public key. 51 * @field proposals list of proposal. 52 */ 53 struct Platform { 54 55 bool status; 56 57 uint weight; 58 59 address[] publicKeys; 60 61 mapping(string => Proposal) proposals; 62 } 63 64 Admin private admin; 65 66 address[] private callers; 67 68 mapping(bytes32 => Platform) private platforms; 69 70 function XCPlugin() public { 71 //TODO 72 bytes32 name = "ETH"; 73 74 admin = Admin(false, name, msg.sender); 75 } 76 77 function start() external { 78 79 require(admin.account == msg.sender); 80 81 if (!admin.status) { 82 83 admin.status = true; 84 } 85 } 86 87 function stop() external { 88 89 require(admin.account == msg.sender); 90 91 if (admin.status) { 92 93 admin.status = false; 94 } 95 } 96 97 function getStatus() external view returns (bool) { 98 99 return admin.status; 100 } 101 102 function setPlatformName(bytes32 platformName) external { 103 104 require(admin.account == msg.sender); 105 106 if (admin.platformName != platformName) { 107 108 admin.platformName = platformName; 109 } 110 } 111 112 function getPlatformName() external view returns (bytes32) { 113 114 return admin.platformName; 115 } 116 117 function setAdmin(address account) external { 118 119 require(account != address(0)); 120 121 require(admin.account == msg.sender); 122 123 if (admin.account != account) { 124 125 admin.account = account; 126 } 127 } 128 129 function getAdmin() external view returns (address) { 130 131 return admin.account; 132 } 133 134 function addCaller(address caller) external { 135 136 require(admin.account == msg.sender); 137 138 if (!_existCaller(caller)) { 139 140 callers.push(caller); 141 } 142 } 143 144 function deleteCaller(address caller) external { 145 146 require(admin.account == msg.sender); 147 148 if (_existCaller(caller)) { 149 150 bool exist; 151 152 for (uint i = 0; i <= callers.length; i++) { 153 154 if (exist) { 155 156 if (i == callers.length) { 157 158 delete callers[i - 1]; 159 160 callers.length--; 161 } else { 162 163 callers[i - 1] = callers[i]; 164 } 165 } else if (callers[i] == caller) { 166 167 exist = true; 168 } 169 } 170 171 } 172 } 173 174 function existCaller(address caller) external view returns (bool) { 175 176 return _existCaller(caller); 177 } 178 179 function _existCaller(address caller) internal view returns (bool) { 180 181 for (uint i = 0; i < callers.length; i++) { 182 183 if (callers[i] == caller) { 184 185 return true; 186 } 187 } 188 189 return false; 190 } 191 192 function getCallers() external view returns (address[]) { 193 194 require(admin.account == msg.sender); 195 196 return callers; 197 } 198 199 function addPlatform(bytes32 name) external { 200 201 require(admin.account == msg.sender); 202 203 require(name != ""); 204 205 require(name != admin.platformName); 206 207 if (!_existPlatform(name)) { 208 209 platforms[name].status = true; 210 211 if (platforms[name].weight == 0) { 212 213 platforms[name].weight = 1; 214 } 215 } 216 } 217 218 function deletePlatform(bytes32 name) external { 219 220 require(admin.account == msg.sender); 221 222 require(name != admin.platformName); 223 224 if (_existPlatform(name)) { 225 226 platforms[name].status = false; 227 } 228 } 229 230 function existPlatform(bytes32 name) external view returns (bool){ 231 232 return _existPlatform(name); 233 } 234 235 function _existPlatform(bytes32 name) internal view returns (bool){ 236 237 return platforms[name].status; 238 } 239 240 function setWeight(bytes32 platformName, uint weight) external { 241 242 require(admin.account == msg.sender); 243 244 require(_existPlatform(platformName)); 245 246 require(weight > 0); 247 248 if (platforms[platformName].weight != weight) { 249 250 platforms[platformName].weight = weight; 251 } 252 } 253 254 function getWeight(bytes32 platformName) external view returns (uint) { 255 256 require(admin.account == msg.sender); 257 258 require(_existPlatform(platformName)); 259 260 return platforms[platformName].weight; 261 } 262 263 function addPublicKey(bytes32 platformName, address publicKey) external { 264 265 require(admin.account == msg.sender); 266 267 require(_existPlatform(platformName)); 268 269 require(publicKey != address(0)); 270 271 address[] storage listOfPublicKey = platforms[platformName].publicKeys; 272 273 for (uint i; i < listOfPublicKey.length; i++) { 274 275 if (publicKey == listOfPublicKey[i]) { 276 277 return; 278 } 279 } 280 281 listOfPublicKey.push(publicKey); 282 } 283 284 function deletePublicKey(bytes32 platformName, address publickey) external { 285 286 require(admin.account == msg.sender); 287 288 require(_existPlatform(platformName)); 289 290 address[] storage listOfPublicKey = platforms[platformName].publicKeys; 291 292 bool exist; 293 294 for (uint i = 0; i <= listOfPublicKey.length; i++) { 295 296 if (exist) { 297 if (i == listOfPublicKey.length) { 298 299 delete listOfPublicKey[i - 1]; 300 301 listOfPublicKey.length--; 302 } else { 303 304 listOfPublicKey[i - 1] = listOfPublicKey[i]; 305 } 306 } else if (listOfPublicKey[i] == publickey) { 307 308 exist = true; 309 } 310 } 311 } 312 313 function existPublicKey(bytes32 platformName, address publicKey) external view returns (bool) { 314 315 require(admin.account == msg.sender); 316 317 return _existPublicKey(platformName, publicKey); 318 } 319 320 function _existPublicKey(bytes32 platformName, address publicKey) internal view returns (bool) { 321 322 address[] memory listOfPublicKey = platforms[platformName].publicKeys; 323 324 for (uint i = 0; i < listOfPublicKey.length; i++) { 325 326 if (listOfPublicKey[i] == publicKey) { 327 328 return true; 329 } 330 } 331 332 return false; 333 } 334 335 function countOfPublicKey(bytes32 platformName) external view returns (uint){ 336 337 require(admin.account == msg.sender); 338 339 require(_existPlatform(platformName)); 340 341 return platforms[platformName].publicKeys.length; 342 } 343 344 function publicKeys(bytes32 platformName) external view returns (address[]){ 345 346 require(admin.account == msg.sender); 347 348 require(_existPlatform(platformName)); 349 350 return platforms[platformName].publicKeys; 351 } 352 353 function voteProposal(bytes32 fromPlatform, address fromAccount, address toAccount, uint value, string txid, bytes32 r, bytes32 s, uint8 v) external { 354 355 require(admin.status); 356 357 require(_existPlatform(fromPlatform)); 358 359 bytes32 msgHash = hashMsg(fromPlatform, fromAccount, admin.platformName, toAccount, value, txid); 360 361 address publicKey = ecrecover(msgHash, v, r, s); 362 363 require(_existPublicKey(fromPlatform, publicKey)); 364 365 Proposal storage proposal = platforms[fromPlatform].proposals[txid]; 366 367 if (proposal.value == 0) { 368 369 proposal.fromAccount = fromAccount; 370 371 proposal.toAccount = toAccount; 372 373 proposal.value = value; 374 } else { 375 376 require(proposal.fromAccount == fromAccount && proposal.toAccount == toAccount && proposal.value == value); 377 } 378 379 changeVoters(fromPlatform, publicKey, txid); 380 } 381 382 function verifyProposal(bytes32 fromPlatform, address fromAccount, address toAccount, uint value, string txid) external view returns (bool, bool) { 383 384 require(admin.status); 385 386 require(_existPlatform(fromPlatform)); 387 388 Proposal storage proposal = platforms[fromPlatform].proposals[txid]; 389 390 if (proposal.status) { 391 392 return (true, (proposal.voters.length >= proposal.weight)); 393 } 394 395 if (proposal.value == 0) { 396 397 return (false, false); 398 } 399 400 require(proposal.fromAccount == fromAccount && proposal.toAccount == toAccount && proposal.value == value); 401 402 return (false, (proposal.voters.length >= platforms[fromPlatform].weight)); 403 } 404 405 function commitProposal(bytes32 platformName, string txid) external returns (bool) { 406 407 require(admin.status); 408 409 require(_existCaller(msg.sender) || msg.sender == admin.account); 410 411 require(_existPlatform(platformName)); 412 413 require(!platforms[platformName].proposals[txid].status); 414 415 platforms[platformName].proposals[txid].status = true; 416 417 platforms[platformName].proposals[txid].weight = platforms[platformName].proposals[txid].voters.length; 418 419 return true; 420 } 421 422 function getProposal(bytes32 platformName, string txid) external view returns (bool status, address fromAccount, address toAccount, uint value, address[] voters, uint weight){ 423 424 require(admin.status); 425 426 require(_existPlatform(platformName)); 427 428 fromAccount = platforms[platformName].proposals[txid].fromAccount; 429 430 toAccount = platforms[platformName].proposals[txid].toAccount; 431 432 value = platforms[platformName].proposals[txid].value; 433 434 voters = platforms[platformName].proposals[txid].voters; 435 436 status = platforms[platformName].proposals[txid].status; 437 438 weight = platforms[platformName].proposals[txid].weight; 439 440 return; 441 } 442 443 function deleteProposal(bytes32 platformName, string txid) external { 444 445 require(msg.sender == admin.account); 446 447 require(_existPlatform(platformName)); 448 449 delete platforms[platformName].proposals[txid]; 450 } 451 452 function transfer(address account, uint value) external payable { 453 454 require(admin.account == msg.sender); 455 456 require(account != address(0)); 457 458 require(value > 0 && value >= this.balance); 459 460 this.transfer(account, value); 461 } 462 463 /** 464 * ###################### 465 * # private function # 466 * ###################### 467 */ 468 469 function hashMsg(bytes32 fromPlatform, address fromAccount, bytes32 toPlatform, address toAccount, uint value, string txid) internal pure returns (bytes32) { 470 471 return sha256(bytes32ToStr(fromPlatform), ":0x", uintToStr(uint160(fromAccount), 16), ":", bytes32ToStr(toPlatform), ":0x", uintToStr(uint160(toAccount), 16), ":", uintToStr(value, 10), ":", txid); 472 } 473 474 function changeVoters(bytes32 platformName, address publicKey, string txid) internal { 475 476 address[] storage voters = platforms[platformName].proposals[txid].voters; 477 478 bool change = true; 479 480 for (uint i = 0; i < voters.length; i++) { 481 482 if (voters[i] == publicKey) { 483 484 change = false; 485 } 486 } 487 488 if (change) { 489 490 voters.push(publicKey); 491 } 492 } 493 494 function bytes32ToBytes(bytes32 b) internal pure returns (bytes) { 495 496 uint length = b.length; 497 498 for (uint i = 0; i < b.length; i++) { 499 500 if (b[b.length - 1 - i] == "") { 501 502 length -= 1; 503 } else { 504 505 break; 506 } 507 } 508 509 bytes memory bs = new bytes(length); 510 511 for (uint j = 0; j < length; j++) { 512 513 bs[j] = b[j]; 514 } 515 516 return bs; 517 } 518 519 function bytes32ToStr(bytes32 b) internal pure returns (string) { 520 521 bytes memory bs = bytes32ToBytes(b); 522 523 return string(bs); 524 } 525 526 function uintToStr(uint value, uint base) internal pure returns (string) { 527 528 uint _value = value; 529 530 uint length = 0; 531 532 bytes16 tenStr = "0123456789abcdef"; 533 534 while (true) { 535 536 if (_value > 0) { 537 538 length ++; 539 540 _value = _value / base; 541 } else { 542 543 break; 544 } 545 } 546 547 if (base == 16) { 548 length = 40; 549 } 550 551 bytes memory bs = new bytes(length); 552 553 for (uint i = 0; i < length; i++) { 554 555 bs[length - 1 - i] = tenStr[value % base]; 556 557 value = value / base; 558 } 559 560 return string(bs); 561 } 562 563 }