diff --git a/contracts/pools/erc20.sol b/contracts/pools/erc20.sol index 32a98b0..89a4520 100644 --- a/contracts/pools/erc20.sol +++ b/contracts/pools/erc20.sol @@ -8,11 +8,6 @@ import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; import { DSMath } from "../libs/safeMath.sol"; -interface AccountInterface { - function isAuth(address) external view returns(bool); - 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); @@ -22,8 +17,7 @@ interface RegistryInterface { function chief(address) external view returns (bool); function poolLogic(address) external returns (address); function fee(address) external view returns (uint); - function withdrawalFee(address) external view returns (uint); - function isDsa(address, address) external view returns (bool); + function poolCap(address) external view returns (uint); function checkSettleLogics(address, address[] calldata) external view returns (bool); } @@ -32,209 +26,168 @@ interface RateInterface { } contract PoolToken is ReentrancyGuard, DSMath, ERC20Pausable { - using SafeERC20 for IERC20; + using SafeERC20 for IERC20; - event LogDeploy(address indexed dsa, address token, uint amount); - event LogExchangeRate(uint exchangeRate, uint tokenBalance, uint insuranceAmt); - event LogSettle(uint settleBlock); - event LogDeposit(address indexed user, uint depositAmt, uint poolMintAmt); - event LogWithdraw(address indexed user, uint withdrawAmt, uint poolBurnAmt, uint feeAmt); - event LogAddFee(uint amount); - event LogWithdrawFee(uint amount); - event LogPausePool(bool); + event LogDeploy(address indexed dsa, address token, uint amount); + event LogExchangeRate(uint exchangeRate, uint tokenBalance, uint insuranceAmt); + event LogSettle(uint settleBlock); + event LogDeposit(address indexed user, uint depositAmt, uint poolMintAmt); + event LogWithdraw(address indexed user, uint withdrawAmt, uint poolBurnAmt); + event LogAddFee(uint amount); + event LogWithdrawFee(uint amount); + event LogPausePool(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 + IERC20 public immutable baseToken; // Base token. Eg:- DAI, USDC, etc. + RegistryInterface public immutable registry; // Pool Registry + IndexInterface public constant instaIndex = IndexInterface(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723); // Main Index - uint private tokenBalance; // total token balance - uint public exchangeRate; // initial 1 token = 1 - uint public feeAmt; // fee collected on profits + uint public exchangeRate; // initial 1 token = 1 + uint public feeAmt; // fee collected on profits - constructor( - address _registry, - string memory _name, - string memory _symbol, - address _baseToken - ) public ERC20(_name, _symbol) { - baseToken = IERC20(_baseToken); - registry = RegistryInterface(_registry); - exchangeRate = 10 ** uint(36 - ERC20(_baseToken).decimals()); - } + constructor( + address _registry, + string memory _name, + string memory _symbol, + address _baseToken + ) public ERC20(_name, _symbol) { + baseToken = IERC20(_baseToken); + registry = RegistryInterface(_registry); + exchangeRate = 10 ** uint(36 - ERC20(_baseToken).decimals()); + } - modifier isChief() { - require(registry.chief(msg.sender) || msg.sender == instaIndex.master() || msg.sender == address(this), "not-chief"); - _; - } + modifier isChief() { + require(registry.chief(msg.sender) || msg.sender == instaIndex.master(), "not-chief"); + _; + } - /** - * @dev Deploy assets to DSA. - * @param _dsa DSA address - * @param token token address - * @param amount token amount + /** + * @dev get pool token rate + * @param tokenAmt total token amount */ - function deploy(address _dsa, address token, uint amount) public isChief { - require(registry.isDsa(address(this), _dsa), "not-autheticated-dsa"); - require(AccountInterface(_dsa).isAuth(address(this)), "token-pool-not-auth"); - if (token == address(0)) { // pool base token - baseToken.safeTransfer(_dsa, amount); - } else if (token == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE){ // non-pool ethereum - payable(_dsa).transfer(amount); - } else { // non-pool other tokens - IERC20(token).safeTransfer(_dsa, amount); - } - emit LogDeploy(_dsa, token, amount); - } + function getCurrentRate(uint tokenAmt) internal view returns (uint) { + return wdiv(totalSupply(), tokenAmt); + } - /** - * @dev get pool token rate - * @param tokenAmt total token amount - */ - function getCurrentRate(uint tokenAmt) public view returns (uint) { - return wdiv(totalSupply(), tokenAmt); - } - - /** - * @dev sets exchange rates - */ - function setExchangeRate() public isChief { - uint _previousRate = exchangeRate; - uint _totalToken = RateInterface(registry.poolLogic(address(this))).getTotalToken(); - _totalToken = sub(_totalToken, feeAmt); - uint _currentRate = getCurrentRate(_totalToken); - require(_currentRate != 0, "current-rate-is-zero"); - if (_currentRate > _previousRate) { // loss => deduct partially/fully from insurance amount - _currentRate = _previousRate; - } else { // profit => add to insurance amount - uint _newFee = wmul(sub(_totalToken, tokenBalance), registry.fee(address(this))); - feeAmt = add(feeAmt, _newFee); - tokenBalance = sub(_totalToken, _newFee); - _currentRate = getCurrentRate(tokenBalance); - } - exchangeRate = _currentRate; - emit LogExchangeRate(exchangeRate, tokenBalance, feeAmt); - } - - /** - * @dev Delegate the calls to Connector And this function is ran by cast(). - * @param _target Target to of Connector. - * @param _data CallData of function in Connector. + /** + * @dev sets exchange rates */ - function spell(address _target, bytes memory _data) internal { - require(_target != address(0), "target-invalid"); - assembly { - let succeeded := delegatecall(gas(), _target, add(_data, 0x20), mload(_data), 0, 0) - - switch iszero(succeeded) - case 1 { - // throw if delegatecall failed - let size := returndatasize() - returndatacopy(0x00, 0x00, size) - revert(0x00, size) - } - } + function setExchangeRate() public { + require(msg.sender == address(this), "not-pool-address"); + uint _previousRate = exchangeRate; + uint _totalToken = RateInterface(registry.poolLogic(address(this))).getTotalToken(); + _totalToken = sub(_totalToken, feeAmt); + uint _currentRate = getCurrentRate(_totalToken); + uint _tokenBal; + require(_currentRate != 0, "current-rate-is-zero"); + if (_currentRate > _previousRate) { // loss => deduct partially/fully from insurance amount + _currentRate = _previousRate; + } else { // profit => add to insurance amount + uint _newFee = wmul(sub(_totalToken, _tokenBal), registry.fee(address(this))); + feeAmt = add(feeAmt, _newFee); + _tokenBal = sub(_totalToken, _newFee); + _currentRate = getCurrentRate(_tokenBal); } + exchangeRate = _currentRate; + emit LogExchangeRate(exchangeRate, _tokenBal, feeAmt); + } - /** - * @dev Settle the assets on dsa and update exchange rate - * @param _targets array of connector's address - * @param _data array of connector's function calldata - */ - function settle(address[] calldata _targets, bytes[] calldata _data) external isChief { - require(_targets.length == _data.length , "array-length-invalid"); - require(registry.checkSettleLogics(address(this), _targets), "not-logic"); - for (uint i = 0; i < _targets.length; i++) { - spell(_targets[i], _data[i]); - } - setExchangeRate(); - emit LogSettle(block.number); + /** + * @dev Delegate the calls to Connector And this function is ran by cast(). + * @param _target Target to of Connector. + * @param _data CallData of function in Connector. + */ + function spell(address _target, bytes memory _data) internal { + require(_target != address(0), "target-invalid"); + assembly { + let succeeded := delegatecall(gas(), _target, add(_data, 0x20), mload(_data), 0, 0) + + switch iszero(succeeded) + case 1 { + // throw if delegatecall failed + let size := returndatasize() + returndatacopy(0x00, 0x00, size) + revert(0x00, size) + } } + } - /** - * @dev Deposit token. - * @param tknAmt token amount - * @return _mintAmt amount of wrap token minted - */ - function deposit(uint tknAmt) external whenNotPaused payable returns (uint _mintAmt) { - require(msg.value == 0, "non-eth-pool"); - tokenBalance = add(tokenBalance, tknAmt); - - baseToken.safeTransferFrom(msg.sender, address(this), tknAmt); - _mintAmt = wmul(tknAmt, exchangeRate); - _mint(msg.sender, _mintAmt); - - emit LogDeposit(msg.sender, tknAmt, _mintAmt); + /** + * @dev Settle the assets on dsa and update exchange rate + * @param _targets array of connector's address + * @param _data array of connector's function calldata + */ + function settle(address[] calldata _targets, bytes[] calldata _data) external isChief { + require(_targets.length == _data.length , "array-length-invalid"); + require(registry.checkSettleLogics(address(this), _targets), "not-logic"); + for (uint i = 0; i < _targets.length; i++) { + spell(_targets[i], _data[i]); } + emit LogSettle(block.number); + } - /** - * @dev Withdraw tokens. - * @param tknAmt token amount - * @param to withdraw tokens to address - * @return _tknAmt amount of token withdrawn - */ - function withdraw(uint tknAmt, address to) external nonReentrant whenNotPaused returns (uint _tknAmt) { - uint poolBal = baseToken.balanceOf(address(this)); - require(to != address(0), "to-address-not-vaild"); - uint _bal = balanceOf(msg.sender); - uint _tknBal = wdiv(_bal, exchangeRate); - uint _burnAmt; - if (tknAmt >= _tknBal) { - _burnAmt = _bal; - _tknAmt = _tknBal; - } else { - _burnAmt = wmul(tknAmt, exchangeRate); - _tknAmt = tknAmt; - } - require(_tknAmt <= poolBal, "not-enough-liquidity-available"); + /** + * @dev Deposit token. + * @param tknAmt token amount + * @return _mintAmt amount of wrap token minted + */ + function deposit(uint tknAmt) external whenNotPaused payable returns (uint _mintAmt) { + require(msg.value == 0, "non-eth-pool"); + uint _tokenBal = wdiv(totalSupply(), exchangeRate); + uint _newTknBal = add(_tokenBal, tknAmt); + require(_newTknBal < registry.poolCap(address(this)), "unmatched-amount"); + baseToken.safeTransferFrom(msg.sender, address(this), tknAmt); + _mintAmt = wmul(tknAmt, exchangeRate); + _mint(msg.sender, _mintAmt); + emit LogDeposit(msg.sender, tknAmt, _mintAmt); + } - tokenBalance = sub(tokenBalance, _tknAmt); - - _burn(msg.sender, _burnAmt); - - uint _withdrawalFee = registry.withdrawalFee(address(this)); - uint _feeAmt; - if (_withdrawalFee > 0) { - _feeAmt = wmul(_tknAmt, _withdrawalFee); - feeAmt = add(feeAmt, _feeAmt); - _tknAmt = sub(_tknAmt, _feeAmt); - } - - baseToken.safeTransfer(to, _tknAmt); - - emit LogWithdraw(msg.sender, _tknAmt, _burnAmt, _feeAmt); + /** + * @dev Withdraw tokens. + * @param tknAmt token amount + * @param to withdraw tokens to address + * @return _tknAmt amount of token withdrawn + */ + function withdraw(uint tknAmt, address to) external nonReentrant whenNotPaused returns (uint _tknAmt) { + require(to != address(0), "to-address-not-vaild"); + uint _userBal = wdiv(balanceOf(msg.sender), exchangeRate); + uint _burnAmt; + if (tknAmt >= _userBal) { + _burnAmt = balanceOf(msg.sender); + _tknAmt = _userBal; + } else { + _burnAmt = wmul(tknAmt, exchangeRate); + _tknAmt = tknAmt; } + require(_tknAmt <= baseToken.balanceOf(address(this)), "not-enough-liquidity-available"); - /** - * @dev Add Insurance to the pool. - * @param tknAmt insurance token amount to add - */ - function addFee(uint tknAmt) external { - baseToken.safeTransferFrom(msg.sender, address(this), tknAmt); - feeAmt = add(feeAmt, tknAmt); - emit LogAddFee(tknAmt); - } + _burn(msg.sender, _burnAmt); + baseToken.safeTransfer(to, _tknAmt); - /** - * @dev Withdraw Insurance from the pool. - * @notice only master can call this function. - * @param tknAmt insurance token amount to remove - */ - function withdrawFee(uint tknAmt) external { - require(msg.sender == instaIndex.master(), "not-master"); - require(tknAmt <= feeAmt, "not-enough-insurance"); - baseToken.safeTransfer(msg.sender, tknAmt); - feeAmt = sub(feeAmt, tknAmt); - emit LogWithdrawFee(tknAmt); - } + emit LogWithdraw(msg.sender, _tknAmt, _burnAmt); + } - /** - * @dev Shut the pool. - * @notice only master can call this function. - */ - function shutdown() external { - require(msg.sender == instaIndex.master(), "not-master"); - paused() ? _unpause() : _pause(); - } + /** + * @dev Withdraw Insurance from the pool. + * @notice only master can call this function. + * @param wdAmt insurance token amount to remove + */ + function withdrawFee(uint wdAmt) external { + require(msg.sender == instaIndex.master(), "not-master"); + if (wdAmt > feeAmt) wdAmt = feeAmt; + baseToken.safeTransfer(msg.sender, wdAmt); + feeAmt = sub(feeAmt, wdAmt); + emit LogWithdrawFee(wdAmt); + } + + /** + * @dev Shut the pool. + * @notice only master can call this function. + */ + function shutdown() external { + require(msg.sender == instaIndex.master(), "not-master"); + paused() ? _unpause() : _pause(); + } + + receive() external payable {} - receive() external payable {} } diff --git a/contracts/pools/eth.sol b/contracts/pools/eth.sol index 628cd9d..8dedd21 100644 --- a/contracts/pools/eth.sol +++ b/contracts/pools/eth.sol @@ -17,6 +17,7 @@ interface RegistryInterface { function chief(address) external view returns (bool); function poolLogic(address) external returns (address); function fee(address) external view returns (uint); + function poolCap(address) external view returns (uint); function checkSettleLogics(address, address[] calldata) external view returns (bool); } @@ -60,23 +61,25 @@ contract PoolETH is ReentrancyGuard, ERC20Pausable, DSMath { * @dev get pool token rate * @param tokenAmt total token amount */ - function getCurrentRate(uint tokenAmt) internal returns (uint) { + function getCurrentRate(uint tokenAmt) internal view returns (uint) { return wdiv(totalSupply(), tokenAmt); } /** * @dev sets exchange rates */ - function setExchangeRate() public isChief { + function setExchangeRate() public { + require(msg.sender == address(this), "not-pool-address"); uint _prevRate = exchangeRate; uint _totalToken = RateInterface(registry.poolLogic(address(this))).getTotalToken(); _totalToken = sub(_totalToken, feeAmt); uint _newRate = getCurrentRate(_totalToken); + uint _tokenBal; require(_newRate != 0, "current-rate-is-zero"); if (_newRate > _prevRate) { _newRate = _prevRate; } else { - uint _tokenBal = wdiv(totalSupply(), _prevRate); + _tokenBal = wdiv(totalSupply(), _prevRate); uint _newFee = wmul(sub(_totalToken, _tokenBal), registry.fee(address(this))); feeAmt = add(feeAmt, _newFee); _tokenBal = sub(_totalToken, _newFee); @@ -127,6 +130,9 @@ contract PoolETH is ReentrancyGuard, ERC20Pausable, DSMath { */ function deposit(uint tknAmt) public whenNotPaused payable returns (uint mintAmt) { require(tknAmt == msg.value, "unmatched-amount"); + uint _tokenBal = wdiv(totalSupply(), exchangeRate); + uint _newTknBal = add(_tokenBal, tknAmt); + require(_newTknBal < registry.poolCap(address(this)), "unmatched-amount"); mintAmt = wmul(msg.value, exchangeRate); _mint(msg.sender, mintAmt); emit LogDeposit(msg.sender, tknAmt, mintAmt); @@ -136,7 +142,7 @@ contract PoolETH is ReentrancyGuard, ERC20Pausable, DSMath { * @dev Withdraw tokens. * @param tknAmt token amount * @param target withdraw tokens to address - * @return "wdAmt" amount of token withdrawn + * @return wdAmt amount of token withdrawn */ function withdraw(uint tknAmt, address target) external nonReentrant whenNotPaused returns (uint wdAmt) { require(target != address(0), "invalid-target-address"); diff --git a/contracts/registry.sol b/contracts/registry.sol index 5f0d818..50d79fc 100644 --- a/contracts/registry.sol +++ b/contracts/registry.sol @@ -16,6 +16,7 @@ contract Registry { event LogRemoveSigner(address indexed signer); event LogUpdatePoolLogic(address token, address newLogic); event LogUpdateFee(address token, uint newFee); + event LogUpdateCap(address token, uint newFee); event LogAddPool(address indexed token, address indexed pool); event LogRemovePool(address indexed token, address indexed pool); event LogAddSettleLogic(address indexed token, address indexed logic); @@ -118,14 +119,14 @@ contract Registry { address _pool = poolToken[_token]; require(_pool != address(0), "invalid-pool"); require(_newLogic != address(0), "invalid-address"); - require( poolLogic[_pool] != _newLogic, "same-pool-logic"); + require(poolLogic[_pool] != _newLogic, "same-pool-logic"); poolLogic[_pool] = _newLogic; emit LogUpdatePoolLogic(_pool, _newLogic); } /** * @dev update pool fee - * @param _pool pool address + * @param _token pool address * @param _newFee new fee amount */ function updateFee(address _token, uint _newFee) external isMaster { @@ -137,6 +138,18 @@ contract Registry { emit LogUpdateFee(_pool, _newFee); } + /** + * @dev update pool fee + * @param _token pool address + * @param _newCap new fee amount + */ + function updateCap(address _token, uint _newCap) external isMaster { + address _pool = poolToken[_token]; + require(_pool != address(0), "invalid-pool"); + poolCap[_pool] = _newCap; + emit LogUpdateCap(_pool, _newCap); + } + function addSettleLogic(address _token, address _logic) external isMaster { address _pool = poolToken[_token]; require(_pool != address(0), "invalid-pool");