├── README.md └── contracts ├── adapters ├── 1inch │ └── OneInchAdapter.sol ├── AdapterManager.sol ├── IAdapterManager.sol ├── WavaxGateway │ └── WavaxGateway.sol ├── base │ ├── AdapterBase.sol │ └── IAdapterBase.sol ├── benqi │ ├── BenqiAdapter.sol │ └── SAVAXAdapter.sol ├── feeBox │ ├── FeeBoxAVAX.sol │ ├── FeeBoxSAVAX.sol │ └── VerifierBasic.sol ├── paraswap │ └── ParaswapAdapter.sol └── traderJoe │ ├── BankerJoeAdapter.sol │ └── TraderJoeAdapter.sol ├── common └── Basic.sol ├── core ├── accountManager │ └── AccountManager.sol ├── automation │ ├── Automation.sol │ ├── AutomationCallable.sol │ └── IAutomation.sol ├── controller │ ├── ControllerLib.sol │ ├── ControllerLibSub.sol │ ├── ControllerLink.sol │ ├── IAccount.sol │ ├── IControllerLink.sol │ └── ProxyWallet.sol └── verifier │ ├── ERC2612Verifier.sol │ ├── IERC2612Verifier.sol │ ├── ITokenApprovalVerifier.sol │ └── TokenApprovalVerifier.sol ├── interfaces ├── IToken.sol ├── IWAVAX.sol ├── benqi │ ├── IComptroller.sol │ ├── IMaximillion.sol │ ├── IQiAVAX.sol │ ├── IQiToken.sol │ └── ISAVAX.sol └── traderJoe │ ├── IJoeBar.sol │ ├── IJoeCallee.sol │ ├── IJoeFactory.sol │ ├── IJoeLens │ ├── IJToken.sol │ ├── IJWrappedNativeDelegator.sol │ ├── IJoeLens.sol │ ├── IJoetroller.sol │ ├── IMaximillion.sol │ ├── IPriceOracle.sol │ ├── IRewardDistributor.sol │ ├── IRewardDistributor_.sol │ ├── ITripleSlopeRateModelGovernance_SeedTokens.sol │ ├── ITripleSlopeRateModelMajors.sol │ └── ITripleSlopeRateModelStablecoins.sol │ ├── IJoePair.sol │ ├── IJoeRouter01.sol │ ├── IJoeRouter02.sol │ ├── IMasterChefJoeV2.sol │ ├── IMasterChefJoeV3.sol │ └── ISimpleRewardPerSecond.sol ├── timelock ├── Timelock.sol └── TimelockCallable.sol └── utils ├── AddressArrayLib.sol └── HomoraMath.sol /README.md: -------------------------------------------------------------------------------- 1 | # cian-protocol 2 | 3 | "dependencies": 4 | "@openzeppelin/contracts": "4.5.0", 5 | "@openzeppelin/contracts-upgradeable": "^4.5.2" 6 | -------------------------------------------------------------------------------- /contracts/adapters/1inch/OneInchAdapter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | import "../base/AdapterBase.sol"; 6 | 7 | contract OneInchAdapter is AdapterBase { 8 | constructor(address _adapterManager, address _timelock) 9 | AdapterBase(_adapterManager, _timelock, "1InchAdapter") 10 | {} 11 | 12 | address public constant oneInchRouter = 13 | 0x1111111254fb6c44bAC0beD2854e76F90643097d; 14 | 15 | function swap(bytes memory callArgs, uint256 amountETH) 16 | external 17 | onlyDelegation 18 | { 19 | (bool success, bytes memory returnData) = oneInchRouter.call{ 20 | value: amountETH 21 | }(callArgs); 22 | require(success, string(returnData)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /contracts/adapters/AdapterManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; 6 | import "@openzeppelin/contracts/access/Ownable.sol"; 7 | import "../utils/AddressArrayLib.sol"; 8 | import "../timelock/TimelockCallable.sol"; 9 | import "./base/IAdapterBase.sol"; 10 | import "../core/controller/IControllerLink.sol"; 11 | 12 | contract AdapterManager is TimelockCallable, Ownable { 13 | using EnumerableSet for EnumerableSet.AddressSet; 14 | using AddressArrayLib for address[]; 15 | 16 | bool public _paused; 17 | address public immutable userDatabase; 18 | uint256 public constant maxReservedBits = 16; //0 ~ 15 are reserved bits 19 | uint256 public maxIndex = maxReservedBits; 20 | EnumerableSet.AddressSet private registeredAdapters; 21 | mapping(address => bool) public suspendPermissions; 22 | mapping(address => uint256) public adaptersIndex; 23 | 24 | /** 25 | * @dev Emitted when the pause is triggered. 26 | */ 27 | event Paused(); 28 | 29 | /** 30 | * @dev Emitted when the pause is lifted. 31 | */ 32 | event Unpaused(); 33 | 34 | event AdapterRegistered(address indexed adapter, string indexed identifier); 35 | event AdapterUnregistered( 36 | address indexed adapter, 37 | string indexed identifier 38 | ); 39 | 40 | event CallOnAdapterExecuted( 41 | address vaultProxy, 42 | address indexed adapter, 43 | bytes4 indexed selector, 44 | bytes adpaterData 45 | ); 46 | 47 | event SetPauseWhiteList(address partner, bool val); 48 | 49 | constructor(address _userDatabase, address _timelock) 50 | TimelockCallable(_timelock) 51 | { 52 | userDatabase = _userDatabase; 53 | } 54 | 55 | modifier onlyUser() { 56 | require( 57 | IControllerLink(userDatabase).existing(msg.sender), 58 | "!Cian user." 59 | ); 60 | _; 61 | } 62 | 63 | modifier whenNotPaused() { 64 | _whenNotPaused(); 65 | _; 66 | } 67 | 68 | function _whenNotPaused() internal view { 69 | require(!_paused, "System is paused"); 70 | } 71 | 72 | function execute(bytes calldata callArgs) 73 | external 74 | payable 75 | onlyUser 76 | whenNotPaused 77 | returns (bytes memory) 78 | { 79 | (address adapter, , bytes4 selector, bytes memory callData) = abi 80 | .decode(callArgs, (address, uint256, bytes4, bytes)); 81 | require(adapterIsRegistered(adapter), "Adapter is not registered"); 82 | return __callOnAdapter(msg.sender, adapter, selector, callData); 83 | } 84 | 85 | function __callOnAdapter( 86 | address account, 87 | address adapter, 88 | bytes4 selector, 89 | bytes memory callArgs 90 | ) internal returns (bytes memory) { 91 | (bool success, bytes memory returnData) = adapter.call{ 92 | value: msg.value 93 | }(abi.encodeWithSelector(selector, account, callArgs)); 94 | 95 | emit CallOnAdapterExecuted(account, adapter, selector, callArgs); 96 | require(success, string(returnData)); 97 | return returnData; 98 | } 99 | 100 | function registerAdapters(address[] calldata _adapters) 101 | external 102 | onlyTimelock 103 | { 104 | require(_adapters.length > 0, "Adapter cannot be empty"); 105 | for (uint256 i; i < _adapters.length; i++) { 106 | require(_adapters[i] != address(0), "Adapter cannot be empty"); 107 | require( 108 | !adapterIsRegistered(_adapters[i]), 109 | "Adapter already registered" 110 | ); 111 | require(maxIndex < 256, "Out of length!"); 112 | registeredAdapters.add(_adapters[i]); 113 | adaptersIndex[_adapters[i]] = maxIndex++; 114 | emit AdapterRegistered( 115 | _adapters[i], 116 | IAdapterBase(_adapters[i]).ADAPTER_NAME() 117 | ); 118 | } 119 | } 120 | 121 | function unregisterAdapters(address[] calldata _adapters) 122 | external 123 | onlyTimelock 124 | { 125 | require(_adapters.length > 0, "Adapter cannot be empty"); 126 | 127 | for (uint256 i; i < _adapters.length; i++) { 128 | require(_adapters[i] != address(0), "Adapter cannot be empty"); 129 | 130 | require( 131 | adapterIsRegistered(_adapters[i]), 132 | "Adapter does not exist" 133 | ); 134 | 135 | registeredAdapters.remove(_adapters[i]); 136 | adaptersIndex[_adapters[i]] = 0; 137 | emit AdapterUnregistered( 138 | _adapters[i], 139 | IAdapterBase(_adapters[i]).ADAPTER_NAME() 140 | ); 141 | } 142 | } 143 | 144 | function adapterIsRegistered(address _adapter) public view returns (bool) { 145 | return registeredAdapters.contains(_adapter); 146 | } 147 | 148 | function adapterIsAvailable(address _adapter) 149 | external 150 | view 151 | whenNotPaused 152 | returns (bool) 153 | { 154 | return adapterIsRegistered(_adapter); 155 | } 156 | 157 | function getAdaptersLength() external view returns (uint256) { 158 | return registeredAdapters.length(); 159 | } 160 | 161 | function getRegisteredAdapter(uint256 i) 162 | external 163 | view 164 | returns (address adapter) 165 | { 166 | return registeredAdapters.at(i); 167 | } 168 | 169 | function setPauseWhiteList(address partner, bool val) 170 | external 171 | onlyTimelock 172 | { 173 | require(suspendPermissions[partner] != val, "No change."); 174 | suspendPermissions[partner] = val; 175 | emit SetPauseWhiteList(partner, val); 176 | } 177 | 178 | function setPause(bool val) external { 179 | if (val == true) { 180 | require( 181 | suspendPermissions[msg.sender] || msg.sender == owner(), 182 | "verification failed." 183 | ); 184 | } else { 185 | require(msg.sender == TIMELOCK_ADDRESS, "verification failed."); 186 | } 187 | _paused = val; 188 | if (_paused) { 189 | emit Paused(); 190 | } else { 191 | emit Unpaused(); 192 | } 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /contracts/adapters/IAdapterManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface IAdapterManager { 6 | function execute(bytes calldata callArgs) 7 | external 8 | payable 9 | returns (bytes memory); 10 | 11 | function maxReservedBits() external view returns (uint256); 12 | 13 | function adaptersIndex(address adapter) external view returns (uint256); 14 | 15 | function maxIndex() external view returns (uint256); 16 | 17 | function adapterIsAvailable(address) external view returns (bool); 18 | } 19 | -------------------------------------------------------------------------------- /contracts/adapters/WavaxGateway/WavaxGateway.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | import "../base/AdapterBase.sol"; 6 | import "../../interfaces/IWAVAX.sol"; 7 | 8 | contract WavaxGateway is AdapterBase { 9 | constructor(address _adapterManager, address _timelock) 10 | AdapterBase(_adapterManager, _timelock, "WavaxGateway") 11 | {} 12 | 13 | function deposit(uint256 amount) external onlyDelegation { 14 | require(amount > 0, "deposit amount error."); 15 | IWAVAX(payable(wavaxAddr)).deposit{value: amount}(); 16 | } 17 | 18 | function withdraw(uint256 amount) external onlyDelegation { 19 | require(amount > 0, "withdraw amount error."); 20 | IWAVAX(wavaxAddr).withdraw(amount); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /contracts/adapters/base/AdapterBase.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | import "@openzeppelin/contracts/access/Ownable.sol"; 6 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 7 | import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 8 | import "../../timelock/TimelockCallable.sol"; 9 | import "../../common/Basic.sol"; 10 | 11 | abstract contract AdapterBase is Basic, Ownable, TimelockCallable { 12 | using SafeERC20 for IERC20; 13 | 14 | address public ADAPTER_MANAGER; 15 | address public immutable ADAPTER_ADDRESS; 16 | string public ADAPTER_NAME; 17 | mapping(address => mapping(address => bool)) private approved; 18 | 19 | receive() external payable {} 20 | 21 | modifier onlyAdapterManager() { 22 | require( 23 | ADAPTER_MANAGER == msg.sender, 24 | "Caller is not the adapterManager." 25 | ); 26 | _; 27 | } 28 | 29 | modifier onlyDelegation() { 30 | require(ADAPTER_ADDRESS != address(this), "Only for delegatecall."); 31 | _; 32 | } 33 | 34 | constructor( 35 | address _adapterManager, 36 | address _timelock, 37 | string memory _name 38 | ) TimelockCallable(_timelock) { 39 | ADAPTER_MANAGER = _adapterManager; 40 | ADAPTER_ADDRESS = address(this); 41 | ADAPTER_NAME = _name; 42 | } 43 | 44 | function pullTokensIfNeeded( 45 | address _token, 46 | address _from, 47 | uint256 _amount 48 | ) internal { 49 | if (_amount == 0) return; 50 | require(_token != address(0) && _token != avaxAddr); 51 | uint256 balance = IERC20(_token).balanceOf(_from); 52 | uint256 currentAmount = balance < _amount ? balance : _amount; 53 | IERC20(_token).safeTransferFrom(_from, address(this), currentAmount); 54 | } 55 | 56 | function approveToken( 57 | address _token, 58 | address _spender, 59 | uint256 _amount 60 | ) internal { 61 | if (_amount == 0) return; 62 | if (!approved[_token][_spender]) { 63 | IERC20 token = IERC20(_token); 64 | token.safeApprove(_spender, 0); 65 | token.safeApprove(_spender, type(uint256).max); 66 | approved[_token][_spender] = true; 67 | } 68 | } 69 | 70 | /// @dev get the token from sender, and approve to the user in one step 71 | function pullAndApprove( 72 | address _token, 73 | address _from, 74 | address _spender, 75 | uint256 _amount 76 | ) internal { 77 | pullTokensIfNeeded(_token, _from, _amount); 78 | approveToken(_token, _spender, _amount); 79 | } 80 | 81 | function returnAsset( 82 | address _token, 83 | address _to, 84 | uint256 _amount 85 | ) internal { 86 | if (_amount > 0) { 87 | if (_token == avaxAddr) { 88 | safeTransferAVAX(_to, _amount); 89 | } else { 90 | require(_token != address(0), "Token error!"); 91 | IERC20(_token).safeTransfer(_to, _amount); 92 | } 93 | } 94 | } 95 | 96 | function toCallback( 97 | address _target, 98 | bytes4 _selector, 99 | bytes memory _callData 100 | ) internal { 101 | (bool success, bytes memory returnData) = _target.call( 102 | abi.encodePacked(_selector, _callData) 103 | ); 104 | require(success, string(returnData)); 105 | } 106 | 107 | //Handle when someone else accidentally transfers assets to this contract 108 | function sweep(address[] memory tokens, address receiver) 109 | external 110 | onlyTimelock 111 | { 112 | require(address(this) == ADAPTER_ADDRESS, "!Invalid call"); 113 | for (uint256 i = 0; i < tokens.length; i++) { 114 | address token = tokens[i]; 115 | if (token == address(0)) continue; 116 | uint256 amount = IERC20(token).balanceOf(address(this)); 117 | if (amount > 0) { 118 | IERC20(token).safeTransfer(receiver, amount); 119 | } 120 | } 121 | 122 | uint256 balance = address(this).balance; 123 | if (balance > 0) { 124 | safeTransferAVAX(receiver, balance); 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /contracts/adapters/base/IAdapterBase.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface IAdapterBase { 6 | function ADAPTER_NAME() external pure returns (string memory); 7 | } 8 | -------------------------------------------------------------------------------- /contracts/adapters/benqi/BenqiAdapter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | import "../base/AdapterBase.sol"; 6 | import "../../interfaces/benqi/IQiToken.sol"; 7 | import "../../interfaces/benqi/IQiAVAX.sol"; 8 | import "../../interfaces/benqi/IComptroller.sol"; 9 | import "../../interfaces/traderJoe/IJoeLens/IPriceOracle.sol"; 10 | import "../../interfaces/benqi/IMaximillion.sol"; 11 | import "../../interfaces/IWAVAX.sol"; 12 | 13 | interface IBenqiAdapter { 14 | function trustQiTokenAddr(address tokenAddr) 15 | external 16 | view 17 | returns (address); 18 | } 19 | 20 | contract BenqiAdapter is AdapterBase { 21 | using SafeERC20 for IERC20; 22 | 23 | address public constant unitrollerAddr = 24 | 0x486Af39519B4Dc9a7fCcd318217352830E8AD9b4; 25 | address public constant qiAvaxAddr = 26 | 0x5C0401e81Bc07Ca70fAD469b451682c0d747Ef1c; 27 | address public constant qiMaximillionAddr = 28 | 0xd78DEd803b28A5A9C860c2cc7A4d84F611aA4Ef8; 29 | 30 | mapping(address => address) public trustQiTokenAddr; 31 | event BenqiInitialize(address[] tokenAddr, address[] qiTokenAddr); 32 | event BenqiBorrow(address qiToken, uint256 amount, address account); 33 | event BenqiRepay(address qiToken, uint256 amount, address account); 34 | event BenqiDeposit(address token, uint256 amount, address account); 35 | event BenqiWithdraw(address token, uint256 amount, address account); 36 | 37 | constructor(address _adapterManager, address _timelock) 38 | AdapterBase(_adapterManager, _timelock, "Benqi") 39 | {} 40 | 41 | function initialize( 42 | address[] calldata tokenAddrs, 43 | address[] calldata qiTokenAddrs 44 | ) external onlyTimelock { 45 | require( 46 | tokenAddrs.length > 0 && tokenAddrs.length == qiTokenAddrs.length, 47 | "Set length mismatch." 48 | ); 49 | for (uint256 i = 0; i < tokenAddrs.length; i++) { 50 | if (tokenAddrs[i] == avaxAddr || tokenAddrs[i] == wavaxAddr) { 51 | require(qiTokenAddrs[i] == qiAvaxAddr, "Token invalid."); 52 | } else { 53 | require( 54 | IQiToken(qiTokenAddrs[i]).underlying() == tokenAddrs[i], 55 | "Address mismatch." 56 | ); 57 | } 58 | (bool isMarketListed, , ) = IComptroller(unitrollerAddr).markets( 59 | qiTokenAddrs[i] 60 | ); 61 | require(isMarketListed, "!Invalid qitoken"); 62 | trustQiTokenAddr[tokenAddrs[i]] = qiTokenAddrs[i]; 63 | } 64 | 65 | emit BenqiInitialize(tokenAddrs, qiTokenAddrs); 66 | } 67 | 68 | function deposit(address tokenAddr, uint256 tokenAmount) 69 | external 70 | onlyDelegation 71 | { 72 | address qiTokenAddr = IBenqiAdapter(ADAPTER_ADDRESS).trustQiTokenAddr( 73 | tokenAddr 74 | ); 75 | require(qiTokenAddr != address(0), "Token invalid."); 76 | if (tokenAddr == avaxAddr) { 77 | IQiAVAX(qiTokenAddr).mint{value: tokenAmount}(); 78 | } else if (tokenAddr == wavaxAddr) { 79 | IWAVAX(wavaxAddr).withdraw(tokenAmount); 80 | IQiAVAX(qiTokenAddr).mint{value: tokenAmount}(); 81 | } else { 82 | require(IQiToken(qiTokenAddr).mint(tokenAmount) == 0, "!mint"); 83 | } 84 | emit BenqiDeposit(tokenAddr, tokenAmount, address(this)); 85 | } 86 | 87 | function withdraw(address account, bytes calldata encodedData) 88 | external 89 | onlyAdapterManager 90 | { 91 | (address tokenAddr, uint256 qiTokenAmount) = abi.decode( 92 | encodedData, 93 | (address, uint256) 94 | ); 95 | address qiTokenAddr = trustQiTokenAddr[tokenAddr]; 96 | require(qiTokenAddr != address(0), "Token invalid."); 97 | pullAndApprove(qiTokenAddr, account, qiTokenAddr, qiTokenAmount); 98 | uint256 amountDiff; 99 | if (tokenAddr == avaxAddr) { 100 | uint256 amountBefore = address(this).balance; 101 | require(IQiAVAX(qiTokenAddr).redeem(qiTokenAmount) == 0, "!redeem"); 102 | amountDiff = address(this).balance - amountBefore; 103 | require(amountDiff > 0, "amount error"); 104 | safeTransferAVAX(account, amountDiff); 105 | } else { 106 | IERC20 token = IERC20(tokenAddr); 107 | if (tokenAddr == wavaxAddr) { 108 | uint256 amountBefore = address(this).balance; 109 | require( 110 | IQiToken(qiTokenAddr).redeem(qiTokenAmount) == 0, 111 | "!redeem" 112 | ); 113 | amountDiff = address(this).balance - amountBefore; 114 | IWAVAX(wavaxAddr).deposit{value: amountDiff}(); 115 | } else { 116 | uint256 amountBefore = token.balanceOf(address(this)); 117 | require( 118 | IQiToken(qiTokenAddr).redeem(qiTokenAmount) == 0, 119 | "!redeem" 120 | ); 121 | amountDiff = token.balanceOf(address(this)) - amountBefore; 122 | } 123 | 124 | require(amountDiff > 0, "amount error"); 125 | token.safeTransfer(account, amountDiff); 126 | } 127 | 128 | emit BenqiWithdraw(tokenAddr, qiTokenAmount, account); 129 | } 130 | 131 | function enterMarkets(address[] memory qiTokenAddr) 132 | external 133 | onlyDelegation 134 | { 135 | IComptroller(unitrollerAddr).enterMarkets(qiTokenAddr); 136 | } 137 | 138 | function exitMarket(address qiTokenAddr) external onlyDelegation { 139 | IComptroller(unitrollerAddr).exitMarket(qiTokenAddr); 140 | } 141 | 142 | function borrow(address tokenAddr, uint256 amount) external onlyDelegation { 143 | address qiTokenAddr = IBenqiAdapter(ADAPTER_ADDRESS).trustQiTokenAddr( 144 | tokenAddr 145 | ); 146 | require(qiTokenAddr != address(0), "Token invalid."); 147 | if (tokenAddr == avaxAddr) { 148 | IQiAVAX(qiTokenAddr).borrow(amount); 149 | } else { 150 | if (tokenAddr == wavaxAddr) { 151 | require(IQiAVAX(qiTokenAddr).borrow(amount) == 0, "!borrow"); 152 | IWAVAX(wavaxAddr).deposit{value: amount}(); 153 | } else { 154 | IQiToken(qiTokenAddr).borrow(amount); 155 | } 156 | } 157 | 158 | emit BenqiBorrow(qiTokenAddr, amount, address(this)); 159 | } 160 | 161 | function repay(address tokenAddr, uint256 amount) external onlyDelegation { 162 | address qiTokenAddr = IBenqiAdapter(ADAPTER_ADDRESS).trustQiTokenAddr( 163 | tokenAddr 164 | ); 165 | require(qiTokenAddr != address(0), "Token invalid."); 166 | if (tokenAddr == avaxAddr) { 167 | if (amount == type(uint256).max) { 168 | uint256 repayValue = IQiAVAX(qiTokenAddr).borrowBalanceCurrent( 169 | address(this) 170 | ); 171 | IMaximillion(qiMaximillionAddr).repayBehalf{value: repayValue}( 172 | address(this) 173 | ); 174 | } else { 175 | IQiAVAX(qiTokenAddr).repayBorrow{value: amount}(); 176 | } 177 | } else if (tokenAddr == wavaxAddr) { 178 | if (amount == type(uint256).max) { 179 | uint256 repayValue = IQiAVAX(qiTokenAddr).borrowBalanceCurrent( 180 | address(this) 181 | ); 182 | IWAVAX(wavaxAddr).withdraw(repayValue); 183 | IMaximillion(qiMaximillionAddr).repayBehalf{value: repayValue}( 184 | address(this) 185 | ); 186 | } else { 187 | IWAVAX(wavaxAddr).withdraw(amount); 188 | IQiAVAX(qiTokenAddr).repayBorrow{value: amount}(); 189 | } 190 | } else { 191 | IQiToken(qiTokenAddr).repayBorrow(amount); 192 | } 193 | emit BenqiRepay(qiTokenAddr, amount, address(this)); 194 | } 195 | 196 | function claimRewards(uint8 rewardType) external onlyDelegation { 197 | IComptroller(unitrollerAddr).claimReward(rewardType, address(this)); 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /contracts/adapters/benqi/SAVAXAdapter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | import "../base/AdapterBase.sol"; 6 | import "../../interfaces/benqi/ISAVAX.sol"; 7 | import "../../interfaces/IWAVAX.sol"; 8 | 9 | contract SAVAXAdapter is AdapterBase { 10 | address public constant SAVAX = 0x2b2C81e08f1Af8835a78Bb2A90AE924ACE0eA4bE; 11 | address public constant WAVAX = 0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7; 12 | 13 | constructor(address _adapterManager, address _timelock) 14 | AdapterBase(_adapterManager, _timelock, "SAVAX") 15 | {} 16 | 17 | function stake(uint256 amount) external onlyDelegation { 18 | ISAVAX(SAVAX).submit{value: amount}(); 19 | } 20 | 21 | function stakeWAVAX(uint256 amount) external onlyDelegation { 22 | IWAVAX(WAVAX).withdraw(amount); 23 | ISAVAX(SAVAX).submit{value: amount}(); 24 | } 25 | 26 | function unstake(uint256 amount) external onlyDelegation { 27 | ISAVAX(SAVAX).requestUnlock(amount); 28 | } 29 | 30 | function redeem() external onlyDelegation { 31 | ISAVAX(SAVAX).redeem(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /contracts/adapters/feeBox/FeeBoxAVAX.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | import "../base/AdapterBase.sol"; 6 | import "./VerifierBasic.sol"; 7 | import "../../interfaces/IWAVAX.sol"; 8 | import "../../core/controller/IAccount.sol"; 9 | 10 | /* 11 | Users deposit some avax/wavax as gas fee to support automatic contract calls in the background 12 | */ 13 | contract Verifier is VerifierBasic { 14 | function getMessageHash( 15 | address _account, 16 | uint256 _amount, 17 | bool _access, 18 | uint256 _deadline, 19 | uint256 _nonce 20 | ) public pure returns (bytes32) { 21 | return 22 | keccak256( 23 | abi.encodePacked(_account, _amount, _access, _deadline, _nonce) 24 | ); 25 | } 26 | 27 | function verify( 28 | address _signer, 29 | address _account, 30 | uint256 _amount, 31 | bool _access, 32 | uint256 _deadline, 33 | bytes memory signature 34 | ) internal returns (bool) { 35 | require(_deadline >= block.timestamp, "Signature expired"); 36 | bytes32 messageHash = getMessageHash( 37 | _account, 38 | _amount, 39 | _access, 40 | _deadline, 41 | nonces[_account]++ 42 | ); 43 | bytes32 ethSignedMessageHash = getEthSignedMessageHash(messageHash); 44 | 45 | return recoverSigner(ethSignedMessageHash, signature) == _signer; 46 | } 47 | } 48 | 49 | contract FeeBoxAVAX is Verifier, AdapterBase { 50 | using SafeERC20 for IERC20; 51 | 52 | event FeeBoxAVAXDeposit( 53 | address account, 54 | uint256 amount, 55 | uint256 consumedAmount 56 | ); 57 | event FeeBoxAVAXWithdraw( 58 | address account, 59 | uint256 amount, 60 | uint256 consumedAmount 61 | ); 62 | 63 | address public balanceController; 64 | address public feeReceiver; 65 | 66 | mapping(address => uint256) public avaxBalance; 67 | 68 | event Initialize(address _balanceController, address _feeReceiver); 69 | event SetAdapterManager(address newAdapterManager); 70 | 71 | constructor(address _adapterManager, address _timelock) 72 | AdapterBase(_adapterManager, _timelock, "FeeBoxAVAX") 73 | {} 74 | 75 | function initialize(address _balanceController, address _feeReceiver) 76 | external 77 | onlyTimelock 78 | { 79 | balanceController = _balanceController; 80 | feeReceiver = _feeReceiver; 81 | 82 | emit Initialize(balanceController, feeReceiver); 83 | } 84 | 85 | function setAdapterManager(address newAdapterManger) external onlyTimelock { 86 | ADAPTER_MANAGER = newAdapterManger; 87 | emit SetAdapterManager(ADAPTER_MANAGER); 88 | } 89 | 90 | modifier onlySigner() { 91 | require(balanceController == msg.sender, "!Signer"); 92 | _; 93 | } 94 | 95 | function setBalance(address[] memory users, uint256[] memory balance) 96 | external 97 | onlySigner 98 | { 99 | require(users.length == balance.length, "length error!"); 100 | for (uint256 i = 0; i < users.length; i++) { 101 | avaxBalance[users[i]] = balance[i]; 102 | } 103 | } 104 | 105 | function paymentCheck(address account, uint256 consumedAmount) 106 | external 107 | onlySigner 108 | { 109 | require(avaxBalance[account] >= consumedAmount, "Insolvent!"); 110 | avaxBalance[account] -= consumedAmount; 111 | safeTransferAVAX(feeReceiver, consumedAmount); 112 | } 113 | 114 | function depositWithPermit(address account, bytes calldata encodedData) 115 | external 116 | payable 117 | onlyAdapterManager 118 | { 119 | require(tx.origin == IAccount(account).owner(), "!EOA"); 120 | ( 121 | uint256 amount, 122 | uint256 consumedAmount, 123 | bool access, 124 | uint256 deadline, 125 | bytes memory signature 126 | ) = abi.decode(encodedData, (uint256, uint256, bool, uint256, bytes)); 127 | require(access, "Not deposit method."); 128 | require( 129 | verify( 130 | balanceController, 131 | account, 132 | consumedAmount, 133 | access, 134 | deadline, 135 | signature 136 | ), 137 | "Verify failed!" 138 | ); 139 | if (amount != 0) { 140 | pullTokensIfNeeded(wavaxAddr, account, amount); 141 | IWAVAX(wavaxAddr).withdraw(amount); 142 | } 143 | require( 144 | avaxBalance[account] + amount + msg.value >= consumedAmount, 145 | "Insolvent!" 146 | ); 147 | 148 | avaxBalance[account] = 149 | avaxBalance[account] + 150 | amount + 151 | msg.value - 152 | consumedAmount; 153 | if (consumedAmount != 0) { 154 | safeTransferAVAX(feeReceiver, consumedAmount); 155 | } 156 | emit FeeBoxAVAXDeposit(account, amount + msg.value, consumedAmount); 157 | } 158 | 159 | function withdrawWithPermit(address account, bytes calldata encodedData) 160 | external 161 | onlyAdapterManager 162 | { 163 | ( 164 | bool isNative, 165 | uint256 amount, 166 | uint256 consumedAmount, 167 | bool access, 168 | uint256 deadline, 169 | bytes memory signature 170 | ) = abi.decode( 171 | encodedData, 172 | (bool, uint256, uint256, bool, uint256, bytes) 173 | ); 174 | require(!access, "Not withdraw method."); 175 | require( 176 | verify( 177 | balanceController, 178 | account, 179 | consumedAmount, 180 | access, 181 | deadline, 182 | signature 183 | ), 184 | "Verify failed!" 185 | ); 186 | 187 | require(avaxBalance[account] >= consumedAmount + amount, "Insolvent!"); 188 | avaxBalance[account] = avaxBalance[account] - amount - consumedAmount; 189 | if (isNative) { 190 | safeTransferAVAX(account, amount); 191 | } else { 192 | IWAVAX(wavaxAddr).deposit{value: amount}(); 193 | IERC20(wavaxAddr).safeTransfer(account, amount); 194 | } 195 | if (consumedAmount != 0) { 196 | safeTransferAVAX(feeReceiver, consumedAmount); 197 | } 198 | 199 | emit FeeBoxAVAXWithdraw(account, amount, consumedAmount); 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /contracts/adapters/feeBox/FeeBoxSAVAX.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | import "../base/AdapterBase.sol"; 6 | import "./VerifierBasic.sol"; 7 | import "../../interfaces/benqi/ISAVAX.sol"; 8 | import "../../core/controller/IAccount.sol"; 9 | 10 | /* 11 | Users deposit some savax as gas fee to support automatic contract calls in the background 12 | */ 13 | contract Verifier is VerifierBasic { 14 | function getMessageHash( 15 | address _account, 16 | address _token, 17 | uint256 _amount, 18 | bool _access, 19 | uint256 _deadline, 20 | uint256 _nonce 21 | ) public pure returns (bytes32) { 22 | return 23 | keccak256( 24 | abi.encodePacked( 25 | _account, 26 | _token, 27 | _amount, 28 | _access, 29 | _deadline, 30 | _nonce 31 | ) 32 | ); 33 | } 34 | 35 | function verify( 36 | address _signer, 37 | address _account, 38 | address _token, 39 | uint256 _amount, 40 | bool _access, 41 | uint256 _deadline, 42 | bytes memory signature 43 | ) internal returns (bool) { 44 | require(_deadline >= block.timestamp, "Signature expired"); 45 | bytes32 messageHash = getMessageHash( 46 | _account, 47 | _token, 48 | _amount, 49 | _access, 50 | _deadline, 51 | nonces[_account]++ 52 | ); 53 | bytes32 ethSignedMessageHash = getEthSignedMessageHash(messageHash); 54 | 55 | return recoverSigner(ethSignedMessageHash, signature) == _signer; 56 | } 57 | } 58 | 59 | contract FeeBoxSAVAX is Verifier, AdapterBase { 60 | using SafeERC20 for IERC20; 61 | 62 | event FeeBoxSAVAXDeposit( 63 | address account, 64 | uint256 amount, 65 | uint256 consumedAmount 66 | ); 67 | event FeeBoxSAVAXWithdraw( 68 | address account, 69 | uint256 amount, 70 | uint256 consumedAmount 71 | ); 72 | 73 | address public balanceController; 74 | address public feeReceiver; 75 | address public constant sAVAX = 0x2b2C81e08f1Af8835a78Bb2A90AE924ACE0eA4bE; 76 | 77 | mapping(address => uint256) public tokenBalance; 78 | 79 | event Initialize(address _balanceController, address _feeReceiver); 80 | event SetAdapterManager(address newAdapterManager); 81 | 82 | constructor(address _adapterManager, address _timelock) 83 | AdapterBase(_adapterManager, _timelock, "feeBoxSAVAX") 84 | {} 85 | 86 | function initialize(address _balanceController, address _feeReceiver) 87 | external 88 | onlyTimelock 89 | { 90 | balanceController = _balanceController; 91 | feeReceiver = _feeReceiver; 92 | emit Initialize(balanceController, feeReceiver); 93 | } 94 | 95 | function setAdapterManager(address newAdapterManger) external onlyTimelock { 96 | ADAPTER_MANAGER = newAdapterManger; 97 | emit SetAdapterManager(ADAPTER_MANAGER); 98 | } 99 | 100 | modifier onlySigner() { 101 | require(balanceController == msg.sender, "!Signer"); 102 | _; 103 | } 104 | 105 | function setBalance(address[] memory users, uint256[] memory balance) 106 | external 107 | onlySigner 108 | { 109 | require(users.length == balance.length, "length error!"); 110 | for (uint256 i = 0; i < users.length; i++) { 111 | tokenBalance[users[i]] = balance[i]; 112 | } 113 | } 114 | 115 | function _paymentCheck(address account, uint256 consumedAmount) internal { 116 | if (consumedAmount != 0) { 117 | require(tokenBalance[account] >= consumedAmount, "Insolvent!"); 118 | ISAVAX(sAVAX).transfer(feeReceiver, consumedAmount); 119 | tokenBalance[account] -= consumedAmount; 120 | } 121 | } 122 | 123 | function paymentCheck(address account, uint256 consumedAmount) 124 | external 125 | onlySigner 126 | { 127 | _paymentCheck(account, consumedAmount); 128 | } 129 | 130 | function depositWithPermit(address account, bytes calldata encodedData) 131 | external 132 | onlyAdapterManager 133 | { 134 | require(tx.origin == IAccount(account).owner(), "!EOA"); 135 | ( 136 | uint256 amount, 137 | uint256 consumedAmount, 138 | bool access, 139 | uint256 deadline, 140 | bytes memory signature 141 | ) = abi.decode(encodedData, (uint256, uint256, bool, uint256, bytes)); 142 | require(access, "Not deposit method."); 143 | require( 144 | verify( 145 | balanceController, 146 | account, 147 | sAVAX, 148 | consumedAmount, 149 | access, 150 | deadline, 151 | signature 152 | ), 153 | "Verify failed!" 154 | ); 155 | 156 | pullTokensIfNeeded(sAVAX, account, amount); 157 | tokenBalance[account] += amount; 158 | _paymentCheck(account, consumedAmount); 159 | emit FeeBoxSAVAXDeposit(account, amount, consumedAmount); 160 | } 161 | 162 | function withdrawWithPermit(address account, bytes calldata encodedData) 163 | external 164 | onlyAdapterManager 165 | { 166 | ( 167 | uint256 amount, 168 | uint256 consumedAmount, 169 | bool access, 170 | uint256 deadline, 171 | bytes memory signature 172 | ) = abi.decode(encodedData, (uint256, uint256, bool, uint256, bytes)); 173 | require(!access, "Not withdraw method."); 174 | require( 175 | verify( 176 | balanceController, 177 | account, 178 | sAVAX, 179 | consumedAmount, 180 | access, 181 | deadline, 182 | signature 183 | ), 184 | "Verify failed!" 185 | ); 186 | 187 | require(tokenBalance[account] >= amount, "Insolvent!"); 188 | tokenBalance[account] -= amount; 189 | _paymentCheck(account, consumedAmount); 190 | IERC20(sAVAX).safeTransfer(account, amount); 191 | emit FeeBoxSAVAXWithdraw(account, amount, consumedAmount); 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /contracts/adapters/feeBox/VerifierBasic.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; 6 | import "../base/AdapterBase.sol"; 7 | 8 | contract VerifierBasic { 9 | using ECDSA for bytes32; 10 | mapping(address => uint256) public nonces; 11 | 12 | function getEthSignedMessageHash(bytes32 _messageHash) 13 | public 14 | pure 15 | returns (bytes32) 16 | { 17 | return 18 | keccak256( 19 | abi.encodePacked( 20 | "\x19Ethereum Signed Message:\n32", 21 | _messageHash 22 | ) 23 | ); 24 | } 25 | 26 | function recoverSigner( 27 | bytes32 _ethSignedMessageHash, 28 | bytes memory _signature 29 | ) public pure returns (address) { 30 | (bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature); 31 | 32 | return _ethSignedMessageHash.recover(v, r, s); 33 | } 34 | 35 | function splitSignature(bytes memory sig) 36 | public 37 | pure 38 | returns ( 39 | bytes32 r, 40 | bytes32 s, 41 | uint8 v 42 | ) 43 | { 44 | require(sig.length == 65, "invalid signature length"); 45 | 46 | assembly { 47 | /* 48 | First 32 bytes stores the length of the signature 49 | 50 | add(sig, 32) = pointer of sig + 32 51 | effectively, skips first 32 bytes of signature 52 | 53 | mload(p) loads next 32 bytes starting at the memory address p into memory 54 | */ 55 | 56 | // first 32 bytes, after the length prefix 57 | r := mload(add(sig, 32)) 58 | // second 32 bytes 59 | s := mload(add(sig, 64)) 60 | // final byte (first byte of the next 32 bytes) 61 | v := byte(0, mload(add(sig, 96))) 62 | } 63 | // implicitly return (r, s, v) 64 | } 65 | 66 | function getEthBlockTimestamp() public view returns (uint256 timestamp) { 67 | timestamp = block.timestamp; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /contracts/adapters/paraswap/ParaswapAdapter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | import "../base/AdapterBase.sol"; 6 | 7 | contract ParaswapAdapter is AdapterBase { 8 | constructor(address _adapterManager, address _timelock) 9 | AdapterBase(_adapterManager, _timelock, "ParaswapAdapter") 10 | {} 11 | 12 | address public constant AugustusSwapper = 13 | 0xDEF171Fe48CF0115B1d80b88dc8eAB59176FEe57; 14 | 15 | function swap(bytes memory callArgs, uint256 amountETH) 16 | external 17 | onlyDelegation 18 | { 19 | (bool success, bytes memory returnData) = AugustusSwapper.call{ 20 | value: amountETH 21 | }(callArgs); 22 | require(success, string(returnData)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /contracts/adapters/traderJoe/BankerJoeAdapter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity >=0.8.0 <0.9.0; 3 | 4 | import "../base/AdapterBase.sol"; 5 | import "../../interfaces/traderJoe/IJoeLens/IJToken.sol"; 6 | import "../../interfaces/traderJoe/IJoeLens/IJoetroller.sol"; 7 | import "../../interfaces/traderJoe/IJoeLens/IJWrappedNativeDelegator.sol"; 8 | import "../../interfaces/traderJoe/IJoeLens/IPriceOracle.sol"; 9 | import "../../interfaces/traderJoe/IJoeLens/IMaximillion.sol"; 10 | import "../../interfaces/IWAVAX.sol"; 11 | 12 | interface IBankerJoeAdapter { 13 | function trustJTokenAddr(address tokenAddr) external view returns (address); 14 | } 15 | 16 | contract BankerJoeAdapter is AdapterBase { 17 | using SafeERC20 for IERC20; 18 | 19 | address public constant JoetrollerAddr = 20 | 0xdc13687554205E5b89Ac783db14bb5bba4A1eDaC; 21 | IJoetroller internal Joetroller = IJoetroller(JoetrollerAddr); 22 | 23 | address public constant joeMaximillionAddr = 24 | 0xe5cDdAFd0f7Af3DEAf4bd213bBaee7A5927AB7E7; 25 | 26 | mapping(address => address) public trustJTokenAddr; 27 | 28 | constructor(address _adapterManager, address _timelock) 29 | AdapterBase(_adapterManager, _timelock, "BankerJoe") 30 | {} 31 | 32 | event BankerJoeInitialize(address[] tokenAddr, address[] jTokenAddr); 33 | event TraderJoeSupplyEvent( 34 | address token, 35 | address joeToken, 36 | uint256 amount, 37 | address account 38 | ); 39 | 40 | event TraderJoeWithdrawEvent( 41 | address token, 42 | address joeToken, 43 | uint256 amount, 44 | address account 45 | ); 46 | 47 | event TraderJoeBorrowEvent( 48 | address joeToken, 49 | uint256 amount, 50 | address account 51 | ); 52 | event TraderJoeRepayEvent( 53 | address joeToken, 54 | uint256 amount, 55 | address account 56 | ); 57 | 58 | function initialize( 59 | address[] calldata tokenAddrs, 60 | address[] calldata jTokenAddrs 61 | ) external onlyTimelock { 62 | require( 63 | tokenAddrs.length > 0 && tokenAddrs.length == jTokenAddrs.length, 64 | "Set length mismatch." 65 | ); 66 | for (uint256 i = 0; i < tokenAddrs.length; i++) { 67 | if (tokenAddrs[i] == avaxAddr) { 68 | require( 69 | IJWrappedNativeDelegator(jTokenAddrs[i]).underlying() == 70 | wavaxAddr, 71 | "Address mismatch." 72 | ); 73 | } else { 74 | require( 75 | IJToken(jTokenAddrs[i]).underlying() == tokenAddrs[i], 76 | "Address mismatch." 77 | ); 78 | } 79 | require( 80 | Joetroller.isMarketListed(jTokenAddrs[i]), 81 | "!Invalid jtoken" 82 | ); 83 | trustJTokenAddr[tokenAddrs[i]] = jTokenAddrs[i]; 84 | } 85 | 86 | emit BankerJoeInitialize(tokenAddrs, jTokenAddrs); 87 | } 88 | 89 | function deposit(address tokenAddr, uint256 tokenAmount) 90 | external 91 | onlyDelegation 92 | { 93 | address jtokenAddr = IBankerJoeAdapter(ADAPTER_ADDRESS).trustJTokenAddr( 94 | tokenAddr 95 | ); 96 | require(jtokenAddr != address(0), "Token invalid."); 97 | if (tokenAddr == avaxAddr) { 98 | require( 99 | IJWrappedNativeDelegator(jtokenAddr).underlying() == wavaxAddr, 100 | "Not AVAX." 101 | ); 102 | require( 103 | IJWrappedNativeDelegator(jtokenAddr).mintNative{ 104 | value: tokenAmount 105 | }() == 0, 106 | "!mint" 107 | ); 108 | } else { 109 | require( 110 | tokenAddr == IJToken(jtokenAddr).underlying(), 111 | "Token invalid." 112 | ); 113 | require(IJToken(jtokenAddr).mint(tokenAmount) == 0, "!mint"); 114 | } 115 | 116 | emit TraderJoeSupplyEvent( 117 | tokenAddr, 118 | jtokenAddr, 119 | tokenAmount, 120 | address(this) 121 | ); 122 | } 123 | 124 | //todo delete jtokenAddr arg 125 | function withdraw(address account, bytes calldata encodedData) 126 | external 127 | onlyAdapterManager 128 | { 129 | (address tokenAddr, uint256 jtokenAmount) = abi.decode( 130 | encodedData, 131 | (address, uint256) 132 | ); 133 | address jtokenAddr = trustJTokenAddr[tokenAddr]; 134 | require(jtokenAddr != address(0), "Token invalid."); 135 | 136 | uint256 amountDiff; 137 | if (tokenAddr == avaxAddr || tokenAddr == wavaxAddr) { 138 | require( 139 | IJWrappedNativeDelegator(jtokenAddr).underlying() == wavaxAddr, 140 | "Not AVAX." 141 | ); 142 | pullAndApprove(jtokenAddr, account, jtokenAddr, jtokenAmount); 143 | uint256 amountBefore = address(this).balance; 144 | require( 145 | IJWrappedNativeDelegator(jtokenAddr).redeemNative( 146 | jtokenAmount 147 | ) == 0, 148 | "!redeem" 149 | ); 150 | amountDiff = address(this).balance - amountBefore; 151 | require(amountDiff >= 0, "amount error"); 152 | if (tokenAddr == avaxAddr) { 153 | safeTransferAVAX(account, amountDiff); 154 | } else { 155 | IWAVAX(wavaxAddr).deposit{value: amountDiff}(); 156 | IWAVAX(wavaxAddr).transfer(account, amountDiff); 157 | } 158 | } else { 159 | require( 160 | IJToken(jtokenAddr).underlying() == tokenAddr, 161 | "Not token." 162 | ); 163 | pullAndApprove(jtokenAddr, account, jtokenAddr, jtokenAmount); 164 | IERC20 token = IERC20(tokenAddr); 165 | uint256 amountBefore = token.balanceOf(address(this)); 166 | 167 | require(IJToken(jtokenAddr).redeem(jtokenAmount) == 0, "!redeem"); 168 | amountDiff = token.balanceOf(address(this)) - amountBefore; 169 | require(amountDiff > 0, "amount error"); 170 | token.safeTransfer(account, amountDiff); 171 | } 172 | emit TraderJoeWithdrawEvent(tokenAddr, jtokenAddr, amountDiff, account); 173 | } 174 | 175 | function enterMarkets(address[] memory jTokenAddr) external onlyDelegation { 176 | IJoetroller(JoetrollerAddr).enterMarkets(jTokenAddr); 177 | } 178 | 179 | function exitMarket(address jTokenAddr) external onlyDelegation { 180 | IJoetroller(JoetrollerAddr).exitMarket(jTokenAddr); 181 | } 182 | 183 | function borrow(address tokenAddr, uint256 amount) external onlyDelegation { 184 | address jtokenAddr = IBankerJoeAdapter(ADAPTER_ADDRESS).trustJTokenAddr( 185 | tokenAddr 186 | ); 187 | require(jtokenAddr != address(0), "Token invalid."); 188 | 189 | if (tokenAddr == avaxAddr) { 190 | require( 191 | IJWrappedNativeDelegator(jtokenAddr).borrowNative(amount) == 0, 192 | "!borrow" 193 | ); 194 | } else { 195 | require(IJToken(jtokenAddr).borrow(amount) == 0, "!borrow"); 196 | } 197 | 198 | emit TraderJoeBorrowEvent(jtokenAddr, amount, address(this)); 199 | } 200 | 201 | function repay(address tokenAddr, uint256 amount) external onlyDelegation { 202 | address jtokenAddr = IBankerJoeAdapter(ADAPTER_ADDRESS).trustJTokenAddr( 203 | tokenAddr 204 | ); 205 | require(jtokenAddr != address(0), "Token invalid."); 206 | if (tokenAddr == avaxAddr) { 207 | if (amount == type(uint256).max) { 208 | uint256 repayValue = IJWrappedNativeDelegator(jtokenAddr) 209 | .borrowBalanceCurrent(address(this)); 210 | IMaximillion(joeMaximillionAddr).repayBehalf{value: repayValue}( 211 | address(this) 212 | ); 213 | } else { 214 | IJWrappedNativeDelegator(jtokenAddr).repayBorrowNative{ 215 | value: amount 216 | }(); 217 | } 218 | } else { 219 | IJToken(jtokenAddr).repayBorrow(amount); 220 | } 221 | 222 | emit TraderJoeRepayEvent(jtokenAddr, amount, address(this)); 223 | } 224 | 225 | function claimReward(uint8 rewardType, address holder) 226 | external 227 | onlyDelegation 228 | { 229 | IJoetroller(JoetrollerAddr).claimReward(rewardType, holder); 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /contracts/adapters/traderJoe/TraderJoeAdapter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity >=0.8.0 <0.9.0; 3 | 4 | import "../base/AdapterBase.sol"; 5 | import "../../interfaces/traderJoe/IJoeLens/IJToken.sol"; 6 | import "../../interfaces/traderJoe/IMasterChefJoeV2.sol"; 7 | import "../../interfaces/traderJoe/IJoeBar.sol"; 8 | import "../../interfaces/traderJoe/IJoeFactory.sol"; 9 | import "../../interfaces/traderJoe/IJoeRouter02.sol"; 10 | import "../../interfaces/traderJoe/IJoePair.sol"; 11 | import "../../interfaces/IWAVAX.sol"; 12 | import "../../utils/HomoraMath.sol"; 13 | 14 | interface ITraderJoeAdapter { 15 | function isTrustMasterChef(address tokenAddr) external view returns (bool); 16 | } 17 | 18 | contract TraderJoeAdapter is AdapterBase { 19 | using SafeERC20 for IERC20; 20 | 21 | address public constant routerAddr = 22 | 0x60aE616a2155Ee3d9A68541Ba4544862310933d4; 23 | IJoeRouter02 internal constant router = IJoeRouter02(routerAddr); 24 | 25 | mapping(address => bool) public isTrustMasterChef; 26 | 27 | constructor(address _adapterManager, address _timelock) 28 | AdapterBase(_adapterManager, _timelock, "TraderJoe") 29 | {} 30 | 31 | event TraderJoeInitialize(address[] masterChefs); 32 | 33 | event TraderJoeFarmEvent( 34 | address farmAddress, 35 | address account, 36 | uint256 amount, 37 | uint256 pid 38 | ); 39 | 40 | event TraderJoeUnFarmEvent( 41 | address farmAddress, 42 | address account, 43 | uint256 amount, 44 | uint256 pid 45 | ); 46 | 47 | event TraderJoeEmergencyWithdrawEvent( 48 | address farmAddress, 49 | address account, 50 | uint256 pid 51 | ); 52 | 53 | event TraderJoeAddLiquidityEvent( 54 | uint256 liquidity, 55 | address token0, 56 | address token1, 57 | uint256 amount0, 58 | uint256 amount1, 59 | address account 60 | ); 61 | 62 | event TraderJoeRemoveLiquidityEvent( 63 | address token0, 64 | address token1, 65 | uint256 amount, 66 | uint256 amount0, 67 | uint256 amount1, 68 | address account 69 | ); 70 | 71 | function initialize(address[] calldata masterChefs) external onlyTimelock { 72 | for (uint256 i = 0; i < masterChefs.length; i++) { 73 | isTrustMasterChef[masterChefs[i]] = true; 74 | } 75 | 76 | emit TraderJoeInitialize(masterChefs); 77 | } 78 | 79 | function swapTokensForExactTokens( 80 | address account, 81 | bytes calldata encodedData 82 | ) external onlyAdapterManager { 83 | (uint256 amountOut, uint256 amountInMax, address[] memory path) = abi 84 | .decode(encodedData, (uint256, uint256, address[])); 85 | pullAndApprove(path[0], account, routerAddr, amountInMax); 86 | uint256[] memory amounts = router.swapTokensForExactTokens( 87 | amountOut, 88 | amountInMax, 89 | path, 90 | account, 91 | block.timestamp 92 | ); 93 | returnAsset(path[0], account, amountInMax - amounts[0]); 94 | } 95 | 96 | function swapExactTokensForTokens( 97 | address account, 98 | bytes calldata encodedData 99 | ) external onlyAdapterManager { 100 | (uint256 amountIn, uint256 amountOutMin, address[] memory path) = abi 101 | .decode(encodedData, (uint256, uint256, address[])); 102 | pullAndApprove(path[0], account, routerAddr, amountIn); 103 | router.swapExactTokensForTokens( 104 | amountIn, 105 | amountOutMin, 106 | path, 107 | account, 108 | block.timestamp 109 | ); 110 | } 111 | 112 | struct addLiquidityInfo { 113 | address tokenA; 114 | address tokenB; 115 | uint256 amountA; 116 | uint256 amountB; 117 | uint256 minAmountA; 118 | uint256 minAmountB; 119 | } 120 | 121 | function addLiquidity(address account, bytes calldata encodedData) 122 | external 123 | onlyAdapterManager 124 | { 125 | addLiquidityInfo memory addInfo = abi.decode( 126 | encodedData, 127 | (addLiquidityInfo) 128 | ); 129 | pullAndApprove(addInfo.tokenA, account, routerAddr, addInfo.amountA); 130 | pullAndApprove(addInfo.tokenB, account, routerAddr, addInfo.amountB); 131 | (uint256 _amountA, uint256 _amountB, uint256 _liquidity) = router 132 | .addLiquidity( 133 | addInfo.tokenA, 134 | addInfo.tokenB, 135 | addInfo.amountA, 136 | addInfo.amountB, 137 | addInfo.minAmountA, 138 | addInfo.minAmountB, 139 | account, 140 | block.timestamp 141 | ); 142 | returnAsset(addInfo.tokenA, account, addInfo.amountA - _amountA); 143 | returnAsset(addInfo.tokenB, account, addInfo.amountB - _amountB); 144 | 145 | emit TraderJoeAddLiquidityEvent( 146 | _liquidity, 147 | addInfo.tokenA, 148 | addInfo.tokenB, 149 | _amountA, 150 | _amountB, 151 | account 152 | ); 153 | } 154 | 155 | struct removeLiquidityInfo { 156 | address tokenA; 157 | address tokenB; 158 | uint256 amount; 159 | uint256 minAmountA; 160 | uint256 minAmountB; 161 | } 162 | 163 | function removeLiquidity(address account, bytes calldata encodedData) 164 | external 165 | onlyAdapterManager 166 | { 167 | removeLiquidityInfo memory removeInfo = abi.decode( 168 | encodedData, 169 | (removeLiquidityInfo) 170 | ); 171 | address lpTokenAddr = IJoeFactory(router.factory()).getPair( 172 | removeInfo.tokenA, 173 | removeInfo.tokenB 174 | ); 175 | require(lpTokenAddr != address(0), "pair-not-found."); 176 | pullAndApprove(lpTokenAddr, account, routerAddr, removeInfo.amount); 177 | (uint256 _amountA, uint256 _amountB) = router.removeLiquidity( 178 | removeInfo.tokenA, 179 | removeInfo.tokenB, 180 | removeInfo.amount, 181 | removeInfo.minAmountA, 182 | removeInfo.minAmountB, 183 | account, 184 | block.timestamp 185 | ); 186 | emit TraderJoeRemoveLiquidityEvent( 187 | removeInfo.tokenA, 188 | removeInfo.tokenB, 189 | removeInfo.amount, 190 | _amountA, 191 | _amountB, 192 | account 193 | ); 194 | } 195 | 196 | struct addLiquidityAVAXInfo { 197 | address tokenAddr; 198 | uint256 amountTokenDesired; 199 | uint256 amountTokenMin; 200 | uint256 amountAVAXMin; 201 | } 202 | 203 | /// @dev using AVAX to add liquidity 204 | function addLiquidityAVAX(address account, bytes calldata encodedData) 205 | external 206 | payable 207 | onlyAdapterManager 208 | { 209 | addLiquidityAVAXInfo memory addInfo = abi.decode( 210 | encodedData, 211 | (addLiquidityAVAXInfo) 212 | ); 213 | pullAndApprove( 214 | addInfo.tokenAddr, 215 | account, 216 | routerAddr, 217 | addInfo.amountTokenDesired 218 | ); 219 | (uint256 _amountToken, uint256 _amountAVAX, uint256 _liquidity) = router 220 | .addLiquidityAVAX{value: msg.value}( 221 | addInfo.tokenAddr, 222 | addInfo.amountTokenDesired, 223 | addInfo.amountTokenMin, 224 | addInfo.amountAVAXMin, 225 | account, 226 | block.timestamp 227 | ); 228 | returnAsset( 229 | addInfo.tokenAddr, 230 | account, 231 | addInfo.amountTokenDesired - _amountToken 232 | ); 233 | returnAsset(avaxAddr, account, msg.value - _amountAVAX); 234 | 235 | emit TraderJoeAddLiquidityEvent( 236 | _liquidity, 237 | addInfo.tokenAddr, 238 | avaxAddr, 239 | _amountToken, 240 | _amountAVAX, 241 | account 242 | ); 243 | } 244 | 245 | struct removeLiquidityAVAXInfo { 246 | address tokenA; 247 | uint256 liquidity; 248 | uint256 amountTokenMin; 249 | uint256 amountAVAXMin; 250 | } 251 | 252 | /// @dev remove liquidity to get AVAX 253 | function removeLiquidityAVAX(address account, bytes calldata encodedData) 254 | external 255 | onlyAdapterManager 256 | { 257 | removeLiquidityAVAXInfo memory removeInfo = abi.decode( 258 | encodedData, 259 | (removeLiquidityAVAXInfo) 260 | ); 261 | address lpTokenAddr = IJoeFactory(router.factory()).getPair( 262 | removeInfo.tokenA, 263 | wavaxAddr 264 | ); 265 | pullAndApprove(lpTokenAddr, account, routerAddr, removeInfo.liquidity); 266 | (uint256 amountToken, uint256 amountAVAX) = router.removeLiquidityAVAX( 267 | removeInfo.tokenA, 268 | removeInfo.liquidity, 269 | removeInfo.amountTokenMin, 270 | removeInfo.amountAVAXMin, 271 | account, 272 | block.timestamp 273 | ); 274 | emit TraderJoeRemoveLiquidityEvent( 275 | removeInfo.tokenA, 276 | avaxAddr, 277 | removeInfo.liquidity, 278 | amountToken, 279 | amountAVAX, 280 | account 281 | ); 282 | } 283 | 284 | /// @dev traderJoe uses the same function to deposit and claim rewards, if deposit amount is 0, you will claim your rewards 285 | function depositLpToken( 286 | address masterChefAddr, 287 | uint256 pid, 288 | uint256 amount 289 | ) external onlyDelegation { 290 | require( 291 | ITraderJoeAdapter(ADAPTER_ADDRESS).isTrustMasterChef( 292 | masterChefAddr 293 | ), 294 | "!trustMasterChef" 295 | ); 296 | IMasterChefJoeV2(masterChefAddr).deposit(pid, amount); 297 | emit TraderJoeFarmEvent(masterChefAddr, address(this), amount, pid); 298 | } 299 | 300 | function emergencyWithdraw(address masterChefAddr, uint256 pid) 301 | external 302 | onlyDelegation 303 | { 304 | require( 305 | ITraderJoeAdapter(ADAPTER_ADDRESS).isTrustMasterChef( 306 | masterChefAddr 307 | ), 308 | "!trustMasterChef" 309 | ); 310 | IMasterChefJoeV2(masterChefAddr).emergencyWithdraw(pid); 311 | emit TraderJoeEmergencyWithdrawEvent( 312 | masterChefAddr, 313 | address(this), 314 | pid 315 | ); 316 | } 317 | 318 | function withdrawLpToken( 319 | address masterChefAddr, 320 | uint256 pid, 321 | uint256 amount 322 | ) external onlyDelegation { 323 | require( 324 | ITraderJoeAdapter(ADAPTER_ADDRESS).isTrustMasterChef( 325 | masterChefAddr 326 | ), 327 | "!trustMasterChef" 328 | ); 329 | IMasterChefJoeV2(masterChefAddr).withdraw(pid, amount); 330 | emit TraderJoeUnFarmEvent(masterChefAddr, address(this), amount, pid); 331 | } 332 | 333 | struct LiquidityCustomized { 334 | address tokenA; 335 | address tokenB; 336 | uint256 amtAUser; // Supplied tokenA amount 337 | uint256 amtBUser; // Supplied tokenB amount 338 | uint256 amtAMin; // Desired tokenA amount (slippage control) 339 | uint256 amtBMin; // Desired tokenB amount (slippage control) 340 | } 341 | 342 | function addLiquidityInternal( 343 | address account, 344 | uint256 balA, 345 | uint256 balB, 346 | LiquidityCustomized memory liquidity 347 | ) internal returns (uint256 _amountA, uint256 _amountB) { 348 | (_amountA, _amountB, ) = router.addLiquidity( 349 | liquidity.tokenA, 350 | liquidity.tokenB, 351 | balA, 352 | balB, 353 | liquidity.amtAMin, 354 | liquidity.amtBMin, 355 | account, 356 | block.timestamp 357 | ); 358 | } 359 | 360 | function addLiquidityCustomized(address account, bytes calldata encodedData) 361 | external 362 | payable 363 | onlyAdapterManager 364 | { 365 | LiquidityCustomized memory liquidity = abi.decode( 366 | encodedData, 367 | (LiquidityCustomized) 368 | ); 369 | pullTokensIfNeeded(liquidity.tokenA, account, liquidity.amtAUser); 370 | pullTokensIfNeeded(liquidity.tokenB, account, liquidity.amtBUser); 371 | 372 | (uint256 swapAmt, uint256 swapAmtGet, bool isReversed) = autoSwap( 373 | liquidity 374 | ); 375 | 376 | (uint256 balA, uint256 balB) = isReversed 377 | ? (liquidity.amtAUser + swapAmtGet, liquidity.amtBUser - swapAmt) 378 | : (liquidity.amtAUser - swapAmt, liquidity.amtBUser + swapAmtGet); 379 | 380 | approveToken(liquidity.tokenA, routerAddr, balA); 381 | approveToken(liquidity.tokenB, routerAddr, balB); 382 | (uint256 amountA, uint256 amountB) = addLiquidityInternal( 383 | account, 384 | balA, 385 | balB, 386 | liquidity 387 | ); 388 | returnAsset(liquidity.tokenA, account, balA - amountA); 389 | returnAsset(liquidity.tokenB, account, balB - amountB); 390 | } 391 | 392 | function autoSwap(LiquidityCustomized memory liquidity) 393 | internal 394 | returns ( 395 | uint256 swapAmt, 396 | uint256 swapAmtGet, 397 | bool isReversed 398 | ) 399 | { 400 | uint256 resA; 401 | uint256 resB; 402 | address lp = IJoeFactory(router.factory()).getPair( 403 | liquidity.tokenA, 404 | liquidity.tokenB 405 | ); 406 | if (IJoePair(lp).token0() == liquidity.tokenA) { 407 | (resA, resB, ) = IJoePair(lp).getReserves(); 408 | } else { 409 | (resB, resA, ) = IJoePair(lp).getReserves(); 410 | } 411 | (swapAmt, isReversed) = optimalDeposit( 412 | liquidity.amtAUser, 413 | liquidity.amtBUser, 414 | resA, 415 | resB 416 | ); 417 | 418 | if (swapAmt > 0) { 419 | address[] memory path = new address[](2); 420 | (path[0], path[1]) = isReversed 421 | ? (liquidity.tokenB, liquidity.tokenA) 422 | : (liquidity.tokenA, liquidity.tokenB); 423 | approveToken(path[0], routerAddr, swapAmt); 424 | uint256[] memory tokenAmounts = router.swapExactTokensForTokens( 425 | swapAmt, 426 | 0, 427 | path, 428 | address(this), 429 | block.timestamp 430 | ); 431 | swapAmtGet = tokenAmounts[1]; 432 | } 433 | } 434 | 435 | /// @dev Compute optimal deposit amount 436 | /// @param amtA amount of token A desired to deposit 437 | /// @param amtB amount of token B desired to deposit 438 | /// @param resA amount of token A in reserve 439 | /// @param resB amount of token B in reserve 440 | function optimalDeposit( 441 | uint256 amtA, 442 | uint256 amtB, 443 | uint256 resA, 444 | uint256 resB 445 | ) internal pure returns (uint256 swapAmt, bool isReversed) { 446 | if (amtA * resB >= amtB * resA) { 447 | swapAmt = _optimalDepositA(amtA, amtB, resA, resB); 448 | isReversed = false; 449 | } else { 450 | swapAmt = _optimalDepositA(amtB, amtA, resB, resA); 451 | isReversed = true; 452 | } 453 | } 454 | 455 | /// @dev Compute optimal deposit amount helper. 456 | /// @param amtA amount of token A desired to deposit 457 | /// @param amtB amount of token B desired to deposit 458 | /// @param resA amount of token A in reserve 459 | /// @param resB amount of token B in reserve 460 | /// Formula: https://blog.alphafinance.io/byot/ 461 | function _optimalDepositA( 462 | uint256 amtA, 463 | uint256 amtB, 464 | uint256 resA, 465 | uint256 resB 466 | ) internal pure returns (uint256) { 467 | require(amtA * resB >= amtB * resA, "Reversed"); 468 | uint256 a = 997; 469 | uint256 b = uint256(1997) * resA; 470 | uint256 _c = (amtA * resB) - (amtB * resA); 471 | uint256 c = ((_c * 1000) / (amtB + resB)) * resA; 472 | uint256 d = a * c * 4; 473 | uint256 e = HomoraMath.sqrt(b * b + d); 474 | uint256 numerator = e - b; 475 | uint256 denominator = a * 2; 476 | return numerator / denominator; 477 | } 478 | 479 | struct LiquidityFromOneToken { 480 | address sourceToken; 481 | address tokenA; 482 | address[] pathA; 483 | address tokenB; 484 | address[] pathB; 485 | uint256 amtSource; 486 | uint256 amtAMin; // Desired tokenA amount (slippage control) 487 | uint256 amtBMin; // Desired tokenB amount (slippage control) 488 | } 489 | 490 | function addLiquidityFromOneToken( 491 | address account, 492 | bytes calldata encodedData 493 | ) external payable onlyAdapterManager { 494 | LiquidityFromOneToken memory liquidity = abi.decode( 495 | encodedData, 496 | (LiquidityFromOneToken) 497 | ); 498 | if (msg.value != 0 && liquidity.sourceToken == wavaxAddr) { 499 | IWAVAX(wavaxAddr).deposit{value: msg.value}(); 500 | pullTokensIfNeeded(wavaxAddr, account, liquidity.amtSource); 501 | liquidity.amtSource += msg.value; 502 | approveToken(wavaxAddr, routerAddr, liquidity.amtSource); 503 | } else { 504 | pullAndApprove( 505 | liquidity.sourceToken, 506 | account, 507 | routerAddr, 508 | liquidity.amtSource 509 | ); 510 | } 511 | 512 | (uint256 tokenAget, uint256 tokenBget) = autoSwapFromOneToken( 513 | liquidity 514 | ); 515 | 516 | approveToken(liquidity.tokenA, routerAddr, tokenAget); 517 | approveToken(liquidity.tokenB, routerAddr, tokenBget); 518 | 519 | if (tokenAget > 0 || tokenBget > 0) { 520 | (uint256 amountA, uint256 amountB, ) = router.addLiquidity( 521 | liquidity.tokenA, 522 | liquidity.tokenB, 523 | tokenAget, 524 | tokenBget, 525 | liquidity.amtAMin, 526 | liquidity.amtBMin, 527 | account, 528 | block.timestamp 529 | ); 530 | returnAsset(liquidity.tokenA, account, tokenAget - amountA); 531 | returnAsset(liquidity.tokenB, account, tokenBget - amountB); 532 | } 533 | } 534 | 535 | function autoSwapFromOneToken(LiquidityFromOneToken memory liquidity) 536 | internal 537 | returns (uint256 tokenAget, uint256 tokenBget) 538 | { 539 | uint256 swapAmt = liquidity.amtSource / 2; 540 | require( 541 | liquidity.pathA[0] == liquidity.sourceToken && 542 | liquidity.pathB[0] == liquidity.sourceToken, 543 | "sourceToken error!" 544 | ); 545 | uint256[] memory amountsA = router.swapExactTokensForTokens( 546 | swapAmt, 547 | 0, 548 | liquidity.pathA, 549 | address(this), 550 | block.timestamp 551 | ); 552 | tokenAget = amountsA[amountsA.length - 1]; 553 | 554 | uint256[] memory amountsB = router.swapExactTokensForTokens( 555 | swapAmt, 556 | 0, 557 | liquidity.pathB, 558 | address(this), 559 | block.timestamp 560 | ); 561 | tokenBget = amountsB[amountsB.length - 1]; 562 | } 563 | } 564 | -------------------------------------------------------------------------------- /contracts/common/Basic.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | abstract contract Basic { 6 | /** 7 | * @dev Return ethereum address 8 | */ 9 | address public constant avaxAddr = 10 | 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; 11 | 12 | /// @dev Return Wrapped AVAX address 13 | address public constant wavaxAddr = 14 | 0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7; 15 | 16 | function safeTransferAVAX(address to, uint256 value) internal { 17 | if (value != 0) { 18 | (bool success, ) = to.call{value: value}(new bytes(0)); 19 | require(success, "helper::safeTransferAVAX: AVAX transfer failed"); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /contracts/core/accountManager/AccountManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; 6 | import "@openzeppelin/contracts/access/Ownable.sol"; 7 | import "../controller/IAccount.sol"; 8 | import "../verifier/IERC2612Verifier.sol"; 9 | import "../verifier/ITokenApprovalVerifier.sol"; 10 | 11 | contract AccountManager is Ownable { 12 | using EnumerableSet for EnumerableSet.AddressSet; 13 | 14 | enum OPERATIONS { 15 | CREATE_SUBACCOUNT, 16 | EXECUTE_ON_ADAPTER, 17 | MULTICALL, 18 | SET_ADVANCED_OPTION, 19 | CALL_ON_SUBACCOUNT, 20 | WITHDRAW_ASSETS, 21 | APPROVE_TOKENS, 22 | APPROVE_ERC2612_VERIFIER, 23 | APPROVE_TOKEN_VERIFIER, 24 | LENGTH 25 | } 26 | uint256 public constant MINIMUM_DEADLINE = 1 days; 27 | uint256 public constant MAXIMUM_DEADLINE = 365 days; 28 | 29 | uint256 public min_delay; 30 | uint256 public max_delay; 31 | 32 | address public erc2612Verifier; 33 | address public tokenApprovalVerifier; 34 | 35 | EnumerableSet.AddressSet private accounts; 36 | mapping(address => mapping(address => bytes32)) public authorizationInfo; 37 | mapping(address => mapping(address => uint256)) public deadline; 38 | 39 | event SetDelay(uint256 min_delay, uint256 max_delay); 40 | event SetVerifier(address erc2612Verifier, address tokenApprovalVerifier); 41 | event AddAccounts(address[] accounts); 42 | event DelAccounts(address[] accounts); 43 | 44 | event SetAuthorization( 45 | address account, 46 | address executor, 47 | bytes32 authorization, 48 | uint256 deadline 49 | ); 50 | event Revoke(address account, address executor); 51 | 52 | constructor( 53 | uint256 _min_delay, 54 | uint256 _max_delay, 55 | address _erc2612Verifier, 56 | address _tokenApprovalVerifier 57 | ) { 58 | require( 59 | _min_delay <= _max_delay, 60 | "AccountManager:Invalid delay time in constructor." 61 | ); 62 | require( 63 | _min_delay >= MINIMUM_DEADLINE && _max_delay <= MAXIMUM_DEADLINE, 64 | "AccountManager:Delay time out of range in constructor." 65 | ); 66 | require( 67 | _erc2612Verifier != address(0) && 68 | _tokenApprovalVerifier != address(0), 69 | "AccountManager:Invalid verifier." 70 | ); 71 | 72 | min_delay = _min_delay; 73 | max_delay = _max_delay; 74 | _setVerifier(_erc2612Verifier, _tokenApprovalVerifier); 75 | 76 | emit SetDelay(min_delay, max_delay); 77 | emit SetVerifier(erc2612Verifier, tokenApprovalVerifier); 78 | } 79 | 80 | function _setVerifier( 81 | address _erc2612Verifier, 82 | address _tokenApprovalVerifier 83 | ) internal { 84 | require( 85 | _erc2612Verifier != address(0) && 86 | _tokenApprovalVerifier != address(0), 87 | "AccountManager:Verifier address should not be zero!" 88 | ); 89 | erc2612Verifier = _erc2612Verifier; 90 | tokenApprovalVerifier = _tokenApprovalVerifier; 91 | } 92 | 93 | function setDelay(uint256 _min_delay, uint256 _max_delay) 94 | external 95 | onlyOwner 96 | { 97 | require(_min_delay <= _max_delay, "AccountManager:Invalid delay time."); 98 | require( 99 | _min_delay >= MINIMUM_DEADLINE && _max_delay <= MAXIMUM_DEADLINE, 100 | "AccountManager:Delay time out of range." 101 | ); 102 | 103 | min_delay = _min_delay; 104 | max_delay = _max_delay; 105 | 106 | emit SetDelay(min_delay, max_delay); 107 | } 108 | 109 | function setVerifier( 110 | address _erc2612Verifier, 111 | address _tokenApprovalVerifier 112 | ) external onlyOwner { 113 | _setVerifier(_erc2612Verifier, _tokenApprovalVerifier); 114 | 115 | emit SetVerifier(erc2612Verifier, tokenApprovalVerifier); 116 | } 117 | 118 | function accountExist(address _account) public view returns (bool) { 119 | return accounts.contains(_account); 120 | } 121 | 122 | function addAccounts(address[] calldata _accounts) external onlyOwner { 123 | require( 124 | _accounts.length > 0, 125 | "AccountManager:account cannot be empty." 126 | ); 127 | for (uint256 i; i < _accounts.length; i++) { 128 | require( 129 | _accounts[i] != address(0), 130 | "AccountManager:cannot cannot be zero." 131 | ); 132 | require( 133 | Ownable(_accounts[i]).owner() == address(this), 134 | "AccountManager:Not my account." 135 | ); 136 | require( 137 | !accountExist(_accounts[i]), 138 | "AccountManager:account already exists." 139 | ); 140 | accounts.add(_accounts[i]); 141 | } 142 | emit AddAccounts(_accounts); 143 | } 144 | 145 | function delAccounts(address[] calldata _accounts) external onlyOwner { 146 | require( 147 | _accounts.length > 0, 148 | "AccountManager:account cannot be empty." 149 | ); 150 | for (uint256 i; i < _accounts.length; i++) { 151 | require( 152 | _accounts[i] != address(0), 153 | "AccountManager:account cannot be empty." 154 | ); 155 | require( 156 | accountExist(_accounts[i]), 157 | "AccountManager:account does not exist." 158 | ); 159 | Ownable(_accounts[i]).transferOwnership(owner()); 160 | accounts.remove(_accounts[i]); 161 | } 162 | emit DelAccounts(_accounts); 163 | } 164 | 165 | function getAccountsLength() external view returns (uint256) { 166 | return accounts.length(); 167 | } 168 | 169 | function getAccount(uint256 i) external view returns (address) { 170 | return accounts.at(i); 171 | } 172 | 173 | function setAuthorization( 174 | address _account, 175 | address _executor, 176 | bytes32 _authorization, 177 | uint256 _deadline 178 | ) external onlyOwner { 179 | require( 180 | accountExist(_account), 181 | "AccountManager:Account is out of control." 182 | ); 183 | require( 184 | uint256(_authorization) < (1 << uint256(OPERATIONS.LENGTH)), 185 | "AccountManager:Invalid operation bytes." 186 | ); 187 | if (_deadline != 0) { 188 | require( 189 | _deadline >= block.timestamp + min_delay && 190 | _deadline <= block.timestamp + max_delay, 191 | "AccountManager:Set time out of range." 192 | ); 193 | } 194 | authorizationInfo[_account][_executor] = _authorization; 195 | deadline[_account][_executor] = _deadline; 196 | emit SetAuthorization(_account, _executor, _authorization, _deadline); 197 | } 198 | 199 | function revoke(address _account, address _executor) external onlyOwner { 200 | require( 201 | authorizationInfo[_account][_executor] != bytes32(0) && 202 | deadline[_account][_executor] >= block.timestamp, 203 | "AccountManager:The executor does not have permission." 204 | ); 205 | authorizationInfo[_account][_executor] = bytes32(0); 206 | deadline[_account][_executor] = 0; 207 | 208 | emit Revoke(_account, _executor); 209 | } 210 | 211 | function authorizationCheck(address _account, OPERATIONS _operationIndex) 212 | public 213 | view 214 | { 215 | require( 216 | accountExist(_account), 217 | "AccountManager:Account is out of control." 218 | ); 219 | uint256 types = uint256(authorizationInfo[_account][msg.sender]); 220 | require( 221 | (types >> uint256(_operationIndex)) & uint256(1) == uint256(1), 222 | "AccountManager:Operation: not allowed." 223 | ); 224 | require( 225 | deadline[_account][msg.sender] >= block.timestamp, 226 | "AccountManager:Operation: authorization expires." 227 | ); 228 | } 229 | 230 | function createSubAccount( 231 | address _account, 232 | bytes calldata _callBytes, 233 | uint256 _costETH 234 | ) external { 235 | authorizationCheck(_account, OPERATIONS.CREATE_SUBACCOUNT); 236 | IAccount(_account).createSubAccount(_callBytes, _costETH); 237 | } 238 | 239 | function executeOnAdapter( 240 | address _account, 241 | bytes calldata _callBytes, 242 | bool _callType 243 | ) external { 244 | authorizationCheck(_account, OPERATIONS.EXECUTE_ON_ADAPTER); 245 | IAccount(_account).executeOnAdapter(_callBytes, _callType); 246 | } 247 | 248 | function executeMultiCall( 249 | address _account, 250 | bool[] calldata _callType, 251 | bytes[] calldata _callBytes, 252 | bool[] calldata _isNeedCallback 253 | ) external { 254 | authorizationCheck(_account, OPERATIONS.MULTICALL); 255 | IAccount(_account).multiCall(_callType, _callBytes, _isNeedCallback); 256 | } 257 | 258 | function setAdvancedOption(address _account, bool _val) external { 259 | authorizationCheck(_account, OPERATIONS.SET_ADVANCED_OPTION); 260 | IAccount(_account).setAdvancedOption(_val); 261 | } 262 | 263 | function callOnSubAccount( 264 | address _account, 265 | address _target, 266 | bytes calldata _callArgs, 267 | uint256 _amountETH 268 | ) external { 269 | authorizationCheck(_account, OPERATIONS.CALL_ON_SUBACCOUNT); 270 | IAccount(_account).callOnSubAccount(_target, _callArgs, _amountETH); 271 | } 272 | 273 | function withdrawAssets( 274 | address _account, 275 | address[] calldata _tokens, 276 | address _receiver, 277 | uint256[] calldata _amounts 278 | ) external { 279 | authorizationCheck(_account, OPERATIONS.WITHDRAW_ASSETS); 280 | require( 281 | _receiver == owner() || IAccount(_account).isSubAccount(_receiver), 282 | "AccountManager:Invalid receiver." 283 | ); 284 | IAccount(_account).withdrawAssets(_tokens, _receiver, _amounts); 285 | } 286 | 287 | function approveTokens( 288 | address _account, 289 | address[] calldata _tokens, 290 | address[] calldata _spenders, 291 | uint256[] calldata _amounts 292 | ) external { 293 | authorizationCheck(_account, OPERATIONS.APPROVE_TOKENS); 294 | IAccount(_account).approveTokens(_tokens, _spenders, _amounts); 295 | } 296 | 297 | function approveERC2612Verifier( 298 | address _account, 299 | address _operator, 300 | bytes32 _approvalType, 301 | uint256 _deadline 302 | ) external { 303 | authorizationCheck(_account, OPERATIONS.APPROVE_ERC2612_VERIFIER); 304 | IERC2612Verifier(erc2612Verifier).approve( 305 | _account, 306 | _operator, 307 | _approvalType, 308 | _deadline 309 | ); 310 | } 311 | 312 | function approveTokenApprovalVerifier( 313 | address _account, 314 | address[] memory _spenders, 315 | bool _enable, 316 | uint256 _deadline 317 | ) external { 318 | authorizationCheck(_account, OPERATIONS.APPROVE_TOKEN_VERIFIER); 319 | ITokenApprovalVerifier(tokenApprovalVerifier).approve( 320 | _account, 321 | _spenders, 322 | _enable, 323 | _deadline 324 | ); 325 | } 326 | } 327 | -------------------------------------------------------------------------------- /contracts/core/automation/Automation.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | import "@openzeppelin/contracts/access/Ownable.sol"; 6 | import "@openzeppelin/contracts/interfaces/IERC3156FlashLender.sol"; 7 | import "../controller/IAccount.sol"; 8 | import "../verifier/IERC2612Verifier.sol"; 9 | import "../verifier/ITokenApprovalVerifier.sol"; 10 | 11 | contract Automation { 12 | address public immutable verifier; 13 | address public immutable tokenApprovalVerifier; 14 | address public immutable loanProvider; 15 | mapping(address => address) public customizedLoanProviders; 16 | 17 | event SetLoanProvider(address account, address loanProvider); 18 | 19 | constructor( 20 | address _verifier, 21 | address _tokenApprovalVerifier, 22 | address _loanProvider 23 | ) { 24 | verifier = _verifier; 25 | tokenApprovalVerifier = _tokenApprovalVerifier; 26 | loanProvider = _loanProvider; 27 | } 28 | 29 | function setLoanProvider(address account, address customizedLoanProvider) 30 | external 31 | { 32 | require(IAccount(account).owner() == msg.sender, "Owner check failed."); 33 | customizedLoanProviders[account] = customizedLoanProvider; 34 | emit SetLoanProvider(account, customizedLoanProvider); 35 | } 36 | 37 | function getLoanProvider(address account) public view returns (address) { 38 | return 39 | customizedLoanProviders[account] == address(0) 40 | ? loanProvider 41 | : customizedLoanProviders[account]; 42 | } 43 | 44 | function _executeVerifyBasic(address account, uint256 operation) 45 | internal 46 | view 47 | { 48 | require( 49 | IERC2612Verifier(verifier).isTxPermitted( 50 | account, 51 | msg.sender, 52 | operation 53 | ), 54 | "denied" 55 | ); 56 | } 57 | 58 | function _executeVerifyAdapter(address account, bytes memory callBytes) 59 | internal 60 | view 61 | { 62 | address adapter; 63 | assembly { 64 | adapter := mload(add(callBytes, 32)) 65 | } 66 | require( 67 | IERC2612Verifier(verifier).isTxPermitted( 68 | account, 69 | msg.sender, 70 | adapter 71 | ), 72 | "denied" 73 | ); 74 | } 75 | 76 | function _executeVerifyApproval(address account, address spender) 77 | internal 78 | view 79 | { 80 | require( 81 | ITokenApprovalVerifier(tokenApprovalVerifier).isWhitelisted( 82 | account, 83 | spender 84 | ), 85 | "denied" 86 | ); 87 | } 88 | 89 | function _autoExecute( 90 | address account, 91 | bytes calldata callBytes, 92 | bool callType 93 | ) internal returns (bytes memory returnData) { 94 | _executeVerifyAdapter(account, callBytes); 95 | returnData = IAccount(account).executeOnAdapter(callBytes, callType); 96 | } 97 | 98 | function autoExecute( 99 | address account, 100 | bytes calldata callBytes, 101 | bool callType 102 | ) external returns (bytes memory) { 103 | return _autoExecute(account, callBytes, callType); 104 | } 105 | 106 | function autoExecuteWithPermit( 107 | address account, 108 | bytes calldata callBytes, 109 | bool callType, 110 | bytes32 approvalType, 111 | uint256 deadline, 112 | uint8 v, 113 | bytes32 r, 114 | bytes32 s 115 | ) external returns (bytes memory) { 116 | IERC2612Verifier(verifier).permit( 117 | account, 118 | msg.sender, 119 | approvalType, 120 | deadline, 121 | v, 122 | r, 123 | s 124 | ); 125 | return _autoExecute(account, callBytes, callType); 126 | } 127 | 128 | function autoExecuteMultiCall( 129 | address account, 130 | bool[] memory callType, 131 | bytes[] memory callBytes, 132 | bool[] memory isNeedCallback 133 | ) external { 134 | require( 135 | callType.length == callBytes.length && 136 | callBytes.length == isNeedCallback.length 137 | ); 138 | for (uint256 i = 0; i < callType.length; i++) { 139 | _executeVerifyAdapter(account, callBytes[i]); 140 | } 141 | IAccount(payable(account)).multiCall( 142 | callType, 143 | callBytes, 144 | isNeedCallback 145 | ); 146 | } 147 | 148 | function autoApprove( 149 | address account, 150 | address token, 151 | address spender, 152 | uint256 amount 153 | ) external { 154 | _executeVerifyBasic(account, 0); 155 | _executeVerifyApproval(account, spender); 156 | IAccount(payable(account)).approve(token, spender, amount); 157 | } 158 | 159 | function autoApproveWithPermit( 160 | address account, 161 | address[] memory tokens, 162 | address[] memory spenders, 163 | uint256[] memory amounts, 164 | address[] memory permitSpenders, 165 | bool enable, 166 | uint256 deadline, 167 | uint8 v, 168 | bytes32 r, 169 | bytes32 s 170 | ) external { 171 | require( 172 | tokens.length == spenders.length && 173 | spenders.length == amounts.length, 174 | "approve length error." 175 | ); 176 | _executeVerifyBasic(account, 0); 177 | ITokenApprovalVerifier(tokenApprovalVerifier).permit( 178 | account, 179 | permitSpenders, 180 | enable, 181 | deadline, 182 | v, 183 | r, 184 | s 185 | ); 186 | for (uint256 i = 0; i < spenders.length; i++) { 187 | _executeVerifyApproval(account, spenders[i]); 188 | } 189 | IAccount(payable(account)).approveTokens(tokens, spenders, amounts); 190 | } 191 | 192 | function doFlashLoan( 193 | address account, 194 | address token, 195 | uint256 amount, 196 | bytes calldata payload 197 | ) external { 198 | _executeVerifyBasic(account, 1); 199 | ( 200 | bool[] memory _callType, 201 | bytes[] memory _callBytes, 202 | bool[] memory _isNeedCallback 203 | ) = abi.decode(payload, (bool[], bytes[], bool[])); 204 | require( 205 | _callType.length == _callBytes.length && 206 | _callBytes.length == _isNeedCallback.length 207 | ); 208 | for (uint256 i = 0; i < _callBytes.length; i++) { 209 | _executeVerifyAdapter(account, _callBytes[i]); 210 | } 211 | IERC3156FlashLender(getLoanProvider(account)).flashLoan( 212 | IERC3156FlashBorrower(account), 213 | token, 214 | amount, 215 | payload 216 | ); 217 | } 218 | 219 | function autoExecuteOnSubAccount( 220 | address account, 221 | address subAccount, 222 | bytes calldata callArgs, 223 | uint256 amountETH 224 | ) external { 225 | _executeVerifyBasic(account, 2); 226 | require(Ownable(subAccount).owner() == account, "invalid account!"); 227 | IAccount(payable(account)).callOnSubAccount( 228 | subAccount, 229 | callArgs, 230 | amountETH 231 | ); 232 | } 233 | 234 | function doFlashLoanOnSubAccount( 235 | address account, 236 | address subAccount, 237 | address token, 238 | uint256 amount, 239 | bytes calldata payload 240 | ) external { 241 | _executeVerifyBasic(account, 3); 242 | require(Ownable(subAccount).owner() == account, "invalid account!"); 243 | IERC3156FlashLender(getLoanProvider(account)).flashLoan( 244 | IERC3156FlashBorrower(subAccount), 245 | token, 246 | amount, 247 | payload 248 | ); 249 | } 250 | } 251 | -------------------------------------------------------------------------------- /contracts/core/automation/AutomationCallable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; 6 | 7 | contract AutomationCallable is Initializable { 8 | address public autoExecutor; 9 | event ChangeAutomation(address oldExecutor, address newExecutor); 10 | 11 | function _setAutomation(address newExecutor) internal { 12 | address oldExecutor = autoExecutor; 13 | autoExecutor = newExecutor; 14 | emit ChangeAutomation(oldExecutor, newExecutor); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /contracts/core/automation/IAutomation.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface IAutomation { 6 | function getLoanProvider(address account) external view returns (address); 7 | } 8 | -------------------------------------------------------------------------------- /contracts/core/controller/ControllerLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 7 | import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; 8 | import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; 9 | import "@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol"; 10 | import "../../common/Basic.sol"; 11 | import "../automation/AutomationCallable.sol"; 12 | import "../automation/IAutomation.sol"; 13 | import "../../adapters/IAdapterManager.sol"; 14 | 15 | interface IWalletFactory { 16 | function createSubAccount( 17 | address _adapterManager, 18 | address _autoExecutor, 19 | bytes memory _data 20 | ) external payable returns (address); 21 | } 22 | 23 | contract ControllerLib is 24 | Initializable, 25 | OwnableUpgradeable, 26 | Basic, 27 | AutomationCallable, 28 | IERC3156FlashBorrower 29 | { 30 | using SafeERC20 for IERC20; 31 | 32 | address public immutable implementationAddress; 33 | address public adapterManager; 34 | bool public advancedOptionEnable; 35 | address public walletFactory; 36 | address public currentAdapter; 37 | mapping(address => bool) public isSubAccount; 38 | 39 | event NewAccount(address owner, address account); 40 | event ResetAccount( 41 | address adapterManager, 42 | address autoExecutor, 43 | address walletFactory 44 | ); 45 | event SetAdvancedOption(bool); 46 | event NewSubAccount(address _subAccount); 47 | event WithdrawAssets( 48 | address[] _tokens, 49 | address _receiver, 50 | uint256[] _amounts 51 | ); 52 | event ApproveToken(IERC20 _token, address _spender, uint256 _amount); 53 | event ApproveTokens( 54 | IERC20[] _tokens, 55 | address[] _spenders, 56 | uint256[] _amounts 57 | ); 58 | event OnFlashLoan( 59 | address _initiator, 60 | address _token, 61 | uint256 _amount, 62 | uint256 _fee 63 | ); 64 | 65 | constructor() { 66 | implementationAddress = address(this); 67 | } 68 | 69 | modifier onlyProxy() { 70 | require(address(this) != implementationAddress, "!proxy"); 71 | _; 72 | } 73 | 74 | function initialize( 75 | address _owner, 76 | address _autoExecutor, 77 | address _adapterManager 78 | ) public initializer onlyProxy { 79 | __Ownable_init(); 80 | _setAutomation(_autoExecutor); 81 | adapterManager = _adapterManager; 82 | walletFactory = msg.sender; 83 | emit NewAccount(_owner, address(this)); 84 | } 85 | 86 | function reinitialize( 87 | address _adapterManager, 88 | address _autoExecutor, 89 | address _walletFactory 90 | ) external onlyOwner onlyProxy { 91 | if (_adapterManager != address(0)) { 92 | adapterManager = _adapterManager; 93 | } 94 | if (_autoExecutor != address(0)) { 95 | _setAutomation(_autoExecutor); 96 | } 97 | if (_walletFactory != address(0)) { 98 | walletFactory = _walletFactory; 99 | } 100 | emit ResetAccount(_adapterManager, _autoExecutor, _walletFactory); 101 | } 102 | 103 | function getVersion() external pure returns (string memory) { 104 | return "v0.4"; 105 | } 106 | 107 | function _fallbackForAdapter() internal { 108 | (bool success, bytes memory returnData) = currentAdapter.delegatecall( 109 | msg.data 110 | ); 111 | require(success, string(returnData)); 112 | currentAdapter = address(0); 113 | } 114 | 115 | fallback() external payable { 116 | require( 117 | msg.sender == currentAdapter, 118 | "Not allowed: caller is not the currentAdapter" 119 | ); 120 | _fallbackForAdapter(); 121 | } 122 | 123 | modifier onlyAutomationOrOwner() { 124 | require( 125 | // autoExecutor or owner 126 | autoExecutor == msg.sender || owner() == msg.sender, 127 | "Permit: sender not permitted" 128 | ); 129 | _; 130 | } 131 | 132 | function setCurrentAdapter(address _currentAdapter) internal { 133 | require( 134 | IAdapterManager(adapterManager).adapterIsAvailable(_currentAdapter), 135 | "Invalid currentAdapter!" 136 | ); 137 | currentAdapter = _currentAdapter; 138 | } 139 | 140 | function createSubAccount(bytes memory _data, uint256 _costETH) 141 | external 142 | payable 143 | onlyOwner 144 | returns (address newSubAccount) 145 | { 146 | newSubAccount = IWalletFactory(walletFactory).createSubAccount{ 147 | value: _costETH + msg.value 148 | }(adapterManager, autoExecutor, _data); 149 | isSubAccount[newSubAccount] = true; 150 | 151 | emit NewSubAccount(newSubAccount); 152 | } 153 | 154 | //callback only for callOnAdapter so far 155 | function _callOnAdapter(bytes memory _callBytes, bool _isNeedCallback) 156 | internal 157 | returns (bytes memory returnData) 158 | { 159 | (address adapter, uint256 costETH, , ) = abi.decode( 160 | _callBytes, 161 | (address, uint256, bytes4, bytes) 162 | ); 163 | if (_isNeedCallback) { 164 | setCurrentAdapter(adapter); 165 | } 166 | 167 | returnData = IAdapterManager(adapterManager).execute{ 168 | value: costETH + msg.value 169 | }(_callBytes); 170 | 171 | if (_isNeedCallback) { 172 | require(currentAdapter == address(0), "!not reset"); 173 | } 174 | } 175 | 176 | function _delegatecallOnAdapter(bytes memory _callBytes) 177 | internal 178 | returns (bytes memory) 179 | { 180 | (address adapter, bytes memory callData) = abi.decode( 181 | _callBytes, 182 | (address, bytes) 183 | ); 184 | require( 185 | IAdapterManager(adapterManager).adapterIsAvailable(adapter), 186 | "Permission verification failed!" 187 | ); 188 | 189 | (bool success, bytes memory returnData) = adapter.delegatecall( 190 | callData 191 | ); 192 | require(success, string(returnData)); 193 | return returnData; 194 | } 195 | 196 | function _executeOnAdapter( 197 | bytes memory _callBytes, 198 | bool _callType, 199 | bool _isNeedCallback 200 | ) internal returns (bytes memory returnData) { 201 | returnData = _callType 202 | ? _delegatecallOnAdapter(_callBytes) 203 | : _callOnAdapter(_callBytes, _isNeedCallback); 204 | } 205 | 206 | function _multiCall( 207 | bool[] memory _callType, 208 | bytes[] memory _callArgs, 209 | bool[] memory _isNeedCallback 210 | ) internal { 211 | require( 212 | _callType.length == _callArgs.length && 213 | _callArgs.length == _isNeedCallback.length 214 | ); 215 | for (uint256 i; i < _callArgs.length; i++) { 216 | _executeOnAdapter(_callArgs[i], _callType[i], _isNeedCallback[i]); 217 | } 218 | } 219 | 220 | function executeOnAdapter(bytes memory _callBytes, bool _callType) 221 | external 222 | payable 223 | onlyAutomationOrOwner 224 | returns (bytes memory) 225 | { 226 | return _executeOnAdapter(_callBytes, _callType, false); 227 | } 228 | 229 | function multiCall( 230 | bool[] memory _callType, 231 | bytes[] memory _callArgs, 232 | bool[] memory _isNeedCallback 233 | ) external onlyAutomationOrOwner { 234 | _multiCall(_callType, _callArgs, _isNeedCallback); 235 | } 236 | 237 | function _callDirectly( 238 | address _target, 239 | bytes calldata _callArgs, 240 | uint256 _amountETH 241 | ) internal { 242 | (bool success, bytes memory returnData) = _target.call{ 243 | value: _amountETH + msg.value 244 | }(_callArgs); 245 | require(success, string(returnData)); 246 | } 247 | 248 | function callDirectly( 249 | address _target, 250 | bytes calldata _callArgs, 251 | uint256 _amountETH 252 | ) external payable onlyOwner { 253 | require(advancedOptionEnable, "Not allowed!"); 254 | _callDirectly(_target, _callArgs, _amountETH); 255 | } 256 | 257 | function callOnSubAccount( 258 | address _target, 259 | bytes calldata _callArgs, 260 | uint256 _amountETH 261 | ) external payable onlyAutomationOrOwner { 262 | require(isSubAccount[_target], "Not my subAccount!"); 263 | _callDirectly(_target, _callArgs, _amountETH); 264 | } 265 | 266 | function setAdvancedOption(bool val) external onlyOwner { 267 | advancedOptionEnable = val; 268 | 269 | emit SetAdvancedOption(advancedOptionEnable); 270 | } 271 | 272 | function _transferAsset( 273 | address _token, 274 | uint256 _amount, 275 | address _receiver 276 | ) internal { 277 | if (_token == avaxAddr) { 278 | uint256 _balance = address(this).balance; 279 | require(_balance >= _amount, "not enough AVAX balance"); 280 | safeTransferAVAX(_receiver, _amount); 281 | } else { 282 | uint256 _balance = IERC20(_token).balanceOf(address(this)); 283 | require(_balance >= _amount, "not enough token balance"); 284 | IERC20(_token).safeTransfer(_receiver, _amount); 285 | } 286 | } 287 | 288 | function _transferAssets( 289 | address[] memory _tokens, 290 | uint256[] memory _amounts, 291 | address _receiver 292 | ) internal { 293 | require(_tokens.length == _amounts.length, "withdraw length error."); 294 | for (uint256 i = 0; i < _tokens.length; i++) { 295 | _transferAsset(_tokens[i], _amounts[i], _receiver); 296 | } 297 | } 298 | 299 | function withdrawAssets( 300 | address[] memory _tokens, 301 | address _receiver, 302 | uint256[] memory _amounts 303 | ) external onlyOwner { 304 | if (_receiver != owner() && !isSubAccount[_receiver]) { 305 | require(advancedOptionEnable, "Not allowed!"); 306 | } 307 | _transferAssets(_tokens, _amounts, _receiver); 308 | 309 | emit WithdrawAssets(_tokens, _receiver, _amounts); 310 | } 311 | 312 | function approve( 313 | IERC20 _token, 314 | address _spender, 315 | uint256 _amount 316 | ) external onlyAutomationOrOwner { 317 | _token.safeApprove(_spender, 0); 318 | _token.safeApprove(_spender, _amount); 319 | 320 | emit ApproveToken(_token, _spender, _amount); 321 | } 322 | 323 | function approveTokens( 324 | IERC20[] memory _tokens, 325 | address[] memory _spenders, 326 | uint256[] memory _amounts 327 | ) external onlyAutomationOrOwner { 328 | require( 329 | _tokens.length == _amounts.length && 330 | _spenders.length == _amounts.length, 331 | "approve length error." 332 | ); 333 | for (uint256 i = 0; i < _tokens.length; i++) { 334 | _tokens[i].safeApprove(_spenders[i], 0); 335 | _tokens[i].safeApprove(_spenders[i], _amounts[i]); 336 | } 337 | 338 | emit ApproveTokens(_tokens, _spenders, _amounts); 339 | } 340 | 341 | function onFlashLoan( 342 | address _initiator, 343 | address _token, 344 | uint256 _amount, 345 | uint256 _fee, 346 | bytes calldata _data 347 | ) external override returns (bytes32) { 348 | require(autoExecutor == _initiator, "Initiator verification failed."); 349 | require( 350 | msg.sender == 351 | IAutomation(autoExecutor).getLoanProvider(address(this)), 352 | "FlashLoan verification failed." 353 | ); 354 | ( 355 | bool[] memory _callType, 356 | bytes[] memory _callArgs, 357 | bool[] memory _isNeedCallback 358 | ) = abi.decode(_data, (bool[], bytes[], bool[])); 359 | _multiCall(_callType, _callArgs, _isNeedCallback); 360 | // Handle native token. 361 | IERC20 borrow = IERC20(_token); 362 | borrow.safeApprove(msg.sender, 0); 363 | borrow.safeApprove(msg.sender, _amount + _fee); 364 | 365 | emit OnFlashLoan(_initiator, _token, _amount, _fee); 366 | return keccak256("ERC3156FlashBorrower.onFlashLoan"); 367 | } 368 | } 369 | -------------------------------------------------------------------------------- /contracts/core/controller/ControllerLibSub.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 7 | import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; 8 | import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; 9 | import "@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol"; 10 | import "../../common/Basic.sol"; 11 | import "../automation/IAutomation.sol"; 12 | import "../../adapters/IAdapterManager.sol"; 13 | 14 | contract ControllerLibSub is 15 | Initializable, 16 | OwnableUpgradeable, 17 | Basic, 18 | IERC3156FlashBorrower 19 | { 20 | using SafeERC20 for IERC20; 21 | 22 | address public immutable implementationAddress; 23 | address public eoaOwner; 24 | address public adapterManager; 25 | address public autoExecutor; 26 | address public currentAdapter; 27 | 28 | constructor() { 29 | implementationAddress = address(this); 30 | } 31 | 32 | event NewAccount(address adapterManager, address autoExecutor); 33 | event ResetAccount(address adapterManager, address autoExecutor); 34 | event WithdrawAssets(address[] tokens, uint256[] amounts); 35 | event ApproveTokens(IERC20[] tokens, address[] to, uint256[] amounts); 36 | event OnFlashLoan( 37 | address initiator, 38 | address token, 39 | uint256 amount, 40 | uint256 fee 41 | ); 42 | 43 | modifier onlyProxy() { 44 | require(address(this) != implementationAddress, "!proxy"); 45 | _; 46 | } 47 | 48 | modifier onlyEoaOwner() { 49 | require(msg.sender == eoaOwner, "!eoaOwner"); 50 | _; 51 | } 52 | 53 | function initialize( 54 | address _adapterManager, 55 | address _autoExecutor, 56 | bytes calldata _data 57 | ) public initializer onlyProxy { 58 | __Ownable_init(); 59 | adapterManager = _adapterManager; 60 | autoExecutor = _autoExecutor; 61 | ( 62 | address _eoaOwner, 63 | IERC20[] memory _tokens, 64 | address[] memory _spenders, 65 | uint256[] memory _amounts 66 | ) = abi.decode(_data, (address, IERC20[], address[], uint256[])); 67 | eoaOwner = _eoaOwner; 68 | _approveTokens(_tokens, _spenders, _amounts); 69 | 70 | emit NewAccount(adapterManager, autoExecutor); 71 | } 72 | 73 | function reinitialize(address _adapterManager, address _autoExecutor) 74 | external 75 | onlyEoaOwner 76 | onlyProxy 77 | { 78 | if (_adapterManager != address(0)) { 79 | adapterManager = _adapterManager; 80 | } 81 | if (_autoExecutor != address(0)) { 82 | autoExecutor = _autoExecutor; 83 | } 84 | emit ResetAccount(adapterManager, autoExecutor); 85 | } 86 | 87 | function getVersion() external pure returns (string memory) { 88 | return "v0.3"; 89 | } 90 | 91 | function _fallbackForAdapter() internal { 92 | (bool success, bytes memory returnData) = currentAdapter.delegatecall( 93 | msg.data 94 | ); 95 | require(success, string(returnData)); 96 | currentAdapter = address(0); 97 | } 98 | 99 | fallback() external payable { 100 | require( 101 | msg.sender == currentAdapter, 102 | "Not allowed: caller is not the currentAdapter" 103 | ); 104 | _fallbackForAdapter(); 105 | } 106 | 107 | receive() external payable {} 108 | 109 | function setCurrentAdapter(address _currentAdapter) internal { 110 | require( 111 | IAdapterManager(adapterManager).adapterIsAvailable(_currentAdapter), 112 | "Invalid currentAdapter!" 113 | ); 114 | currentAdapter = _currentAdapter; 115 | } 116 | 117 | //callback only for callOnAdapter so far 118 | function _callOnAdapter(bytes memory _callBytes, bool isNeedCallback) 119 | internal 120 | returns (bytes memory returnData) 121 | { 122 | (address adapter, uint256 costETH, , ) = abi.decode( 123 | _callBytes, 124 | (address, uint256, bytes4, bytes) 125 | ); 126 | if (isNeedCallback) { 127 | setCurrentAdapter(adapter); 128 | } 129 | 130 | returnData = IAdapterManager(adapterManager).execute{ 131 | value: costETH + msg.value 132 | }(_callBytes); 133 | 134 | if (isNeedCallback) { 135 | require(currentAdapter == address(0), "!not reset"); 136 | } 137 | } 138 | 139 | function _delegatecallOnAdapter(bytes memory _callBytes) 140 | internal 141 | returns (bytes memory) 142 | { 143 | (address adapter, bytes memory callData) = abi.decode( 144 | _callBytes, 145 | (address, bytes) 146 | ); 147 | require( 148 | IAdapterManager(adapterManager).adapterIsAvailable(adapter), 149 | "Permission verification failed!" 150 | ); 151 | 152 | (bool success, bytes memory returnData) = adapter.delegatecall( 153 | callData 154 | ); 155 | require(success, string(returnData)); 156 | return returnData; 157 | } 158 | 159 | function _executeOnAdapter( 160 | bytes memory _callBytes, 161 | bool _callType, 162 | bool _isNeedCallback 163 | ) internal returns (bytes memory returnData) { 164 | returnData = _callType 165 | ? _delegatecallOnAdapter(_callBytes) 166 | : _callOnAdapter(_callBytes, _isNeedCallback); 167 | } 168 | 169 | function _multiCall( 170 | bool[] memory _callType, 171 | bytes[] memory _callArgs, 172 | bool[] memory _isNeedCallback 173 | ) internal { 174 | require( 175 | _callType.length == _callArgs.length && 176 | _callArgs.length == _isNeedCallback.length 177 | ); 178 | for (uint256 i; i < _callArgs.length; i++) { 179 | _executeOnAdapter(_callArgs[i], _callType[i], _isNeedCallback[i]); 180 | } 181 | } 182 | 183 | function executeOnAdapter(bytes memory _callBytes, bool _callType) 184 | external 185 | payable 186 | onlyOwner 187 | returns (bytes memory) 188 | { 189 | return _executeOnAdapter(_callBytes, _callType, false); 190 | } 191 | 192 | function multiCall( 193 | bool[] memory _callType, 194 | bytes[] memory _callArgs, 195 | bool[] memory _isNeedCallback 196 | ) external onlyOwner { 197 | _multiCall(_callType, _callArgs, _isNeedCallback); 198 | } 199 | 200 | function _transferAsset(address _token, uint256 _amount) internal { 201 | if (_token == avaxAddr) { 202 | uint256 _balance = address(this).balance; 203 | require(_balance >= _amount, "not enough AVAX balance"); 204 | safeTransferAVAX(owner(), _amount); 205 | } else { 206 | uint256 _balance = IERC20(_token).balanceOf(address(this)); 207 | require(_balance >= _amount, "not enough token balance"); 208 | IERC20(_token).safeTransfer(owner(), _amount); 209 | } 210 | } 211 | 212 | function withdrawAssets(address[] memory _tokens, uint256[] memory _amounts) 213 | external 214 | onlyOwner 215 | { 216 | require(_tokens.length == _amounts.length, "withdraw length error."); 217 | for (uint256 i = 0; i < _tokens.length; i++) { 218 | _transferAsset(_tokens[i], _amounts[i]); 219 | } 220 | emit WithdrawAssets(_tokens, _amounts); 221 | } 222 | 223 | function _approveTokens( 224 | IERC20[] memory _tokens, 225 | address[] memory _spenders, 226 | uint256[] memory _amounts 227 | ) internal { 228 | require( 229 | _tokens.length == _amounts.length && 230 | _spenders.length == _amounts.length, 231 | "approve length error." 232 | ); 233 | for (uint256 i = 0; i < _tokens.length; i++) { 234 | _tokens[i].safeApprove(_spenders[i], 0); 235 | _tokens[i].safeApprove(_spenders[i], _amounts[i]); 236 | } 237 | } 238 | 239 | function approveTokens( 240 | IERC20[] memory _tokens, 241 | address[] memory _spenders, 242 | uint256[] memory _amounts 243 | ) external onlyEoaOwner { 244 | _approveTokens(_tokens, _spenders, _amounts); 245 | 246 | emit ApproveTokens(_tokens, _spenders, _amounts); 247 | } 248 | 249 | function onFlashLoan( 250 | address _initiator, 251 | address _token, 252 | uint256 _amount, 253 | uint256 _fee, 254 | bytes calldata _data 255 | ) external override returns (bytes32) { 256 | require(autoExecutor == _initiator, "Initiator verification failed."); 257 | require( 258 | msg.sender == IAutomation(autoExecutor).getLoanProvider(owner()), 259 | "FlashLoan verification failed." 260 | ); 261 | ( 262 | bool[] memory _callType, 263 | bytes[] memory _callArgs, 264 | bool[] memory _isNeedCallback 265 | ) = abi.decode(_data, (bool[], bytes[], bool[])); 266 | _multiCall(_callType, _callArgs, _isNeedCallback); 267 | // Handle native token. 268 | IERC20 borrow = IERC20(_token); 269 | borrow.safeApprove(msg.sender, 0); 270 | borrow.safeApprove(msg.sender, _amount + _fee); 271 | 272 | emit OnFlashLoan(_initiator, _token, _amount, _fee); 273 | return keccak256("ERC3156FlashBorrower.onFlashLoan"); 274 | } 275 | } 276 | -------------------------------------------------------------------------------- /contracts/core/controller/ControllerLink.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | import "@openzeppelin/contracts/access/Ownable.sol"; 6 | import "../../timelock/TimelockCallable.sol"; 7 | import "./IAccount.sol"; 8 | 9 | contract ControllerLink is TimelockCallable, Ownable { 10 | // Smart Account Count. 11 | uint256 public accounts; 12 | mapping(address => uint256) public accountID; 13 | mapping(uint256 => address) public accountAddr; 14 | mapping(address => UserLink) public userLink; 15 | mapping(address => mapping(uint256 => UserList)) public userList; 16 | 17 | address public trustFactory; 18 | 19 | event NewAccount(address owner, address account); 20 | event DelAccount(address owner, address account); 21 | 22 | struct UserLink { 23 | uint256 first; 24 | uint256 last; 25 | uint256 count; 26 | } 27 | struct UserList { 28 | uint256 prev; 29 | uint256 next; 30 | } 31 | 32 | mapping(uint256 => AccountLink) public accountLink; 33 | mapping(uint256 => mapping(address => AccountList)) public accountList; 34 | 35 | struct AccountLink { 36 | address first; 37 | address last; 38 | uint256 count; 39 | } 40 | struct AccountList { 41 | address prev; 42 | address next; 43 | } 44 | 45 | constructor(address _timelock) TimelockCallable(_timelock) {} 46 | 47 | function initialize(address _trustFactory) external onlyTimelock { 48 | trustFactory = _trustFactory; 49 | } 50 | 51 | modifier onlyFactory() { 52 | require(msg.sender == trustFactory, "!trustFactory"); 53 | _; 54 | } 55 | 56 | function accountVerification(address _owner, address _account) 57 | internal 58 | view 59 | returns (bool) 60 | { 61 | return IAccount(_account).owner() == _owner; 62 | } 63 | 64 | function addAuth(address _owner, address _account) external onlyFactory { 65 | require( 66 | accountVerification(_owner, _account), 67 | "Account addition verification failed!" 68 | ); 69 | accounts++; 70 | accountID[_account] = accounts; 71 | accountAddr[accounts] = _account; 72 | addAccount(_owner, accounts); 73 | addUser(_owner, accounts); 74 | 75 | emit NewAccount(_owner, _account); 76 | } 77 | 78 | function removeAuth(address _owner, address _account) external { 79 | uint256 removeAccountID = accountID[_account]; 80 | require(removeAccountID != 0, "not-account"); 81 | require( 82 | accountVerification(_owner, _account) && msg.sender == _account, 83 | "Account deletion verification failed!" 84 | ); 85 | removeAccount(_owner, removeAccountID); 86 | removeUser(_owner, removeAccountID); 87 | accountID[_account] = 0; 88 | 89 | emit DelAccount(_owner, _account); 90 | } 91 | 92 | function addAccount(address _owner, uint256 _account) internal { 93 | if (userLink[_owner].last != 0) { 94 | userList[_owner][_account].prev = userLink[_owner].last; 95 | userList[_owner][userLink[_owner].last].next = _account; 96 | } 97 | if (userLink[_owner].first == 0) userLink[_owner].first = _account; 98 | userLink[_owner].last = _account; 99 | userLink[_owner].count++; 100 | } 101 | 102 | function addUser(address _owner, uint256 _account) internal { 103 | if (accountLink[_account].last != address(0)) { 104 | accountList[_account][_owner].prev = accountLink[_account].last; 105 | accountList[_account][accountLink[_account].last].next = _owner; 106 | } 107 | if (accountLink[_account].first == address(0)) 108 | accountLink[_account].first = _owner; 109 | accountLink[_account].last = _owner; 110 | accountLink[_account].count++; 111 | } 112 | 113 | function removeAccount(address _owner, uint256 _account) internal { 114 | uint256 _prev = userList[_owner][_account].prev; 115 | uint256 _next = userList[_owner][_account].next; 116 | if (_prev != 0) userList[_owner][_prev].next = _next; 117 | if (_next != 0) userList[_owner][_next].prev = _prev; 118 | if (_prev == 0) userLink[_owner].first = _next; 119 | if (_next == 0) userLink[_owner].last = _prev; 120 | userLink[_owner].count--; 121 | delete userList[_owner][_account]; 122 | } 123 | 124 | function removeUser(address _owner, uint256 _account) internal { 125 | address _prev = accountList[_account][_owner].prev; 126 | address _next = accountList[_account][_owner].next; 127 | if (_prev != address(0)) accountList[_account][_prev].next = _next; 128 | if (_next != address(0)) accountList[_account][_next].prev = _prev; 129 | if (_prev == address(0)) accountLink[_account].first = _next; 130 | if (_next == address(0)) accountLink[_account].last = _prev; 131 | accountLink[_account].count--; 132 | delete accountList[_account][_owner]; 133 | } 134 | 135 | function existing(address _account) external view returns (bool) { 136 | if (accountID[_account] == 0) { 137 | return false; 138 | } else { 139 | return true; 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /contracts/core/controller/IAccount.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface IAccount { 6 | function owner() external view returns (address); 7 | 8 | function createSubAccount(bytes memory _data, uint256 _costETH) 9 | external 10 | payable 11 | returns (address newSubAccount); 12 | 13 | function executeOnAdapter(bytes calldata _callBytes, bool _callType) 14 | external 15 | payable 16 | returns (bytes memory); 17 | 18 | function multiCall( 19 | bool[] calldata _callType, 20 | bytes[] calldata _callArgs, 21 | bool[] calldata _isNeedCallback 22 | ) external; 23 | 24 | function setAdvancedOption(bool val) external; 25 | 26 | function callOnSubAccount( 27 | address _target, 28 | bytes calldata _callArgs, 29 | uint256 amountETH 30 | ) external; 31 | 32 | function withdrawAssets( 33 | address[] calldata _tokens, 34 | address _receiver, 35 | uint256[] calldata _amounts 36 | ) external; 37 | 38 | function approve( 39 | address tokenAddr, 40 | address to, 41 | uint256 amount 42 | ) external; 43 | 44 | function approveTokens( 45 | address[] calldata _tokens, 46 | address[] calldata _spenders, 47 | uint256[] calldata _amounts 48 | ) external; 49 | 50 | function isSubAccount(address subAccount) external view returns (bool); 51 | } 52 | -------------------------------------------------------------------------------- /contracts/core/controller/IControllerLink.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface IControllerLink { 6 | function addAuth(address _owner, address _account) external; 7 | 8 | function existing(address _account) external view returns (bool); 9 | } 10 | -------------------------------------------------------------------------------- /contracts/core/controller/ProxyWallet.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | pragma solidity >=0.8.0 <0.9.0; 3 | 4 | import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; 5 | import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; 6 | import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; 7 | import "@openzeppelin/contracts/proxy/Clones.sol"; 8 | import "../../timelock/TimelockCallable.sol"; 9 | import "../../common/Basic.sol"; 10 | import "./IControllerLink.sol"; 11 | 12 | interface IControllerLibSub { 13 | function initialize( 14 | address _adapterManager, 15 | address _autoExecutor, 16 | bytes memory data 17 | ) external; 18 | } 19 | 20 | contract ProxyWallet is TransparentUpgradeableProxy { 21 | event Received(address addr, uint256 amount); 22 | 23 | constructor( 24 | address _logic, 25 | address _admin, 26 | bytes memory _data 27 | ) payable TransparentUpgradeableProxy(_logic, _admin, _data) {} 28 | 29 | function getProxyAdmin() external view returns (address) { 30 | return _getAdmin(); 31 | } 32 | 33 | receive() external payable override { 34 | emit Received(msg.sender, msg.value); 35 | } 36 | } 37 | 38 | contract WalletFactory is TimelockCallable, Basic { 39 | address public immutable userDatabase; 40 | bytes32 public immutable trustProxyAdminCodeHash; //proxyAdmin for ControllerLib 41 | address public trustAccountLogic; //ControllerLib 42 | address public trustSubAccountLogic; //ControllerLibSub 43 | 44 | event updateTrustLogic( 45 | address _trustAccountLogic, 46 | address _trustSubAccountLogic 47 | ); 48 | 49 | event mainAccountCreate(address _userAddress, address _newAccount); 50 | event subAccountCreate(address _mainAccount, address _newSubAccount); 51 | 52 | constructor( 53 | address _userDatabase, 54 | address _trustAccountLogic, 55 | address _trustSubAccountLogic, 56 | address _timelock, 57 | bytes32 _trustProxyAdminCodeHash 58 | ) TimelockCallable(_timelock) { 59 | userDatabase = _userDatabase; 60 | trustAccountLogic = _trustAccountLogic; 61 | trustSubAccountLogic = _trustSubAccountLogic; 62 | trustProxyAdminCodeHash = _trustProxyAdminCodeHash; 63 | } 64 | 65 | function setTrustLogic( 66 | address _trustAccountLogic, 67 | address _trustSubAccountLogic 68 | ) external onlyTimelock { 69 | trustAccountLogic = _trustAccountLogic; 70 | trustSubAccountLogic = _trustSubAccountLogic; 71 | 72 | emit updateTrustLogic(trustAccountLogic, trustSubAccountLogic); 73 | } 74 | 75 | function proxyAdminCheck(address defaultProxyAdmin) 76 | internal 77 | returns (address) 78 | { 79 | if (defaultProxyAdmin == address(0)) { 80 | ProxyAdmin newProxyAdmin = new ProxyAdmin(); 81 | address newProxyAdminAddr = address(newProxyAdmin); 82 | Ownable(newProxyAdminAddr).transferOwnership(msg.sender); 83 | return newProxyAdminAddr; 84 | } 85 | bytes32 codeHash; 86 | assembly { 87 | codeHash := extcodehash(defaultProxyAdmin) 88 | } 89 | require( 90 | Ownable(defaultProxyAdmin).owner() == msg.sender && 91 | codeHash == trustProxyAdminCodeHash, 92 | "!trustProxyAdmin" 93 | ); 94 | return defaultProxyAdmin; 95 | } 96 | 97 | function upgradableWalletCreate( 98 | address _logic, 99 | address _admin, 100 | bytes memory _data 101 | ) internal returns (address) { 102 | ProxyWallet newAccount = new ProxyWallet(_logic, _admin, _data); 103 | address newAccountAddr = address(newAccount); 104 | OwnableUpgradeable(newAccountAddr).transferOwnership(msg.sender); 105 | IControllerLink(userDatabase).addAuth(msg.sender, newAccountAddr); 106 | 107 | emit mainAccountCreate(msg.sender, newAccountAddr); 108 | return newAccountAddr; 109 | } 110 | 111 | function createAccount(address _admin, bytes memory _data) 112 | external 113 | payable 114 | returns (address proxyAdmin, address newAccount) 115 | { 116 | proxyAdmin = proxyAdminCheck(_admin); 117 | newAccount = upgradableWalletCreate( 118 | trustAccountLogic, 119 | proxyAdmin, 120 | _data 121 | ); 122 | safeTransferAVAX(newAccount, msg.value); 123 | } 124 | 125 | function createSubAccount( 126 | address _adapterManager, 127 | address _autoExecutor, 128 | bytes memory _data 129 | ) external payable returns (address newAccount) { 130 | require( 131 | IControllerLink(userDatabase).existing(msg.sender) == true, 132 | "!cianUser" 133 | ); 134 | newAccount = Clones.clone(trustSubAccountLogic); 135 | IControllerLibSub(newAccount).initialize( 136 | _adapterManager, 137 | _autoExecutor, 138 | _data 139 | ); 140 | Ownable(newAccount).transferOwnership(msg.sender); 141 | IControllerLink(userDatabase).addAuth(msg.sender, newAccount); 142 | safeTransferAVAX(newAccount, msg.value); 143 | 144 | emit subAccountCreate(msg.sender, address(newAccount)); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /contracts/core/verifier/ERC2612Verifier.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; 6 | import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; 7 | import "./IERC2612Verifier.sol"; 8 | import "../../adapters/IAdapterManager.sol"; 9 | 10 | contract ERC2612Verifier is IERC2612Verifier { 11 | using ECDSA for bytes32; 12 | string public constant name = "CIAN.ERC2612Verifier"; 13 | bytes32 immutable DOMAIN_SEPARATOR; 14 | // keccak256("Permit(address account,address operator,bytes32 approvalType,uint256 nonce,uint256 deadline)"); 15 | bytes32 public constant PERMIT_TYPEHASH = 16 | 0xd29eae1810f9a3f065590ccfa473d6fdb29545b7a5e09c439cc6b0552ad6ed86; 17 | 18 | mapping(address => uint256) public nonces; 19 | mapping(address => mapping(address => bytes32)) public approvals_types; 20 | mapping(address => mapping(address => uint256)) public approvals_deadline; 21 | address public adapterManager; 22 | 23 | constructor(address _adapterManager) { 24 | adapterManager = _adapterManager; 25 | uint256 chainId; 26 | assembly { 27 | chainId := chainid() 28 | } 29 | DOMAIN_SEPARATOR = keccak256( 30 | abi.encode( 31 | keccak256( 32 | "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" 33 | ), 34 | keccak256(bytes(name)), 35 | keccak256(bytes("1")), 36 | chainId, 37 | address(this) 38 | ) 39 | ); 40 | } 41 | 42 | function approvals(address account, address operator) 43 | external 44 | view 45 | returns (uint256, bytes32) 46 | { 47 | return ( 48 | approvals_deadline[account][operator], 49 | approvals_types[account][operator] 50 | ); 51 | } 52 | 53 | function revoke(address account, address operator) external { 54 | require( 55 | OwnableUpgradeable(account).owner() == msg.sender, 56 | "not the owner of the address" 57 | ); 58 | approvals_deadline[account][operator] = 0; 59 | emit OperatorUpdate(account, operator, bytes32(0)); 60 | } 61 | 62 | function approve( 63 | address account, 64 | address operator, 65 | bytes32 approvalType, 66 | uint256 deadline 67 | ) external override { 68 | require( 69 | OwnableUpgradeable(account).owner() == msg.sender, 70 | "not the owner of the address" 71 | ); 72 | approvals_deadline[account][operator] = deadline; 73 | approvals_types[account][operator] = approvalType; 74 | emit OperatorUpdate(account, operator, approvalType); 75 | } 76 | 77 | function permit( 78 | address account, 79 | address operator, 80 | bytes32 approvalType, 81 | uint256 deadline, 82 | uint8 v, 83 | bytes32 r, 84 | bytes32 s 85 | ) external override { 86 | require(deadline >= block.timestamp, "Permit: EXPIRED"); 87 | bytes32 digest = keccak256( 88 | abi.encodePacked( 89 | "\x19\x01", 90 | DOMAIN_SEPARATOR, 91 | keccak256( 92 | abi.encode( 93 | PERMIT_TYPEHASH, 94 | account, 95 | operator, 96 | approvalType, 97 | nonces[account]++, 98 | deadline 99 | ) 100 | ) 101 | ) 102 | ); 103 | address recoveredAddress = digest.recover(v, r, s); 104 | require( 105 | OwnableUpgradeable(account).owner() == recoveredAddress && 106 | recoveredAddress != address(0x0), 107 | "not the owner of the address" 108 | ); 109 | approvals_deadline[account][operator] = deadline; 110 | approvals_types[account][operator] = approvalType; 111 | emit OperatorUpdate(account, operator, approvalType); 112 | } 113 | 114 | function isTxPermitted( 115 | address account, 116 | address operator, 117 | address adapter 118 | ) external view override returns (bool) { 119 | IAdapterManager manager = IAdapterManager(adapterManager); 120 | uint256 index = manager.adaptersIndex(adapter); 121 | require(index >= manager.maxReservedBits(), "adapter invalid!"); 122 | uint256 types = uint256(approvals_types[account][operator]); 123 | require((types >> index) & 1 == 1, "Adapter: not allowed!"); 124 | if (approvals_deadline[account][operator] >= block.timestamp) { 125 | return true; 126 | } 127 | return false; 128 | } 129 | 130 | function isTxPermitted( 131 | address account, 132 | address operator, 133 | uint256 operationIndex 134 | ) external view override returns (bool) { 135 | require( 136 | operationIndex < IAdapterManager(adapterManager).maxReservedBits(), 137 | "operation invalid!" 138 | ); 139 | uint256 types = uint256(approvals_types[account][operator]); 140 | require((types >> operationIndex) & 1 == 1, "Basic: not allowed!"); 141 | if (approvals_deadline[account][operator] >= block.timestamp) { 142 | return true; 143 | } 144 | return false; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /contracts/core/verifier/IERC2612Verifier.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface IERC2612Verifier { 6 | event OperatorUpdate( 7 | address account, 8 | address operator, 9 | bytes32 approvalType 10 | ); 11 | 12 | function approve( 13 | address account, 14 | address operator, 15 | bytes32 approvalType, 16 | uint256 deadline 17 | ) external; 18 | 19 | function permit( 20 | address account, 21 | address operator, 22 | bytes32 approvalType, 23 | uint256 deadline, 24 | uint8 v, 25 | bytes32 r, 26 | bytes32 s 27 | ) external; 28 | 29 | function isTxPermitted( 30 | address account, 31 | address operator, 32 | address adapter 33 | ) external view returns (bool); 34 | 35 | function isTxPermitted( 36 | address account, 37 | address operator, 38 | uint256 operation 39 | ) external view returns (bool); 40 | } 41 | -------------------------------------------------------------------------------- /contracts/core/verifier/ITokenApprovalVerifier.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface ITokenApprovalVerifier { 6 | event ApprovalUpdate(address account, address[] spenders, bool isAllowed); 7 | 8 | function approve( 9 | address account, 10 | address[] memory spenders, 11 | bool enable, 12 | uint256 deadline 13 | ) external; 14 | 15 | function permit( 16 | address account, 17 | address[] memory spenders, 18 | bool enable, 19 | uint256 deadline, 20 | uint8 v, 21 | bytes32 r, 22 | bytes32 s 23 | ) external; 24 | 25 | function isWhitelisted(address account, address operator) 26 | external 27 | view 28 | returns (bool); 29 | } 30 | -------------------------------------------------------------------------------- /contracts/core/verifier/TokenApprovalVerifier.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; 6 | import "./ITokenApprovalVerifier.sol"; 7 | 8 | contract TokenApprovalVerifier is ITokenApprovalVerifier { 9 | string public constant name = "CIAN.TokenVerifier"; 10 | bytes32 immutable DOMAIN_SEPARATOR; 11 | // keccak256("Permit(address account,addresses[] spenders,bool enable,uint256 nonce,uint256 deadline)"); 12 | bytes32 public constant PERMIT_TYPEHASH = 13 | 0x5b81b3276291d9d72597588dc491860bfd4b6f4cec1758e357b430c3b4db0619; 14 | 15 | mapping(address => uint256) public nonces; 16 | mapping(address => mapping(address => bool)) public approval_enable; 17 | mapping(address => mapping(address => uint256)) public approvals_deadline; 18 | 19 | constructor() { 20 | uint256 chainId; 21 | assembly { 22 | chainId := chainid() 23 | } 24 | DOMAIN_SEPARATOR = keccak256( 25 | abi.encode( 26 | keccak256( 27 | "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" 28 | ), 29 | keccak256(bytes(name)), 30 | keccak256(bytes("1")), 31 | chainId, 32 | address(this) 33 | ) 34 | ); 35 | } 36 | 37 | function approvals(address account, address spender) 38 | external 39 | view 40 | returns (uint256, bool) 41 | { 42 | return ( 43 | approvals_deadline[account][spender], 44 | approval_enable[account][spender] 45 | ); 46 | } 47 | 48 | function revoke(address account, address[] memory spenders) external { 49 | require( 50 | OwnableUpgradeable(account).owner() == msg.sender, 51 | "not the owner of the address" 52 | ); 53 | for (uint256 i = 0; i < spenders.length; i++) { 54 | approvals_deadline[account][spenders[i]] = 0; 55 | } 56 | 57 | emit ApprovalUpdate(account, spenders, false); 58 | } 59 | 60 | function approve( 61 | address account, 62 | address[] memory spenders, 63 | bool enable, 64 | uint256 deadline 65 | ) external override { 66 | require( 67 | OwnableUpgradeable(account).owner() == msg.sender, 68 | "not the owner of the address" 69 | ); 70 | for (uint256 i = 0; i < spenders.length; i++) { 71 | approvals_deadline[account][spenders[i]] = deadline; 72 | approval_enable[account][spenders[i]] = enable; 73 | } 74 | 75 | emit ApprovalUpdate(account, spenders, enable); 76 | } 77 | 78 | function permit( 79 | address account, 80 | address[] memory spenders, 81 | bool enable, 82 | uint256 deadline, 83 | uint8 v, 84 | bytes32 r, 85 | bytes32 s 86 | ) external override { 87 | require(deadline >= block.timestamp, "Permit: EXPIRED"); 88 | bytes32 digest = keccak256( 89 | abi.encodePacked( 90 | "\x19\x01", 91 | DOMAIN_SEPARATOR, 92 | keccak256( 93 | abi.encode( 94 | PERMIT_TYPEHASH, 95 | account, 96 | spenders, 97 | enable, 98 | nonces[account]++, 99 | deadline 100 | ) 101 | ) 102 | ) 103 | ); 104 | address recoveredAddress = ecrecover(digest, v, r, s); 105 | require( 106 | OwnableUpgradeable(account).owner() == recoveredAddress && 107 | recoveredAddress != address(0x0), 108 | "not the owner of the address" 109 | ); 110 | for (uint256 i = 0; i < spenders.length; i++) { 111 | approvals_deadline[account][spenders[i]] = deadline; 112 | approval_enable[account][spenders[i]] = enable; 113 | } 114 | emit ApprovalUpdate(account, spenders, enable); 115 | } 116 | 117 | function isWhitelisted(address account, address spender) 118 | external 119 | view 120 | override 121 | returns (bool) 122 | { 123 | require(approval_enable[account][spender], "Not whitelisted!"); 124 | if (approvals_deadline[account][spender] >= block.timestamp) { 125 | return true; 126 | } 127 | return false; 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /contracts/interfaces/IToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface IToken { 6 | function approve(address, uint256) external; 7 | 8 | function transfer(address, uint256) external; 9 | 10 | function mint() external payable; 11 | 12 | function mint(uint256 mintAmount) external payable; 13 | 14 | function transferFrom( 15 | address, 16 | address, 17 | uint256 18 | ) external; 19 | 20 | function deposit() external payable; 21 | 22 | function withdraw(uint256) external; 23 | 24 | function balanceOf(address) external view returns (uint256); 25 | 26 | function decimals() external view returns (uint256); 27 | 28 | function symbol() external view returns (string memory); 29 | 30 | function allowance(address owner, address spender) 31 | external 32 | view 33 | returns (uint256); 34 | } 35 | -------------------------------------------------------------------------------- /contracts/interfaces/IWAVAX.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface IWAVAX { 6 | function allowance(address, address) external view returns (uint256); 7 | 8 | function approve(address guy, uint256 wad) external returns (bool); 9 | 10 | function balanceOf(address) external view returns (uint256); 11 | 12 | function decimals() external view returns (uint8); 13 | 14 | function deposit() external payable; 15 | 16 | function name() external view returns (string memory); 17 | 18 | function symbol() external view returns (string memory); 19 | 20 | function totalSupply() external view returns (uint256); 21 | 22 | function transfer(address dst, uint256 wad) external returns (bool); 23 | 24 | function transferFrom( 25 | address src, 26 | address dst, 27 | uint256 wad 28 | ) external returns (bool); 29 | 30 | function withdraw(uint256 wad) external; 31 | } 32 | -------------------------------------------------------------------------------- /contracts/interfaces/benqi/IComptroller.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface IComptroller { 6 | function accountAssets(address, uint256) external view returns (address); 7 | 8 | function admin() external view returns (address); 9 | 10 | function allMarkets(uint256) external view returns (address); 11 | 12 | function borrowAllowed( 13 | address qiToken, 14 | address borrower, 15 | uint256 borrowAmount 16 | ) external returns (uint256); 17 | 18 | function borrowCapGuardian() external view returns (address); 19 | 20 | function borrowCaps(address) external view returns (uint256); 21 | 22 | function borrowVerify( 23 | address qiToken, 24 | address borrower, 25 | uint256 borrowAmount 26 | ) external; 27 | 28 | function checkMembership(address account, address qiToken) 29 | external 30 | view 31 | returns (bool); 32 | 33 | function claimReward(uint8 rewardType, address holder) external; 34 | 35 | function claimReward( 36 | uint8 rewardType, 37 | address holder, 38 | address[] calldata qiTokens 39 | ) external; 40 | 41 | function claimReward( 42 | uint8 rewardType, 43 | address[] calldata holders, 44 | address[] calldata qiTokens, 45 | bool borrowers, 46 | bool suppliers 47 | ) external payable; 48 | 49 | function closeFactorMantissa() external view returns (uint256); 50 | 51 | function comptrollerImplementation() external view returns (address); 52 | 53 | function enterMarkets(address[] calldata qiTokens) 54 | external 55 | returns (uint256[] calldata); 56 | 57 | function exitMarket(address qiTokenAddress) external returns (uint256); 58 | 59 | function getAccountLiquidity(address account) 60 | external 61 | view 62 | returns ( 63 | uint256, 64 | uint256, 65 | uint256 66 | ); 67 | 68 | function getAllMarkets() external view returns (address[] calldata); 69 | 70 | function getAssetsIn(address account) 71 | external 72 | view 73 | returns (address[] calldata); 74 | 75 | function getBlockTimestamp() external view returns (uint256); 76 | 77 | function getHypotheticalAccountLiquidity( 78 | address account, 79 | address qiTokenModify, 80 | uint256 redeemTokens, 81 | uint256 borrowAmount 82 | ) 83 | external 84 | view 85 | returns ( 86 | uint256, 87 | uint256, 88 | uint256 89 | ); 90 | 91 | function initialIndexConstant() external view returns (uint224); 92 | 93 | function isComptroller() external view returns (bool); 94 | 95 | function liquidateBorrowAllowed( 96 | address qiTokenBorrowed, 97 | address qiTokenCollateral, 98 | address liquidator, 99 | address borrower, 100 | uint256 repayAmount 101 | ) external returns (uint256); 102 | 103 | function liquidateBorrowVerify( 104 | address qiTokenBorrowed, 105 | address qiTokenCollateral, 106 | address liquidator, 107 | address borrower, 108 | uint256 actualRepayAmount, 109 | uint256 seizeTokens 110 | ) external; 111 | 112 | function liquidateCalculateSeizeTokens( 113 | address qiTokenBorrowed, 114 | address qiTokenCollateral, 115 | uint256 actualRepayAmount 116 | ) external view returns (uint256, uint256); 117 | 118 | function liquidationIncentiveMantissa() external view returns (uint256); 119 | 120 | function markets(address) 121 | external 122 | view 123 | returns ( 124 | bool isListed, 125 | uint256 collateralFactorMantissa, 126 | bool isQied 127 | ); 128 | 129 | function maxAssets() external view returns (uint256); 130 | 131 | function mintAllowed( 132 | address qiToken, 133 | address minter, 134 | uint256 mintAmount 135 | ) external returns (uint256); 136 | 137 | function mintGuardianPaused(address) external view returns (bool); 138 | 139 | function mintVerify( 140 | address qiToken, 141 | address minter, 142 | uint256 actualMintAmount, 143 | uint256 mintTokens 144 | ) external; 145 | 146 | function oracle() external view returns (address); 147 | 148 | function pauseGuardian() external view returns (address); 149 | 150 | function pendingAdmin() external view returns (address); 151 | 152 | function pendingComptrollerImplementation() external view returns (address); 153 | 154 | function qiAddress() external view returns (address); 155 | 156 | function redeemAllowed( 157 | address qiToken, 158 | address redeemer, 159 | uint256 redeemTokens 160 | ) external returns (uint256); 161 | 162 | function redeemVerify( 163 | address qiToken, 164 | address redeemer, 165 | uint256 redeemAmount, 166 | uint256 redeemTokens 167 | ) external; 168 | 169 | function repayBorrowAllowed( 170 | address qiToken, 171 | address payer, 172 | address borrower, 173 | uint256 repayAmount 174 | ) external returns (uint256); 175 | 176 | function repayBorrowVerify( 177 | address qiToken, 178 | address payer, 179 | address borrower, 180 | uint256 actualRepayAmount, 181 | uint256 borrowerIndex 182 | ) external; 183 | 184 | function rewardAccrued(uint8, address) external view returns (uint256); 185 | 186 | function rewardAvax() external view returns (uint8); 187 | 188 | function rewardBorrowState(uint8, address) 189 | external 190 | view 191 | returns (uint224 index, uint32 timestamp); 192 | 193 | function rewardBorrowerIndex( 194 | uint8, 195 | address, 196 | address 197 | ) external view returns (uint256); 198 | 199 | function rewardQi() external view returns (uint8); 200 | 201 | function rewardSpeeds(uint8, address) external view returns (uint256); 202 | 203 | function rewardSupplierIndex( 204 | uint8, 205 | address, 206 | address 207 | ) external view returns (uint256); 208 | 209 | function rewardSupplyState(uint8, address) 210 | external 211 | view 212 | returns (uint224 index, uint32 timestamp); 213 | 214 | function seizeAllowed( 215 | address qiTokenCollateral, 216 | address qiTokenBorrowed, 217 | address liquidator, 218 | address borrower, 219 | uint256 seizeTokens 220 | ) external returns (uint256); 221 | 222 | function seizeGuardianPaused() external view returns (bool); 223 | 224 | function seizeVerify( 225 | address qiTokenCollateral, 226 | address qiTokenBorrowed, 227 | address liquidator, 228 | address borrower, 229 | uint256 seizeTokens 230 | ) external; 231 | 232 | function setQiAddress(address newQiAddress) external; 233 | 234 | function transferAllowed( 235 | address qiToken, 236 | address src, 237 | address dst, 238 | uint256 transferTokens 239 | ) external returns (uint256); 240 | 241 | function transferGuardianPaused() external view returns (bool); 242 | 243 | function transferVerify( 244 | address qiToken, 245 | address src, 246 | address dst, 247 | uint256 transferTokens 248 | ) external; 249 | } 250 | -------------------------------------------------------------------------------- /contracts/interfaces/benqi/IMaximillion.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface IMaximillion { 6 | function jAvax() external view returns (address); 7 | 8 | function repayBehalf(address borrower) external payable; 9 | 10 | function repayBehalfExplicit(address borrower, address jAvax_) 11 | external 12 | payable; 13 | } 14 | -------------------------------------------------------------------------------- /contracts/interfaces/benqi/IQiAVAX.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface IQiAVAX { 6 | function _acceptAdmin() external returns (uint256); 7 | 8 | function _addReserves() external payable returns (uint256); 9 | 10 | function _reduceReserves(uint256 reduceAmount) external returns (uint256); 11 | 12 | function _setComptroller(address newComptroller) external returns (uint256); 13 | 14 | function _setInterestRateModel(address newInterestRateModel) 15 | external 16 | returns (uint256); 17 | 18 | function _setPendingAdmin(address newPendingAdmin) 19 | external 20 | returns (uint256); 21 | 22 | function _setProtocolSeizeShare(uint256 newProtocolSeizeShareMantissa) 23 | external 24 | returns (uint256); 25 | 26 | function _setReserveFactor(uint256 newReserveFactorMantissa) 27 | external 28 | returns (uint256); 29 | 30 | function accrualBlockTimestamp() external view returns (uint256); 31 | 32 | function accrueInterest() external returns (uint256); 33 | 34 | function admin() external view returns (address); 35 | 36 | function allowance(address owner, address spender) 37 | external 38 | view 39 | returns (uint256); 40 | 41 | function approve(address spender, uint256 amount) external returns (bool); 42 | 43 | function balanceOf(address owner) external view returns (uint256); 44 | 45 | function balanceOfUnderlying(address owner) external returns (uint256); 46 | 47 | function borrow(uint256 borrowAmount) external returns (uint256); 48 | 49 | function borrowBalanceCurrent(address account) external returns (uint256); 50 | 51 | function borrowBalanceStored(address account) 52 | external 53 | view 54 | returns (uint256); 55 | 56 | function borrowIndex() external view returns (uint256); 57 | 58 | function borrowRatePerTimestamp() external view returns (uint256); 59 | 60 | function comptroller() external view returns (address); 61 | 62 | function decimals() external view returns (uint8); 63 | 64 | function exchangeRateCurrent() external returns (uint256); 65 | 66 | function exchangeRateStored() external view returns (uint256); 67 | 68 | function getAccountSnapshot(address account) 69 | external 70 | view 71 | returns ( 72 | uint256, 73 | uint256, 74 | uint256, 75 | uint256 76 | ); 77 | 78 | function getCash() external view returns (uint256); 79 | 80 | function initialize( 81 | address comptroller_, 82 | address interestRateModel_, 83 | uint256 initialExchangeRateMantissa_, 84 | string calldata name_, 85 | string calldata symbol_, 86 | uint8 decimals_ 87 | ) external; 88 | 89 | function interestRateModel() external view returns (address); 90 | 91 | function isQiToken() external view returns (bool); 92 | 93 | function liquidateBorrow(address borrower, address qiTokenCollateral) 94 | external 95 | payable; 96 | 97 | function mint() external payable; 98 | 99 | function name() external view returns (string memory); 100 | 101 | function pendingAdmin() external view returns (address); 102 | 103 | function protocolSeizeShareMantissa() external view returns (uint256); 104 | 105 | function redeem(uint256 redeemTokens) external returns (uint256); 106 | 107 | function redeemUnderlying(uint256 redeemAmount) external returns (uint256); 108 | 109 | function repayBorrow() external payable; 110 | 111 | function repayBorrowBehalf(address borrower) external payable; 112 | 113 | function reserveFactorMantissa() external view returns (uint256); 114 | 115 | function seize( 116 | address liquidator, 117 | address borrower, 118 | uint256 seizeTokens 119 | ) external returns (uint256); 120 | 121 | function supplyRatePerTimestamp() external view returns (uint256); 122 | 123 | function symbol() external view returns (string memory); 124 | 125 | function totalBorrows() external view returns (uint256); 126 | 127 | function totalBorrowsCurrent() external returns (uint256); 128 | 129 | function totalReserves() external view returns (uint256); 130 | 131 | function totalSupply() external view returns (uint256); 132 | 133 | function transfer(address dst, uint256 amount) external returns (bool); 134 | 135 | function transferFrom( 136 | address src, 137 | address dst, 138 | uint256 amount 139 | ) external returns (bool); 140 | } 141 | -------------------------------------------------------------------------------- /contracts/interfaces/benqi/IQiToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface IQiToken { 6 | function _acceptAdmin() external returns (uint256); 7 | 8 | function _addReserves(uint256 addAmount) external returns (uint256); 9 | 10 | function _reduceReserves(uint256 reduceAmount) external returns (uint256); 11 | 12 | function _setComptroller(address newComptroller) external returns (uint256); 13 | 14 | function _setImplementation( 15 | address implementation_, 16 | bool allowResign, 17 | bytes calldata becomeImplementationData 18 | ) external; 19 | 20 | function _setInterestRateModel(address newInterestRateModel) 21 | external 22 | returns (uint256); 23 | 24 | function _setPendingAdmin(address newPendingAdmin) 25 | external 26 | returns (uint256); 27 | 28 | function _setProtocolSeizeShare(uint256 newProtocolSeizeShareMantissa) 29 | external 30 | returns (uint256); 31 | 32 | function _setReserveFactor(uint256 newReserveFactorMantissa) 33 | external 34 | returns (uint256); 35 | 36 | function accrualBlockTimestamp() external view returns (uint256); 37 | 38 | function accrueInterest() external returns (uint256); 39 | 40 | function admin() external view returns (address); 41 | 42 | function allowance(address owner, address spender) 43 | external 44 | view 45 | returns (uint256); 46 | 47 | function approve(address spender, uint256 amount) external returns (bool); 48 | 49 | function balanceOf(address owner) external view returns (uint256); 50 | 51 | function balanceOfUnderlying(address owner) external returns (uint256); 52 | 53 | function borrow(uint256 borrowAmount) external returns (uint256); 54 | 55 | function borrowBalanceCurrent(address account) external returns (uint256); 56 | 57 | function borrowBalanceStored(address account) 58 | external 59 | view 60 | returns (uint256); 61 | 62 | function borrowIndex() external view returns (uint256); 63 | 64 | function borrowRatePerTimestamp() external view returns (uint256); 65 | 66 | function comptroller() external view returns (address); 67 | 68 | function decimals() external view returns (uint8); 69 | 70 | function delegateToImplementation(bytes calldata data) 71 | external 72 | returns (bytes calldata); 73 | 74 | function delegateToViewImplementation(bytes calldata data) 75 | external 76 | view 77 | returns (bytes calldata); 78 | 79 | function exchangeRateCurrent() external returns (uint256); 80 | 81 | function exchangeRateStored() external view returns (uint256); 82 | 83 | function getAccountSnapshot(address account) 84 | external 85 | view 86 | returns ( 87 | uint256, 88 | uint256, 89 | uint256, 90 | uint256 91 | ); 92 | 93 | function getCash() external view returns (uint256); 94 | 95 | function implementation() external view returns (address); 96 | 97 | function interestRateModel() external view returns (address); 98 | 99 | function isQiToken() external view returns (bool); 100 | 101 | function liquidateBorrow( 102 | address borrower, 103 | uint256 repayAmount, 104 | address qiTokenCollateral 105 | ) external returns (uint256); 106 | 107 | function mint(uint256 mintAmount) external returns (uint256); 108 | 109 | function name() external view returns (string memory); 110 | 111 | function pendingAdmin() external view returns (address); 112 | 113 | function protocolSeizeShareMantissa() external view returns (uint256); 114 | 115 | function redeem(uint256 redeemTokens) external returns (uint256); 116 | 117 | function redeemUnderlying(uint256 redeemAmount) external returns (uint256); 118 | 119 | function repayBorrow(uint256 repayAmount) external returns (uint256); 120 | 121 | function repayBorrowBehalf(address borrower, uint256 repayAmount) 122 | external 123 | returns (uint256); 124 | 125 | function reserveFactorMantissa() external view returns (uint256); 126 | 127 | function seize( 128 | address liquidator, 129 | address borrower, 130 | uint256 seizeTokens 131 | ) external returns (uint256); 132 | 133 | function supplyRatePerTimestamp() external view returns (uint256); 134 | 135 | function sweepToken(address token) external; 136 | 137 | function symbol() external view returns (string memory); 138 | 139 | function totalBorrows() external view returns (uint256); 140 | 141 | function totalBorrowsCurrent() external returns (uint256); 142 | 143 | function totalReserves() external view returns (uint256); 144 | 145 | function totalSupply() external view returns (uint256); 146 | 147 | function transfer(address dst, uint256 amount) external returns (bool); 148 | 149 | function transferFrom( 150 | address src, 151 | address dst, 152 | uint256 amount 153 | ) external returns (bool); 154 | 155 | function underlying() external view returns (address); 156 | } 157 | -------------------------------------------------------------------------------- /contracts/interfaces/benqi/ISAVAX.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface ISAVAX { 6 | function DEFAULT_ADMIN_ROLE() external view returns (bytes32); 7 | 8 | function ROLE_ACCRUE_REWARDS() external view returns (bytes32); 9 | 10 | function ROLE_DEPOSIT() external view returns (bytes32); 11 | 12 | function ROLE_PAUSE() external view returns (bytes32); 13 | 14 | function ROLE_PAUSE_MINTING() external view returns (bytes32); 15 | 16 | function ROLE_RESUME() external view returns (bytes32); 17 | 18 | function ROLE_RESUME_MINTING() external view returns (bytes32); 19 | 20 | function ROLE_SET_TOTAL_POOLED_AVAX_CAP() external view returns (bytes32); 21 | 22 | function ROLE_WITHDRAW() external view returns (bytes32); 23 | 24 | function accrueRewards(uint256 amount) external; 25 | 26 | function allowance(address owner, address spender) 27 | external 28 | view 29 | returns (uint256); 30 | 31 | function approve(address spender, uint256 amount) external returns (bool); 32 | 33 | function balanceOf(address account) external view returns (uint256); 34 | 35 | function cancelPendingUnlockRequests() external; 36 | 37 | function cancelRedeemableUnlockRequests() external; 38 | 39 | function cancelUnlockRequest(uint256 unlockIndex) external; 40 | 41 | function cooldownPeriod() external view returns (uint256); 42 | 43 | function decimals() external pure returns (uint8); 44 | 45 | function deposit() external; 46 | 47 | // function getPaginatedUnlockRequests( 48 | // address user, 49 | // uint256 from, 50 | // uint256 to 51 | // ) external view returns (tuple[], uint256[]); 52 | 53 | function getPooledAvaxByShares(uint256 shareAmount) 54 | external 55 | view 56 | returns (uint256); 57 | 58 | function getRoleAdmin(bytes32 role) external view returns (bytes32); 59 | 60 | function getRoleMember(bytes32 role, uint256 index) 61 | external 62 | view 63 | returns (address); 64 | 65 | function getRoleMemberCount(bytes32 role) external view returns (uint256); 66 | 67 | function getSharesByPooledAvax(uint256 avaxAmount) 68 | external 69 | view 70 | returns (uint256); 71 | 72 | function getUnlockRequestCount(address user) 73 | external 74 | view 75 | returns (uint256); 76 | 77 | function grantRole(bytes32 role, address account) external; 78 | 79 | function hasRole(bytes32 role, address account) 80 | external 81 | view 82 | returns (bool); 83 | 84 | function historicalExchangeRateTimestamps(uint256) 85 | external 86 | view 87 | returns (uint256); 88 | 89 | function historicalExchangeRatesByTimestamp(uint256) 90 | external 91 | view 92 | returns (uint256); 93 | 94 | function initialize(uint256 _cooldownPeriod, uint256 _redeemPeriod) 95 | external; 96 | 97 | function mintingPaused() external view returns (bool); 98 | 99 | function name() external pure returns (string memory); 100 | 101 | function pause() external; 102 | 103 | function pauseMinting() external; 104 | 105 | function paused() external view returns (bool); 106 | 107 | function redeem() external; 108 | 109 | function redeem(uint256 unlockIndex) external; 110 | 111 | function redeemOverdueShares() external; 112 | 113 | function redeemOverdueShares(uint256 unlockIndex) external; 114 | 115 | function redeemPeriod() external view returns (uint256); 116 | 117 | function renounceRole(bytes32 role, address account) external; 118 | 119 | function requestUnlock(uint256 shareAmount) external; 120 | 121 | function resume() external; 122 | 123 | function resumeMinting() external; 124 | 125 | function revokeRole(bytes32 role, address account) external; 126 | 127 | function setCooldownPeriod(uint256 newCooldownPeriod) external; 128 | 129 | // function setHistoricalExchangeRatesByTimestamp( 130 | // uint256[] timestamps, 131 | // uint256[] exchangeRates 132 | // ) external; 133 | 134 | function setRedeemPeriod(uint256 newRedeemPeriod) external; 135 | 136 | function setTotalPooledAvaxCap(uint256 newTotalPooledAvaxCap) external; 137 | 138 | function stakerCount() external view returns (uint256); 139 | 140 | function submit() external payable returns (uint256); 141 | 142 | function symbol() external pure returns (string memory); 143 | 144 | function totalPooledAvax() external view returns (uint256); 145 | 146 | function totalPooledAvaxCap() external view returns (uint256); 147 | 148 | function totalShares() external view returns (uint256); 149 | 150 | function totalSupply() external view returns (uint256); 151 | 152 | function transfer(address recipient, uint256 amount) 153 | external 154 | returns (bool); 155 | 156 | function transferFrom( 157 | address sender, 158 | address recipient, 159 | uint256 amount 160 | ) external returns (bool); 161 | 162 | function userSharesInCustody(address) external view returns (uint256); 163 | 164 | function userUnlockRequests(address, uint256) 165 | external 166 | view 167 | returns (uint256 startedAt, uint256 shareAmount); 168 | 169 | function withdraw(uint256 amount) external; 170 | } 171 | -------------------------------------------------------------------------------- /contracts/interfaces/traderJoe/IJoeBar.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface IJoeBar { 6 | function allowance(address owner, address spender) 7 | external 8 | view 9 | returns (uint256); 10 | 11 | function approve(address spender, uint256 amount) external returns (bool); 12 | 13 | function balanceOf(address account) external view returns (uint256); 14 | 15 | function decimals() external view returns (uint8); 16 | 17 | function decreaseAllowance(address spender, uint256 subtractedValue) 18 | external 19 | returns (bool); 20 | 21 | function enter(uint256 _amount) external; 22 | 23 | function increaseAllowance(address spender, uint256 addedValue) 24 | external 25 | returns (bool); 26 | 27 | function joe() external view returns (address); 28 | 29 | function leave(uint256 _share) external; 30 | 31 | function name() external view returns (string memory); 32 | 33 | function symbol() external view returns (string memory); 34 | 35 | function totalSupply() external view returns (uint256); 36 | 37 | function transfer(address recipient, uint256 amount) 38 | external 39 | returns (bool); 40 | 41 | function transferFrom( 42 | address sender, 43 | address recipient, 44 | uint256 amount 45 | ) external returns (bool); 46 | } 47 | -------------------------------------------------------------------------------- /contracts/interfaces/traderJoe/IJoeCallee.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface IJoeCallee { 6 | function joeCall( 7 | address sender, 8 | uint256 amount0, 9 | uint256 amount1, 10 | bytes calldata data 11 | ) external; 12 | } 13 | -------------------------------------------------------------------------------- /contracts/interfaces/traderJoe/IJoeFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface IJoeFactory { 6 | event PairCreated( 7 | address indexed token0, 8 | address indexed token1, 9 | address pair, 10 | uint256 11 | ); 12 | 13 | function feeTo() external view returns (address); 14 | 15 | function feeToSetter() external view returns (address); 16 | 17 | function migrator() external view returns (address); 18 | 19 | function getPair(address tokenA, address tokenB) 20 | external 21 | view 22 | returns (address pair); 23 | 24 | function allPairs(uint256) external view returns (address pair); 25 | 26 | function allPairsLength() external view returns (uint256); 27 | 28 | function createPair(address tokenA, address tokenB) 29 | external 30 | returns (address pair); 31 | 32 | function setFeeTo(address) external; 33 | 34 | function setFeeToSetter(address) external; 35 | 36 | function setMigrator(address) external; 37 | } 38 | -------------------------------------------------------------------------------- /contracts/interfaces/traderJoe/IJoeLens/IJToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface IJToken { 6 | function _acceptAdmin() external returns (uint256); 7 | 8 | function _addReserves(uint256 addAmount) external returns (uint256); 9 | 10 | function _reduceReserves(uint256 reduceAmount) external returns (uint256); 11 | 12 | function _setCollateralCap(uint256 newCollateralCap) external; 13 | 14 | function _setImplementation( 15 | address implementation_, 16 | bool allowResign, 17 | bytes memory becomeImplementationData 18 | ) external; 19 | 20 | function _setInterestRateModel(address newInterestRateModel) 21 | external 22 | returns (uint256); 23 | 24 | function _setJoetroller(address newJoetroller) external returns (uint256); 25 | 26 | function _setPendingAdmin(address newPendingAdmin) 27 | external 28 | returns (uint256); 29 | 30 | function _setReserveFactor(uint256 newReserveFactorMantissa) 31 | external 32 | returns (uint256); 33 | 34 | function accountCollateralTokens(address) external view returns (uint256); 35 | 36 | function accrualBlockTimestamp() external view returns (uint256); 37 | 38 | function accrueInterest() external returns (uint256); 39 | 40 | function admin() external view returns (address); 41 | 42 | function allowance(address owner, address spender) 43 | external 44 | view 45 | returns (uint256); 46 | 47 | function approve(address spender, uint256 amount) external returns (bool); 48 | 49 | function balanceOf(address owner) external view returns (uint256); 50 | 51 | function balanceOfUnderlying(address owner) external returns (uint256); 52 | 53 | function borrow(uint256 borrowAmount) external returns (uint256); 54 | 55 | function borrowBalanceCurrent(address account) external returns (uint256); 56 | 57 | function borrowBalanceStored(address account) 58 | external 59 | view 60 | returns (uint256); 61 | 62 | function borrowIndex() external view returns (uint256); 63 | 64 | function borrowRatePerSecond() external view returns (uint256); 65 | 66 | function collateralCap() external view returns (uint256); 67 | 68 | function decimals() external view returns (uint8); 69 | 70 | function delegateToImplementation(bytes memory data) 71 | external 72 | returns (bytes memory); 73 | 74 | function delegateToViewImplementation(bytes memory data) 75 | external 76 | view 77 | returns (bytes memory); 78 | 79 | function exchangeRateCurrent() external returns (uint256); 80 | 81 | function exchangeRateStored() external view returns (uint256); 82 | 83 | function flashFee(uint256 amount) external view returns (uint256); 84 | 85 | function flashFeeBips() external view returns (uint256); 86 | 87 | function flashLoan( 88 | address receiver, 89 | address initiator, 90 | uint256 amount, 91 | bytes memory data 92 | ) external returns (bool); 93 | 94 | function getAccountSnapshot(address account) 95 | external 96 | view 97 | returns ( 98 | uint256, 99 | uint256, 100 | uint256, 101 | uint256 102 | ); 103 | 104 | function getCash() external view returns (uint256); 105 | 106 | function gulp() external; 107 | 108 | function implementation() external view returns (address); 109 | 110 | function interestRateModel() external view returns (address); 111 | 112 | function internalCash() external view returns (uint256); 113 | 114 | function isCollateralTokenInit(address) external view returns (bool); 115 | 116 | function isJToken() external view returns (bool); 117 | 118 | function joetroller() external view returns (address); 119 | 120 | function liquidateBorrow( 121 | address borrower, 122 | uint256 repayAmount, 123 | address jTokenCollateral 124 | ) external returns (uint256); 125 | 126 | function maxFlashLoan() external view returns (uint256); 127 | 128 | function mint(uint256 mintAmount) external returns (uint256); 129 | 130 | function name() external view returns (string memory); 131 | 132 | function pendingAdmin() external view returns (address); 133 | 134 | function redeem(uint256 redeemTokens) external returns (uint256); 135 | 136 | function redeemUnderlying(uint256 redeemAmount) external returns (uint256); 137 | 138 | function registerCollateral(address account) external returns (uint256); 139 | 140 | function repayBorrow(uint256 repayAmount) external returns (uint256); 141 | 142 | function repayBorrowBehalf(address borrower, uint256 repayAmount) 143 | external 144 | returns (uint256); 145 | 146 | function reserveFactorMantissa() external view returns (uint256); 147 | 148 | function seize( 149 | address liquidator, 150 | address borrower, 151 | uint256 seizeTokens 152 | ) external returns (uint256); 153 | 154 | function supplyRatePerSecond() external view returns (uint256); 155 | 156 | function symbol() external view returns (string memory); 157 | 158 | function totalBorrows() external view returns (uint256); 159 | 160 | function totalBorrowsCurrent() external returns (uint256); 161 | 162 | function totalCollateralTokens() external view returns (uint256); 163 | 164 | function totalReserves() external view returns (uint256); 165 | 166 | function totalSupply() external view returns (uint256); 167 | 168 | function transfer(address dst, uint256 amount) external returns (bool); 169 | 170 | function transferFrom( 171 | address src, 172 | address dst, 173 | uint256 amount 174 | ) external returns (bool); 175 | 176 | function underlying() external view returns (address); 177 | 178 | function unregisterCollateral(address account) external; 179 | } 180 | -------------------------------------------------------------------------------- /contracts/interfaces/traderJoe/IJoeLens/IJWrappedNativeDelegator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface IJWrappedNativeDelegator { 6 | function _acceptAdmin() external returns (uint256); 7 | 8 | function _addReserves(uint256 addAmount) external returns (uint256); 9 | 10 | function _addReservesNative() external payable returns (uint256); 11 | 12 | function _reduceReserves(uint256 reduceAmount) external returns (uint256); 13 | 14 | function _setImplementation( 15 | address implementation_, 16 | bool allowResign, 17 | bytes memory becomeImplementationData 18 | ) external; 19 | 20 | function _setInterestRateModel(address newInterestRateModel) 21 | external 22 | returns (uint256); 23 | 24 | function _setJoetroller(address newJoetroller) external returns (uint256); 25 | 26 | function _setPendingAdmin(address newPendingAdmin) 27 | external 28 | returns (uint256); 29 | 30 | function _setReserveFactor(uint256 newReserveFactorMantissa) 31 | external 32 | returns (uint256); 33 | 34 | function accrualBlockTimestamp() external view returns (uint256); 35 | 36 | function accrueInterest() external returns (uint256); 37 | 38 | function admin() external view returns (address); 39 | 40 | function allowance(address owner, address spender) 41 | external 42 | view 43 | returns (uint256); 44 | 45 | function approve(address spender, uint256 amount) external returns (bool); 46 | 47 | function balanceOf(address owner) external view returns (uint256); 48 | 49 | function balanceOfUnderlying(address owner) external returns (uint256); 50 | 51 | function borrow(uint256 borrowAmount) external returns (uint256); 52 | 53 | function borrowBalanceCurrent(address account) external returns (uint256); 54 | 55 | function borrowBalanceStored(address account) 56 | external 57 | view 58 | returns (uint256); 59 | 60 | function borrowIndex() external view returns (uint256); 61 | 62 | function borrowNative(uint256 borrowAmount) external returns (uint256); 63 | 64 | function borrowRatePerSecond() external view returns (uint256); 65 | 66 | function decimals() external view returns (uint8); 67 | 68 | function delegateToImplementation(bytes calldata data) 69 | external 70 | returns (bytes calldata); 71 | 72 | function delegateToViewImplementation(bytes calldata data) 73 | external 74 | view 75 | returns (bytes calldata); 76 | 77 | function exchangeRateCurrent() external returns (uint256); 78 | 79 | function exchangeRateStored() external view returns (uint256); 80 | 81 | function flashFeeBips() external view returns (uint256); 82 | 83 | function flashLoan( 84 | address receiver, 85 | address initiator, 86 | uint256 amount, 87 | bytes calldata data 88 | ) external returns (bool); 89 | 90 | function getAccountSnapshot(address account) 91 | external 92 | view 93 | returns ( 94 | uint256, 95 | uint256, 96 | uint256, 97 | uint256 98 | ); 99 | 100 | function getCash() external view returns (uint256); 101 | 102 | function implementation() external view returns (address); 103 | 104 | function interestRateModel() external view returns (address); 105 | 106 | function isJToken() external view returns (bool); 107 | 108 | function joetroller() external view returns (address); 109 | 110 | function liquidateBorrow( 111 | address borrower, 112 | uint256 repayAmount, 113 | address jTokenCollateral 114 | ) external returns (uint256); 115 | 116 | function liquidateBorrowNative(address borrower, address jTokenCollateral) 117 | external 118 | payable 119 | returns (uint256); 120 | 121 | function mint(uint256 mintAmount) external returns (uint256); 122 | 123 | function mintNative() external payable returns (uint256); 124 | 125 | function name() external view returns (string memory); 126 | 127 | function pendingAdmin() external view returns (address); 128 | 129 | function redeem(uint256 redeemTokens) external returns (uint256); 130 | 131 | function redeemNative(uint256 redeemTokens) external returns (uint256); 132 | 133 | function redeemUnderlying(uint256 redeemAmount) external returns (uint256); 134 | 135 | function redeemUnderlyingNative(uint256 redeemAmount) 136 | external 137 | returns (uint256); 138 | 139 | function repayBorrow(uint256 repayAmount) external returns (uint256); 140 | 141 | function repayBorrowBehalf(address borrower, uint256 repayAmount) 142 | external 143 | returns (uint256); 144 | 145 | function repayBorrowBehalfNative(address borrower) 146 | external 147 | payable 148 | returns (uint256); 149 | 150 | function repayBorrowNative() external payable returns (uint256); 151 | 152 | function reserveFactorMantissa() external view returns (uint256); 153 | 154 | function seize( 155 | address liquidator, 156 | address borrower, 157 | uint256 seizeTokens 158 | ) external returns (uint256); 159 | 160 | function supplyRatePerSecond() external view returns (uint256); 161 | 162 | function symbol() external view returns (string memory); 163 | 164 | function totalBorrows() external view returns (uint256); 165 | 166 | function totalBorrowsCurrent() external returns (uint256); 167 | 168 | function totalReserves() external view returns (uint256); 169 | 170 | function totalSupply() external view returns (uint256); 171 | 172 | function transfer(address dst, uint256 amount) external returns (bool); 173 | 174 | function transferFrom( 175 | address src, 176 | address dst, 177 | uint256 amount 178 | ) external returns (bool); 179 | 180 | function underlying() external view returns (address); 181 | } 182 | -------------------------------------------------------------------------------- /contracts/interfaces/traderJoe/IJoeLens/IJoeLens.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface IJoeLens { 6 | enum Version { 7 | VANILLA, 8 | COLLATERALCAP, 9 | WRAPPEDNATIVE 10 | } 11 | struct JTokenMetadata { 12 | address jToken; 13 | uint256 exchangeRateCurrent; 14 | uint256 supplyRatePerSecond; 15 | uint256 borrowRatePerSecond; 16 | uint256 reserveFactorMantissa; 17 | uint256 totalBorrows; 18 | uint256 totalReserves; 19 | uint256 totalSupply; 20 | uint256 totalCash; 21 | uint256 totalCollateralTokens; 22 | bool isListed; 23 | uint256 collateralFactorMantissa; 24 | address underlyingAssetAddress; 25 | uint256 jTokenDecimals; 26 | uint256 underlyingDecimals; 27 | Version version; 28 | uint256 collateralCap; 29 | uint256 underlyingPrice; 30 | bool supplyPaused; 31 | bool borrowPaused; 32 | uint256 supplyCap; 33 | uint256 borrowCap; 34 | } 35 | 36 | function getAccountLimits(address joetroller, address account) 37 | external 38 | returns (bytes calldata); 39 | 40 | function getClaimableRewards( 41 | uint8 rewardType, 42 | address joetroller, 43 | address joe, 44 | address account 45 | ) external returns (uint256); 46 | 47 | function jTokenBalances(address jToken, address account) 48 | external 49 | returns (bytes calldata); 50 | 51 | function jTokenBalancesAll(address[] calldata jTokens, address account) 52 | external 53 | returns (bytes[] calldata); 54 | 55 | function jTokenMetadata(address jToken) 56 | external 57 | returns (JTokenMetadata calldata); 58 | 59 | function jTokenMetadataAll(address[] calldata jTokens) 60 | external 61 | returns (JTokenMetadata[] calldata); 62 | 63 | function nativeSymbol() external view returns (string calldata); 64 | } 65 | -------------------------------------------------------------------------------- /contracts/interfaces/traderJoe/IJoeLens/IJoetroller.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface IJoetroller { 6 | function _acceptAdmin() external returns (uint256); 7 | 8 | function _acceptImplementation() external returns (uint256); 9 | 10 | function _setPendingAdmin(address newPendingAdmin) 11 | external 12 | returns (uint256); 13 | 14 | function _setPendingImplementation(address newPendingImplementation) 15 | external 16 | returns (uint256); 17 | 18 | function admin() external view returns (address); 19 | 20 | function implementation() external view returns (address); 21 | 22 | function pendingAdmin() external view returns (address); 23 | 24 | function pendingImplementation() external view returns (address); 25 | 26 | /*** Assets You Are In ***/ 27 | 28 | function enterMarkets(address[] calldata jTokens) 29 | external 30 | returns (uint256[] memory); 31 | 32 | function exitMarket(address jToken) external returns (uint256); 33 | 34 | /*** Policy Hooks ***/ 35 | 36 | function mintAllowed( 37 | address jToken, 38 | address minter, 39 | uint256 mintAmount 40 | ) external returns (uint256); 41 | 42 | function mintVerify( 43 | address jToken, 44 | address minter, 45 | uint256 mintAmount, 46 | uint256 mintTokens 47 | ) external; 48 | 49 | function redeemAllowed( 50 | address jToken, 51 | address redeemer, 52 | uint256 redeemTokens 53 | ) external returns (uint256); 54 | 55 | function redeemVerify( 56 | address jToken, 57 | address redeemer, 58 | uint256 redeemAmount, 59 | uint256 redeemTokens 60 | ) external; 61 | 62 | function borrowAllowed( 63 | address jToken, 64 | address borrower, 65 | uint256 borrowAmount 66 | ) external returns (uint256); 67 | 68 | function borrowVerify( 69 | address jToken, 70 | address borrower, 71 | uint256 borrowAmount 72 | ) external; 73 | 74 | function repayBorrowAllowed( 75 | address jToken, 76 | address payer, 77 | address borrower, 78 | uint256 repayAmount 79 | ) external returns (uint256); 80 | 81 | function repayBorrowVerify( 82 | address jToken, 83 | address payer, 84 | address borrower, 85 | uint256 repayAmount, 86 | uint256 borrowerIndex 87 | ) external; 88 | 89 | function liquidateBorrowAllowed( 90 | address jTokenBorrowed, 91 | address jTokenCollateral, 92 | address liquidator, 93 | address borrower, 94 | uint256 repayAmount 95 | ) external returns (uint256); 96 | 97 | function liquidateBorrowVerify( 98 | address jTokenBorrowed, 99 | address jTokenCollateral, 100 | address liquidator, 101 | address borrower, 102 | uint256 repayAmount, 103 | uint256 seizeTokens 104 | ) external; 105 | 106 | function seizeAllowed( 107 | address jTokenCollateral, 108 | address jTokenBorrowed, 109 | address liquidator, 110 | address borrower, 111 | uint256 seizeTokens 112 | ) external returns (uint256); 113 | 114 | function seizeVerify( 115 | address jTokenCollateral, 116 | address jTokenBorrowed, 117 | address liquidator, 118 | address borrower, 119 | uint256 seizeTokens 120 | ) external; 121 | 122 | function transferAllowed( 123 | address jToken, 124 | address src, 125 | address dst, 126 | uint256 transferTokens 127 | ) external returns (uint256); 128 | 129 | function transferVerify( 130 | address jToken, 131 | address src, 132 | address dst, 133 | uint256 transferTokens 134 | ) external; 135 | 136 | /*** Liquidity/Liquidation Calculations ***/ 137 | 138 | function liquidateCalculateSeizeTokens( 139 | address jTokenBorrowed, 140 | address jTokenCollateral, 141 | uint256 repayAmount 142 | ) external view returns (uint256, uint256); 143 | 144 | function getAssetsIn(address user) external view returns (address[] memory); 145 | 146 | function oracle() external view returns (address); 147 | 148 | function markets(address jToken) 149 | external 150 | view 151 | returns ( 152 | bool, 153 | uint256, 154 | uint8 155 | ); 156 | 157 | function claimReward(uint8 rewardType, address holder) external; 158 | 159 | function claimReward( 160 | uint8 rewardType, 161 | address holder, 162 | address[] calldata jTokens 163 | ) external; 164 | 165 | function claimReward( 166 | uint8 rewardType, 167 | address[] calldata holders, 168 | address[] calldata jTokens, 169 | bool borrowers, 170 | bool suppliers 171 | ) external payable; 172 | 173 | function getAllMarkets() external view returns (address[] memory); 174 | 175 | function checkMembership(address account, address jToken) 176 | external 177 | view 178 | returns (bool); 179 | 180 | function getAccountLiquidity(address account) 181 | external 182 | view 183 | returns ( 184 | uint256, 185 | uint256, 186 | uint256 187 | ); 188 | 189 | function isMarketListed(address jToken) external returns (bool); 190 | } 191 | -------------------------------------------------------------------------------- /contracts/interfaces/traderJoe/IJoeLens/IMaximillion.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface IMaximillion { 6 | function jAvax() external view returns (address); 7 | 8 | function repayBehalf(address borrower) external payable; 9 | 10 | function repayBehalfExplicit(address borrower, address jAvax_) 11 | external 12 | payable; 13 | } 14 | -------------------------------------------------------------------------------- /contracts/interfaces/traderJoe/IJoeLens/IPriceOracle.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface IPriceOracle { 6 | function _setAdmin(address _admin) external; 7 | 8 | function _setAggregators( 9 | address[] memory jTokenAddresses, 10 | address[] memory sources 11 | ) external; 12 | 13 | function _setGuardian(address _guardian) external; 14 | 15 | function _setUnderlyingPrice( 16 | address jToken, 17 | uint256 underlyingPriceMantissa 18 | ) external; 19 | 20 | function admin() external view returns (address); 21 | 22 | function aggregators(address) external view returns (address); 23 | 24 | function getUnderlyingPrice(address jToken) external view returns (uint256); 25 | 26 | function guardian() external view returns (address); 27 | 28 | function setDirectPrice(address asset, uint256 price) external; 29 | } 30 | -------------------------------------------------------------------------------- /contracts/interfaces/traderJoe/IJoeLens/IRewardDistributor.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface IRewardDistributor { 6 | function _grantReward( 7 | uint8 rewardType, 8 | address recipient, 9 | uint256 amount 10 | ) external; 11 | 12 | function _setRewardSpeed( 13 | uint8 rewardType, 14 | address jToken, 15 | uint256 rewardSupplySpeed, 16 | uint256 rewardBorrowSpeed 17 | ) external; 18 | 19 | function admin() external view returns (address); 20 | 21 | function claimReward(uint8 rewardType, address holder) external; 22 | 23 | function claimReward( 24 | uint8 rewardType, 25 | address holder, 26 | address[] memory jTokens 27 | ) external; 28 | 29 | function claimReward( 30 | uint8 rewardType, 31 | address[] memory holders, 32 | address[] memory jTokens, 33 | bool borrowers, 34 | bool suppliers 35 | ) external payable; 36 | 37 | function getBlockTimestamp() external view returns (uint256); 38 | 39 | function initialize() external; 40 | 41 | function joeAddress() external view returns (address); 42 | 43 | function joetroller() external view returns (address); 44 | 45 | function rewardAccrued(uint8, address) external view returns (uint256); 46 | 47 | function rewardBorrowSpeeds(uint8, address) external view returns (uint256); 48 | 49 | function rewardBorrowState(uint8, address) 50 | external 51 | view 52 | returns (uint224 index, uint32 timestamp); 53 | 54 | function rewardBorrowerIndex( 55 | uint8, 56 | address, 57 | address 58 | ) external view returns (uint256); 59 | 60 | function rewardInitialIndex() external view returns (uint224); 61 | 62 | function rewardSupplierIndex( 63 | uint8, 64 | address, 65 | address 66 | ) external view returns (uint256); 67 | 68 | function rewardSupplySpeeds(uint8, address) external view returns (uint256); 69 | 70 | function rewardSupplyState(uint8, address) 71 | external 72 | view 73 | returns (uint224 index, uint32 timestamp); 74 | 75 | function setAdmin(address _newAdmin) external; 76 | 77 | function setJoeAddress(address newJoeAddress) external; 78 | 79 | function setJoetroller(address _joetroller) external; 80 | 81 | // function updateAndDistributeBorrowerRewardsForToken( 82 | // address jToken, 83 | // address borrower, 84 | // tuple marketBorrowIndex 85 | // ) external; 86 | 87 | function updateAndDistributeSupplierRewardsForToken( 88 | address jToken, 89 | address supplier 90 | ) external; 91 | } 92 | -------------------------------------------------------------------------------- /contracts/interfaces/traderJoe/IJoeLens/IRewardDistributor_.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface IRewardDistributor_ { 6 | function _grantReward( 7 | uint8 rewardType, 8 | address recipient, 9 | uint256 amount 10 | ) external; 11 | 12 | function _setRewardSpeed( 13 | uint8 rewardType, 14 | address jToken, 15 | uint256 rewardSpeed 16 | ) external; 17 | 18 | function admin() external view returns (address); 19 | 20 | function claimReward(uint8 rewardType, address holder) external; 21 | 22 | function claimReward( 23 | uint8 rewardType, 24 | address holder, 25 | address[] calldata jTokens 26 | ) external; 27 | 28 | function claimReward( 29 | uint8 rewardType, 30 | address[] calldata holders, 31 | address[] calldata jTokens, 32 | bool borrowers, 33 | bool suppliers 34 | ) external payable; 35 | 36 | function getBlockTimestamp() external view returns (uint256); 37 | 38 | function initialize() external; 39 | 40 | function joeAddress() external view returns (address); 41 | 42 | function joetroller() external view returns (address); 43 | 44 | function rewardAccrued(uint8, address) external view returns (uint256); 45 | 46 | function rewardBorrowState(uint8, address) 47 | external 48 | view 49 | returns (uint224 index, uint32 timestamp); 50 | 51 | function rewardBorrowerIndex( 52 | uint8, 53 | address, 54 | address 55 | ) external view returns (uint256); 56 | 57 | function rewardInitialIndex() external view returns (uint224); 58 | 59 | function rewardSpeeds(uint8, address) external view returns (uint256); 60 | 61 | function rewardSupplierIndex( 62 | uint8, 63 | address, 64 | address 65 | ) external view returns (uint256); 66 | 67 | function rewardSupplyState(uint8, address) 68 | external 69 | view 70 | returns (uint224 index, uint32 timestamp); 71 | 72 | function setAdmin(address _newAdmin) external; 73 | 74 | function setJoeAddress(address newJoeAddress) external; 75 | 76 | function setJoetroller(address _joetroller) external; 77 | 78 | function updateAndDistributeBorrowerRewardsForToken( 79 | address jToken, 80 | address borrower, 81 | bytes memory marketBorrowIndex 82 | ) external; 83 | 84 | function updateAndDistributeSupplierRewardsForToken( 85 | address jToken, 86 | address supplier 87 | ) external; 88 | } 89 | -------------------------------------------------------------------------------- /contracts/interfaces/traderJoe/IJoeLens/ITripleSlopeRateModelGovernance_SeedTokens.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface ITripleSlopeRateModelGovernance_SeedTokens { 6 | function baseRatePerSecond() external view returns (uint256); 7 | 8 | function getBorrowRate( 9 | uint256 cash, 10 | uint256 borrows, 11 | uint256 reserves 12 | ) external view returns (uint256); 13 | 14 | function getSupplyRate( 15 | uint256 cash, 16 | uint256 borrows, 17 | uint256 reserves, 18 | uint256 reserveFactorMantissa 19 | ) external view returns (uint256); 20 | 21 | function isInterestRateModel() external view returns (bool); 22 | 23 | function jumpMultiplierPerSecond() external view returns (uint256); 24 | 25 | function kink1() external view returns (uint256); 26 | 27 | function kink2() external view returns (uint256); 28 | 29 | function multiplierPerSecond() external view returns (uint256); 30 | 31 | function owner() external view returns (address); 32 | 33 | function roof() external view returns (uint256); 34 | 35 | function secondsPerYear() external view returns (uint256); 36 | 37 | function updateTripleRateModel( 38 | uint256 baseRatePerYear, 39 | uint256 multiplierPerYear, 40 | uint256 jumpMultiplierPerYear, 41 | uint256 kink1_, 42 | uint256 kink2_, 43 | uint256 roof_ 44 | ) external; 45 | 46 | function utilizationRate( 47 | uint256 cash, 48 | uint256 borrows, 49 | uint256 reserves 50 | ) external view returns (uint256); 51 | } 52 | -------------------------------------------------------------------------------- /contracts/interfaces/traderJoe/IJoeLens/ITripleSlopeRateModelMajors.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface ITripleSlopeRateModelMajors { 6 | function baseRatePerSecond() external view returns (uint256); 7 | 8 | function getBorrowRate( 9 | uint256 cash, 10 | uint256 borrows, 11 | uint256 reserves 12 | ) external view returns (uint256); 13 | 14 | function getSupplyRate( 15 | uint256 cash, 16 | uint256 borrows, 17 | uint256 reserves, 18 | uint256 reserveFactorMantissa 19 | ) external view returns (uint256); 20 | 21 | function isInterestRateModel() external view returns (bool); 22 | 23 | function jumpMultiplierPerSecond() external view returns (uint256); 24 | 25 | function kink1() external view returns (uint256); 26 | 27 | function kink2() external view returns (uint256); 28 | 29 | function multiplierPerSecond() external view returns (uint256); 30 | 31 | function owner() external view returns (address); 32 | 33 | function roof() external view returns (uint256); 34 | 35 | function secondsPerYear() external view returns (uint256); 36 | 37 | function updateTripleRateModel( 38 | uint256 baseRatePerYear, 39 | uint256 multiplierPerYear, 40 | uint256 jumpMultiplierPerYear, 41 | uint256 kink1_, 42 | uint256 kink2_, 43 | uint256 roof_ 44 | ) external; 45 | 46 | function utilizationRate( 47 | uint256 cash, 48 | uint256 borrows, 49 | uint256 reserves 50 | ) external view returns (uint256); 51 | } 52 | -------------------------------------------------------------------------------- /contracts/interfaces/traderJoe/IJoeLens/ITripleSlopeRateModelStablecoins.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface ITripleSlopeRateModelStablecoins { 6 | function baseRatePerSecond() external view returns (uint256); 7 | 8 | function getBorrowRate( 9 | uint256 cash, 10 | uint256 borrows, 11 | uint256 reserves 12 | ) external view returns (uint256); 13 | 14 | function getSupplyRate( 15 | uint256 cash, 16 | uint256 borrows, 17 | uint256 reserves, 18 | uint256 reserveFactorMantissa 19 | ) external view returns (uint256); 20 | 21 | function isInterestRateModel() external view returns (bool); 22 | 23 | function jumpMultiplierPerSecond() external view returns (uint256); 24 | 25 | function kink1() external view returns (uint256); 26 | 27 | function kink2() external view returns (uint256); 28 | 29 | function multiplierPerSecond() external view returns (uint256); 30 | 31 | function owner() external view returns (address); 32 | 33 | function roof() external view returns (uint256); 34 | 35 | function secondsPerYear() external view returns (uint256); 36 | 37 | function updateTripleRateModel( 38 | uint256 baseRatePerYear, 39 | uint256 multiplierPerYear, 40 | uint256 jumpMultiplierPerYear, 41 | uint256 kink1_, 42 | uint256 kink2_, 43 | uint256 roof_ 44 | ) external; 45 | 46 | function utilizationRate( 47 | uint256 cash, 48 | uint256 borrows, 49 | uint256 reserves 50 | ) external view returns (uint256); 51 | } 52 | -------------------------------------------------------------------------------- /contracts/interfaces/traderJoe/IJoePair.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface IJoePair { 6 | event Approval( 7 | address indexed owner, 8 | address indexed spender, 9 | uint256 value 10 | ); 11 | event Transfer(address indexed from, address indexed to, uint256 value); 12 | 13 | function name() external pure returns (string memory); 14 | 15 | function symbol() external pure returns (string memory); 16 | 17 | function decimals() external pure returns (uint8); 18 | 19 | function totalSupply() external view returns (uint256); 20 | 21 | function balanceOf(address owner) external view returns (uint256); 22 | 23 | function allowance(address owner, address spender) 24 | external 25 | view 26 | returns (uint256); 27 | 28 | function approve(address spender, uint256 value) external returns (bool); 29 | 30 | function transfer(address to, uint256 value) external returns (bool); 31 | 32 | function transferFrom( 33 | address from, 34 | address to, 35 | uint256 value 36 | ) external returns (bool); 37 | 38 | function DOMAIN_SEPARATOR() external view returns (bytes32); 39 | 40 | function PERMIT_TYPEHASH() external pure returns (bytes32); 41 | 42 | function nonces(address owner) external view returns (uint256); 43 | 44 | function permit( 45 | address owner, 46 | address spender, 47 | uint256 value, 48 | uint256 deadline, 49 | uint8 v, 50 | bytes32 r, 51 | bytes32 s 52 | ) external; 53 | 54 | event Mint(address indexed sender, uint256 amount0, uint256 amount1); 55 | event Burn( 56 | address indexed sender, 57 | uint256 amount0, 58 | uint256 amount1, 59 | address indexed to 60 | ); 61 | event Swap( 62 | address indexed sender, 63 | uint256 amount0In, 64 | uint256 amount1In, 65 | uint256 amount0Out, 66 | uint256 amount1Out, 67 | address indexed to 68 | ); 69 | event Sync(uint112 reserve0, uint112 reserve1); 70 | 71 | function MINIMUM_LIQUIDITY() external pure returns (uint256); 72 | 73 | function factory() external view returns (address); 74 | 75 | function token0() external view returns (address); 76 | 77 | function token1() external view returns (address); 78 | 79 | function getReserves() 80 | external 81 | view 82 | returns ( 83 | uint112 reserve0, 84 | uint112 reserve1, 85 | uint32 blockTimestampLast 86 | ); 87 | 88 | function price0CumulativeLast() external view returns (uint256); 89 | 90 | function price1CumulativeLast() external view returns (uint256); 91 | 92 | function kLast() external view returns (uint256); 93 | 94 | function mint(address to) external returns (uint256 liquidity); 95 | 96 | function burn(address to) 97 | external 98 | returns (uint256 amount0, uint256 amount1); 99 | 100 | function swap( 101 | uint256 amount0Out, 102 | uint256 amount1Out, 103 | address to, 104 | bytes calldata data 105 | ) external; 106 | 107 | function skim(address to) external; 108 | 109 | function sync() external; 110 | 111 | function initialize(address, address) external; 112 | } 113 | -------------------------------------------------------------------------------- /contracts/interfaces/traderJoe/IJoeRouter01.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface IJoeRouter01 { 6 | function factory() external pure returns (address); 7 | 8 | function WAVAX() external pure returns (address); 9 | 10 | function addLiquidity( 11 | address tokenA, 12 | address tokenB, 13 | uint256 amountADesired, 14 | uint256 amountBDesired, 15 | uint256 amountAMin, 16 | uint256 amountBMin, 17 | address to, 18 | uint256 deadline 19 | ) 20 | external 21 | returns ( 22 | uint256 amountA, 23 | uint256 amountB, 24 | uint256 liquidity 25 | ); 26 | 27 | function addLiquidityAVAX( 28 | address token, 29 | uint256 amountTokenDesired, 30 | uint256 amountTokenMin, 31 | uint256 amountAVAXMin, 32 | address to, 33 | uint256 deadline 34 | ) 35 | external 36 | payable 37 | returns ( 38 | uint256 amountToken, 39 | uint256 amountAVAX, 40 | uint256 liquidity 41 | ); 42 | 43 | function removeLiquidity( 44 | address tokenA, 45 | address tokenB, 46 | uint256 liquidity, 47 | uint256 amountAMin, 48 | uint256 amountBMin, 49 | address to, 50 | uint256 deadline 51 | ) external returns (uint256 amountA, uint256 amountB); 52 | 53 | function removeLiquidityAVAX( 54 | address token, 55 | uint256 liquidity, 56 | uint256 amountTokenMin, 57 | uint256 amountAVAXMin, 58 | address to, 59 | uint256 deadline 60 | ) external returns (uint256 amountToken, uint256 amountAVAX); 61 | 62 | function removeLiquidityWithPermit( 63 | address tokenA, 64 | address tokenB, 65 | uint256 liquidity, 66 | uint256 amountAMin, 67 | uint256 amountBMin, 68 | address to, 69 | uint256 deadline, 70 | bool approveMax, 71 | uint8 v, 72 | bytes32 r, 73 | bytes32 s 74 | ) external returns (uint256 amountA, uint256 amountB); 75 | 76 | function removeLiquidityAVAXWithPermit( 77 | address token, 78 | uint256 liquidity, 79 | uint256 amountTokenMin, 80 | uint256 amountAVAXMin, 81 | address to, 82 | uint256 deadline, 83 | bool approveMax, 84 | uint8 v, 85 | bytes32 r, 86 | bytes32 s 87 | ) external returns (uint256 amountToken, uint256 amountAVAX); 88 | 89 | function swapExactTokensForTokens( 90 | uint256 amountIn, 91 | uint256 amountOutMin, 92 | address[] calldata path, 93 | address to, 94 | uint256 deadline 95 | ) external returns (uint256[] memory amounts); 96 | 97 | function swapTokensForExactTokens( 98 | uint256 amountOut, 99 | uint256 amountInMax, 100 | address[] calldata path, 101 | address to, 102 | uint256 deadline 103 | ) external returns (uint256[] memory amounts); 104 | 105 | function swapExactAVAXForTokens( 106 | uint256 amountOutMin, 107 | address[] calldata path, 108 | address to, 109 | uint256 deadline 110 | ) external payable returns (uint256[] memory amounts); 111 | 112 | function swapTokensForExactAVAX( 113 | uint256 amountOut, 114 | uint256 amountInMax, 115 | address[] calldata path, 116 | address to, 117 | uint256 deadline 118 | ) external returns (uint256[] memory amounts); 119 | 120 | function swapExactTokensForAVAX( 121 | uint256 amountIn, 122 | uint256 amountOutMin, 123 | address[] calldata path, 124 | address to, 125 | uint256 deadline 126 | ) external returns (uint256[] memory amounts); 127 | 128 | function swapAVAXForExactTokens( 129 | uint256 amountOut, 130 | address[] calldata path, 131 | address to, 132 | uint256 deadline 133 | ) external payable returns (uint256[] memory amounts); 134 | 135 | function quote( 136 | uint256 amountA, 137 | uint256 reserveA, 138 | uint256 reserveB 139 | ) external pure returns (uint256 amountB); 140 | 141 | function getAmountOut( 142 | uint256 amountIn, 143 | uint256 reserveIn, 144 | uint256 reserveOut 145 | ) external pure returns (uint256 amountOut); 146 | 147 | function getAmountIn( 148 | uint256 amountOut, 149 | uint256 reserveIn, 150 | uint256 reserveOut 151 | ) external pure returns (uint256 amountIn); 152 | 153 | function getAmountsOut(uint256 amountIn, address[] calldata path) 154 | external 155 | view 156 | returns (uint256[] memory amounts); 157 | 158 | function getAmountsIn(uint256 amountOut, address[] calldata path) 159 | external 160 | view 161 | returns (uint256[] memory amounts); 162 | } 163 | -------------------------------------------------------------------------------- /contracts/interfaces/traderJoe/IJoeRouter02.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | import "./IJoeRouter01.sol"; 6 | 7 | interface IJoeRouter02 is IJoeRouter01 { 8 | function removeLiquidityAVAXSupportingFeeOnTransferTokens( 9 | address token, 10 | uint256 liquidity, 11 | uint256 amountTokenMin, 12 | uint256 amountAVAXMin, 13 | address to, 14 | uint256 deadline 15 | ) external returns (uint256 amountAVAX); 16 | 17 | function removeLiquidityAVAXWithPermitSupportingFeeOnTransferTokens( 18 | address token, 19 | uint256 liquidity, 20 | uint256 amountTokenMin, 21 | uint256 amountAVAXMin, 22 | address to, 23 | uint256 deadline, 24 | bool approveMax, 25 | uint8 v, 26 | bytes32 r, 27 | bytes32 s 28 | ) external returns (uint256 amountAVAX); 29 | 30 | function swapExactTokensForTokensSupportingFeeOnTransferTokens( 31 | uint256 amountIn, 32 | uint256 amountOutMin, 33 | address[] calldata path, 34 | address to, 35 | uint256 deadline 36 | ) external; 37 | 38 | function swapExactAVAXForTokensSupportingFeeOnTransferTokens( 39 | uint256 amountOutMin, 40 | address[] calldata path, 41 | address to, 42 | uint256 deadline 43 | ) external payable; 44 | 45 | function swapExactTokensForAVAXSupportingFeeOnTransferTokens( 46 | uint256 amountIn, 47 | uint256 amountOutMin, 48 | address[] calldata path, 49 | address to, 50 | uint256 deadline 51 | ) external; 52 | } 53 | -------------------------------------------------------------------------------- /contracts/interfaces/traderJoe/IMasterChefJoeV2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface IMasterChefJoeV2 { 6 | function add( 7 | uint256 _allocPoint, 8 | address _lpToken, 9 | address _rewarder 10 | ) external; 11 | 12 | function deposit(uint256 _pid, uint256 _amount) external; 13 | 14 | function dev(address _devAddr) external; 15 | 16 | function devAddr() external view returns (address); 17 | 18 | function devPercent() external view returns (uint256); 19 | 20 | function emergencyWithdraw(uint256 _pid) external; 21 | 22 | function investorAddr() external view returns (address); 23 | 24 | function investorPercent() external view returns (uint256); 25 | 26 | function joe() external view returns (address); 27 | 28 | function joePerSec() external view returns (uint256); 29 | 30 | function massUpdatePools() external; 31 | 32 | function owner() external view returns (address); 33 | 34 | function pendingTokens(uint256 _pid, address _user) 35 | external 36 | view 37 | returns ( 38 | uint256 pendingJoe, 39 | address bonusTokenAddress, 40 | string memory bonusTokenSymbol, 41 | uint256 pendingBonusToken 42 | ); 43 | 44 | function poolInfo(uint256) 45 | external 46 | view 47 | returns ( 48 | address lpToken, 49 | uint256 allocPoint, 50 | uint256 lastRewardTimestamp, 51 | uint256 accJoePerShare, 52 | address rewarder 53 | ); 54 | 55 | function poolLength() external view returns (uint256); 56 | 57 | function renounceOwnership() external; 58 | 59 | function rewarderBonusTokenInfo(uint256 _pid) 60 | external 61 | view 62 | returns (address bonusTokenAddress, string memory bonusTokenSymbol); 63 | 64 | function set( 65 | uint256 _pid, 66 | uint256 _allocPoint, 67 | address _rewarder, 68 | bool overwrite 69 | ) external; 70 | 71 | function setDevPercent(uint256 _newDevPercent) external; 72 | 73 | function setInvestorAddr(address _investorAddr) external; 74 | 75 | function setInvestorPercent(uint256 _newInvestorPercent) external; 76 | 77 | function setTreasuryAddr(address _treasuryAddr) external; 78 | 79 | function setTreasuryPercent(uint256 _newTreasuryPercent) external; 80 | 81 | function startTimestamp() external view returns (uint256); 82 | 83 | function totalAllocPoint() external view returns (uint256); 84 | 85 | function transferOwnership(address newOwner) external; 86 | 87 | function treasuryAddr() external view returns (address); 88 | 89 | function treasuryPercent() external view returns (uint256); 90 | 91 | function updateEmissionRate(uint256 _joePerSec) external; 92 | 93 | function updatePool(uint256 _pid) external; 94 | 95 | function userInfo(uint256, address) 96 | external 97 | view 98 | returns (uint256 amount, uint256 rewardDebt); 99 | 100 | function withdraw(uint256 _pid, uint256 _amount) external; 101 | } 102 | -------------------------------------------------------------------------------- /contracts/interfaces/traderJoe/IMasterChefJoeV3.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface IMasterChefJoeV3 { 6 | function JOE() external view returns (address); 7 | 8 | function MASTER_CHEF_V2() external view returns (address); 9 | 10 | function MASTER_PID() external view returns (uint256); 11 | 12 | function add( 13 | uint256 allocPoint, 14 | address _lpToken, 15 | address _rewarder 16 | ) external; 17 | 18 | function deposit(uint256 pid, uint256 amount) external; 19 | 20 | function emergencyWithdraw(uint256 pid) external; 21 | 22 | function harvestFromMasterChef() external; 23 | 24 | function init(address dummyToken) external; 25 | 26 | function joePerSec() external view returns (uint256 amount); 27 | 28 | function massUpdatePools(uint256[] memory pids) external; 29 | 30 | function owner() external view returns (address); 31 | 32 | function pendingTokens(uint256 _pid, address _user) 33 | external 34 | view 35 | returns ( 36 | uint256 pendingJoe, 37 | address bonusTokenAddress, 38 | string memory bonusTokenSymbol, 39 | uint256 pendingBonusToken 40 | ); 41 | 42 | function poolInfo(uint256) 43 | external 44 | view 45 | returns ( 46 | address lpToken, 47 | uint256 accJoePerShare, 48 | uint256 lastRewardTimestamp, 49 | uint256 allocPoint, 50 | address rewarder 51 | ); 52 | 53 | function poolLength() external view returns (uint256 pools); 54 | 55 | function renounceOwnership() external; 56 | 57 | function set( 58 | uint256 _pid, 59 | uint256 _allocPoint, 60 | address _rewarder, 61 | bool overwrite 62 | ) external; 63 | 64 | function totalAllocPoint() external view returns (uint256); 65 | 66 | function transferOwnership(address newOwner) external; 67 | 68 | function updatePool(uint256 pid) external; 69 | 70 | function userInfo(uint256, address) 71 | external 72 | view 73 | returns (uint256 amount, uint256 rewardDebt); 74 | 75 | function withdraw(uint256 pid, uint256 amount) external; 76 | } 77 | -------------------------------------------------------------------------------- /contracts/interfaces/traderJoe/ISimpleRewardPerSecond.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | interface ISimpleRewardPerSecond { 6 | function MCJ() external view returns (address); 7 | 8 | function balance() external view returns (uint256); 9 | 10 | function claimOwnership() external; 11 | 12 | function emergencyWithdraw() external; 13 | 14 | function isNative() external view returns (bool); 15 | 16 | function lpToken() external view returns (address); 17 | 18 | function onJoeReward(address _user, uint256 _lpAmount) external; 19 | 20 | function owner() external view returns (address); 21 | 22 | function pendingOwner() external view returns (address); 23 | 24 | function pendingTokens(address _user) 25 | external 26 | view 27 | returns (uint256 pending); 28 | 29 | function poolInfo() 30 | external 31 | view 32 | returns (uint256 accTokenPerShare, uint256 lastRewardTimestamp); 33 | 34 | function rewardToken() external view returns (address); 35 | 36 | function setRewardRate(uint256 _tokenPerSec) external; 37 | 38 | function tokenPerSec() external view returns (uint256); 39 | 40 | function transferOwnership( 41 | address newOwner, 42 | bool direct, 43 | bool renounce 44 | ) external; 45 | 46 | // function updatePool ( ) external returns ( tuple pool ); 47 | function userInfo(address) 48 | external 49 | view 50 | returns (uint256 amount, uint256 rewardDebt); 51 | } 52 | -------------------------------------------------------------------------------- /contracts/timelock/Timelock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | import "@openzeppelin/contracts/access/Ownable.sol"; 6 | 7 | contract Timelock is Ownable { 8 | event NewAdmin(address indexed newAdmin); 9 | event NewPendingAdmin(address indexed newPendingAdmin); 10 | event NewDelay(uint256 indexed newDelay); 11 | event CancelTransaction( 12 | bytes32 indexed txHash, 13 | address indexed target, 14 | uint256 value, 15 | string signature, 16 | bytes data, 17 | uint256 eta 18 | ); 19 | event ExecuteTransaction( 20 | bytes32 indexed txHash, 21 | address indexed target, 22 | uint256 value, 23 | string signature, 24 | bytes data, 25 | uint256 eta 26 | ); 27 | event QueueTransaction( 28 | bytes32 indexed txHash, 29 | address indexed target, 30 | uint256 value, 31 | string signature, 32 | bytes data, 33 | uint256 eta 34 | ); 35 | 36 | uint256 public constant GRACE_PERIOD = 14 days; 37 | uint256 public constant MINIMUM_DELAY = 12 hours; 38 | uint256 public constant MAXIMUM_DELAY = 30 days; 39 | 40 | address public admin; 41 | address public pendingAdmin; 42 | uint256 public delay; 43 | bool public admin_initialized; 44 | 45 | mapping(bytes32 => bool) public queuedTransactions; 46 | 47 | modifier onlyAdmin() { 48 | require( 49 | admin == msg.sender, 50 | "Timelock::queueTransaction: Call must come from admin." 51 | ); 52 | _; 53 | } 54 | 55 | constructor(address admin_, uint256 delay_) { 56 | require( 57 | delay_ >= MINIMUM_DELAY, 58 | "Timelock::constructor: Delay must exceed minimum delay." 59 | ); 60 | require( 61 | delay_ <= MAXIMUM_DELAY, 62 | "Timelock::constructor: Delay must not exceed maximum delay." 63 | ); 64 | 65 | admin = admin_; 66 | delay = delay_; 67 | admin_initialized = false; 68 | } 69 | 70 | // XXX: function() external payable { } 71 | receive() external payable {} 72 | 73 | function setDelay(uint256 delay_) public { 74 | require( 75 | msg.sender == address(this), 76 | "Timelock::setDelay: Call must come from Timelock." 77 | ); 78 | require( 79 | delay_ >= MINIMUM_DELAY, 80 | "Timelock::setDelay: Delay must exceed minimum delay." 81 | ); 82 | require( 83 | delay_ <= MAXIMUM_DELAY, 84 | "Timelock::setDelay: Delay must not exceed maximum delay." 85 | ); 86 | delay = delay_; 87 | 88 | emit NewDelay(delay); 89 | } 90 | 91 | function acceptAdmin() public { 92 | require( 93 | msg.sender == pendingAdmin, 94 | "Timelock::acceptAdmin: Call must come from pendingAdmin." 95 | ); 96 | admin = msg.sender; 97 | pendingAdmin = address(0); 98 | 99 | emit NewAdmin(admin); 100 | } 101 | 102 | function setPendingAdmin(address pendingAdmin_) public { 103 | // allows one time setting of admin for deployment purposes 104 | if (admin_initialized) { 105 | require( 106 | msg.sender == address(this), 107 | "Timelock::setPendingAdmin: Call must come from Timelock." 108 | ); 109 | } else { 110 | require( 111 | msg.sender == admin, 112 | "Timelock::setPendingAdmin: First call must come from admin." 113 | ); 114 | admin_initialized = true; 115 | } 116 | pendingAdmin = pendingAdmin_; 117 | 118 | emit NewPendingAdmin(pendingAdmin); 119 | } 120 | 121 | function queueTransaction( 122 | address target, 123 | uint256 value, 124 | string memory signature, 125 | bytes memory data, 126 | uint256 eta 127 | ) public onlyAdmin returns (bytes32) { 128 | require( 129 | eta >= getBlockTimestamp() + delay, 130 | "Timelock::queueTransaction: Estimated execution block must satisfy delay." 131 | ); 132 | 133 | bytes32 txHash = keccak256( 134 | abi.encode(target, value, signature, data, eta) 135 | ); 136 | queuedTransactions[txHash] = true; 137 | emit QueueTransaction(txHash, target, value, signature, data, eta); 138 | return txHash; 139 | } 140 | 141 | function cancelTransaction( 142 | address target, 143 | uint256 value, 144 | string memory signature, 145 | bytes memory data, 146 | uint256 eta 147 | ) public onlyAdmin { 148 | bytes32 txHash = keccak256( 149 | abi.encode(target, value, signature, data, eta) 150 | ); 151 | queuedTransactions[txHash] = false; 152 | 153 | emit CancelTransaction(txHash, target, value, signature, data, eta); 154 | } 155 | 156 | function executeTransaction( 157 | address target, 158 | uint256 value, 159 | string memory signature, 160 | bytes memory data, 161 | uint256 eta 162 | ) public payable onlyAdmin returns (bytes memory) { 163 | bytes32 txHash = keccak256( 164 | abi.encode(target, value, signature, data, eta) 165 | ); 166 | require( 167 | queuedTransactions[txHash], 168 | "Timelock::executeTransaction: Transaction hasn't been queued." 169 | ); 170 | require( 171 | getBlockTimestamp() >= eta, 172 | "Timelock::executeTransaction: Transaction hasn't surpassed time lock." 173 | ); 174 | require( 175 | getBlockTimestamp() <= eta + GRACE_PERIOD, 176 | "Timelock::executeTransaction: Transaction is stale." 177 | ); 178 | 179 | queuedTransactions[txHash] = false; 180 | 181 | bytes memory callData; 182 | 183 | if (bytes(signature).length == 0) { 184 | callData = data; 185 | } else { 186 | callData = abi.encodePacked( 187 | bytes4(keccak256(bytes(signature))), 188 | data 189 | ); 190 | } 191 | 192 | // solium-disable-next-line security/no-call-value 193 | (bool success, bytes memory returnData) = target.call{value: value}( 194 | callData 195 | ); 196 | require( 197 | success, 198 | "Timelock::executeTransaction: Transaction execution reverted." 199 | ); 200 | 201 | emit ExecuteTransaction(txHash, target, value, signature, data, eta); 202 | 203 | return returnData; 204 | } 205 | 206 | function getBlockTimestamp() internal view returns (uint256) { 207 | // solium-disable-next-line security/no-block-members 208 | return block.timestamp; 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /contracts/timelock/TimelockCallable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | abstract contract TimelockCallable { 6 | address public TIMELOCK_ADDRESS; 7 | 8 | event SetTimeLock(address newTimelock); 9 | 10 | constructor(address _timelock) { 11 | TIMELOCK_ADDRESS = _timelock; 12 | } 13 | 14 | modifier onlyTimelock() { 15 | require(TIMELOCK_ADDRESS == msg.sender, "Caller is not the timelock."); 16 | _; 17 | } 18 | 19 | function setTimelock(address newTimelock) external onlyTimelock { 20 | require(newTimelock != address(0)); 21 | TIMELOCK_ADDRESS = newTimelock; 22 | emit SetTimeLock(newTimelock); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /contracts/utils/AddressArrayLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | library AddressArrayLib { 6 | /// @dev Helper to add an item to an array. Does not assert uniqueness of the new item. 7 | function addItem(address[] memory _self, address _itemToAdd) 8 | internal 9 | pure 10 | returns (address[] memory nextArray_) 11 | { 12 | nextArray_ = new address[](_self.length + 1); 13 | for (uint256 i; i < _self.length; i++) { 14 | nextArray_[i] = _self[i]; 15 | } 16 | nextArray_[_self.length] = _itemToAdd; 17 | 18 | return nextArray_; 19 | } 20 | 21 | /// @dev Helper to add an item to an array, only if it is not already in the array. 22 | function addUniqueItem(address[] memory _self, address _itemToAdd) 23 | internal 24 | pure 25 | returns (address[] memory nextArray_) 26 | { 27 | if (contains(_self, _itemToAdd)) { 28 | return _self; 29 | } 30 | 31 | return addItem(_self, _itemToAdd); 32 | } 33 | 34 | /// @dev Helper to verify if an array contains a particular value 35 | function contains(address[] memory _self, address _target) 36 | internal 37 | pure 38 | returns (bool doesContain_) 39 | { 40 | for (uint256 i; i < _self.length; i++) { 41 | if (_target == _self[i]) { 42 | return true; 43 | } 44 | } 45 | return false; 46 | } 47 | 48 | /// @dev Helper to reassign all items in an array with a specified value 49 | function fill(address[] memory _self, address _value) 50 | internal 51 | pure 52 | returns (address[] memory nextArray_) 53 | { 54 | nextArray_ = new address[](_self.length); 55 | for (uint256 i; i < nextArray_.length; i++) { 56 | nextArray_[i] = _value; 57 | } 58 | 59 | return nextArray_; 60 | } 61 | 62 | /// @dev Helper to verify if array is a set of unique values. 63 | /// Does not assert length > 0. 64 | function isUniqueSet(address[] memory _self) 65 | internal 66 | pure 67 | returns (bool isUnique_) 68 | { 69 | if (_self.length <= 1) { 70 | return true; 71 | } 72 | 73 | uint256 arrayLength = _self.length; 74 | for (uint256 i; i < arrayLength; i++) { 75 | for (uint256 j = i + 1; j < arrayLength; j++) { 76 | if (_self[i] == _self[j]) { 77 | return false; 78 | } 79 | } 80 | } 81 | 82 | return true; 83 | } 84 | 85 | /// @dev Helper to remove items from an array. Removes all matching occurrences of each item. 86 | /// Does not assert uniqueness of either array. 87 | function removeItems( 88 | address[] memory _self, 89 | address[] memory _itemsToRemove 90 | ) internal pure returns (address[] memory nextArray_) { 91 | if (_itemsToRemove.length == 0) { 92 | return _self; 93 | } 94 | 95 | bool[] memory indexesToRemove = new bool[](_self.length); 96 | uint256 remainingItemsCount = _self.length; 97 | for (uint256 i; i < _self.length; i++) { 98 | if (contains(_itemsToRemove, _self[i])) { 99 | indexesToRemove[i] = true; 100 | remainingItemsCount--; 101 | } 102 | } 103 | 104 | if (remainingItemsCount == _self.length) { 105 | nextArray_ = _self; 106 | } else if (remainingItemsCount > 0) { 107 | nextArray_ = new address[](remainingItemsCount); 108 | uint256 nextArrayIndex; 109 | for (uint256 i; i < _self.length; i++) { 110 | if (!indexesToRemove[i]) { 111 | nextArray_[nextArrayIndex] = _self[i]; 112 | nextArrayIndex++; 113 | } 114 | } 115 | } 116 | 117 | return nextArray_; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /contracts/utils/HomoraMath.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity >=0.8.0 <0.9.0; 4 | 5 | import "@openzeppelin/contracts/utils/math/SafeMath.sol"; 6 | 7 | library HomoraMath { 8 | using SafeMath for uint256; 9 | 10 | function divCeil(uint256 lhs, uint256 rhs) internal pure returns (uint256) { 11 | return lhs.add(rhs).sub(1) / rhs; 12 | } 13 | 14 | function fmul(uint256 lhs, uint256 rhs) internal pure returns (uint256) { 15 | return lhs.mul(rhs) / (2**112); 16 | } 17 | 18 | function fdiv(uint256 lhs, uint256 rhs) internal pure returns (uint256) { 19 | return lhs.mul(2**112) / rhs; 20 | } 21 | 22 | // implementation from https://github.com/Uniswap/uniswap-lib/commit/99f3f28770640ba1bb1ff460ac7c5292fb8291a0 23 | // original implementation: https://github.com/abdk-consulting/abdk-libraries-solidity/blob/master/ABDKMath64x64.sol#L687 24 | function sqrt(uint256 x) internal pure returns (uint256) { 25 | if (x == 0) return 0; 26 | uint256 xx = x; 27 | uint256 r = 1; 28 | 29 | if (xx >= 0x100000000000000000000000000000000) { 30 | xx >>= 128; 31 | r <<= 64; 32 | } 33 | 34 | if (xx >= 0x10000000000000000) { 35 | xx >>= 64; 36 | r <<= 32; 37 | } 38 | if (xx >= 0x100000000) { 39 | xx >>= 32; 40 | r <<= 16; 41 | } 42 | if (xx >= 0x10000) { 43 | xx >>= 16; 44 | r <<= 8; 45 | } 46 | if (xx >= 0x100) { 47 | xx >>= 8; 48 | r <<= 4; 49 | } 50 | if (xx >= 0x10) { 51 | xx >>= 4; 52 | r <<= 2; 53 | } 54 | if (xx >= 0x8) { 55 | r <<= 1; 56 | } 57 | 58 | r = (r + x / r) >> 1; 59 | r = (r + x / r) >> 1; 60 | r = (r + x / r) >> 1; 61 | r = (r + x / r) >> 1; 62 | r = (r + x / r) >> 1; 63 | r = (r + x / r) >> 1; 64 | r = (r + x / r) >> 1; // Seven iterations should be enough 65 | uint256 r1 = x / r; 66 | return (r < r1 ? r : r1); 67 | } 68 | } 69 | --------------------------------------------------------------------------------