From 82584a71ed68bac53ffa57222881130d05d45a7a Mon Sep 17 00:00:00 2001 From: Thrilok Kumar Date: Sat, 22 Aug 2020 08:37:55 +0530 Subject: [PATCH 01/15] Basic contracts. WIP --- contracts/ethPool.sol | 13 ++++ contracts/libs/safeMath.sol | 42 +++++++++++++ contracts/rateLogics/dai.sol | 54 +++++++++++++++++ contracts/registry.sol | 62 +++++++++++++++++++ contracts/tokenPool.sol | 113 +++++++++++++++++++++++++++++++++++ package-lock.json | 7 +-- package.json | 2 +- 7 files changed, 288 insertions(+), 5 deletions(-) create mode 100644 contracts/ethPool.sol create mode 100644 contracts/libs/safeMath.sol create mode 100644 contracts/rateLogics/dai.sol create mode 100644 contracts/registry.sol create mode 100644 contracts/tokenPool.sol diff --git a/contracts/ethPool.sol b/contracts/ethPool.sol new file mode 100644 index 0000000..3a281ba --- /dev/null +++ b/contracts/ethPool.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.8; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract PoolToken is ERC20 { + constructor( + string memory _name, + string memory _symbol + ) public ERC20(_name, _symbol) { + // TODO - 0 + } +} diff --git a/contracts/libs/safeMath.sol b/contracts/libs/safeMath.sol new file mode 100644 index 0000000..e83d4c3 --- /dev/null +++ b/contracts/libs/safeMath.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.6.8; + +import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol"; + +contract DSMath { + uint constant WAD = 10 ** 18; + uint constant RAY = 10 ** 27; + + function add(uint x, uint y) internal pure returns (uint z) { + z = SafeMath.add(x, y); + } + + function sub(uint x, uint y) internal virtual pure returns (uint z) { + z = SafeMath.sub(x, y); + } + + function mul(uint x, uint y) internal pure returns (uint z) { + z = SafeMath.mul(x, y); + } + + function div(uint x, uint y) internal pure returns (uint z) { + z = SafeMath.div(x, y); + } + + function wmul(uint x, uint y) internal pure returns (uint z) { + z = SafeMath.add(SafeMath.mul(x, y), WAD / 2) / WAD; + } + + function wdiv(uint x, uint y) internal pure returns (uint z) { + z = SafeMath.add(SafeMath.mul(x, WAD), y / 2) / y; + } + + function rdiv(uint x, uint y) internal pure returns (uint z) { + z = SafeMath.add(SafeMath.mul(x, RAY), y / 2) / y; + } + + function rmul(uint x, uint y) internal pure returns (uint z) { + z = SafeMath.add(SafeMath.mul(x, y), RAY / 2) / RAY; + } +} diff --git a/contracts/rateLogics/dai.sol b/contracts/rateLogics/dai.sol new file mode 100644 index 0000000..4088a94 --- /dev/null +++ b/contracts/rateLogics/dai.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.8; + +import { DSMath } from "../libs/safeMath.sol"; + +interface PoolTokenInterface { + function totalBalance() external view returns (uint); + function dsaAmount() external view returns (uint); + function totalSupply() external view returns (uint); + +} + +interface ATokenInterface { + function balanceOf(address) external view returns (uint); +} + +interface CTokenInterface { + function getExchangeRate() external view returns (uint); + function balanceOf(address) external view returns (uint); +} + +contract RateLogic is DSMath { + PoolTokenInterface poolToken = PoolTokenInterface(address(0)); + ATokenInterface atoken = ATokenInterface(address(0)); + CTokenInterface ctoken = CTokenInterface(address(0)); + CTokenInterface token = CTokenInterface(address(0)); + + uint fee = 1e17; // 10% + function totalBalanceDSA() public view returns (uint) { + address _dsa; + uint abal = atoken.balanceOf(_dsa); + uint cbal = wmul(ctoken.balanceOf(_dsa), ctoken.getExchangeRate()); + uint bal = token.balanceOf(_dsa); + return add(abal, add(cbal, bal)); + } + + function totalBalance() public view returns (uint) { + address _dsa; + uint abal = atoken.balanceOf(_dsa); + uint cbal = wmul(ctoken.balanceOf(_dsa), ctoken.getExchangeRate()); + uint dsaBal = token.balanceOf(_dsa); + uint poolBal = token.balanceOf(address(poolToken)); + return add(add(abal, poolBal) , add(cbal, dsaBal)); + } + + function pricePerToken() public view returns(uint256) { + // TODO - add security logic + uint _totalBalance = totalBalanceDSA(); + uint profit = sub(_totalBalance, poolToken.dsaAmount()); + uint leftProfit = wmul(profit, fee); + uint leftTotalBalance = add(leftProfit, poolToken.dsaAmount()); + return wdiv(leftTotalBalance, poolToken.totalSupply()); + } +} diff --git a/contracts/registry.sol b/contracts/registry.sol new file mode 100644 index 0000000..cab1258 --- /dev/null +++ b/contracts/registry.sol @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.6.8; +pragma experimental ABIEncoderV2; + +// TODO +// function for adding and removing rate logics. +// Added fee variable and required function to change it. +// Link all the contract more properly. +// Have to think more on pricePerToken function. + +interface IndexInterface { + function master() external view returns (address); +} + +contract Registry { + + event LogAddChief(address indexed chief); + event LogRemoveChief(address indexed chief); + + IndexInterface public instaIndex; + + mapping (address => bool) public chief; + mapping (address => address) public dsa; + mapping (address => address) public rateLogic; + + modifier isMaster() { + require(msg.sender == instaIndex.master(), "not-master"); + _; + } + + modifier isController() { + require(chief[msg.sender] || msg.sender == instaIndex.master(), "not-chief"); + _; + } + + constructor(address _index) public { + instaIndex = IndexInterface(_index); + } + + /** + * @dev Enable New Chief. + * @param _chief Address of the new chief. + */ + function enableChief(address _chief) external isMaster { + require(_chief != address(0), "address-not-valid"); + require(!chief[_chief], "chief-already-enabled"); + chief[_chief] = true; + emit LogAddChief(_chief); + } + + /** + * @dev Disable Chief. + * @param _chief Address of the existing chief. + */ + function disableChief(address _chief) external isMaster { + require(_chief != address(0), "address-not-valid"); + require(chief[_chief], "chief-already-disabled"); + delete chief[_chief]; + emit LogRemoveChief(_chief); + } +} diff --git a/contracts/tokenPool.sol b/contracts/tokenPool.sol new file mode 100644 index 0000000..923eecd --- /dev/null +++ b/contracts/tokenPool.sol @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.8; +pragma experimental ABIEncoderV2; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; + +import { DSMath } from "./libs/safeMath.sol"; + +// TODO - Add ReentrancyGuard lib + +interface AccountInterface { + function enable(address authority) external; + function cast(address[] calldata _targets, bytes[] calldata _datas, address _origin) external payable; +} + +interface IndexInterface { + function master() external view returns (address); +} + +interface RegistryInterface { + function chief(address) external view returns (bool); + function dsa(address) external view returns (address); + function rateLogic(address) external view returns (address); +} + +interface RateInterface { + function pricePerToken() external view returns (uint); + function totalBalance() external view returns (uint); +} + +contract PoolToken is ERC20, DSMath { + using SafeERC20 for IERC20; + + IERC20 public immutable baseToken; + RegistryInterface public immutable registry; + IndexInterface public immutable instaIndex; + + uint private tokenBalance; + uint private tokenProfit; + uint private tokenCap; + + + + constructor( + address _registry, + address _index, + string memory _name, + string memory _symbol, + address _baseToken + ) public ERC20(_name, _symbol) { + // TODO - 0 + baseToken = IERC20(_baseToken); + registry = RegistryInterface(_registry); + instaIndex = IndexInterface(_index); + } + + modifier isMaster() { + require(msg.sender == instaIndex.master(), "not-master"); + _; + } + + modifier isChief() { + require(registry.chief(msg.sender) || msg.sender == instaIndex.master(), "not-chief"); + _; + } + + uint dsaAmount; + function depositDSA(uint amount) public isChief { + address _dsa = registry.dsa(address(this)); + baseToken.safeTransfer(_dsa, amount); + dsaAmount = add(dsaAmount, amount); + } + + function withdrawDSA(uint amount) public isChief { + // address _dsa = registry.dsa(address(this)); + baseToken.safeTransferFrom(msg.sender, address(this), amount); + uint totalAmountWithProfit = RateInterface(address(0)).totalBalance(); // TODO - change to => totalBalanceDSA + uint _amount = wdiv(wmul(amount, dsaAmount), totalAmountWithProfit); + uint profit = sub(amount, _amount); + tokenProfit = add(tokenProfit, profit); + dsaAmount = sub(dsaAmount, _amount); + } + + function getBalance() public view returns(uint) { + return sub(add(dsaAmount, baseToken.balanceOf(address(this))), tokenProfit); + } + + function pricePerToken() public view returns(uint) { + return 1e18; // TODO - still need to work on it. + } + + function deposit(uint amount) public returns(uint) { + uint _newTokenBal = add(tokenBalance, amount); + require(_newTokenBal <= getBalance(), "deposit-cap-reached"); + + baseToken.safeTransferFrom(msg.sender, address(this), amount); + uint iAmt = wdiv(amount, pricePerToken()); + _mint(msg.sender, iAmt); + } + + function withdraw(address owner, uint iAmount) public returns (uint) { + uint amount = wmul(iAmount, pricePerToken()); + _burn(msg.sender, iAmount); + + baseToken.safeTransfer(owner, amount); + } + + function withdraw(uint amount) public returns (uint) { + return withdraw(msg.sender, amount); + } +} diff --git a/package-lock.json b/package-lock.json index d1cc943..2ee220a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -531,10 +531,9 @@ } }, "@openzeppelin/contracts": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-2.5.1.tgz", - "integrity": "sha512-qIy6tLx8rtybEsIOAlrM4J/85s2q2nPkDqj/Rx46VakBZ0LwtFhXIVub96LXHczQX0vaqmAueDqNPXtbSXSaYQ==", - "dev": true + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-3.1.0.tgz", + "integrity": "sha512-dVXDnUKxrAKLzPdCRkz+N8qsVkK1XxJ6kk3zuI6zaQmcKxN7CkizoDP7lXxcs/Mi2I0mxceTRjJBqlzFffLJrQ==" }, "@openzeppelin/test-helpers": { "version": "0.5.6", diff --git a/package.json b/package.json index 0e7373c..68e5cc2 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ }, "homepage": "https://github.com/InstaDApp/dsa-yield-contract#readme", "dependencies": { + "@openzeppelin/contracts": "^3.1.0", "solc": "^0.6.8", "truffle-assertions": "^0.9.2", "truffle-hdwallet-provider": "^1.0.17", @@ -24,7 +25,6 @@ "web3": "^1.2.11" }, "devDependencies": { - "@openzeppelin/contracts": "^2.4.0", "@nomiclabs/buidler": "^1.4.3", "@nomiclabs/buidler-truffle5": "^1.3.4", "@nomiclabs/buidler-web3": "^1.3.4", From 5fc9feab5db95fe86b3a55a216c2b381ca87f753 Mon Sep 17 00:00:00 2001 From: Thrilok Kumar Date: Sat, 22 Aug 2020 08:59:54 +0530 Subject: [PATCH 02/15] Added TODOs --- contracts/tokenPool.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contracts/tokenPool.sol b/contracts/tokenPool.sol index 923eecd..4728cbc 100644 --- a/contracts/tokenPool.sol +++ b/contracts/tokenPool.sol @@ -88,7 +88,7 @@ contract PoolToken is ERC20, DSMath { } function pricePerToken() public view returns(uint) { - return 1e18; // TODO - still need to work on it. + return 1e18; // TODO - Link to rate logic contract } function deposit(uint amount) public returns(uint) { @@ -101,6 +101,7 @@ contract PoolToken is ERC20, DSMath { } function withdraw(address owner, uint iAmount) public returns (uint) { + // TODO - check balance before withdrawing uint amount = wmul(iAmount, pricePerToken()); _burn(msg.sender, iAmount); From dd00b6f8aecbf1f90faac3510d877ea859e8d492 Mon Sep 17 00:00:00 2001 From: Sowmay Jain Date: Sat, 22 Aug 2020 16:48:15 +1000 Subject: [PATCH 03/15] minor changes --- contracts/tokenPool.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/tokenPool.sol b/contracts/tokenPool.sol index 4728cbc..9efed1c 100644 --- a/contracts/tokenPool.sol +++ b/contracts/tokenPool.sol @@ -67,13 +67,13 @@ contract PoolToken is ERC20, DSMath { } uint dsaAmount; - function depositDSA(uint amount) public isChief { + function deploy(uint amount) public isChief { address _dsa = registry.dsa(address(this)); baseToken.safeTransfer(_dsa, amount); dsaAmount = add(dsaAmount, amount); } - function withdrawDSA(uint amount) public isChief { + function claim(uint amount) public isChief { // address _dsa = registry.dsa(address(this)); baseToken.safeTransferFrom(msg.sender, address(this), amount); uint totalAmountWithProfit = RateInterface(address(0)).totalBalance(); // TODO - change to => totalBalanceDSA From 108d1182509a28ef7e34e6526ad95d03d01ed5f9 Mon Sep 17 00:00:00 2001 From: Sowmay Jain Date: Sat, 22 Aug 2020 21:50:42 +1000 Subject: [PATCH 04/15] minor change --- contracts/registry.sol | 2 +- contracts/tokenPool.sol | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/contracts/registry.sol b/contracts/registry.sol index cab1258..0f287eb 100644 --- a/contracts/registry.sol +++ b/contracts/registry.sol @@ -22,7 +22,7 @@ contract Registry { mapping (address => bool) public chief; mapping (address => address) public dsa; - mapping (address => address) public rateLogic; + mapping (address => address) public logic; modifier isMaster() { require(msg.sender == instaIndex.master(), "not-master"); diff --git a/contracts/tokenPool.sol b/contracts/tokenPool.sol index 9efed1c..3273950 100644 --- a/contracts/tokenPool.sol +++ b/contracts/tokenPool.sol @@ -40,8 +40,6 @@ contract PoolToken is ERC20, DSMath { uint private tokenBalance; uint private tokenProfit; uint private tokenCap; - - constructor( address _registry, From 64518a43ff2e066acf3b530dba935ebb243539fb Mon Sep 17 00:00:00 2001 From: Samyak Jain <34437877+KaymasJain@users.noreply.github.com> Date: Sun, 23 Aug 2020 04:48:23 +1000 Subject: [PATCH 05/15] tokenPool contract basics --- contracts/Samyak/registry.sol | 62 ++++++++++++++ contracts/Samyak/tokenPool.sol | 143 +++++++++++++++++++++++++++++++++ 2 files changed, 205 insertions(+) create mode 100644 contracts/Samyak/registry.sol create mode 100644 contracts/Samyak/tokenPool.sol diff --git a/contracts/Samyak/registry.sol b/contracts/Samyak/registry.sol new file mode 100644 index 0000000..4ae0d8f --- /dev/null +++ b/contracts/Samyak/registry.sol @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; + +// TODO +// function for adding and removing rate logics. +// Added fee variable and required function to change it. +// Link all the contract more properly. +// Have to think more on pricePerToken function. + +interface IndexInterface { + function master() external view returns (address); +} + +contract Registry { + + event LogAddChief(address indexed chief); + event LogRemoveChief(address indexed chief); + + IndexInterface public instaIndex; + + mapping (address => bool) public chief; + mapping (address => address) public dsa; + mapping (address => address) public logic; + + modifier isMaster() { + require(msg.sender == instaIndex.master(), "not-master"); + _; + } + + modifier isController() { + require(chief[msg.sender] || msg.sender == instaIndex.master(), "not-chief"); + _; + } + + constructor(address _index) public { + instaIndex = IndexInterface(_index); + } + + /** + * @dev Enable New Chief. + * @param _chief Address of the new chief. + */ + function enableChief(address _chief) external isMaster { + require(_chief != address(0), "address-not-valid"); + require(!chief[_chief], "chief-already-enabled"); + chief[_chief] = true; + emit LogAddChief(_chief); + } + + /** + * @dev Disable Chief. + * @param _chief Address of the existing chief. + */ + function disableChief(address _chief) external isMaster { + require(_chief != address(0), "address-not-valid"); + require(chief[_chief], "chief-already-disabled"); + delete chief[_chief]; + emit LogRemoveChief(_chief); + } +} diff --git a/contracts/Samyak/tokenPool.sol b/contracts/Samyak/tokenPool.sol new file mode 100644 index 0000000..74f3438 --- /dev/null +++ b/contracts/Samyak/tokenPool.sol @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; + +import { DSMath } from "./../libs/safeMath.sol"; + +// TODO - Add ReentrancyGuard lib + +interface AccountInterface { + function enable(address authority) external; + function cast(address[] calldata _targets, bytes[] calldata _datas, address _origin) external payable; +} + +interface IndexInterface { + function master() external view returns (address); +} + +interface RegistryInterface { + function chief(address) external view returns (bool); + function dsa(address) external view returns (address); + function rateLogic(address) external view returns (address); +} + +interface RateInterface { + function pricePerToken() external view returns (uint); + function totalBalance() external view returns (uint); + function getTotalToken() external returns (uint totalUnderlyingTkn); +} + +contract PoolToken is ERC20, DSMath { + using SafeERC20 for IERC20; + + IERC20 public immutable baseToken; + RegistryInterface public immutable registry; + IndexInterface public immutable instaIndex; + + uint private tokenBalance; + uint private tokenProfit; + uint private tokenCap; + uint public exchangeRate = 1000000000000000000; // initial 1 token = 1 + address public settlementLogic; + uint public insuranceAmt; + + constructor( + address _registry, + address _index, + string memory _name, + string memory _symbol, + address _baseToken + ) public ERC20(_name, _symbol) { + // TODO - 0 + baseToken = IERC20(_baseToken); + registry = RegistryInterface(_registry); + instaIndex = IndexInterface(_index); + } + + modifier isMaster() { + require(msg.sender == instaIndex.master(), "not-master"); + _; + } + + modifier isChief() { + require(registry.chief(msg.sender) || msg.sender == instaIndex.master(), "not-chief"); + _; + } + + uint dsaAmount; + function deploy(uint amount) public isChief { + address _dsa = registry.dsa(address(this)); + baseToken.safeTransfer(_dsa, amount); + dsaAmount = add(dsaAmount, amount); + } + + function claim(uint amount) public isChief { + // address _dsa = registry.dsa(address(this)); + baseToken.safeTransferFrom(msg.sender, address(this), amount); + uint totalAmountWithProfit = RateInterface(address(0)).totalBalance(); // TODO - change to => totalBalanceDSA + uint _amount = wdiv(wmul(amount, dsaAmount), totalAmountWithProfit); + uint profit = sub(amount, _amount); + tokenProfit = add(tokenProfit, profit); + dsaAmount = sub(dsaAmount, _amount); + } + + function getBalance() public view returns(uint) { + return sub(add(dsaAmount, baseToken.balanceOf(address(this))), tokenProfit); + } + + function pricePerToken() public view returns(uint) { + return 1e18; // TODO - Link to rate logic contract + } + + function setExchangeRate() public view isChief { + uint _previousRate = exchangeRate; + uint _totalToken = RateInterface(settlementLogic).getTotalToken(); + uint _currentRate = wdiv(_totalToken, totalSupply()); + if (_currentRate < _previousRate) { + uint difRate = _previousRate - _currentRate; + uint difTkn = wmul(_totalToken, difRate); + insuranceAmt = sub(insuranceAmt, difTkn); + _currentRate = _previousRate; + } else { + uint difRate = _currentRate - _previousRate; + uint insureFee = wmul(difRate, 100000000000000000); // 1e17 + uint insureFeeAmt = wmul(_totalToken, insureRate); + insuranceAmt = add(insuranceAmt, insureFeeAmt); + _currentRate = sub(_currentRate, insureFee); + } + exchangeRate = _currentRate; + } + + function settlement(address[] calldata _targets, bytes[] calldata _datas, address _origin) external view isChief { + address _dsa = registry.dsa(address(this)); + if (_targets.length > 0 && _datas.length > 0) { + AccountInterface(_dsa).cast(_targets, _datas, _origin); + } + setExchangeRate(); + } + + function deposit(uint amount) public returns(uint) { + uint _newTokenBal = add(tokenBalance, amount); + require(_newTokenBal <= getBalance(), "deposit-cap-reached"); + + baseToken.safeTransferFrom(msg.sender, address(this), amount); + uint iAmt = wdiv(amount, exchangeRate); + _mint(msg.sender, iAmt); + } + + function withdraw(address owner, uint iAmount) public returns (uint) { + // TODO - check balance before withdrawing + uint amount = wmul(iAmount, exchangeRate); + _burn(msg.sender, iAmount); + + baseToken.safeTransfer(owner, amount); + } + + function withdraw(uint amount) public returns (uint) { + return withdraw(msg.sender, amount); + } +} From e879ff4d854f2022ebca103dbbca1e9a535f4b8a Mon Sep 17 00:00:00 2001 From: Samyak Jain <34437877+KaymasJain@users.noreply.github.com> Date: Sun, 23 Aug 2020 20:53:01 +1000 Subject: [PATCH 06/15] instapool done events remaining --- contracts/Samyak/registry.sol | 43 +++++++++--- contracts/Samyak/tokenPool.sol | 121 ++++++++++++++++----------------- 2 files changed, 93 insertions(+), 71 deletions(-) diff --git a/contracts/Samyak/registry.sol b/contracts/Samyak/registry.sol index 4ae0d8f..7008f66 100644 --- a/contracts/Samyak/registry.sol +++ b/contracts/Samyak/registry.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; +pragma solidity ^0.6.8; pragma experimental ABIEncoderV2; // TODO @@ -18,26 +18,24 @@ contract Registry { event LogAddChief(address indexed chief); event LogRemoveChief(address indexed chief); - IndexInterface public instaIndex; + IndexInterface public constant instaIndex = IndexInterface(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723); mapping (address => bool) public chief; - mapping (address => address) public dsa; - mapping (address => address) public logic; + mapping (address => bool) public isPool; + mapping (address => address) public poolLogic; + mapping (address => uint) public poolCap; + mapping (address => uint) public insureFee; modifier isMaster() { require(msg.sender == instaIndex.master(), "not-master"); _; } - modifier isController() { + modifier isChief() { require(chief[msg.sender] || msg.sender == instaIndex.master(), "not-chief"); _; } - constructor(address _index) public { - instaIndex = IndexInterface(_index); - } - /** * @dev Enable New Chief. * @param _chief Address of the new chief. @@ -59,4 +57,31 @@ contract Registry { delete chief[_chief]; emit LogRemoveChief(_chief); } + + function enablePool(address _pool) external isMaster { + isPool[_pool] = true; + } + + function updatePoolCap(address _pool, uint _newCap) external isChief { + require(isPool[_pool], "not-a-pool"); + poolCap[_pool] = _newCap; + } + + function updateLogic(address _pool, address _newLogic) external isChief { + require(isPool[_pool], "not-a-pool"); + require(_newLogic != address(0), "address-0"); + poolLogic[_pool] = _newLogic; + } + + function updateInsureFee(address _pool, uint _newFee) external isChief { + require(isPool[_pool], "not-a-pool"); + require(_newFee < 1000000000000000000, "insure-fee-limit-reached"); + insureFee[_pool] = _newFee; + } + + constructor(address _chief) public { + chief[_chief] = true; + emit LogAddChief(_chief); + } + } diff --git a/contracts/Samyak/tokenPool.sol b/contracts/Samyak/tokenPool.sol index 74f3438..b354112 100644 --- a/contracts/Samyak/tokenPool.sol +++ b/contracts/Samyak/tokenPool.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.7.0; +pragma solidity ^0.6.8; pragma experimental ABIEncoderV2; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; @@ -17,16 +17,17 @@ interface AccountInterface { interface IndexInterface { function master() external view returns (address); + function build(address _owner, uint accountVersion, address _origin) external returns (address _account); } interface RegistryInterface { function chief(address) external view returns (bool); - function dsa(address) external view returns (address); - function rateLogic(address) external view returns (address); + function poolLogic(address) external returns (address); + function poolCap(address) external view returns (uint); + function insureFee(address) external view returns (uint); } interface RateInterface { - function pricePerToken() external view returns (uint); function totalBalance() external view returns (uint); function getTotalToken() external returns (uint totalUnderlyingTkn); } @@ -36,66 +37,40 @@ contract PoolToken is ERC20, DSMath { IERC20 public immutable baseToken; RegistryInterface public immutable registry; - IndexInterface public immutable instaIndex; + IndexInterface public constant instaIndex = IndexInterface(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723); + AccountInterface public immutable dsa; - uint private tokenBalance; - uint private tokenProfit; - uint private tokenCap; + uint private tokenBalance; // total token balance since last rebalancing uint public exchangeRate = 1000000000000000000; // initial 1 token = 1 - address public settlementLogic; - uint public insuranceAmt; - + uint public insuranceAmt; // insurance amount to keep pool safe + bool public shutPool; + constructor( address _registry, - address _index, string memory _name, string memory _symbol, - address _baseToken + address _baseToken, + address _origin ) public ERC20(_name, _symbol) { // TODO - 0 baseToken = IERC20(_baseToken); registry = RegistryInterface(_registry); - instaIndex = IndexInterface(_index); - } - - modifier isMaster() { - require(msg.sender == instaIndex.master(), "not-master"); - _; + address _dsa = instaIndex.build(address(this), 1, _origin); + dsa = AccountInterface(_dsa); } modifier isChief() { require(registry.chief(msg.sender) || msg.sender == instaIndex.master(), "not-chief"); _; } - - uint dsaAmount; + function deploy(uint amount) public isChief { - address _dsa = registry.dsa(address(this)); - baseToken.safeTransfer(_dsa, amount); - dsaAmount = add(dsaAmount, amount); + baseToken.safeTransfer(address(dsa), amount); } - function claim(uint amount) public isChief { - // address _dsa = registry.dsa(address(this)); - baseToken.safeTransferFrom(msg.sender, address(this), amount); - uint totalAmountWithProfit = RateInterface(address(0)).totalBalance(); // TODO - change to => totalBalanceDSA - uint _amount = wdiv(wmul(amount, dsaAmount), totalAmountWithProfit); - uint profit = sub(amount, _amount); - tokenProfit = add(tokenProfit, profit); - dsaAmount = sub(dsaAmount, _amount); - } - - function getBalance() public view returns(uint) { - return sub(add(dsaAmount, baseToken.balanceOf(address(this))), tokenProfit); - } - - function pricePerToken() public view returns(uint) { - return 1e18; // TODO - Link to rate logic contract - } - - function setExchangeRate() public view isChief { + function setExchangeRate() public isChief { uint _previousRate = exchangeRate; - uint _totalToken = RateInterface(settlementLogic).getTotalToken(); + uint _totalToken = RateInterface(registry.poolLogic(address(this))).getTotalToken(); uint _currentRate = wdiv(_totalToken, totalSupply()); if (_currentRate < _previousRate) { uint difRate = _previousRate - _currentRate; @@ -104,40 +79,62 @@ contract PoolToken is ERC20, DSMath { _currentRate = _previousRate; } else { uint difRate = _currentRate - _previousRate; - uint insureFee = wmul(difRate, 100000000000000000); // 1e17 - uint insureFeeAmt = wmul(_totalToken, insureRate); + uint insureFee = wmul(difRate, registry.insureFee(address(this))); // 1e17 + uint insureFeeAmt = wmul(_totalToken, insureFee); insuranceAmt = add(insuranceAmt, insureFeeAmt); _currentRate = sub(_currentRate, insureFee); + tokenBalance = sub(_totalToken, insuranceAmt); } exchangeRate = _currentRate; } - function settlement(address[] calldata _targets, bytes[] calldata _datas, address _origin) external view isChief { - address _dsa = registry.dsa(address(this)); + function settle(address[] calldata _targets, bytes[] calldata _datas, address _origin) external isChief { if (_targets.length > 0 && _datas.length > 0) { - AccountInterface(_dsa).cast(_targets, _datas, _origin); + dsa.cast(_targets, _datas, _origin); } setExchangeRate(); } - function deposit(uint amount) public returns(uint) { - uint _newTokenBal = add(tokenBalance, amount); - require(_newTokenBal <= getBalance(), "deposit-cap-reached"); + function deposit(uint tknAmt) public payable returns(uint) { + require(!shutPool, "pool-shut"); + uint _newTokenBal = add(tokenBalance, tknAmt); + require(_newTokenBal <= registry.poolCap(address(this)), "deposit-cap-reached"); - baseToken.safeTransferFrom(msg.sender, address(this), amount); - uint iAmt = wdiv(amount, exchangeRate); - _mint(msg.sender, iAmt); + baseToken.safeTransferFrom(msg.sender, address(this), tknAmt); + uint _mintAmt = wdiv(tknAmt, exchangeRate); + _mint(msg.sender, _mintAmt); } - function withdraw(address owner, uint iAmount) public returns (uint) { - // TODO - check balance before withdrawing - uint amount = wmul(iAmount, exchangeRate); - _burn(msg.sender, iAmount); + function withdraw(uint tknAmt, address to) public returns (uint) { + require(!shutPool, "pool-shut"); + uint poolBal = baseToken.balanceOf(address(this)); + require(tknAmt <= poolBal, "not-enough-liquidity-available"); + uint _bal = balanceOf(msg.sender); + uint _tknBal = wmul(_bal, exchangeRate); + uint _burnAmt; + uint _tknAmt; + if (tknAmt == uint(-1)) { + _burnAmt = _bal; + _tknAmt = wmul(_burnAmt, exchangeRate); + } else { + require(tknAmt <= _tknBal, "balance-exceeded"); + _burnAmt = wdiv(tknAmt, exchangeRate); + _tknAmt = tknAmt; + } - baseToken.safeTransfer(owner, amount); + _burn(msg.sender, _burnAmt); + + baseToken.safeTransfer(to, _tknAmt); } - function withdraw(uint amount) public returns (uint) { - return withdraw(msg.sender, amount); + function addInsurance(uint tknAmt) public { + baseToken.safeTransferFrom(msg.sender, address(this), tknAmt); + insuranceAmt = tknAmt; } + + function shutdown() public { + require(msg.sender == instaIndex.master(), "not-master"); + shutPool = !shutPool; + } + } From 29dbb98bea3dcbda41cdb0df45778a89d2df7656 Mon Sep 17 00:00:00 2001 From: Samyak Jain <34437877+KaymasJain@users.noreply.github.com> Date: Sun, 23 Aug 2020 22:05:09 +1000 Subject: [PATCH 07/15] ethPool done --- contracts/Samyak/ethPool.sol | 144 +++++++++++++++++++++++++++++++++ contracts/Samyak/tokenPool.sol | 8 +- 2 files changed, 148 insertions(+), 4 deletions(-) create mode 100644 contracts/Samyak/ethPool.sol diff --git a/contracts/Samyak/ethPool.sol b/contracts/Samyak/ethPool.sol new file mode 100644 index 0000000..8253311 --- /dev/null +++ b/contracts/Samyak/ethPool.sol @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.8; +pragma experimental ABIEncoderV2; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; + +import { DSMath } from "./../libs/safeMath.sol"; + +// TODO - Add ReentrancyGuard lib + +interface AccountInterface { + function enable(address authority) external; + function cast(address[] calldata _targets, bytes[] calldata _datas, address _origin) external payable; +} + +interface IndexInterface { + function master() external view returns (address); + function build(address _owner, uint accountVersion, address _origin) external returns (address _account); +} + +interface RegistryInterface { + function chief(address) external view returns (bool); + function poolLogic(address) external returns (address); + function poolCap(address) external view returns (uint); + function insureFee(address) external view returns (uint); +} + +interface RateInterface { + function totalBalance() external view returns (uint); + function getTotalToken() external returns (uint totalUnderlyingTkn); +} + +contract PoolToken is ERC20, DSMath { + using SafeERC20 for IERC20; + + IERC20 public immutable baseToken; + RegistryInterface public immutable registry; + IndexInterface public constant instaIndex = IndexInterface(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723); + AccountInterface public immutable dsa; + + uint private tokenBalance; // total token balance since last rebalancing + uint public exchangeRate = 1000000000000000000; // initial 1 token = 1 + uint public insuranceAmt; // insurance amount to keep pool safe + bool public shutPool; + + constructor( + address _registry, + string memory _name, + string memory _symbol, + address _baseToken, + address _origin + ) public ERC20(_name, _symbol) { + // TODO - 0 + baseToken = IERC20(_baseToken); + registry = RegistryInterface(_registry); + address _dsa = instaIndex.build(address(this), 1, _origin); + dsa = AccountInterface(_dsa); + } + + modifier isChief() { + require(registry.chief(msg.sender) || msg.sender == instaIndex.master(), "not-chief"); + _; + } + + function deploy(uint amount) external isChief { + baseToken.safeTransfer(address(dsa), amount); + } + + function setExchangeRate() public isChief { + uint _previousRate = exchangeRate; + uint _totalToken = RateInterface(registry.poolLogic(address(this))).getTotalToken(); + uint _currentRate = wdiv(_totalToken, totalSupply()); + if (_currentRate < _previousRate) { + uint difRate = _previousRate - _currentRate; + uint difTkn = wmul(_totalToken, difRate); + insuranceAmt = sub(insuranceAmt, difTkn); + _currentRate = _previousRate; + } else { + uint difRate = _currentRate - _previousRate; + uint insureFee = wmul(difRate, registry.insureFee(address(this))); // 1e17 + uint insureFeeAmt = wmul(_totalToken, insureFee); + insuranceAmt = add(insuranceAmt, insureFeeAmt); + _currentRate = sub(_currentRate, insureFee); + tokenBalance = sub(_totalToken, insuranceAmt); + } + exchangeRate = _currentRate; + } + + function settle(address[] calldata _targets, bytes[] calldata _datas, address _origin) external isChief { + if (_targets.length > 0 && _datas.length > 0) { + dsa.cast(_targets, _datas, _origin); + } + setExchangeRate(); + } + + function deposit(uint tknAmt) public payable returns(uint) { + require(!shutPool, "pool-shut"); + uint _newTokenBal = add(tokenBalance, tknAmt); + require(_newTokenBal <= registry.poolCap(address(this)), "deposit-cap-reached"); + + baseToken.safeTransferFrom(msg.sender, address(this), tknAmt); + uint _mintAmt = wdiv(tknAmt, exchangeRate); + _mint(msg.sender, _mintAmt); + } + + function withdraw(uint tknAmt, address to) external returns (uint) { + require(!shutPool, "pool-shut"); + uint poolBal = baseToken.balanceOf(address(this)); + require(tknAmt <= poolBal, "not-enough-liquidity-available"); + uint _bal = balanceOf(msg.sender); + uint _tknBal = wmul(_bal, exchangeRate); + uint _burnAmt; + uint _tknAmt; + if (tknAmt == uint(-1)) { + _burnAmt = _bal; + _tknAmt = wmul(_burnAmt, exchangeRate); + } else { + require(tknAmt <= _tknBal, "balance-exceeded"); + _burnAmt = wdiv(tknAmt, exchangeRate); + _tknAmt = tknAmt; + } + + _burn(msg.sender, _burnAmt); + + baseToken.safeTransfer(to, _tknAmt); + } + + function addInsurance(uint tknAmt) external { + baseToken.safeTransferFrom(msg.sender, address(this), tknAmt); + insuranceAmt = tknAmt; + } + + function shutdown() external { + require(msg.sender == instaIndex.master(), "not-master"); + shutPool = !shutPool; + } + + receive() external payable { + deposit(msg.value); + } + +} diff --git a/contracts/Samyak/tokenPool.sol b/contracts/Samyak/tokenPool.sol index b354112..def0656 100644 --- a/contracts/Samyak/tokenPool.sol +++ b/contracts/Samyak/tokenPool.sol @@ -95,7 +95,7 @@ contract PoolToken is ERC20, DSMath { setExchangeRate(); } - function deposit(uint tknAmt) public payable returns(uint) { + function deposit(uint tknAmt) external payable returns(uint) { require(!shutPool, "pool-shut"); uint _newTokenBal = add(tokenBalance, tknAmt); require(_newTokenBal <= registry.poolCap(address(this)), "deposit-cap-reached"); @@ -105,7 +105,7 @@ contract PoolToken is ERC20, DSMath { _mint(msg.sender, _mintAmt); } - function withdraw(uint tknAmt, address to) public returns (uint) { + function withdraw(uint tknAmt, address to) external returns (uint) { require(!shutPool, "pool-shut"); uint poolBal = baseToken.balanceOf(address(this)); require(tknAmt <= poolBal, "not-enough-liquidity-available"); @@ -127,12 +127,12 @@ contract PoolToken is ERC20, DSMath { baseToken.safeTransfer(to, _tknAmt); } - function addInsurance(uint tknAmt) public { + function addInsurance(uint tknAmt) external { baseToken.safeTransferFrom(msg.sender, address(this), tknAmt); insuranceAmt = tknAmt; } - function shutdown() public { + function shutdown() external { require(msg.sender == instaIndex.master(), "not-master"); shutPool = !shutPool; } From a115927405dd50e303da8bdc6b75ecab5912269e Mon Sep 17 00:00:00 2001 From: Samyak Jain <34437877+KaymasJain@users.noreply.github.com> Date: Sun, 23 Aug 2020 22:42:32 +1000 Subject: [PATCH 08/15] event added and eth edits --- contracts/Samyak/ethPool.sol | 47 +++++++++++++++++++++++----------- contracts/Samyak/registry.sol | 14 +++++++--- contracts/Samyak/tokenPool.sol | 32 +++++++++++++++++------ 3 files changed, 67 insertions(+), 26 deletions(-) diff --git a/contracts/Samyak/ethPool.sol b/contracts/Samyak/ethPool.sol index 8253311..958b703 100644 --- a/contracts/Samyak/ethPool.sol +++ b/contracts/Samyak/ethPool.sol @@ -35,25 +35,32 @@ interface RateInterface { contract PoolToken is ERC20, DSMath { using SafeERC20 for IERC20; - IERC20 public immutable baseToken; - RegistryInterface public immutable registry; + event LogDeploy(uint amount); + event LogExchangeRate(uint exchangeRate, uint tokenBalance, uint insuranceAmt); + event LogSettle(uint settleTime); + event LogDeposit(uint depositAmt, uint poolMintAmt); + event LogWithdraw(uint withdrawAmt, uint poolBurnAmt); + event LogAddInsurance(uint amount); + event LogPoolShut(bool); + + // IERC20 public immutable baseToken; + RegistryInterface public immutable registry; // Pool Registry IndexInterface public constant instaIndex = IndexInterface(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723); - AccountInterface public immutable dsa; + AccountInterface public immutable dsa; // Pool's DSA account uint private tokenBalance; // total token balance since last rebalancing uint public exchangeRate = 1000000000000000000; // initial 1 token = 1 uint public insuranceAmt; // insurance amount to keep pool safe - bool public shutPool; + bool public shutPool; // shutdown deposits and withdrawals constructor( address _registry, string memory _name, string memory _symbol, - address _baseToken, address _origin ) public ERC20(_name, _symbol) { // TODO - 0 - baseToken = IERC20(_baseToken); + // baseToken = IERC20(_baseToken); registry = RegistryInterface(_registry); address _dsa = instaIndex.build(address(this), 1, _origin); dsa = AccountInterface(_dsa); @@ -65,7 +72,8 @@ contract PoolToken is ERC20, DSMath { } function deploy(uint amount) external isChief { - baseToken.safeTransfer(address(dsa), amount); + payable(address(dsa)).transfer(amount); + emit LogDeploy(amount); } function setExchangeRate() public isChief { @@ -86,6 +94,7 @@ contract PoolToken is ERC20, DSMath { tokenBalance = sub(_totalToken, insuranceAmt); } exchangeRate = _currentRate; + emit LogExchangeRate(exchangeRate, tokenBalance, insuranceAmt); } function settle(address[] calldata _targets, bytes[] calldata _datas, address _origin) external isChief { @@ -93,21 +102,25 @@ contract PoolToken is ERC20, DSMath { dsa.cast(_targets, _datas, _origin); } setExchangeRate(); + + emit LogSettle(block.timestamp); } function deposit(uint tknAmt) public payable returns(uint) { require(!shutPool, "pool-shut"); - uint _newTokenBal = add(tokenBalance, tknAmt); + require(tknAmt == msg.value, "unmatched-amount"); + uint _newTokenBal = add(tokenBalance, msg.value); require(_newTokenBal <= registry.poolCap(address(this)), "deposit-cap-reached"); - baseToken.safeTransferFrom(msg.sender, address(this), tknAmt); - uint _mintAmt = wdiv(tknAmt, exchangeRate); + uint _mintAmt = wdiv(msg.value, exchangeRate); _mint(msg.sender, _mintAmt); + + emit LogDeposit(tknAmt, _mintAmt); } function withdraw(uint tknAmt, address to) external returns (uint) { require(!shutPool, "pool-shut"); - uint poolBal = baseToken.balanceOf(address(this)); + uint poolBal = address(this).balance; require(tknAmt <= poolBal, "not-enough-liquidity-available"); uint _bal = balanceOf(msg.sender); uint _tknBal = wmul(_bal, exchangeRate); @@ -124,17 +137,21 @@ contract PoolToken is ERC20, DSMath { _burn(msg.sender, _burnAmt); - baseToken.safeTransfer(to, _tknAmt); + payable(to).transfer(_tknAmt); + + emit LogWithdraw(tknAmt, _burnAmt); } - function addInsurance(uint tknAmt) external { - baseToken.safeTransferFrom(msg.sender, address(this), tknAmt); - insuranceAmt = tknAmt; + function addInsurance(uint tknAmt) external payable { + require(tknAmt == msg.value, "unmatched-amount"); + insuranceAmt += tknAmt; + emit LogAddInsurance(tknAmt); } function shutdown() external { require(msg.sender == instaIndex.master(), "not-master"); shutPool = !shutPool; + emit LogPoolShut(shutPool); } receive() external payable { diff --git a/contracts/Samyak/registry.sol b/contracts/Samyak/registry.sol index 7008f66..dd10eb4 100644 --- a/contracts/Samyak/registry.sol +++ b/contracts/Samyak/registry.sol @@ -17,6 +17,10 @@ contract Registry { event LogAddChief(address indexed chief); event LogRemoveChief(address indexed chief); + event LogSwitchPool(address pool, bool); + event LogUpdatePoolCap(address pool, uint newCap); + event LogUpdatePoolLogic(address pool, address newLogic); + event LogUpdateInsureFee(address pool, uint newFee); IndexInterface public constant instaIndex = IndexInterface(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723); @@ -58,25 +62,29 @@ contract Registry { emit LogRemoveChief(_chief); } - function enablePool(address _pool) external isMaster { - isPool[_pool] = true; + function switchPool(address _pool) external isMaster { + isPool[_pool] = !isPool[_pool]; + emit LogSwitchPool(_pool, isPool[_pool]); } function updatePoolCap(address _pool, uint _newCap) external isChief { require(isPool[_pool], "not-a-pool"); poolCap[_pool] = _newCap; + emit LogUpdatePoolCap(_pool, _newCap); } - function updateLogic(address _pool, address _newLogic) external isChief { + function updatePoolLogic(address _pool, address _newLogic) external isChief { require(isPool[_pool], "not-a-pool"); require(_newLogic != address(0), "address-0"); poolLogic[_pool] = _newLogic; + emit LogUpdatePoolLogic(_pool, _newLogic); } function updateInsureFee(address _pool, uint _newFee) external isChief { require(isPool[_pool], "not-a-pool"); require(_newFee < 1000000000000000000, "insure-fee-limit-reached"); insureFee[_pool] = _newFee; + emit LogUpdateInsureFee(_pool, _newFee); } constructor(address _chief) public { diff --git a/contracts/Samyak/tokenPool.sol b/contracts/Samyak/tokenPool.sol index def0656..a0d7d33 100644 --- a/contracts/Samyak/tokenPool.sol +++ b/contracts/Samyak/tokenPool.sol @@ -35,15 +35,23 @@ interface RateInterface { contract PoolToken is ERC20, DSMath { using SafeERC20 for IERC20; - IERC20 public immutable baseToken; - RegistryInterface public immutable registry; - IndexInterface public constant instaIndex = IndexInterface(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723); - AccountInterface public immutable dsa; + event LogDeploy(uint amount); + event LogExchangeRate(uint exchangeRate, uint tokenBalance, uint insuranceAmt); + event LogSettle(uint settleTime); + event LogDeposit(uint depositAmt, uint poolMintAmt); + event LogWithdraw(uint withdrawAmt, uint poolBurnAmt); + event LogAddInsurance(uint amount); + event LogPoolShut(bool); + + IERC20 public immutable baseToken; // Base token. Eg:- DAI, USDC, etc. + RegistryInterface public immutable registry; // Pool Registry + IndexInterface public constant instaIndex = IndexInterface(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723); // Main Index + AccountInterface public immutable dsa; // Pool's DSA account uint private tokenBalance; // total token balance since last rebalancing uint public exchangeRate = 1000000000000000000; // initial 1 token = 1 uint public insuranceAmt; // insurance amount to keep pool safe - bool public shutPool; + bool public shutPool; // shutdown deposits and withdrawals constructor( address _registry, @@ -52,7 +60,6 @@ contract PoolToken is ERC20, DSMath { address _baseToken, address _origin ) public ERC20(_name, _symbol) { - // TODO - 0 baseToken = IERC20(_baseToken); registry = RegistryInterface(_registry); address _dsa = instaIndex.build(address(this), 1, _origin); @@ -66,6 +73,7 @@ contract PoolToken is ERC20, DSMath { function deploy(uint amount) public isChief { baseToken.safeTransfer(address(dsa), amount); + emit LogDeploy(amount); } function setExchangeRate() public isChief { @@ -86,6 +94,7 @@ contract PoolToken is ERC20, DSMath { tokenBalance = sub(_totalToken, insuranceAmt); } exchangeRate = _currentRate; + emit LogExchangeRate(exchangeRate, tokenBalance, insuranceAmt); } function settle(address[] calldata _targets, bytes[] calldata _datas, address _origin) external isChief { @@ -93,6 +102,7 @@ contract PoolToken is ERC20, DSMath { dsa.cast(_targets, _datas, _origin); } setExchangeRate(); + emit LogSettle(block.timestamp); } function deposit(uint tknAmt) external payable returns(uint) { @@ -103,6 +113,8 @@ contract PoolToken is ERC20, DSMath { baseToken.safeTransferFrom(msg.sender, address(this), tknAmt); uint _mintAmt = wdiv(tknAmt, exchangeRate); _mint(msg.sender, _mintAmt); + + emit LogDeposit(tknAmt, _mintAmt); } function withdraw(uint tknAmt, address to) external returns (uint) { @@ -125,16 +137,20 @@ contract PoolToken is ERC20, DSMath { _burn(msg.sender, _burnAmt); baseToken.safeTransfer(to, _tknAmt); + + emit LogWithdraw(tknAmt, _burnAmt); } - function addInsurance(uint tknAmt) external { + function addInsurance(uint tknAmt) external payable { baseToken.safeTransferFrom(msg.sender, address(this), tknAmt); - insuranceAmt = tknAmt; + insuranceAmt += tknAmt; + emit LogAddInsurance(tknAmt); } function shutdown() external { require(msg.sender == instaIndex.master(), "not-master"); shutPool = !shutPool; + emit LogPoolShut(shutPool); } } From 26e86c9436b95a41ac696c20995a14fac9e45f3a Mon Sep 17 00:00:00 2001 From: Samyak Jain <34437877+KaymasJain@users.noreply.github.com> Date: Sun, 23 Aug 2020 23:16:13 +1000 Subject: [PATCH 09/15] withdraw return uint --- contracts/Samyak/ethPool.sol | 3 +-- contracts/Samyak/tokenPool.sol | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/contracts/Samyak/ethPool.sol b/contracts/Samyak/ethPool.sol index 958b703..740a3c9 100644 --- a/contracts/Samyak/ethPool.sol +++ b/contracts/Samyak/ethPool.sol @@ -118,14 +118,13 @@ contract PoolToken is ERC20, DSMath { emit LogDeposit(tknAmt, _mintAmt); } - function withdraw(uint tknAmt, address to) external returns (uint) { + function withdraw(uint tknAmt, address to) external returns (uint _tknAmt) { require(!shutPool, "pool-shut"); uint poolBal = address(this).balance; require(tknAmt <= poolBal, "not-enough-liquidity-available"); uint _bal = balanceOf(msg.sender); uint _tknBal = wmul(_bal, exchangeRate); uint _burnAmt; - uint _tknAmt; if (tknAmt == uint(-1)) { _burnAmt = _bal; _tknAmt = wmul(_burnAmt, exchangeRate); diff --git a/contracts/Samyak/tokenPool.sol b/contracts/Samyak/tokenPool.sol index a0d7d33..56b245f 100644 --- a/contracts/Samyak/tokenPool.sol +++ b/contracts/Samyak/tokenPool.sol @@ -117,14 +117,13 @@ contract PoolToken is ERC20, DSMath { emit LogDeposit(tknAmt, _mintAmt); } - function withdraw(uint tknAmt, address to) external returns (uint) { + function withdraw(uint tknAmt, address to) external returns (uint _tknAmt) { require(!shutPool, "pool-shut"); uint poolBal = baseToken.balanceOf(address(this)); require(tknAmt <= poolBal, "not-enough-liquidity-available"); uint _bal = balanceOf(msg.sender); uint _tknBal = wmul(_bal, exchangeRate); uint _burnAmt; - uint _tknAmt; if (tknAmt == uint(-1)) { _burnAmt = _bal; _tknAmt = wmul(_burnAmt, exchangeRate); From 2f0549b709b8536dcb871fb71ec9d4c14ffcc45f Mon Sep 17 00:00:00 2001 From: Thrilok Kumar Date: Mon, 24 Aug 2020 06:10:01 +0530 Subject: [PATCH 10/15] Updated file structure --- contracts/Samyak/ethPool.sol | 160 --------------------------------- contracts/Samyak/registry.sol | 95 -------------------- contracts/Samyak/tokenPool.sol | 155 -------------------------------- contracts/ethPool.sol | 151 ++++++++++++++++++++++++++++++- contracts/registry.sol | 71 ++++++++++----- contracts/tokenPool.sol | 143 ++++++++++++++++++----------- 6 files changed, 290 insertions(+), 485 deletions(-) delete mode 100644 contracts/Samyak/ethPool.sol delete mode 100644 contracts/Samyak/registry.sol delete mode 100644 contracts/Samyak/tokenPool.sol diff --git a/contracts/Samyak/ethPool.sol b/contracts/Samyak/ethPool.sol deleted file mode 100644 index 740a3c9..0000000 --- a/contracts/Samyak/ethPool.sol +++ /dev/null @@ -1,160 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.8; -pragma experimental ABIEncoderV2; - -import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; - -import { DSMath } from "./../libs/safeMath.sol"; - -// TODO - Add ReentrancyGuard lib - -interface AccountInterface { - function enable(address authority) external; - function cast(address[] calldata _targets, bytes[] calldata _datas, address _origin) external payable; -} - -interface IndexInterface { - function master() external view returns (address); - function build(address _owner, uint accountVersion, address _origin) external returns (address _account); -} - -interface RegistryInterface { - function chief(address) external view returns (bool); - function poolLogic(address) external returns (address); - function poolCap(address) external view returns (uint); - function insureFee(address) external view returns (uint); -} - -interface RateInterface { - function totalBalance() external view returns (uint); - function getTotalToken() external returns (uint totalUnderlyingTkn); -} - -contract PoolToken is ERC20, DSMath { - using SafeERC20 for IERC20; - - event LogDeploy(uint amount); - event LogExchangeRate(uint exchangeRate, uint tokenBalance, uint insuranceAmt); - event LogSettle(uint settleTime); - event LogDeposit(uint depositAmt, uint poolMintAmt); - event LogWithdraw(uint withdrawAmt, uint poolBurnAmt); - event LogAddInsurance(uint amount); - event LogPoolShut(bool); - - // IERC20 public immutable baseToken; - RegistryInterface public immutable registry; // Pool Registry - IndexInterface public constant instaIndex = IndexInterface(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723); - AccountInterface public immutable dsa; // Pool's DSA account - - uint private tokenBalance; // total token balance since last rebalancing - uint public exchangeRate = 1000000000000000000; // initial 1 token = 1 - uint public insuranceAmt; // insurance amount to keep pool safe - bool public shutPool; // shutdown deposits and withdrawals - - constructor( - address _registry, - string memory _name, - string memory _symbol, - address _origin - ) public ERC20(_name, _symbol) { - // TODO - 0 - // baseToken = IERC20(_baseToken); - registry = RegistryInterface(_registry); - address _dsa = instaIndex.build(address(this), 1, _origin); - dsa = AccountInterface(_dsa); - } - - modifier isChief() { - require(registry.chief(msg.sender) || msg.sender == instaIndex.master(), "not-chief"); - _; - } - - function deploy(uint amount) external isChief { - payable(address(dsa)).transfer(amount); - emit LogDeploy(amount); - } - - function setExchangeRate() public isChief { - uint _previousRate = exchangeRate; - uint _totalToken = RateInterface(registry.poolLogic(address(this))).getTotalToken(); - uint _currentRate = wdiv(_totalToken, totalSupply()); - if (_currentRate < _previousRate) { - uint difRate = _previousRate - _currentRate; - uint difTkn = wmul(_totalToken, difRate); - insuranceAmt = sub(insuranceAmt, difTkn); - _currentRate = _previousRate; - } else { - uint difRate = _currentRate - _previousRate; - uint insureFee = wmul(difRate, registry.insureFee(address(this))); // 1e17 - uint insureFeeAmt = wmul(_totalToken, insureFee); - insuranceAmt = add(insuranceAmt, insureFeeAmt); - _currentRate = sub(_currentRate, insureFee); - tokenBalance = sub(_totalToken, insuranceAmt); - } - exchangeRate = _currentRate; - emit LogExchangeRate(exchangeRate, tokenBalance, insuranceAmt); - } - - function settle(address[] calldata _targets, bytes[] calldata _datas, address _origin) external isChief { - if (_targets.length > 0 && _datas.length > 0) { - dsa.cast(_targets, _datas, _origin); - } - setExchangeRate(); - - emit LogSettle(block.timestamp); - } - - function deposit(uint tknAmt) public payable returns(uint) { - require(!shutPool, "pool-shut"); - require(tknAmt == msg.value, "unmatched-amount"); - uint _newTokenBal = add(tokenBalance, msg.value); - require(_newTokenBal <= registry.poolCap(address(this)), "deposit-cap-reached"); - - uint _mintAmt = wdiv(msg.value, exchangeRate); - _mint(msg.sender, _mintAmt); - - emit LogDeposit(tknAmt, _mintAmt); - } - - function withdraw(uint tknAmt, address to) external returns (uint _tknAmt) { - require(!shutPool, "pool-shut"); - uint poolBal = address(this).balance; - require(tknAmt <= poolBal, "not-enough-liquidity-available"); - uint _bal = balanceOf(msg.sender); - uint _tknBal = wmul(_bal, exchangeRate); - uint _burnAmt; - if (tknAmt == uint(-1)) { - _burnAmt = _bal; - _tknAmt = wmul(_burnAmt, exchangeRate); - } else { - require(tknAmt <= _tknBal, "balance-exceeded"); - _burnAmt = wdiv(tknAmt, exchangeRate); - _tknAmt = tknAmt; - } - - _burn(msg.sender, _burnAmt); - - payable(to).transfer(_tknAmt); - - emit LogWithdraw(tknAmt, _burnAmt); - } - - function addInsurance(uint tknAmt) external payable { - require(tknAmt == msg.value, "unmatched-amount"); - insuranceAmt += tknAmt; - emit LogAddInsurance(tknAmt); - } - - function shutdown() external { - require(msg.sender == instaIndex.master(), "not-master"); - shutPool = !shutPool; - emit LogPoolShut(shutPool); - } - - receive() external payable { - deposit(msg.value); - } - -} diff --git a/contracts/Samyak/registry.sol b/contracts/Samyak/registry.sol deleted file mode 100644 index dd10eb4..0000000 --- a/contracts/Samyak/registry.sol +++ /dev/null @@ -1,95 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.6.8; -pragma experimental ABIEncoderV2; - -// TODO -// function for adding and removing rate logics. -// Added fee variable and required function to change it. -// Link all the contract more properly. -// Have to think more on pricePerToken function. - -interface IndexInterface { - function master() external view returns (address); -} - -contract Registry { - - event LogAddChief(address indexed chief); - event LogRemoveChief(address indexed chief); - event LogSwitchPool(address pool, bool); - event LogUpdatePoolCap(address pool, uint newCap); - event LogUpdatePoolLogic(address pool, address newLogic); - event LogUpdateInsureFee(address pool, uint newFee); - - IndexInterface public constant instaIndex = IndexInterface(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723); - - mapping (address => bool) public chief; - mapping (address => bool) public isPool; - mapping (address => address) public poolLogic; - mapping (address => uint) public poolCap; - mapping (address => uint) public insureFee; - - modifier isMaster() { - require(msg.sender == instaIndex.master(), "not-master"); - _; - } - - modifier isChief() { - require(chief[msg.sender] || msg.sender == instaIndex.master(), "not-chief"); - _; - } - - /** - * @dev Enable New Chief. - * @param _chief Address of the new chief. - */ - function enableChief(address _chief) external isMaster { - require(_chief != address(0), "address-not-valid"); - require(!chief[_chief], "chief-already-enabled"); - chief[_chief] = true; - emit LogAddChief(_chief); - } - - /** - * @dev Disable Chief. - * @param _chief Address of the existing chief. - */ - function disableChief(address _chief) external isMaster { - require(_chief != address(0), "address-not-valid"); - require(chief[_chief], "chief-already-disabled"); - delete chief[_chief]; - emit LogRemoveChief(_chief); - } - - function switchPool(address _pool) external isMaster { - isPool[_pool] = !isPool[_pool]; - emit LogSwitchPool(_pool, isPool[_pool]); - } - - function updatePoolCap(address _pool, uint _newCap) external isChief { - require(isPool[_pool], "not-a-pool"); - poolCap[_pool] = _newCap; - emit LogUpdatePoolCap(_pool, _newCap); - } - - function updatePoolLogic(address _pool, address _newLogic) external isChief { - require(isPool[_pool], "not-a-pool"); - require(_newLogic != address(0), "address-0"); - poolLogic[_pool] = _newLogic; - emit LogUpdatePoolLogic(_pool, _newLogic); - } - - function updateInsureFee(address _pool, uint _newFee) external isChief { - require(isPool[_pool], "not-a-pool"); - require(_newFee < 1000000000000000000, "insure-fee-limit-reached"); - insureFee[_pool] = _newFee; - emit LogUpdateInsureFee(_pool, _newFee); - } - - constructor(address _chief) public { - chief[_chief] = true; - emit LogAddChief(_chief); - } - -} diff --git a/contracts/Samyak/tokenPool.sol b/contracts/Samyak/tokenPool.sol deleted file mode 100644 index 56b245f..0000000 --- a/contracts/Samyak/tokenPool.sol +++ /dev/null @@ -1,155 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.8; -pragma experimental ABIEncoderV2; - -import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; - -import { DSMath } from "./../libs/safeMath.sol"; - -// TODO - Add ReentrancyGuard lib - -interface AccountInterface { - function enable(address authority) external; - function cast(address[] calldata _targets, bytes[] calldata _datas, address _origin) external payable; -} - -interface IndexInterface { - function master() external view returns (address); - function build(address _owner, uint accountVersion, address _origin) external returns (address _account); -} - -interface RegistryInterface { - function chief(address) external view returns (bool); - function poolLogic(address) external returns (address); - function poolCap(address) external view returns (uint); - function insureFee(address) external view returns (uint); -} - -interface RateInterface { - function totalBalance() external view returns (uint); - function getTotalToken() external returns (uint totalUnderlyingTkn); -} - -contract PoolToken is ERC20, DSMath { - using SafeERC20 for IERC20; - - event LogDeploy(uint amount); - event LogExchangeRate(uint exchangeRate, uint tokenBalance, uint insuranceAmt); - event LogSettle(uint settleTime); - event LogDeposit(uint depositAmt, uint poolMintAmt); - event LogWithdraw(uint withdrawAmt, uint poolBurnAmt); - event LogAddInsurance(uint amount); - event LogPoolShut(bool); - - IERC20 public immutable baseToken; // Base token. Eg:- DAI, USDC, etc. - RegistryInterface public immutable registry; // Pool Registry - IndexInterface public constant instaIndex = IndexInterface(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723); // Main Index - AccountInterface public immutable dsa; // Pool's DSA account - - uint private tokenBalance; // total token balance since last rebalancing - uint public exchangeRate = 1000000000000000000; // initial 1 token = 1 - uint public insuranceAmt; // insurance amount to keep pool safe - bool public shutPool; // shutdown deposits and withdrawals - - constructor( - address _registry, - string memory _name, - string memory _symbol, - address _baseToken, - address _origin - ) public ERC20(_name, _symbol) { - baseToken = IERC20(_baseToken); - registry = RegistryInterface(_registry); - address _dsa = instaIndex.build(address(this), 1, _origin); - dsa = AccountInterface(_dsa); - } - - modifier isChief() { - require(registry.chief(msg.sender) || msg.sender == instaIndex.master(), "not-chief"); - _; - } - - function deploy(uint amount) public isChief { - baseToken.safeTransfer(address(dsa), amount); - emit LogDeploy(amount); - } - - function setExchangeRate() public isChief { - uint _previousRate = exchangeRate; - uint _totalToken = RateInterface(registry.poolLogic(address(this))).getTotalToken(); - uint _currentRate = wdiv(_totalToken, totalSupply()); - if (_currentRate < _previousRate) { - uint difRate = _previousRate - _currentRate; - uint difTkn = wmul(_totalToken, difRate); - insuranceAmt = sub(insuranceAmt, difTkn); - _currentRate = _previousRate; - } else { - uint difRate = _currentRate - _previousRate; - uint insureFee = wmul(difRate, registry.insureFee(address(this))); // 1e17 - uint insureFeeAmt = wmul(_totalToken, insureFee); - insuranceAmt = add(insuranceAmt, insureFeeAmt); - _currentRate = sub(_currentRate, insureFee); - tokenBalance = sub(_totalToken, insuranceAmt); - } - exchangeRate = _currentRate; - emit LogExchangeRate(exchangeRate, tokenBalance, insuranceAmt); - } - - function settle(address[] calldata _targets, bytes[] calldata _datas, address _origin) external isChief { - if (_targets.length > 0 && _datas.length > 0) { - dsa.cast(_targets, _datas, _origin); - } - setExchangeRate(); - emit LogSettle(block.timestamp); - } - - function deposit(uint tknAmt) external payable returns(uint) { - require(!shutPool, "pool-shut"); - uint _newTokenBal = add(tokenBalance, tknAmt); - require(_newTokenBal <= registry.poolCap(address(this)), "deposit-cap-reached"); - - baseToken.safeTransferFrom(msg.sender, address(this), tknAmt); - uint _mintAmt = wdiv(tknAmt, exchangeRate); - _mint(msg.sender, _mintAmt); - - emit LogDeposit(tknAmt, _mintAmt); - } - - function withdraw(uint tknAmt, address to) external returns (uint _tknAmt) { - require(!shutPool, "pool-shut"); - uint poolBal = baseToken.balanceOf(address(this)); - require(tknAmt <= poolBal, "not-enough-liquidity-available"); - uint _bal = balanceOf(msg.sender); - uint _tknBal = wmul(_bal, exchangeRate); - uint _burnAmt; - if (tknAmt == uint(-1)) { - _burnAmt = _bal; - _tknAmt = wmul(_burnAmt, exchangeRate); - } else { - require(tknAmt <= _tknBal, "balance-exceeded"); - _burnAmt = wdiv(tknAmt, exchangeRate); - _tknAmt = tknAmt; - } - - _burn(msg.sender, _burnAmt); - - baseToken.safeTransfer(to, _tknAmt); - - emit LogWithdraw(tknAmt, _burnAmt); - } - - function addInsurance(uint tknAmt) external payable { - baseToken.safeTransferFrom(msg.sender, address(this), tknAmt); - insuranceAmt += tknAmt; - emit LogAddInsurance(tknAmt); - } - - function shutdown() external { - require(msg.sender == instaIndex.master(), "not-master"); - shutPool = !shutPool; - emit LogPoolShut(shutPool); - } - -} diff --git a/contracts/ethPool.sol b/contracts/ethPool.sol index 3a281ba..740a3c9 100644 --- a/contracts/ethPool.sol +++ b/contracts/ethPool.sol @@ -1,13 +1,160 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.6.8; +pragma experimental ABIEncoderV2; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; + +import { DSMath } from "./../libs/safeMath.sol"; + +// TODO - Add ReentrancyGuard lib + +interface AccountInterface { + function enable(address authority) external; + function cast(address[] calldata _targets, bytes[] calldata _datas, address _origin) external payable; +} + +interface IndexInterface { + function master() external view returns (address); + function build(address _owner, uint accountVersion, address _origin) external returns (address _account); +} + +interface RegistryInterface { + function chief(address) external view returns (bool); + function poolLogic(address) external returns (address); + function poolCap(address) external view returns (uint); + function insureFee(address) external view returns (uint); +} + +interface RateInterface { + function totalBalance() external view returns (uint); + function getTotalToken() external returns (uint totalUnderlyingTkn); +} + +contract PoolToken is ERC20, DSMath { + using SafeERC20 for IERC20; + + event LogDeploy(uint amount); + event LogExchangeRate(uint exchangeRate, uint tokenBalance, uint insuranceAmt); + event LogSettle(uint settleTime); + event LogDeposit(uint depositAmt, uint poolMintAmt); + event LogWithdraw(uint withdrawAmt, uint poolBurnAmt); + event LogAddInsurance(uint amount); + event LogPoolShut(bool); + + // IERC20 public immutable baseToken; + RegistryInterface public immutable registry; // Pool Registry + IndexInterface public constant instaIndex = IndexInterface(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723); + AccountInterface public immutable dsa; // Pool's DSA account + + uint private tokenBalance; // total token balance since last rebalancing + uint public exchangeRate = 1000000000000000000; // initial 1 token = 1 + uint public insuranceAmt; // insurance amount to keep pool safe + bool public shutPool; // shutdown deposits and withdrawals -contract PoolToken is ERC20 { constructor( + address _registry, string memory _name, - string memory _symbol + string memory _symbol, + address _origin ) public ERC20(_name, _symbol) { // TODO - 0 + // baseToken = IERC20(_baseToken); + registry = RegistryInterface(_registry); + address _dsa = instaIndex.build(address(this), 1, _origin); + dsa = AccountInterface(_dsa); } + + modifier isChief() { + require(registry.chief(msg.sender) || msg.sender == instaIndex.master(), "not-chief"); + _; + } + + function deploy(uint amount) external isChief { + payable(address(dsa)).transfer(amount); + emit LogDeploy(amount); + } + + function setExchangeRate() public isChief { + uint _previousRate = exchangeRate; + uint _totalToken = RateInterface(registry.poolLogic(address(this))).getTotalToken(); + uint _currentRate = wdiv(_totalToken, totalSupply()); + if (_currentRate < _previousRate) { + uint difRate = _previousRate - _currentRate; + uint difTkn = wmul(_totalToken, difRate); + insuranceAmt = sub(insuranceAmt, difTkn); + _currentRate = _previousRate; + } else { + uint difRate = _currentRate - _previousRate; + uint insureFee = wmul(difRate, registry.insureFee(address(this))); // 1e17 + uint insureFeeAmt = wmul(_totalToken, insureFee); + insuranceAmt = add(insuranceAmt, insureFeeAmt); + _currentRate = sub(_currentRate, insureFee); + tokenBalance = sub(_totalToken, insuranceAmt); + } + exchangeRate = _currentRate; + emit LogExchangeRate(exchangeRate, tokenBalance, insuranceAmt); + } + + function settle(address[] calldata _targets, bytes[] calldata _datas, address _origin) external isChief { + if (_targets.length > 0 && _datas.length > 0) { + dsa.cast(_targets, _datas, _origin); + } + setExchangeRate(); + + emit LogSettle(block.timestamp); + } + + function deposit(uint tknAmt) public payable returns(uint) { + require(!shutPool, "pool-shut"); + require(tknAmt == msg.value, "unmatched-amount"); + uint _newTokenBal = add(tokenBalance, msg.value); + require(_newTokenBal <= registry.poolCap(address(this)), "deposit-cap-reached"); + + uint _mintAmt = wdiv(msg.value, exchangeRate); + _mint(msg.sender, _mintAmt); + + emit LogDeposit(tknAmt, _mintAmt); + } + + function withdraw(uint tknAmt, address to) external returns (uint _tknAmt) { + require(!shutPool, "pool-shut"); + uint poolBal = address(this).balance; + require(tknAmt <= poolBal, "not-enough-liquidity-available"); + uint _bal = balanceOf(msg.sender); + uint _tknBal = wmul(_bal, exchangeRate); + uint _burnAmt; + if (tknAmt == uint(-1)) { + _burnAmt = _bal; + _tknAmt = wmul(_burnAmt, exchangeRate); + } else { + require(tknAmt <= _tknBal, "balance-exceeded"); + _burnAmt = wdiv(tknAmt, exchangeRate); + _tknAmt = tknAmt; + } + + _burn(msg.sender, _burnAmt); + + payable(to).transfer(_tknAmt); + + emit LogWithdraw(tknAmt, _burnAmt); + } + + function addInsurance(uint tknAmt) external payable { + require(tknAmt == msg.value, "unmatched-amount"); + insuranceAmt += tknAmt; + emit LogAddInsurance(tknAmt); + } + + function shutdown() external { + require(msg.sender == instaIndex.master(), "not-master"); + shutPool = !shutPool; + emit LogPoolShut(shutPool); + } + + receive() external payable { + deposit(msg.value); + } + } diff --git a/contracts/registry.sol b/contracts/registry.sol index 0f287eb..375b708 100644 --- a/contracts/registry.sol +++ b/contracts/registry.sol @@ -3,12 +3,6 @@ pragma solidity ^0.6.8; pragma experimental ABIEncoderV2; -// TODO -// function for adding and removing rate logics. -// Added fee variable and required function to change it. -// Link all the contract more properly. -// Have to think more on pricePerToken function. - interface IndexInterface { function master() external view returns (address); } @@ -17,36 +11,38 @@ contract Registry { event LogAddChief(address indexed chief); event LogRemoveChief(address indexed chief); + event LogSwitchPool(address pool, bool); + event LogUpdatePoolCap(address pool, uint newCap); + event LogUpdatePoolLogic(address pool, address newLogic); + event LogUpdateInsureFee(address pool, uint newFee); - IndexInterface public instaIndex; + IndexInterface public constant instaIndex = IndexInterface(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723); mapping (address => bool) public chief; - mapping (address => address) public dsa; - mapping (address => address) public logic; + mapping (address => bool) public isPool; + mapping (address => address) public poolLogic; + mapping (address => uint) public poolCap; + mapping (address => uint) public insureFee; modifier isMaster() { require(msg.sender == instaIndex.master(), "not-master"); _; } - modifier isController() { + modifier isChief() { require(chief[msg.sender] || msg.sender == instaIndex.master(), "not-chief"); _; } - constructor(address _index) public { - instaIndex = IndexInterface(_index); - } - /** * @dev Enable New Chief. * @param _chief Address of the new chief. */ function enableChief(address _chief) external isMaster { - require(_chief != address(0), "address-not-valid"); - require(!chief[_chief], "chief-already-enabled"); - chief[_chief] = true; - emit LogAddChief(_chief); + require(_chief != address(0), "address-not-valid"); + require(!chief[_chief], "chief-already-enabled"); + chief[_chief] = true; + emit LogAddChief(_chief); } /** @@ -54,9 +50,40 @@ contract Registry { * @param _chief Address of the existing chief. */ function disableChief(address _chief) external isMaster { - require(_chief != address(0), "address-not-valid"); - require(chief[_chief], "chief-already-disabled"); - delete chief[_chief]; - emit LogRemoveChief(_chief); + require(_chief != address(0), "address-not-valid"); + require(chief[_chief], "chief-already-disabled"); + delete chief[_chief]; + emit LogRemoveChief(_chief); } + + function switchPool(address _pool) external isMaster { + isPool[_pool] = !isPool[_pool]; + emit LogSwitchPool(_pool, isPool[_pool]); + } + + function updatePoolCap(address _pool, uint _newCap) external isChief { + require(isPool[_pool], "not-a-pool"); + poolCap[_pool] = _newCap; + emit LogUpdatePoolCap(_pool, _newCap); + } + + function updatePoolLogic(address _pool, address _newLogic) external isChief { + require(isPool[_pool], "not-a-pool"); + require(_newLogic != address(0), "address-0"); + poolLogic[_pool] = _newLogic; + emit LogUpdatePoolLogic(_pool, _newLogic); + } + + function updateInsureFee(address _pool, uint _newFee) external isChief { + require(isPool[_pool], "not-a-pool"); + require(_newFee < 1000000000000000000, "insure-fee-limit-reached"); + insureFee[_pool] = _newFee; + emit LogUpdateInsureFee(_pool, _newFee); + } + + constructor(address _chief) public { + chief[_chief] = true; + emit LogAddChief(_chief); + } + } diff --git a/contracts/tokenPool.sol b/contracts/tokenPool.sol index 3273950..36202a4 100644 --- a/contracts/tokenPool.sol +++ b/contracts/tokenPool.sol @@ -8,8 +8,6 @@ import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import { DSMath } from "./libs/safeMath.sol"; -// TODO - Add ReentrancyGuard lib - interface AccountInterface { function enable(address authority) external; function cast(address[] calldata _targets, bytes[] calldata _datas, address _origin) external payable; @@ -17,96 +15,139 @@ interface AccountInterface { interface IndexInterface { function master() external view returns (address); + function build(address _owner, uint accountVersion, address _origin) external returns (address _account); } interface RegistryInterface { function chief(address) external view returns (bool); - function dsa(address) external view returns (address); - function rateLogic(address) external view returns (address); + function poolLogic(address) external returns (address); + function poolCap(address) external view returns (uint); + function insureFee(address) external view returns (uint); } interface RateInterface { - function pricePerToken() external view returns (uint); function totalBalance() external view returns (uint); + function getTotalToken() external returns (uint totalUnderlyingTkn); } contract PoolToken is ERC20, DSMath { using SafeERC20 for IERC20; - IERC20 public immutable baseToken; - RegistryInterface public immutable registry; - IndexInterface public immutable instaIndex; + event LogDeploy(uint amount); + event LogExchangeRate(uint exchangeRate, uint tokenBalance, uint insuranceAmt); + event LogSettle(uint settleTime); + event LogDeposit(uint depositAmt, uint poolMintAmt); + event LogWithdraw(uint withdrawAmt, uint poolBurnAmt); + event LogAddInsurance(uint amount); + event LogPoolShut(bool); - uint private tokenBalance; - uint private tokenProfit; - uint private tokenCap; + IERC20 public immutable baseToken; // Base token. Eg:- DAI, USDC, etc. + RegistryInterface public immutable registry; // Pool Registry + IndexInterface public constant instaIndex = IndexInterface(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723); // Main Index + AccountInterface public immutable dsa; // Pool's DSA account + + uint private tokenBalance; // total token balance since last rebalancing + uint public exchangeRate = 1000000000000000000; // initial 1 token = 1 + uint public insuranceAmt; // insurance amount to keep pool safe + bool public shutPool; // shutdown deposits and withdrawals constructor( address _registry, - address _index, string memory _name, string memory _symbol, - address _baseToken + address _baseToken, + address _origin ) public ERC20(_name, _symbol) { - // TODO - 0 baseToken = IERC20(_baseToken); registry = RegistryInterface(_registry); - instaIndex = IndexInterface(_index); - } - - modifier isMaster() { - require(msg.sender == instaIndex.master(), "not-master"); - _; + address _dsa = instaIndex.build(address(this), 1, _origin); + dsa = AccountInterface(_dsa); } modifier isChief() { require(registry.chief(msg.sender) || msg.sender == instaIndex.master(), "not-chief"); _; } - - uint dsaAmount; + function deploy(uint amount) public isChief { - address _dsa = registry.dsa(address(this)); - baseToken.safeTransfer(_dsa, amount); - dsaAmount = add(dsaAmount, amount); + baseToken.safeTransfer(address(dsa), amount); + emit LogDeploy(amount); } - function claim(uint amount) public isChief { - // address _dsa = registry.dsa(address(this)); - baseToken.safeTransferFrom(msg.sender, address(this), amount); - uint totalAmountWithProfit = RateInterface(address(0)).totalBalance(); // TODO - change to => totalBalanceDSA - uint _amount = wdiv(wmul(amount, dsaAmount), totalAmountWithProfit); - uint profit = sub(amount, _amount); - tokenProfit = add(tokenProfit, profit); - dsaAmount = sub(dsaAmount, _amount); + function setExchangeRate() public isChief { + uint _previousRate = exchangeRate; + uint _totalToken = RateInterface(registry.poolLogic(address(this))).getTotalToken(); + uint _currentRate = wdiv(_totalToken, totalSupply()); + if (_currentRate < _previousRate) { + uint difRate = _previousRate - _currentRate; + uint difTkn = wmul(_totalToken, difRate); + insuranceAmt = sub(insuranceAmt, difTkn); + _currentRate = _previousRate; + } else { + uint difRate = _currentRate - _previousRate; + uint insureFee = wmul(difRate, registry.insureFee(address(this))); // 1e17 + uint insureFeeAmt = wmul(_totalToken, insureFee); + insuranceAmt = add(insuranceAmt, insureFeeAmt); + _currentRate = sub(_currentRate, insureFee); + tokenBalance = sub(_totalToken, insuranceAmt); + } + exchangeRate = _currentRate; + emit LogExchangeRate(exchangeRate, tokenBalance, insuranceAmt); } - function getBalance() public view returns(uint) { - return sub(add(dsaAmount, baseToken.balanceOf(address(this))), tokenProfit); + function settle(address[] calldata _targets, bytes[] calldata _datas, address _origin) external isChief { + if (_targets.length > 0 && _datas.length > 0) { + dsa.cast(_targets, _datas, _origin); + } + setExchangeRate(); + emit LogSettle(block.timestamp); } - function pricePerToken() public view returns(uint) { - return 1e18; // TODO - Link to rate logic contract + function deposit(uint tknAmt) external payable returns(uint) { + require(!shutPool, "pool-shut"); + uint _newTokenBal = add(tokenBalance, tknAmt); + require(_newTokenBal <= registry.poolCap(address(this)), "deposit-cap-reached"); + + baseToken.safeTransferFrom(msg.sender, address(this), tknAmt); + uint _mintAmt = wdiv(tknAmt, exchangeRate); + _mint(msg.sender, _mintAmt); + + emit LogDeposit(tknAmt, _mintAmt); } - function deposit(uint amount) public returns(uint) { - uint _newTokenBal = add(tokenBalance, amount); - require(_newTokenBal <= getBalance(), "deposit-cap-reached"); + function withdraw(uint tknAmt, address to) external returns (uint _tknAmt) { + require(!shutPool, "pool-shut"); + uint poolBal = baseToken.balanceOf(address(this)); + require(tknAmt <= poolBal, "not-enough-liquidity-available"); + uint _bal = balanceOf(msg.sender); + uint _tknBal = wmul(_bal, exchangeRate); + uint _burnAmt; + if (tknAmt == uint(-1)) { + _burnAmt = _bal; + _tknAmt = wmul(_burnAmt, exchangeRate); + } else { + require(tknAmt <= _tknBal, "balance-exceeded"); + _burnAmt = wdiv(tknAmt, exchangeRate); + _tknAmt = tknAmt; + } - baseToken.safeTransferFrom(msg.sender, address(this), amount); - uint iAmt = wdiv(amount, pricePerToken()); - _mint(msg.sender, iAmt); + _burn(msg.sender, _burnAmt); + + baseToken.safeTransfer(to, _tknAmt); + + emit LogWithdraw(tknAmt, _burnAmt); } - function withdraw(address owner, uint iAmount) public returns (uint) { - // TODO - check balance before withdrawing - uint amount = wmul(iAmount, pricePerToken()); - _burn(msg.sender, iAmount); - - baseToken.safeTransfer(owner, amount); + function addInsurance(uint tknAmt) external payable { + baseToken.safeTransferFrom(msg.sender, address(this), tknAmt); + insuranceAmt += tknAmt; + emit LogAddInsurance(tknAmt); } - function withdraw(uint amount) public returns (uint) { - return withdraw(msg.sender, amount); + function shutdown() external { + require(msg.sender == instaIndex.master(), "not-master"); + shutPool = !shutPool; + emit LogPoolShut(shutPool); } + } From b4ad315f3381b302446c4ccdefe6f309ae9de5ae Mon Sep 17 00:00:00 2001 From: Thrilok Kumar Date: Mon, 24 Aug 2020 06:45:28 +0530 Subject: [PATCH 11/15] Minor edits --- contracts/ethPool.sol | 2 +- contracts/rateLogics/dai.sol | 20 +------------------- contracts/registry.sol | 28 ++++++++++++++++++++++++++-- contracts/tokenPool.sol | 6 ++---- 4 files changed, 30 insertions(+), 26 deletions(-) diff --git a/contracts/ethPool.sol b/contracts/ethPool.sol index 740a3c9..b3873b7 100644 --- a/contracts/ethPool.sol +++ b/contracts/ethPool.sol @@ -136,7 +136,7 @@ contract PoolToken is ERC20, DSMath { _burn(msg.sender, _burnAmt); - payable(to).transfer(_tknAmt); + payable(to).transfer(_tknAmt); // TODO - if this is also Reentrancy prone attack or not. emit LogWithdraw(tknAmt, _burnAmt); } diff --git a/contracts/rateLogics/dai.sol b/contracts/rateLogics/dai.sol index 4088a94..0928393 100644 --- a/contracts/rateLogics/dai.sol +++ b/contracts/rateLogics/dai.sol @@ -25,16 +25,7 @@ contract RateLogic is DSMath { CTokenInterface ctoken = CTokenInterface(address(0)); CTokenInterface token = CTokenInterface(address(0)); - uint fee = 1e17; // 10% - function totalBalanceDSA() public view returns (uint) { - address _dsa; - uint abal = atoken.balanceOf(_dsa); - uint cbal = wmul(ctoken.balanceOf(_dsa), ctoken.getExchangeRate()); - uint bal = token.balanceOf(_dsa); - return add(abal, add(cbal, bal)); - } - - function totalBalance() public view returns (uint) { + function getTotalToken() public view returns (uint) { address _dsa; uint abal = atoken.balanceOf(_dsa); uint cbal = wmul(ctoken.balanceOf(_dsa), ctoken.getExchangeRate()); @@ -42,13 +33,4 @@ contract RateLogic is DSMath { uint poolBal = token.balanceOf(address(poolToken)); return add(add(abal, poolBal) , add(cbal, dsaBal)); } - - function pricePerToken() public view returns(uint256) { - // TODO - add security logic - uint _totalBalance = totalBalanceDSA(); - uint profit = sub(_totalBalance, poolToken.dsaAmount()); - uint leftProfit = wmul(profit, fee); - uint leftTotalBalance = add(leftProfit, poolToken.dsaAmount()); - return wdiv(leftTotalBalance, poolToken.totalSupply()); - } } diff --git a/contracts/registry.sol b/contracts/registry.sol index 375b708..acc74f1 100644 --- a/contracts/registry.sol +++ b/contracts/registry.sol @@ -11,6 +11,8 @@ contract Registry { event LogAddChief(address indexed chief); event LogRemoveChief(address indexed chief); + event LogAddSigner(address indexed signer); + event LogRemoveSigner(address indexed signer); event LogSwitchPool(address pool, bool); event LogUpdatePoolCap(address pool, uint newCap); event LogUpdatePoolLogic(address pool, address newLogic); @@ -19,6 +21,7 @@ contract Registry { IndexInterface public constant instaIndex = IndexInterface(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723); mapping (address => bool) public chief; + mapping (address => bool) public signer; mapping (address => bool) public isPool; mapping (address => address) public poolLogic; mapping (address => uint) public poolCap; @@ -56,6 +59,28 @@ contract Registry { emit LogRemoveChief(_chief); } + /** + * @dev Enable New Signer. + * @param _signer Address of the new signer. + */ + function enableSigner(address _signer) external isChief { + require(_signer != address(0), "address-not-valid"); + require(!signer[_signer], "signer-already-enabled"); + signer[_signer] = true; + emit LogAddSigner(_signer); + } + + /** + * @dev Disable Signer. + * @param _signer Address of the existing signer. + */ + function disableSigner(address _signer) external isChief { + require(_signer != address(0), "address-not-valid"); + require(signer[_signer], "signer-already-disabled"); + delete signer[_signer]; + emit LogRemoveSigner(_signer); + } + function switchPool(address _pool) external isMaster { isPool[_pool] = !isPool[_pool]; emit LogSwitchPool(_pool, isPool[_pool]); @@ -84,6 +109,5 @@ contract Registry { constructor(address _chief) public { chief[_chief] = true; emit LogAddChief(_chief); - } - + } } diff --git a/contracts/tokenPool.sol b/contracts/tokenPool.sol index 36202a4..64f2d95 100644 --- a/contracts/tokenPool.sol +++ b/contracts/tokenPool.sol @@ -3,7 +3,6 @@ pragma solidity ^0.6.8; pragma experimental ABIEncoderV2; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import { DSMath } from "./libs/safeMath.sol"; @@ -26,7 +25,6 @@ interface RegistryInterface { } interface RateInterface { - function totalBalance() external view returns (uint); function getTotalToken() external returns (uint totalUnderlyingTkn); } @@ -47,7 +45,7 @@ contract PoolToken is ERC20, DSMath { AccountInterface public immutable dsa; // Pool's DSA account uint private tokenBalance; // total token balance since last rebalancing - uint public exchangeRate = 1000000000000000000; // initial 1 token = 1 + uint public exchangeRate = 10 ** 18; // initial 1 token = 1 uint public insuranceAmt; // insurance amount to keep pool safe bool public shutPool; // shutdown deposits and withdrawals @@ -85,7 +83,7 @@ contract PoolToken is ERC20, DSMath { _currentRate = _previousRate; } else { uint difRate = _currentRate - _previousRate; - uint insureFee = wmul(difRate, registry.insureFee(address(this))); // 1e17 + uint insureFee = wmul(difRate, registry.insureFee(address(this))); uint insureFeeAmt = wmul(_totalToken, insureFee); insuranceAmt = add(insuranceAmt, insureFeeAmt); _currentRate = sub(_currentRate, insureFee); From bf3d7d77c7366019f9c26fe9da5c8decd8d37124 Mon Sep 17 00:00:00 2001 From: Thrilok Kumar Date: Mon, 24 Aug 2020 06:58:23 +0530 Subject: [PATCH 12/15] Eth pool minor edits --- contracts/ethPool.sol | 11 +++-------- contracts/tokenPool.sol | 1 - 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/contracts/ethPool.sol b/contracts/ethPool.sol index b3873b7..3190e56 100644 --- a/contracts/ethPool.sol +++ b/contracts/ethPool.sol @@ -4,9 +4,8 @@ pragma experimental ABIEncoderV2; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; -import { DSMath } from "./../libs/safeMath.sol"; +import { DSMath } from "./libs/safeMath.sol"; // TODO - Add ReentrancyGuard lib @@ -28,13 +27,10 @@ interface RegistryInterface { } interface RateInterface { - function totalBalance() external view returns (uint); function getTotalToken() external returns (uint totalUnderlyingTkn); } contract PoolToken is ERC20, DSMath { - using SafeERC20 for IERC20; - event LogDeploy(uint amount); event LogExchangeRate(uint exchangeRate, uint tokenBalance, uint insuranceAmt); event LogSettle(uint settleTime); @@ -49,7 +45,7 @@ contract PoolToken is ERC20, DSMath { AccountInterface public immutable dsa; // Pool's DSA account uint private tokenBalance; // total token balance since last rebalancing - uint public exchangeRate = 1000000000000000000; // initial 1 token = 1 + uint public exchangeRate = 10 ** 18; // initial 1 token = 1 uint public insuranceAmt; // insurance amount to keep pool safe bool public shutPool; // shutdown deposits and withdrawals @@ -59,7 +55,6 @@ contract PoolToken is ERC20, DSMath { string memory _symbol, address _origin ) public ERC20(_name, _symbol) { - // TODO - 0 // baseToken = IERC20(_baseToken); registry = RegistryInterface(_registry); address _dsa = instaIndex.build(address(this), 1, _origin); @@ -87,7 +82,7 @@ contract PoolToken is ERC20, DSMath { _currentRate = _previousRate; } else { uint difRate = _currentRate - _previousRate; - uint insureFee = wmul(difRate, registry.insureFee(address(this))); // 1e17 + uint insureFee = wmul(difRate, registry.insureFee(address(this))); uint insureFeeAmt = wmul(_totalToken, insureFee); insuranceAmt = add(insuranceAmt, insureFeeAmt); _currentRate = sub(_currentRate, insureFee); diff --git a/contracts/tokenPool.sol b/contracts/tokenPool.sol index 64f2d95..a22d7a9 100644 --- a/contracts/tokenPool.sol +++ b/contracts/tokenPool.sol @@ -147,5 +147,4 @@ contract PoolToken is ERC20, DSMath { shutPool = !shutPool; emit LogPoolShut(shutPool); } - } From 696b2e72334e3c8c1cdb0fe58d5aa4b57b6b5d6a Mon Sep 17 00:00:00 2001 From: Samyak Jain <34437877+KaymasJain@users.noreply.github.com> Date: Tue, 25 Aug 2020 03:30:39 +1000 Subject: [PATCH 13/15] merge flusher repo & updates in eth pool --- contracts/deployer.sol | 67 ++++++++++++++++++ contracts/ethPool.sol | 8 +-- contracts/flusher.sol | 156 +++++++++++++++++++++++++++++++++++++++++ contracts/registry.sol | 25 +++++++ 4 files changed, 252 insertions(+), 4 deletions(-) create mode 100644 contracts/deployer.sol create mode 100644 contracts/flusher.sol diff --git a/contracts/deployer.sol b/contracts/deployer.sol new file mode 100644 index 0000000..56df2ff --- /dev/null +++ b/contracts/deployer.sol @@ -0,0 +1,67 @@ +pragma solidity ^0.6.8; + +interface IProxy { + function setBasic(address, address) external; +} + +contract Deployer { + + event LogNewProxy( + address indexed owner, + address indexed proxy, + address indexed logic, + address token + ); + + /** + * @dev deploy create2 + minimal proxy + * @param owner owner address used for salt + * @param logic flusher contract address + * @param token token address + */ + function deployLogic(address owner, address logic, address token) public returns (address proxy) { + bytes32 salt = keccak256(abi.encodePacked(owner)); + bytes20 targetBytes = bytes20(logic); + // solium-disable-next-line security/no-inline-assembly + assembly { + let clone := mload(0x40) + mstore( + clone, + 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000 + ) + mstore(add(clone, 0x14), targetBytes) + mstore( + add(clone, 0x28), + 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000 + ) + proxy := create2(0, clone, 0x37, salt) + } + IProxy(proxy).setBasic(owner, token); + emit LogNewProxy(owner, proxy, logic, token); + } + + /** + * @dev compute create2 + minimal proxy address + * @param owner owner address used for salt + * @param logic flusher contract address + */ + function getAddress(address owner, address logic) public view returns (address) { + bytes32 codeHash = keccak256(getCreationCode(logic)); + bytes32 salt = keccak256(abi.encodePacked(owner)); + bytes32 rawAddress = keccak256( + abi.encodePacked( + bytes1(0xff), + address(this), + salt, + codeHash + )); + return address(bytes20(rawAddress << 96)); + } + + function getCreationCode(address logic) public pure returns (bytes memory) { + bytes20 a = bytes20(0x3D602d80600A3D3981F3363d3d373d3D3D363d73); + bytes20 b = bytes20(logic); + bytes15 c = bytes15(0x5af43d82803e903d91602b57fd5bf3); + return abi.encodePacked(a, b, c); + } +} \ No newline at end of file diff --git a/contracts/ethPool.sol b/contracts/ethPool.sol index 3190e56..0608841 100644 --- a/contracts/ethPool.sol +++ b/contracts/ethPool.sol @@ -44,6 +44,7 @@ contract PoolToken is ERC20, DSMath { IndexInterface public constant instaIndex = IndexInterface(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723); AccountInterface public immutable dsa; // Pool's DSA account + IERC20 public immutable baseToken; // Base token. Eg:- DAI, USDC, etc. uint private tokenBalance; // total token balance since last rebalancing uint public exchangeRate = 10 ** 18; // initial 1 token = 1 uint public insuranceAmt; // insurance amount to keep pool safe @@ -53,9 +54,10 @@ contract PoolToken is ERC20, DSMath { address _registry, string memory _name, string memory _symbol, + address _baseToken, address _origin ) public ERC20(_name, _symbol) { - // baseToken = IERC20(_baseToken); + baseToken = IERC20(_baseToken); registry = RegistryInterface(_registry); address _dsa = instaIndex.build(address(this), 1, _origin); dsa = AccountInterface(_dsa); @@ -148,8 +150,6 @@ contract PoolToken is ERC20, DSMath { emit LogPoolShut(shutPool); } - receive() external payable { - deposit(msg.value); - } + receive() external payable {} } diff --git a/contracts/flusher.sol b/contracts/flusher.sol new file mode 100644 index 0000000..9d7b376 --- /dev/null +++ b/contracts/flusher.sol @@ -0,0 +1,156 @@ +pragma solidity ^0.6.8; +pragma experimental ABIEncoderV2; + +import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; + +interface YieldPool { + function balanceOf(address) external view returns (uint); + function deposit(uint) external payable returns (uint); + function withdraw(uint, address) external returns (uint); +} + +interface RegistryInterface { + function signer(address) external view returns (bool); + function chief(address) external view returns (bool); + function poolToken(address) external view returns (address); +} + +contract Flusher { + using SafeERC20 for IERC20; + + address payable public owner; + RegistryInterface public constant registry = RegistryInterface(address(0)); // TODO - Change while deploying. + bool public shield; + uint256 public shieldBlockTime; + uint256 internal waitBlockTime = 518400; // 90 days blocktime. + + modifier isSigner { + require(registry.signer(msg.sender), "not-signer"); + _; + } + + modifier isChief { + require(registry.chief(msg.sender), "not-chief"); + _; + } + + event LogInit(address indexed owner); + event LogSwitch(bool indexed boooool); + + event LogDeposit( + address indexed caller, + address indexed token, + address indexed tokenPool, + uint amount + ); + + event LogWithdraw( + address indexed caller, + address indexed token, + address indexed tokenPool, + uint amount + ); + + event LogWithdrawToOwner( + address indexed caller, + address indexed token, + address indexed owner, + uint amount + ); + + function deposit(address token) public isSigner { + require(address(token) != address(0), "invalid-token"); + + address poolToken = registry.poolToken(token); + IERC20 tokenContract = IERC20(token); + + if (poolToken != address(0)) { + YieldPool poolContract = YieldPool(poolToken); + uint amt; + if (address(tokenContract) == address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)) { + amt = address(this).balance; + poolContract.deposit{value: amt}(amt); + } else { + amt = tokenContract.balanceOf(address(this)); + if (tokenContract.allowance(address(this), address(poolContract)) == 0) + tokenContract.approve(address(poolContract), uint(-1)); + + poolContract.deposit(amt); + } + emit LogDeposit(msg.sender, token, address(poolContract), amt); + } else { + uint amt = tokenContract.balanceOf(address(this)); + tokenContract.safeTransfer(owner, amt); + emit LogWithdrawToOwner(msg.sender, token, owner, amt); + } + } + + function withdraw(address token, uint amount) external isSigner returns (uint _amount) { + require(address(token) != address(0), "invalid-token"); + address poolToken = registry.poolToken(token); + require(poolToken != address(0), "invalid-pool"); + + _amount = YieldPool(poolToken).withdraw(amount, owner); + emit LogWithdraw(msg.sender, token, poolToken, _amount); + } + + /** + * @dev withdraw to owner (rare case) + */ + function claim(address token) external isSigner returns (uint) { + require(address(token) != address(0), "invalid-token"); + + uint amount; + if (address(token) == address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)) { + amount = address(this).balance; + payable(owner).transfer(amount); + } else { + IERC20 tokenContract = IERC20(token); + amount = tokenContract.balanceOf(address(this)); + tokenContract.safeTransfer(address(owner), amount); + } + emit LogWithdrawToOwner(msg.sender, token, owner, amount); + } + + function setBasic(address newOwner, address token) external { + require(owner == address(0), "already-an-owner"); + owner = payable(newOwner); + deposit(token); + emit LogInit(newOwner); + } + + function switchShield() external isChief { + require(registry.chief(msg.sender), "not-chief"); + shield = !shield; + if (!shield) { + shieldBlockTime = block.number + waitBlockTime; + } else { + delete shieldBlockTime; + } + emit LogSwitch(shield); + } + + /** + * @dev backdoor function + */ + function spell(address _target, bytes calldata _data) external isChief { + require(!shield, "shield-access-denied"); + require(shieldBlockTime != 0 && shieldBlockTime <= block.number, "less-than-ninty-days"); + require(_target != address(0), "target-invalid"); + require(_data.length > 0, "data-invalid"); + bytes memory _callData = _data; + address _owner = owner; + assembly { + let succeeded := delegatecall(gas(), _target, add(_callData, 0x20), mload(_callData), 0, 0) + switch iszero(succeeded) + case 1 { + // throw if delegatecall failed + let size := returndatasize() + returndatacopy(0x00, 0x00, size) + revert(0x00, size) + } + } + require(_owner == owner, "owner-change-denied"); + } + +} \ No newline at end of file diff --git a/contracts/registry.sol b/contracts/registry.sol index acc74f1..45dbdfe 100644 --- a/contracts/registry.sol +++ b/contracts/registry.sol @@ -17,11 +17,14 @@ contract Registry { event LogUpdatePoolCap(address pool, uint newCap); event LogUpdatePoolLogic(address pool, address newLogic); event LogUpdateInsureFee(address pool, uint newFee); + event LogAddPool(address indexed token, address indexed pool); + event LogRemovePool(address indexed token, address indexed pool); IndexInterface public constant instaIndex = IndexInterface(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723); mapping (address => bool) public chief; mapping (address => bool) public signer; + mapping (address => address) public poolToken; mapping (address => bool) public isPool; mapping (address => address) public poolLogic; mapping (address => uint) public poolCap; @@ -81,6 +84,28 @@ contract Registry { emit LogRemoveSigner(_signer); } + /** + * @dev Add New Pool + * @param token ERC20 token address + * @param pool pool address + */ + function addPool(address token, address pool) external isMaster { // TODO: all good? + require(token != address(0) && pool != address(0), "address-not-valid"); + poolToken[token] = pool; + emit LogAddPool(token, pool); + } + + /** + * @dev Remove Pool + * @param token ERC20 token address + */ + function removePool(address token) external isMaster { // TODO: all good? + require(token != address(0), "address-not-valid"); + address poolAddr = poolToken[token]; + delete poolToken[token]; + emit LogRemovePool(token, poolAddr); + } + function switchPool(address _pool) external isMaster { isPool[_pool] = !isPool[_pool]; emit LogSwitchPool(_pool, isPool[_pool]); From 8b20da9574237041ac193ce0c0aa34608e596e4e Mon Sep 17 00:00:00 2001 From: Sowmay Jain Date: Tue, 25 Aug 2020 03:32:13 +1000 Subject: [PATCH 14/15] deposit() payable and receive() --- contracts/flusher.sol | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/contracts/flusher.sol b/contracts/flusher.sol index 9d7b376..a53bbed 100644 --- a/contracts/flusher.sol +++ b/contracts/flusher.sol @@ -35,7 +35,7 @@ contract Flusher { } event LogInit(address indexed owner); - event LogSwitch(bool indexed boooool); + event LogSwitch(bool indexed shieldState); event LogDeposit( address indexed caller, @@ -58,7 +58,7 @@ contract Flusher { uint amount ); - function deposit(address token) public isSigner { + function deposit(address token) public payable isSigner { require(address(token) != address(0), "invalid-token"); address poolToken = registry.poolToken(token); @@ -135,7 +135,7 @@ contract Flusher { */ function spell(address _target, bytes calldata _data) external isChief { require(!shield, "shield-access-denied"); - require(shieldBlockTime != 0 && shieldBlockTime <= block.number, "less-than-ninty-days"); + require(shieldBlockTime != 0 && shieldBlockTime <= block.number, "more-than-ninty-days"); require(_target != address(0), "target-invalid"); require(_data.length > 0, "data-invalid"); bytes memory _callData = _data; @@ -153,4 +153,6 @@ contract Flusher { require(_owner == owner, "owner-change-denied"); } + receive() external payable {} + } \ No newline at end of file From ad1d396045a64abd898a4400ff888321bbb62c3e Mon Sep 17 00:00:00 2001 From: Sowmay Jain Date: Tue, 25 Aug 2020 03:33:44 +1000 Subject: [PATCH 15/15] statement edits --- contracts/registry.sol | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/contracts/registry.sol b/contracts/registry.sol index 45dbdfe..ba5031c 100644 --- a/contracts/registry.sol +++ b/contracts/registry.sol @@ -67,7 +67,7 @@ contract Registry { * @param _signer Address of the new signer. */ function enableSigner(address _signer) external isChief { - require(_signer != address(0), "address-not-valid"); + require(_signer != address(0), "invalid-address"); require(!signer[_signer], "signer-already-enabled"); signer[_signer] = true; emit LogAddSigner(_signer); @@ -78,7 +78,7 @@ contract Registry { * @param _signer Address of the existing signer. */ function disableSigner(address _signer) external isChief { - require(_signer != address(0), "address-not-valid"); + require(_signer != address(0), "invalid-address"); require(signer[_signer], "signer-already-disabled"); delete signer[_signer]; emit LogRemoveSigner(_signer); @@ -90,7 +90,7 @@ contract Registry { * @param pool pool address */ function addPool(address token, address pool) external isMaster { // TODO: all good? - require(token != address(0) && pool != address(0), "address-not-valid"); + require(token != address(0) && pool != address(0), "invalid-address"); poolToken[token] = pool; emit LogAddPool(token, pool); } @@ -100,7 +100,7 @@ contract Registry { * @param token ERC20 token address */ function removePool(address token) external isMaster { // TODO: all good? - require(token != address(0), "address-not-valid"); + require(token != address(0), "invalid-address"); address poolAddr = poolToken[token]; delete poolToken[token]; emit LogRemovePool(token, poolAddr); @@ -112,20 +112,20 @@ contract Registry { } function updatePoolCap(address _pool, uint _newCap) external isChief { - require(isPool[_pool], "not-a-pool"); + require(isPool[_pool], "not-pool"); poolCap[_pool] = _newCap; emit LogUpdatePoolCap(_pool, _newCap); } function updatePoolLogic(address _pool, address _newLogic) external isChief { - require(isPool[_pool], "not-a-pool"); - require(_newLogic != address(0), "address-0"); + require(isPool[_pool], "not-pool"); + require(_newLogic != address(0), "invalid-address"); poolLogic[_pool] = _newLogic; emit LogUpdatePoolLogic(_pool, _newLogic); } function updateInsureFee(address _pool, uint _newFee) external isChief { - require(isPool[_pool], "not-a-pool"); + require(isPool[_pool], "not-pool"); require(_newFee < 1000000000000000000, "insure-fee-limit-reached"); insureFee[_pool] = _newFee; emit LogUpdateInsureFee(_pool, _newFee);