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 }