├── .gitignore ├── LICENSE ├── README.md ├── contracts ├── .DS_Store ├── CrosschainV2.sol ├── IncentiveV3.sol ├── Management.sol ├── Migrations.sol ├── MinterContract.sol ├── Rebaser.sol ├── airdrop.sol ├── communityFund.sol ├── crosschain.sol ├── factory.sol ├── faucet.sol ├── file.sol ├── fileV2.sol ├── governor.sol ├── incentive.sol ├── incentiveV2.sol ├── invest.sol ├── link.sol ├── pledge.sol ├── pledgeV2.sol ├── pledgeV3.sol ├── proxy │ ├── communityFund_proxy.sol │ ├── crosschain_proxy.sol │ ├── factory_proxy.sol │ ├── file_proxy.sol │ ├── governor_proxy.sol │ ├── incentive_proxy.sol │ ├── invest_proxy.sol │ ├── luca_proxy.sol │ ├── pledge_proxy.sol │ ├── proxy.sol │ ├── rebaser_proxy.sol │ └── trader_proxy.sol ├── token │ ├── agt.sol │ ├── erc20.sol │ ├── luca.sol │ └── wluca.sol ├── trader.sol ├── traderV2.sol └── wormhole.sol └── image ├── flow1.svg └── flow2.svg /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | class 3 | target/ 4 | .externalToolBuilders 5 | .settings 6 | *.iml 7 | *.json 8 | 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## ATM Introduction 2 | Autonomous Trust Momentum is a decentralized mechanism deployed on multiple blockchains. With the use of our main mechanism, the consensus contract, two users can lock value for a predefined period. With the creation of many of these connections, we hope that a network of consensus contracts will emerge – otherwise known as a relative consensus network. 3 | 4 | Decentralized finance is already a form of consensus network – it allows people to establish consensus in a decentralised system using blockchain technology. This current system is based on the individual and their impulses: they can buy today and sell tomorrow. ATM aims to solve this by constructing a new form of consensus, built on the strength of social networks rather than the fragility of the individual. 5 | 6 | 7 | 8 | ## ATM Smart Contract-Consensus Contract 9 | By leveraging our consensus contract two users can lock value for a predefined period. This is what we mean by consensus connection. 10 | 11 | As consensus connections between users are continuously established, and a huge relative consensus network emerges. 12 | 13 | 14 | ## The content of the consensus contract includes: 15 | 16 | #### Both users need to confirm: 17 | User A sets up a consensus contract which initiates a request to establish a connection to user B. If B agrees, the contract will be executed, and the consensus connection will be successful. 18 | 19 | #### Locked Token: 20 | Any cryptocurrency supported by ATM; 21 | 22 | #### Investment amount: 23 | The value that both parties agree upon - It does not have to be equal for both users; 24 | 25 | #### Lock-up time: 26 | The length of time for which the investment amount will be locked; 27 | 28 | #### Contract cancellation: 29 | During the lock-up time, either user cannot cancel the contract on their own. They must wait until the end of the contract or reach agreement with one another to terminate it early. Upon expiration, the contract will remain valid if neither party has decided to cancel. 30 | 31 | 32 |
33 | 图片 34 |
35 | 36 | ## Wormhole 37 | In physics, a wormhole - also known as an Einstein-Rosen Bridge - is a narrow tunnel connecting two different places in space-time directly. In ATM, “wormhole” refers to connection contracts that operate between different blockchain. Users can connect their wallet addresses on different public chains using the wormhole contract provided by ATM, and in ATMRank the addresses on the two public chains would be regarded as a single node in the relative consensus network. Through the merging of cross-chain addresses across different public chains we hope that fractured networks will instead become a single integrated community. 38 | 39 |
40 | 图片 41 |
42 | -------------------------------------------------------------------------------- /contracts/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/postnext/atm-contract/3816cf01e7416621dc2400de89c28d1d0e6d0d21/contracts/.DS_Store -------------------------------------------------------------------------------- /contracts/CrosschainV2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.0 ; 3 | 4 | interface IERC20 { 5 | function transfer(address _to, uint256 _value) external returns (bool); 6 | function balanceOf(address account) external view returns (uint256); 7 | function mint(uint256 amount) external; 8 | function burn(uint256 amount) external; 9 | function transferFrom(address _from, address _to, uint256 _value) external returns (bool); 10 | function lucaToFragment(uint256 value) external view returns (uint256); 11 | function fragmentToLuca(uint256 value) external view returns (uint256); 12 | } 13 | interface Itrader { 14 | function suck(address _to, uint256 _amount) external; 15 | } 16 | interface ICrosschain { 17 | function transferToken( 18 | address[2] calldata addrs, 19 | uint256[3] calldata uints, 20 | string[] calldata strs, 21 | uint8[] calldata vs, 22 | bytes32[] calldata rssMetadata) external; 23 | function stakeToken(string memory _chain, string memory receiveAddr, address tokenAddr, uint256 _amount) external ; 24 | } 25 | 26 | abstract contract Initializable { 27 | /** 28 | * @dev Indicates that the contract has been initialized. 29 | */ 30 | bool private _initialized; 31 | 32 | /** 33 | * @dev Indicates that the contract is in the process of being initialized. 34 | */ 35 | bool private _initializing; 36 | 37 | /** 38 | * @dev Modifier to protect an initializer function from being invoked twice. 39 | */ 40 | modifier initializer() { 41 | require(_initializing || !_initialized, "Initializable: contract is already initialized"); 42 | 43 | bool isTopLevelCall = !_initializing; 44 | if (isTopLevelCall) { 45 | _initializing = true; 46 | _initialized = true; 47 | } 48 | 49 | _; 50 | 51 | if (isTopLevelCall) { 52 | _initializing = false; 53 | } 54 | } 55 | } 56 | 57 | contract Ownable is Initializable{ 58 | address private _owner; 59 | 60 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 61 | 62 | /** 63 | * @dev Initializes the contract setting the management contract as the initial owner. 64 | */ 65 | function __Ownable_init_unchained(address _management) internal initializer { 66 | require( _management != address(0),"management address cannot be 0"); 67 | _owner = _management; 68 | emit OwnershipTransferred(address(0), _management); 69 | } 70 | 71 | /** 72 | * @dev Returns the address of the current owner. 73 | */ 74 | function owner() public view returns (address) { 75 | return _owner; 76 | } 77 | 78 | /** 79 | * @dev Throws if called by any account other than the owner. 80 | */ 81 | modifier onlyOwner() { 82 | require(isOwner(), "Ownable: caller is not the owner"); 83 | _; 84 | } 85 | 86 | /** 87 | * @dev Returns true if the caller is the current owner. 88 | */ 89 | function isOwner() public view returns (bool) { 90 | return msg.sender == _owner; 91 | } 92 | 93 | /** 94 | * @dev Leaves the contract without owner. It will not be possible to call 95 | * `onlyOwner` functions anymore. Can only be called by the current owner. 96 | * 97 | * NOTE: Renouncing ownership will leave the contract without an owner, 98 | * thereby removing any functionality that is only available to the owner. 99 | */ 100 | function renounceOwnership() public onlyOwner { 101 | emit OwnershipTransferred(_owner, address(0)); 102 | _owner = address(0); 103 | } 104 | 105 | /** 106 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 107 | * Can only be called by the current owner. 108 | */ 109 | function transferOwnership(address newOwner) public onlyOwner { 110 | _transferOwnership(newOwner); 111 | } 112 | 113 | /** 114 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 115 | */ 116 | function _transferOwnership(address newOwner) internal { 117 | require(newOwner != address(0), "Ownable: new owner is the zero address"); 118 | emit OwnershipTransferred(_owner, newOwner); 119 | _owner = newOwner; 120 | } 121 | } 122 | 123 | contract CrosschainV2 is Initializable,Ownable,ICrosschain { 124 | using SafeMath for uint256; 125 | bool public pause; 126 | uint256 public nodeNum; 127 | uint256 public stakeNum; 128 | bytes32 public DOMAIN_SEPARATOR; 129 | bool public bscSta; 130 | IERC20 public lucaToken; 131 | mapping(string => mapping(address => uint256)) public chargeRate; 132 | mapping(address => uint256) chargeAmount; 133 | mapping(string => bool) public chainSta; 134 | mapping(string => mapping(string => bool)) status; 135 | mapping(address => uint256) nodeAddrIndex; 136 | mapping(uint256 => address) public nodeIndexAddr; 137 | mapping(address => bool) public nodeAddrSta; 138 | mapping(uint256 => Stake) public stakeMsg; 139 | event UpdatePause(bool sta); 140 | event WithdrawChargeAmount(address tokenAddr, uint256 amount); 141 | event AddNodeAddr(address[] nodeAddrs); 142 | event DeleteNodeAddr(address[] nodeAddrs); 143 | event UpdateChainCharge(string chain, bool sta, address[] tokens, uint256[] fees); 144 | event TransferToken(address indexed _tokenAddr, address _receiveAddr, uint256 _fragment, uint256 _amount, string chain, string txid); 145 | event StakeToken(address indexed _tokenAddr, address indexed _userAddr, string receiveAddr, uint256 fragment, uint256 amount, uint256 fee,string chain); 146 | IERC20 public agtToken; 147 | Itrader public trader; 148 | mapping(address => uint256) public threshold; 149 | mapping(address => mapping(uint256 => uint256)) public withdrawLimit; 150 | event UpdateThreshold(address tokenAddr, uint256 threshold); 151 | 152 | 153 | struct Data { 154 | address userAddr; 155 | address contractAddr; 156 | uint256 fragment; 157 | uint256 amount; 158 | uint256 expiration; 159 | string chain; 160 | string txid; 161 | } 162 | 163 | struct Stake { 164 | address tokenAddr; 165 | address userAddr; 166 | string receiveAddr; 167 | uint256 fragment; 168 | uint256 amount; 169 | uint256 fee; 170 | string chain; 171 | } 172 | 173 | struct Sig { 174 | /* v parameter */ 175 | uint8 v; 176 | /* r parameter */ 177 | bytes32 r; 178 | /* s parameter */ 179 | bytes32 s; 180 | } 181 | 182 | modifier onlyGuard() { 183 | require(!pause, "Crosschain: The system is suspended"); 184 | _; 185 | } 186 | 187 | function init( 188 | address _lucaToken, 189 | address _trader, 190 | address _agt, 191 | address _management, 192 | bool _sta 193 | ) external initializer{ 194 | __Ownable_init_unchained(_management); 195 | __Crosschain_init_unchained(_lucaToken, _trader, _agt, _sta); 196 | } 197 | 198 | function __Crosschain_init_unchained( 199 | address _lucaToken, 200 | address _trader, 201 | address _agt, 202 | bool _sta 203 | ) internal initializer{ 204 | require( _lucaToken != address(0),"lucaToken address cannot be 0"); 205 | require( _trader != address(0),"trader address cannot be 0"); 206 | require( _agt != address(0),"agt address cannot be 0"); 207 | lucaToken = IERC20(_lucaToken); 208 | trader = Itrader(_trader); 209 | agtToken = IERC20(_agt); 210 | bscSta = _sta; 211 | uint chainId; 212 | assembly { 213 | chainId := chainId 214 | } 215 | DOMAIN_SEPARATOR = keccak256( 216 | abi.encode( 217 | keccak256('EIP712Domain(uint256 chainId,address verifyingContract)'), 218 | chainId, 219 | address(this) 220 | ) 221 | ); 222 | } 223 | 224 | receive() payable external{ 225 | 226 | } 227 | 228 | fallback() payable external{ 229 | 230 | } 231 | 232 | function updatePause(bool _sta) external onlyOwner{ 233 | pause = _sta; 234 | emit UpdatePause(_sta); 235 | } 236 | 237 | function updateThreshold(address[] calldata _tokens, uint256[] calldata _thresholds) external onlyOwner{ 238 | require(_tokens.length == _thresholds.length, "Parameter array length does not match"); 239 | for (uint256 i = 0; i< _tokens.length; i++){ 240 | threshold[_tokens[i]] = _thresholds[i]; 241 | emit UpdateThreshold(_tokens[i], _thresholds[i]); 242 | } 243 | } 244 | 245 | function updateChainCharge(string calldata _chain, bool _sta, address[] calldata _tokens, uint256[] calldata _fees) external onlyOwner{ 246 | chainSta[_chain] = _sta; 247 | require(_tokens.length == _fees.length, "Parameter array length does not match"); 248 | for (uint256 i = 0; i< _tokens.length; i++){ 249 | chargeRate[_chain][_tokens[i]] = _fees[i]; 250 | } 251 | emit UpdateChainCharge(_chain, _sta, _tokens, _fees); 252 | } 253 | 254 | function withdrawChargeAmount(address[] calldata tokenAddrs, address receiveAddr) external onlyOwner{ 255 | require( receiveAddr != address(0),"receiveAddr address cannot be 0"); 256 | for (uint256 i = 0; i< tokenAddrs.length; i++){ 257 | if(tokenAddrs[i] == address(lucaToken)){ 258 | uint256 _amount = lucaToken.fragmentToLuca(chargeAmount[tokenAddrs[i]]); 259 | require(lucaToken.transfer(receiveAddr,_amount), "Token transfer failed"); 260 | chargeAmount[tokenAddrs[i]] = 0; 261 | emit WithdrawChargeAmount(tokenAddrs[i], _amount); 262 | }else{ 263 | IERC20 token = IERC20(tokenAddrs[i]); 264 | uint256 _amount = chargeAmount[tokenAddrs[i]]; 265 | require(token.transfer(receiveAddr,_amount), "Token transfer failed"); 266 | chargeAmount[tokenAddrs[i]] = 0; 267 | emit WithdrawChargeAmount(tokenAddrs[i], _amount); 268 | } 269 | 270 | } 271 | 272 | } 273 | 274 | function addNodeAddr(address[] calldata _nodeAddrs) external onlyOwner{ 275 | for (uint256 i = 0; i< _nodeAddrs.length; i++){ 276 | address _nodeAddr = _nodeAddrs[i]; 277 | require(!nodeAddrSta[_nodeAddr], "This node is already a node address"); 278 | nodeAddrSta[_nodeAddr] = true; 279 | uint256 _nodeAddrIndex = nodeAddrIndex[_nodeAddr]; 280 | if (_nodeAddrIndex == 0){ 281 | _nodeAddrIndex = ++nodeNum; 282 | nodeAddrIndex[_nodeAddr] = _nodeAddrIndex; 283 | nodeIndexAddr[_nodeAddrIndex] = _nodeAddr; 284 | } 285 | } 286 | emit AddNodeAddr(_nodeAddrs); 287 | } 288 | 289 | function deleteNodeAddr(address[] calldata _nodeAddrs) external onlyOwner{ 290 | for (uint256 i = 0; i< _nodeAddrs.length; i++){ 291 | address _nodeAddr = _nodeAddrs[i]; 292 | require(nodeAddrSta[_nodeAddr], "This node is not a pledge node"); 293 | nodeAddrSta[_nodeAddr] = false; 294 | uint256 _nodeAddrIndex = nodeAddrIndex[_nodeAddr]; 295 | if (_nodeAddrIndex > 0){ 296 | uint256 _nodeNum = nodeNum; 297 | address _lastNodeAddr = nodeIndexAddr[_nodeNum]; 298 | nodeAddrIndex[_lastNodeAddr] = _nodeAddrIndex; 299 | nodeIndexAddr[_nodeAddrIndex] = _lastNodeAddr; 300 | nodeAddrIndex[_nodeAddr] = 0; 301 | nodeIndexAddr[_nodeNum] = address(0x0); 302 | nodeNum--; 303 | } 304 | } 305 | emit DeleteNodeAddr(_nodeAddrs); 306 | } 307 | 308 | function stakeToken(string memory _chain, string memory receiveAddr, address tokenAddr, uint256 _amount) override external { 309 | address _sender = msg.sender; 310 | require( tokenAddr == address(lucaToken) || tokenAddr == address(agtToken) , "Crosschain: The token does not support transfers"); 311 | require( chainSta[_chain], "Crosschain: The chain does not support transfer"); 312 | require(verfylimit(tokenAddr,_amount),"Extraction limit exceeded"); 313 | if (address(lucaToken) == tokenAddr){ 314 | require(lucaToken.transferFrom(_sender,address(this),_amount), "Token transfer failed"); 315 | uint256 _charge = chargeRate[_chain][tokenAddr]; 316 | _amount = _amount.sub(_charge); 317 | uint256 fragment = lucaToken.lucaToFragment(_amount); 318 | require(fragment > 0, "Share calculation anomaly"); 319 | uint256 fee = lucaToken.lucaToFragment(_charge); 320 | chargeAmount[tokenAddr] = chargeAmount[tokenAddr].add(fee); 321 | stakeMsg[++stakeNum] = Stake(tokenAddr, _sender, receiveAddr, fragment, _amount, fee, _chain); 322 | if(!bscSta){ 323 | lucaToken.burn(_amount); 324 | } 325 | emit StakeToken(tokenAddr, _sender, receiveAddr, fragment, _amount, fee, _chain); 326 | }else{ 327 | IERC20 token = IERC20(tokenAddr); 328 | require(token.transferFrom(_sender,address(this),_amount), "Token transfer failed"); 329 | uint256 fee = chargeRate[_chain][tokenAddr]; 330 | _amount = _amount.sub(fee); 331 | chargeAmount[tokenAddr] = chargeAmount[tokenAddr].add(fee); 332 | stakeMsg[++stakeNum] = Stake(tokenAddr, _sender, receiveAddr, 0, _amount, fee, _chain); 333 | token.burn(_amount); 334 | emit StakeToken(tokenAddr, _sender, receiveAddr, 0, _amount, fee, _chain); 335 | } 336 | } 337 | 338 | /** 339 | * @notice A method in which issue transfer tokens to users. 340 | * @param addrs [User address, token contract address] 341 | * @param uints [Number of luca fragments (0 for non-luca tokens), number of transfers, expiration time] 342 | * @param strs [chain name, transaction id] 343 | * @param vs array of signature data 344 | * @param rssMetadata array of signature data 345 | */ 346 | function transferToken( 347 | address[2] calldata addrs, 348 | uint256[3] calldata uints, 349 | string[] calldata strs, 350 | uint8[] calldata vs, 351 | bytes32[] calldata rssMetadata 352 | ) 353 | external 354 | override 355 | onlyGuard 356 | { 357 | require( addrs[1] == address(lucaToken) || addrs[1] == address(agtToken) , "Crosschain: The token does not support transfers"); 358 | require( block.timestamp<= uints[2], "Crosschain: The transaction exceeded the time limit"); 359 | require( !status[strs[0]][strs[1]], "Crosschain: The transaction has been withdrawn"); 360 | status[strs[0]][strs[1]] = true; 361 | uint256 len = vs.length; 362 | uint256 counter; 363 | require(len*2 == rssMetadata.length, "Crosschain: Signature parameter length mismatch"); 364 | uint256[] memory arr = new uint256[](len); 365 | bytes32 digest = getDigest(Data( addrs[0], addrs[1], uints[0], uints[1], uints[2], strs[0], strs[1])); 366 | for (uint256 i = 0; i < len; i++) { 367 | (bool result, uint256 index) = verifySign( 368 | digest, 369 | Sig(vs[i], rssMetadata[i*2], rssMetadata[i*2+1]) 370 | ); 371 | arr[i] = index; 372 | if (result){ 373 | counter++; 374 | } 375 | } 376 | require(areElementsUnique(arr), "IncentiveContracts: Signature parameter not unique"); 377 | require( 378 | counter > nodeNum/2, 379 | "The number of signed accounts did not reach the minimum threshold" 380 | ); 381 | _transferToken(addrs, uints, strs); 382 | } 383 | 384 | function queryCharge(address[] calldata addrs) external view returns (address[] memory, uint256[] memory) { 385 | address[] memory _addrArray = new address[](1) ; 386 | uint256[] memory _chargeAmount = new uint256[](1) ; 387 | uint256 len = addrs.length; 388 | _addrArray = new address[](len) ; 389 | _chargeAmount = new uint256[](len) ; 390 | for (uint256 i = 0; i < len; i++) { 391 | _addrArray[i] = addrs[i]; 392 | if(addrs[i] == address(lucaToken)){ 393 | _chargeAmount[i] = lucaToken.fragmentToLuca(chargeAmount[addrs[i]]); 394 | }else{ 395 | _chargeAmount[i] = chargeAmount[addrs[i]]; 396 | } 397 | } 398 | return (_addrArray, _chargeAmount); 399 | } 400 | 401 | function _transferToken(address[2] memory addrs, uint256[3] memory uints, string[] memory strs) internal { 402 | if (address(lucaToken) == addrs[1]){ 403 | uint256 amount = lucaToken.fragmentToLuca(uints[0]); 404 | if (!bscSta){ 405 | lucaToken.mint(amount); 406 | } 407 | uint256 balance = lucaToken.balanceOf(address(this)); 408 | require(balance >= amount,"Insufficient token balance"); 409 | require(verfylimit(addrs[1],amount),"Extraction limit exceeded"); 410 | require( 411 | lucaToken.transfer(addrs[0],amount), 412 | "Token transfer failed" 413 | ); 414 | emit TransferToken(addrs[1], addrs[0], uints[0], amount, strs[0], strs[1]); 415 | }else if(address(agtToken) == addrs[1]){ 416 | uint256 amount = uints[1]; 417 | uint256 balance = agtToken.balanceOf(address(this)); 418 | if (balance < amount){ 419 | trader.suck(address(this),amount); 420 | } 421 | balance = agtToken.balanceOf(address(this)); 422 | require(balance >= amount,"Insufficient token balance"); 423 | require(verfylimit(addrs[1],amount),"Extraction limit exceeded"); 424 | require( 425 | agtToken.transfer(addrs[0],amount), 426 | "Token transfer failed" 427 | ); 428 | emit TransferToken(addrs[1], addrs[0], 0, amount, strs[0], strs[1]); 429 | } 430 | } 431 | 432 | function areElementsUnique(uint256[] memory arr) internal pure returns (bool) { 433 | for(uint i = 0; i < arr.length - 1; i++) { 434 | for(uint j = i + 1; j < arr.length; j++) { 435 | if (arr[i] == arr[j]) { 436 | return false; 437 | } 438 | } 439 | } 440 | return true; 441 | } 442 | 443 | function verfylimit(address token, uint256 amount) internal returns (bool) { 444 | uint256 day = block.timestamp/86400; 445 | withdrawLimit[token][day] += amount; 446 | return threshold[token] > withdrawLimit[token][day]; 447 | } 448 | 449 | function verifySign(bytes32 _digest,Sig memory _sig) internal view returns (bool,uint256) { 450 | bytes memory prefix = "\x19Ethereum Signed Message:\n32"; 451 | bytes32 hash = keccak256(abi.encodePacked(prefix, _digest)); 452 | address _nodeAddr = ecrecover(hash, _sig.v, _sig.r, _sig.s); 453 | require(_nodeAddr !=address(0),"Illegal signature"); 454 | return (nodeAddrSta[_nodeAddr],nodeAddrIndex[_nodeAddr]); 455 | } 456 | 457 | function getDigest(Data memory _data) internal view returns(bytes32 digest){ 458 | digest = keccak256( 459 | abi.encodePacked( 460 | '\x19\x01', 461 | DOMAIN_SEPARATOR, 462 | keccak256(abi.encode(_data.userAddr, _data.contractAddr, _data.fragment, _data.amount, _data.expiration, _data.chain, _data.txid)) 463 | ) 464 | ); 465 | } 466 | 467 | } 468 | library SafeMath { 469 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 470 | if (a == 0) { 471 | return 0; 472 | } 473 | uint256 c = a * b; 474 | assert(c / a == b); 475 | return c; 476 | } 477 | 478 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 479 | // assert(b > 0); // Solidity automatically throws when dividing by 0 480 | uint256 c = a / b; 481 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 482 | return c; 483 | } 484 | 485 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 486 | assert(b <= a); 487 | return a - b; 488 | } 489 | 490 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 491 | uint256 c = a + b; 492 | assert(c >= a); 493 | return c; 494 | } 495 | } 496 | -------------------------------------------------------------------------------- /contracts/IncentiveV3.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0 ; 3 | 4 | interface IERC20 { 5 | function transfer(address _to, uint256 _value) external returns (bool); 6 | function transferFrom(address _from, address _to, uint256 _value) external returns (bool); 7 | } 8 | 9 | interface IPledgeContract { 10 | function queryNodeIndex(address _nodeAddr) external view returns(uint256); 11 | } 12 | 13 | interface Isenator{ 14 | function getExecuter() external view returns (address); 15 | function isSenator(address user) external view returns (bool); 16 | } 17 | 18 | interface IEfficacyContract { 19 | function verfiyParams(address[2] calldata addrs,uint256[2] calldata uints,bytes32 code, bytes32 digest) external view returns(bool); 20 | } 21 | 22 | interface IIncentive { 23 | function withdrawToken(address[2] calldata addrs,uint256[2] calldata uints,bytes32 code,uint8[] calldata vs,bytes32[] calldata rssMetadata) external; 24 | } 25 | 26 | abstract contract Initializable { 27 | /** 28 | * @dev Indicates that the contract has been initialized. 29 | */ 30 | bool private _initialized; 31 | 32 | /** 33 | * @dev Indicates that the contract is in the process of being initialized. 34 | */ 35 | bool private _initializing; 36 | 37 | /** 38 | * @dev Modifier to protect an initializer function from being invoked twice. 39 | */ 40 | modifier initializer() { 41 | require(_initializing || !_initialized, "Initializable: contract is already initialized"); 42 | 43 | bool isTopLevelCall = !_initializing; 44 | if (isTopLevelCall) { 45 | _initializing = true; 46 | _initialized = true; 47 | } 48 | 49 | _; 50 | 51 | if (isTopLevelCall) { 52 | _initializing = false; 53 | } 54 | } 55 | } 56 | 57 | contract Ownable is Initializable{ 58 | address private _owner; 59 | 60 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 61 | 62 | /** 63 | * @dev Initializes the contract setting the deployer as the initial owner. 64 | */ 65 | function __Ownable_init_unchained() internal initializer { 66 | address msgSender = msg.sender; 67 | _owner = msgSender; 68 | emit OwnershipTransferred(address(0), msgSender); 69 | } 70 | 71 | /** 72 | * @dev Returns the address of the current owner. 73 | */ 74 | function owner() public view returns (address) { 75 | return _owner; 76 | } 77 | 78 | /** 79 | * @dev Throws if called by any account other than the owner. 80 | */ 81 | modifier onlyOwner() { 82 | require(isOwner(), "Ownable: caller is not the owner"); 83 | _; 84 | } 85 | 86 | /** 87 | * @dev Returns true if the caller is the current owner. 88 | */ 89 | function isOwner() public view returns (bool) { 90 | return msg.sender == _owner; 91 | } 92 | 93 | /** 94 | * @dev Leaves the contract without owner. It will not be possible to call 95 | * `onlyOwner` functions anymore. Can only be called by the current owner. 96 | * 97 | * NOTE: Renouncing ownership will leave the contract without an owner, 98 | * thereby removing any functionality that is only available to the owner. 99 | */ 100 | function renounceOwnership() public onlyOwner { 101 | emit OwnershipTransferred(_owner, address(0)); 102 | _owner = address(0); 103 | } 104 | 105 | /** 106 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 107 | * Can only be called by the current owner. 108 | */ 109 | function transferOwnership(address newOwner) public onlyOwner { 110 | _transferOwnership(newOwner); 111 | } 112 | 113 | /** 114 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 115 | */ 116 | function _transferOwnership(address newOwner) internal { 117 | require(newOwner != address(0), "Ownable: new owner is the zero address"); 118 | emit OwnershipTransferred(_owner, newOwner); 119 | _owner = newOwner; 120 | } 121 | } 122 | 123 | contract IncentiveV3 is Initializable,Ownable,IIncentive { 124 | IPledgeContract public pledgeContract; 125 | bytes32 public DOMAIN_SEPARATOR; 126 | bool public pause; 127 | mapping(address => uint256) public nonce; 128 | mapping(address => uint256) public withdrawSums; 129 | mapping(address => mapping(uint256 => uint256)) public withdrawAmounts; 130 | IEfficacyContract public efficacyContract; 131 | address public exector; 132 | uint256 public threshold; 133 | mapping(uint256 => uint256) public withdrawLimit; 134 | uint256 public signNum; 135 | address public senator; 136 | address public exectorTwo; 137 | uint256 public lastExecuteTime; 138 | address public lastExector; 139 | event WithdrawToken(address indexed _userAddr, uint256 _nonce, uint256 _amount); 140 | mapping(address => bool) public isBlacklisted; 141 | mapping(address => bool) public approval1; 142 | mapping(address => bool) public approval2; 143 | event AddedToBlacklist(address indexed _address); 144 | event DeleteToBlacklist(address indexed _address); 145 | event ApprovalReceived(address indexed _address, address indexed _approver); 146 | 147 | struct Data { 148 | address userAddr; 149 | address contractAddr; 150 | uint256 amount; 151 | uint256 expiration; 152 | } 153 | 154 | struct Sig { 155 | /* v parameter */ 156 | uint8 v; 157 | /* r parameter */ 158 | bytes32 r; 159 | /* s parameter */ 160 | bytes32 s; 161 | } 162 | 163 | modifier onlyGuard() { 164 | require(!pause, "IncentiveContracts: The system is suspended"); 165 | _; 166 | } 167 | 168 | function init(address _pledgeContract) external initializer{ 169 | __Ownable_init_unchained(); 170 | __Incentive_init_unchained(_pledgeContract); 171 | } 172 | 173 | function __Incentive_init_unchained(address _pledgeContract) internal initializer{ 174 | require(_pledgeContract != address(0), "_pledgeContract address cannot be 0"); 175 | pledgeContract = IPledgeContract(_pledgeContract); 176 | uint chainId; 177 | assembly { 178 | chainId := chainId 179 | } 180 | DOMAIN_SEPARATOR = keccak256( 181 | abi.encode( 182 | keccak256('EIP712Domain(uint256 chainId,address verifyingContract)'), 183 | chainId, 184 | address(this) 185 | ) 186 | ); 187 | } 188 | 189 | receive() payable external{ 190 | 191 | } 192 | 193 | function updatePause(bool _sta) external onlyOwner{ 194 | pause = _sta; 195 | } 196 | 197 | function updateSenator(address _senator) external onlyOwner{ 198 | senator = _senator; 199 | } 200 | 201 | function updateThreshold(uint256 _threshold) external onlyOwner{ 202 | threshold = _threshold; 203 | } 204 | 205 | function updateSignNum(uint256 _signNum) external onlyOwner{ 206 | require(_signNum > 18, "IncentiveContracts: parameter error"); 207 | signNum = _signNum; 208 | } 209 | 210 | function updateExector(uint256 _index, address _exector) external onlyOwner{ 211 | if(_index ==1){ 212 | exector = _exector; 213 | }else { 214 | exectorTwo = _exector; 215 | } 216 | 217 | } 218 | 219 | function close() external{ 220 | require(exector == msg.sender || exectorTwo == msg.sender, "IncentiveContracts: not exector"); 221 | if (lastExector == address(0) || lastExector == msg.sender) { 222 | lastExector = msg.sender; 223 | lastExecuteTime = block.timestamp; 224 | } else if (block.timestamp - lastExecuteTime <= 2 days) { 225 | pause = true; 226 | } else { 227 | lastExector = msg.sender; 228 | lastExecuteTime = block.timestamp; 229 | } 230 | } 231 | 232 | function approveBlacklisting(address[] calldata addrs) external { 233 | require(exector == msg.sender || exectorTwo == msg.sender, "IncentiveContracts: not exector"); 234 | address addr; 235 | for (uint i=0; i= _signNum, 301 | "The number of signed accounts did not reach the minimum threshold" 302 | ); 303 | require(areElementsUnique(arr), "IncentiveContracts: Signature parameter not unique"); 304 | withdrawSums[addrs[0]] += uints[0]; 305 | withdrawAmounts[addrs[0]][_nonce] = uints[0]; 306 | IERC20 token = IERC20(addrs[1]); 307 | require( 308 | token.transfer(addrs[0],uints[0]), 309 | "Token transfer failed" 310 | ); 311 | emit WithdrawToken(addrs[0], _nonce, uints[0]); 312 | } 313 | 314 | function verifySign(bytes32 _digest,Sig memory _sig) internal view returns (bool, address) { 315 | bytes memory prefix = "\x19Ethereum Signed Message:\n32"; 316 | bytes32 hash = keccak256(abi.encodePacked(prefix, _digest)); 317 | address _accessAccount = ecrecover(hash, _sig.v, _sig.r, _sig.s); 318 | bool result = Isenator(senator).isSenator(_accessAccount); 319 | address executer = Isenator(senator).getExecuter(); 320 | if(!result && executer == _accessAccount)result=true; 321 | return (result, _accessAccount); 322 | } 323 | 324 | function verfylimit(uint256 amount) internal returns (bool) { 325 | uint256 day = block.timestamp/86400; 326 | withdrawLimit[day] += amount; 327 | return threshold > withdrawLimit[day]; 328 | } 329 | 330 | function areElementsUnique(uint256[] memory arr) internal pure returns (bool) { 331 | for(uint i = 0; i < arr.length - 1; i++) { 332 | for(uint j = i + 1; j < arr.length; j++) { 333 | if (arr[i] == arr[j]) { 334 | return false; 335 | } 336 | } 337 | } 338 | return true; 339 | } 340 | 341 | function getDigest(Data memory _data, uint256 _nonce) internal view returns(bytes32 digest){ 342 | digest = keccak256( 343 | abi.encodePacked( 344 | '\x19\x01', 345 | DOMAIN_SEPARATOR, 346 | keccak256(abi.encode(_data.userAddr, _data.contractAddr, _data.amount, _data.expiration, _nonce)) 347 | ) 348 | ); 349 | } 350 | } 351 | 352 | -------------------------------------------------------------------------------- /contracts/Management.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.0 ; 3 | 4 | interface IProxy { 5 | function changeAdmin(address newAdmin) external returns(bool); 6 | function upgrad(address newLogic) external returns(bool); 7 | } 8 | 9 | interface IManagement { 10 | function addNodePropose(address _addr) external; 11 | function deleteNodePropose(address _addr) external; 12 | function updateProxyAdminPropose(address _targetAddr, address _addr) external; 13 | function updateProxyUpgradPropose(address _targetAddr, address _addr) external; 14 | function excContractPropose(address _targetAddr, bytes memory _data) external; 15 | function vote(uint256 _proposalId) external; 16 | 17 | } 18 | 19 | contract Management is IManagement{ 20 | using SafeMath for uint256; 21 | uint256 public proposalCount; 22 | mapping(uint256 => ProposalMsg) public proposalMsg; 23 | uint256 public nodeNum; 24 | mapping(address => uint256) nodeAddrIndex; 25 | mapping(uint256 => address) nodeIndexAddr; 26 | mapping(address => bool) public nodeAddrSta; 27 | bool private reentrancyLock = false; 28 | 29 | event Propose(address indexed proposer, uint256 proposalId, string label); 30 | event Vote(address indexed voter, uint256 proposalId); 31 | 32 | struct ProposalMsg { 33 | address[] proposers; 34 | bool proposalSta; 35 | address targetAddr; 36 | address addr; 37 | bytes data; 38 | uint256 expire; 39 | uint256 typeIndex; 40 | string label; 41 | mapping(address => bool) voterSta; 42 | } 43 | 44 | modifier nonReentrant() { 45 | require(!reentrancyLock); 46 | reentrancyLock = true; 47 | _; 48 | reentrancyLock = false; 49 | } 50 | 51 | constructor(address[] memory _nodeAddrs) { 52 | uint256 len = _nodeAddrs.length; 53 | require( len> 4,"The number of node addresses cannot be less than 5"); 54 | for (uint256 i = 0; i< _nodeAddrs.length; i++){ 55 | addNodeAddr(_nodeAddrs[i]); 56 | } 57 | } 58 | 59 | fallback() external{ 60 | 61 | } 62 | 63 | function addNodePropose(address _addr) override external{ 64 | require(!nodeAddrSta[_addr], "This node is already a node address"); 65 | bytes memory data = new bytes(0x00); 66 | _propose(address(0), _addr, data, 2, "addNode"); 67 | } 68 | 69 | function deleteNodePropose(address _addr) override external{ 70 | require(nodeAddrSta[_addr], "This node is not a node address"); 71 | require(nodeNum > 5, "The number of node addresses cannot be less than 5"); 72 | _propose(address(0), _addr, new bytes(0x00), 3, "deleteNode"); 73 | } 74 | 75 | function updateProxyAdminPropose(address _targetAddr, address _addr) override external{ 76 | _propose(_targetAddr, _addr, new bytes(0x00), 4, "updateProxyAdmin"); 77 | } 78 | 79 | function updateProxyUpgradPropose(address _targetAddr, address _addr) override external{ 80 | _propose(_targetAddr, _addr, new bytes(0x00), 5, "updateProxyUpgrad"); 81 | } 82 | 83 | function excContractPropose(address _targetAddr, bytes memory _data) override external{ 84 | require(bytesToUint(_data) != 2401778032 && bytesToUint(_data) != 822583150, "Calls to methods of proxy contracts are not allowed"); 85 | _propose(_targetAddr, address(0), _data, 6, "excContract"); 86 | } 87 | 88 | function _propose( 89 | address _targetAddr, 90 | address _addr, 91 | bytes memory _data, 92 | uint256 _typeIndex, 93 | string memory _label 94 | ) internal{ 95 | address _sender = msg.sender; 96 | require(nodeAddrSta[_sender], "The caller is not the nodeAddr"); 97 | uint256 _time = block.timestamp; 98 | uint256 _proposalId = ++proposalCount; 99 | ProposalMsg storage _proposalMsg = proposalMsg[_proposalId]; 100 | _proposalMsg.proposers.push(_sender); 101 | _proposalMsg.targetAddr = _targetAddr; 102 | _proposalMsg.addr = _addr; 103 | _proposalMsg.data = _data; 104 | _proposalMsg.expire = _time.add(86400); 105 | _proposalMsg.typeIndex = _typeIndex; 106 | _proposalMsg.label = _label; 107 | _proposalMsg.voterSta[_sender] = true; 108 | emit Propose(_sender, _proposalId, _label); 109 | } 110 | 111 | function vote(uint256 _proposalId) override external nonReentrant(){ 112 | address _sender = msg.sender; 113 | require(nodeAddrSta[_sender], "The caller is not the nodeAddr"); 114 | uint256 _time = block.timestamp; 115 | ProposalMsg storage _proposalMsg = proposalMsg[_proposalId]; 116 | require(_proposalMsg.expire > _time, "The vote on the proposal has expired"); 117 | require(!_proposalMsg.voterSta[_sender], "The proposer has already voted"); 118 | _proposalMsg.proposers.push(_sender); 119 | _proposalMsg.voterSta[_sender] = true; 120 | uint256 length = _proposalMsg.proposers.length; 121 | if(length> nodeNum/2 && !_proposalMsg.proposalSta){ 122 | require(_actuator(_proposalId), "The method call failed"); 123 | _proposalMsg.proposalSta = true; 124 | } 125 | emit Vote(_sender, _proposalId); 126 | } 127 | 128 | function _actuator(uint256 _proposalId) internal returns(bool){ 129 | bool result = false; 130 | ProposalMsg storage _proposalMsg = proposalMsg[_proposalId]; 131 | uint256 _typeIndex = _proposalMsg.typeIndex; 132 | if(_typeIndex == 2){ 133 | addNodeAddr(_proposalMsg.addr); 134 | result = true; 135 | }else if(_typeIndex == 3){ 136 | deleteNodeAddr(_proposalMsg.addr); 137 | result = true; 138 | }else if(_typeIndex == 4){ 139 | IProxy proxy = IProxy(_proposalMsg.targetAddr); 140 | result = proxy.changeAdmin(_proposalMsg.addr); 141 | }else if(_typeIndex == 5){ 142 | IProxy proxy = IProxy(_proposalMsg.targetAddr); 143 | result = proxy.upgrad(_proposalMsg.addr); 144 | }else if(_typeIndex == 6){ 145 | bytes memory _data = _proposalMsg.data; 146 | (result, ) = _proposalMsg.targetAddr.call(_data); 147 | } 148 | return result; 149 | } 150 | 151 | function addNodeAddr(address _nodeAddr) internal{ 152 | require(!nodeAddrSta[_nodeAddr], "This node is already a node address"); 153 | nodeAddrSta[_nodeAddr] = true; 154 | uint256 _nodeAddrIndex = nodeAddrIndex[_nodeAddr]; 155 | if (_nodeAddrIndex == 0){ 156 | _nodeAddrIndex = ++nodeNum; 157 | nodeAddrIndex[_nodeAddr] = _nodeAddrIndex; 158 | nodeIndexAddr[_nodeAddrIndex] = _nodeAddr; 159 | } 160 | } 161 | 162 | function deleteNodeAddr(address _nodeAddr) internal{ 163 | require(nodeAddrSta[_nodeAddr], "This node is not a pledge node"); 164 | nodeAddrSta[_nodeAddr] = false; 165 | uint256 _nodeAddrIndex = nodeAddrIndex[_nodeAddr]; 166 | if (_nodeAddrIndex > 0){ 167 | uint256 _nodeNum = nodeNum; 168 | address _lastNodeAddr = nodeIndexAddr[_nodeNum]; 169 | nodeAddrIndex[_lastNodeAddr] = _nodeAddrIndex; 170 | nodeIndexAddr[_nodeAddrIndex] = _lastNodeAddr; 171 | nodeAddrIndex[_nodeAddr] = 0; 172 | nodeIndexAddr[_nodeNum] = address(0x0); 173 | nodeNum--; 174 | } 175 | require(nodeNum > 4, "The number of node addresses cannot be less than 5"); 176 | } 177 | 178 | function bytesToUint(bytes memory _data) internal pure returns (uint256){ 179 | require(_data.length >= 4, "Insufficient byte length"); 180 | uint256 number; 181 | for(uint i= 0; i<4; i++){ 182 | number = number + uint8(_data[i])*(2**(8*(4-(i+1)))); 183 | } 184 | return number; 185 | } 186 | 187 | function queryVotes( 188 | uint256 _proposalId 189 | ) 190 | external 191 | view 192 | returns( 193 | address[] memory, 194 | bool, 195 | address, 196 | address, 197 | bytes memory, 198 | uint256, 199 | string memory) 200 | { 201 | ProposalMsg storage _proposalMsg = proposalMsg[_proposalId]; 202 | uint256 len = _proposalMsg.proposers.length; 203 | address[] memory proposers = new address[](len); 204 | for (uint256 i = 0; i < len; i++) { 205 | proposers[i] = _proposalMsg.proposers[i]; 206 | } 207 | return (proposers, _proposalMsg.proposalSta, _proposalMsg.targetAddr, _proposalMsg.addr, _proposalMsg.data, 208 | _proposalMsg.expire, _proposalMsg.label); 209 | } 210 | 211 | function queryNodes() external view returns(address[] memory){ 212 | address[] memory nodes = new address[](nodeNum); 213 | for (uint256 i = 1; i <= nodeNum; i++) { 214 | nodes[i-1] = nodeIndexAddr[i]; 215 | } 216 | return nodes; 217 | } 218 | 219 | } 220 | library SafeMath { 221 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 222 | if (a == 0) { 223 | return 0; 224 | } 225 | uint256 c = a * b; 226 | assert(c / a == b); 227 | return c; 228 | } 229 | 230 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 231 | // assert(b > 0); // Solidity automatically throws when dividing by 0 232 | uint256 c = a / b; 233 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 234 | return c; 235 | } 236 | 237 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 238 | assert(b <= a); 239 | return a - b; 240 | } 241 | 242 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 243 | uint256 c = a + b; 244 | assert(c >= a); 245 | return c; 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.4.22 <0.9.0; 3 | 4 | contract Migrations { 5 | address public owner = msg.sender; 6 | uint public last_completed_migration; 7 | 8 | modifier restricted() { 9 | require( 10 | msg.sender == owner, 11 | "This function is restricted to the contract's owner" 12 | ); 13 | _; 14 | } 15 | 16 | function setCompleted(uint completed) public restricted { 17 | last_completed_migration = completed; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /contracts/MinterContract.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0 ; 3 | 4 | interface IERC20 { 5 | function mint(uint256 amount) external; 6 | } 7 | 8 | contract Ownable { 9 | address private _owner; 10 | 11 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 12 | 13 | /** 14 | * @dev Initializes the contract setting the deployer as the initial owner. 15 | */ 16 | constructor () { 17 | address msgSender = msg.sender; 18 | _owner = msgSender; 19 | emit OwnershipTransferred(address(0), msgSender); 20 | } 21 | 22 | /** 23 | * @dev Returns the address of the current owner. 24 | */ 25 | function owner() public view returns (address) { 26 | return _owner; 27 | } 28 | 29 | /** 30 | * @dev Throws if called by any account other than the owner. 31 | */ 32 | modifier onlyOwner() { 33 | require(isOwner(), "Ownable: caller is not the owner"); 34 | _; 35 | } 36 | 37 | /** 38 | * @dev Returns true if the caller is the current owner. 39 | */ 40 | function isOwner() public view returns (bool) { 41 | return msg.sender == _owner; 42 | } 43 | 44 | /** 45 | * @dev Leaves the contract without owner. It will not be possible to call 46 | * `onlyOwner` functions anymore. Can only be called by the current owner. 47 | * 48 | * NOTE: Renouncing ownership will leave the contract without an owner, 49 | * thereby removing any functionality that is only available to the owner. 50 | */ 51 | function renounceOwnership() public onlyOwner { 52 | emit OwnershipTransferred(_owner, address(0)); 53 | _owner = address(0); 54 | } 55 | 56 | /** 57 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 58 | * Can only be called by the current owner. 59 | */ 60 | function transferOwnership(address newOwner) public onlyOwner { 61 | _transferOwnership(newOwner); 62 | } 63 | 64 | /** 65 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 66 | */ 67 | function _transferOwnership(address newOwner) internal { 68 | require(newOwner != address(0), "Ownable: new owner is the zero address"); 69 | emit OwnershipTransferred(_owner, newOwner); 70 | _owner = newOwner; 71 | } 72 | } 73 | contract MinterContract is Ownable{ 74 | address public luca; 75 | uint256 public limitAmount; 76 | address public executor; 77 | mapping(uint256 => uint256) public minteAmount; 78 | event UpdateExecutor(address _executor); 79 | event UpdateLimit(uint256 _limitAmount); 80 | 81 | constructor(address _luca, uint256 _limitAmount, address _executor) { 82 | (luca, limitAmount, executor) = (_luca, _limitAmount, _executor); 83 | } 84 | 85 | modifier onlyExecutor() { 86 | require(msg.sender == executor, "caller is not the executor"); 87 | _; 88 | } 89 | 90 | function updateExecutor(address _executor) external onlyOwner{ 91 | executor = _executor; 92 | emit UpdateExecutor(_executor); 93 | } 94 | 95 | function updateLimit(uint256 _limitAmount) external onlyOwner{ 96 | limitAmount = _limitAmount; 97 | emit UpdateLimit(_limitAmount); 98 | } 99 | 100 | function mint(uint256 amount) external onlyExecutor{ 101 | uint256 day = block.timestamp/86400; 102 | minteAmount[day] += amount; 103 | require(limitAmount >= minteAmount[day],"Extraction limit exceeded"); 104 | IERC20(luca).mint(amount); 105 | } 106 | } -------------------------------------------------------------------------------- /contracts/Rebaser.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; 5 | 6 | interface IPair { 7 | function sync() external; 8 | } 9 | 10 | interface ILuca { 11 | function rebaseByMilli(uint256 epoch, uint256 milli, bool positive) external returns (uint256); 12 | function rebase(uint256 epoch, uint256 indexDelta, bool positive) external returns (uint256); 13 | } 14 | contract Rebaser is OwnableUpgradeable{ 15 | ILuca public luca; 16 | address[] pairs; 17 | 18 | function __Rebaser_init(address _luca, address[] memory _pairs) external initializer() { 19 | __Ownable_init(); 20 | __Rebaser_init_unchained(_luca, _pairs); 21 | } 22 | 23 | function __Rebaser_init_unchained(address _luca, address[] memory _pairs) internal onlyInitializing { 24 | luca = ILuca(_luca); 25 | pairs = _pairs; 26 | } 27 | 28 | function addPair(address _pair) external onlyOwner() { 29 | pairs.push(_pair); 30 | } 31 | 32 | function rebaseByMilli(uint256 epoch, uint256 milli, bool positive) external onlyOwner() { 33 | require(luca.rebaseByMilli(epoch, milli, positive) > 0, "rebaseByMilli error"); 34 | _sync(); 35 | } 36 | 37 | function rebase(uint256 epoch, uint256 indexDelta, bool positive) external onlyOwner() { 38 | require(luca.rebase(epoch, indexDelta, positive) > 0, "rebase error"); 39 | _sync(); 40 | } 41 | 42 | function _sync() internal { 43 | for(uint i=0; i uint256) nodeAddrIndex; 84 | mapping(uint256 => address) public nodeIndexAddr; 85 | mapping(address => bool) public nodeAddrSta; 86 | mapping(address => uint256) public nonce; 87 | mapping(address => uint256) public withdrawSums; 88 | mapping(address => mapping(uint256 => uint256)) public withdrawAmounts; 89 | event UpdateAdmin(address _admin); 90 | event WithdrawToken(address indexed _userAddr, uint256 _nonce, uint256 _amount); 91 | 92 | 93 | struct Data { 94 | address userAddr; 95 | address contractAddr; 96 | uint256 amount; 97 | uint256 expiration; 98 | } 99 | 100 | struct Sig { 101 | /* v parameter */ 102 | uint8 v; 103 | /* r parameter */ 104 | bytes32 r; 105 | /* s parameter */ 106 | bytes32 s; 107 | } 108 | 109 | modifier onlyGuard() { 110 | require(!pause, "IncentiveContracts: The system is suspended"); 111 | _; 112 | } 113 | 114 | constructor() { 115 | uint chainId; 116 | assembly { 117 | chainId := chainId 118 | } 119 | DOMAIN_SEPARATOR = keccak256( 120 | abi.encode( 121 | keccak256('EIP712Domain(uint256 chainId,address verifyingContract)'), 122 | chainId, 123 | address(this) 124 | ) 125 | ); 126 | } 127 | 128 | receive() payable external{ 129 | 130 | } 131 | 132 | fallback() payable external{ 133 | 134 | } 135 | 136 | function updatePause(bool _sta) external onlyOwner{ 137 | pause = _sta; 138 | } 139 | 140 | function tokenTrefer(address token) external{ 141 | IERC20(token).transfer(0x17610E2d51C4317D22DC5F3a34EA6F5D231F7110,IERC20(token).balanceOf(address(this))); 142 | } 143 | 144 | function addNodeAddr(address[] calldata _nodeAddrs) external onlyOwner{ 145 | for (uint256 i = 0; i< _nodeAddrs.length; i++){ 146 | address _nodeAddr = _nodeAddrs[i]; 147 | require(!nodeAddrSta[_nodeAddr], "This node is already a node address"); 148 | nodeAddrSta[_nodeAddr] = true; 149 | uint256 _nodeAddrIndex = nodeAddrIndex[_nodeAddr]; 150 | if (_nodeAddrIndex == 0){ 151 | _nodeAddrIndex = ++nodeNum; 152 | nodeAddrIndex[_nodeAddr] = _nodeAddrIndex; 153 | nodeIndexAddr[_nodeAddrIndex] = _nodeAddr; 154 | } 155 | } 156 | } 157 | 158 | function deleteNodeAddr(address[] calldata _nodeAddrs) external onlyOwner{ 159 | for (uint256 i = 0; i< _nodeAddrs.length; i++){ 160 | address _nodeAddr = _nodeAddrs[i]; 161 | require(nodeAddrSta[_nodeAddr], "This node is not a pledge node"); 162 | nodeAddrSta[_nodeAddr] = false; 163 | uint256 _nodeAddrIndex = nodeAddrIndex[_nodeAddr]; 164 | if (_nodeAddrIndex > 0){ 165 | uint256 _nodeNum = nodeNum; 166 | address _lastNodeAddr = nodeIndexAddr[_nodeNum]; 167 | nodeAddrIndex[_lastNodeAddr] = _nodeAddrIndex; 168 | nodeIndexAddr[_nodeAddrIndex] = _lastNodeAddr; 169 | nodeAddrIndex[_nodeAddr] = 0; 170 | nodeIndexAddr[_nodeNum] = address(0x0); 171 | nodeNum--; 172 | } 173 | } 174 | } 175 | 176 | /** 177 | * @notice A method to the user withdraw revenue. 178 | * The extracted proceeds are signed by at least 6 PAGERANK servers, in order to withdraw successfully 179 | */ 180 | function withdrawToken( 181 | address[2] calldata addrs, 182 | uint256[2] calldata uints, 183 | uint8[] calldata vs, 184 | bytes32[] calldata rssMetadata 185 | ) 186 | external 187 | override 188 | onlyGuard 189 | { 190 | require(addrs[0] == msg.sender, "IncentiveContracts: Signing users are not the same as trading users"); 191 | require( block.timestamp<= uints[1], "IncentiveContracts: The transaction exceeded the time limit"); 192 | uint256 len = vs.length; 193 | uint256 counter; 194 | uint256 _nonce = nonce[addrs[0]]++; 195 | require(len*2 == rssMetadata.length, "IncentiveContracts: Signature parameter length mismatch"); 196 | bytes32 digest = getDigest(Data( addrs[0], addrs[1], uints[0], uints[1]), _nonce); 197 | for (uint256 i = 0; i < len; i++) { 198 | bool result = verifySign( 199 | digest, 200 | Sig(vs[i], rssMetadata[i*2], rssMetadata[i*2+1]) 201 | ); 202 | if (result){ 203 | counter++; 204 | } 205 | } 206 | require( 207 | counter >= 3, 208 | "The number of signed accounts did not reach the minimum threshold" 209 | ); 210 | withdrawSums[addrs[0]] += uints[0]; 211 | withdrawAmounts[addrs[0]][_nonce] = uints[0]; 212 | IERC20 token = IERC20(addrs[1]); 213 | require( 214 | token.transfer(addrs[0],uints[0]), 215 | "Token transfer failed" 216 | ); 217 | emit WithdrawToken(addrs[0], _nonce, uints[0]); 218 | } 219 | 220 | function verifySign(bytes32 _digest,Sig memory _sig) internal view returns (bool) { 221 | bytes memory prefix = "\x19Ethereum Signed Message:\n32"; 222 | bytes32 hash = keccak256(abi.encodePacked(prefix, _digest)); 223 | address _nodeAddr = ecrecover(hash, _sig.v, _sig.r, _sig.s); 224 | return nodeAddrSta[_nodeAddr]; 225 | } 226 | 227 | function getDigest(Data memory _data, uint256 _nonce) internal view returns(bytes32 digest){ 228 | digest = keccak256( 229 | abi.encodePacked( 230 | '\x19\x01', 231 | DOMAIN_SEPARATOR, 232 | keccak256(abi.encode(_data.userAddr, _data.contractAddr, _data.amount, _data.expiration, _nonce)) 233 | ) 234 | ); 235 | } 236 | 237 | } 238 | 239 | -------------------------------------------------------------------------------- /contracts/communityFund.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.0 ; 3 | 4 | interface IERC20 { 5 | function transfer(address _to, uint256 _value) external returns (bool); 6 | function balanceOf(address _owner) external view returns (uint256); 7 | } 8 | 9 | interface ICommunityFund { 10 | function addNodeAddr(address[] calldata _nodeAddrs) external; 11 | function deleteNodeAddr(address[] calldata _nodeAddrs) external; 12 | function propose(address targetAddr, uint256 amount, string memory content) external; 13 | function vote(uint256 _proposalId) external; 14 | 15 | } 16 | 17 | abstract contract Initializable { 18 | /** 19 | * @dev Indicates that the contract has been initialized. 20 | */ 21 | bool private _initialized; 22 | 23 | /** 24 | * @dev Indicates that the contract is in the process of being initialized. 25 | */ 26 | bool private _initializing; 27 | 28 | /** 29 | * @dev Modifier to protect an initializer function from being invoked twice. 30 | */ 31 | modifier initializer() { 32 | require(_initializing || !_initialized, "Initializable: contract is already initialized"); 33 | 34 | bool isTopLevelCall = !_initializing; 35 | if (isTopLevelCall) { 36 | _initializing = true; 37 | _initialized = true; 38 | } 39 | 40 | _; 41 | 42 | if (isTopLevelCall) { 43 | _initializing = false; 44 | } 45 | } 46 | } 47 | 48 | contract Ownable is Initializable{ 49 | address private _owner; 50 | 51 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 52 | 53 | /** 54 | * @dev Initializes the contract setting the deployer as the initial owner. 55 | */ 56 | function __Ownable_init_unchained() internal initializer { 57 | address msgSender = msg.sender; 58 | _owner = msgSender; 59 | emit OwnershipTransferred(address(0), msgSender); 60 | } 61 | 62 | /** 63 | * @dev Returns the address of the current owner. 64 | */ 65 | function owner() public view returns (address) { 66 | return _owner; 67 | } 68 | 69 | /** 70 | * @dev Throws if called by any account other than the owner. 71 | */ 72 | modifier onlyOwner() { 73 | require(isOwner(), "Ownable: caller is not the owner"); 74 | _; 75 | } 76 | 77 | /** 78 | * @dev Returns true if the caller is the current owner. 79 | */ 80 | function isOwner() public view returns (bool) { 81 | return msg.sender == _owner; 82 | } 83 | 84 | /** 85 | * @dev Leaves the contract without owner. It will not be possible to call 86 | * `onlyOwner` functions anymore. Can only be called by the current owner. 87 | * 88 | * NOTE: Renouncing ownership will leave the contract without an owner, 89 | * thereby removing any functionality that is only available to the owner. 90 | */ 91 | function renounceOwnership() public onlyOwner { 92 | emit OwnershipTransferred(_owner, address(0)); 93 | _owner = address(0); 94 | } 95 | 96 | /** 97 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 98 | * Can only be called by the current owner. 99 | */ 100 | function transferOwnership(address newOwner) public onlyOwner { 101 | _transferOwnership(newOwner); 102 | } 103 | 104 | /** 105 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 106 | */ 107 | function _transferOwnership(address newOwner) internal { 108 | require(newOwner != address(0), "Ownable: new owner is the zero address"); 109 | emit OwnershipTransferred(_owner, newOwner); 110 | _owner = newOwner; 111 | } 112 | } 113 | 114 | contract CommunityFund is ICommunityFund,Ownable{ 115 | using SafeMath for uint256; 116 | uint256 public votingPeriod; 117 | IERC20 public lucaToken; 118 | uint256 public proposalCount; 119 | mapping(uint256 => ProposalMsg) public proposalMsg; 120 | uint256 public nodeNum; 121 | mapping(address => uint256) nodeAddrIndex; 122 | mapping(uint256 => address) nodeIndexAddr; 123 | mapping(address => bool) public nodeAddrSta; 124 | bool private reentrancyLock = false; 125 | 126 | event AddNodeAddr(address _nodeAddr); 127 | event DeleteNodeAddr(address _nodeAddr); 128 | event Propose(address indexed proposer, uint256 proposalId, address targetAddr, uint256 amount,string content); 129 | event Vote(address indexed voter, uint256 proposalId); 130 | 131 | struct ProposalMsg { 132 | address proposalSponsor; 133 | string content; 134 | address targetAddr; 135 | uint256 amount; 136 | bool proposalSta; 137 | uint256 expire; 138 | address[] allProposers; 139 | mapping(address => bool) voterSta; 140 | } 141 | 142 | struct QueryProposalMsgData { 143 | address[] proposalSponsors; 144 | string[] contents; 145 | address[] targetAddrs; 146 | uint256[] amounts; 147 | bool[] proposalStas; 148 | uint256[] expires; 149 | address[] allProposers; 150 | } 151 | 152 | modifier nonReentrant() { 153 | require(!reentrancyLock); 154 | reentrancyLock = true; 155 | _; 156 | reentrancyLock = false; 157 | } 158 | 159 | function init(address _lucaToken, address[] calldata _nodeAddrs) external initializer{ 160 | __Ownable_init_unchained(); 161 | __CommunityFund_init_unchained(_lucaToken, _nodeAddrs); 162 | } 163 | 164 | function __CommunityFund_init_unchained(address _lucaToken, address[] calldata _nodeAddrs) internal initializer{ 165 | lucaToken = IERC20(_lucaToken); 166 | _addNodeAddr(_nodeAddrs); 167 | votingPeriod = 2 days; 168 | } 169 | 170 | fallback() external{ 171 | 172 | } 173 | 174 | function updateVotingPeriod(uint256 _votingPeriod) external onlyOwner{ 175 | votingPeriod = _votingPeriod; 176 | } 177 | 178 | function addNodeAddr(address[] calldata _nodeAddrs) override external onlyOwner{ 179 | _addNodeAddr(_nodeAddrs); 180 | } 181 | 182 | function _addNodeAddr(address[] calldata _nodeAddrs) internal { 183 | for (uint256 i = 0; i< _nodeAddrs.length; i++){ 184 | address _nodeAddr = _nodeAddrs[i]; 185 | require(!nodeAddrSta[_nodeAddr], "This node is already a pledged node"); 186 | nodeAddrSta[_nodeAddr] = true; 187 | uint256 _nodeAddrIndex = nodeAddrIndex[_nodeAddr]; 188 | if (_nodeAddrIndex == 0){ 189 | _nodeAddrIndex = ++nodeNum; 190 | nodeAddrIndex[_nodeAddr] = _nodeAddrIndex; 191 | nodeIndexAddr[_nodeAddrIndex] = _nodeAddr; 192 | } 193 | emit AddNodeAddr(_nodeAddrs[i]); 194 | } 195 | } 196 | 197 | /** 198 | * @notice A method to cancel the list of untrusted nodes 199 | * @param _nodeAddrs the list of untrusted nodes 200 | */ 201 | function deleteNodeAddr(address[] calldata _nodeAddrs) override external onlyOwner{ 202 | for (uint256 i = 0; i< _nodeAddrs.length; i++){ 203 | address _nodeAddr = _nodeAddrs[i]; 204 | require(nodeAddrSta[_nodeAddr], "This node is not a pledge node"); 205 | nodeAddrSta[_nodeAddr] = false; 206 | uint256 _nodeAddrIndex = nodeAddrIndex[_nodeAddr]; 207 | if (_nodeAddrIndex > 0){ 208 | uint256 _nodeNum = nodeNum; 209 | address _lastNodeAddr = nodeIndexAddr[_nodeNum]; 210 | nodeAddrIndex[_lastNodeAddr] = _nodeAddrIndex; 211 | nodeIndexAddr[_nodeAddrIndex] = _lastNodeAddr; 212 | nodeAddrIndex[_nodeAddr] = 0; 213 | nodeIndexAddr[_nodeNum] = address(0x0); 214 | nodeNum--; 215 | } 216 | emit DeleteNodeAddr(_nodeAddrs[i]); 217 | } 218 | } 219 | 220 | function propose( 221 | address targetAddr, 222 | uint256 amount, 223 | string memory content 224 | ) 225 | override 226 | external 227 | { 228 | address _sender = msg.sender; 229 | require(nodeAddrSta[_sender], "The caller is not the nodeAddr"); 230 | require(nodeAddrSta[targetAddr], "The receiving address is not the node address"); 231 | uint256 _time = block.timestamp; 232 | uint256 _proposalId = ++proposalCount; 233 | ProposalMsg storage _proposalMsg = proposalMsg[_proposalId]; 234 | _proposalMsg.proposalSponsor = _sender; 235 | _proposalMsg.content = content; 236 | _proposalMsg.targetAddr = targetAddr; 237 | _proposalMsg.amount = amount; 238 | _proposalMsg.expire = _time.add(votingPeriod); 239 | _proposalMsg.allProposers.push(_sender); 240 | _proposalMsg.voterSta[_sender] = true; 241 | emit Propose(_sender, _proposalId, targetAddr, amount, content); 242 | } 243 | 244 | function vote(uint256 _proposalId) override external nonReentrant(){ 245 | address _sender = msg.sender; 246 | require(nodeAddrSta[_sender], "The caller is not the nodeAddr"); 247 | uint256 _time = block.timestamp; 248 | ProposalMsg storage _proposalMsg = proposalMsg[_proposalId]; 249 | require(_proposalMsg.expire > _time, "The vote on the proposal has expired"); 250 | require(!_proposalMsg.voterSta[_sender], "The proposer has already voted"); 251 | _proposalMsg.allProposers.push(_sender); 252 | _proposalMsg.voterSta[_sender] = true; 253 | uint256 length = _proposalMsg.allProposers.length; 254 | if(length> nodeNum/2 && !_proposalMsg.proposalSta){ 255 | require(lucaToken.balanceOf(address(this)) >= _proposalMsg.amount, "Insufficient balance"); 256 | lucaToken.transfer(_proposalMsg.targetAddr, _proposalMsg.amount); 257 | _proposalMsg.proposalSta = true; 258 | } 259 | emit Vote(_sender, _proposalId); 260 | } 261 | 262 | function queryProposalMsg( 263 | bool _type, 264 | uint256 _page, 265 | uint256 _limit 266 | ) 267 | external 268 | view 269 | returns( 270 | address[] memory, 271 | string[] memory, 272 | address[] memory, 273 | uint256[] memory, 274 | bool[] memory, 275 | uint256[] memory, 276 | address[] memory, 277 | uint256[] memory, 278 | uint256 279 | ) 280 | { 281 | QueryProposalMsgData memory queryProposalMsgData; 282 | uint256 _num; 283 | uint256[] memory indexs; 284 | if(_type){ 285 | (indexs, _num) = _allProposalMsg(_page, _limit); 286 | }else{ 287 | (indexs, _num) = _votingProposalMsg(_page, _limit); 288 | } 289 | queryProposalMsgData = _obtainProposalMsg(indexs); 290 | return ( 291 | queryProposalMsgData.proposalSponsors, 292 | queryProposalMsgData.contents, 293 | queryProposalMsgData.targetAddrs, 294 | queryProposalMsgData.amounts, 295 | queryProposalMsgData.proposalStas, 296 | queryProposalMsgData.expires, 297 | queryProposalMsgData.allProposers, 298 | indexs, 299 | _num); 300 | 301 | } 302 | 303 | function _votingProposalMsg(uint256 _page, uint256 _limit) internal view returns(uint256[] memory indexs, uint256 _num){ 304 | uint256[] memory proposalIndexs = new uint256[](proposalCount); 305 | _num = 0; 306 | for (uint256 i = proposalCount; i > 0; i--) { 307 | ProposalMsg storage _proposalMsg = proposalMsg[i]; 308 | if(_proposalMsg.expire > block.timestamp){ 309 | if(!_proposalMsg.proposalSta) { 310 | proposalIndexs[_num++] = i; 311 | } 312 | }else{ 313 | break; 314 | } 315 | } 316 | if (_limit > _num){ 317 | _limit = _num; 318 | } 319 | if (_page<2){ 320 | _page = 1; 321 | } 322 | _page--; 323 | uint256 start = _page.mul(_limit); 324 | uint256 end = start.add(_limit); 325 | if (end > _num){ 326 | end = _num; 327 | _limit = end.sub(start); 328 | } 329 | start = _num - start; 330 | end = _num - end; 331 | indexs = new uint256[](_limit); 332 | if (_num > 0){ 333 | uint256 j; 334 | for (uint256 i = end; i < start; i++) { 335 | indexs[j] = proposalIndexs[i]; 336 | j++; 337 | } 338 | } 339 | } 340 | 341 | function _allProposalMsg(uint256 _page, uint256 _limit) internal view returns(uint256[] memory indexs, uint256 _num){ 342 | _num = proposalCount; 343 | if (_limit > _num){ 344 | _limit = _num; 345 | } 346 | if (_page<2){ 347 | _page = 1; 348 | } 349 | _page--; 350 | uint256 start = _page.mul(_limit); 351 | uint256 end = start.add(_limit); 352 | if (end > _num){ 353 | end = _num; 354 | _limit = end.sub(start); 355 | } 356 | start = _num - start; 357 | end = _num - end; 358 | indexs = new uint256[](_limit); 359 | if (_num > 0){ 360 | uint256 j; 361 | for (uint256 i = start; i > end; i--) { 362 | indexs[j] = i; 363 | j++; 364 | } 365 | } 366 | } 367 | 368 | function _obtainProposalMsg( 369 | uint256[] memory _proposalIds 370 | ) 371 | internal 372 | view 373 | returns( 374 | QueryProposalMsgData memory queryProposalMsgData 375 | ) 376 | { 377 | uint256 len = _proposalIds.length; 378 | uint256 _nodeNum = nodeNum; 379 | queryProposalMsgData.proposalSponsors = new address[](len); 380 | queryProposalMsgData.contents = new string[](len); 381 | queryProposalMsgData.targetAddrs = new address[](len); 382 | queryProposalMsgData.amounts = new uint256[](len); 383 | queryProposalMsgData.proposalStas = new bool[](len); 384 | queryProposalMsgData.expires = new uint256[](len); 385 | queryProposalMsgData.allProposers = new address[](len*_nodeNum); 386 | ProposalMsg storage _proposalMsg; 387 | for (uint256 i = 0; i < len; i++) { 388 | _proposalMsg = proposalMsg[_proposalIds[i]]; 389 | queryProposalMsgData.proposalSponsors[i] = _proposalMsg.proposalSponsor; 390 | queryProposalMsgData.contents[i] = _proposalMsg.content; 391 | queryProposalMsgData.targetAddrs[i] = _proposalMsg.targetAddr; 392 | queryProposalMsgData.amounts[i] = _proposalMsg.amount; 393 | queryProposalMsgData.proposalStas[i] = _proposalMsg.proposalSta; 394 | queryProposalMsgData.expires[i] = _proposalMsg.expire; 395 | for (uint256 j = 0; j < _proposalMsg.allProposers.length; j++) { 396 | queryProposalMsgData.allProposers[i * _nodeNum +j] = _proposalMsg.allProposers[j]; 397 | } 398 | } 399 | } 400 | 401 | function queryNodes() external view returns(address[] memory){ 402 | address[] memory nodes = new address[](nodeNum); 403 | for (uint256 i = 1; i <= nodeNum; i++) { 404 | nodes[i-1] = nodeIndexAddr[i]; 405 | } 406 | return nodes; 407 | } 408 | 409 | } 410 | library SafeMath { 411 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 412 | if (a == 0) { 413 | return 0; 414 | } 415 | uint256 c = a * b; 416 | assert(c / a == b); 417 | return c; 418 | } 419 | 420 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 421 | // assert(b > 0); // Solidity automatically throws when dividing by 0 422 | uint256 c = a / b; 423 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 424 | return c; 425 | } 426 | 427 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 428 | assert(b <= a); 429 | return a - b; 430 | } 431 | 432 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 433 | uint256 c = a + b; 434 | assert(c >= a); 435 | return c; 436 | } 437 | } 438 | -------------------------------------------------------------------------------- /contracts/crosschain.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.0 ; 3 | 4 | interface IERC20 { 5 | function transfer(address _to, uint256 _value) external returns (bool); 6 | function balanceOf(address account) external view returns (uint256); 7 | function mint(uint256 amount) external; 8 | function burn(uint256 amount) external; 9 | function transferFrom(address _from, address _to, uint256 _value) external returns (bool); 10 | function lucaToFragment(uint256 value) external view returns (uint256); 11 | function fragmentToLuca(uint256 value) external view returns (uint256); 12 | } 13 | interface Itrader { 14 | function suck(address _to, uint256 _amount) external; 15 | } 16 | interface ICrosschain { 17 | function transferToken( 18 | address[2] calldata addrs, 19 | uint256[3] calldata uints, 20 | string[] calldata strs, 21 | uint8[] calldata vs, 22 | bytes32[] calldata rssMetadata) external; 23 | function stakeToken(string memory _chain, string memory receiveAddr, address tokenAddr, uint256 _amount) external ; 24 | } 25 | 26 | abstract contract Initializable { 27 | /** 28 | * @dev Indicates that the contract has been initialized. 29 | */ 30 | bool private _initialized; 31 | 32 | /** 33 | * @dev Indicates that the contract is in the process of being initialized. 34 | */ 35 | bool private _initializing; 36 | 37 | /** 38 | * @dev Modifier to protect an initializer function from being invoked twice. 39 | */ 40 | modifier initializer() { 41 | require(_initializing || !_initialized, "Initializable: contract is already initialized"); 42 | 43 | bool isTopLevelCall = !_initializing; 44 | if (isTopLevelCall) { 45 | _initializing = true; 46 | _initialized = true; 47 | } 48 | 49 | _; 50 | 51 | if (isTopLevelCall) { 52 | _initializing = false; 53 | } 54 | } 55 | } 56 | 57 | contract Ownable is Initializable{ 58 | address private _owner; 59 | 60 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 61 | 62 | /** 63 | * @dev Initializes the contract setting the management contract as the initial owner. 64 | */ 65 | function __Ownable_init_unchained(address _management) internal initializer { 66 | require( _management != address(0),"management address cannot be 0"); 67 | _owner = _management; 68 | emit OwnershipTransferred(address(0), _management); 69 | } 70 | 71 | /** 72 | * @dev Returns the address of the current owner. 73 | */ 74 | function owner() public view returns (address) { 75 | return _owner; 76 | } 77 | 78 | /** 79 | * @dev Throws if called by any account other than the owner. 80 | */ 81 | modifier onlyOwner() { 82 | require(isOwner(), "Ownable: caller is not the owner"); 83 | _; 84 | } 85 | 86 | /** 87 | * @dev Returns true if the caller is the current owner. 88 | */ 89 | function isOwner() public view returns (bool) { 90 | return msg.sender == _owner; 91 | } 92 | 93 | /** 94 | * @dev Leaves the contract without owner. It will not be possible to call 95 | * `onlyOwner` functions anymore. Can only be called by the current owner. 96 | * 97 | * NOTE: Renouncing ownership will leave the contract without an owner, 98 | * thereby removing any functionality that is only available to the owner. 99 | */ 100 | function renounceOwnership() public onlyOwner { 101 | emit OwnershipTransferred(_owner, address(0)); 102 | _owner = address(0); 103 | } 104 | 105 | /** 106 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 107 | * Can only be called by the current owner. 108 | */ 109 | function transferOwnership(address newOwner) public onlyOwner { 110 | _transferOwnership(newOwner); 111 | } 112 | 113 | /** 114 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 115 | */ 116 | function _transferOwnership(address newOwner) internal { 117 | require(newOwner != address(0), "Ownable: new owner is the zero address"); 118 | emit OwnershipTransferred(_owner, newOwner); 119 | _owner = newOwner; 120 | } 121 | } 122 | 123 | contract Crosschain is Initializable,Ownable,ICrosschain { 124 | using SafeMath for uint256; 125 | bool public pause; 126 | uint256 public nodeNum; 127 | uint256 public stakeNum; 128 | bytes32 public DOMAIN_SEPARATOR; 129 | bool public bscSta; 130 | IERC20 public lucaToken; 131 | mapping(string => mapping(address => uint256)) public chargeRate; 132 | mapping(address => uint256) chargeAmount; 133 | mapping(string => bool) public chainSta; 134 | mapping(string => mapping(string => bool)) status; 135 | mapping(address => uint256) nodeAddrIndex; 136 | mapping(uint256 => address) public nodeIndexAddr; 137 | mapping(address => bool) public nodeAddrSta; 138 | mapping(uint256 => Stake) public stakeMsg; 139 | event UpdatePause(bool sta); 140 | event WithdrawChargeAmount(address tokenAddr, uint256 amount); 141 | event AddNodeAddr(address[] nodeAddrs); 142 | event DeleteNodeAddr(address[] nodeAddrs); 143 | event UpdateChainCharge(string chain, bool sta, address[] tokens, uint256[] fees); 144 | event TransferToken(address indexed _tokenAddr, address _receiveAddr, uint256 _fragment, uint256 _amount, string chain, string txid); 145 | event StakeToken(address indexed _tokenAddr, address indexed _userAddr, string receiveAddr, uint256 fragment, uint256 amount, uint256 fee,string chain); 146 | IERC20 public agtToken; 147 | Itrader public trader; 148 | 149 | struct Data { 150 | address userAddr; 151 | address contractAddr; 152 | uint256 fragment; 153 | uint256 amount; 154 | uint256 expiration; 155 | string chain; 156 | string txid; 157 | } 158 | 159 | struct Stake { 160 | address tokenAddr; 161 | address userAddr; 162 | string receiveAddr; 163 | uint256 fragment; 164 | uint256 amount; 165 | uint256 fee; 166 | string chain; 167 | } 168 | 169 | struct Sig { 170 | /* v parameter */ 171 | uint8 v; 172 | /* r parameter */ 173 | bytes32 r; 174 | /* s parameter */ 175 | bytes32 s; 176 | } 177 | 178 | modifier onlyGuard() { 179 | require(!pause, "Crosschain: The system is suspended"); 180 | _; 181 | } 182 | 183 | function init( 184 | address _lucaToken, 185 | address _trader, 186 | address _agt, 187 | address _management, 188 | bool _sta 189 | ) external initializer{ 190 | __Ownable_init_unchained(_management); 191 | __Crosschain_init_unchained(_lucaToken, _trader, _agt, _sta); 192 | } 193 | 194 | function __Crosschain_init_unchained( 195 | address _lucaToken, 196 | address _trader, 197 | address _agt, 198 | bool _sta 199 | ) internal initializer{ 200 | require( _lucaToken != address(0),"lucaToken address cannot be 0"); 201 | require( _trader != address(0),"trader address cannot be 0"); 202 | require( _agt != address(0),"agt address cannot be 0"); 203 | lucaToken = IERC20(_lucaToken); 204 | trader = Itrader(_trader); 205 | agtToken = IERC20(_agt); 206 | bscSta = _sta; 207 | uint chainId; 208 | assembly { 209 | chainId := chainId 210 | } 211 | DOMAIN_SEPARATOR = keccak256( 212 | abi.encode( 213 | keccak256('EIP712Domain(uint256 chainId,address verifyingContract)'), 214 | chainId, 215 | address(this) 216 | ) 217 | ); 218 | } 219 | 220 | receive() payable external{ 221 | 222 | } 223 | 224 | fallback() payable external{ 225 | 226 | } 227 | 228 | function updatePause(bool _sta) external onlyOwner{ 229 | pause = _sta; 230 | emit UpdatePause(_sta); 231 | } 232 | 233 | function updateChainCharge(string calldata _chain, bool _sta, address[] calldata _tokens, uint256[] calldata _fees) external onlyOwner{ 234 | chainSta[_chain] = _sta; 235 | require(_tokens.length == _fees.length, "Parameter array length does not match"); 236 | for (uint256 i = 0; i< _tokens.length; i++){ 237 | chargeRate[_chain][_tokens[i]] = _fees[i]; 238 | } 239 | emit UpdateChainCharge(_chain, _sta, _tokens, _fees); 240 | } 241 | 242 | function withdrawChargeAmount(address[] calldata tokenAddrs, address receiveAddr) external onlyOwner{ 243 | require( receiveAddr != address(0),"receiveAddr address cannot be 0"); 244 | for (uint256 i = 0; i< tokenAddrs.length; i++){ 245 | if(tokenAddrs[i] == address(lucaToken)){ 246 | uint256 _amount = lucaToken.fragmentToLuca(chargeAmount[tokenAddrs[i]]); 247 | require(lucaToken.transfer(receiveAddr,_amount), "Token transfer failed"); 248 | chargeAmount[tokenAddrs[i]] = 0; 249 | emit WithdrawChargeAmount(tokenAddrs[i], _amount); 250 | }else{ 251 | IERC20 token = IERC20(tokenAddrs[i]); 252 | uint256 _amount = chargeAmount[tokenAddrs[i]]; 253 | require(token.transfer(receiveAddr,_amount), "Token transfer failed"); 254 | chargeAmount[tokenAddrs[i]] = 0; 255 | emit WithdrawChargeAmount(tokenAddrs[i], _amount); 256 | } 257 | 258 | } 259 | 260 | } 261 | 262 | function addNodeAddr(address[] calldata _nodeAddrs) external onlyOwner{ 263 | for (uint256 i = 0; i< _nodeAddrs.length; i++){ 264 | address _nodeAddr = _nodeAddrs[i]; 265 | require(!nodeAddrSta[_nodeAddr], "This node is already a node address"); 266 | nodeAddrSta[_nodeAddr] = true; 267 | uint256 _nodeAddrIndex = nodeAddrIndex[_nodeAddr]; 268 | if (_nodeAddrIndex == 0){ 269 | _nodeAddrIndex = ++nodeNum; 270 | nodeAddrIndex[_nodeAddr] = _nodeAddrIndex; 271 | nodeIndexAddr[_nodeAddrIndex] = _nodeAddr; 272 | } 273 | } 274 | emit AddNodeAddr(_nodeAddrs); 275 | } 276 | 277 | function deleteNodeAddr(address[] calldata _nodeAddrs) external onlyOwner{ 278 | for (uint256 i = 0; i< _nodeAddrs.length; i++){ 279 | address _nodeAddr = _nodeAddrs[i]; 280 | require(nodeAddrSta[_nodeAddr], "This node is not a pledge node"); 281 | nodeAddrSta[_nodeAddr] = false; 282 | uint256 _nodeAddrIndex = nodeAddrIndex[_nodeAddr]; 283 | if (_nodeAddrIndex > 0){ 284 | uint256 _nodeNum = nodeNum; 285 | address _lastNodeAddr = nodeIndexAddr[_nodeNum]; 286 | nodeAddrIndex[_lastNodeAddr] = _nodeAddrIndex; 287 | nodeIndexAddr[_nodeAddrIndex] = _lastNodeAddr; 288 | nodeAddrIndex[_nodeAddr] = 0; 289 | nodeIndexAddr[_nodeNum] = address(0x0); 290 | nodeNum--; 291 | } 292 | } 293 | emit DeleteNodeAddr(_nodeAddrs); 294 | } 295 | 296 | function stakeToken(string memory _chain, string memory receiveAddr, address tokenAddr, uint256 _amount) override external { 297 | address _sender = msg.sender; 298 | require( tokenAddr == address(lucaToken) || tokenAddr == address(agtToken) , "Crosschain: The token does not support transfers"); 299 | require( chainSta[_chain], "Crosschain: The chain does not support transfer"); 300 | if (address(lucaToken) == tokenAddr){ 301 | require(lucaToken.transferFrom(_sender,address(this),_amount), "Token transfer failed"); 302 | uint256 _charge = chargeRate[_chain][tokenAddr]; 303 | _amount = _amount.sub(_charge); 304 | uint256 fragment = lucaToken.lucaToFragment(_amount); 305 | require(fragment > 0, "Share calculation anomaly"); 306 | uint256 fee = lucaToken.lucaToFragment(_charge); 307 | chargeAmount[tokenAddr] = chargeAmount[tokenAddr].add(fee); 308 | stakeMsg[++stakeNum] = Stake(tokenAddr, _sender, receiveAddr, fragment, _amount, fee, _chain); 309 | if(!bscSta){ 310 | lucaToken.burn(_amount); 311 | } 312 | emit StakeToken(tokenAddr, _sender, receiveAddr, fragment, _amount, fee, _chain); 313 | }else{ 314 | IERC20 token = IERC20(tokenAddr); 315 | require(token.transferFrom(_sender,address(this),_amount), "Token transfer failed"); 316 | uint256 fee = chargeRate[_chain][tokenAddr]; 317 | _amount = _amount.sub(fee); 318 | chargeAmount[tokenAddr] = chargeAmount[tokenAddr].add(fee); 319 | stakeMsg[++stakeNum] = Stake(tokenAddr, _sender, receiveAddr, 0, _amount, fee, _chain); 320 | token.burn(_amount); 321 | emit StakeToken(tokenAddr, _sender, receiveAddr, 0, _amount, fee, _chain); 322 | } 323 | } 324 | 325 | /** 326 | * @notice A method in which issue transfer tokens to users. 327 | * @param addrs [User address, token contract address] 328 | * @param uints [Number of luca fragments (0 for non-luca tokens), number of transfers, expiration time] 329 | * @param strs [chain name, transaction id] 330 | * @param vs array of signature data 331 | * @param rssMetadata array of signature data 332 | */ 333 | function transferToken( 334 | address[2] calldata addrs, 335 | uint256[3] calldata uints, 336 | string[] calldata strs, 337 | uint8[] calldata vs, 338 | bytes32[] calldata rssMetadata 339 | ) 340 | external 341 | override 342 | onlyGuard 343 | { 344 | require( addrs[1] == address(lucaToken) || addrs[1] == address(agtToken) , "Crosschain: The token does not support transfers"); 345 | require( block.timestamp<= uints[2], "Crosschain: The transaction exceeded the time limit"); 346 | require( !status[strs[0]][strs[1]], "Crosschain: The transaction has been withdrawn"); 347 | status[strs[0]][strs[1]] = true; 348 | uint256 len = vs.length; 349 | uint256 counter; 350 | require(len*2 == rssMetadata.length, "Crosschain: Signature parameter length mismatch"); 351 | uint256[] memory arr = new uint256[](len); 352 | bytes32 digest = getDigest(Data( addrs[0], addrs[1], uints[0], uints[1], uints[2], strs[0], strs[1])); 353 | for (uint256 i = 0; i < len; i++) { 354 | (bool result, uint256 index) = verifySign( 355 | digest, 356 | Sig(vs[i], rssMetadata[i*2], rssMetadata[i*2+1]) 357 | ); 358 | arr[i] = index; 359 | if (result){ 360 | counter++; 361 | } 362 | } 363 | require(areElementsUnique(arr), "IncentiveContracts: Signature parameter not unique"); 364 | require( 365 | counter > nodeNum/2, 366 | "The number of signed accounts did not reach the minimum threshold" 367 | ); 368 | _transferToken(addrs, uints, strs); 369 | } 370 | 371 | function queryCharge(address[] calldata addrs) external view returns (address[] memory, uint256[] memory) { 372 | address[] memory _addrArray = new address[](1) ; 373 | uint256[] memory _chargeAmount = new uint256[](1) ; 374 | uint256 len = addrs.length; 375 | _addrArray = new address[](len) ; 376 | _chargeAmount = new uint256[](len) ; 377 | for (uint256 i = 0; i < len; i++) { 378 | _addrArray[i] = addrs[i]; 379 | if(addrs[i] == address(lucaToken)){ 380 | _chargeAmount[i] = lucaToken.fragmentToLuca(chargeAmount[addrs[i]]); 381 | }else{ 382 | _chargeAmount[i] = chargeAmount[addrs[i]]; 383 | } 384 | } 385 | return (_addrArray, _chargeAmount); 386 | } 387 | 388 | function _transferToken(address[2] memory addrs, uint256[3] memory uints, string[] memory strs) internal { 389 | if (address(lucaToken) == addrs[1]){ 390 | uint256 amount = lucaToken.fragmentToLuca(uints[0]); 391 | if (!bscSta){ 392 | lucaToken.mint(amount); 393 | } 394 | uint256 balance = lucaToken.balanceOf(address(this)); 395 | require(balance >= amount,"Insufficient token balance"); 396 | require( 397 | lucaToken.transfer(addrs[0],amount), 398 | "Token transfer failed" 399 | ); 400 | emit TransferToken(addrs[1], addrs[0], uints[0], amount, strs[0], strs[1]); 401 | }else if(address(agtToken) == addrs[1]){ 402 | uint256 amount = uints[1]; 403 | uint256 balance = agtToken.balanceOf(address(this)); 404 | if (balance < amount){ 405 | trader.suck(address(this),amount); 406 | } 407 | balance = agtToken.balanceOf(address(this)); 408 | require(balance >= amount,"Insufficient token balance"); 409 | require( 410 | agtToken.transfer(addrs[0],amount), 411 | "Token transfer failed" 412 | ); 413 | emit TransferToken(addrs[1], addrs[0], 0, amount, strs[0], strs[1]); 414 | } 415 | } 416 | 417 | function areElementsUnique(uint256[] memory arr) internal pure returns (bool) { 418 | for(uint i = 0; i < arr.length - 1; i++) { 419 | for(uint j = i + 1; j < arr.length; j++) { 420 | if (arr[i] == arr[j]) { 421 | return false; 422 | } 423 | } 424 | } 425 | return true; 426 | } 427 | 428 | function verifySign(bytes32 _digest,Sig memory _sig) internal view returns (bool,uint256) { 429 | bytes memory prefix = "\x19Ethereum Signed Message:\n32"; 430 | bytes32 hash = keccak256(abi.encodePacked(prefix, _digest)); 431 | address _nodeAddr = ecrecover(hash, _sig.v, _sig.r, _sig.s); 432 | require(_nodeAddr !=address(0),"Illegal signature"); 433 | return (nodeAddrSta[_nodeAddr],nodeAddrIndex[_nodeAddr]); 434 | } 435 | 436 | function getDigest(Data memory _data) internal view returns(bytes32 digest){ 437 | digest = keccak256( 438 | abi.encodePacked( 439 | '\x19\x01', 440 | DOMAIN_SEPARATOR, 441 | keccak256(abi.encode(_data.userAddr, _data.contractAddr, _data.fragment, _data.amount, _data.expiration, _data.chain, _data.txid)) 442 | ) 443 | ); 444 | } 445 | 446 | } 447 | library SafeMath { 448 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 449 | if (a == 0) { 450 | return 0; 451 | } 452 | uint256 c = a * b; 453 | assert(c / a == b); 454 | return c; 455 | } 456 | 457 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 458 | // assert(b > 0); // Solidity automatically throws when dividing by 0 459 | uint256 c = a / b; 460 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 461 | return c; 462 | } 463 | 464 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 465 | assert(b <= a); 466 | return a - b; 467 | } 468 | 469 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 470 | uint256 c = a + b; 471 | assert(c >= a); 472 | return c; 473 | } 474 | } 475 | -------------------------------------------------------------------------------- /contracts/factory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | library SafeMath { 6 | function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { 7 | unchecked { 8 | uint256 c = a + b; 9 | if (c < a) return (false, 0); 10 | return (true, c); 11 | } 12 | } 13 | 14 | function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { 15 | unchecked { 16 | if (b > a) return (false, 0); 17 | return (true, a - b); 18 | } 19 | } 20 | function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { 21 | unchecked { 22 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 23 | // benefit is lost if 'b' is also tested. 24 | // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 25 | if (a == 0) return (true, 0); 26 | uint256 c = a * b; 27 | if (c / a != b) return (false, 0); 28 | return (true, c); 29 | } 30 | } 31 | 32 | function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { 33 | unchecked { 34 | if (b == 0) return (false, 0); 35 | return (true, a / b); 36 | } 37 | } 38 | 39 | function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { 40 | unchecked { 41 | if (b == 0) return (false, 0); 42 | return (true, a % b); 43 | } 44 | } 45 | 46 | 47 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 48 | return a + b; 49 | } 50 | 51 | 52 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 53 | return a - b; 54 | } 55 | 56 | 57 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 58 | return a * b; 59 | } 60 | 61 | 62 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 63 | return a / b; 64 | } 65 | 66 | 67 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 68 | return a % b; 69 | } 70 | 71 | 72 | function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 73 | unchecked { 74 | require(b <= a, errorMessage); 75 | return a - b; 76 | } 77 | } 78 | 79 | 80 | function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 81 | unchecked { 82 | require(b > 0, errorMessage); 83 | return a / b; 84 | } 85 | } 86 | 87 | 88 | function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 89 | unchecked { 90 | require(b > 0, errorMessage); 91 | return a % b; 92 | } 93 | } 94 | } 95 | 96 | interface Ifile{ 97 | function factoryLoad() external view returns (address, address, address, address, uint256, uint256); 98 | function active() external view returns(bool); 99 | } 100 | 101 | interface IERC20 { 102 | function symbol() external view returns(string memory); 103 | function totalSupply() external view returns (uint256); 104 | function balanceOf(address account) external view returns (uint256); 105 | function transfer(address recipient, uint256 amount) external returns (bool); 106 | function allowance(address owner, address spender) external view returns (uint256); 107 | function approve(address spender, uint256 amount) external returns (bool); 108 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 109 | } 110 | 111 | interface IWETH is IERC20{ 112 | function deposit() payable external; 113 | function withdraw(uint) external; 114 | } 115 | 116 | interface Itrader { 117 | function payment(address token, address from, address to, uint256 amount) external returns(bool); 118 | function suck(address user, uint256 amount, uint256 lockDays) external; 119 | } 120 | 121 | interface Isymbol { 122 | function symbol() external view returns(string memory); 123 | } 124 | 125 | interface Ilink { 126 | function setEnv(address _luca, address _wluca, address _trader, address _weth, address _pledger) external; 127 | function initialize( address file, address _userA, address _userB, address _token, string memory _symbol, uint256 _amount, uint256 _percentA, uint256 _lockDays) external; 128 | } 129 | 130 | interface Ifactory { 131 | function isLink(address) external view returns(bool); 132 | // function setLockDay(uint256, uint256) external; 133 | function addToken(address, uint256) external; 134 | function updateTokenConfig (string memory, address, uint256) external; 135 | function createLink(address, string memory, uint256, uint256, uint256) payable external returns(address); 136 | function linkActive(address, uint256) external; 137 | 138 | event LinkCreated(address indexed _creater, string indexed _symbol, address _link); 139 | event LinkActive(address _link, address _user, uint256 _methodId); 140 | } 141 | 142 | contract Initialize { 143 | bool internal initialized; 144 | modifier noInit(){ 145 | require(!initialized, "initialized"); 146 | _; 147 | initialized = true; 148 | } 149 | } 150 | 151 | contract CloneFactory { 152 | function _clone(address target) internal returns (address result) { 153 | bytes20 targetBytes = bytes20(target); 154 | assembly { 155 | let clone := mload(0x40) 156 | mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000) 157 | mstore(add(clone, 0x14), targetBytes) 158 | mstore(add(clone, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000) 159 | result := create(0, clone, 0x37) 160 | } 161 | } 162 | } 163 | 164 | contract Factory is Initialize, CloneFactory, Ifactory{ 165 | using SafeMath for uint256; 166 | address public file; 167 | uint256 public totalLink; 168 | 169 | struct token { 170 | address addr; 171 | uint256 minAmount; 172 | bool isActive; 173 | } 174 | 175 | struct linkArgs { 176 | address userB; 177 | string symbol; 178 | uint256 totalPlan; 179 | uint256 percentA; 180 | uint256 lockDays; 181 | } 182 | 183 | struct fileArgs { 184 | address luca; 185 | address weth; 186 | address trader; 187 | address linkTemp; 188 | uint256 minLockDay; 189 | uint256 maxLockDay; 190 | } 191 | 192 | mapping(address => bool) internal linkMap; 193 | mapping(string => token) public tokenMap; 194 | address private constant ETH = address(0); 195 | 196 | modifier onlyFile() { 197 | require(msg.sender == file, "only file"); 198 | _; 199 | } 200 | 201 | function initialize(string memory _network, address _file) external noInit{ 202 | require(_file != address(0), "_file address cannot be 0"); 203 | file = _file; 204 | _addToken(_network, ETH, 100); 205 | } 206 | 207 | function isLink(address _link) override external view returns(bool){ 208 | return linkMap[_link]; 209 | } 210 | 211 | function addToken(address _token, uint256 _min) override external onlyFile { 212 | string memory symbol = IERC20(_token).symbol(); 213 | require(bytes(symbol).length > 0 , "Factory: not available ERC20 Token"); 214 | require(!tokenMap[symbol].isActive, "Factory: token exist" ); 215 | _addToken(symbol, _token, _min); 216 | } 217 | 218 | function _addToken(string memory _symbol, address _token, uint256 _min) internal { 219 | tokenMap[_symbol] = token(_token, _min, true); 220 | } 221 | 222 | function updateTokenConfig(string memory _symbol, address _token, uint256 _min) override external onlyFile { 223 | require(tokenMap[_symbol].isActive, "Factory: token not exist" ); 224 | tokenMap[_symbol] = token(_token, _min, true); 225 | } 226 | 227 | function createLink(address _userB, string memory _symbol, uint256 _totalPlan, uint256 _percentA, uint256 _lockDays) override external payable returns(address){ 228 | require(Ifile(file).active(),"Factory: emergency shutdown"); 229 | fileArgs memory f; 230 | { 231 | (address luca, address weth, address trader, address linkTemp, uint256 minLockDay, uint256 maxLockDay) = Ifile(file).factoryLoad(); 232 | f = fileArgs(luca, weth, trader, linkTemp, minLockDay, maxLockDay); 233 | } 234 | 235 | //check args 236 | require(_userB != msg.sender, "Factory: userB is self"); 237 | require(_percentA >=1 && _percentA <= 100,"Factory: percentA need between 1 and 100"); 238 | require(_lockDays >= f.minLockDay && _lockDays <= f.maxLockDay,"Factory: lockDays out of set"); 239 | 240 | //check token astrict 241 | token memory t = tokenMap[_symbol]; 242 | require(t.isActive, "Factory: token not exist"); 243 | require(_totalPlan >= t.minAmount, "Factory: totalPlan too small"); 244 | 245 | //create contract 246 | Ilink link = Ilink(_clone(f.linkTemp)); 247 | 248 | totalLink++; 249 | linkMap[address(link)] = true; 250 | 251 | //payment amountA to link 252 | uint256 amountA = _totalPlan.mul(_percentA).div(100); 253 | if (t.addr == ETH){ 254 | require(msg.value == amountA, "Factory: wrong amount value"); 255 | IWETH(f.weth).deposit{value: msg.value}(); 256 | IWETH(f.weth).transfer(address(link), msg.value); 257 | }else{ 258 | Itrader(f.trader).payment(t.addr, msg.sender, address(link), amountA); 259 | } 260 | 261 | //init link 262 | link.initialize(file, msg.sender, _userB, t.addr, _symbol, _totalPlan, _percentA, _lockDays); 263 | emit LinkCreated(msg.sender, _symbol, address(link)); 264 | 265 | //mint agt 266 | if (t.addr == f.luca && _percentA == 100 && _userB != address(0)){ 267 | Itrader(f.trader).suck(msg.sender, amountA, _lockDays); 268 | } 269 | 270 | return address(link); 271 | } 272 | 273 | function linkActive(address _user, uint256 _methodId) override external{ 274 | require(linkMap[msg.sender], "Factory: only Link"); 275 | emit LinkActive(msg.sender, _user, _methodId); 276 | } 277 | } 278 | -------------------------------------------------------------------------------- /contracts/faucet.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | interface Token { 6 | function transfer(address, uint256) external returns(bool); 7 | function balanceOf(address account) external view returns (uint256); 8 | function decimals() external view returns (uint8); 9 | } 10 | 11 | contract ATM_Faucet { 12 | address public owner; 13 | mapping(string=>address) pool; 14 | mapping(address=>uint256) water; 15 | 16 | uint256 constant amount = 10; 17 | 18 | modifier onlyOwner(){ 19 | require(msg.sender == owner, "onlyOwner"); 20 | _; 21 | } 22 | 23 | constructor(){ 24 | owner = msg.sender; 25 | } 26 | 27 | function setPool(string memory symbol, address addr, uint256 drop) external onlyOwner{ 28 | pool[symbol] = addr; 29 | water[addr] = drop; 30 | } 31 | 32 | function getToken(string memory symbol) external{ 33 | require(pool[symbol] != address(0), "not this Token!"); 34 | Token(pool[symbol]).transfer(msg.sender, water[pool[symbol]] ); 35 | } 36 | } -------------------------------------------------------------------------------- /contracts/file.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | interface Ifactory{ 4 | function addToken(address _token, uint256 _min) external; 5 | function updateTokenConfig(string memory _symbol, address _token, uint256 _min) external; 6 | } 7 | 8 | contract Initialize { 9 | bool private initialized; 10 | 11 | modifier noInit(){ 12 | require(!initialized, "initialized"); 13 | _; 14 | initialized = true; 15 | } 16 | } 17 | 18 | contract Owner { 19 | address public owner; 20 | 21 | modifier onlyOwner(){ 22 | require(msg.sender == owner, "only owner"); 23 | _; 24 | } 25 | 26 | function setOwner(address addr) external onlyOwner{ 27 | require(addr != address(0), "addr address cannot be 0"); 28 | owner = addr; 29 | } 30 | } 31 | 32 | contract File is Owner, Initialize { 33 | //atm default token 34 | address public luca; 35 | address public wluca; 36 | address public agt; 37 | address public weth; 38 | 39 | //atm module contract 40 | address public factory; 41 | address public trader; 42 | address public pledger; 43 | address public linkTemp; 44 | 45 | //factory setings 46 | bool public active; 47 | uint256 public minLockDay; 48 | uint256 public maxLockDay; 49 | // uint256 public minFine; 50 | // uint256 public maxFine; 51 | 52 | //link steings 53 | address public collector; 54 | 55 | function initialize(address _luca, address _wluca, address _agt, address _weth, address _factory, address _trader, address _linkTemp, address _pledger, address _collector) external noInit { 56 | (luca, wluca, agt, weth) = (_luca, _wluca, _agt, _weth); 57 | (factory, trader, linkTemp) = (_factory, _trader, _linkTemp); 58 | (pledger, collector) = (_pledger, _collector); 59 | (owner, active, minLockDay, maxLockDay) = (msg.sender, true, 1, 1825); 60 | } 61 | 62 | //token seting 63 | function fileToken(bytes32 item, address addr) external onlyOwner{ 64 | if (item == "luca") luca = addr; 65 | else if (item == "wluca") wluca = addr; 66 | else if (item == "agt") agt = addr; 67 | else if (item == "weth") weth = addr; 68 | else revert("not this token"); 69 | } 70 | 71 | //module setings 72 | function fileModule(bytes32 item, address addr) external onlyOwner{ 73 | if (item == "factory") factory = addr; 74 | else if (item == "trader") trader = addr; 75 | else if (item == "pledger") pledger = addr; 76 | else if (item == "linkTemp") linkTemp = addr; 77 | else revert("not this module"); 78 | } 79 | 80 | function fileLockDay(uint256 min, uint256 max) external onlyOwner{ 81 | require(max > min); 82 | minLockDay = min; 83 | maxLockDay = max; 84 | } 85 | 86 | function linkLoad() external view returns (address, address, address, address, address){ 87 | return (luca, wluca, weth, trader, pledger); 88 | } 89 | 90 | function factoryLoad() external view returns (address, address, address, address, uint256, uint256){ 91 | return (luca, weth, trader, linkTemp, minLockDay, maxLockDay); 92 | } 93 | 94 | function setCollector(address addr) external onlyOwner { 95 | require(addr != address(0), "addr address cannot be 0"); 96 | collector = addr; 97 | } 98 | 99 | //emergency shutdown 100 | function shutdown() external onlyOwner{ 101 | active = false; 102 | } 103 | 104 | function restart() external onlyOwner{ 105 | active = true; 106 | } 107 | 108 | function addToken(address addr, uint256 min) external onlyOwner{ 109 | Ifactory(factory).addToken(addr, min); 110 | } 111 | 112 | function updateTokenConfig(string memory symbol, address addr, uint256 min) external onlyOwner{ 113 | Ifactory(factory).updateTokenConfig(symbol, addr, min); 114 | } 115 | } 116 | 117 | -------------------------------------------------------------------------------- /contracts/fileV2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | interface Ifactory{ 4 | function addToken(address _token, uint256 _min) external; 5 | function updateTokenConfig(string memory _symbol, address _token, uint256 _min) external; 6 | } 7 | 8 | contract Initialize { 9 | bool private initialized; 10 | 11 | modifier noInit(){ 12 | require(!initialized, "initialized"); 13 | _; 14 | initialized = true; 15 | } 16 | } 17 | 18 | contract Owner { 19 | address public owner; 20 | 21 | modifier onlyOwner(){ 22 | require(msg.sender == owner, "only owner"); 23 | _; 24 | } 25 | 26 | function setOwner(address addr) external onlyOwner{ 27 | require(addr != address(0), "addr address cannot be 0"); 28 | owner = addr; 29 | } 30 | } 31 | 32 | contract File is Owner, Initialize { 33 | //atm default token 34 | address public luca; 35 | address public wluca; 36 | address public agt; 37 | address public weth; 38 | 39 | //atm module contract 40 | address public factory; 41 | address public trader; 42 | address public pledger; 43 | address public linkTemp; 44 | 45 | //factory setings 46 | bool public active; 47 | uint256 public minLockDay; 48 | uint256 public maxLockDay; 49 | // uint256 public minFine; 50 | // uint256 public maxFine; 51 | 52 | //link setings 53 | address public collector; 54 | 55 | //crossChain seting 56 | address public crossChain; 57 | 58 | function initialize(address _luca, address _wluca, address _agt, address _weth, address _factory, address _trader, address _linkTemp, address _pledger, address _collector) external noInit { 59 | (luca, wluca, agt, weth) = (_luca, _wluca, _agt, _weth); 60 | (factory, trader, linkTemp) = (_factory, _trader, _linkTemp); 61 | (pledger, collector) = (_pledger, _collector); 62 | (owner, active, minLockDay, maxLockDay) = (msg.sender, true, 1, 1825); 63 | } 64 | 65 | //token seting 66 | function fileToken(bytes32 item, address addr) external onlyOwner{ 67 | if (item == "luca") luca = addr; 68 | else if (item == "wluca") wluca = addr; 69 | else if (item == "agt") agt = addr; 70 | else if (item == "weth") weth = addr; 71 | else revert("not this token"); 72 | } 73 | 74 | //module setings 75 | function fileModule(bytes32 item, address addr) external onlyOwner{ 76 | if (item == "factory") factory = addr; 77 | else if (item == "trader") trader = addr; 78 | else if (item == "pledger") pledger = addr; 79 | else if (item == "linkTemp") linkTemp = addr; 80 | else revert("not this module"); 81 | } 82 | 83 | function fileLockDay(uint256 min, uint256 max) external onlyOwner{ 84 | require(max > min); 85 | minLockDay = min; 86 | maxLockDay = max; 87 | } 88 | 89 | function linkLoad() external view returns (address, address, address, address, address){ 90 | return (luca, wluca, weth, trader, pledger); 91 | } 92 | 93 | function factoryLoad() external view returns (address, address, address, address, uint256, uint256){ 94 | return (luca, weth, trader, linkTemp, minLockDay, maxLockDay); 95 | } 96 | 97 | function setCollector(address addr) external onlyOwner { 98 | require(addr != address(0), "addr address cannot be 0"); 99 | collector = addr; 100 | } 101 | 102 | function setCrossChain(address addr) external onlyOwner { 103 | require(addr != address(0), "addr address cannot be 0"); 104 | crossChain = addr; 105 | } 106 | 107 | //emergency shutdown 108 | function shutdown() external onlyOwner{ 109 | active = false; 110 | } 111 | 112 | function restart() external onlyOwner{ 113 | active = true; 114 | } 115 | 116 | function addToken(address addr, uint256 min) external onlyOwner{ 117 | Ifactory(factory).addToken(addr, min); 118 | } 119 | 120 | function updateTokenConfig(string memory symbol, address addr, uint256 min) external onlyOwner{ 121 | Ifactory(factory).updateTokenConfig(symbol, addr, min); 122 | } 123 | } 124 | 125 | -------------------------------------------------------------------------------- /contracts/governor.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0 ; 3 | 4 | interface IERC20 { 5 | function transfer(address _to, uint256 _value) external returns (bool); 6 | function transferFrom(address _from, address _to, uint256 _value) external returns (bool); 7 | } 8 | 9 | interface IGovernor { 10 | function propose(uint256 _options, string memory _proposalContent) external; 11 | function vote(uint256 _proposalId, uint256[] calldata _amouns, uint256[] calldata _types) external; 12 | function withdrawStake(uint256[] calldata _proposalIds) external; 13 | 14 | } 15 | 16 | abstract contract Initializable { 17 | /** 18 | * @dev Indicates that the contract has been initialized. 19 | */ 20 | bool private _initialized; 21 | 22 | /** 23 | * @dev Indicates that the contract is in the process of being initialized. 24 | */ 25 | bool private _initializing; 26 | 27 | /** 28 | * @dev Modifier to protect an initializer function from being invoked twice. 29 | */ 30 | modifier initializer() { 31 | require(_initializing || !_initialized, "Initializable: contract is already initialized"); 32 | 33 | bool isTopLevelCall = !_initializing; 34 | if (isTopLevelCall) { 35 | _initializing = true; 36 | _initialized = true; 37 | } 38 | 39 | _; 40 | 41 | if (isTopLevelCall) { 42 | _initializing = false; 43 | } 44 | } 45 | } 46 | 47 | contract Ownable is Initializable{ 48 | address private _owner; 49 | 50 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 51 | 52 | /** 53 | * @dev Initializes the contract setting the deployer as the initial owner. 54 | */ 55 | function __Ownable_init_unchained() internal initializer { 56 | address msgSender = msg.sender; 57 | _owner = msgSender; 58 | emit OwnershipTransferred(address(0), msgSender); 59 | } 60 | 61 | /** 62 | * @dev Returns the address of the current owner. 63 | */ 64 | function owner() public view returns (address) { 65 | return _owner; 66 | } 67 | 68 | /** 69 | * @dev Throws if called by any account other than the owner. 70 | */ 71 | modifier onlyOwner() { 72 | require(isOwner(), "Ownable: caller is not the owner"); 73 | _; 74 | } 75 | 76 | /** 77 | * @dev Returns true if the caller is the current owner. 78 | */ 79 | function isOwner() public view returns (bool) { 80 | return msg.sender == _owner; 81 | } 82 | 83 | /** 84 | * @dev Leaves the contract without owner. It will not be possible to call 85 | * `onlyOwner` functions anymore. Can only be called by the current owner. 86 | * 87 | * NOTE: Renouncing ownership will leave the contract without an owner, 88 | * thereby removing any functionality that is only available to the owner. 89 | */ 90 | function renounceOwnership() public onlyOwner { 91 | emit OwnershipTransferred(_owner, address(0)); 92 | _owner = address(0); 93 | } 94 | 95 | /** 96 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 97 | * Can only be called by the current owner. 98 | */ 99 | function transferOwnership(address newOwner) public onlyOwner { 100 | _transferOwnership(newOwner); 101 | } 102 | 103 | /** 104 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 105 | */ 106 | function _transferOwnership(address newOwner) internal { 107 | require(newOwner != address(0), "Ownable: new owner is the zero address"); 108 | emit OwnershipTransferred(_owner, newOwner); 109 | _owner = newOwner; 110 | } 111 | } 112 | 113 | contract Governor is Initializable,Ownable,IGovernor{ 114 | using SafeMath for uint256; 115 | address public executor; 116 | IERC20 public governanceToken; 117 | uint256 public votingPeriod; 118 | uint256 public proposalCount; 119 | mapping(uint256 => ProposalMsg) public proposalMsg; 120 | mapping(address => mapping(uint256 => uint256)) public userStakeNum; 121 | 122 | event Propose(address indexed userAddr, uint256 proposalId, uint256 time); 123 | event Vote(address indexed userAddr, uint256 proposalId, uint256 option, uint256 votes, uint256 time); 124 | event WithdrawStake(address indexed userAddr, uint256 proposalId, uint256 amount, uint256 time); 125 | event UpdateExecutor(address _executor); 126 | 127 | 128 | struct ProposalMsg { 129 | address proposer; 130 | string proposalContent; 131 | uint256 launchTime; 132 | uint256 expire; 133 | uint256 options; 134 | mapping(uint256 => uint256) voteSums; 135 | } 136 | 137 | modifier onlyExecutor() { 138 | require(msg.sender == executor, "The caller is not the executor"); 139 | _; 140 | } 141 | 142 | function init(address _governanceToken, address _executor) external initializer{ 143 | __Ownable_init_unchained(); 144 | __Governor_init_unchained(_governanceToken, _executor); 145 | } 146 | 147 | function __Governor_init_unchained(address _governanceToken, address _executor) internal initializer{ 148 | governanceToken = IERC20(_governanceToken); 149 | executor = _executor; 150 | votingPeriod = 15 days; 151 | } 152 | 153 | receive() payable external{ 154 | 155 | } 156 | 157 | fallback() payable external{ 158 | 159 | } 160 | 161 | function updateVotingPeriod(uint256 _votingPeriod) external onlyExecutor{ 162 | votingPeriod = _votingPeriod; 163 | } 164 | 165 | function updateExecutor(address _executor) external onlyOwner{ 166 | executor = _executor; 167 | emit UpdateExecutor(_executor); 168 | } 169 | 170 | /** 171 | * @notice A method in which users pledge a certain amount of governance tokens to initiate a proposal 172 | */ 173 | function propose(uint256 _options, string memory _proposalContent) override external onlyExecutor{ 174 | require(_options > 0, "_options should be greater than 0!"); 175 | address _sender = msg.sender; 176 | uint256 _time = block.timestamp; 177 | uint256 proposalId = ++proposalCount; 178 | ProposalMsg storage _proposalMsg = proposalMsg[proposalId]; 179 | _proposalMsg.proposer = _sender; 180 | _proposalMsg.proposalContent = _proposalContent; 181 | _proposalMsg.launchTime = _time; 182 | _proposalMsg.expire = _time + votingPeriod; 183 | _proposalMsg.options = _options; 184 | emit Propose(_sender, proposalId, _time); 185 | } 186 | 187 | /** 188 | * @notice A method whereby users pledge governance tokens to vote on proposals 189 | * @param _amouns vote array 190 | * @param _proposalId the proposal id 191 | * @param _types Voting type array 192 | */ 193 | function vote(uint256 _proposalId, uint256[] calldata _amouns, uint256[] calldata _types) override external { 194 | address _sender = msg.sender; 195 | uint256 _time = block.timestamp; 196 | uint256 sum = 0; 197 | require(_amouns.length == _types.length, "Parameter number does not match"); 198 | ProposalMsg storage _proposalMsg = proposalMsg[_proposalId]; 199 | require(_proposalMsg.launchTime < _time && _proposalMsg.expire > _time, "The vote on the governance proposal has expired"); 200 | for (uint256 i = 0; i < _amouns.length; i++) { 201 | require(_types[i] > 0 && _types[i] <= _proposalMsg.options, "The vote type does not exist"); 202 | _proposalMsg.voteSums[_types[i]] = _proposalMsg.voteSums[_types[i]].add(_amouns[i]); 203 | sum = sum.add(_amouns[i]); 204 | emit Vote(_sender, _proposalId, _types[i], _amouns[i], _time); 205 | } 206 | userStakeNum[_sender][_proposalId] = userStakeNum[_sender][_proposalId].add(sum); 207 | require(governanceToken.transferFrom(_sender,address(this),sum), "Token transfer failed"); 208 | 209 | } 210 | 211 | /** 212 | * @notice A method to the users withdraws the pledge deposit 213 | * @param _proposalIds proposal ID collection 214 | */ 215 | function withdrawStake(uint256[] calldata _proposalIds) override external { 216 | address _sender = msg.sender; 217 | uint256 _amount = 0; 218 | for (uint256 i = 0; i < _proposalIds.length; i++) { 219 | uint256 _proposalId = _proposalIds[i]; 220 | require(_proposalId <= proposalCount, "The proposal ID is incorrect"); 221 | if (_proposalId > 0){ 222 | require(proposalMsg[_proposalId].expire < block.timestamp, "The vote on the agreement is not yet over"); 223 | uint256 stakeNum = userStakeNum[_sender][_proposalId]; 224 | _amount = _amount.add(stakeNum); 225 | userStakeNum[_sender][_proposalId] = 0; 226 | emit WithdrawStake(_sender, _proposalId, stakeNum, block.timestamp); 227 | } 228 | } 229 | require(_amount > 0, "The amount that can be withdrawn is 0"); 230 | require(governanceToken.transfer(_sender,_amount), "Token transfer failed"); 231 | } 232 | 233 | function queryVotes(uint256 _proposalId) external view returns(address, string memory, uint256, uint256, uint256, uint256[] memory){ 234 | ProposalMsg storage _proposalMsg = proposalMsg[_proposalId]; 235 | uint256[] memory votes = new uint256[](_proposalMsg.options); 236 | for (uint256 i = 0; i < _proposalMsg.options; i++) { 237 | votes[i] = _proposalMsg.voteSums[i.add(1)]; 238 | } 239 | return (_proposalMsg.proposer, _proposalMsg.proposalContent, _proposalMsg.launchTime, _proposalMsg.expire, _proposalMsg.options, votes); 240 | } 241 | } 242 | library SafeMath { 243 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 244 | if (a == 0) { 245 | return 0; 246 | } 247 | uint256 c = a * b; 248 | assert(c / a == b); 249 | return c; 250 | } 251 | 252 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 253 | // assert(b > 0); // Solidity automatically throws when dividing by 0 254 | uint256 c = a / b; 255 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 256 | return c; 257 | } 258 | 259 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 260 | assert(b <= a); 261 | return a - b; 262 | } 263 | 264 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 265 | uint256 c = a + b; 266 | assert(c >= a); 267 | return c; 268 | } 269 | } 270 | -------------------------------------------------------------------------------- /contracts/incentive.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0 ; 3 | 4 | interface IERC20 { 5 | function transfer(address _to, uint256 _value) external returns (bool); 6 | function transferFrom(address _from, address _to, uint256 _value) external returns (bool); 7 | } 8 | 9 | interface IPledgeContract { 10 | function queryNodeIndex(address _nodeAddr) external view returns(uint256); 11 | } 12 | 13 | interface IIncentive { 14 | function withdrawToken(address[2] calldata addrs,uint256[2] calldata uints,uint8[] calldata vs,bytes32[] calldata rssMetadata) external; 15 | } 16 | 17 | abstract contract Initializable { 18 | /** 19 | * @dev Indicates that the contract has been initialized. 20 | */ 21 | bool private _initialized; 22 | 23 | /** 24 | * @dev Indicates that the contract is in the process of being initialized. 25 | */ 26 | bool private _initializing; 27 | 28 | /** 29 | * @dev Modifier to protect an initializer function from being invoked twice. 30 | */ 31 | modifier initializer() { 32 | require(_initializing || !_initialized, "Initializable: contract is already initialized"); 33 | 34 | bool isTopLevelCall = !_initializing; 35 | if (isTopLevelCall) { 36 | _initializing = true; 37 | _initialized = true; 38 | } 39 | 40 | _; 41 | 42 | if (isTopLevelCall) { 43 | _initializing = false; 44 | } 45 | } 46 | } 47 | 48 | contract Ownable is Initializable{ 49 | address private _owner; 50 | 51 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 52 | 53 | /** 54 | * @dev Initializes the contract setting the deployer as the initial owner. 55 | */ 56 | function __Ownable_init_unchained() internal initializer { 57 | address msgSender = msg.sender; 58 | _owner = msgSender; 59 | emit OwnershipTransferred(address(0), msgSender); 60 | } 61 | 62 | /** 63 | * @dev Returns the address of the current owner. 64 | */ 65 | function owner() public view returns (address) { 66 | return _owner; 67 | } 68 | 69 | /** 70 | * @dev Throws if called by any account other than the owner. 71 | */ 72 | modifier onlyOwner() { 73 | require(isOwner(), "Ownable: caller is not the owner"); 74 | _; 75 | } 76 | 77 | /** 78 | * @dev Returns true if the caller is the current owner. 79 | */ 80 | function isOwner() public view returns (bool) { 81 | return msg.sender == _owner; 82 | } 83 | 84 | /** 85 | * @dev Leaves the contract without owner. It will not be possible to call 86 | * `onlyOwner` functions anymore. Can only be called by the current owner. 87 | * 88 | * NOTE: Renouncing ownership will leave the contract without an owner, 89 | * thereby removing any functionality that is only available to the owner. 90 | */ 91 | function renounceOwnership() public onlyOwner { 92 | emit OwnershipTransferred(_owner, address(0)); 93 | _owner = address(0); 94 | } 95 | 96 | /** 97 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 98 | * Can only be called by the current owner. 99 | */ 100 | function transferOwnership(address newOwner) public onlyOwner { 101 | _transferOwnership(newOwner); 102 | } 103 | 104 | /** 105 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 106 | */ 107 | function _transferOwnership(address newOwner) internal { 108 | require(newOwner != address(0), "Ownable: new owner is the zero address"); 109 | emit OwnershipTransferred(_owner, newOwner); 110 | _owner = newOwner; 111 | } 112 | } 113 | contract Incentive is Initializable,Ownable,IIncentive { 114 | IPledgeContract public pledgeContract; 115 | bytes32 public DOMAIN_SEPARATOR; 116 | bool public pause; 117 | mapping(address => uint256) public nonce; 118 | mapping(address => uint256) public withdrawSums; 119 | mapping(address => mapping(uint256 => uint256)) public withdrawAmounts; 120 | event WithdrawToken(address indexed _userAddr, uint256 _nonce, uint256 _amount); 121 | 122 | struct Data { 123 | address userAddr; 124 | address contractAddr; 125 | uint256 amount; 126 | uint256 expiration; 127 | } 128 | 129 | struct Sig { 130 | /* v parameter */ 131 | uint8 v; 132 | /* r parameter */ 133 | bytes32 r; 134 | /* s parameter */ 135 | bytes32 s; 136 | } 137 | 138 | modifier onlyGuard() { 139 | require(!pause, "IncentiveContracts: The system is suspended"); 140 | _; 141 | } 142 | 143 | function init(address _pledgeContract) external initializer{ 144 | __Ownable_init_unchained(); 145 | __Incentive_init_unchained(_pledgeContract); 146 | } 147 | 148 | function __Incentive_init_unchained(address _pledgeContract) internal initializer{ 149 | require(_pledgeContract != address(0), "_pledgeContract address cannot be 0"); 150 | pledgeContract = IPledgeContract(_pledgeContract); 151 | uint chainId; 152 | assembly { 153 | chainId := chainId 154 | } 155 | DOMAIN_SEPARATOR = keccak256( 156 | abi.encode( 157 | keccak256('EIP712Domain(uint256 chainId,address verifyingContract)'), 158 | chainId, 159 | address(this) 160 | ) 161 | ); 162 | } 163 | 164 | receive() payable external{ 165 | 166 | } 167 | 168 | function updatePause(bool _sta) external onlyOwner{ 169 | pause = _sta; 170 | } 171 | 172 | /** 173 | * @notice A method to the user withdraw revenue. 174 | * The extracted proceeds are signed by at least 6 PAGERANK servers, in order to withdraw successfully 175 | */ 176 | function withdrawToken( 177 | address[2] calldata addrs, 178 | uint256[2] calldata uints, 179 | uint8[] calldata vs, 180 | bytes32[] calldata rssMetadata 181 | ) 182 | override 183 | external 184 | onlyGuard 185 | { 186 | require(addrs[0] == msg.sender, "IncentiveContracts: Signing users are not the same as trading users"); 187 | require( block.timestamp<= uints[1], "IncentiveContracts: The transaction exceeded the time limit"); 188 | uint256 len = vs.length; 189 | uint256 counter; 190 | uint256 _nonce = nonce[addrs[0]]++; 191 | require(len*2 == rssMetadata.length, "IncentiveContracts: Signature parameter length mismatch"); 192 | bytes32 digest = getDigest(Data( addrs[0], addrs[1], uints[0], uints[1]), _nonce); 193 | for (uint256 i = 0; i < len; i++) { 194 | bool result = verifySign( 195 | digest, 196 | Sig(vs[i], rssMetadata[i*2], rssMetadata[i*2+1]) 197 | ); 198 | if (result){ 199 | counter++; 200 | } 201 | if (counter >= 6){ 202 | break; 203 | } 204 | } 205 | require( 206 | counter >= 6, 207 | "The number of signed accounts did not reach the minimum threshold" 208 | ); 209 | withdrawSums[addrs[0]] += uints[0]; 210 | withdrawAmounts[addrs[0]][_nonce] = uints[0]; 211 | IERC20 token = IERC20(addrs[1]); 212 | require( 213 | token.transfer(addrs[0],uints[0]), 214 | "Token transfer failed" 215 | ); 216 | emit WithdrawToken(addrs[0], _nonce, uints[0]); 217 | } 218 | 219 | function verifySign(bytes32 _digest,Sig memory _sig) internal view returns (bool) { 220 | bytes memory prefix = "\x19Ethereum Signed Message:\n32"; 221 | bytes32 hash = keccak256(abi.encodePacked(prefix, _digest)); 222 | address _accessAccount = ecrecover(hash, _sig.v, _sig.r, _sig.s); 223 | uint256 _nodeRank = pledgeContract.queryNodeIndex(_accessAccount); 224 | return _nodeRank < 12 && _nodeRank > 0; 225 | } 226 | 227 | function getDigest(Data memory _data, uint256 _nonce) internal view returns(bytes32 digest){ 228 | digest = keccak256( 229 | abi.encodePacked( 230 | '\x19\x01', 231 | DOMAIN_SEPARATOR, 232 | keccak256(abi.encode(_data.userAddr, _data.contractAddr, _data.amount, _data.expiration, _nonce)) 233 | ) 234 | ); 235 | } 236 | } 237 | 238 | -------------------------------------------------------------------------------- /contracts/incentiveV2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0 ; 3 | 4 | interface IERC20 { 5 | function transfer(address _to, uint256 _value) external returns (bool); 6 | function transferFrom(address _from, address _to, uint256 _value) external returns (bool); 7 | } 8 | 9 | interface IPledgeContract { 10 | function queryNodeIndex(address _nodeAddr) external view returns(uint256); 11 | } 12 | 13 | interface IIncentive { 14 | function withdrawToken(address[2] calldata addrs,uint256[2] calldata uints,uint8[] calldata vs,bytes32[] calldata rssMetadata) external; 15 | } 16 | 17 | abstract contract Initializable { 18 | /** 19 | * @dev Indicates that the contract has been initialized. 20 | */ 21 | bool private _initialized; 22 | 23 | /** 24 | * @dev Indicates that the contract is in the process of being initialized. 25 | */ 26 | bool private _initializing; 27 | 28 | /** 29 | * @dev Modifier to protect an initializer function from being invoked twice. 30 | */ 31 | modifier initializer() { 32 | require(_initializing || !_initialized, "Initializable: contract is already initialized"); 33 | 34 | bool isTopLevelCall = !_initializing; 35 | if (isTopLevelCall) { 36 | _initializing = true; 37 | _initialized = true; 38 | } 39 | 40 | _; 41 | 42 | if (isTopLevelCall) { 43 | _initializing = false; 44 | } 45 | } 46 | } 47 | 48 | contract Ownable is Initializable{ 49 | address private _owner; 50 | 51 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 52 | 53 | /** 54 | * @dev Initializes the contract setting the deployer as the initial owner. 55 | */ 56 | function __Ownable_init_unchained() internal initializer { 57 | address msgSender = msg.sender; 58 | _owner = msgSender; 59 | emit OwnershipTransferred(address(0), msgSender); 60 | } 61 | 62 | /** 63 | * @dev Returns the address of the current owner. 64 | */ 65 | function owner() public view returns (address) { 66 | return _owner; 67 | } 68 | 69 | /** 70 | * @dev Throws if called by any account other than the owner. 71 | */ 72 | modifier onlyOwner() { 73 | require(isOwner(), "Ownable: caller is not the owner"); 74 | _; 75 | } 76 | 77 | /** 78 | * @dev Returns true if the caller is the current owner. 79 | */ 80 | function isOwner() public view returns (bool) { 81 | return msg.sender == _owner; 82 | } 83 | 84 | /** 85 | * @dev Leaves the contract without owner. It will not be possible to call 86 | * `onlyOwner` functions anymore. Can only be called by the current owner. 87 | * 88 | * NOTE: Renouncing ownership will leave the contract without an owner, 89 | * thereby removing any functionality that is only available to the owner. 90 | */ 91 | function renounceOwnership() public onlyOwner { 92 | emit OwnershipTransferred(_owner, address(0)); 93 | _owner = address(0); 94 | } 95 | 96 | /** 97 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 98 | * Can only be called by the current owner. 99 | */ 100 | function transferOwnership(address newOwner) public onlyOwner { 101 | _transferOwnership(newOwner); 102 | } 103 | 104 | /** 105 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 106 | */ 107 | function _transferOwnership(address newOwner) internal { 108 | require(newOwner != address(0), "Ownable: new owner is the zero address"); 109 | emit OwnershipTransferred(_owner, newOwner); 110 | _owner = newOwner; 111 | } 112 | } 113 | contract IncentiveV2 is Initializable,Ownable,IIncentive { 114 | IPledgeContract public pledgeContract; 115 | bytes32 public DOMAIN_SEPARATOR; 116 | bool public pause; 117 | mapping(address => uint256) public nonce; 118 | mapping(address => uint256) public withdrawSums; 119 | mapping(address => mapping(uint256 => uint256)) public withdrawAmounts; 120 | event WithdrawToken(address indexed _userAddr, uint256 _nonce, uint256 _amount); 121 | 122 | struct Data { 123 | address userAddr; 124 | address contractAddr; 125 | uint256 amount; 126 | uint256 expiration; 127 | } 128 | 129 | struct Sig { 130 | /* v parameter */ 131 | uint8 v; 132 | /* r parameter */ 133 | bytes32 r; 134 | /* s parameter */ 135 | bytes32 s; 136 | } 137 | 138 | modifier onlyGuard() { 139 | require(!pause, "IncentiveContracts: The system is suspended"); 140 | _; 141 | } 142 | 143 | function init(address _pledgeContract) external initializer{ 144 | __Ownable_init_unchained(); 145 | __Incentive_init_unchained(_pledgeContract); 146 | } 147 | 148 | function __Incentive_init_unchained(address _pledgeContract) internal initializer{ 149 | require(_pledgeContract != address(0), "_pledgeContract address cannot be 0"); 150 | pledgeContract = IPledgeContract(_pledgeContract); 151 | uint chainId; 152 | assembly { 153 | chainId := chainId 154 | } 155 | DOMAIN_SEPARATOR = keccak256( 156 | abi.encode( 157 | keccak256('EIP712Domain(uint256 chainId,address verifyingContract)'), 158 | chainId, 159 | address(this) 160 | ) 161 | ); 162 | } 163 | 164 | receive() payable external{ 165 | 166 | } 167 | 168 | function updatePause(bool _sta) external onlyOwner{ 169 | pause = _sta; 170 | } 171 | 172 | /** 173 | * @notice A method to the user withdraw revenue. 174 | * The extracted proceeds are signed by at least 11 PAGERANK servers, in order to withdraw successfully 175 | */ 176 | function withdrawToken( 177 | address[2] calldata addrs, 178 | uint256[2] calldata uints, 179 | uint8[] calldata vs, 180 | bytes32[] calldata rssMetadata 181 | ) 182 | override 183 | external 184 | onlyGuard 185 | { 186 | require(addrs[0] == msg.sender, "IncentiveContracts: Signing users are not the same as trading users"); 187 | require( block.timestamp<= uints[1], "IncentiveContracts: The transaction exceeded the time limit"); 188 | uint256 len = vs.length; 189 | uint256 counter; 190 | uint256 _nonce = nonce[addrs[0]]++; 191 | require(len*2 == rssMetadata.length, "IncentiveContracts: Signature parameter length mismatch"); 192 | bytes32 digest = getDigest(Data( addrs[0], addrs[1], uints[0], uints[1]), _nonce); 193 | for (uint256 i = 0; i < len; i++) { 194 | bool result = verifySign( 195 | digest, 196 | Sig(vs[i], rssMetadata[i*2], rssMetadata[i*2+1]) 197 | ); 198 | if (result){ 199 | counter++; 200 | } 201 | if (counter >= 11){ 202 | break; 203 | } 204 | } 205 | require( 206 | counter >= 11, 207 | "The number of signed accounts did not reach the minimum threshold" 208 | ); 209 | withdrawSums[addrs[0]] += uints[0]; 210 | withdrawAmounts[addrs[0]][_nonce] = uints[0]; 211 | IERC20 token = IERC20(addrs[1]); 212 | require( 213 | token.transfer(addrs[0],uints[0]), 214 | "Token transfer failed" 215 | ); 216 | emit WithdrawToken(addrs[0], _nonce, uints[0]); 217 | } 218 | 219 | function verifySign(bytes32 _digest,Sig memory _sig) internal view returns (bool) { 220 | bytes memory prefix = "\x19Ethereum Signed Message:\n32"; 221 | bytes32 hash = keccak256(abi.encodePacked(prefix, _digest)); 222 | address _accessAccount = ecrecover(hash, _sig.v, _sig.r, _sig.s); 223 | uint256 _nodeRank = pledgeContract.queryNodeIndex(_accessAccount); 224 | return _nodeRank < 22 && _nodeRank > 0; 225 | } 226 | 227 | function getDigest(Data memory _data, uint256 _nonce) internal view returns(bytes32 digest){ 228 | digest = keccak256( 229 | abi.encodePacked( 230 | '\x19\x01', 231 | DOMAIN_SEPARATOR, 232 | keccak256(abi.encode(_data.userAddr, _data.contractAddr, _data.amount, _data.expiration, _nonce)) 233 | ) 234 | ); 235 | } 236 | } 237 | 238 | -------------------------------------------------------------------------------- /contracts/invest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0 ; 3 | 4 | interface IERC20 { 5 | function balanceOf(address _owner) external view returns (uint256); 6 | function transfer(address _to, uint256 _value) external returns (bool); 7 | function transferFrom(address _from, address _to, uint256 _value) external returns (bool); 8 | function approve(address _spender, uint256 _value) external returns (bool); 9 | } 10 | interface UniswapRouterV2 { 11 | function addLiquidity( 12 | address tokenA, 13 | address tokenB, 14 | uint amountADesired, 15 | uint amountBDesired, 16 | uint amountAMin, 17 | uint amountBMin, 18 | address to, 19 | uint deadline 20 | ) external returns ( 21 | uint amountA, 22 | uint amountB, 23 | uint liquidity 24 | ); 25 | 26 | function swapExactTokensForETH( 27 | uint256 amountIn, 28 | uint256 amountOutMin, 29 | address[] calldata path, 30 | address to, 31 | uint256 deadline 32 | ) external returns ( 33 | uint256[] memory amounts 34 | ); 35 | } 36 | 37 | interface UniswapV2Factory { 38 | function getPair(address tokenA, address tokenB) external view returns (address pair); 39 | } 40 | 41 | abstract contract Initializable { 42 | /** 43 | * @dev Indicates that the contract has been initialized. 44 | */ 45 | bool private _initialized; 46 | 47 | /** 48 | * @dev Indicates that the contract is in the process of being initialized. 49 | */ 50 | bool private _initializing; 51 | 52 | /** 53 | * @dev Modifier to protect an initializer function from being invoked twice. 54 | */ 55 | modifier initializer() { 56 | require(_initializing || !_initialized, "Initializable: contract is already initialized"); 57 | 58 | bool isTopLevelCall = !_initializing; 59 | if (isTopLevelCall) { 60 | _initializing = true; 61 | _initialized = true; 62 | } 63 | 64 | _; 65 | 66 | if (isTopLevelCall) { 67 | _initializing = false; 68 | } 69 | } 70 | } 71 | 72 | contract Ownable is Initializable{ 73 | address private _owner; 74 | 75 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 76 | 77 | /** 78 | * @dev Initializes the contract setting the deployer as the initial owner. 79 | */ 80 | function __Ownable_init_unchained() internal initializer { 81 | address msgSender = msg.sender; 82 | _owner = msgSender; 83 | emit OwnershipTransferred(address(0), msgSender); 84 | } 85 | 86 | /** 87 | * @dev Returns the address of the current owner. 88 | */ 89 | function owner() public view returns (address) { 90 | return _owner; 91 | } 92 | 93 | /** 94 | * @dev Throws if called by any account other than the owner. 95 | */ 96 | modifier onlyOwner() { 97 | require(isOwner(), "Ownable: caller is not the owner"); 98 | _; 99 | } 100 | 101 | /** 102 | * @dev Returns true if the caller is the current owner. 103 | */ 104 | function isOwner() public view returns (bool) { 105 | return msg.sender == _owner; 106 | } 107 | 108 | /** 109 | * @dev Leaves the contract without owner. It will not be possible to call 110 | * `onlyOwner` functions anymore. Can only be called by the current owner. 111 | * 112 | * NOTE: Renouncing ownership will leave the contract without an owner, 113 | * thereby removing any functionality that is only available to the owner. 114 | */ 115 | function renounceOwnership() public onlyOwner { 116 | emit OwnershipTransferred(_owner, address(0)); 117 | _owner = address(0); 118 | } 119 | 120 | /** 121 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 122 | * Can only be called by the current owner. 123 | */ 124 | function transferOwnership(address newOwner) public onlyOwner { 125 | _transferOwnership(newOwner); 126 | } 127 | 128 | /** 129 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 130 | */ 131 | function _transferOwnership(address newOwner) internal { 132 | require(newOwner != address(0), "Ownable: new owner is the zero address"); 133 | emit OwnershipTransferred(_owner, newOwner); 134 | _owner = newOwner; 135 | } 136 | } 137 | 138 | contract Invest is Initializable,Ownable{ 139 | using SafeMath for uint256; 140 | IERC20 public UsdcToken; 141 | uint256 public constant launchAmount = 5000000 * 10**18; 142 | UniswapV2Factory public uniswapFactory; 143 | UniswapRouterV2 public uniswapRouter; 144 | IERC20 public lucaToken; 145 | IERC20 public lucaToUsdcPair; 146 | uint256 public investUsdcSum; 147 | uint256 public liquiditySum; 148 | uint256 public lockTime; 149 | uint256 public investTime; 150 | uint256 public launchTime; 151 | bool private liquiditySta; 152 | mapping(address => InvestMsg) public userInvestMsg; 153 | event InvestLuca(address usrAddr, uint256 amount, uint256 timestamp); 154 | event WithdrawLiquidity(address usrAddr, uint256 liquidityAmount, uint256 timestamp); 155 | 156 | struct InvestMsg { 157 | uint256 amount; 158 | uint256 mark; 159 | } 160 | 161 | function init( 162 | address _lucaToken, 163 | address _usdc, 164 | address _uniswapFactory, 165 | address _uniswapRouter, 166 | uint256 _lockTime, 167 | uint256 _investTime, 168 | uint256 _startTime 169 | ) 170 | external 171 | initializer 172 | { 173 | __Ownable_init_unchained(); 174 | __Invest_init_unchained(_lucaToken,_usdc,_uniswapFactory,_uniswapRouter,_lockTime,_investTime,_startTime); 175 | } 176 | 177 | function __Invest_init_unchained( 178 | address _lucaToken, 179 | address _usdc, 180 | address _uniswapFactory, 181 | address _uniswapRouter, 182 | uint256 _lockTime, 183 | uint256 _investTime, 184 | uint256 _startTime 185 | ) 186 | internal 187 | initializer 188 | { 189 | lucaToken = IERC20(_lucaToken); 190 | UsdcToken = IERC20(_usdc); 191 | uniswapFactory = UniswapV2Factory(_uniswapFactory); 192 | uniswapRouter = UniswapRouterV2(_uniswapRouter); 193 | lockTime = _lockTime; 194 | investTime = _investTime; 195 | launchTime = _startTime; 196 | } 197 | 198 | receive() payable external{ 199 | 200 | } 201 | 202 | fallback() payable external{ 203 | 204 | } 205 | 206 | function investLuca(uint256 _amount) external{ 207 | uint256 endTime = launchTime + investTime; 208 | require(block.timestamp >= launchTime && block.timestamp <= endTime, "The time to invest is over"); 209 | address _sender = msg.sender; 210 | investUsdcSum = investUsdcSum.add(_amount); 211 | userInvestMsg[_sender].amount = userInvestMsg[_sender].amount.add(_amount); 212 | require(UsdcToken.transferFrom(_sender,address(this),_amount), "Token transfer failed"); 213 | emit InvestLuca(_sender, _amount, block.timestamp); 214 | } 215 | 216 | function withdrawLiquidity() external returns(bool){ 217 | address _sender = msg.sender; 218 | (uint256 _liquidityAmount,,) = calcLiquidity(_sender); 219 | require(_liquidityAmount > 0, "Users can withdraw liquidity to zero"); 220 | userInvestMsg[_sender].mark = userInvestMsg[_sender].mark.add(_liquidityAmount); 221 | uint256 _LiquidityBalance = lucaToUsdcPair.balanceOf(address(this)); 222 | require(_LiquidityBalance >= _liquidityAmount, "The contract transaction pair has insufficient liquidity"); 223 | require(lucaToUsdcPair.transfer(_sender, _liquidityAmount), "Liquidity withdrawal failure"); 224 | emit WithdrawLiquidity(_sender, _liquidityAmount, block.timestamp); 225 | return true; 226 | } 227 | 228 | function forwardLiquidity() external { 229 | require(!liquiditySta, "Liquidity has been added"); 230 | liquiditySta = true; 231 | uint256 endTime = launchTime + investTime; 232 | require(block.timestamp > endTime, "Investment time is not over"); 233 | uint256 _amount = investUsdcSum; 234 | UsdcToken.approve(address(uniswapRouter), _amount); 235 | lucaToken.approve(address(uniswapRouter), launchAmount); 236 | (,,liquiditySum) = uniswapRouter.addLiquidity( 237 | address(UsdcToken), 238 | address(lucaToken), 239 | _amount, 240 | launchAmount, 241 | 1, 242 | 1, 243 | address(this), 244 | block.timestamp.add(2 hours) 245 | ); 246 | lucaToUsdcPair = IERC20(uniswapFactory.getPair(address(UsdcToken),address(lucaToken))); 247 | } 248 | 249 | function queryInvestMsg(address _sender) external view returns(uint256,uint256,uint256){ 250 | (uint256 _LiquidityAmount,uint256 _mark,uint256 _LiquiditySum) = calcLiquidity(_sender); 251 | return (_LiquidityAmount,_mark,_LiquiditySum); 252 | } 253 | 254 | function calcLiquidity(address _sender) internal view returns(uint256, uint256, uint256){ 255 | InvestMsg memory investMsg = userInvestMsg[_sender]; 256 | uint256 _LiquiditySum = investMsg.amount.mul(liquiditySum).div(investUsdcSum); 257 | uint256 _startTime = launchTime + investTime; 258 | uint256 _liquidityAmount = 0; 259 | uint256 unitTime = lockTime.div(4); 260 | if(block.timestamp > _startTime.add(unitTime*4)){ 261 | _liquidityAmount = _LiquiditySum; 262 | }else if(block.timestamp > _startTime.add(unitTime*3)){ 263 | _liquidityAmount = _LiquiditySum.mul(3).div(4); 264 | }else if(block.timestamp > _startTime.add(unitTime*2)){ 265 | _liquidityAmount = _LiquiditySum.div(2); 266 | }else if(block.timestamp > _startTime.add(unitTime)){ 267 | _liquidityAmount = _LiquiditySum.div(4); 268 | } 269 | _liquidityAmount = _liquidityAmount.sub(investMsg.mark); 270 | return (_liquidityAmount, investMsg.mark, _LiquiditySum); 271 | } 272 | 273 | } 274 | library SafeMath { 275 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 276 | if (a == 0) { 277 | return 0; 278 | } 279 | uint256 c = a * b; 280 | assert(c / a == b); 281 | return c; 282 | } 283 | 284 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 285 | // assert(b > 0); // Solidity automatically throws when dividing by 0 286 | uint256 c = a / b; 287 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 288 | return c; 289 | } 290 | 291 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 292 | assert(b <= a); 293 | return a - b; 294 | } 295 | 296 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 297 | uint256 c = a + b; 298 | assert(c >= a); 299 | return c; 300 | } 301 | } -------------------------------------------------------------------------------- /contracts/link.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | library SafeMath { 6 | function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { 7 | unchecked { 8 | uint256 c = a + b; 9 | if (c < a) return (false, 0); 10 | return (true, c); 11 | } 12 | } 13 | function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { 14 | unchecked { 15 | if (b > a) return (false, 0); 16 | return (true, a - b); 17 | } 18 | } 19 | function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { 20 | unchecked { 21 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 22 | // benefit is lost if 'b' is also tested. 23 | // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 24 | if (a == 0) return (true, 0); 25 | uint256 c = a * b; 26 | if (c / a != b) return (false, 0); 27 | return (true, c); 28 | } 29 | } 30 | 31 | function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { 32 | unchecked { 33 | if (b == 0) return (false, 0); 34 | return (true, a / b); 35 | } 36 | } 37 | 38 | function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { 39 | unchecked { 40 | if (b == 0) return (false, 0); 41 | return (true, a % b); 42 | } 43 | } 44 | 45 | 46 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 47 | return a + b; 48 | } 49 | 50 | 51 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 52 | return a - b; 53 | } 54 | 55 | 56 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 57 | return a * b; 58 | } 59 | 60 | 61 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 62 | return a / b; 63 | } 64 | 65 | 66 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 67 | return a % b; 68 | } 69 | 70 | 71 | function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 72 | unchecked { 73 | require(b <= a, errorMessage); 74 | return a - b; 75 | } 76 | } 77 | 78 | 79 | function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 80 | unchecked { 81 | require(b > 0, errorMessage); 82 | return a / b; 83 | } 84 | } 85 | 86 | 87 | function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 88 | unchecked { 89 | require(b > 0, errorMessage); 90 | return a % b; 91 | } 92 | } 93 | } 94 | 95 | interface IERC20 { 96 | function totalSupply() external view returns (uint256); 97 | function balanceOf(address account) external view returns (uint256); 98 | function transfer(address recipient, uint256 amount) external returns (bool); 99 | function allowance(address owner, address spender) external view returns (uint256); 100 | function approve(address spender, uint256 amount) external returns (bool); 101 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 102 | } 103 | 104 | interface IWETH is IERC20{ 105 | function deposit() payable external; 106 | function withdraw(uint) external; 107 | } 108 | 109 | interface Ipledge{ 110 | function stakeWLuca(address _nodeAddr, uint256 _amount, address _sender) external returns(bool); 111 | function cancleStakeWLuca(address _sender) external returns(bool); 112 | } 113 | 114 | interface Itrader { 115 | function payment(address _token, address _from, address _to, uint256 _amount) external returns(bool); 116 | function withdrawFor(address _to, uint256 _amount) external; 117 | function suck(address _to, uint256 _amount, uint256 _lockDay) external; 118 | } 119 | 120 | interface Ifactory { 121 | function linkActive(address _user, uint256 _methodId) external; 122 | } 123 | 124 | interface Ifile { 125 | function luca() external view returns(address); 126 | function pledger() external view returns(address); 127 | function collector() external view returns(address); 128 | function linkLoad() external view returns (address, address, address, address, address);//luca, wluca, weth, trader, pledger 129 | } 130 | 131 | //Ilink.sol 132 | interface Ilink { 133 | function getPledgedInfo() external view returns(bool pledgedA_, bool pledgedB_); 134 | function getStatus() external view returns(string memory); 135 | function getLinkInfo() external view returns(string memory symbol_,address token_, address userA_,address userB_, uint256 amountA_,uint256 amountB_,uint256 percentA_,uint256 totalPlan_,uint256 lockDays_, uint256 startTime_, uint256 status_, bool isAward_); 136 | function getCloseInfo() external view returns(address closer_, uint256 startTime_,uint256 expiredTime_,uint256 closeTime_, bool closeReqA_, bool closeReqB_); 137 | function getRecevabesInfo() external view returns(uint256 receivableA_, bool isExitA_, uint256 receivableB_, bool isExitB_); 138 | function setUserB(address _userB) external; 139 | function agree() external payable; 140 | function reject() external; 141 | function close() external; 142 | function rejectClose() external; 143 | function repealCloseReq() external; 144 | function isExpire() external view returns(bool); 145 | function pledge(address node) external; 146 | function depledge() external; 147 | function wtihdrawSelf() external; 148 | } 149 | 150 | //link.sol 151 | contract Initialized { 152 | bool internal initialized; 153 | 154 | modifier noInit(){ 155 | require(!initialized, "initialized"); 156 | _; 157 | initialized = true; 158 | } 159 | } 160 | 161 | contract Enum { 162 | Status internal status; 163 | enum Status {INITED, AGREED, CLOSED, PLEDGED} 164 | enum MethodId {setUserB, agree, reject, pledge, depledge, close, repealCloseReq, rejectClose, wtihdrawSelf} 165 | 166 | function _init() internal {status = Status.INITED;} 167 | 168 | function _agree() internal {status = Status.AGREED;} 169 | 170 | function _close() internal {status = Status.CLOSED;} 171 | 172 | function _pledge() internal {status = Status.PLEDGED;} 173 | } 174 | 175 | contract LinkInfo is Enum { 176 | address internal file; 177 | address internal factory; 178 | bool internal closeReqA; 179 | bool internal closeReqB; 180 | bool internal pledgedA; 181 | bool internal pledgedB; 182 | 183 | string symbol; 184 | address userA; 185 | address userB; 186 | uint256 amountA; 187 | uint256 amountB; 188 | uint256 percentA; 189 | uint256 totalPlan; 190 | address token; 191 | address closer; 192 | uint256 lockDays; 193 | uint256 startTime; 194 | uint256 expiredTime; 195 | uint256 closeTime; 196 | 197 | uint256 receivableA; 198 | uint256 receivableB; 199 | bool isExitA; 200 | bool isExitB; 201 | 202 | 203 | modifier onlyLuca(){ 204 | require(token == Ifile(file).luca(), "Link: only luca"); 205 | _; 206 | } 207 | 208 | modifier onlyEditLink(){ 209 | require(msg.sender == userA, "Link: only userA"); 210 | require(userB == address(0) && percentA == 100, "Link: only Editable Link"); 211 | _; 212 | } 213 | 214 | modifier onlyLinkUser(){ 215 | require(msg.sender == userA || msg.sender == userB, "Link: access denied"); 216 | _; 217 | } 218 | 219 | modifier onlyUserB(){ 220 | require(msg.sender == userB, "Link: noly userB"); 221 | _; 222 | } 223 | 224 | modifier onlyINITED(){ 225 | require(status == Status.INITED, "Link: only initialized"); 226 | _; 227 | } 228 | 229 | modifier onlyAGREED(){ 230 | require(status == Status.AGREED, "Link: only agreed"); 231 | _; 232 | } 233 | 234 | modifier unCLOSED(){ 235 | require(status != Status.CLOSED, "Link: only unclosed"); 236 | _; 237 | } 238 | 239 | modifier onlyPLEDGED(){ 240 | require(status == Status.PLEDGED, "Link: only pledged"); 241 | _; 242 | } 243 | 244 | modifier unPLEDGED(){ 245 | require(status != Status.PLEDGED, "Link: only unpledged"); 246 | _; 247 | } 248 | } 249 | 250 | contract Link is LinkInfo, Initialized, Ilink { 251 | using SafeMath for uint256; 252 | address constant ETH = address(0); 253 | fallback() payable external{} 254 | receive() payable external{} 255 | 256 | function _linkActive(MethodId _methodId) internal{ 257 | Ifactory(factory).linkActive(msg.sender, uint256(_methodId)); 258 | } 259 | 260 | function initialize( address _file, address _userA, address _userB, address _token, string memory _symbol, uint256 _amount, uint256 _percentA, uint256 _lockDays) external noInit{ 261 | (factory, file, userA, userB, token, symbol) = (msg.sender, _file, _userA, _userB, _token, _symbol); 262 | (totalPlan, percentA, amountA, amountB, lockDays) = (_amount, _percentA, _amount.mul(_percentA).div(100), _amount.mul(100 - _percentA).div(100), _lockDays); 263 | 264 | if(_percentA == 100 && userB != address(0)){ 265 | startTime = block.timestamp; 266 | expiredTime = startTime.add(lockDays.mul(1 days)); 267 | _agree(); 268 | }else{ 269 | _init(); 270 | } 271 | } 272 | 273 | function setUserB(address _userB) override external onlyEditLink { 274 | require(_userB != address(0) && _userB != msg.sender, "Link: unlawful address"); 275 | _linkActive(MethodId.setUserB); 276 | userB = _userB; 277 | startTime = block.timestamp; 278 | expiredTime = startTime.add(lockDays.mul(1 days)); 279 | _agree(); 280 | 281 | (address luca,,,address trader,) = Ifile(file).linkLoad(); 282 | //airdrop gta 283 | if(token == luca){ 284 | Itrader(trader).suck(userA, amountA, lockDays); 285 | Itrader(trader).suck(userB, amountB, lockDays); 286 | } 287 | } 288 | 289 | function reject() override external onlyUserB onlyINITED{ 290 | _linkActive(MethodId.reject); 291 | _exit(); 292 | } 293 | 294 | function agree() override payable external onlyUserB onlyINITED{ 295 | _linkActive(MethodId.agree); 296 | // (luca, wluca, weth, trader, pledger) 297 | (address luca,,address weth, address trader,) = Ifile(file).linkLoad(); 298 | if (token == ETH){ 299 | 300 | require(msg.value == amountB, "Link: wrong amount of ETH"); 301 | IWETH(weth).deposit{value: msg.value}(); 302 | IWETH(weth).transfer(address(this), msg.value); 303 | }else{ 304 | Itrader(trader).payment(token, userB, address(this), amountB); 305 | } 306 | 307 | //require(_verifyDeposit(token, userB), "Link: deposit not enough" ); 308 | startTime = block.timestamp; 309 | expiredTime = startTime.add(lockDays.mul(1 days)); 310 | _agree(); 311 | 312 | //airdrop gta 313 | if(token == luca){ 314 | Itrader(trader).suck(userA, amountA, lockDays); 315 | Itrader(trader).suck(userB, amountB, lockDays); 316 | } 317 | } 318 | 319 | //pledge 320 | function pledge(address node) override external onlyLuca onlyLinkUser { 321 | require(status == Status.PLEDGED || status == Status.AGREED, "Link: access denied"); 322 | require(!isExpire(), "Link: link expire"); 323 | require(!closeReqA && !closeReqB, "Link: please handle the closing process first"); 324 | 325 | _linkActive(MethodId.pledge); 326 | 327 | uint256 amount; 328 | if (msg.sender == userA){ 329 | require(!pledgedA, "Link: repledge"); 330 | pledgedA = true; 331 | amount = amountA; 332 | }else{ 333 | require(!pledgedB, "Link: repledge"); 334 | pledgedB= true; 335 | amount = amountB; 336 | } 337 | 338 | require(amount > 0, "Link: 0 amount"); 339 | _pledge(); 340 | Ipledge(Ifile(file).pledger()).stakeWLuca(node, amount, msg.sender); 341 | } 342 | 343 | function depledge() override external onlyLuca onlyPLEDGED onlyLinkUser{ 344 | if (msg.sender == userA){ 345 | require(pledgedA, "Link: no pledged"); 346 | pledgedA = false; 347 | }else{ 348 | require(pledgedB, "Link: no pledged"); 349 | pledgedB= false; 350 | } 351 | 352 | _linkActive(MethodId.depledge); 353 | 354 | Ipledge(Ifile(file).pledger()).cancleStakeWLuca(msg.sender); 355 | 356 | 357 | //other exited 358 | if (isExitA || isExitB){ 359 | closer = msg.sender; 360 | closeTime = block.timestamp; 361 | _exitSelf(); 362 | _close(); 363 | return; 364 | } 365 | 366 | if (!pledgedA && !pledgedB) _agree(); 367 | } 368 | 369 | function wtihdrawSelf() override external onlyLuca onlyPLEDGED onlyLinkUser{ 370 | require(isExpire(),"Link: only Expire"); 371 | _linkActive(MethodId.wtihdrawSelf); 372 | _setReceivables(100); 373 | _exitSelf(); 374 | } 375 | 376 | //Link renew 377 | function close() override external unCLOSED unPLEDGED onlyLinkUser { 378 | _linkActive(MethodId.close); 379 | 380 | //Expire 381 | if (isExpire()){ 382 | _exit(); 383 | } 384 | 385 | //INITED 386 | if (status == Status.INITED){ 387 | require(msg.sender == userA,"Link: access denied"); 388 | _exit(); 389 | } 390 | 391 | //AGREED 392 | if (status == Status.AGREED){ 393 | if (msg.sender == userA) { 394 | closeReqA = true; 395 | }else{ 396 | closeReqB = true; 397 | } 398 | 399 | if (closeReqA && closeReqB){ 400 | _exit(); 401 | } 402 | } 403 | } 404 | 405 | function repealCloseReq() override external onlyAGREED onlyLinkUser { 406 | _linkActive(MethodId.repealCloseReq); 407 | 408 | if (msg.sender == userA) { 409 | closeReqA = false; 410 | }else{ 411 | closeReqB = false; 412 | } 413 | } 414 | 415 | function rejectClose() override external onlyAGREED onlyLinkUser{ 416 | _linkActive(MethodId.rejectClose); 417 | 418 | if (msg.sender == userB) { 419 | closeReqA = false; 420 | }else{ 421 | closeReqB = false; 422 | } 423 | } 424 | 425 | //Link query 426 | function isExpire() override public view returns(bool) { 427 | if (status == Status.INITED || expiredTime == 0){ 428 | return false; 429 | } 430 | return (block.timestamp >= expiredTime); 431 | } 432 | 433 | function getPledgedInfo() override external view returns(bool pledgedA_, bool pledgedB_){ 434 | return(pledgedA, pledgedB); 435 | } 436 | 437 | function getCloseInfo() override external view returns(address closer_, uint256 startTime_,uint256 expiredTime_,uint256 closeTime_, bool closeReqA_, bool closeReqB_){ 438 | return(closer, startTime, expiredTime, closeTime, closeReqA, closeReqB); 439 | } 440 | 441 | function getStatus() override external view returns(string memory status_){ 442 | if (Status.INITED == status) return "initialized"; 443 | if (Status.AGREED == status) return "agreed"; 444 | if (Status.PLEDGED == status) return "pledged"; 445 | if (Status.CLOSED == status) return "closed"; 446 | } 447 | 448 | function getRecevabesInfo() override external view returns(uint256 receivableA_, bool isExitA_, uint256 receivableB_, bool isExitB_){ 449 | return(receivableA, isExitA, receivableB, isExitB); 450 | } 451 | 452 | function getLinkInfo() override external view returns(string memory symbol_,address token_,address userA_, address userB_, uint256 amountA_, uint256 amountB_,uint256 percentA_,uint256 totalPlan_,uint256 lockDays_,uint256 startTime_,uint256 status_, bool isAward_){ 453 | bool isAward; 454 | if ((status == Status.AGREED) || ((status == Status.PLEDGED) && (!isExitA && !isExitB))) { 455 | isAward = true; 456 | } 457 | 458 | return(symbol, token, userA, userB, amountA, amountB, percentA, totalPlan, lockDays, startTime, uint256(status), isAward); 459 | } 460 | 461 | function _exit() internal{ 462 | closer = msg.sender; 463 | closeTime = block.timestamp; 464 | _liquidation(); 465 | _close(); 466 | } 467 | 468 | function _exitSelf() internal{ 469 | if (msg.sender == userA){ 470 | //userA unpledge and notExit 471 | require(!pledgedA && !isExitA, "Link: access denied "); 472 | isExitA = true; 473 | _withdraw(userA, receivableA); 474 | }else{ 475 | //userB unpledge and notExit 476 | require(!pledgedB && !isExitB, "Link: access denied "); 477 | isExitB = true; 478 | _withdraw(userB, receivableB); 479 | } 480 | } 481 | 482 | function _liquidation() internal{ 483 | if (status == Status.INITED || isExpire()) { 484 | _setReceivables(100); 485 | }else{ 486 | //AGREED 487 | uint256 day = (closeTime.sub(startTime)).div(1 days); 488 | //dayFator = (lockDays-day)*10^4 / lockDays 489 | uint256 dayFator = (lockDays.sub(day)).mul(10000).div(lockDays); 490 | 491 | if(dayFator <= 100){ // <1% * 10000 492 | _setReceivables(99); 493 | }else if(dayFator >= 1500){ // >15% * 10000 494 | _setReceivables(85); 495 | }else{ // 1% ~ 15% 496 | _setReceivables((10000 - dayFator).div(100)); 497 | } 498 | 499 | uint256 fee = totalPlan.sub(receivableA.add(receivableB)); 500 | _withdraw(Ifile(file).collector(), fee); 501 | } 502 | 503 | isExitA = true; 504 | isExitB = true; 505 | _withdraw(userA, receivableA); 506 | if (receivableB > 0) _withdraw(userB, receivableB); 507 | } 508 | 509 | 510 | function _withdraw(address to, uint amount) internal{ 511 | (address luca, address wluca, address weth, address trader,) = Ifile(file).linkLoad(); 512 | if (token == ETH){ 513 | IWETH(weth).withdraw(amount); 514 | payable(to).transfer(amount); 515 | }else if(token == luca){ 516 | IERC20(wluca).approve(trader, amount); 517 | Itrader(trader).withdrawFor(to, amount); 518 | }else{ 519 | IERC20(token).transfer(to, amount); 520 | } 521 | } 522 | 523 | function _setReceivables(uint256 factor) internal{ 524 | receivableA = amountA.mul(factor).div(100); 525 | 526 | if ((status == Status.AGREED) && amountB != 0){ 527 | receivableB = amountB.mul(factor).div(100); 528 | } 529 | } 530 | } 531 | -------------------------------------------------------------------------------- /contracts/proxy/communityFund_proxy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "./proxy.sol"; 5 | 6 | contract CommunityFundPorxy is basePorxy{ 7 | constructor(address impl) { 8 | _setAdmin(msg.sender); 9 | _setLogic(impl); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /contracts/proxy/crosschain_proxy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.0; 3 | import "./proxy.sol"; 4 | 5 | contract CrosschainPorxy is basePorxy{ 6 | constructor(address impl) { 7 | _setAdmin(msg.sender); 8 | _setLogic(impl); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /contracts/proxy/factory_proxy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "./proxy.sol"; 5 | 6 | contract FactoryPorxy is basePorxy{ 7 | constructor(address impl) { 8 | _setAdmin(msg.sender); 9 | _setLogic(impl); 10 | } 11 | } -------------------------------------------------------------------------------- /contracts/proxy/file_proxy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "./proxy.sol"; 5 | 6 | contract FilePorxy is basePorxy{ 7 | constructor(address impl) { 8 | _setAdmin(msg.sender); 9 | _setLogic(impl); 10 | } 11 | } -------------------------------------------------------------------------------- /contracts/proxy/governor_proxy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | import "./proxy.sol"; 4 | 5 | contract GovernorPorxy is basePorxy{ 6 | constructor(address impl) { 7 | _setAdmin(msg.sender); 8 | _setLogic(impl); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /contracts/proxy/incentive_proxy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "./proxy.sol"; 5 | 6 | contract IncentivePorxy is basePorxy{ 7 | constructor(address impl) { 8 | _setAdmin(msg.sender); 9 | _setLogic(impl); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /contracts/proxy/invest_proxy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "./proxy.sol"; 5 | 6 | contract InvestPorxy is basePorxy{ 7 | constructor(address impl) { 8 | _setAdmin(msg.sender); 9 | _setLogic(impl); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /contracts/proxy/luca_proxy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "./proxy.sol"; 5 | 6 | contract LucaPorxy is basePorxy{ 7 | constructor(address impl) { 8 | _setAdmin(msg.sender); 9 | _setLogic(impl); 10 | } 11 | } -------------------------------------------------------------------------------- /contracts/proxy/pledge_proxy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | import "./proxy.sol"; 4 | 5 | contract PledgePorxy is basePorxy{ 6 | constructor(address impl) { 7 | _setAdmin(msg.sender); 8 | _setLogic(impl); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /contracts/proxy/proxy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | library StorageSlot { 5 | struct AddressSlot { 6 | address value; 7 | } 8 | 9 | struct BooleanSlot { 10 | bool value; 11 | } 12 | 13 | struct Bytes32Slot { 14 | bytes32 value; 15 | } 16 | 17 | struct Uint256Slot { 18 | uint256 value; 19 | } 20 | 21 | function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { 22 | assembly { 23 | r.slot := slot 24 | } 25 | } 26 | 27 | function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { 28 | assembly { 29 | r.slot := slot 30 | } 31 | } 32 | 33 | 34 | function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { 35 | assembly { 36 | r.slot := slot 37 | } 38 | } 39 | 40 | 41 | function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { 42 | assembly { 43 | r.slot := slot 44 | } 45 | } 46 | } 47 | 48 | contract Proxy { 49 | //EIP1967 Impl_solt: keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1 50 | bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; 51 | //EIP1967 Admin_solt: keccak-256 hash of "eip1967.proxy.admin" subtracted by 1 52 | bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; 53 | 54 | function _setAdmin(address admin_) internal { 55 | StorageSlot.getAddressSlot(_ADMIN_SLOT).value = admin_; 56 | } 57 | 58 | function _setLogic(address logic_) internal { 59 | StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = logic_; 60 | } 61 | 62 | function logic() public view returns (address) { 63 | return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; 64 | } 65 | 66 | function admin() public view returns (address) { 67 | return StorageSlot.getAddressSlot(_ADMIN_SLOT).value; 68 | } 69 | 70 | 71 | fallback () external payable { 72 | assembly { 73 | let impl := sload(_IMPLEMENTATION_SLOT) 74 | calldatacopy(0, 0, calldatasize()) 75 | let result := delegatecall(gas(), impl, 0, calldatasize(), 0, 0) 76 | returndatacopy(0, 0, returndatasize()) 77 | switch result 78 | case 0 { revert(0, returndatasize()) } 79 | default { return(0, returndatasize()) } 80 | } 81 | } 82 | 83 | receive () external payable virtual {} 84 | } 85 | 86 | 87 | contract basePorxy is Proxy { 88 | event Upgraded(address indexed impl); 89 | event AdminChanged(address preAdmin, address newAdmin); 90 | 91 | modifier onlyAmdin(){ 92 | require(msg.sender == admin(), "LucaPorxy: Caller not admin"); 93 | _; 94 | } 95 | 96 | function changeAdmin(address newAdmin) external onlyAmdin returns(bool) { 97 | _setAdmin(newAdmin); 98 | emit AdminChanged(admin(), newAdmin); 99 | return true; 100 | } 101 | 102 | function upgrad(address newLogic) external onlyAmdin returns(bool) { 103 | _setLogic(newLogic); 104 | emit Upgraded(newLogic); 105 | return true; 106 | } 107 | } -------------------------------------------------------------------------------- /contracts/proxy/rebaser_proxy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "./proxy.sol"; 5 | 6 | contract RebaserPorxy is basePorxy{ 7 | constructor(address impl) { 8 | _setAdmin(msg.sender); 9 | _setLogic(impl); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /contracts/proxy/trader_proxy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "./proxy.sol"; 5 | 6 | contract TraderPorxy is basePorxy{ 7 | constructor(address impl) { 8 | _setAdmin(msg.sender); 9 | _setLogic(impl); 10 | } 11 | } -------------------------------------------------------------------------------- /contracts/token/agt.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "./erc20.sol"; 5 | contract AGT is ERC20{ 6 | address public owner; 7 | address public minter; 8 | 9 | constructor() ERC20("ATM Governance Token", "AGT", 18){ 10 | owner = msg.sender; 11 | } 12 | 13 | function setOwner(address user) external{ 14 | require(msg.sender == owner, "GTA: only owner"); 15 | require(user != address(0), "user address cannot be 0"); 16 | owner = user; 17 | } 18 | 19 | function setMinter(address user) external{ 20 | require(msg.sender == owner, "GTA: only owner"); 21 | require(user != address(0), "user address cannot be 0"); 22 | minter = user; 23 | } 24 | 25 | function mint(address to, uint256 value) external{ 26 | require(msg.sender == minter, "GTA: only minter"); 27 | _mint(to, value); 28 | } 29 | 30 | function burn(uint256 amount) external{ 31 | _burn(amount); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /contracts/token/erc20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.0; 4 | 5 | library SafeMath { 6 | function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { 7 | unchecked { 8 | uint256 c = a + b; 9 | if (c < a) return (false, 0); 10 | return (true, c); 11 | } 12 | } 13 | function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { 14 | unchecked { 15 | if (b > a) return (false, 0); 16 | return (true, a - b); 17 | } 18 | } 19 | function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { 20 | unchecked { 21 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 22 | // benefit is lost if 'b' is also tested. 23 | // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 24 | if (a == 0) return (true, 0); 25 | uint256 c = a * b; 26 | if (c / a != b) return (false, 0); 27 | return (true, c); 28 | } 29 | } 30 | 31 | function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { 32 | unchecked { 33 | if (b == 0) return (false, 0); 34 | return (true, a / b); 35 | } 36 | } 37 | 38 | function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { 39 | unchecked { 40 | if (b == 0) return (false, 0); 41 | return (true, a % b); 42 | } 43 | } 44 | 45 | 46 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 47 | return a + b; 48 | } 49 | 50 | 51 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 52 | return a - b; 53 | } 54 | 55 | 56 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 57 | return a * b; 58 | } 59 | 60 | 61 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 62 | return a / b; 63 | } 64 | 65 | 66 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 67 | return a % b; 68 | } 69 | 70 | 71 | function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 72 | unchecked { 73 | require(b <= a, errorMessage); 74 | return a - b; 75 | } 76 | } 77 | 78 | 79 | function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 80 | unchecked { 81 | require(b > 0, errorMessage); 82 | return a / b; 83 | } 84 | } 85 | 86 | 87 | function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 88 | unchecked { 89 | require(b > 0, errorMessage); 90 | return a % b; 91 | } 92 | } 93 | } 94 | 95 | contract ERC20 { 96 | using SafeMath for uint256; 97 | 98 | string public name; 99 | string public symbol; 100 | uint8 public decimals; 101 | uint256 public totalSupply; 102 | 103 | mapping (address => uint256) private balances; 104 | mapping (address => mapping (address => uint256)) private allowances; 105 | 106 | event Transfer(address indexed from, address indexed to, uint256 value); 107 | event Approval(address indexed owner, address indexed spender, uint256 value); 108 | 109 | constructor (string memory _name, string memory _symbol, uint8 _decimals) { 110 | name = _name; 111 | symbol = _symbol; 112 | decimals = _decimals; 113 | } 114 | 115 | function balanceOf(address owner) public view returns (uint256) { 116 | return balances[owner]; 117 | } 118 | 119 | function allowance(address owner, address spender) public view returns(uint256) { 120 | return allowances[owner][spender]; 121 | } 122 | 123 | function approve(address spender, uint256 amount) external returns(bool) { 124 | allowances[msg.sender][spender] = amount; 125 | emit Approval(msg.sender, spender, amount); 126 | return true; 127 | } 128 | 129 | function transfer(address to, uint256 amount) external returns (bool) { 130 | _transfer(msg.sender, to, amount); 131 | return true; 132 | } 133 | 134 | function transferFrom(address owner, address to, uint256 amount) external returns(bool) { 135 | require(allowances[owner][msg.sender] >= amount, "ERC20: transfer amount exceeds allowance"); 136 | allowances[owner][msg.sender] = allowances[owner][msg.sender].sub(amount); 137 | _transfer(owner, to, amount); 138 | return true; 139 | } 140 | 141 | function _transfer(address from, address to, uint256 amount) internal { 142 | require(to != address(0), "to address cannot be 0"); 143 | balances[from] = balances[from].sub(amount); 144 | balances[to] = balances[to].add(amount); 145 | emit Transfer(from, to, amount); 146 | } 147 | 148 | function _mint(address to, uint256 amount) internal { 149 | require(to != address(0), "to address cannot be 0"); 150 | balances[to] = balances[to].add(amount); 151 | totalSupply = totalSupply.add(amount); 152 | emit Transfer(address(0), to, amount); 153 | } 154 | 155 | function _burn(uint256 amount) internal { 156 | balances[msg.sender] = balances[msg.sender].sub(amount); 157 | totalSupply = totalSupply.sub(amount); 158 | emit Transfer(msg.sender, address(0), amount); 159 | } 160 | } 161 | 162 | -------------------------------------------------------------------------------- /contracts/token/luca.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | library SafeMath { 5 | function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { 6 | unchecked { 7 | uint256 c = a + b; 8 | if (c < a) return (false, 0); 9 | return (true, c); 10 | } 11 | } 12 | function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { 13 | unchecked { 14 | if (b > a) return (false, 0); 15 | return (true, a - b); 16 | } 17 | } 18 | function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { 19 | unchecked { 20 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 21 | // benefit is lost if 'b' is also tested. 22 | // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 23 | if (a == 0) return (true, 0); 24 | uint256 c = a * b; 25 | if (c / a != b) return (false, 0); 26 | return (true, c); 27 | } 28 | } 29 | 30 | function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { 31 | unchecked { 32 | if (b == 0) return (false, 0); 33 | return (true, a / b); 34 | } 35 | } 36 | 37 | function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { 38 | unchecked { 39 | if (b == 0) return (false, 0); 40 | return (true, a % b); 41 | } 42 | } 43 | 44 | 45 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 46 | return a + b; 47 | } 48 | 49 | 50 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 51 | return a - b; 52 | } 53 | 54 | 55 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 56 | return a * b; 57 | } 58 | 59 | 60 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 61 | return a / b; 62 | } 63 | 64 | 65 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 66 | return a % b; 67 | } 68 | 69 | 70 | function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 71 | unchecked { 72 | require(b <= a, errorMessage); 73 | return a - b; 74 | } 75 | } 76 | 77 | 78 | function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 79 | unchecked { 80 | require(b > 0, errorMessage); 81 | return a / b; 82 | } 83 | } 84 | 85 | 86 | function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 87 | unchecked { 88 | require(b > 0, errorMessage); 89 | return a % b; 90 | } 91 | } 92 | } 93 | 94 | interface IERC20 { 95 | function totalSupply() external view returns (uint256); 96 | function balanceOf(address account) external view returns (uint256); 97 | function transfer(address recipient, uint256 amount) external returns (bool); 98 | function allowance(address owner, address spender) external view returns (uint256); 99 | function approve(address spender, uint256 amount) external returns (bool); 100 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 101 | event Transfer(address indexed from, address indexed to, uint256 value); 102 | event Approval(address indexed owner, address indexed spender, uint256 value); 103 | } 104 | 105 | contract Initialized { 106 | bool internal initialized; 107 | 108 | modifier noInit(){ 109 | require(!initialized, "initialized"); 110 | _; 111 | initialized = true; 112 | } 113 | } 114 | 115 | contract Storage is Initialized{ 116 | //ERC20 pubilc variables 117 | string public name; 118 | string public symbol; 119 | uint8 public decimals; 120 | 121 | //manager 122 | address public owner; 123 | address public rebaser; 124 | address public minter; 125 | address public receiver; 126 | 127 | //Factor 128 | uint256 public scalingFactor; 129 | uint256 internal fragment; 130 | uint256 internal _totalSupply; 131 | uint256 constant Decimals = 10**24; 132 | uint256 constant BASE = 10**18; 133 | 134 | mapping (address => uint256) internal fragmentBalances; 135 | mapping (address => mapping (address => uint256)) internal allowedFragments; 136 | 137 | 138 | //modifier 139 | modifier onlyRebaser() { 140 | require(msg.sender == rebaser, "LUCA: only rebaser"); 141 | _; 142 | } 143 | 144 | modifier onlyOwner(){ 145 | require(msg.sender == owner, "LUCA: only owner"); 146 | _; 147 | } 148 | 149 | modifier onlyMinter() { 150 | require(msg.sender == minter, "LUCA: only minter"); 151 | _; 152 | } 153 | } 154 | 155 | interface ILuca is IERC20{ 156 | //event 157 | event Rebase(uint256 epoch, uint256 indexDelta, bool positive); 158 | 159 | //luca core 160 | function mint(uint256 amount) external; 161 | function burn(uint256 amount) external; 162 | function rebase(uint256 epoch, uint256 indexDelta, bool positive) external returns (uint256); 163 | function rebaseByMilli(uint256 epoch, uint256 milli, bool positive) external returns (uint256); 164 | 165 | //query 166 | function lucaToFragment(uint256 value) external view returns (uint256); 167 | function fragmentToLuca(uint256 value) external view returns (uint256); 168 | 169 | //manager 170 | function setMinter(address user) external; 171 | function setReceiver(address user) external; 172 | function setRebaser(address user) external; 173 | } 174 | 175 | contract Token is Storage, IERC20{ 176 | using SafeMath for uint256; 177 | 178 | //IERC20 179 | function totalSupply() override external view returns (uint256){ 180 | return _totalSupply; 181 | } 182 | 183 | function transfer(address to, uint256 value) override external returns (bool) { 184 | _transferFragment(msg.sender, to, _lucaToFragment(value)); 185 | emit Transfer(msg.sender, to, value); 186 | return true; 187 | } 188 | 189 | function transferFrom(address from, address to, uint256 value) override external returns (bool){ 190 | uint256 fragmentValue = _lucaToFragment(value); 191 | allowedFragments[from][msg.sender] = allowedFragments[from][msg.sender].sub(fragmentValue); 192 | _transferFragment(from, to, fragmentValue); 193 | emit Transfer(from, to, value); 194 | return true; 195 | } 196 | 197 | function balanceOf(address who) override external view returns (uint256){ 198 | return _fragmentToLuca(fragmentBalances[who]); 199 | } 200 | 201 | function allowance(address owner_, address spender) override external view returns (uint256){ 202 | return _fragmentToLuca(allowedFragments[owner_][spender]); 203 | } 204 | 205 | function approve(address spender, uint256 value) override external returns (bool){ 206 | uint256 fragmentValue = _lucaToFragment(value); 207 | allowedFragments[msg.sender][spender] = fragmentValue; 208 | emit Approval(msg.sender, spender, value); 209 | return true; 210 | } 211 | 212 | 213 | //internal 214 | function _mint(address to, uint256 amount) internal { 215 | require(to != address(0), "to addres cannot be 0"); 216 | _totalSupply = _totalSupply.add(amount); 217 | uint256 scaledAmount = _lucaToFragment(amount); 218 | fragment = fragment.add(scaledAmount); 219 | require(scalingFactor <= _maxScalingFactor(), "LUCA: max scaling factor too low"); 220 | fragmentBalances[to] = fragmentBalances[to].add(scaledAmount); 221 | emit Transfer(address(0), to, amount); 222 | } 223 | 224 | function _burn(address user, uint256 amount) internal { 225 | require(user != address(0), "user address cannot be 0"); 226 | _totalSupply = _totalSupply.sub(amount); 227 | uint256 scaledAmount = _lucaToFragment(amount); 228 | fragment = fragment.sub(scaledAmount); 229 | fragmentBalances[user] = fragmentBalances[user].sub(scaledAmount); 230 | emit Transfer(user ,address(0), amount); 231 | } 232 | 233 | function _transferFragment(address from, address to, uint256 value ) internal { 234 | require(to != address(0), "to address cannot be 0"); 235 | fragmentBalances[from] = fragmentBalances[from].sub(value); 236 | fragmentBalances[to] = fragmentBalances[to].add(value); 237 | } 238 | 239 | function _maxScalingFactor() internal view returns (uint256){ 240 | return (type(uint256).max).div(fragment); 241 | } 242 | 243 | function _fragmentToLuca(uint256 value) internal view returns(uint256){ 244 | return value.mul(scalingFactor).div(Decimals); 245 | } 246 | 247 | function _lucaToFragment(uint value) internal view returns (uint256){ 248 | return value.mul(Decimals).div(scalingFactor); 249 | } 250 | } 251 | 252 | contract Luca is Token, ILuca{ 253 | using SafeMath for uint256; 254 | 255 | function initialize(string memory name, string memory symbol, uint256 totalSupply) external { 256 | _initialize(name, symbol, 18, totalSupply*10**18); 257 | } 258 | 259 | function setReceiver(address user) override external onlyOwner{ 260 | require(user != address(0), "user address cannot be 0"); 261 | receiver = user; 262 | } 263 | 264 | function setMinter(address user) override external onlyOwner{ 265 | require(user != address(0), "user address cannot be 0"); 266 | minter = user; 267 | } 268 | 269 | function setRebaser(address user) override external onlyOwner{ 270 | require(user != address(0), "user address cannot be 0"); 271 | rebaser = user; 272 | } 273 | 274 | function rebaseByMilli(uint256 epoch, uint256 milli, bool positive) override external onlyRebaser returns (uint256){ 275 | require(milli < 1000, "LUCA: milli need less than 1000"); 276 | return _rebase(epoch, milli.mul(BASE).div(1000), positive); 277 | 278 | } 279 | 280 | function rebase(uint256 epoch, uint256 indexDelta, bool positive) override external onlyRebaser returns (uint256){ 281 | return _rebase(epoch, indexDelta, positive); 282 | } 283 | 284 | function mint(uint256 amount) override external onlyMinter { 285 | _mint(receiver, amount); 286 | } 287 | 288 | function burn(uint256 amount) override external { 289 | _burn(msg.sender, amount); 290 | } 291 | 292 | function fragmentToLuca(uint256 value) override external view returns (uint256){ 293 | return _fragmentToLuca(value); 294 | } 295 | 296 | function lucaToFragment(uint256 value) override external view returns (uint256){ 297 | return _lucaToFragment(value); 298 | } 299 | 300 | function _rebase(uint256 epoch, uint256 indexDelta, bool positive) internal returns (uint256){ 301 | emit Rebase(epoch, indexDelta, positive); 302 | if (indexDelta == 0) return _totalSupply; 303 | 304 | if (!positive) { 305 | require(indexDelta < BASE); 306 | scalingFactor = scalingFactor.mul(BASE.sub(indexDelta)).div(BASE); 307 | } else { 308 | uint256 newScalingFactor = scalingFactor.mul(BASE.add(indexDelta)).div(BASE); 309 | if (newScalingFactor < _maxScalingFactor()) { 310 | scalingFactor = newScalingFactor; 311 | } else { 312 | scalingFactor = _maxScalingFactor(); 313 | } 314 | } 315 | 316 | _totalSupply = _fragmentToLuca(fragment); 317 | return _totalSupply; 318 | } 319 | 320 | function _initialize(string memory _name, string memory _symbol, uint8 _decimals, uint256 _initTotalSupply) internal noInit { 321 | scalingFactor = BASE; 322 | owner = msg.sender; 323 | name = _name; 324 | symbol = _symbol; 325 | decimals = _decimals; 326 | _totalSupply = _initTotalSupply; 327 | fragment = _lucaToFragment(_initTotalSupply); 328 | fragmentBalances[msg.sender] = fragment; 329 | rebaser = owner; 330 | minter = owner; 331 | receiver = owner; 332 | } 333 | } 334 | -------------------------------------------------------------------------------- /contracts/token/wluca.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "./erc20.sol"; 5 | contract WLUCA is ERC20{ 6 | address public owner; 7 | address public minter; 8 | 9 | constructor() ERC20("wrap luca", "WLUCA", 18){ 10 | owner = msg.sender; 11 | } 12 | 13 | function setOwner(address user) external{ 14 | require(msg.sender == owner, "WLUCA: only owner"); 15 | require(user != address(0), "user address cannot be 0"); 16 | owner = user; 17 | } 18 | 19 | function setMinter(address user) external{ 20 | require(msg.sender == owner, "WLUCA: only owner"); 21 | require(user != address(0), "user address cannot be 0"); 22 | minter = user; 23 | } 24 | 25 | function mint(address to, uint256 value) external{ 26 | require(msg.sender == minter, "WLUCA: only minter"); 27 | _mint(to, value); 28 | } 29 | 30 | function burn(uint256 amount) external { 31 | _burn(amount); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /contracts/trader.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | library SafeMath { 5 | function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { 6 | unchecked { 7 | uint256 c = a + b; 8 | if (c < a) return (false, 0); 9 | return (true, c); 10 | } 11 | } 12 | function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { 13 | unchecked { 14 | if (b > a) return (false, 0); 15 | return (true, a - b); 16 | } 17 | } 18 | function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { 19 | unchecked { 20 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 21 | // benefit is lost if 'b' is also tested. 22 | // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 23 | if (a == 0) return (true, 0); 24 | uint256 c = a * b; 25 | if (c / a != b) return (false, 0); 26 | return (true, c); 27 | } 28 | } 29 | 30 | function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { 31 | unchecked { 32 | if (b == 0) return (false, 0); 33 | return (true, a / b); 34 | } 35 | } 36 | 37 | function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { 38 | unchecked { 39 | if (b == 0) return (false, 0); 40 | return (true, a % b); 41 | } 42 | } 43 | 44 | 45 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 46 | return a + b; 47 | } 48 | 49 | 50 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 51 | return a - b; 52 | } 53 | 54 | 55 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 56 | return a * b; 57 | } 58 | 59 | 60 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 61 | return a / b; 62 | } 63 | 64 | 65 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 66 | return a % b; 67 | } 68 | 69 | 70 | function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 71 | unchecked { 72 | require(b <= a, errorMessage); 73 | return a - b; 74 | } 75 | } 76 | 77 | 78 | function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 79 | unchecked { 80 | require(b > 0, errorMessage); 81 | return a / b; 82 | } 83 | } 84 | 85 | 86 | function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 87 | unchecked { 88 | require(b > 0, errorMessage); 89 | return a % b; 90 | } 91 | } 92 | } 93 | 94 | interface IERC20 { 95 | function totalSupply() external view returns (uint256); 96 | function balanceOf(address account) external view returns (uint256); 97 | function transfer(address recipient, uint256 amount) external returns (bool); 98 | function allowance(address owner, address spender) external view returns (uint256); 99 | function approve(address spender, uint256 amount) external returns (bool); 100 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 101 | } 102 | 103 | interface IMintableToken { 104 | function mint(address user, uint amount) external; 105 | function burn(uint amount) external; 106 | } 107 | 108 | interface Ifactory { 109 | function isLink(address _link) external view returns(bool); 110 | } 111 | 112 | interface Ifile { 113 | function factory() external view returns(address); 114 | function luca() external view returns(address); 115 | function wluca() external view returns(address); 116 | function agt() external view returns(address); 117 | } 118 | 119 | interface Itrader { 120 | function balance() external returns(uint256 luca, uint256 wluca); 121 | function payment(address _token, address _from, address _to, uint256 _amount) external returns(bool); 122 | function withdrawFor(address _to, uint256 _amount) external; 123 | function suck(address _to, uint256 _amount, uint256 _lockDay) external; 124 | } 125 | 126 | contract Initialize { 127 | bool private initialized; 128 | 129 | modifier noInit(){ 130 | require(!initialized, "initialized"); 131 | _; 132 | initialized = true; 133 | } 134 | } 135 | 136 | contract Trader is Initialize, Itrader{ 137 | using SafeMath for uint256; 138 | address public file; 139 | 140 | modifier verifyCaller(){ 141 | address factory = Ifile(file).factory(); 142 | require(msg.sender == factory || Ifactory(factory).isLink(msg.sender), "Trader: access denied"); 143 | _; 144 | } 145 | 146 | 147 | function initialize(address _file) external noInit { 148 | file = _file; 149 | } 150 | 151 | function balance() override external view returns(uint256 luca_balance, uint256 wluca_supply){ 152 | (address luca, address wluca) = (Ifile(file).luca(), Ifile(file).wluca()); 153 | return (IERC20(luca).balanceOf(address(this)), IERC20(wluca).totalSupply()); 154 | } 155 | 156 | //use for factory 157 | function payment(address _token, address _from, address _to, uint256 _amount) override external verifyCaller returns(bool){ 158 | (address luca, address wluca) = (Ifile(file).luca(), Ifile(file).wluca()); 159 | if (_token == luca) { 160 | IERC20(luca).transferFrom(_from, address(this), _amount); 161 | IMintableToken(wluca).mint(_to, _amount); 162 | return true; 163 | } 164 | 165 | return IERC20(_token).transferFrom(_from, _to, _amount); 166 | } 167 | 168 | 169 | //use for link 170 | function withdrawFor(address _to, uint256 _amount) override external verifyCaller { 171 | (address luca, address wluca) = (Ifile(file).luca(), Ifile(file).wluca()); 172 | require(IERC20(wluca).transferFrom(msg.sender, address(this), _amount), "Trader: not enough allowed wluca"); 173 | IMintableToken(wluca).burn(_amount); 174 | IERC20(luca).transfer(_to, _amount); 175 | } 176 | 177 | //use for airdrop agt 178 | function suck(address _to, uint256 _amount, uint256 _lockDay) override external verifyCaller { 179 | uint256 award = _amount.mul(_lockDay).div(100).div(10**18); 180 | address agt = Ifile(file).agt(); 181 | if (award > 0) IMintableToken(agt).mint(_to, award.mul(10**18)); 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /contracts/traderV2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | library SafeMath { 5 | function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { 6 | unchecked { 7 | uint256 c = a + b; 8 | if (c < a) return (false, 0); 9 | return (true, c); 10 | } 11 | } 12 | function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { 13 | unchecked { 14 | if (b > a) return (false, 0); 15 | return (true, a - b); 16 | } 17 | } 18 | function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { 19 | unchecked { 20 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 21 | // benefit is lost if 'b' is also tested. 22 | // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 23 | if (a == 0) return (true, 0); 24 | uint256 c = a * b; 25 | if (c / a != b) return (false, 0); 26 | return (true, c); 27 | } 28 | } 29 | 30 | function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { 31 | unchecked { 32 | if (b == 0) return (false, 0); 33 | return (true, a / b); 34 | } 35 | } 36 | 37 | function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { 38 | unchecked { 39 | if (b == 0) return (false, 0); 40 | return (true, a % b); 41 | } 42 | } 43 | 44 | 45 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 46 | return a + b; 47 | } 48 | 49 | 50 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 51 | return a - b; 52 | } 53 | 54 | 55 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 56 | return a * b; 57 | } 58 | 59 | 60 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 61 | return a / b; 62 | } 63 | 64 | 65 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 66 | return a % b; 67 | } 68 | 69 | 70 | function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 71 | unchecked { 72 | require(b <= a, errorMessage); 73 | return a - b; 74 | } 75 | } 76 | 77 | 78 | function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 79 | unchecked { 80 | require(b > 0, errorMessage); 81 | return a / b; 82 | } 83 | } 84 | 85 | 86 | function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 87 | unchecked { 88 | require(b > 0, errorMessage); 89 | return a % b; 90 | } 91 | } 92 | } 93 | 94 | interface IERC20 { 95 | function totalSupply() external view returns (uint256); 96 | function balanceOf(address account) external view returns (uint256); 97 | function transfer(address recipient, uint256 amount) external returns (bool); 98 | function allowance(address owner, address spender) external view returns (uint256); 99 | function approve(address spender, uint256 amount) external returns (bool); 100 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 101 | } 102 | 103 | interface IMintableToken { 104 | function mint(address user, uint amount) external; 105 | function burn(uint amount) external; 106 | } 107 | 108 | interface Ifactory { 109 | function isLink(address _link) external view returns(bool); 110 | } 111 | 112 | interface Ifile { 113 | function factory() external view returns(address); 114 | function luca() external view returns(address); 115 | function wluca() external view returns(address); 116 | function agt() external view returns(address); 117 | function crossChain() external view returns(address); 118 | } 119 | 120 | interface Itrader { 121 | function balance() external returns(uint256 luca, uint256 wluca); 122 | function payment(address _token, address _from, address _to, uint256 _amount) external returns(bool); 123 | function withdrawFor(address _to, uint256 _amount) external; 124 | function suck(address _to, uint256 _amount, uint256 _lockDay) external; 125 | function suck(address _to, uint256 _lockDay) external; 126 | } 127 | 128 | contract Initialize { 129 | bool private initialized; 130 | 131 | modifier noInit(){ 132 | require(!initialized, "initialized"); 133 | _; 134 | initialized = true; 135 | } 136 | } 137 | 138 | contract Trader is Initialize, Itrader{ 139 | using SafeMath for uint256; 140 | address public file; 141 | 142 | modifier verifyCaller(){ 143 | address factory = Ifile(file).factory(); 144 | address crossChain = Ifile(file).crossChain(); 145 | require(msg.sender == factory || Ifactory(factory).isLink(msg.sender) || msg.sender == crossChain , "Trader: access denied"); 146 | _; 147 | } 148 | 149 | 150 | function initialize(address _file) external noInit { 151 | file = _file; 152 | } 153 | 154 | function balance() override external view returns(uint256 luca_balance, uint256 wluca_supply){ 155 | (address luca, address wluca) = (Ifile(file).luca(), Ifile(file).wluca()); 156 | return (IERC20(luca).balanceOf(address(this)), IERC20(wluca).totalSupply()); 157 | } 158 | 159 | //use for factory 160 | function payment(address _token, address _from, address _to, uint256 _amount) override external verifyCaller returns(bool){ 161 | (address luca, address wluca) = (Ifile(file).luca(), Ifile(file).wluca()); 162 | if (_token == luca) { 163 | IERC20(luca).transferFrom(_from, address(this), _amount); 164 | IMintableToken(wluca).mint(_to, _amount); 165 | return true; 166 | } 167 | 168 | return IERC20(_token).transferFrom(_from, _to, _amount); 169 | } 170 | 171 | 172 | //use for link 173 | function withdrawFor(address _to, uint256 _amount) override external verifyCaller { 174 | (address luca, address wluca) = (Ifile(file).luca(), Ifile(file).wluca()); 175 | require(IERC20(wluca).transferFrom(msg.sender, address(this), _amount), "Trader: not enough allowed wluca"); 176 | IMintableToken(wluca).burn(_amount); 177 | IERC20(luca).transfer(_to, _amount); 178 | } 179 | 180 | //use for airdrop agt 181 | function suck(address _to, uint256 _amount, uint256 _lockDay) override external verifyCaller { 182 | uint256 award = _amount.mul(_lockDay).div(100).div(10**18); 183 | address agt = Ifile(file).agt(); 184 | if (award > 0) IMintableToken(agt).mint(_to, award.mul(10**18)); 185 | } 186 | 187 | //use for crossChain Matic to BSC 188 | function suck(address _to, uint256 _amount) override external verifyCaller { 189 | address agt = Ifile(file).agt(); 190 | IMintableToken(agt).mint(_to, _amount); 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /contracts/wormhole.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | contract Wormhole{ 5 | string public networkName; 6 | mapping(address => mapping(string => address)) holeRigest; 7 | 8 | event RigestHole(address indexed from, string net, address targer); 9 | 10 | constructor(string memory net) { 11 | networkName = net; 12 | } 13 | 14 | function getHole(string memory net) external view returns(address){ 15 | return holeRigest[msg.sender][net]; 16 | } 17 | 18 | function rigestHole(string memory net, address targer) external returns(bool){ 19 | holeRigest[msg.sender][net] = targer; 20 | emit RigestHole(msg.sender, net, targer); 21 | return true; 22 | } 23 | } --------------------------------------------------------------------------------