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] 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); + } +}