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 new file mode 100644 index 0000000..0608841 --- /dev/null +++ b/contracts/ethPool.sol @@ -0,0 +1,155 @@ +// 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 { 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 getTotalToken() external returns (uint totalUnderlyingTkn); +} + +contract PoolToken is ERC20, DSMath { + 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 + + 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 + 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) 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))); + 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); // TODO - if this is also Reentrancy prone attack or not. + + 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 {} + +} diff --git a/contracts/flusher.sol b/contracts/flusher.sol new file mode 100644 index 0000000..a53bbed --- /dev/null +++ b/contracts/flusher.sol @@ -0,0 +1,158 @@ +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 shieldState); + + 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 payable 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, "more-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"); + } + + receive() external payable {} + +} \ No newline at end of file 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..0928393 --- /dev/null +++ b/contracts/rateLogics/dai.sol @@ -0,0 +1,36 @@ +// 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)); + + function getTotalToken() 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)); + } +} diff --git a/contracts/registry.sol b/contracts/registry.sol new file mode 100644 index 0000000..ba5031c --- /dev/null +++ b/contracts/registry.sol @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.6.8; +pragma experimental ABIEncoderV2; + +interface IndexInterface { + function master() external view returns (address); +} + +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); + 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; + 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); + } + + /** + * @dev Enable New Signer. + * @param _signer Address of the new signer. + */ + function enableSigner(address _signer) external isChief { + require(_signer != address(0), "invalid-address"); + 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), "invalid-address"); + require(signer[_signer], "signer-already-disabled"); + delete signer[_signer]; + 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), "invalid-address"); + 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), "invalid-address"); + 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]); + } + + function updatePoolCap(address _pool, uint _newCap) external isChief { + require(isPool[_pool], "not-pool"); + poolCap[_pool] = _newCap; + emit LogUpdatePoolCap(_pool, _newCap); + } + + function updatePoolLogic(address _pool, address _newLogic) external isChief { + 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-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 new file mode 100644 index 0000000..a22d7a9 --- /dev/null +++ b/contracts/tokenPool.sol @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.8; +pragma experimental ABIEncoderV2; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; + +import { DSMath } from "./libs/safeMath.sol"; + +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 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 = 10 ** 18; // 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))); + 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/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",