github.com/inklabsfoundation/inkchain@v0.17.1-0.20181025012015-c3cef8062f19/examples/xc/qtum/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 = "QTUM"; 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 180 function _existCaller(address caller) internal view returns (bool) { 181 182 for (uint i = 0; i < callers.length; i++) { 183 184 if (callers[i] == caller) { 185 186 return true; 187 } 188 } 189 190 return false; 191 } 192 193 function getCallers() external view returns (address[]) { 194 195 require(admin.account == msg.sender); 196 197 return callers; 198 } 199 200 function addPlatform(bytes32 name) external { 201 202 require(admin.account == msg.sender); 203 204 require(name != ""); 205 206 require(name != admin.platformName); 207 208 if (!_existPlatform(name)) { 209 210 platforms[name].status = true; 211 212 if (platforms[name].weight == 0) { 213 214 platforms[name].weight = 1; 215 } 216 } 217 } 218 219 function deletePlatform(bytes32 name) external { 220 221 require(admin.account == msg.sender); 222 223 require(name != admin.platformName); 224 225 if (_existPlatform(name)) { 226 227 platforms[name].status = false; 228 } 229 } 230 231 function existPlatform(bytes32 name) external view returns (bool){ 232 233 return _existPlatform(name); 234 } 235 236 function _existPlatform(bytes32 name) internal view returns (bool){ 237 238 return platforms[name].status; 239 } 240 241 function setWeight(bytes32 platformName, uint weight) external { 242 243 require(admin.account == msg.sender); 244 245 require(_existPlatform(platformName)); 246 247 require(weight > 0); 248 249 if (platforms[platformName].weight != weight) { 250 251 platforms[platformName].weight = weight; 252 } 253 } 254 255 function getWeight(bytes32 platformName) external view returns (uint) { 256 257 require(admin.account == msg.sender); 258 259 require(_existPlatform(platformName)); 260 261 return platforms[platformName].weight; 262 } 263 264 function addPublicKey(bytes32 platformName, address publicKey) external { 265 266 require(admin.account == msg.sender); 267 268 require(_existPlatform(platformName)); 269 270 require(publicKey != address(0)); 271 272 address[] storage listOfPublicKey = platforms[platformName].publicKeys; 273 274 for (uint i; i < listOfPublicKey.length; i++) { 275 276 if (publicKey == listOfPublicKey[i]) { 277 278 return; 279 } 280 } 281 282 listOfPublicKey.push(publicKey); 283 } 284 285 function deletePublicKey(bytes32 platformName, address publickey) external { 286 287 require(admin.account == msg.sender); 288 289 require(_existPlatform(platformName)); 290 291 address[] storage listOfPublicKey = platforms[platformName].publicKeys; 292 293 bool exist; 294 295 for (uint i = 0; i <= listOfPublicKey.length; i++) { 296 297 if (exist) { 298 if (i == listOfPublicKey.length) { 299 300 delete listOfPublicKey[i - 1]; 301 302 listOfPublicKey.length--; 303 } else { 304 305 listOfPublicKey[i - 1] = listOfPublicKey[i]; 306 } 307 } else if (listOfPublicKey[i] == publickey) { 308 309 exist = true; 310 } 311 } 312 } 313 314 function existPublicKey(bytes32 platformName, address publicKey) external view returns (bool) { 315 316 require(admin.account == msg.sender); 317 318 return _existPublicKey(platformName, publicKey); 319 } 320 321 function _existPublicKey(bytes32 platformName, address publicKey) internal view returns (bool) { 322 323 324 address[] memory listOfPublicKey = platforms[platformName].publicKeys; 325 326 for (uint i = 0; i < listOfPublicKey.length; i++) { 327 328 if (listOfPublicKey[i] == publicKey) { 329 330 return true; 331 } 332 } 333 334 return false; 335 } 336 337 function countOfPublicKey(bytes32 platformName) external view returns (uint){ 338 339 require(admin.account == msg.sender); 340 341 require(_existPlatform(platformName)); 342 343 return platforms[platformName].publicKeys.length; 344 } 345 346 function publicKeys(bytes32 platformName) external view returns (address[]){ 347 348 require(admin.account == msg.sender); 349 350 require(_existPlatform(platformName)); 351 352 return platforms[platformName].publicKeys; 353 } 354 355 function voteProposal(bytes32 fromPlatform, address fromAccount, address toAccount, uint value, string txid, bytes32 r, bytes32 s, uint8 v) external { 356 357 require(admin.status); 358 359 require(_existPlatform(fromPlatform)); 360 361 bytes32 msgHash = hashMsg(fromPlatform, fromAccount, admin.platformName, toAccount, value, txid); 362 363 address publicKey = ecrecover(msgHash, v, r, s); 364 365 require(_existPublicKey(fromPlatform, publicKey)); 366 367 Proposal storage proposal = platforms[fromPlatform].proposals[txid]; 368 369 if (proposal.value == 0) { 370 371 proposal.fromAccount = fromAccount; 372 373 proposal.toAccount = toAccount; 374 375 proposal.value = value; 376 } else { 377 378 require(proposal.fromAccount == fromAccount && proposal.toAccount == toAccount && proposal.value == value); 379 } 380 381 changeVoters(fromPlatform, publicKey, txid); 382 } 383 384 function verifyProposal(bytes32 fromPlatform, address fromAccount, address toAccount, uint value, string txid) external view returns (bool, bool) { 385 386 require(admin.status); 387 388 require(_existPlatform(fromPlatform)); 389 390 Proposal storage proposal = platforms[fromPlatform].proposals[txid]; 391 392 if (proposal.status) { 393 394 return (true, (proposal.voters.length >= proposal.weight)); 395 } 396 397 if (proposal.value == 0) { 398 399 return (false, false); 400 } 401 402 require(proposal.fromAccount == fromAccount && proposal.toAccount == toAccount && proposal.value == value); 403 404 return (false, (proposal.voters.length >= platforms[fromPlatform].weight)); 405 } 406 407 function commitProposal(bytes32 platformName, string txid) external returns (bool) { 408 409 require(admin.status); 410 411 require(_existCaller(msg.sender) || msg.sender == admin.account); 412 413 require(_existPlatform(platformName)); 414 415 require(!platforms[platformName].proposals[txid].status); 416 417 platforms[platformName].proposals[txid].status = true; 418 419 platforms[platformName].proposals[txid].weight = platforms[platformName].proposals[txid].voters.length; 420 421 return true; 422 } 423 424 function getProposal(bytes32 platformName, string txid) external view returns (bool status, address fromAccount, address toAccount, uint value, address[] voters, uint weight){ 425 426 require(admin.status); 427 428 require(_existPlatform(platformName)); 429 430 fromAccount = platforms[platformName].proposals[txid].fromAccount; 431 432 toAccount = platforms[platformName].proposals[txid].toAccount; 433 434 value = platforms[platformName].proposals[txid].value; 435 436 voters = platforms[platformName].proposals[txid].voters; 437 438 status = platforms[platformName].proposals[txid].status; 439 440 weight = platforms[platformName].proposals[txid].weight; 441 442 return; 443 } 444 445 function deleteProposal(bytes32 platformName, string txid) external { 446 447 require(msg.sender == admin.account); 448 449 require(_existPlatform(platformName)); 450 451 delete platforms[platformName].proposals[txid]; 452 } 453 454 function transfer(address account, uint value) external payable { 455 456 require(admin.account == msg.sender); 457 458 require(account != address(0)); 459 460 require(value > 0 && value >= this.balance); 461 462 this.transfer(account, value); 463 } 464 465 /** 466 * ###################### 467 * # private function # 468 * ###################### 469 */ 470 471 function hashMsg(bytes32 fromPlatform, address fromAccount, bytes32 toPlatform, address toAccount, uint value, string txid) internal pure returns (bytes32) { 472 473 return sha256(bytes32ToStr(fromPlatform), ":0x", uintToStr(uint160(fromAccount), 16), ":", bytes32ToStr(toPlatform), ":0x", uintToStr(uint160(toAccount), 16), ":", uintToStr(value, 10), ":", txid); 474 } 475 476 function changeVoters(bytes32 platformName, address publicKey, string txid) internal { 477 478 address[] storage voters = platforms[platformName].proposals[txid].voters; 479 480 bool change = true; 481 482 for (uint i = 0; i < voters.length; i++) { 483 484 if (voters[i] == publicKey) { 485 486 change = false; 487 } 488 } 489 490 if (change) { 491 492 voters.push(publicKey); 493 } 494 } 495 496 function bytes32ToBytes(bytes32 b) internal pure returns (bytes) { 497 498 uint length = b.length; 499 500 for (uint i = 0; i < b.length; i++) { 501 502 if (b[b.length - 1 - i] == "") { 503 504 length -= 1; 505 } else { 506 507 break; 508 } 509 } 510 511 bytes memory bs = new bytes(length); 512 513 for (uint j = 0; j < length; j++) { 514 515 bs[j] = b[j]; 516 } 517 518 return bs; 519 } 520 521 function bytes32ToStr(bytes32 b) internal pure returns (string) { 522 523 bytes memory bs = bytes32ToBytes(b); 524 525 return string(bs); 526 } 527 528 function uintToStr(uint value, uint base) internal pure returns (string) { 529 530 uint _value = value; 531 532 uint length = 0; 533 534 bytes16 tenStr = "0123456789abcdef"; 535 536 while (true) { 537 538 if (_value > 0) { 539 540 length ++; 541 542 _value = _value / base; 543 } else { 544 545 break; 546 } 547 } 548 549 if (base == 16) { 550 length = 40; 551 } 552 553 bytes memory bs = new bytes(length); 554 555 for (uint i = 0; i < length; i++) { 556 557 bs[length - 1 - i] = tenStr[value % base]; 558 559 value = value / base; 560 } 561 562 return string(bs); 563 } 564 565 }