diff --git a/README.md b/README.md index 482a63a4..8ddc1658 100644 --- a/README.md +++ b/README.md @@ -1 +1,35 @@ -# sol-lib \ No newline at end of file +# 组件介绍 + +智能合约库模板,涵盖了从基础类型到上层业务的常见代码,用户可根据实际需要进行参考、复用。内部包含几个模块: + +[](https://toolkit-doc.readthedocs.io/zh_CN/latest/_images/wescott.png) + +## 环境要求 + +| 依赖软件 | 说明 |备注| +| --- | --- | --- | +| Solidity |>= 0.6.10 | 需使用0.6.10版本编译| +| Git | 下载需要使用Git | | + +## 文档 +- [**中文**](https://toolkit-doc.readthedocs.io/zh_CN/latest/docs/WeBankBlockchain-Toolkit-Contract/index.html) + +## 贡献代码 +欢迎参与本项目的社区建设: +- 如项目对您有帮助,欢迎点亮我们的小星星(点击项目左上方Star按钮)。 +- 欢迎提交代码(Pull requests)。 +- [提问和提交BUG](https://github.com/WeBankBlockchain/SmartDev-Contract/issues)。 +- 如果发现代码存在安全漏洞,请在[这里](https://security.webank.com)上报。 + + +![](https://media.githubusercontent.com/media/FISCO-BCOS/LargeFiles/master/images/QR_image.png) + + +## License +![license](http://img.shields.io/badge/license-Apache%20v2-blue.svg) + +开源协议为[Apache License 2.0](http://www.apache.org/licenses/). 详情参考[LICENSE](../LICENSE)。 + + + + diff --git a/contracts/base_type/LibAddress.sol b/contracts/base_type/LibAddress.sol new file mode 100644 index 00000000..c6d78b4e --- /dev/null +++ b/contracts/base_type/LibAddress.sol @@ -0,0 +1,133 @@ +/* + * Copyright 2014-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * */ + +pragma solidity>=0.4.24 <0.6.11; + +library LibAddress{ + + /* + *@dev + *@param + *@return + */ + function isContract(address account) internal view returns(bool) { + uint256 size; + assembly { size := extcodesize(account) } + return size> 0; + } + + function isEmptyAddress(address addr) internal pure returns(bool){ + return addr == address(0); + } + + + function addressToBytes(address addr) internal pure returns (bytes memory){ + bytes20 addrBytes = bytes20(uint160(addr)); + bytes memory rtn = new bytes(20); + for(uint8 i=0;i<20;i++){ + rtn[i] = addrBytes[i]; + } + return rtn; + } + + + function bytesToAddress(bytes memory addrBytes) internal pure returns (address){ + require(addrBytes.length == 20); + //Convert binary to uint160 + uint160 intVal = 0; + + for(uint8 i=0;i<20;i++){ + intVal <<= 8; + intVal += uint8(addrBytes[i]); + } + return address(intVal); + } + + + function addressToString(address addr) internal pure returns(string memory){ + //Convert addr to bytes + bytes20 value = bytes20(uint160(addr)); + bytes memory strBytes = new bytes(42); + //Encode hex prefix + strBytes[0] = '0'; + strBytes[1] = 'x'; + //Encode bytes usig hex encoding + for(uint i=0;i<20;i++){ + uint8 byteValue = uint8(value[i]); + strBytes[2 + (i<<1)] = encode((byteValue>> 4) & 0x0f); + strBytes[3 + (i<<1)] = encode(byteValue & 0x0f); + } + return string(strBytes); + } + + function stringToAddress(string memory data) internal returns(address){ + bytes memory strBytes = bytes(data); + require(strBytes.length>= 39 && strBytes.length <= 42, "Not hex string"); + //Skip prefix + uint start = 0; + uint bytesBegin = 0; + if(strBytes[1] == 'x' || strBytes[1] == 'X'){ + start = 2; + } + //Special case: 0xabc. should be 0x0abc + uint160 addrValue = 0; + uint effectPayloadLen = strBytes.length - start; + if(effectPayloadLen == 39){ + addrValue += decode(strBytes[start++]); + bytesBegin++; + } + //Main loop + for(uint i=bytesBegin;i < 20; i++){ + addrValue <<= 8; + uint8 tmp1 = decode(strBytes[start]); + uint8 tmp2 = decode(strBytes[start+1]); + uint8 combined = (tmp1 << 4) + tmp2; + addrValue += combined; + start+=2; + } + + return address(addrValue); + } + + + //-----------HELPER METHOD--------------// + + //num represents a number from 0-15 and returns ascii representing [0-9A-Fa-f] + function encode(uint8 num) private pure returns(byte){ + //0-9 -> 0-9 + if(num>= 0 && num <= 9){ + return byte(num + 48); + } + //10-15 -> a-f + return byte(num + 87); + } + + //asc represents one of the char:[0-9A-Fa-f] and returns consperronding value from 0-15 + function decode(byte asc) private pure returns(uint8){ + uint8 val = uint8(asc); + //0-9 + if(val>= 48 && val <= 57){ + return val - 48; + } + //A-F + if(val>= 65 && val <= 70){ + return val - 55; + } + //a-f + return val - 87; + } + +} diff --git a/contracts/base_type/LibArrayForUint256Utils.sol b/contracts/base_type/LibArrayForUint256Utils.sol new file mode 100644 index 00000000..c6efd70a --- /dev/null +++ b/contracts/base_type/LibArrayForUint256Utils.sol @@ -0,0 +1,198 @@ +/* + * Copyright 2014-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * */ + +pragma solidity>=0.4.24 <0.6.11; + +import "./LibSafeMathForUint256Utils.sol"; + +library LibArrayForUint256Utils { + + /** + * @dev Searches a sortd uint256 array and returns the first element index that + * match the key value, Time complexity O(log n) + * + * @param array is expected to be sorted in ascending order + * @param key is element + * + * @return if matches key in the array return true,else return false + * @return the first element index that match the key value,if not exist,return 0 + */ + function binarySearch(uint256[] storage array, uint256 key) internal view returns (bool, uint) { + if(array.length == 0){ + return (false, 0); + } + + uint256 low = 0; + uint256 high = array.length-1; + + while(low <= high){ + uint256 mid = LibSafeMathForUint256Utils.average(low, high); + if(array[mid] == key){ + return (true, mid); + }else if (array[mid]> key) { + high = mid - 1; + } else { + low = mid + 1; + } + } + + return (false, 0); + } + + function firstIndexOf(uint256[] storage array, uint256 key) internal view returns (bool, uint256) { + + if(array.length == 0){ + return (false, 0); + } + + for(uint256 i = 0; i < array.length; i++){ + if(array[i] == key){ + return (true, i); + } + } + return (false, 0); + } + + function reverse(uint256[] storage array) internal { + uint256 temp; + for (uint i = 0; i < array.length / 2; i++) { + temp = array[i]; + array[i] = array[array.length - 1 - i]; + array[array.length - 1 - i] = temp; + } + } + + function equals(uint256[] storage a, uint256[] storage b) internal view returns (bool){ + if(a.length != b.length){ + return false; + } + for(uint256 i = 0; i < a.length; i++){ + if(a[i] != b[i]){ + return false; + } + } + return true; + } + + function removeByIndex(uint256[] storage array, uint index) internal{ + require(index < array.length, "ArrayForUint256: index out of bounds"); + + while (index < array.length - 1) { + array[index] = array[index + 1]; + index++; + } + array.pop(); + } + + function removeByValue(uint256[] storage array, uint256 value) internal{ + uint index; + bool isIn; + (isIn, index) = firstIndexOf(array, value); + if(isIn){ + removeByIndex(array, index); + } + } + + function addValue(uint256[] storage array, uint256 value) internal{ + uint index; + bool isIn; + (isIn, index) = firstIndexOf(array, value); + if(!isIn){ + array.push(value); + } + } + + function extend(uint256[] storage a, uint256[] storage b) internal { + if(b.length != 0){ + for(uint i = 0; i < b.length; i++){ + a.push(b[i]); + } + } + } + + function distinct(uint256[] storage array) internal returns (uint256 length) { + bool contains; + uint index; + for (uint i = 0; i < array.length; i++) { + bool contains = false; + uint256 index = 0; + for(uint j = i+1;j < array.length; j++){ + if(array[j] == array[i]){ + contains =true; + index = i; + break; + } + } + if (contains) { + for (uint j = index; j < array.length - 1; j++){ + array[j] = array[j + 1]; + } + array.pop(); + i--; + } + } + length = array.length; + } + + function qsort(uint256[] storage array) internal { + qsort(array, 0, array.length-1); + } + + function qsort(uint256[] storage array, uint256 begin, uint256 end) private { + if(begin>= end || end == uint256(-1)) return; + uint256 pivot = array[end]; + + uint256 store = begin; + uint256 i = begin; + for(;i maxValue){ + maxValue = array[i]; + maxIndex = i; + } + } + } + + function min(uint256[] storage array) internal view returns (uint256 minValue, uint256 minIndex) { + minValue = array[0]; + minIndex = 0; + for(uint256 i = 0;i < array.length;i++){ + if(array[i] < minValue){ + minValue = array[i]; + minIndex = i; + } + } + } + +} diff --git a/contracts/base_type/LibConverter.sol b/contracts/base_type/LibConverter.sol new file mode 100644 index 00000000..0a8ca669 --- /dev/null +++ b/contracts/base_type/LibConverter.sol @@ -0,0 +1,169 @@ +/* + * Copyright 2014-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * */ + +pragma solidity>=0.4.24 <0.6.11; + +library LibConverter { + + /** + * @dev Returns the downcasted uint128 from uint256, reverting on + * overflow (when the input is greater than largest uint128). + * + * Counterpart to Solidity's `uint128` operator. + * + * Requirements: + * + * - input must fit into 128 bits + */ + function toUint128(uint256 value) internal pure returns (uint128) { + require(value < 2**128, "SafeCast: value doesn\'t fit in 128 bits"); + return uint128(value); + } + + /** + * @dev Returns the downcasted uint64 from uint256, reverting on + * overflow (when the input is greater than largest uint64). + * + * Counterpart to Solidity's `uint64` operator. + * + * Requirements: + * + * - input must fit into 64 bits + */ + function toUint64(uint256 value) internal pure returns (uint64) { + require(value < 2**64, "SafeCast: value doesn\'t fit in 64 bits"); + return uint64(value); + } + + /** + * @dev Returns the downcasted uint32 from uint256, reverting on + * overflow (when the input is greater than largest uint32). + * + * Counterpart to Solidity's `uint32` operator. + * + * Requirements: + * + * - input must fit into 32 bits + */ + function toUint32(uint256 value) internal pure returns (uint32) { + require(value < 2**32, "SafeCast: value doesn\'t fit in 32 bits"); + return uint32(value); + } + + /** + * @dev Returns the downcasted uint16 from uint256, reverting on + * overflow (when the input is greater than largest uint16). + * + * Counterpart to Solidity's `uint16` operator. + * + * Requirements: + * + * - input must fit into 16 bits + */ + function toUint16(uint256 value) internal pure returns (uint16) { + require(value < 2**16, "SafeCast: value doesn\'t fit in 16 bits"); + return uint16(value); + } + + /** + * @dev Returns the downcasted uint8 from uint256, reverting on + * overflow (when the input is greater than largest uint8). + * + * Counterpart to Solidity's `uint8` operator. + * + * Requirements: + * + * - input must fit into 8 bits. + */ + function toUint8(uint256 value) internal pure returns (uint8) { + require(value < 2**8, "SafeCast: value doesn\'t fit in 8 bits"); + return uint8(value); + } + + /** + * @dev Convert unsigned int to c-string (bytes). + * @param v - uint to convert. + * @return bytes. + */ + function uintToBytes(uint v) internal pure returns (bytes memory) { + uint maxlength = 100; + bytes memory reversed = new bytes(maxlength); + uint i = 0; + while (v != 0) { + uint8 remainder = uint8(v % 10); + v = v / 10; + reversed[i % maxlength] = byte(48 + remainder); + i++; + } + bytes memory s = new bytes(i + 1); + for (uint j = 1; j <= i % maxlength; j++) { + s[j-1] = reversed[i - j]; + } + return bytes(s); + } + + + function bytesToInt(bytes memory b) internal pure returns (int result) { + uint i = 0; + uint tr = 0; + result = 0; + bool sign = false; + if(b[i] == "-") { + sign = true; + i++; + } else if(b[i] == "+") { + i++; + } + while(uint8(b[b.length - tr - 1]) == 0x00) { + tr++; + } + for (;i < b.length - tr; i++) { + uint8 c = uint8(b[i]); + if (c>= 48 && c <= 57) { + result *= 10; + result = result + int(c - 48); + } + } + if(sign) { + result *= -1; + } + } + + function intToBytes(int v) internal pure returns (bytes memory) { + uint maxlength = 100; + bytes memory reversed = new bytes(maxlength); + uint i = 0; + uint x; + if(v < 0) + x = uint(-v); + else + x = uint(v); + while (x != 0) { + uint8 remainder = uint8(x % 10); + x = x / 10; + reversed[i % maxlength] = byte(48 + remainder); + i++; + } + if(v < 0) + reversed[(i++) % maxlength] = "-"; + bytes memory s = new bytes(i+1); + for (uint j = 1; j <= i % maxlength; j++) { + s[j - 1] = reversed[i - j]; + } + return bytes(s); + } +} + diff --git a/contracts/base_type/LibSafeMathForUint256Utils.sol b/contracts/base_type/LibSafeMathForUint256Utils.sol new file mode 100644 index 00000000..b83c43e2 --- /dev/null +++ b/contracts/base_type/LibSafeMathForUint256Utils.sol @@ -0,0 +1,76 @@ +/* + * Copyright 2014-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * */ + +pragma solidity>=0.4.24 <0.6.11; + +library LibSafeMathForUint256Utils { + + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c>= a, "SafeMathForUint256: addition overflow"); + return c; + } + + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + require(b <= a, "SafeMathForUint256: subtraction overflow"); + uint256 c = a - b; + return c; + } + + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + if (a == 0 || b == 0) { + return 0; + } + + uint256 c = a * b; + require(c / a == b, "SafeMathForUint256: multiplication overflow"); + return c; + } + + function div(uint256 a, uint256 b) internal pure returns (uint256) { + require(b> 0, "SafeMathForUint256: division by zero"); + uint256 c = a / b; + return c; + } + + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + require(b != 0, "SafeMathForUint256: modulo by zero"); + return a % b; + } + + function power(uint256 a, uint256 b) internal pure returns (uint256){ + + if(a == 0) return 0; + if(b == 0) return 1; + + uint256 c = 1; + for(uint256 i = 0; i < b; i++){ + c = mul(c, a); + } + } + + function max(uint256 a, uint256 b) internal pure returns (uint256) { + return a>= b ? a : b; + } + + function min(uint256 a, uint256 b) internal pure returns (uint256) { + return a < b ? a : b; + } + + function average(uint256 a, uint256 b) internal pure returns (uint256) { + return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2); + } +} diff --git a/contracts/base_type/LibString.sol b/contracts/base_type/LibString.sol new file mode 100644 index 00000000..31f859c3 --- /dev/null +++ b/contracts/base_type/LibString.sol @@ -0,0 +1,356 @@ +/* + * Copyright 2014-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * */ + +pragma solidity>=0.4.24 <0.6.11; + +library LibString{ + + + function lenOfChars(string memory src) internal pure returns(uint){ + uint i=0; + uint length = 0; + bytes memory string_rep = bytes(src); + //UTF-8 skip word + while (i b2) return 1; + if(b1 < b2) return -1; + } + //and length + if(selfb.length> otherb.length) return 1; + if(selfb.length < otherb.length) return -1; + return 0; + } + + function compareNocase(string memory self, string memory other) internal pure returns(int8){ + bytes memory selfb = bytes(self); + bytes memory otherb = bytes(other); + for(uint i=0;i= 'a' && ch1 <= 'z' && ch2>= 'a' && ch2 <= 'z'){ + if(ch1> ch2) return 1; + if(ch1 < ch2) return -1; + } + else{ + if(b1> b2) return 1; + if(b1 < b2) return -1; + } + } + + if(selfb.length> otherb.length) return 1; + if(selfb.length < otherb.length) return -1; + return 0; + } + + function toUppercase(string memory src) internal pure returns(string memory){ + bytes memory srcb = bytes(src); + for(uint i=0;i= 'a' && b <= 'z'){ + b &= byte(0xDF);// -32 + srcb[i] = b ; + } + } + return src; + } + + function toLowercase(string memory src) internal pure returns(string memory){ + bytes memory srcb = bytes(src); + for(uint i=0;i= 'A' && b <= 'Z'){ + b |= 0x20; + srcb[i] = b; + } + } + return src; + } + + /** + * Index Of + * + * Locates and returns the position of a character within a string + * + * @param src When being used for a data type this is the extended object + * otherwise this is the string acting as the haystack to be + * searched + * @param value The needle to search for, at present this is currently + * limited to one character + * @return int The position of the needle starting from 0 and returning -1 + * in the case of no matches found + */ + function indexOf(string memory src, string memory value) + internal + pure + returns (int) { + return indexOf(src, value, 0); + } + + /** + * Index Of + * + * Locates and returns the position of a character within a string starting + * from a defined offset + * + * @param src When being used for a data type this is the extended object + * otherwise this is the string acting as the haystack to be + * searched + * @param value The needle to search for, at present this is currently + * limited to one character + * @param offset The starting point to start searching from which can start + * from 0, but must not exceed the length of the string + * @return int The position of the needle starting from 0 and returning -1 + * in the case of no matches found + */ + function indexOf(string memory src, string memory value, uint offset) + internal + pure + returns (int) { + bytes memory srcBytes = bytes(src); + bytes memory valueBytes = bytes(value); + + assert(valueBytes.length == 1); + + for (uint i = offset; i < srcBytes.length; i++) { + if (srcBytes[i] == valueBytes[0]) { + return int(i); + } + } + + return -1; + } + + function split(string memory src, string memory separator) + internal + pure + returns (string[] memory splitArr) { + bytes memory srcBytes = bytes(src); + + uint offset = 0; + uint splitsCount = 1; + while (offset < srcBytes.length - 1) { + int limit = indexOf(src, separator, offset); + if (limit == -1) + break; + else { + splitsCount++; + offset = uint(limit) + 1; + } + } + + splitArr = new string[](splitsCount); + + offset = 0; + splitsCount = 0; + while (offset < srcBytes.length - 1) { + + int limit = indexOf(src, separator, offset); + if (limit == - 1) { + limit = int(srcBytes.length); + } + + string memory tmp = new string(uint(limit) - offset); + bytes memory tmpBytes = bytes(tmp); + + uint j = 0; + for (uint i = offset; i < uint(limit); i++) { + tmpBytes[j++] = srcBytes[i]; + } + offset = uint(limit) + 1; + splitArr[splitsCount++] = string(tmpBytes); + } + return splitArr; + } + + //------------HELPER FUNCTIONS---------------- + + function utf8CharBytesLength(bytes memory stringRep, uint ptr) internal pure returns(uint){ + + if ((stringRep[ptr]>>7)==byte(0)) + return 1; + if ((stringRep[ptr]>>5)==byte(0x06)) + return 2; + if ((stringRep[ptr]>>4)==byte(0x0e)) + return 3; + if ((stringRep[ptr]>>3)==byte(0x1e)) + return 4; + return 1; + } + + function memcpy(uint dest, uint src, uint len) private { + // Copy word-length chunks while possible + for(; len>= 32; len -= 32) { + assembly { + mstore(dest, mload(src)) + } + dest += 32; + src += 32; + } + + // Copy remaining bytes + uint mask = 256 ** (32 - len) - 1; + assembly { + let srcpart := and(mload(src), not(mask)) + let destpart := and(mload(dest), mask) + mstore(dest, or(destpart, srcpart)) + } + } + +} \ No newline at end of file diff --git a/contracts/business_template/Evidence/Authentication.sol b/contracts/business_template/Evidence/Authentication.sol new file mode 100644 index 00000000..35ba0f52 --- /dev/null +++ b/contracts/business_template/Evidence/Authentication.sol @@ -0,0 +1,44 @@ +/* + * Copyright 2014-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * */ + +pragma solidity>=0.4.24 <0.6.11; + +contract Authentication{ + address public _owner; + mapping(address=>bool) private _acl; + + constructor() public{ + _owner = msg.sender; + } + + modifier onlyOwner(){ + require(msg.sender == _owner, "Not admin"); + _; + } + + modifier auth(){ + require(msg.sender == _owner || _acl[msg.sender]==true, "Not authenticated"); + _; + } + + function allow(address addr) public onlyOwner{ + _acl[addr] = true; + } + + function deny(address addr) public onlyOwner{ + _acl[addr] = false; + } +} diff --git a/contracts/business_template/Evidence/EvidenceController.sol b/contracts/business_template/Evidence/EvidenceController.sol new file mode 100644 index 00000000..7afc2ce8 --- /dev/null +++ b/contracts/business_template/Evidence/EvidenceController.sol @@ -0,0 +1,70 @@ + +/* + * Copyright 2014-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * */ + +pragma solidity>=0.4.24 <0.6.11; + +import "./RequestRepository.sol"; +import "./EvidenceRepository.sol"; + +contract EvidenceController{ + RequestRepository public _requestRepo; + EvidenceRepository public _evidenceRepo; + + event CreateSaveRequest(bytes32 indexed hash, address creator); + event VoteSaveRequest(bytes32 indexed hash, address voter, bool complete); + event EvidenceSaved(bytes32 indexed hash); + + constructor(uint8 threshold, address[] memory voterArray) public{ + _requestRepo = new RequestRepository(threshold, voterArray); + _evidenceRepo = new EvidenceRepository(); + } + + modifier validateHash(bytes32 hash){ + require(hash != 0, "Not valid hash"); + _; + } + + function createSaveRequest(bytes32 hash, bytes memory ext) public validateHash(hash){ + _requestRepo.createSaveRequest(hash, msg.sender, ext); + emit CreateSaveRequest(hash, msg.sender); + } + + function voteSaveRequest(bytes32 hash) public validateHash(hash) returns(bool){ + bool b = _requestRepo.voteSaveRequest(hash, msg.sender); + if(!b) { + return false; + } + (bytes32 h, address creator, bytes memory ext, uint8 voted, uint8 threshold) = _requestRepo.getRequestData(hash); + bool passed = voted>= threshold; + emit VoteSaveRequest(hash, msg.sender, passed); + if(passed){ + _evidenceRepo.setData(hash, creator, now); + _requestRepo.deleteSaveRequest(hash); + emit EvidenceSaved(hash); + } + return true; + } + + function getRequestData(bytes32 hash) public view + returns(bytes32, address creator, bytes memory ext, uint8 voted, uint8 threshold){ + return _requestRepo.getRequestData(hash); + } + + function getEvidence(bytes32 hash) public view returns(bytes32 , address, uint){ + return _evidenceRepo.getData(hash); + } +} diff --git a/contracts/business_template/Evidence/EvidenceRepository.sol b/contracts/business_template/Evidence/EvidenceRepository.sol new file mode 100644 index 00000000..bfbac88c --- /dev/null +++ b/contracts/business_template/Evidence/EvidenceRepository.sol @@ -0,0 +1,39 @@ +/* + * Copyright 2014-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * */ + +pragma solidity>=0.4.24 <0.6.11; +import "./Authentication.sol"; + +contract EvidenceRepository is Authentication { + struct EvidenceData{ + bytes32 hash; + address owner; + uint timestamp; + } + mapping(bytes32=>EvidenceData) private _evidences; + + function setData(bytes32 hash, address owner, uint timestamp) public auth { + _evidences[hash].hash = hash; + _evidences[hash].owner = owner; + _evidences[hash].timestamp = timestamp; + } + + function getData(bytes32 hash) public view returns(bytes32 , address, uint){ + EvidenceData storage evidence = _evidences[hash]; + require(evidence.hash == hash, "Evidence not exist"); + return (evidence.hash, evidence.owner, evidence.timestamp); + } +} diff --git a/contracts/business_template/Evidence/RequestRepository.sol b/contracts/business_template/Evidence/RequestRepository.sol new file mode 100644 index 00000000..f6501a08 --- /dev/null +++ b/contracts/business_template/Evidence/RequestRepository.sol @@ -0,0 +1,68 @@ +/* + * Copyright 2014-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * */ + +pragma solidity>=0.4.24 <0.6.11; + +import "./Authentication.sol"; + +contract RequestRepository is Authentication{ + struct SaveRequest{ + bytes32 hash; + address creator; + uint8 voted; + bytes ext; + mapping(address=>bool) status; + } + uint8 public _threshold; + mapping(bytes32=>SaveRequest) private _saveRequests; + mapping(address=>bool) private _voters; + + constructor(uint8 threshold, address[] memory voterArray) public{ + _threshold = threshold; + for(uint i=0;i=0.4.24 <0.6.11; + +import "./BasicAuth.sol"; +import "./RewardPointController.sol"; +import "./RewardPointData.sol"; + + +contract Admin is BasicAuth { + address public _dataAddress; + address public _controllerAddress; + + constructor() public { + RewardPointData data = new RewardPointData("Point of V1"); + _dataAddress = address(data); + RewardPointController controller = new RewardPointController(_dataAddress); + _controllerAddress = address(controller); + data.upgradeVersion(_controllerAddress); + data.addIssuer(msg.sender); + data.addIssuer(_controllerAddress); + } + + function upgradeVersion(address newVersion) public { + RewardPointData data = RewardPointData(_dataAddress); + data.upgradeVersion(newVersion); + } + +} \ No newline at end of file diff --git a/contracts/business_template/RewardPoint/BasicAuth.sol b/contracts/business_template/RewardPoint/BasicAuth.sol new file mode 100644 index 00000000..8a99a142 --- /dev/null +++ b/contracts/business_template/RewardPoint/BasicAuth.sol @@ -0,0 +1,47 @@ +/* + * Copyright 2014-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * */ + +pragma solidity>=0.4.24 <0.6.11; + +contract BasicAuth { + address public _owner; + + constructor() public { + _owner = msg.sender; + } + + modifier onlyOwner() { + require(auth(msg.sender), "Only owner!"); + _; + } + + function setOwner(address owner) + public + onlyOwner + { + _owner = owner; + } + + function auth(address src) public view returns (bool) { + if (src == address(this)) { + return true; + } else if (src == _owner) { + return true; + } else { + return false; + } + } +} \ No newline at end of file diff --git a/contracts/business_template/RewardPoint/IssuerRole.sol b/contracts/business_template/RewardPoint/IssuerRole.sol new file mode 100644 index 00000000..d07f3e38 --- /dev/null +++ b/contracts/business_template/RewardPoint/IssuerRole.sol @@ -0,0 +1,51 @@ +/* + * Copyright 2014-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * */ + +pragma solidity>=0.4.24 <0.6.11; + +import "./LibRoles.sol"; + +contract IssuerRole { + using LibRoles for LibRoles.Role; + + event IssuerAdded(address indexed account); + event IssuerRemoved(address indexed account); + + LibRoles.Role private _issuers; + + constructor () internal { + _issuers.add(msg.sender); + } + + modifier onlyIssuer() { + require(isIssuer(msg.sender), "IssuerRole: caller does not have the Issuer role"); + _; + } + + function isIssuer(address account) public view returns (bool) { + return _issuers.has(account); + } + + function addIssuer(address account) public { + _issuers.add(account); + emit IssuerAdded(account); + } + + function renounceIssuer(address account) public onlyIssuer { + _issuers.remove(account); + emit IssuerRemoved(account); + } +} \ No newline at end of file diff --git a/contracts/business_template/RewardPoint/LibRoles.sol b/contracts/business_template/RewardPoint/LibRoles.sol new file mode 100644 index 00000000..e33cb47b --- /dev/null +++ b/contracts/business_template/RewardPoint/LibRoles.sol @@ -0,0 +1,38 @@ +/* + * Copyright 2014-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * */ + +pragma solidity>=0.4.24 <0.6.11; + +library LibRoles { + struct Role { + mapping (address => bool) bearer; + } + + function add(Role storage role, address account) internal { + require(!has(role, account), "Roles: account already has role"); + role.bearer[account] = true; + } + + function remove(Role storage role, address account) internal { + require(has(role, account), "Roles: account does not have role"); + role.bearer[account] = false; + } + + function has(Role storage role, address account) internal view returns (bool) { + require(account != address(0), "Roles: account is the zero address"); + return role.bearer[account]; + } +} diff --git a/contracts/business_template/RewardPoint/LibSafeMath.sol b/contracts/business_template/RewardPoint/LibSafeMath.sol new file mode 100644 index 00000000..0deff2da --- /dev/null +++ b/contracts/business_template/RewardPoint/LibSafeMath.sol @@ -0,0 +1,33 @@ +/* + * Copyright 2014-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * */ + +pragma solidity>=0.4.24 <0.6.11; + + +library LibSafeMath { + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + require(b <= a, "SafeMath: subtraction overflow"); + uint256 c = a - b; + + return c; + } + function add(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 c = a + b; + require(c>= a, "SafeMath: addition overflow"); + + return c; + } +} diff --git a/contracts/business_template/RewardPoint/RewardPointController.sol b/contracts/business_template/RewardPoint/RewardPointController.sol new file mode 100644 index 00000000..d00e8be0 --- /dev/null +++ b/contracts/business_template/RewardPoint/RewardPointController.sol @@ -0,0 +1,130 @@ +/* + * Copyright 2014-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * */ + +pragma solidity>=0.4.24 <0.6.11; + +import "./RewardPointData.sol"; +import "./BasicAuth.sol"; +import "./LibSafeMath.sol"; + +contract RewardPointController is BasicAuth { + using LibSafeMath for uint256; + + RewardPointData _rewardPointData; + + event LogRegister(address account); + event LogUnregister(address account); + event LogSend( address indexed from, address indexed to, uint256 value); + + constructor(address dataAddress) public { + _rewardPointData = RewardPointData(dataAddress); + } + + modifier accountExist(address addr) { + require(_rewardPointData.hasAccount(addr)==true && addr != address(0), "Only existed account!"); + _; + } + + modifier accountNotExist(address account) { + require(_rewardPointData.hasAccount(account)==false, "Account already existed!"); + _; + } + + modifier canUnregister(address account) { + require(_rewardPointData.hasAccount(account)==true && _rewardPointData.getBalance(account) == 0 , "Cann't unregister!"); + _; + } + + modifier checkAccount(address sender) { + require(msg.sender != sender && sender != address(0), "Can't transfer to illegal address!"); + _; + } + + modifier onlyIssuer() { + require(_rewardPointData.isIssuer(msg.sender), "IssuerRole: caller does not have the Issuer role"); + _; + } + + function register() accountNotExist(msg.sender) public returns (address) { + _rewardPointData.setAccount(msg.sender, true); + // init balances + _rewardPointData.setBalance(msg.sender, 0); + emit LogRegister(msg.sender); + } + + function unregister() canUnregister(msg.sender) public returns (address) { + _rewardPointData.setAccount(msg.sender, false); + emit LogUnregister(msg.sender); + } + + function isRegistered(address addr) public view returns (bool) { + return _rewardPointData.hasAccount(addr); + } + + function balance(address addr) public view returns (uint256) { + return _rewardPointData.getBalance(addr); + } + + function transfer(address toAddress, uint256 value) accountExist(msg.sender) accountExist(toAddress) + public returns(bool b, uint256 balanceOfFrom, uint256 balanceOfTo) { + uint256 balance1 = _rewardPointData.getBalance(msg.sender); + balanceOfFrom = balance1.sub(value); + _rewardPointData.setBalance(msg.sender, balanceOfFrom); + uint256 balance2 = _rewardPointData.getBalance(toAddress); + balanceOfTo = balance2.add(value); + _rewardPointData.setBalance(toAddress, balanceOfTo); + emit LogSend(msg.sender, toAddress, value); + b = true; + } + + function destroy(uint256 value) accountExist(msg.sender) public returns (bool) { + uint256 totalAmount = _rewardPointData._totalAmount(); + totalAmount = totalAmount.sub(value); + _rewardPointData.setTotalAmount(totalAmount); + uint256 balance1 = _rewardPointData.getBalance(msg.sender); + balance1 = balance1.sub(value); + _rewardPointData.setBalance(msg.sender, balance1); + emit LogSend( msg.sender, address(0), value); + return true; + } + + + function issue(address account, uint256 value) public accountExist(account) returns (bool) { + uint256 totalAmount = _rewardPointData._totalAmount(); + totalAmount = totalAmount.add(value); + _rewardPointData.setTotalAmount(totalAmount); + uint256 balance1 = _rewardPointData.getBalance(account); + balance1 = balance1.add(value); + _rewardPointData.setBalance(account, balance1); + emit LogSend( address(0), account, value); + return true; + } + + function isIssuer(address account) public view returns (bool) { + return _rewardPointData.isIssuer(account); + } + + function addIssuer(address account) public returns (bool) { + _rewardPointData.addIssuer(account); + return true; + } + + function renounceIssuer() public returns (bool) { + _rewardPointData.renounceIssuer(msg.sender); + return true; + } +} + diff --git a/contracts/business_template/RewardPoint/RewardPointData.sol b/contracts/business_template/RewardPoint/RewardPointData.sol new file mode 100644 index 00000000..b0ef20c4 --- /dev/null +++ b/contracts/business_template/RewardPoint/RewardPointData.sol @@ -0,0 +1,73 @@ +/* + * Copyright 2014-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * */ + +pragma solidity>=0.4.24 <0.6.11; + +import "./BasicAuth.sol"; +import "./IssuerRole.sol"; + +contract RewardPointData is BasicAuth, IssuerRole { + + mapping(address => uint256) private _balances; + mapping(address => bool) private _accounts; + uint256 public _totalAmount; + string public _description; + address _latestVersion; + + constructor(string memory description) public { + _description = description; + } + + modifier onlyLatestVersion() { + require(msg.sender == _latestVersion); + _; + } + + function upgradeVersion(address newVersion) public { + require(msg.sender == _owner); + _latestVersion = newVersion; + } + + + function setBalance(address a, uint256 value) onlyLatestVersion public returns (bool) { + _balances[a] = value; + return true; + } + + function setAccount(address a, bool b) onlyLatestVersion public returns (bool) { + _accounts[a] = b; + return true; + } + + function setTotalAmount(uint256 amount) onlyLatestVersion public returns (bool) { + _totalAmount = amount; + return true; + } + + function getAccountInfo(address account) public view returns (bool, uint256) { + return (_accounts[account], _balances[account]); + } + + function hasAccount(address account) public view returns(bool) { + return _accounts[account]; + } + + function getBalance(address account) public view returns (uint256) { + return _balances[account]; + } + +} + diff --git a/contracts/data_structure/LibAddressSet.sol b/contracts/data_structure/LibAddressSet.sol new file mode 100644 index 00000000..5fd4cb5d --- /dev/null +++ b/contracts/data_structure/LibAddressSet.sol @@ -0,0 +1,65 @@ +/* + * Copyright 2014-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * */ + +pragma solidity>=0.4.24 <0.6.11; + + +library LibAddressSet { + + struct AddressSet { + mapping (address => uint256) indexMapping; + address[] values; + } + + function add(AddressSet storage self, address value) internal { + require(value != address(0x0), "LibAddressSet: value can't be 0x0"); + require(!contains(self, value), "LibAddressSet: value already exists in the set."); + self.values.push(value); + self.indexMapping[value] = self.values.length; + } + + function contains(AddressSet storage self, address value) internal view returns (bool) { + return self.indexMapping[value] != 0; + } + + function remove(AddressSet storage self, address value) internal { + require(contains(self, value), "LibAddressSet: value doesn't exist."); + uint256 toDeleteindexMapping = self.indexMapping[value] - 1; + uint256 lastindexMapping = self.values.length - 1; + address lastValue = self.values[lastindexMapping]; + self.values[toDeleteindexMapping] = lastValue; + self.indexMapping[lastValue] = toDeleteindexMapping; + self.values.pop(); + } + + function getSize(AddressSet storage self) internal view returns (uint256) { + return self.values.length; + } + + function get(AddressSet storage self, uint256 index) internal view returns (address){ + return self.values[index]; + } + + function getAll(AddressSet storage self) internal view returns(address[] memory) { + address[] memory output = new address[](self.values.length); + for (uint256 i; i < self.values.length; i++){ + output[i] = self.values[i]; + } + return output; + } + + +} \ No newline at end of file diff --git a/contracts/data_structure/LibBytesMap.sol b/contracts/data_structure/LibBytesMap.sol new file mode 100644 index 00000000..68fc29f1 --- /dev/null +++ b/contracts/data_structure/LibBytesMap.sol @@ -0,0 +1,71 @@ +/* + * Copyright 2014-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * */ + +pragma solidity>=0.4.24 <0.6.11; + +library LibBytesMap{ + + struct Map{ + mapping(bytes => uint256) index; + bytes[] keys; + bytes[] values; + } + + function put(Map storage map, bytes memory key, bytes memory value) internal { + uint256 idx = map.index[key]; + if(idx == 0){ + map.keys.push(key); + map.values.push(value); + map.index[key] = map.keys.length; + } + else{ + map.values[idx - 1] = value; + } + } + + function getKey(Map storage map, uint256 index) internal view returns(bytes memory){ + require(map.keys.length> index); + bytes memory key = map.keys[index - 1]; + return key; + } + + function getValue(Map storage map, bytes memory key) internal view returns(bytes memory){ + uint256 idx = map.index[key]; + bytes memory value = map.values[idx - 1]; + return value; + } + + function getSize(Map storage self) internal view returns(uint256) { + return self.keys.length; + } + + // -----------Iterative functions------------------ + function iterate_start(Map storage self) internal pure returns (uint256){ + return 1; + } + + function can_iterate(Map storage self, uint256 idx) internal view returns(bool){ + return self.keys.length>= idx; + } + + function iterate_next(Map storage self, uint256 idx) internal pure returns(uint256){ + return idx+1; + } + function getKeyByIndex(Map storage map, uint256 idx) internal view returns(bytes memory){ + bytes memory key = map.keys[idx - 1]; + return key; + } +} \ No newline at end of file diff --git a/contracts/data_structure/LibDeque.sol b/contracts/data_structure/LibDeque.sol new file mode 100644 index 00000000..ee13db91 --- /dev/null +++ b/contracts/data_structure/LibDeque.sol @@ -0,0 +1,109 @@ + +/* + * Copyright 2014-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * */ + +pragma solidity>=0.4.24 <0.6.11; + +/** + * Doubly ended queue + * */ + +library LibDeque{ + + struct Deque{ + mapping(int256 => bytes32) data; + int256 head; + int256 tail; + } + + function getSize(Deque storage self) internal view returns(uint256){ + if(self.head == self.tail) return 0; + return uint(self.tail - self.head - 1); + } + + function isEmpty(Deque storage self) internal view returns(bool){ + return self.head == self.tail; + } + + + function offerFirst(Deque storage self, bytes32 element) internal { + bool empty = self.tail == self.head; + self.data[self.head] = element; + self.head--; + if(empty) self.tail++; + } + + function offerLast(Deque storage self, bytes32 element) internal { + bool empty = self.tail == self.head; + self.data[self.tail] = element; + self.tail++; + if(empty) self.head--; + + } + + function pollFirst(Deque storage self) internal returns(bytes32 ret) { + require(!isEmpty(self)); + ret = self.data[++self.head]; + delete self.data[self.head]; + } + + function pollLast(Deque storage self) internal returns(bytes32 ret) { + require(!isEmpty(self)); + ret = self.data[--self.tail]; + delete self.data[self.tail]; + } + + function peekFirst(Deque storage self) internal view returns(bytes32 ret) { + require(!isEmpty(self)); + ret = self.data[self.head + 1]; + } + + function peekLast(Deque storage self) internal view returns(bytes32 ret){ + require(!isEmpty(self)); + ret = self.data[self.tail - 1]; + } + + + + function push(Deque storage self, bytes32 element) internal { + offerFirst(self, element); + } + + function pop(Deque storage self) internal returns(bytes32) { + return pollFirst(self); + } + +} + + + + + + + + + + + + + + + + + + + + diff --git a/contracts/data_structure/LibLinkedList.sol b/contracts/data_structure/LibLinkedList.sol new file mode 100644 index 00000000..971ccf9c --- /dev/null +++ b/contracts/data_structure/LibLinkedList.sol @@ -0,0 +1,126 @@ +/* + * Copyright 2014-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * */ + +pragma solidity>=0.4.24 <0.6.11; + + +library LibLinkedList { + + bytes32 constant private NULL = bytes32(0); + bool constant private PREV = false; + bool constant private NEXT = true; + + struct LinkedList{ + uint256 size; + bytes32 head; + bytes32 tail; + mapping(bytes32 => Node) indexs; + } + + struct Node{ + bytes32 prev; + bytes32 next; + bool exist; + } + + function getSize(LinkedList storage self) internal view returns(uint256){ + return self.size; + } + + function addNode(LinkedList storage self, bytes32 data) internal returns(LinkedList storage) { + require(data != bytes32(0)); + require(!self.indexs[data].exist); + if(self.size == 0){ + Node memory node = Node(NULL, NULL, true); + self.size = 1; + self.head = data; + self.tail = data; + self.indexs[data] = node; + } + else{ + Node memory newNode = Node(self.tail, NULL, true); + Node storage tail = extractNode(self, self.tail); + tail.next = data; + self.tail = data; + self.size++; + self.indexs[data] = newNode; + } + return self; + } + + function getPrev(LinkedList storage self, bytes32 data) internal view returns(bytes32){ + Node storage node = self.indexs[data]; + require(node.exist); + return node.prev; + } + + function getNext(LinkedList storage self, bytes32 data) internal view returns(bytes32){ + Node storage node = self.indexs[data]; + require(node.exist); + return node.next; + } + + + function removeNode(LinkedList storage self, bytes32 data) internal returns(LinkedList storage){ + Node storage node = extractNode(self, data); + require(node.exist); + Node storage prev = extractNode(self, node.prev); + Node storage next = extractNode(self, node.next); + if(prev.exist){ + prev.next = node.next; + } + else{ + self.head = node.next; + } + + if(next.exist){ + next.prev = node.prev; + } + else{ + self.tail = node.prev; + } + delete self.indexs[data]; + self.size--; + return self; + } + + + function getTail(LinkedList storage self) internal view returns(bytes32){ + return self.tail; + } + + function getHead(LinkedList storage self) internal view returns(bytes32){ + return self.head; + } + + function extractNode(LinkedList storage self, bytes32 data) private view returns(Node storage){ + return self.indexs[data]; + } + + + // -----------Iterative functions------------------ + function iterate_start(LinkedList storage self) internal view returns (bytes32){ + return self.head; + } + + function can_iterate(LinkedList storage self, bytes32 data) internal view returns(bool){ + return self.indexs[data].exist; + } + + function iterate_next(LinkedList storage self, bytes32 data) internal view returns(bytes32){ + return self.indexs[data].next; + } +} \ No newline at end of file diff --git a/contracts/data_structure/LibMaxHeapUint256.sol b/contracts/data_structure/LibMaxHeapUint256.sol new file mode 100644 index 00000000..54c70a33 --- /dev/null +++ b/contracts/data_structure/LibMaxHeapUint256.sol @@ -0,0 +1,86 @@ +/* + * Copyright 2014-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * */ + +pragma solidity>=0.4.24 <0.6.11; + +library LibMaxHeapUint256{ + + struct Heap{ + uint256[] data; + } + + function insert(Heap storage heap, uint256 value) internal{ + heap.data.push(value); + uint256 idx = heap.data.length - 1; + uint256 parent; + + while(idx> 0){ + parent = (idx - 1) / 2; + if(heap.data[parent]>= value){ + break; + } + //do sift-up + heap.data[idx] = heap.data[parent]; + heap.data[parent] = value; + idx = parent; + } + } + + function top(Heap storage heap) internal view returns (uint256){ + require(heap.data.length> 0); + return heap.data[0]; + } + + function extractTop(Heap storage heap) internal returns(uint256 top){ + require(heap.data.length> 0); + top = heap.data[0]; + uint256 last = heap.data[heap.data.length - 1]; + heap.data.pop(); + + heap.data[0] = last; + uint256 index = 0; + uint256 leftIdx; + uint256 rightIdx; + //Sift-down + uint256 swapValue; + uint256 swapIndex; + while(index < heap.data.length){ + leftIdx = 2 * index + 1; + rightIdx = 2 * index + 2; + swapValue = last; + swapIndex = index; + if(leftIdx < heap.data.length && swapValue < heap.data[leftIdx]){ + swapValue = heap.data[leftIdx]; + swapIndex = leftIdx; + } + + if(rightIdx < heap.data.length && swapValue < heap.data[rightIdx]){ + swapValue = heap.data[rightIdx]; + swapIndex = rightIdx; + } + + if(swapIndex == index) break; + heap.data[index] = swapValue; + heap.data[swapIndex] = last; + index = swapIndex; + } + } + + function getSize(Heap storage heap) internal view returns(uint256){ + return heap.data.length; + } + +} diff --git a/contracts/data_structure/LibMinHeapUint256.sol b/contracts/data_structure/LibMinHeapUint256.sol new file mode 100644 index 00000000..6aeea319 --- /dev/null +++ b/contracts/data_structure/LibMinHeapUint256.sol @@ -0,0 +1,87 @@ +/* + * Copyright 2014-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * */ + +pragma solidity>=0.4.24 <0.6.11; + +library LibMinHeapUint256{ + + struct Heap{ + uint256[] data; + } + + function insert(Heap storage heap, uint256 value) internal{ + heap.data.push(value); + uint256 idx = heap.data.length - 1; + uint256 parent; + + while(idx> 0){ + parent = (idx - 1) / 2; + if(heap.data[parent] <= value){ + break; + } + //do sift-up + heap.data[idx] = heap.data[parent]; + heap.data[parent] = value; + idx = parent; + } + } + + function top(Heap storage heap) internal view returns (uint256){ + require(heap.data.length> 0); + return heap.data[0]; + } + + function extractTop(Heap storage heap) internal returns(uint256 top){ + require(heap.data.length> 0); + top = heap.data[0]; + uint256 last = heap.data[heap.data.length - 1]; + heap.data.pop(); + + + heap.data[0] = last; + uint256 index = 0; + uint256 leftIdx; + uint256 rightIdx; + //Sift-down + uint256 swapValue; + uint256 swapIndex; + while(index < heap.data.length){ + leftIdx = 2 * index + 1; + rightIdx = 2 * index + 2; + swapValue = last; + swapIndex = index; + if(leftIdx < heap.data.length && swapValue> heap.data[leftIdx]){ + swapValue = heap.data[leftIdx]; + swapIndex = leftIdx; + } + + if(rightIdx < heap.data.length && swapValue> heap.data[rightIdx]){ + swapValue = heap.data[rightIdx]; + swapIndex = rightIdx; + } + + if(swapIndex == index) break; + heap.data[index] = swapValue; + heap.data[swapIndex] = last; + index = swapIndex; + } + } + + function getSize(Heap storage heap) internal view returns(uint256){ + return heap.data.length; + } + +} diff --git a/contracts/data_structure/LibQueue.sol b/contracts/data_structure/LibQueue.sol new file mode 100644 index 00000000..d53073bc --- /dev/null +++ b/contracts/data_structure/LibQueue.sol @@ -0,0 +1,54 @@ +/* + * Copyright 2014-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * */ + +pragma solidity>=0.4.24 <0.6.11; + +library LibQueue{ + + + struct Queue{ + uint256 first; + uint256 next; + mapping(uint => bytes32) queue; + + } + + function enqueue(Queue storage queue, bytes32 data) internal { + queue.queue[queue.next++] = data; + } + + function dequeue(Queue storage queue) internal returns (bytes32) { + uint256 first = queue.first; + require(queue.next> first); // non-empty queue + + bytes32 data = queue.queue[first]; + delete queue.queue[first]; + queue.first += 1; + return data; + } + + function element(Queue storage queue) internal view returns (bytes32) { + uint256 first = queue.first; + require(queue.next> first); // non-empty queue + bytes32 data = queue.queue[first]; + return data; + } + + + function getSize(Queue storage self) internal view returns(uint256){ + return self.next - self.first; + } +} \ No newline at end of file diff --git a/contracts/data_structure/LibStack.sol b/contracts/data_structure/LibStack.sol new file mode 100644 index 00000000..9b9c41a2 --- /dev/null +++ b/contracts/data_structure/LibStack.sol @@ -0,0 +1,46 @@ +/* + * Copyright 2014-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * */ + +pragma solidity>=0.4.24 <0.6.11; + +library LibStack{ + + + struct Stack{ + bytes32[] datas; + } + + + function push(Stack storage self, bytes32 data) internal{ + self.datas.push(data); + } + + function pop(Stack storage self) internal returns(bytes32){ + require(self.datas.length> 0); + bytes32 data = self.datas[self.datas.length - 1]; + self.datas.pop(); + return data; + } + + function peek(Stack storage self) internal returns(bytes32){ + require(self.datas.length> 0); + bytes32 data = self.datas[self.datas.length - 1]; + return data; + } + function getSize(Stack storage self) internal view returns(uint256){ + return self.datas.length; + } +} \ No newline at end of file diff --git a/contracts/default/Crypto.sol b/contracts/default/Crypto.sol new file mode 100644 index 00000000..9979794b --- /dev/null +++ b/contracts/default/Crypto.sol @@ -0,0 +1,7 @@ +contract Crypto +{ + function sm3(bytes memory data) public view returns(bytes32){} + function keccak256Hash(bytes memory data) public view returns(bytes32){} + function sm2Verify(bytes32 message, bytes memory publicKey, bytes32 r, bytes32 s) public view returns(bool, address){} + function curve25519VRFVerify(string memory input, string memory vrfPublicKey, string memory vrfProof) public view returns(bool,uint256){} +} \ No newline at end of file diff --git a/contracts/default/HelloWorld.sol b/contracts/default/HelloWorld.sol new file mode 100644 index 00000000..9ba9451c --- /dev/null +++ b/contracts/default/HelloWorld.sol @@ -0,0 +1,17 @@ +pragma solidity>=0.4.24 <0.6.11; + +contract HelloWorld { + string name; + + constructor() public { + name = "Hello, World!"; + } + + function get() public view returns (string memory) { + return name; + } + + function set(string memory n) public { + name = n; + } +} \ No newline at end of file diff --git a/contracts/default/KVTableTest.sol b/contracts/default/KVTableTest.sol new file mode 100644 index 00000000..3aa42ee0 --- /dev/null +++ b/contracts/default/KVTableTest.sol @@ -0,0 +1,49 @@ +pragma solidity>=0.4.24 <0.6.11; + +import "./Table.sol"; + +contract KVTableTest { + event SetResult(int256 count); + + KVTableFactory tableFactory; + string constant TABLE_NAME = "t_kvtest"; + + constructor() public { + //The fixed address is 0x1010 for KVTableFactory + tableFactory = KVTableFactory(0x1010); + // the parameters of createTable are tableName,keyField,"vlaueFiled1,vlaueFiled2,vlaueFiled3,..." + tableFactory.createTable(TABLE_NAME, "id", "item_price,item_name"); + } + + //get record + function get(string memory id) public view returns (bool, int256, string memory) { + KVTable table = tableFactory.openTable(TABLE_NAME); + bool ok = false; + Entry entry; + (ok, entry) = table.get(id); + int256 item_price; + string memory item_name; + if (ok) { + item_price = entry.getInt("item_price"); + item_name = entry.getString("item_name"); + } + return (ok, item_price, item_name); + } + + //set record + function set(string memory id, int256 item_price, string memory item_name) + public + returns (int256) + { + KVTable table = tableFactory.openTable(TABLE_NAME); + Entry entry = table.newEntry(); + // the length of entry's field value should < 16MB + entry.set("id", id); + entry.set("item_price", item_price); + entry.set("item_name", item_name); + // the first parameter length of set should <= 255B + int256 count = table.set(id, entry); + emit SetResult(count); + return count; + } +} \ No newline at end of file diff --git a/contracts/default/ShaTest.sol b/contracts/default/ShaTest.sol new file mode 100644 index 00000000..50105476 --- /dev/null +++ b/contracts/default/ShaTest.sol @@ -0,0 +1,29 @@ +pragma solidity>=0.4.24 <0.6.11; + +pragma experimental ABIEncoderV2; + +import "./Crypto.sol"; + +contract ShaTest{ + bytes _data = "Hello, ShaTest"; + Crypto crypto; + + constructor() public { + crypto = Crypto(0x5006); + } + + function getSha256(bytes memory _memory) public returns(bytes32 result) + { + return sha256(_memory); + } + + function getKeccak256(bytes memory _memory) public returns(bytes32 result) + { + return keccak256(_memory); + } + + function getData() public view returns(bytes memory) + { + return _data; + } +} diff --git a/contracts/default/Table.sol b/contracts/default/Table.sol new file mode 100644 index 00000000..adaac40a --- /dev/null +++ b/contracts/default/Table.sol @@ -0,0 +1,67 @@ + +contract TableFactory { + function openTable(string memory) public view returns (Table) {} //open table + function createTable(string memory, string memory, string memory) public returns (int256) {} //create table +} + +//select condition +contract Condition { + function EQ(string memory, int256) public view{} + function EQ(string memory, string memory) public view{} + + function NE(string memory, int256) public view{} + function NE(string memory, string memory) public view{} + + function GT(string memory, int256) public view{} + function GE(string memory, int256) public view{} + + function LT(string memory, int256) public view{} + function LE(string memory, int256) public view{} + + function limit(int256) public view{} + function limit(int256, int256) public view{} +} + +//one record +contract Entry { + function getInt(string memory) public view returns (int256) {} + function getUInt(string memory) public view returns (uint256) {} + function getAddress(string memory) public view returns (address) {} + function getBytes64(string memory) public view returns (bytes1[64] memory) {} + function getBytes32(string memory) public view returns (bytes32) {} + function getString(string memory) public view returns (string memory) {} + + function set(string memory, int256) public {} + function set(string memory, uint256) public {} + function set(string memory, string memory) public {} + function set(string memory, address) public {} +} + +//record sets +contract Entries { + function get(int256) public view returns (Entry) {} + function size() public view returns (int256) {} +} + +//Table main contract +contract Table { + function select(string memory, Condition) public view returns (Entries) {} + function insert(string memory, Entry) public returns (int256) {} + function update(string memory, Entry, Condition) public returns (int256) {} + function remove(string memory, Condition) public returns (int256) {} + + function newEntry() public view returns (Entry) {} + function newCondition() public view returns (Condition) {} +} + +contract KVTableFactory { + function openTable(string memory) public view returns (KVTable) {} + function createTable(string memory, string memory, string memory) public returns (int256) {} +} + +//KVTable per permiary key has only one Entry +contract KVTable { + function get(string memory) public view returns (bool, Entry) {} + function set(string memory, Entry) public returns (int256) {} + function newEntry() public view returns (Entry) {} +} diff --git a/contracts/default/TableTest.sol b/contracts/default/TableTest.sol new file mode 100644 index 00000000..da9811c7 --- /dev/null +++ b/contracts/default/TableTest.sol @@ -0,0 +1,98 @@ +pragma solidity>=0.4.24 <0.6.11; +pragma experimental ABIEncoderV2; + +import "./Table.sol"; + +contract TableTest { + event CreateResult(int256 count); + event InsertResult(int256 count); + event UpdateResult(int256 count); + event RemoveResult(int256 count); + + TableFactory tableFactory; + string constant TABLE_NAME = "t_test"; + constructor() public { + tableFactory = TableFactory(0x1001); //The fixed address is 0x1001 for TableFactory + // the parameters of createTable are tableName,keyField,"vlaueFiled1,vlaueFiled2,vlaueFiled3,..." + tableFactory.createTable(TABLE_NAME, "name", "item_id,item_name"); + } + + //select records + function select(string memory name) + public + view + returns (string[] memory, int256[] memory, string[] memory) + { + Table table = tableFactory.openTable(TABLE_NAME); + + Condition condition = table.newCondition(); + + Entries entries = table.select(name, condition); + string[] memory user_name_bytes_list = new string[]( + uint256(entries.size()) + ); + int256[] memory item_id_list = new int256[](uint256(entries.size())); + string[] memory item_name_bytes_list = new string[]( + uint256(entries.size()) + ); + + for (int256 i = 0; i < entries.size(); ++i) { + Entry entry = entries.get(i); + + user_name_bytes_list[uint256(i)] = entry.getString("name"); + item_id_list[uint256(i)] = entry.getInt("item_id"); + item_name_bytes_list[uint256(i)] = entry.getString("item_name"); + } + + return (user_name_bytes_list, item_id_list, item_name_bytes_list); + } + //insert records + function insert(string memory name, int256 item_id, string memory item_name) + public + returns (int256) + { + Table table = tableFactory.openTable(TABLE_NAME); + + Entry entry = table.newEntry(); + entry.set("name", name); + entry.set("item_id", item_id); + entry.set("item_name", item_name); + + int256 count = table.insert(name, entry); + emit InsertResult(count); + + return count; + } + //update records + function update(string memory name, int256 item_id, string memory item_name) + public + returns (int256) + { + Table table = tableFactory.openTable(TABLE_NAME); + + Entry entry = table.newEntry(); + entry.set("item_name", item_name); + + Condition condition = table.newCondition(); + condition.EQ("name", name); + condition.EQ("item_id", item_id); + + int256 count = table.update(name, entry, condition); + emit UpdateResult(count); + + return count; + } + //remove records + function remove(string memory name, int256 item_id) public returns (int256) { + Table table = tableFactory.openTable(TABLE_NAME); + + Condition condition = table.newCondition(); + condition.EQ("name", name); + condition.EQ("item_id", item_id); + + int256 count = table.remove(name, condition); + emit RemoveResult(count); + + return count; + } +} diff --git a/docs/business_template/Evidence.md b/docs/business_template/Evidence.md new file mode 100644 index 00000000..3a25c08e --- /dev/null +++ b/docs/business_template/Evidence.md @@ -0,0 +1,45 @@ +## 存证模板背景说明 + +电子存证是一种用于保存证据的手段,应用场景很多,例如在版权领域,作者可以将作品指纹保存到电子存证机构,当出现版权纠纷时,可通过取证解决纠纷。存证、取证的关键环节是电子存证服务机构,如何保证它的可信性,即存证机构本身不会对存证数据进行破坏?传统的中心化存证机构很难解决这个问题,需要由区块链技术来解决。在区块链技术中,电子账本由各个节点共同维护,其内容由共识算法决定,单一节点无法篡改已达成共识的账本数据。这一不可篡改的特性是去中心化电子存证方案的核心。该方案中,存证数据不再存储于单一机构,而是分布式地存储在所有区块链节点上。 + +## 场景说明 + +本模板支持基于多签的存证场景。该场景中,包含几个角色:存证方、审核方、存储方、取证方: + + - 存证方:提交存证申请。 + - 审核方:审核存证申请,申请通过后交由存储方保存。 + - 存储方:保存存证数据。在去中心化方案中,由区块链上的智能合约充当存储方。 + - 取证方:提取存证数据。 + +## 接口 + +提供了三个合约:Evidence合约,EvidenceRepository合约,RequestRepository合约,Authentication合约。其中Evidence合约是对外服务合约,其余合约是辅助合约,用于数据和逻辑分离。 + +Evidence合约:对外服务的唯一接口。包含: + - createSaveRequest(byte32 hash, bytes ext): 存证方提交存证请求。hash是存证数据摘要,ext可选地存放说明信息 + - getRequestData(bytes32 hash): 审核方查看存证请求,以便审核。包括ext等信息 + - voteSaveRequest(bytes32 hash):审核方批准存证请求。投票全部通过后, + - getEvidence(bytes32 hash): 取证方查看存证数据,包括时间戳、持有人等信息 + +## 使用示例 + +假如现在要创建一个2-3投票的存证合约,然后上传存证、审核存证、查看存证,整个过程如下: + +合约初始化: + + - 管理员部署EvidenceRepository合约 + - 管理员部署RequestRepository合约,构造时传入threshold参数为2、voters列表为3个投票者 + - 管理员部署Evidence合约 + - 管理员调用EvidenceRepository.allow和RequestRepository.allow,参数传入Evidence合约地址,这一步是指定仅有Evidence合约可以调用EvidenceRepository和RequestRepository + +合约调用: + + - 存证方调用Evidence.createSaveRequest提交存证请求 + - 审核者调用Evidence.getRequestData查看存证请求;调用voteSaveRequest批准审核请求 + - 审核通过后,取证方调用Evidence.getEvidence查看存证数据 + + + + + + diff --git a/docs/business_template/RewardPoint.md b/docs/business_template/RewardPoint.md new file mode 100644 index 00000000..4578cae8 --- /dev/null +++ b/docs/business_template/RewardPoint.md @@ -0,0 +1,96 @@ +## 积分模板背景说明 + +在区块链的业务方案中,积分系统是非常常见的一种场景。 + +基于智能合约的积分系统,支持多家机构发行、用户注册、积分消费、积分销户、用户销户等多种功能。 + + +## 场景说明 + +典型的积分场景包括了以下角色: + + - 发行者:发行积分。 + - 用户:获得和消费积分,还可实现积分的转账。 + - 管理者:积分系统的管理者。 + +积分系统中包括了以下功能: + + - 创建积分系统 + - 注册:用户注册会员,只有经过注册的用户才能获得和消费积分。 + - 销户: 用户销户。只有积分为0的用户才能正常销户。 + - 添加发行者: 发行者具有发行积分的权利。 + - 发行积分: 支持定向发送到某个积分账户。 + - 删除发行者: 发行者可以注销自身的发行积分的权利。 + - 转账: 支持用户积分的互转和消费等。 + - 积分销毁: 用户可以销毁自己的积分。 + + +## 接口 + +主体为3个合约: Admin、RewardPointController、RewardPointData。 + +其中Admin为管理合约,提供合约部署和管理的接口: + + - 构造函数: 部署合约。默认部署合约的外部账户为资产发行者。 + - upgradeVersion(address newVersion) 更新数据的controller最新地址 + - _dataAddress() 查询数据合约的地址 + - _controllerAddress() 查询控制合约的地址 + +RewardPointController 提供了合约控制相关的接口: + + - addIssuer(address account) 添加资产发行者。只有资产发行者可以添加新的资产发行者。 + - issue(address account, uint256 value) 发行积分 + - isIssuer(address account) 判断是否是资产发行者。 + - addIssuer(address account) 添加发行者,只能由发行者添加。 + - renounceIssuer() 撤销发行者,只能撤销自己。 + - register() 普通用户账户注册。 + - unregister() 普通用户账户注销。 + - isRegistered(address addr) 判断普通用户是否注册。 + - balance(address addr) 查询普通用户的积分。 + - transfer(address toAddress, uint256 value) 往目标账户转积分 + - destroy(uint256 value) 销毁自己账户中的指定数量的积分 + +RewardPointData提供了底层的数据存储,不对外暴露直接访问的接口。 + +其他的合约为工具或辅助合约。 + +## 使用示例 + +整体流程如下: + +合约初始化: + + - 管理员部署Admin合约, 管理员在控制台中输入『deploy Admin』部署合约。 + - 管理员调用Admin合约的_controllerAddress()函数,获得RewardPointController合约的地址。 + +资产发行者维护: + + - 管理员使用 RewardPointController 合约的地址,加载RewardPointController合约。 + - 管理员默认为资产发行者,可以通过addIssuer添加其他发行者,通过renounceIssuer接口撤销自己发行者的权限。 + - 通过isIssuer接口查询某个用户是否为资产发行者。 + +账户注册: + + - 用户使用管理员发放的 RewardPointController 合约的地址,加载RewardPointController合约。 + - 用户使用RewardPointController合约中的register()接口注册账户。 + - 通过isRegistered判断是否已注册。 + +积分发行: + + - 用户使用RewardPointController的isIssuer函数判断自己是否为积分发行者。 + - 如果为是,用户通过issue接口定向发现积分。 + +积分操作: + + - 用户通过transfer接口实现积分转账。 + - 用户通过balance接口查询积分余额。 + - 用户通过destroy接口实现指定数额的账户积分的注销。 + +账户销户: + + - 用户通过unregister接口销户,只有积分余额为0的账户可以直接销户。 + + + + + diff --git a/docs/data_structure/LibAddressSet.md b/docs/data_structure/LibAddressSet.md new file mode 100644 index 00000000..ea923615 --- /dev/null +++ b/docs/data_structure/LibAddressSet.md @@ -0,0 +1,225 @@ +# LibAddressSet.sol + +LibAddressSet 提供了存储Address类型的Set数据结构,支持包括add, remove, contains, get, getAll, size等方法。 + +## 使用方法 + +首先需要通过import引入LibAddressSet类库,然后通过"."进行方法调用,如下为调用LibAddressSet方法的例子: + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibAddressSet.sol"; + +contract Test { + using LibAddressSet for LibAddressSet.AddressSet; + LibAddressSet.AddressSet private addressSet; + + event Log(uint256 size); + + function testAddress() public { + addressSet.add(address(1)); + uint256 size = addressSet.getSize();//Expected to be 1 + emit Log(size); + } +} +``` + + +## API列表 + +编号 | API | API描述 +---|---|--- +1 | *add(AddressSet storage self, address value) internal* | 往Set里添加元素。 +2 | *contains(AddressSet storage self, address value) internal view returns (bool)* | 判断Set里是否包含了元素value。 +3 | *remove(AddressSet storage self, address value) internal* | 删除Set中的元素。 +4 | *size(AddressSet storage self) internal view returns (uint256)* | 获取Set内元素数。 +5 | *get(AddressSet storage self, uint256 index) internal view returns (address)* | 查询某个Set的元素。 +6 | *getAll(AddressSet storage self) internal view returns(address[])* | 返回所有元素。 + +## API详情 + +### ***1. add 函数*** + +往Set里添加元素 + +#### 参数 + +- AddressSet: set容器 +- address: 元素 + +#### 返回值 + + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibAddressSet.sol"; + +contract Test { + using LibAddressSet for LibAddressSet.AddressSet; + LibAddressSet.AddressSet private addressSet; + + event Log(uint256 size); + + function testAddress() public { + addressSet.add(address(1)); + uint256 size = addressSet.getSize();//Expected to be 1 + emit Log(size); + } + +} +``` + +### ***2. contains 函数*** + +判断Set里是否包含了元素value。 + +#### 参数 + +- AddressSet: set容器 +- address: 元素 + +#### 返回值 +- bool: 是否包含 + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibAddressSet.sol"; + +contract Test { + using LibAddressSet for LibAddressSet.AddressSet; + LibAddressSet.AddressSet private addressSet; + + event Log(bool b); + + function testAddress() public { + addressSet.add(address(1)); + emit Log(addressSet.contains(address(1)));//Expected true + } + +} +``` + +### ***3. remove 函数*** + +删除Set中的指定元素 + +#### 参数 + +- AddressSet: set容器 +- address: 元素 + +#### 返回值 + + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibAddressSet.sol"; + +contract Test { + using LibAddressSet for LibAddressSet.AddressSet; + LibAddressSet.AddressSet private addressSet; + + event Log(bool b); + + function testAddress() public { + addressSet.add(address(1)); + addressSet.remove(address(1)); + emit Log(addressSet.contains(address(1))); + } + +} +``` + +### ***4. getSize 函数*** + +查询Set中的元素数量。 + +#### 参数 + +- AddressSet: set容器 + +#### 返回值 +- uint256: 元素数量 + +#### 实例 + +``` + uint256 setSize = addressSet.getSize(); +``` + +### ***5. get 函数*** + +查询Set中指定index的值 + +#### 参数 + +- AddressSet: set容器 +- uint256: index + +#### 返回值 +- address: 元素 + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibAddressSet.sol"; + +contract Test { + using LibAddressSet for LibAddressSet.AddressSet; + LibAddressSet.AddressSet private addressSet; + + event Log(bool b); + + function testAddress() public returns(address) { + addressSet.add(address(1)); + addressSet.add(address(2)); + return addressSet.get(1);//Expected be 2 + } + +} +``` + +### ***6. getAll 函数*** + +查询Set中所有的值,返回一个address[]数组 + +#### 参数 + +- AddressSet: set容器 + +#### 返回值 +- address[]: 所有元素值 + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibAddressSet.sol"; + +contract Test { + using LibAddressSet for LibAddressSet.AddressSet; + LibAddressSet.AddressSet private addressSet; + + event Log(bool b); + + function testAddress() public returns(address[] memory) { + addressSet.add(address(1)); + addressSet.add(address(2)); + return addressSet.getAll();//Expected be 2 + } + +} +``` \ No newline at end of file diff --git a/docs/data_structure/LibBytesMap.md b/docs/data_structure/LibBytesMap.md new file mode 100644 index 00000000..af12bfcb --- /dev/null +++ b/docs/data_structure/LibBytesMap.md @@ -0,0 +1,134 @@ +# LibBytesMap.sol + +LibBytesMap提供了基于bytes的可迭代、可查询的映射. + +## 使用方法 + +首先需要通过import引入LibBytesMap类库,然后通过"."进行方法调用,如下为调用例子: + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibBytesMap.sol"; + +contract Test { + + using LibBytesMap for LibBytesMap.Map; + + LibBytesMap.Map private map; + + + event Log(uint256 size); + function f() public { + string memory key = "key"; + string memory value = "value"; + map.put(bytes(key),bytes(value)); + emit Log(map.getSize()); + + } +} +``` + + +## API列表 + +编号 | API | API描述 +---|---|--- +1 | *put(Map storage map, bytes key, bytes value) internal* | 存放键值对 +2 | *getValue(Map storage map, bytes key) internal view returns(bytes)* |根据key获取value +3 | *getKey(Map storage map, uint256 index) internal view returns(bytes)* |根据游标查询key +4 | *iterate_start(Map storage self) internal pure returns (uint256)* | 枚举key的游标 +5 | *can_iterate(Map storage self, uint256 idx) internal view returns(bool)* | 游标是否可用 +6 | *iterate_next(Map storage self, uint256 idx) internal pure returns(uint256)* | 下一个游标值 +7 | *size(Map storage self) internal view returns(uint256)* | 获得当前mapping的容量 + + +## API详情 + +### ***1. put 函数*** + +存放键值对 + +#### 参数 + +- bytes key: 键 +- bytes value:值 + +### ***2. getValue 函数*** + +查询值 + +#### 参数 + +- bytes key:键 + +#### 返回值 + +- bytes: 值 + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibBytesMap.sol"; + +contract Test { + + using LibBytesMap for LibBytesMap.Map; + + LibBytesMap.Map private map; + + event Log(string val); + function f() public { + string memory key = "k"; + string memory value = "v"; + map.put(bytes(key),bytes(value)); + emit Log(string(map.getValue(bytes(key))));//Expected to be v + } +} +``` + +### ***3. 迭代函数 与 getKey函数*** + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibBytesMap.sol"; + +contract Test { + + using LibBytesMap for LibBytesMap.Map; + + LibBytesMap.Map private map; + + + event Log(bytes key, uint256 index); + event Debug(uint256 index, bool can); + function f() public { + map.put(bytes("k1"),bytes("v1")); + map.put(bytes("k2"),bytes("v2")); + map.put(bytes("k3"),bytes("v3")); + + uint256 i = map.iterate_start(); + + while(map.can_iterate(i)){ + emit Log(map.getKeyByIndex(i), i); + i = map.iterate_next(i); + } + } +} +``` + +### ***4. getSize*** + +#### 实例 + +``` + function iterate() public { + uint256 i = map.getSize(); + + } +``` diff --git a/docs/data_structure/LibDeque.md b/docs/data_structure/LibDeque.md new file mode 100644 index 00000000..28d5b98b --- /dev/null +++ b/docs/data_structure/LibDeque.md @@ -0,0 +1,365 @@ +# LibDeque.sol + +LibDeque提供了双端队列。用户也可以像用栈一样使用它。 + +## 使用方法 + +首先需要通过import引入LibDeque类库,然后通过"."进行方法调用,如下为调用LibDeque方法的例子: + +``` +pragma solidity>=0.4.22 <0.7.0; + +import "./LibDeque.sol"; + +contract Test{ + + using LibDeque for LibDeque.Deque; + + LibDeque.Deque private _deque; + + event Log(uint size); + function f() public returns(bytes32, bytes32){ + _deque.offerFirst(bytes32(uint256(1))); + _deque.offerLast(bytes32(uint256(2))); + emit Log(_deque.getSize());//Should be 2 + bytes32 first =_deque.pollFirst();//Shoud be 0x1 + bytes32 last = _deque.pollLast();//Should be 0x2 + emit Log(_deque.getSize());//Should be empty + return (first, last); + } + +} + +``` + + +## API列表 + +编号 | API | API描述 +---|---|--- +1 | *getSize(Deque storage self) internal view returns(uint256)* |获取元素数 +2 | *isEmpty(Deque storage self) internal view returns(bool)* |判断是否为空 +3 | *offerFirst(Deque storage self, bytes32 element) internal* | 将数据存入头部 +4 | *offerLast(Deque storage self, bytes32 element) internal* | 将数据存入尾部 +5 | *pollFirst(Deque storage self) internal returns(bytes32 ret)* |取出头部元素 +6 | *pollLast(Deque storage self) internal returns(bytes32 ret)* |取出尾部元素 +7 | *peekFirst(Deque storage self) internal view returns(bytes32 ret)* |查看头部元素 +8 | *peekLast(Deque storage self) internal view returns(bytes32 ret)* |查看尾部元素 +9 | *push(Deque storage self, bytes32 element) internal* |入栈 +10 | *pop(Deque storage self) internal returns(bytes32)* |出栈 + +## API详情 + +### ***1. getSize 函数*** + +查看元素数目 + +#### 参数 + +- Deque:队列 + +#### 返回值 + +- uint256: 元素数 + +#### 实例 + +``` + uint256 size = _deque.getSize(); +``` +### ***2. isEmpty 函数*** + +查看是否为空 + +#### 参数 + +- Deque:队列 + +#### 返回值 + +- bool 是否为空 + +#### 实例 + +``` + bool empty = _deque.isEmpty(); +``` + +### ***3. offerFirst 函数*** + +从头部存入元素。 + +#### 参数 + +- Deque:队列 +- bytes32: 元素 + +#### 实例 + +``` +pragma solidity>=0.4.22 <0.7.0; + +import "./LibDeque.sol"; + +contract Test{ + + using LibDeque for LibDeque.Deque; + + LibDeque.Deque private _deque; + + event Log(uint size); + + function f() public{ + _deque.offerFirst(bytes32(uint256(1))); + emit Log(_deque.getSize());//Should be 1 + } +} + +``` + +### ***4. offerLast 函数*** + +从尾部存入元素。 + +#### 参数 + +- Deque:队列 +- bytes32: 元素 + +#### 实例 + +``` +pragma solidity>=0.4.22 <0.7.0; + +import "./LibDeque.sol"; + +contract Test{ + + using LibDeque for LibDeque.Deque; + + LibDeque.Deque private _deque; + + event Log(uint size); + + function f() public{ + _deque.offerLast(bytes32(uint256(2))); + emit Log(_deque.getSize());//Should be 1 + } +} + +``` + +### ***5. pollFirst 函数*** + +删除头部元素,并返回该元素。如果队列为空,则失败。 + +#### 参数 + +- Deque:队列 + + +#### 返回值 + +- bytes32: 头部元素 + +#### 实例 + +``` +pragma solidity>=0.4.22 <0.7.0; + +import "./LibDeque.sol"; + +contract Test{ + + using LibDeque for LibDeque.Deque; + + LibDeque.Deque private _deque; + + event Log(uint size); + function f() public returns(bytes32){ + _deque.offerFirst(bytes32(uint256(1))); + _deque.offerLast(bytes32(uint256(2))); + bytes32 r = _deque.pollFirst();//Should be 1 + emit Log(_deque.getSize());//Should be 1 + return (r); + } +} +``` + +### ***6. pollLast 函数*** + +删除尾部元素,并返回该元素。如果队列为空,则失败。 + +#### 参数 + +- Deque:队列 + +#### 返回值 + +- bytes32: 尾部元素 + +#### 实例 + +``` +pragma solidity>=0.4.22 <0.7.0; + +import "./LibDeque.sol"; + +contract Test{ + + using LibDeque for LibDeque.Deque; + + LibDeque.Deque private _deque; + + event Log(uint size); + function f() public returns(bytes32){ + _deque.offerFirst(bytes32(uint256(1))); + _deque.offerLast(bytes32(uint256(2))); + bytes32 r = _deque.pollLast();//Should be 2 + emit Log(_deque.getSize());//Should be 1 + return (r); + } +} +``` + + +### ***7. peekFirst 函数*** + +查看头部元素。如果队列为空,则失败。 + +#### 参数 + +- Deque:队列 + +#### 返回值 + +- bytes32: 头部元素 + +#### 实例 + +``` +pragma solidity>=0.4.22 <0.7.0; + +import "./LibDeque.sol"; + +contract Test{ + + using LibDeque for LibDeque.Deque; + + LibDeque.Deque private _deque; + + event Log(uint size); + function f() public returns(bytes32){ + _deque.offerFirst(bytes32(uint256(1))); + _deque.offerLast(bytes32(uint256(2))); + bytes32 r = _deque.peekFirst();//Should be 1 + emit Log(_deque.getSize());//Should be 2 + return (r); + } +} +``` + +### ***8. peekLast 函数*** + +查看尾部元素。如果队列为空,则失败。 + +#### 参数 + +- Deque:队列 + +#### 返回值 + +- bytes32: 尾部元素 + +#### 实例 + +``` +pragma solidity>=0.4.22 <0.7.0; + +import "./LibDeque.sol"; + +contract Test{ + + using LibDeque for LibDeque.Deque; + + LibDeque.Deque private _deque; + + event Log(uint size); + function f() public returns(bytes32){ + _deque.offerFirst(bytes32(uint256(1))); + _deque.offerLast(bytes32(uint256(2))); + bytes32 r = _deque.peekLast();//Should be 2 + emit Log(_deque.getSize());//Should be 2 + return (r); + } +} +``` + +### ***9. push 函数*** + +推入一个元素,就像使用栈一样。 + +#### 参数 + +- Deque:队列 +- bytes32: 元素 + +#### 实例 + +``` +pragma solidity>=0.4.22 <0.7.0; + +import "./LibDeque.sol"; + +contract Test{ + + using LibDeque for LibDeque.Deque; + + LibDeque.Deque private _deque; + + event Log(uint size); + function f() public returns(bytes32){ + _deque.push(bytes32(uint256(1))); + _deque.push(bytes32(uint256(2))); + emit Log(_deque.getSize());//Should be 2 + } +} +``` + +### ***10. pop 函数*** + +弹出一个元素,就像栈一样。如果队列为空,则失败。 + +#### 参数 + +- Deque:队列 + +#### 返回值 + +- bytes32: 元素 + +#### 实例 + +``` +pragma solidity>=0.4.22 <0.7.0; + +import "./LibDeque.sol"; + +contract Test{ + + using LibDeque for LibDeque.Deque; + + LibDeque.Deque private _deque; + + event Log(uint size); + function f() public returns(bytes32){ + _deque.push(bytes32(uint256(1))); + _deque.push(bytes32(uint256(2))); + bytes32 pop = _deque.pop();//Should be 2 + emit Log(_deque.getSize());//Should be 1 + return pop; + } +} +``` + + diff --git a/docs/data_structure/LibLinkedList.md b/docs/data_structure/LibLinkedList.md new file mode 100644 index 00000000..6de808b3 --- /dev/null +++ b/docs/data_structure/LibLinkedList.md @@ -0,0 +1,296 @@ +# LibLinkedList.sol + +LibLinkedList提供了双向链表操作,包括链表更新、查询、迭代等。 + +## 使用方法 + +首先需要通过import引入LibLinkedList类库,然后通过"."进行方法调用,如下为添加元素的例子: +``` +pragma solidity>=0.4.24 <0.6.11; +import "./LibLinkedList.sol"; + +contract Test { + + using LibLinkedList for LibLinkedList.LinkedList; + + LibLinkedList.LinkedList self; + + + function add() public{ + self.addNode(bytes32(uint(2))); + } +} +``` + + +## API列表 + +编号 | API | API描述 +---|---|--- +1 | *getSize(LinkedList storage self) internal view returns(uint256)* |获取链表元素数 +2 | *addNode(LinkedList storage self, bytes32 data) internal* |添加元素 +3 | *removeNode(LinkedList storage self, bytes32 data) internal returns(bytes32)* | 删除元素 +4 | *getPrev(LinkedList storage self, bytes32 data) internal view returns(bytes32)* | 获取一个元素的前一个元素 +5 | *getNext(LinkedList storage self, bytes32 data) internal view returns(bytes32)* | 获取一个元素的下一个元素 +6 | *getTail(LinkedList storage self) internal view returns(bytes32)* | 获取尾部元素 +7 | *getHead(LinkedList storage self) internal view returns(bytes32)* | 获取头部元素 +8 | *iterate_start(LinkedList storage self) internal view returns (bytes32)* | 链表迭代初始化 +9 | *can_iterate(LinkedList storage self, bytes32 data) internal view returns(bool)* | 迭代条件检查 +10 | *iterate_next(LinkedList storage self, bytes32 data) internal view returns(bytes32)* | 迭代下一个元素 + + +## API详情 + +### ***1. getSize 函数*** + +查询一个双向链表的元素数 + +#### 参数 + +- LinkedList:链表实例 + +#### 返回值 + +- uint256: 返回链表的当前元素数 + +#### 实例 + +``` +uint256 size = self.getSize(); +``` +### ***2. addNode 函数*** + +addNode函数用于添加一个元素,时间复杂度O(1) + +#### 参数 + +- LinkedList: 链表实例 +- bytes32: 元素值 + +#### 返回值 + +- LinkedList: 链表实例 + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; +import "./LibLinkedList.sol"; + +contract Test { + + using LibLinkedList for LibLinkedList.LinkedList; + + LibLinkedList.LinkedList self; + + event Log(uint size); + function f() public{ + self.addNode(bytes32(uint(2))); + uint size = self.getSize(); + emit Log(size);//Expected to be 1 + } +} +``` + +### ***3. removeNode 函数*** + +removeNode函数用于从链表中删除一个元素,时间复杂度O(1) + +#### 参数 + +- LinkedList:链表实例 +- bytes32:待删除元素 + +#### 返回值 + +- LinkedList:链表实例 + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; +import "./LibLinkedList.sol"; + +contract Test { + + using LibLinkedList for LibLinkedList.LinkedList; + + LibLinkedList.LinkedList self; + + event Log(uint size); + function f() public{ + self.addNode(bytes32(uint(2))); + self.removeNode(bytes32(uint(2))); + uint size = self.getSize(); + emit Log(size);//Expected to be 0 + } +} +``` + +### ***4. getPrev 函数*** + +getPrev用于取得一个元素的前一个元素。时间复杂度O(1) + +#### 参数 + +- LinkedList:链表实例 +- bytes32:当前元素值 + +#### 返回值 + +- bytes32:前一个元素值 + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; +import "./LibLinkedList.sol"; + +contract Test { + + using LibLinkedList for LibLinkedList.LinkedList; + + LibLinkedList.LinkedList self; + + event Log(uint size); + function f() public returns(bytes32){ + self.addNode(bytes32(uint(1))); + self.addNode(bytes32(uint(2))); + bytes32 prev = self.getPrev(bytes32(uint(2)));//Expected to be 1 + return prev; + } +} +``` + +### ***5. getNext 函数*** + +getNext用于取得一个元素的下一个函数。时间复杂度O(1) + +#### 参数 + +- LinkedList:链表实例 +- bytes32:当前元素值 + +#### 返回值 + +- bytes32:下一个元素值 + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; +import "./LibLinkedList.sol"; + +contract Test { + + using LibLinkedList for LibLinkedList.LinkedList; + + LibLinkedList.LinkedList self; + + event Log(uint size); + function f() public returns(bytes32){ + self.addNode(bytes32(uint(1))); + self.addNode(bytes32(uint(2))); + bytes32 next = self.getNext(bytes32(uint(1)));//Expected to be 2 + return next; + } +} +``` + +### ***6. getTail 函数*** + +getTail用于取得链表元素的尾部元素。时间复杂度O(1) + +#### 参数 + +- LinkedList:链表实例 + +#### 返回值 + +- bytes32:尾部元素值 + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; +import "./LibLinkedList.sol"; + +contract Test { + + using LibLinkedList for LibLinkedList.LinkedList; + + LibLinkedList.LinkedList self; + + event Log(uint size); + function f() public returns(bytes32){ + self.addNode(bytes32(uint(1))); + self.addNode(bytes32(uint(2))); + bytes32 next = self.getTail();//Expected to be 2 + return next; + } +} +``` + +### ***7. getHead 函数*** + +getHead用于取得链表元素的头部元素。时间复杂度O(1) + +#### 参数 + +- LinkedList:链表实例 + +#### 返回值 + +- bytes32:头部元素值 + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; +import "./LibLinkedList.sol"; + +contract Test { + + using LibLinkedList for LibLinkedList.LinkedList; + + LibLinkedList.LinkedList self; + + event Log(uint size); + function f() public returns(bytes32){ + self.addNode(bytes32(uint(1))); + self.addNode(bytes32(uint(2))); + bytes32 next = self.getHead();//Expected to be 1 + return next; + } +} +``` + +### ***8. 迭代函数*** + +迭代函数用于从头到尾迭代链表。 + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; +import "./LibLinkedList.sol"; + +contract Test { + + using LibLinkedList for LibLinkedList.LinkedList; + + LibLinkedList.LinkedList self; + + event Log(bytes32 val); + function f() public{ + self.addNode(bytes32(uint(1))); + self.addNode(bytes32(uint(2))); + self.addNode(bytes32(uint(3))); + bytes32 start = self.iterate_start(); + while(self.can_iterate(start)){ + emit Log(start);//Shoud be 1 ,2, 3 + start = self.iterate_next(start); + } + } +} +``` diff --git a/docs/data_structure/LibMaxHeapUint256.md b/docs/data_structure/LibMaxHeapUint256.md new file mode 100644 index 00000000..89036a1b --- /dev/null +++ b/docs/data_structure/LibMaxHeapUint256.md @@ -0,0 +1,114 @@ +# LibMaxHeapUint256.sol + +LibMaxHeapUint256提供了最大堆的实现。 + +## 使用方法 + +首先需要通过import引入类库,然后通过"."进行方法调用,如下为调用例子: + +``` + +pragma solidity>=0.4.24 <0.6.11; + +import "./LibMaxHeapUint256.sol"; + +contract Test { + + using LibMaxHeapUint256 for LibMaxHeapUint256.Heap; + + LibMaxHeapUint256.Heap private _heap; + + function insertExample(uint256 value) public returns(uint256) { + _heap.insert(value); + } +} +``` + + +## API列表 + +编号 | API | API描述 +---|---|--- +1 | *insert(Heap storage heap, uint256 value) internal* | 向堆中插入一个元素 +2 | *top(Heap storage heap) internal view returns (uint256)* |查询堆顶元素(最大值) +3 | *extractTop(Heap storage heap) internal returns(uint256 top)* |弹出堆顶元素(最大值) +4 | *getSize(Heap storage heap) internal view returns(uint256)* | 查询堆元素数 + +## API详情 + +### ***1. insert 函数*** + +向堆中插入一个元素 + +#### 参数 + +- Heap heap:堆 +- uint256 value:元素 + +#### 实例 + +``` + function insertExample(uint256 value) public returns(uint256) { + _heap.insert(value); + } + +``` +### ***2. top 函数*** + +查询堆顶 + +#### 参数 + +- Heap heap:堆 + +#### 返回值 + +- uint256: 堆顶元素 + +#### 实例 + +``` + function topExample() public returns(uint256 top) { + top = _heap.top(); + } + +``` +### ***3. extractTop 函数*** + +弹出堆顶元素 + +#### 参数 + +- Heap heap:堆 + +#### 返回值 + +- uint256: 堆顶元素 + +#### 实例 + +``` + function extractTopExample() public returns(uint256 top) { + top = _heap.extractTop(); + } +``` + +### ***4. getSize 函数*** + +获取堆元素数 + +#### 参数 + +- Heap heap:堆 + +#### 返回值 + +- uint256: 堆元素数 + +#### 实例 + +``` + function getSize() public returns(uint256 size) { + size = _heap.getSize(); + } +``` \ No newline at end of file diff --git a/docs/data_structure/LibMinHeapUint256.md b/docs/data_structure/LibMinHeapUint256.md new file mode 100644 index 00000000..74215448 --- /dev/null +++ b/docs/data_structure/LibMinHeapUint256.md @@ -0,0 +1,114 @@ +# LibMinHeapUint256.sol + +LibMinHeapUint256提供了最小堆的实现。 + +## 使用方法 + +首先需要通过import引入类库,然后通过"."进行方法调用,如下为调用例子: + +``` + +pragma solidity>=0.4.24 <0.6.11; + +import "./LibMinHeapUint256.sol"; + +contract Test { + + using LibMinHeapUint256 for LibMinHeapUint256.Heap; + + LibMinHeapUint256.Heap private _heap; + + function insertExample(uint256 value) public returns(uint256) { + _heap.insert(value); + } +} +``` + + +## API列表 + +编号 | API | API描述 +---|---|--- +1 | *insert(Heap storage heap, uint256 value) internal* | 向堆中插入一个元素 +2 | *top(Heap storage heap) internal view returns (uint256)* |查询堆顶元素(最小值) +3 | *extractTop(Heap storage heap) internal returns(uint256 top)* |弹出堆顶元素(最小值) +4 | *getSize(Heap storage heap) internal view returns(uint256)* | 查询堆元素数 + +## API详情 + +### ***1. insert 函数*** + +向堆中插入一个元素 + +#### 参数 + +- Heap heap:堆 +- uint256 value:元素 + +#### 实例 + +``` + function insertExample(uint256 value) public returns(uint256) { + _heap.insert(value); + } + +``` +### ***2. top 函数*** + +查询堆顶 + +#### 参数 + +- Heap heap:堆 + +#### 返回值 + +- uint256: 堆顶元素 + +#### 实例 + +``` + function topExample() public returns(uint256 top) { + top = _heap.top(); + } + +``` +### ***3. extractTop 函数*** + +弹出堆顶元素 + +#### 参数 + +- Heap heap:堆 + +#### 返回值 + +- uint256: 堆顶元素 + +#### 实例 + +``` + function extractTopExample() public returns(uint256 top) { + top = _heap.extractTop(); + } +``` + +### ***4. getSize 函数*** + +获取堆元素数 + +#### 参数 + +- Heap heap:堆 + +#### 返回值 + +- uint256: 堆元素数 + +#### 实例 + +``` + function getSize() public returns(uint256 size) { + size = _heap.getSize(); + } +``` \ No newline at end of file diff --git a/docs/data_structure/LibQueue.md b/docs/data_structure/LibQueue.md new file mode 100644 index 00000000..49d57b6d --- /dev/null +++ b/docs/data_structure/LibQueue.md @@ -0,0 +1,165 @@ +# LibQueue.sol + +LibQueue提供了FIFO队列数据结构。 + +## 使用方法 + +首先需要通过import引入LibQueue类库,然后通过"."进行方法调用,如下为调用LibQueue方法的例子: + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibQueue.sol"; + +contract Test { + + using LibQueue for LibQueue.Queue; + + LibQueue.Queue private queue; + + function f() public { + queue.enqueue(bytes32(uint(1))); + queue.enqueue(bytes32(uint(1))); + bytes32 pop = queue.dequeue();//Expected to be 1 + uint size = queue.getSize();//Expected to be 1 + } + +} +``` + + +## API列表 + +编号 | API | API描述 +---|---|--- +1 | *enqueue(Queue storage queue, bytes32 data) public* |入队 +2 | *dequeue(Queue storage queue) public returns (bytes32)* |出队 +3 | *getSize(Queue storage self) internal view returns(uint256)* | 获取队列元素数 +4 | *element(Queue storage queue) public view returns (bytes32)* | 查询下一个队列中的值,但不从queue中删除。 + +## API详情 + +### ***1. enqueue 函数*** + +入队 + +#### 参数 + +- Queue:队列 +- bytes32: 元素 + +#### 返回值 + + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibQueue.sol"; + +contract Test { + + using LibQueue for LibQueue.Queue; + + LibQueue.Queue private queue; + + function f() public returns(uint) { + queue.enqueue(bytes32(uint(1))); + queue.enqueue(bytes32(uint(2))); + uint size = queue.getSize();//Expected to be 2 + return (size); + } + +} +``` +### ***2. dequeue 函数*** + +出队一个元素 + +#### 参数 + +- Queue: 队列 + +#### 返回值 + +- bytes32:队列元素值 + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibQueue.sol"; + +contract Test { + + using LibQueue for LibQueue.Queue; + + LibQueue.Queue private queue; + + function f() public returns(bytes32, uint) { + queue.enqueue(bytes32(uint(1))); + queue.enqueue(bytes32(uint(2))); + bytes32 head = queue.dequeue();//Expteced to be 1 + uint size = queue.getSize();//Expected to be 1 + return (head, size); + } + +} +``` + +### ***3. getSize 函数*** + +查询队列大小 + +#### 参数 + +- Queue: 队列 + +#### 返回值 + +- uint256: 队列大小 + +#### 实例 + +``` + uint size = queue.getSize();//Expected to be 2 +``` + +### ***4. element 函数*** + +查询队列中的下一个元素,如果队列为空,则函数查询不成功。 + +#### 参数 + +- Queue: 队列 + +#### 返回值 + +- bytes32:队列元素值 + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibQueue.sol"; + +contract Test { + + using LibQueue for LibQueue.Queue; + + LibQueue.Queue private queue; + + function f() public returns(bytes32, uint) { + queue.enqueue(bytes32(uint(1))); + queue.enqueue(bytes32(uint(2))); + bytes32 head = queue.element();//Expteced to be 1 + uint size = queue.getSize();//Expected to be 2 + return (head, size); + } + +} +``` + diff --git a/docs/data_structure/LibStack.md b/docs/data_structure/LibStack.md new file mode 100644 index 00000000..06db0cfc --- /dev/null +++ b/docs/data_structure/LibStack.md @@ -0,0 +1,169 @@ +# LibStack.sol + +LibStack提供了栈数据结构。 + +## 使用方法 + +首先需要通过import引入LibStack类库,然后通过"."进行方法调用,如下为调用LibStack方法的例子: + +``` + +pragma solidity>=0.4.24 <0.6.11; + +import "./LibStack.sol"; + +contract Test { + + using LibStack for LibStack.Stack; + + LibStack.Stack private stack; + + function f() public returns(bytes32, uint) { + stack.push(bytes32(uint(1))); + stack.push(bytes32(uint(2))); + bytes32 pop = stack.pop();//Expect to be 2 + uint size = stack.getSize();//Expected to be 1 + return (pop, size); + } +} + +``` + + +## API列表 + +编号 | API | API描述 +---|---|--- +1 | *push(Stack storage self, bytes32 data) internal* |压入一个元素 +2 | *pop(Stack storage self) internal returns(bytes32)* |弹出一个元素 +3 | *peek(Stack storage self) internal view returns(bytes32)* |查询栈顶元素 +4 | *getSize(Stack storage self) internal view returns(uint256)* | 获取栈元素数 + + +## API详情 + +### ***1. push 函数*** + +压入一个元素 + +#### 参数 + +- Stack:栈 +- bytes32: 元素 + +#### 返回值 + + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibStack.sol"; + +contract Test { + + using LibStack for LibStack.Stack; + + LibStack.Stack private stack; + + function f() public returns(uint ) { + + stack.push(bytes32(uint(2))); + uint size = stack.getSize();//Expected to be 1 + return size; + } + +} +``` +### ***2. pop 函数*** + +弹出一个元素 + +#### 参数 + +- Stack: 栈 + +#### 返回值 + +- bytes32:栈顶元素值 + +#### 实例 + +``` + +pragma solidity>=0.4.24 <0.6.11; + +import "./LibStack.sol"; + +contract Test { + + using LibStack for LibStack.Stack; + + LibStack.Stack private stack; + + function f() public returns(bytes32, uint) { + stack.push(bytes32(uint(1))); + stack.push(bytes32(uint(2))); + bytes32 pop = stack.pop();//Expect to be 2 + uint size = stack.getSize();//Expected to be 1 + return (pop, size); + } +} + +``` + +### ***3. peek 函数*** + +查询栈顶元素 + +#### 参数 + +- Stack: 栈 + +#### 返回值 + +- bytes32:栈顶元素值 + +#### 实例 + +``` + +pragma solidity>=0.4.24 <0.6.11; + +import "./LibStack.sol"; + +contract Test { + + using LibStack for LibStack.Stack; + + LibStack.Stack private stack; + + function f() public returns(bytes32, uint) { + stack.push(bytes32(uint(1))); + stack.push(bytes32(uint(2))); + bytes32 top = stack.peek();//Expect to be 2 + uint size = stack.getSize();//Expected to be 2 + return (top, size); + } +} +``` + + +### ***4. getSize 函数*** + +获取元素数 + +#### 参数 + +- Stack: 栈 + +#### 返回值 + +- uint256: 栈包含的元素数 + +#### 实例 + +``` +uint256 size = stack.getSize(); +``` diff --git a/docs/data_structure/data_structure.lnk b/docs/data_structure/data_structure.lnk new file mode 100644 index 00000000..5e53714d Binary files /dev/null and b/docs/data_structure/data_structure.lnk differ diff --git a/docs/default/Crypto.md b/docs/default/Crypto.md new file mode 100644 index 00000000..83e7ad35 --- /dev/null +++ b/docs/default/Crypto.md @@ -0,0 +1,38 @@ +# Crypto.sol + +Crypto提供了密码学操作 + +## 使用方法 + +``` +pragma solidity>=0.4.24 <0.6.11; + +pragma experimental ABIEncoderV2; + +import "./Crypto.sol"; + +contract ShaTest{ + bytes _data = "Hello, ShaTest"; + Crypto crypto; + + constructor() public { + crypto = Crypto(0x5006); + } + + function getSha256(bytes memory _memory) public returns(bytes32 result) + { + return sha256(_memory); + } + + function getKeccak256(bytes memory _memory) public returns(bytes32 result) + { + return keccak256(_memory); + } + + function getData() public view returns(bytes memory) + { + return _data; + } +} + +``` \ No newline at end of file diff --git a/docs/types/LibAddress.md b/docs/types/LibAddress.md new file mode 100644 index 00000000..c02bd84b --- /dev/null +++ b/docs/types/LibAddress.md @@ -0,0 +1,158 @@ +# LibAddress.sol + +LibAddress提供了address数据类型的基本操作,相关API列表如下。 + +## 使用方法 + +首先需要通过import引入LibAddresss类库,然后通过"."进行方法调用,如下为调用isEmptyAddress方法的例子: + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibAddress.sol" + +contract test { + + function f(address account) returns(bool) { + if(!LibAddress.isEmptyAddress(account)) { + //TODO + } + } +} +``` + + +## API列表 + +编号 | API | API描述 +---|---|--- +1 | *isContract(address account) internal view returns(bool)* | 判断地址是否为合约地址 +2 | *isEmptyAddress(address addr) internal pure returns(bool)* |判断地址是否为空地址 +3 | *addressToBytes(address addr) internal pure returns (bytes memory)* |将address转化为bytes类型 +4 | *bytesToAddress(bytes addrBytes) internal pure returns (address)* | 将bytes类型转化为地址类型 +5 | *addressToString(address addr) internal pure returns(string)* | 将地址类型转化为string类型 +6 | *stringToAddress(string data) internal returns(address)* | 将string类型转化为address类型 + +## API详情 + +### ***1. isContract 方法*** + +isContract方法用于判断一个address是否为合约地址。 + +#### 参数 + +- account:地址 + +#### 返回值 + +- bool:返回bool型,当为合约账户地址时,返回true,反之,返回false。 + +#### 实例 + +``` +address myContract = 0xE0f5206BBD039e7b0592d8918820024e2a7437b9; +if(LibAddress.isContract(myContract)){ + //TODO: +} +``` +### ***2. isEmptyAddress 方法*** + +isEmptyAddress方法用于判断一个address是否为空地址。 + +#### 参数 + +- addr:地址 + +#### 返回值 + +- bool:返回bool型,当为空地址时,返回true,反之,返回false。 + +#### 实例 + +``` + +address addr = address(0); +if(!LibAddress.isEmptyAddress(addr)){ + //TODO: +} +``` +### ***3. addressToBytes 方法*** + +addressToBytes方法可以把一个地址类型转化为bytes类型。 + +#### 参数 + +- addr:地址 + +#### 返回值 + +- bytes:返回转化后的bytes值。 + +#### 实例 + +``` +address addr = 0xE0f5206BBD039e7b0592d8918820024e2a7437b9; +bytes memory bs = LibAddress.addressToBytes(addr); +//TODO: +``` + +### ***4. bytesToAddress 方法*** + +bytesToAddress方法可以把一个bytes类型转化为address类型。 + +#### 参数 + +- bytes:字节数组。要求20字节。 + +#### 返回值 + +- address:返回转化后的address值。 + +#### 实例 + +``` +bytes memory bs = new bytes(20); +address addr = LibAddress.bytesToAddress(bs); +//TODO: +``` + +### ***5. addressToString 方法*** + +addressToString方法可以把一个address类型转化为string类型。 + +#### 参数 + +- addr:地址 + +#### 返回值 + +- string:返回转化后的string值。 + +#### 实例 + +``` +address addr = 0xE0f5206BBD039e7b0592d8918820024e2a7437b9; +string memory addrStr = LibAddress.addressToString(addr); +//TODO: +``` + +### ***6. stringToAddress 方法*** + +stringToAddress方法可以把一个string类型转化为address类型。 + +#### 参数 + +- string:字符串 + +#### 返回值 + +- address:返回转化后的address值。 + +#### 实例 + +``` +string memory str = "0xE0f5206BBD039e7b0592d8918820024e2a7437b9"; +address addr = LibAddress.stringToAddress(str); +//TODO: +``` + diff --git a/docs/types/LibArrayForUint256Utils.md b/docs/types/LibArrayForUint256Utils.md new file mode 100644 index 00000000..106f2625 --- /dev/null +++ b/docs/types/LibArrayForUint256Utils.md @@ -0,0 +1,468 @@ +# LibArrayForUint256Utils.sol + +LibArrayForUint256Utils提供了Uint256数组的相关操作,包括查找、比较、移除、添加、翻转、合并、去重和排序等操作。 + +## 使用方法 + +首先需要通过import引LibArrayForUint256Utils类库,然后通过"."进行方法调用,如下为调用indexOf方法的例子: + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibArrayForUint256Utils.sol"; + +contract test { + + uint[] private array; + + function f() public returns(bool, uint) { + array = new uint[](3); + array[0] = 1; + array[1] = 2; + array[2] = 3; + uint256 key = 3; + bool flag; + uint index; + return LibArrayForUint256Utils.firstIndexOf(array, key);//Expected (true, 2) + } +} +``` + + +## API列表 + +编号 | API | API描述 +---|---|--- +1 | *binarySearch(uint256[] storage array, uint256 key) internal pure returns (bool, uint)* | 对一个升序的数组进行二分查找 +2 | *indexOf(uint256[] storage array, uint256 key) internal pure returns (bool, uint)* |对任意数组进行查找 +3 | *reverse(uint256[] storage array) internal* |对数组进行翻转操作 +4 | *equals(uint256 a[], uint256 b[]) internal pure returns (bool)* | 判断两个数组是否相同 +5 | *removeByIndex(uint256[] storage array, uint index) internal* | 根据索引删除数据元素 +6 | *removeByValue(uint256[] storage array, uint256 value) internal* | 根据值进行数据元素删除,只删除第一个匹配的元素 +7 | *addValue(uint256[] storage array, uint256 value) internal* | 当数组中不存在元素时,把元素添加在数组末尾 +8 | *extend(uint256[] storage a, uint256[] storage b) internal* | 合并两个数组,将第二个数组合并在第一个数组上 +9 | *distinct(uint256[] storage array) internal returns (uint256 length)* | 对数组进行去重操作 +10 | *qsort(uint256[] storage array) internal pure* | 对数组进行升序排列 +11 | *max(uint256[] storage array) internal view returns (uint256, uint256)* | 找出数组的最大值及index +12 | *min(uint256[] storage array) internal view returns (uint256, uint256)* | 找出数组的最小值及index + + +## API详情 + +### ***1. binarySearch 方法*** + +binarySearch对一个升序排列的数组进行二分查找,如果找到,则返回true,并返回第一个匹配的元素索引;反之,返回(false,0) + +#### 参数 + +- array:升序排列的数组 +- key:待查找的元素 + +#### 返回值 + +- bool:当找到元素,则返回true,反之,返回false; +- uint:当找到元素,返回第一个匹配的元素索引,反之返回0; + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibArrayForUint256Utils.sol"; + +contract test { + + uint[] private array; + + function f() public returns(bool, uint) { + array = new uint[](3); + array[0] = 1; + array[1] = 2; + array[2] = 3; + uint256 key = 3; + bool flag; + uint index; + return LibArrayForUint256Utils.binarySearch(array, key);//Expected (true, 2) + } +} +``` +### ***2. firstIndexOf 方法*** + +对任意数组进行查找,如果找到,则返回true,并返回第一个匹配的元素索引;反之,返回(false,0) + +#### 参数 + +- array:升序排列的数组 +- key:待查找的元素 + +#### 返回值 + +- bool:当找到元素,则返回true,反之,返回false; +- uint:当找到元素,返回第一个匹配的元素索引,反之返回0; + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibArrayForUint256Utils.sol"; + +contract test { + + uint[] private array; + + function f() public returns(bool, uint) { + array = new uint[](3); + array[0] = 1; + array[1] = 2; + array[2] = 3; + uint256 key = 3; + bool flag; + uint index; + return LibArrayForUint256Utils.firstIndexOf(array, key);//Expected (true, 2) + } +} +``` + +### ***3. reverse 方法*** + +reverse方法对任意数组进行元素翻转。 + +#### 参数 + +- array:数组 + +#### 返回值 + +- 无 + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibArrayForUint256Utils.sol"; + +contract test { + + uint[] private array; + + function f() public { + array = new uint[](3); + array[0] = 1; + array[1] = 2; + array[2] = 3; + LibArrayForUint256Utils.reverse(array);//array becomes 3 2 1 + } +} +``` + +### ***4. equals 方法*** + +equals方法用于判断两个数组是否相等,当两个数组的元素完全相等时,则返回true,反之返回false。 + +#### 参数 + +- a:数组a +- b:数组b + +#### 返回值 + +- bool:当两个数组的元素完全相等时,则返回true,反之返回false + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibArrayForUint256Utils.sol"; + +contract test { + + uint[] private array1; + uint[] private array2; + + function f() public returns(bool) { + array1 = new uint[](3); + array1[0] = 1; + array1[1] = 2; + + array2 = new uint[](3); + array2[0] = 1; + array2[1] = 2; + return LibArrayForUint256Utils.equals(array1, array2); + } +} +``` + +### ***5. removeByIndex 方法*** + +removeByIndex方法用于根据索引删除数组元素。当数据越界时报错,当元素不存在时,数组保持不变。 + +#### 参数 + +- array:数组 +- index:待删除的元素索引 + +#### 返回值 + +- 无 + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibArrayForUint256Utils.sol"; + +contract test { + + uint[] private array; + + function f() public returns(uint) { + array = new uint[](3); + array[0] = 1; + array[1] = 2; + array[2] = 3; + LibArrayForUint256Utils.removeByIndex(array,0); + return array.length;//Expect 2 + } +} +``` + +### ***6. removeByValue 方法*** + +removeByValue方法用于根据元素值删除数组元素。当数据越界时报错,当元素不存在时,数组保持不变,只删除第一个匹配的元素。 + +#### 参数 + +- array:数组 +- value:待删除的元素值 + +#### 返回值 + +- 无 + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibArrayForUint256Utils.sol"; + +contract test { + + uint[] private array; + + function f() public returns(uint) { + array = new uint[](3); + array[0] = 1; + array[1] = 2; + array[2] = 2; + LibArrayForUint256Utils.removeByValue(array,2); + return array.length;//Expect 2 + } +} +``` + +### ***7. addValue 方法*** + +addValue方法用于向数组中添加元素,且保持数组的元素唯一。当数组中已存在当前值,则不进行添加。 + +#### 参数 + +- array:数组 +- value:待添加的元素 + +#### 返回值 + +- 无 + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibArrayForUint256Utils.sol"; + +contract test { + + uint[] private array; + + function f() public returns(uint) { + array = new uint[](0); + LibArrayForUint256Utils.addValue(array,2); + return array.length;//Expect 1 + } +} +``` + +### ***8. extend 方法*** + +extend方法用于合并两个数组,将第二个数组中的元素按照顺序追加到第一个数组后面。 + +#### 参数 + +- a:被追加数组 +- b:待追加数组 + +#### 返回值 + +- 无 + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibArrayForUint256Utils.sol"; + +contract test { + + uint[] private array; + uint[] private array2; + + function f() public returns(uint) { + array = new uint[](2); + array2 = new uint[](2); + LibArrayForUint256Utils.extend(array,array2); + return array.length;//Expect 4 + } +} +``` + +### ***9. distinct 方法*** + +distinct方法用于对数组进行去重操作。 + +#### 参数 + +- array:数组 + +#### 返回值 + +- 无 + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibArrayForUint256Utils.sol"; + +contract test { + + uint[] private array; + + function f() public returns(uint) { + array = new uint[](3); + array[0] = 2; + array[1] = 2; + array[2] = 2; + LibArrayForUint256Utils.distinct(array); + return array.length;//Expect 1 + } +} +``` + +### ***10. qsort 方法*** + +qsort方法用于对数组进行快速排序。 + +#### 参数 + +- array:数组 + +#### 返回值 + +- 无 + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibArrayForUint256Utils.sol"; + +contract test { + + uint[] private array; + + function f() public returns(uint,uint,uint) { + array = new uint[](3); + array[0] = 3; + array[1] = 2; + array[2] = 1; + LibArrayForUint256Utils.qsort(array); + return (array[0], array[1], array[2]);//expect 1,2,3 + } +} +``` + +### ***11. max 方法*** + +对任意数组进行查找最大值,并返回最大值所在的index + +#### 参数 + +- array:待查找的数组 + +#### 返回值 + +- uint256:最大值; +- uint256:最大值的index; + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibArrayForUint256Utils.sol"; + +contract test { + + uint[] private array; + + function f() public returns(uint, uint) { + array = new uint[](3); + array[0] = 3; + array[1] = 2; + array[2] = 1; + return LibArrayForUint256Utils.max(array);//3 , 0 + } +} +``` + +### ***12. min 方法*** + +对任意数组进行查找最小值,并返回最小值所在的index + +#### 参数 + +- array:待查找的数组 + +#### 返回值 + +- uint256:最小值; +- uint256:最小值的index; + +#### 实例 + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibArrayForUint256Utils.sol"; + +contract test { + + uint[] private array; + + function f() public returns(uint, uint) { + array = new uint[](3); + array[0] = 3; + array[1] = 2; + array[2] = 1; + return LibArrayForUint256Utils.min(array);//1 , 2 + } +} +``` \ No newline at end of file diff --git a/docs/types/LibConverter.md b/docs/types/LibConverter.md new file mode 100644 index 00000000..981a65d8 --- /dev/null +++ b/docs/types/LibConverter.md @@ -0,0 +1,214 @@ +# LibConverter.sol + +LibConverter提供各类solidity数据基本类型的转换,包括uint256转uint128、uint64、uint32等,uint256转bytes,int转bytes,bytes转int等转换方法。 + +## 使用方法 + +首先需要通过import引入LibConverter类库,调用库的相关方法: + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibConverter.sol" + +contract test { + + function f() public view{ + uint256 a = 25; + uint16 b = LibConverter.toUint16(a); + //TODO: + } +} +``` + + +## API列表 + +编号 | API | API描述 +---|---|--- +1 | *toUint128(uint256 value) internal pure returns (uint128)* | 将uint256转为uint128类型 +2 | *toUint64(uint256 value) internal pure returns (uint64)* | 将uint256转为uint64类型 +3 | *toUint32(uint256 value) internal pure returns (uint32)* | 将uint256转为uint32类型 +4 | *toUint16(uint256 value) internal pure returns (uint16)* | 将uint256转为uint16类型 +5 | *toUint8(uint256 value) internal pure returns (uint8)* | 将uint256转为uint8类型 +6 | *uintToBytes(uint v) internal pure returns (bytes)* | 将uint转为bytes类型 +7 | *bytesToInt(bytes b) internal pure returns (int result)* | 将bytes转为int类型 +8 | *intToBytes(int v) internal pure returns (bytes)* | 将int转为bytes类型 + +## API详情 + +### ***1. toUint128 方法*** + +将uint256转为uint128类型,如超出uint128的最大值,则报错退出。 + +#### 参数 + +- uint256:转换数 + +#### 返回值 + +- uint128:返回转换结果。 + +#### 实例 + +``` +function f() public view{ + uint256 a = 25; + uint128 b = LibConverter.toUint128(a); + //TODO: +} +``` + +### ***2. toUint64 方法*** + +将uint256转为uint64类型,如超出uint64的最大值,则报错退出。 + +#### 参数 + +- uint256:转换数 + +#### 返回值 + +- uint64:返回转换结果。 + +#### 实例 + +``` +function f() public view{ + uint256 a = 25; + uint64 b = LibConverter.toUint64(a); + //TODO: +} +``` + +### ***3. toUint32 方法*** + +将uint256转为uint32类型,如超出uint32的最大值,则报错退出。 + +#### 参数 + +- uint256:转换数 + +#### 返回值 + +- uint32:返回转换结果。 + +#### 实例 + +``` +function f() public view{ + uint256 a = 25; + uint32 b = LibConverter.toUint32(a); + //TODO: +} +``` + +### ***4. toUint16 方法*** + +将uint256转为uint16类型,如超出uint16的最大值,则报错退出。 + +#### 参数 + +- uint256:转换数 + +#### 返回值 + +- uint16:返回转换结果。 + +#### 实例 + +``` +function f() public view{ + uint256 a = 25; + uint16 b = LibConverter.toUint16(a); + //TODO: +} +``` + +### ***5. toUint8 方法*** + +将uint256转为uint8类型,如超出uint8的最大值,则报错退出。 + +#### 参数 + +- uint256:转换数 + +#### 返回值 + +- uint8:返回转换结果。 + +#### 实例 + +``` +function f() public view{ + uint256 a = 25; + uint8 b = LibConverter.toUint8(a); + //TODO: +} +``` + +### ***5. toBytes 方法*** + +将uint256转为bytes类型。 + +#### 参数 + +- uint:转换数 + +#### 返回值 + +- bytes:转换结果 + +#### 实例 + +``` +function f() public view{ + uint256 a = 25; + bytes memory b = LibConverter.uintToBytes(a); + //TODO: +} +``` + +### ***6. bytesToInt 方法*** + +将bytes转为uint256类型。 + +#### 参数 + +- bytes:转换字节 + +#### 返回值 + +- int:转换结果 + +#### 实例 + +``` +function f() public view{ + bytes memory a = "25"; + int b = LibConverter.bytesToInt(a); + //TODO: +} +``` + +### ***7. intToBytes 方法*** + +将int转为bytes类型。 + +#### 参数 + +- int:转换数 + +#### 返回值 + +- bytes:转换结果 + +#### 实例 + +``` +function f() public view{ + int a = 25; + bytes memory b = LibConverter.intToBytes(a); + //TODO: +} +``` diff --git a/docs/types/LibSafeMathForUint256Utils.md b/docs/types/LibSafeMathForUint256Utils.md new file mode 100644 index 00000000..a0a6f31d --- /dev/null +++ b/docs/types/LibSafeMathForUint256Utils.md @@ -0,0 +1,256 @@ +# LibSafeMathForUint256Utils.sol + +LibSafeMathForUint256Utils提供了Uint256类型的相关计算操作,且保证数据的正确性和安全性,包括加法、减法、乘法、除法、取模、乘方、最大值、最小值和平均数等操作。 + +## 使用方法 + +首先需要通过import引LibSafeMathForUint256Utils类库,然后通过"."进行方法调用,如下为调用add方法的例子: + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibSafeMathForUint256Utils.sol" + +contract test { + + function f() public view{ + uint256 a = 25; + uint256 b = 20; + uint256 c = LibSafeMathForUint256Utils.add(a,b); + //TODO: + } +} +``` + + +## API列表 + +编号 | API | API描述 +---|---|--- +1 | *add(uint256 a, uint256 b) internal pure returns (uint256)* | 加法操作 +2 | *sub(uint256 a, uint256 b) internal pure returns (uint256)* | 减法操作 +3 | *mul(uint256 a, uint256 b) internal pure returns (uint256)* | 乘法操作 +4 | *div(uint256 a, uint256 b) internal pure returns (uint256)* | 除法操作 +5 | *mod(uint256 a, uint256 b) internal pure returns (uint256)* | 取模操作 +6 | *power(uint256 a, uint256 b) internal pure returns (uint256)* | 乘方操作 +7 | *max(uint256 a, uint256 b) internal pure returns (uint256)* | 取最大值操作 +8 | *min(uint256 a, uint256 b) internal pure returns (uint256)* | 取最小值操作 +9 | *average(uint256 a, uint256 b) internal pure returns (uint256)* | 求平均数操作 + +## API详情 + +### ***1. add 方法*** + +add对两个数进行加法操作,返回相加之后的结果。 + +#### 参数 + +- a:加数 +- b:加数 + +#### 返回值 + +- uint256:返回相加的结果。 + +#### 实例 + +``` +function f() public view{ + uint256 a = 25; + uint256 b = 20; + uint256 c = LibSafeMathForUint256Utils.add(a,b); + //TODO: +} +``` + +### ***2. sub 方法*** + +sub对两个数进行减法操作,返回相减之后的结果。 + +#### 参数 + +- a:被减数 +- b:减数 + +#### 返回值 + +- uint256:返回相减的结果。 + +#### 实例 + +``` +function f() public view{ + uint256 a = 25; + uint256 b = 20; + uint256 c = LibSafeMathForUint256Utils.sub(a,b); + //TODO: +} +``` + +### ***3. mul 方法*** + +mul方法对两个数进行乘法操作,返回相乘之后的结果。 + +#### 参数 + +- a:被乘数 +- b:乘数 + +#### 返回值 + +- uint256:返回相乘的结果。 + +#### 实例 + +``` +function f() public view{ + uint256 a = 25; + uint256 b = 20; + uint256 c = LibSafeMathForUint256Utils.mul(a,b); + //TODO: +} +``` + +### ***4. div 方法*** + +div方法对两个数进行除法操作,返回相除之后的结果。 + +#### 参数 + +- a:被除数 +- b:除数 + +#### 返回值 + +- uint256:返回相除的结果。 + +#### 实例 + +``` +function f() public view{ + uint256 a = 25; + uint256 b = 20; + uint256 c = LibSafeMathForUint256Utils.div(a,b); + //TODO: +} +``` + +### ***5. mod 方法*** + +mod方法对两个数进行取模操作,返回取模之后的结果。 + +#### 参数 + +- a:被取模的数 +- b:模值 + +#### 返回值 + +- uint256:返回取模的结果。 + +#### 实例 + +``` +function f() public view{ + uint256 a = 25; + uint256 b = 20; + uint256 c = LibSafeMathForUint256Utils.mod(a,b); + //TODO: +} +``` + +### ***5. power 方法*** + +power方法对两个数进行乘方操作,返回乘方之后的结果。 + +#### 参数 + +- a:基数 +- b:乘方值 + +#### 返回值 + +- uint256:返回乘方的结果。 + +#### 实例 + +``` +function f() public view{ + uint256 a = 25; + uint256 b = 20; + uint256 c = LibSafeMathForUint256Utils.power(a,b); + //TODO: +} +``` + +### ***6. max 方法*** + +max方法对两个数进行比较,返回最大值。 + +#### 参数 + +- a:数值1 +- b:数值2 + +#### 返回值 + +- uint256:返回最大值。 + +#### 实例 + +``` +function f() public view{ + uint256 a = 25; + uint256 b = 20; + uint256 c = LibSafeMathForUint256Utils.max(a,b); + //TODO: +} +``` + +### ***7. min 方法*** + +min方法对两个数进行比较,返回最小值。 + +#### 参数 + +- a:数值1 +- b:数值2 + +#### 返回值 + +- uint256:返回最小值。 + +#### 实例 + +``` +function f() public view{ + uint256 a = 25; + uint256 b = 20; + uint256 c = LibSafeMathForUint256Utils.mix(a,b); + //TODO: +} +``` + +### ***8. average 方法*** + +average方法对两个数求平均值,返回平均值。 + +#### 参数 + +- a:数值1 +- b:数值2 + +#### 返回值 + +- uint256:返回平均值。 + +#### 实例 + +``` +function f() public view{ + uint256 a = 25; + uint256 b = 20; + uint256 c = LibSafeMathForUint256Utils.average(a,b); + //TODO: +} +``` diff --git a/docs/types/LibString.md b/docs/types/LibString.md new file mode 100644 index 00000000..c847b786 --- /dev/null +++ b/docs/types/LibString.md @@ -0,0 +1,412 @@ +# LibString.sol + +LibString提供了常用的字符串操作。这些操作是基于字符的,而非字节。 + +## 使用方法 + +首先需要通过import引入LibString类库, 以下为使用示例 + +``` +pragma solidity>=0.4.24 <0.6.11; + +import "./LibString.sol"; + +contract TestString { + + function f() public view returns(uint ){ + string memory str = "字符串"; + uint len = LibString.lenOfChars(str);//Expected to be 3 + return len; + } +} +``` + + +## API列表 + +编号 | API | API描述 +---|---|--- +1 | *lenOfChars(string src) internal pure returns(uint)* | 获取字符个数 +2 | *lenOfBytes(string src) internal pure returns(uint)* | 获取字节个数 +3 | *startWith(string src, string prefix) internal pure returns(bool)* | 前缀串判断 +4 | *endWith(string src, string tail) internal pure returns(bool)* | 尾缀串判断 +5 | *equal(string self, string other)* | 两字符串是否相等 +6 | *equalNocase(string self, string other)* | 两字符串是否相等, 忽视大小写 +7 | *empty(string src) public pure returns(bool)* | 字符串是否为空 +8 | *concat(string self, string str) public returns (string _ret)* | 字符串拼接 +9 | *substrByCharIndex(string self, uint start, uint len) public returns (string)* | 取子字符串,下标是字符下标 +10 | *compare(string self, string other) internal pure returns (int)* | 比较两个字符串的大小 +11 | *compareNocase(string self, string other) internal pure returns (int)* | 比较两个字符串的大小,忽视大小写 +12 | *toUppercase(string src) internal pure returns(string)* | 转换为大写 +13 | *toLowercase(string src) internal pure returns(string)* | 转换为小写 +14 | *indexOf(string src, string value) internal pure returns (int)* | 查找字符串中是否含有子字符串 +15 | *indexOf(string src, string value, uint offset) internal pure returns (int)* | 查找字符串中是否含有子字符串 +16 | *split(string src, string separator) internal pure returns (string[])* | 字符串根据分隔符拆分成数组 + +## API详情 + +### ***1. lenOfChars 方法*** + +获取一个字符串所包含的字符数量 + +#### 参数 + +- src: 字符串 + +#### 返回值 + +- uint256:字符个数 + +#### 实例 + +``` + function f() public view returns(uint ){ + string memory str = "字符串"; + uint len = LibString.lenOfChars(str);//Expected to be 3 + return len; + } +``` + +### ***2. lenOfBytes 方法*** + +获取一个字符串所包含的字节数量 + +#### 参数 + +- src: 字符串 + +#### 返回值 + +- uint256:字节个数 + +#### 实例 + +``` + function f() public view returns(uint ){ + string memory str = "字符串"; + uint len = LibString.lenOfBytes(str);//Expected to be 9 + return len; + } +``` + +### ***3. startWith 方法*** + +startWith用于判断一个字符串是否为另一个字符串的前缀串 + +#### 参数 + +- src:字符串 +- prefix:子串 + +#### 返回值 + +- bool: prefix是否为src的前缀串 + +#### 实例 + +``` + function f() public view returns(bool){ + bool r = LibString.startWith("abcd","ab");//Expected to be true + return r; + } +``` + +### ***4. endWith 方法*** + +endWith用于测试一个字符串是否为另一个字符串的尾缀串 + +#### 参数 + +- src: 字符串 +- tail:子串 + +#### 返回值 + +- bool: tail是否为src的尾缀串 + +#### 实例 + +``` + function f() public view returns(bool){ + bool r = LibString.startWith("abcd","cd");//Expected to be true + return r; + } +``` + +### ***5. equal 方法*** + +用于判断两个字符串是否相等。 + +#### 参数 + +- self:字符串 +- other:字符串 + +#### 返回值 + +- bool: 两个字符串是否相等 + +#### 实例 + +``` + function f() public view returns(bool){ + bool r = LibString.equal("abcd","abcd");//Expected to be true + return r; + } +``` + +### ***6. equalNocase 方法*** + +用于判断两个字符串是否相等。忽视大小写 + +#### 参数 + +- self:字符串 +- other:字符串 + +#### 返回值 + +- bool: 两个字符串是否相等。忽视大小写 + +#### 实例 + +``` + function f() public view returns(bool){ + bool r = LibString.equalNocase("abcd","ABCD");//Expected to be true + return r; + } +``` + +### ***7. empty 方法*** + +判断字符串是否为空串 + +#### 参数 + +- src: 待判断串 + +#### 返回值 + +- bool: 该字符串是否为空串 + +#### 实例 + +``` + function f() public returns(bool, bool){ + + bool r1 = LibString.empty("abcd");//Expected to be false + bool r2 = LibString.empty("");//Expected to be true + //TODO: + return (r1,r2); + } +``` + +### ***8. concat 方法*** + +该方法连接两个字符串,并得到一个新的字符串。 + +#### 参数 + +- self:当前字符串 +- str:另一个字符串 + +#### 返回值 + +- string: 拼接所得字符串 + +#### 实例 + +``` + function f() public returns(string memory){ + string memory s1 = "ab"; + string memory s2 = "cd"; + return LibString.concat(s1,s2);//Exptected to be abcd + } +``` + +### ***9. substrByCharIndex方法*** + +substrByCharIndex方法用于提取子字符串。 + +#### 参数 + +- self:当前字符串 +- start:子串起点字符的下标 +- end: 字串的字符长度 + +#### 返回值 + +- string: 子串 + +#### 实例 + +``` + function f() public returns(string memory) { + string memory full = "完整字符串"; + string memory sub = LibString.substrByCharIndex(full ,2, 3);//Expected to be 字符串 + return sub; + } +``` + +### ***10. compare 方法*** + +用于判断两个字符串的大小。 + +#### 参数 + +- self:字符串 +- other:字符串 + +#### 返回值 + +- int8: -1:左值小于右边,0:相等,1-左值大于右边 + +#### 实例 + +``` + function f() public view returns(int8){ + + int8 c = LibString.compare("abcd","abcd");// Expected to be 0 + } +``` + + +### ***11. compareNocase 方法*** + +用于判断两个字符串的大小。忽视大小写 + +#### 参数 + +- self:字符串 +- other:字符串 + +#### 返回值 + +- int8: -1:左值小于右边,0:相等,1-左值大于右边 + +#### 实例 + +``` + function f() public view returns(int8){ + + int8 c = LibString.compareNocase("abcd","abcd");// Expected to be 0 + } +``` + +### ***12. toUppercase 方法*** + +转换成大写 + +#### 参数 + +- src: 字符串 + +#### 返回值 + +- string: 大写字符串 + +#### 实例 + +``` + function f() public view returns(string memory) { + + string memory c = LibString.toUppercase("abcd");// Expected to be ABCD + return c; + } +``` + +### ***13. toLowercase 方法*** + +转换成小写 + +#### 参数 + +- src: 字符串 + +#### 返回值 + +- string: 小写字符串 + +#### 实例 + +``` + function f() public view returns(string memory) { + + string memory c = LibString.toLowercase("ABCD");// Expected to be abcd + return c; + } +``` + +### ***14. indexOf 方法*** + +查找字符串中相同子字符串的位置 + +#### 参数 + +- string: 字符串 +- string: 子字符串 + +#### 返回值 + +- int: 返回字符串的位置,如不存在返回-1 + +#### 实例 + +``` + function f() public view returns(int) { + + int c = LibString.indexOf("ABCD", "B");// Expected to be 1 + return c; + } +``` + +### ***15. indexOf 方法*** + +查找字符串中相同子字符串的位置 + +#### 参数 + +- string: 字符串 +- string: 子字符串 +- uint: 查找起始位置 + +#### 返回值 + +- int: 返回字符串的位置,如不存在返回-1 + +#### 实例 + +``` + function f() public view returns(int){ + + int c = LibString.indexOf("ABCD", "B", 0);// Expected to be 1 + return c; + + } +``` + + +### ***16. split 方法*** + +对字符串按照提供的隔断符分成一个string数组 + +#### 参数 + +- string: 字符串 +- string: 隔断符 + +#### 返回值 + +- string[]: 字符串数组 + +#### 实例 + +``` + + function f() public view returns(string[] memory){ + + string[] memory c = LibString.split("A,B,CD", ",");// Expected to be ["A", "B", "CD"] + return c; + + } +``` \ No newline at end of file

AltStyle によって変換されたページ (->オリジナル) /