From 0ad1ca54dcfef22858da4d52de409bb3e06b3774 Mon Sep 17 00:00:00 2001 From: Abigail Date: Sun, 31 Oct 2021 11:51:21 -0500 Subject: [PATCH 01/33] first commit --- contracts/strategies/strategy-time-stake.sol | 215 +++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 contracts/strategies/strategy-time-stake.sol diff --git a/contracts/strategies/strategy-time-stake.sol b/contracts/strategies/strategy-time-stake.sol new file mode 100644 index 000000000..de8b03db9 --- /dev/null +++ b/contracts/strategies/strategy-time-stake.sol @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.7; + +import "../lib/ownable.sol"; +import "../lib/safe-math.sol"; +import "../lib/erc20.sol"; + +contract TimeStaking is Ownable { + + using SafeMath for uint256; + using SafeMath for uint32; + using SafeERC20 for IERC20; + + address public immutable Time; + address public immutable Memories; + + struct Epoch { + uint number; + uint distribute; + uint32 length; + uint32 endTime; + } + Epoch public epoch; + + address public distributor; + + address public locker; + uint public totalBonus; + + address public warmupContract; + uint public warmupPeriod; + + constructor ( + address _Time, + address _Memories, + uint32 _epochLength, + uint _firstEpochNumber, + uint32 _firstEpochTime + ) public { + require( _Time != address(0) ); + Time = _Time; + require( _Memories != address(0) ); + Memories = _Memories; + + epoch = Epoch({ + length: _epochLength, + number: _firstEpochNumber, + endTime: _firstEpochTime, + distribute: 0 + }); + } + + struct Claim { + uint deposit; + uint gons; + uint expiry; + bool lock; // prevents malicious delays + } + mapping( address => Claim ) public warmupInfo; + + /** + @notice stake OHM to enter warmup + @param _amount uint + @return bool + */ + function stake( uint _amount, address _recipient ) external returns ( bool ) { + rebase(); + + IERC20( Time ).safeTransferFrom( msg.sender, address(this), _amount ); + + Claim memory info = warmupInfo[ _recipient ]; + require( !info.lock, "Deposits for account are locked" ); + + warmupInfo[ _recipient ] = Claim ({ + deposit: info.deposit.add( _amount ), + gons: info.gons.add( IMemo( Memories ).gonsForBalance( _amount ) ), + expiry: epoch.number.add( warmupPeriod ), + lock: false + }); + + IERC20( Memories ).safeTransfer( warmupContract, _amount ); + return true; + } + + /** + @notice retrieve sOHM from warmup + @param _recipient address + */ + function claim ( address _recipient ) public { + Claim memory info = warmupInfo[ _recipient ]; + if ( epoch.number >= info.expiry && info.expiry != 0 ) { + delete warmupInfo[ _recipient ]; + IWarmup( warmupContract ).retrieve( _recipient, IMemo( Memories ).balanceForGons( info.gons ) ); + } + } + + /** + @notice forfeit sOHM in warmup and retrieve OHM + */ + function forfeit() external { + Claim memory info = warmupInfo[ msg.sender ]; + delete warmupInfo[ msg.sender ]; + + IWarmup( warmupContract ).retrieve( address(this), IMemo( Memories ).balanceForGons( info.gons ) ); + IERC20( Time ).safeTransfer( msg.sender, info.deposit ); + } + + /** + @notice prevent new deposits to address (protection from malicious activity) + */ + function toggleDepositLock() external { + warmupInfo[ msg.sender ].lock = !warmupInfo[ msg.sender ].lock; + } + + /** + @notice redeem sOHM for OHM + @param _amount uint + @param _trigger bool + */ + function unstake( uint _amount, bool _trigger ) external { + if ( _trigger ) { + rebase(); + } + IERC20( Memories ).safeTransferFrom( msg.sender, address(this), _amount ); + IERC20( Time ).safeTransfer( msg.sender, _amount ); + } + + /** + @notice returns the sOHM index, which tracks rebase growth + @return uint + */ + function index() public view returns ( uint ) { + return IMemo( Memories ).index(); + } + + /** + @notice trigger rebase if epoch over + */ + function rebase() public { + if( epoch.endTime <= uint32(block.timestamp) ) { + + IMemo( Memories ).rebase( epoch.distribute, epoch.number ); + + epoch.endTime = epoch.endTime.add32( epoch.length ); + epoch.number++; + + if ( distributor != address(0) ) { + IDistributor( distributor ).distribute(); + } + + uint balance = contractBalance(); + uint staked = IMemo( Memories ).circulatingSupply(); + + if( balance <= staked ) { + epoch.distribute = 0; + } else { + epoch.distribute = balance.sub( staked ); + } + } + } + + /** + @notice returns contract OHM holdings, including bonuses provided + @return uint + */ + function contractBalance() public view returns ( uint ) { + return IERC20( Time ).balanceOf( address(this) ).add( totalBonus ); + } + + /** + @notice provide bonus to locked staking contract + @param _amount uint + */ + function giveLockBonus( uint _amount ) external { + require( msg.sender == locker ); + totalBonus = totalBonus.add( _amount ); + IERC20( Memories ).safeTransfer( locker, _amount ); + } + + /** + @notice reclaim bonus from locked staking contract + @param _amount uint + */ + function returnLockBonus( uint _amount ) external { + require( msg.sender == locker ); + totalBonus = totalBonus.sub( _amount ); + IERC20( Memories ).safeTransferFrom( locker, address(this), _amount ); + } + + enum CONTRACTS { DISTRIBUTOR, WARMUP, LOCKER } + + /** + @notice sets the contract address for LP staking + @param _contract address + */ + function setContract( CONTRACTS _contract, address _address ) external onlyManager() { + if( _contract == CONTRACTS.DISTRIBUTOR ) { // 0 + distributor = _address; + } else if ( _contract == CONTRACTS.WARMUP ) { // 1 + require( warmupContract == address( 0 ), "Warmup cannot be set more than once" ); + warmupContract = _address; + } else if ( _contract == CONTRACTS.LOCKER ) { // 2 + require( locker == address(0), "Locker cannot be set more than once" ); + locker = _address; + } + } + + /** + * @notice set warmup period in epoch's numbers for new stakers + * @param _warmupPeriod uint + */ + function setWarmup( uint _warmupPeriod ) external onlyManager() { + warmupPeriod = _warmupPeriod; + } +} \ No newline at end of file From 49f2d03c77fd30cf1aa394842acba346b2e45853 Mon Sep 17 00:00:00 2001 From: Abigail Date: Tue, 2 Nov 2021 11:04:16 -0500 Subject: [PATCH 02/33] include harvest --- contracts/interfaces/wonderland.sol | 26 ++++++++++ contracts/lib/safe-math.sol | 7 +++ contracts/strategies/strategy-time-farm.sol | 52 ++++++++++++++++++++ contracts/strategies/strategy-time-stake.sol | 31 ++++++++---- 4 files changed, 107 insertions(+), 9 deletions(-) create mode 100644 contracts/interfaces/wonderland.sol create mode 100644 contracts/strategies/strategy-time-farm.sol diff --git a/contracts/interfaces/wonderland.sol b/contracts/interfaces/wonderland.sol new file mode 100644 index 000000000..1e5319b61 --- /dev/null +++ b/contracts/interfaces/wonderland.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.7; + + +interface IDistributor { + function distribute() external returns ( bool ); +} + +interface IMemo { + function rebase( uint256 ohmProfit_, uint epoch_) external returns (uint256); + + function circulatingSupply() external view returns (uint256); + + function balanceOf(address who) external view returns (uint256); + + function gonsForBalance( uint amount ) external view returns ( uint ); + + function balanceForGons( uint gons ) external view returns ( uint ); + + function index() external view returns ( uint ); +} + + +interface IWarmup { + function retrieve( address staker_, uint amount_ ) external; +} \ No newline at end of file diff --git a/contracts/lib/safe-math.sol b/contracts/lib/safe-math.sol index 31baf623f..c4b6b913b 100644 --- a/contracts/lib/safe-math.sol +++ b/contracts/lib/safe-math.sol @@ -33,6 +33,13 @@ library SafeMath { return c; } + function add32(uint32 a, uint32 b) internal pure returns (uint32) { + uint32 c = a + b; + require(c >= a, "SafeMath: addition overflow"); + + return c; + } + /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). diff --git a/contracts/strategies/strategy-time-farm.sol b/contracts/strategies/strategy-time-farm.sol new file mode 100644 index 000000000..8c3ac0a25 --- /dev/null +++ b/contracts/strategies/strategy-time-farm.sol @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.7; + +import "./strategy-time-stake.sol"; + +abstract contract StrategyTimeFarm is TimeStaking{ + + constructor( + address _Time, + address _Memories, + uint32 _epochLength, + uint _firstEpochNumber, + uint32 _firstEpochTime + ) public{} + + // **** State Mutations **** + + function _takeFeeTimeToSnob(uint256 _keep) internal { + address[] memory path = new address[](3); + path[0] = Time; + path[1] = wavax; + path[2] = snob; + IERC20(Time).safeApprove(pangolinRouter, 0); + IERC20(Time).safeApprove(pangolinRouter, _keep); + _swapPangolinWithPath(path, _keep); + uint256 _snob = IERC20(snob).balanceOf(address(this)); + uint256 _share = _snob.mul(revenueShare).div(revenueShareMax); + IERC20(snob).safeTransfer(feeDistributor, _share); + IERC20(snob).safeTransfer( + IController(controller).treasury(), + _snob.sub(_share) + ); + } + + +function harvest() public override onlyBenevolent { + + + //check the balance of Time Tokens. + uint256 _TIME = IERC20(Time).balanceOf(address(this)); + if (_TIME > 0){ + uint256 _keep = _TIME.mul(keep).div(keepMax); + if (_keep > 0){ + _takeFeeTimeToSnob(_keep); + } + } +} + + + + +} \ No newline at end of file diff --git a/contracts/strategies/strategy-time-stake.sol b/contracts/strategies/strategy-time-stake.sol index de8b03db9..5df33906f 100644 --- a/contracts/strategies/strategy-time-stake.sol +++ b/contracts/strategies/strategy-time-stake.sol @@ -4,16 +4,20 @@ pragma solidity ^0.6.7; import "../lib/ownable.sol"; import "../lib/safe-math.sol"; import "../lib/erc20.sol"; +import "./strategy-base.sol"; +import "../interfaces/wonderland.sol"; -contract TimeStaking is Ownable { +abstract contract TimeStaking is StrategyBase{ using SafeMath for uint256; using SafeMath for uint32; using SafeERC20 for IERC20; + //Tokens address public immutable Time; address public immutable Memories; + struct Epoch { uint number; uint distribute; @@ -58,16 +62,20 @@ contract TimeStaking is Ownable { } mapping( address => Claim ) public warmupInfo; + /** - @notice stake OHM to enter warmup + @notice stake TIME to enter warmup @param _amount uint @return bool */ function stake( uint _amount, address _recipient ) external returns ( bool ) { + + //the protocol making sure that you own the right proportion of the treasury balancer rebase(); IERC20( Time ).safeTransferFrom( msg.sender, address(this), _amount ); + //The warmup period is a number of epochs before a staker can take their MEMOries. Claim memory info = warmupInfo[ _recipient ]; require( !info.lock, "Deposits for account are locked" ); @@ -83,7 +91,7 @@ contract TimeStaking is Ownable { } /** - @notice retrieve sOHM from warmup + @notice retrieve MEMOries from warmup @param _recipient address */ function claim ( address _recipient ) public { @@ -95,7 +103,7 @@ contract TimeStaking is Ownable { } /** - @notice forfeit sOHM in warmup and retrieve OHM + @notice forfeit MEMOries in warmup and retrieve TIME */ function forfeit() external { Claim memory info = warmupInfo[ msg.sender ]; @@ -113,20 +121,24 @@ contract TimeStaking is Ownable { } /** - @notice redeem sOHM for OHM + @notice redeem MEMOries for TIME @param _amount uint @param _trigger bool */ function unstake( uint _amount, bool _trigger ) external { if ( _trigger ) { + //the protocol making sure that you own the right proportion of the treasury balancer rebase(); } + + //changes MEMOries to TIME IERC20( Memories ).safeTransferFrom( msg.sender, address(this), _amount ); IERC20( Time ).safeTransfer( msg.sender, _amount ); } + /** - @notice returns the sOHM index, which tracks rebase growth + @notice returns the MEMOries index, which tracks rebase growth @return uint */ function index() public view returns ( uint ) { @@ -148,6 +160,7 @@ contract TimeStaking is Ownable { IDistributor( distributor ).distribute(); } + //TIME balance uint balance = contractBalance(); uint staked = IMemo( Memories ).circulatingSupply(); @@ -160,7 +173,7 @@ contract TimeStaking is Ownable { } /** - @notice returns contract OHM holdings, including bonuses provided + @notice returns contract TIME holdings, including bonuses provided @return uint */ function contractBalance() public view returns ( uint ) { @@ -193,7 +206,7 @@ contract TimeStaking is Ownable { @notice sets the contract address for LP staking @param _contract address */ - function setContract( CONTRACTS _contract, address _address ) external onlyManager() { + function setContract( CONTRACTS _contract, address _address ) public { if( _contract == CONTRACTS.DISTRIBUTOR ) { // 0 distributor = _address; } else if ( _contract == CONTRACTS.WARMUP ) { // 1 @@ -209,7 +222,7 @@ contract TimeStaking is Ownable { * @notice set warmup period in epoch's numbers for new stakers * @param _warmupPeriod uint */ - function setWarmup( uint _warmupPeriod ) external onlyManager() { + function setWarmup( uint _warmupPeriod ) public { warmupPeriod = _warmupPeriod; } } \ No newline at end of file From b5e47d5cdc127b311bd7152d599e56ccbe39dc7f Mon Sep 17 00:00:00 2001 From: Abigail Date: Mon, 8 Nov 2021 09:50:45 -0500 Subject: [PATCH 03/33] current position --- contracts/strategies/strategy-time-farm.sol | 23 +++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/contracts/strategies/strategy-time-farm.sol b/contracts/strategies/strategy-time-farm.sol index 8c3ac0a25..b9d9db5f1 100644 --- a/contracts/strategies/strategy-time-farm.sol +++ b/contracts/strategies/strategy-time-farm.sol @@ -35,6 +35,29 @@ abstract contract StrategyTimeFarm is TimeStaking{ function harvest() public override onlyBenevolent { + //if we reach the end of an 8 hour period, then we call the rebase function + if( epoch.endTime <= uint32(block.timestamp) ){ + + } + //get the original balance of the Time tokens + uint256 _time = IERC20(Time).balanceOf( address(this)); + + /** + call the unstake function that rebases to get the right proportion of the treasury balancer, + i.e. determine the amount of MEMOries tokens accumulated during vesting period. + As well transfers MEMOries token to Time tokens + */ + unstake(); + + + + + //call the unstake function to unstake MEMO. + //Determine the delta value of the accumulated TIME and OG TIME after each epoch + //take 10% of that fee and invest it into our snowglobe + + + //check the balance of Time Tokens. uint256 _TIME = IERC20(Time).balanceOf(address(this)); From ddb1c13b27282149a5d13f5b3dff9127f3c6ee08 Mon Sep 17 00:00:00 2001 From: Abigail Date: Mon, 8 Nov 2021 12:46:06 -0500 Subject: [PATCH 04/33] current --- contracts/strategies/strategy-time-stake.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/strategies/strategy-time-stake.sol b/contracts/strategies/strategy-time-stake.sol index 5df33906f..3ee0f2025 100644 --- a/contracts/strategies/strategy-time-stake.sol +++ b/contracts/strategies/strategy-time-stake.sol @@ -125,7 +125,7 @@ abstract contract TimeStaking is StrategyBase{ @param _amount uint @param _trigger bool */ - function unstake( uint _amount, bool _trigger ) external { + function unstake( uint _amount, bool _trigger ) public { if ( _trigger ) { //the protocol making sure that you own the right proportion of the treasury balancer rebase(); From bf1ce02c59a131ae5d2b171546fe48a6bb2e66b5 Mon Sep 17 00:00:00 2001 From: Abigail Date: Wed, 10 Nov 2021 18:12:48 -0500 Subject: [PATCH 05/33] first draft --- contracts/interfaces/wonderland.sol | 4 +++ contracts/strategies/strategy-time-farm.sol | 32 ++++++++++++--------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/contracts/interfaces/wonderland.sol b/contracts/interfaces/wonderland.sol index 1e5319b61..a8d1d5b16 100644 --- a/contracts/interfaces/wonderland.sol +++ b/contracts/interfaces/wonderland.sol @@ -23,4 +23,8 @@ interface IMemo { interface IWarmup { function retrieve( address staker_, uint amount_ ) external; +} + +interface ITimeStaking { + function unstake(uint256 _amount, bool _trigger) external; } \ No newline at end of file diff --git a/contracts/strategies/strategy-time-farm.sol b/contracts/strategies/strategy-time-farm.sol index b9d9db5f1..4a14603d9 100644 --- a/contracts/strategies/strategy-time-farm.sol +++ b/contracts/strategies/strategy-time-farm.sol @@ -33,12 +33,19 @@ abstract contract StrategyTimeFarm is TimeStaking{ } -function harvest() public override onlyBenevolent { +function deposit () public override { + uint256 _want = IERC20(Time).balanceOf(address(this)); + if (_want > 0){ + IERC20(Time).safeApprove(Time, 0); + IERC20(Time).safeApprove(Time, _want); + //ITimeStaking(Time).stake( _want, address(this)); + + } +} - //if we reach the end of an 8 hour period, then we call the rebase function - if( epoch.endTime <= uint32(block.timestamp) ){ +function harvest() public override onlyBenevolent { - } + //find before getting to harvest because all of it has been //get the original balance of the Time tokens uint256 _time = IERC20(Time).balanceOf( address(this)); @@ -47,25 +54,24 @@ function harvest() public override onlyBenevolent { i.e. determine the amount of MEMOries tokens accumulated during vesting period. As well transfers MEMOries token to Time tokens */ - unstake(); + //depends on the contract!!!!!!!! + ITimeStaking(Memories).unstake(_time, true); + uint256 _afterTime = IERC20(Time).balanceOf( address(this)); - //call the unstake function to unstake MEMO. //Determine the delta value of the accumulated TIME and OG TIME after each epoch + uint256 deltaTime = _afterTime.sub(_time); + //take 10% of that fee and invest it into our snowglobe - - - //check the balance of Time Tokens. uint256 _TIME = IERC20(Time).balanceOf(address(this)); - if (_TIME > 0){ - uint256 _keep = _TIME.mul(keep).div(keepMax); - if (_keep > 0){ + if (deltaTime > 0){ + uint256 _keep = deltaTime.mul(keep).div(keepMax); _takeFeeTimeToSnob(_keep); - } + } } From 8ece63c39b4dea8a7cccf3df830debbad3ed3a6b Mon Sep 17 00:00:00 2001 From: Abigail Date: Wed, 10 Nov 2021 18:19:30 -0500 Subject: [PATCH 06/33] draft --- contracts/interfaces/wonderland.sol | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/contracts/interfaces/wonderland.sol b/contracts/interfaces/wonderland.sol index a8d1d5b16..ca8e1325e 100644 --- a/contracts/interfaces/wonderland.sol +++ b/contracts/interfaces/wonderland.sol @@ -26,5 +26,11 @@ interface IWarmup { } interface ITimeStaking { + function stake(uint _amount, address _recipient) external view returns ( bool ); + + function claim(address _recipient) external; + function unstake(uint256 _amount, bool _trigger) external; + + } \ No newline at end of file From 87d4e9026ca99b2d00b59c8a88983085985813bf Mon Sep 17 00:00:00 2001 From: Abigail Date: Sat, 13 Nov 2021 20:21:37 -0500 Subject: [PATCH 07/33] pause-point --- contracts/interfaces/wonderland.sol | 14 ++ contracts/strategies/strategy-time-farm.sol | 103 ++++---- contracts/strategies/strategy-time-stake.sol | 228 ------------------ .../strategies/strategy-wonderland-base.sol | 223 +++++++++++++++++ 4 files changed, 297 insertions(+), 271 deletions(-) delete mode 100644 contracts/strategies/strategy-time-stake.sol create mode 100644 contracts/strategies/strategy-wonderland-base.sol diff --git a/contracts/interfaces/wonderland.sol b/contracts/interfaces/wonderland.sol index ca8e1325e..fbab4af42 100644 --- a/contracts/interfaces/wonderland.sol +++ b/contracts/interfaces/wonderland.sol @@ -30,7 +30,21 @@ interface ITimeStaking { function claim(address _recipient) external; + function index() external view returns ( uint ); + function unstake(uint256 _amount, bool _trigger) external; + function contractBalance() external view returns ( uint ); + + function forfeit() external; + + function giveLockBonus( uint _amount) external; + + function returnLockBonus(uint _amount) external; + + function toggleDepositLock() external; + + function setWarmup( uint _warmupPeriod) external; + } \ No newline at end of file diff --git a/contracts/strategies/strategy-time-farm.sol b/contracts/strategies/strategy-time-farm.sol index 4a14603d9..620b48406 100644 --- a/contracts/strategies/strategy-time-farm.sol +++ b/contracts/strategies/strategy-time-farm.sol @@ -1,17 +1,35 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.6.7; -import "./strategy-time-stake.sol"; +import "./strategy-wonderland-base.sol"; -abstract contract StrategyTimeFarm is TimeStaking{ +abstract contract StrategyTimeFarm is TimeBase{ + + address public rewards; + uint256 public _initial; constructor( - address _Time, - address _Memories, - uint32 _epochLength, - uint _firstEpochNumber, - uint32 _firstEpochTime - ) public{} + address _rewards, + // uint32 _epochLength, + // uint _firstEpochNumber, + // uint32 _firstEpochTime + + address _wantToken, + address _governance, + address _strategist, + address _controller, + address _timelock + ) + public + TimeBase(_wantToken, _governance, _strategist, _controller, _timelock) + { + rewards = _rewards; + } + + function balanceBeingStaked() public override view returns (uint256){ + //return ITimeStaking(rewards).contractBalance() + //return IMemo(rewards).balanceOf(address(this)) + } // **** State Mutations **** @@ -20,9 +38,9 @@ abstract contract StrategyTimeFarm is TimeStaking{ path[0] = Time; path[1] = wavax; path[2] = snob; - IERC20(Time).safeApprove(pangolinRouter, 0); - IERC20(Time).safeApprove(pangolinRouter, _keep); - _swapPangolinWithPath(path, _keep); + IERC20(Time).safeApprove(joeRouter, 0); + IERC20(Time).safeApprove(joeRouter, _keep); + _swapTraderJoeWithPath(path, _keep); uint256 _snob = IERC20(snob).balanceOf(address(this)); uint256 _share = _snob.mul(revenueShare).div(revenueShareMax); IERC20(snob).safeTransfer(feeDistributor, _share); @@ -32,48 +50,47 @@ abstract contract StrategyTimeFarm is TimeStaking{ ); } - -function deposit () public override { - uint256 _want = IERC20(Time).balanceOf(address(this)); - if (_want > 0){ - IERC20(Time).safeApprove(Time, 0); - IERC20(Time).safeApprove(Time, _want); - //ITimeStaking(Time).stake( _want, address(this)); - + // stakes the Time Token + function deposit () public override { + // the amount of Time tokens that you want to stake + _initial = IERC20(Time).balanceOf(address(this)); + if (_initial > 0){ + IERC20(wantToken).safeApprove(rewards, 0); + IERC20(wantToken).safeApprove(rewards, _initial); + ITimeStaking(rewards).stake(_initial, address(this)); + } } -} -function harvest() public override onlyBenevolent { - //find before getting to harvest because all of it has been - //get the original balance of the Time tokens - uint256 _time = IERC20(Time).balanceOf( address(this)); + // function _withdrawSome(uint256 _amount) internal override returns (uint256) { + // ITimeStaking(rewards).withdraw(_amount); + // return _amount; + // } - /** - call the unstake function that rebases to get the right proportion of the treasury balancer, - i.e. determine the amount of MEMOries tokens accumulated during vesting period. - As well transfers MEMOries token to Time tokens - */ + function harvest() public override onlyBenevolent { + uint256 _amount; - //depends on the contract!!!!!!!! - ITimeStaking(Memories).unstake(_time, true); + /** + call the unstake function that rebases to get the right proportion of the treasury balancer, + i.e. determine the amount of MEMOries tokens accumulated during vesting period. + As well transfers MEMOries token to Time tokens + */ + // Collect the time tokens + ITimeStaking(Memories).unstake(_amount, true); + uint256 _time = IERC20(Time).balanceOf( address(this)); - uint256 _afterTime = IERC20(Time).balanceOf( address(this)); + //Determine the delta value of the accumulated TIME and OG TIME after each epoch + uint256 deltaTime = _initial.sub(_time); - //Determine the delta value of the accumulated TIME and OG TIME after each epoch - uint256 deltaTime = _afterTime.sub(_time); - - //take 10% of that fee and invest it into our snowglobe - - - uint256 _TIME = IERC20(Time).balanceOf(address(this)); + //take 10% of that fee and invest it into our snowglobe if (deltaTime > 0){ - uint256 _keep = deltaTime.mul(keep).div(keepMax); - _takeFeeTimeToSnob(_keep); - + uint256 _keep = deltaTime.mul(keep).div(keepMax); + _takeFeeTimeToSnob(_keep); } -} + + + } diff --git a/contracts/strategies/strategy-time-stake.sol b/contracts/strategies/strategy-time-stake.sol deleted file mode 100644 index 3ee0f2025..000000000 --- a/contracts/strategies/strategy-time-stake.sol +++ /dev/null @@ -1,228 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.6.7; - -import "../lib/ownable.sol"; -import "../lib/safe-math.sol"; -import "../lib/erc20.sol"; -import "./strategy-base.sol"; -import "../interfaces/wonderland.sol"; - -abstract contract TimeStaking is StrategyBase{ - - using SafeMath for uint256; - using SafeMath for uint32; - using SafeERC20 for IERC20; - - //Tokens - address public immutable Time; - address public immutable Memories; - - - struct Epoch { - uint number; - uint distribute; - uint32 length; - uint32 endTime; - } - Epoch public epoch; - - address public distributor; - - address public locker; - uint public totalBonus; - - address public warmupContract; - uint public warmupPeriod; - - constructor ( - address _Time, - address _Memories, - uint32 _epochLength, - uint _firstEpochNumber, - uint32 _firstEpochTime - ) public { - require( _Time != address(0) ); - Time = _Time; - require( _Memories != address(0) ); - Memories = _Memories; - - epoch = Epoch({ - length: _epochLength, - number: _firstEpochNumber, - endTime: _firstEpochTime, - distribute: 0 - }); - } - - struct Claim { - uint deposit; - uint gons; - uint expiry; - bool lock; // prevents malicious delays - } - mapping( address => Claim ) public warmupInfo; - - - /** - @notice stake TIME to enter warmup - @param _amount uint - @return bool - */ - function stake( uint _amount, address _recipient ) external returns ( bool ) { - - //the protocol making sure that you own the right proportion of the treasury balancer - rebase(); - - IERC20( Time ).safeTransferFrom( msg.sender, address(this), _amount ); - - //The warmup period is a number of epochs before a staker can take their MEMOries. - Claim memory info = warmupInfo[ _recipient ]; - require( !info.lock, "Deposits for account are locked" ); - - warmupInfo[ _recipient ] = Claim ({ - deposit: info.deposit.add( _amount ), - gons: info.gons.add( IMemo( Memories ).gonsForBalance( _amount ) ), - expiry: epoch.number.add( warmupPeriod ), - lock: false - }); - - IERC20( Memories ).safeTransfer( warmupContract, _amount ); - return true; - } - - /** - @notice retrieve MEMOries from warmup - @param _recipient address - */ - function claim ( address _recipient ) public { - Claim memory info = warmupInfo[ _recipient ]; - if ( epoch.number >= info.expiry && info.expiry != 0 ) { - delete warmupInfo[ _recipient ]; - IWarmup( warmupContract ).retrieve( _recipient, IMemo( Memories ).balanceForGons( info.gons ) ); - } - } - - /** - @notice forfeit MEMOries in warmup and retrieve TIME - */ - function forfeit() external { - Claim memory info = warmupInfo[ msg.sender ]; - delete warmupInfo[ msg.sender ]; - - IWarmup( warmupContract ).retrieve( address(this), IMemo( Memories ).balanceForGons( info.gons ) ); - IERC20( Time ).safeTransfer( msg.sender, info.deposit ); - } - - /** - @notice prevent new deposits to address (protection from malicious activity) - */ - function toggleDepositLock() external { - warmupInfo[ msg.sender ].lock = !warmupInfo[ msg.sender ].lock; - } - - /** - @notice redeem MEMOries for TIME - @param _amount uint - @param _trigger bool - */ - function unstake( uint _amount, bool _trigger ) public { - if ( _trigger ) { - //the protocol making sure that you own the right proportion of the treasury balancer - rebase(); - } - - //changes MEMOries to TIME - IERC20( Memories ).safeTransferFrom( msg.sender, address(this), _amount ); - IERC20( Time ).safeTransfer( msg.sender, _amount ); - } - - - /** - @notice returns the MEMOries index, which tracks rebase growth - @return uint - */ - function index() public view returns ( uint ) { - return IMemo( Memories ).index(); - } - - /** - @notice trigger rebase if epoch over - */ - function rebase() public { - if( epoch.endTime <= uint32(block.timestamp) ) { - - IMemo( Memories ).rebase( epoch.distribute, epoch.number ); - - epoch.endTime = epoch.endTime.add32( epoch.length ); - epoch.number++; - - if ( distributor != address(0) ) { - IDistributor( distributor ).distribute(); - } - - //TIME balance - uint balance = contractBalance(); - uint staked = IMemo( Memories ).circulatingSupply(); - - if( balance <= staked ) { - epoch.distribute = 0; - } else { - epoch.distribute = balance.sub( staked ); - } - } - } - - /** - @notice returns contract TIME holdings, including bonuses provided - @return uint - */ - function contractBalance() public view returns ( uint ) { - return IERC20( Time ).balanceOf( address(this) ).add( totalBonus ); - } - - /** - @notice provide bonus to locked staking contract - @param _amount uint - */ - function giveLockBonus( uint _amount ) external { - require( msg.sender == locker ); - totalBonus = totalBonus.add( _amount ); - IERC20( Memories ).safeTransfer( locker, _amount ); - } - - /** - @notice reclaim bonus from locked staking contract - @param _amount uint - */ - function returnLockBonus( uint _amount ) external { - require( msg.sender == locker ); - totalBonus = totalBonus.sub( _amount ); - IERC20( Memories ).safeTransferFrom( locker, address(this), _amount ); - } - - enum CONTRACTS { DISTRIBUTOR, WARMUP, LOCKER } - - /** - @notice sets the contract address for LP staking - @param _contract address - */ - function setContract( CONTRACTS _contract, address _address ) public { - if( _contract == CONTRACTS.DISTRIBUTOR ) { // 0 - distributor = _address; - } else if ( _contract == CONTRACTS.WARMUP ) { // 1 - require( warmupContract == address( 0 ), "Warmup cannot be set more than once" ); - warmupContract = _address; - } else if ( _contract == CONTRACTS.LOCKER ) { // 2 - require( locker == address(0), "Locker cannot be set more than once" ); - locker = _address; - } - } - - /** - * @notice set warmup period in epoch's numbers for new stakers - * @param _warmupPeriod uint - */ - function setWarmup( uint _warmupPeriod ) public { - warmupPeriod = _warmupPeriod; - } -} \ No newline at end of file diff --git a/contracts/strategies/strategy-wonderland-base.sol b/contracts/strategies/strategy-wonderland-base.sol new file mode 100644 index 000000000..47fcb841c --- /dev/null +++ b/contracts/strategies/strategy-wonderland-base.sol @@ -0,0 +1,223 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.7; + +import "../lib/ownable.sol"; +import "../lib/safe-math.sol"; +import "../lib/erc20.sol"; + +import "../interfaces/icequeen.sol"; +import "../interfaces/globe.sol"; +import "../interfaces/joe.sol"; +import "../interfaces/wonderland.sol"; +import "../interfaces/controller.sol"; + +//Wonderland Strategy Contract Basics +abstract contract TimeBase { + + using SafeMath for uint256; + using SafeMath for uint32; + using SafeERC20 for IERC20; + + // Tokens + address public wantToken; + address public wavax = 0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7; + address public snob = 0xC38f41A296A4493Ff429F1238e030924A1542e50; + address public immutable Time = 0xb54f16fB19478766A268F172C9480f8da1a7c9C3; + address public immutable Memories = 0x136Acd46C134E8269052c62A67042D6bDeDde3C9; + + // Dex + address public constant joeRouter = 0x60aE616a2155Ee3d9A68541Ba4544862310933d4; + + // xSnob Fee Distributor + address public feeDistributor = 0xAd86ef5fD2eBc25bb9Db41A1FE8d0f2a322c7839; + + // Perfomance fees - start with 0% + uint256 public performanceTreasuryFee = 0; + uint256 public constant performanceTreasuryMax = 10000; + + uint256 public performanceDevFee = 0; + uint256 public constant performanceDevMax = 10000; + + // How many rewards tokens to keep? start with 10% converted to Snowballss + uint256 public keep = 1000; + uint256 public constant keepMax = 10000; + + //portion to seend to fee distributor + uint256 public revenueShare = 3000; + uint256 public constant revenueShareMax = 10000; + + // Withdrawal fee 0% + // - 0% to treasury + // - 0% to dev fund + uint256 public withdrawalTreasuryFee = 0; + uint256 public constant withdrawalTreasuryMax = 100000; + + uint256 public withdrawalDevFundFee = 0; + uint256 public constant withdrawalDevFundMax = 100000; + + // User accounts + address public governance; + address public controller; + address public strategist; + address public timelock; + + mapping(address => bool) public harvesters; + + constructor ( + address _wantToken, + address _governance, + address _strategist, + address _controller, + address _timelock + ) public { + require(_wantToken != address(0)); + require(_governance != address(0)); + require(_strategist != address(0)); + require(_controller != address(0)); + require(_timelock != address(0)); + + wantToken = _wantToken; + governance = _governance; + strategist = _strategist; + controller = _controller; + timelock = _timelock; + } + + // **** Modifiers **** // + + modifier onlyBenevolent { + require( + harvesters[msg.sender] || + msg.sender == governance || + msg.sender == strategist + ); + _; + } + + // **** Views **** // + + function balanceOfWant() public view returns (uint256) { + return IERC20(wantToken).balanceOf(address(this)); + } + + function balanceBeingStaked() public virtual view returns (uint256); + + + + function whitelistHarvester(address _harvester) external { + require(msg.sender == governance || + msg.sender == strategist, "not authorized"); + harvesters[_harvester] = true; + } + + function revokeHarvester(address _harvester) external { + require(msg.sender == governance || + msg.sender == strategist, "not authorized"); + harvesters[_harvester] = false; + } + + function setFeeDistributor(address _feeDistributor) external { + require(msg.sender == governance, "not authorized"); + feeDistributor = _feeDistributor; + } + + function setWithdrawalDevFundFee(uint256 _withdrawalDevFundFee) external { + require(msg.sender == timelock, "!timelock"); + withdrawalDevFundFee = _withdrawalDevFundFee; + } + + function setWithdrawalTreasuryFee(uint256 _withdrawalTreasuryFee) external { + require(msg.sender == timelock, "!timelock"); + withdrawalTreasuryFee = _withdrawalTreasuryFee; + } + + function setPerformanceDevFee(uint256 _performanceDevFee) external { + require(msg.sender == timelock, "!timelock"); + performanceDevFee = _performanceDevFee; + } + + function setPerformanceTreasuryFee(uint256 _performanceTreasuryFee) + external + { + require(msg.sender == timelock, "!timelock"); + performanceTreasuryFee = _performanceTreasuryFee; + } + + function setStrategist(address _strategist) external { + require(msg.sender == governance, "!governance"); + strategist = _strategist; + } + + function setGovernance(address _governance) external { + require(msg.sender == governance, "!governance"); + governance = _governance; + } + + function setTimelock(address _timelock) external { + require(msg.sender == timelock, "!timelock"); + timelock = _timelock; + } + + function setController(address _controller) external { + require(msg.sender == timelock, "!timelock"); + controller = _controller; + } + + // **** State mutations **** // + function deposit() public virtual; + + // Controller only function for creating additional rewards from dust + function withdraw(IERC20 _asset) external returns (uint256 balance) { + require(msg.sender == controller, "!controller"); + require(wantToken != address(_asset), "want"); + balance = _asset.balanceOf(address(this)); + _asset.safeTransfer(controller, balance); + } + + // Withdraw partial funds, normally used with a globe withdrawal + function withdraw(uint256 _amount) external { + require(msg.sender == controller, "!controller"); + uint256 _balance = IERC20(wantToken).balanceOf(address(this)); + if (_balance < _amount) { + _amount = _withdrawSome(_amount.sub(_balance)); + _amount = _amount.add(_balance); + } + + uint256 _feeDev = _amount.mul(withdrawalDevFundFee).div( + withdrawalDevFundMax + ); + IERC20(wantToken).safeTransfer(IController(controller).devfund(), _feeDev); + + uint256 _feeTreasury = _amount.mul(withdrawalTreasuryFee).div( + withdrawalTreasuryMax + ); + IERC20(wantToken).safeTransfer( + IController(controller).treasury(), + _feeTreasury + ); + + address _globe = IController(controller).globes(address(wantToken)); + require(_globe != address(0), "!globe"); // additional protection so we don't burn the funds + + IERC20(wantToken).safeTransfer(_globe, _amount.sub(_feeDev).sub(_feeTreasury)); + } + + function harvest() public virtual; + + function _withdrawSome(uint256 _amount) internal virtual returns (uint256); + + function _swapTraderJoeWithPath(address[] memory path, uint256 _amount) + internal + { + require(path[1] != address(0)); + + IJoeRouter(joeRouter).swapExactTokensForTokens( + _amount, + 0, + path, + address(this), + now.add(60) + ); + } + +} \ No newline at end of file From 9333426f43ffdf9895640719733721894e87fdcc Mon Sep 17 00:00:00 2001 From: Abigail Date: Sat, 13 Nov 2021 20:23:02 -0500 Subject: [PATCH 08/33] breakpoint --- contracts/interfaces/wonderland.sol | 4 ++++ contracts/strategies/strategy-time-farm.sol | 17 +++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/contracts/interfaces/wonderland.sol b/contracts/interfaces/wonderland.sol index fbab4af42..636856360 100644 --- a/contracts/interfaces/wonderland.sol +++ b/contracts/interfaces/wonderland.sol @@ -25,6 +25,8 @@ interface IWarmup { function retrieve( address staker_, uint amount_ ) external; } +enum CONTRACTS { DISTRIBUTOR, WARMUP, LOCKER } + interface ITimeStaking { function stake(uint _amount, address _recipient) external view returns ( bool ); @@ -46,5 +48,7 @@ interface ITimeStaking { function setWarmup( uint _warmupPeriod) external; + function setContract( CONTRACTS _contract, address _address ) external; + } \ No newline at end of file diff --git a/contracts/strategies/strategy-time-farm.sol b/contracts/strategies/strategy-time-farm.sol index 620b48406..8bac6a817 100644 --- a/contracts/strategies/strategy-time-farm.sol +++ b/contracts/strategies/strategy-time-farm.sol @@ -10,9 +10,7 @@ abstract contract StrategyTimeFarm is TimeBase{ constructor( address _rewards, - // uint32 _epochLength, - // uint _firstEpochNumber, - // uint32 _firstEpochTime + address _wantToken, address _governance, @@ -55,8 +53,8 @@ abstract contract StrategyTimeFarm is TimeBase{ // the amount of Time tokens that you want to stake _initial = IERC20(Time).balanceOf(address(this)); if (_initial > 0){ - IERC20(wantToken).safeApprove(rewards, 0); - IERC20(wantToken).safeApprove(rewards, _initial); + // IERC20(wantToken).safeApprove(rewards, 0); + // IERC20(wantToken).safeApprove(rewards, _initial); ITimeStaking(rewards).stake(_initial, address(this)); } } @@ -79,17 +77,20 @@ abstract contract StrategyTimeFarm is TimeBase{ // Collect the time tokens ITimeStaking(Memories).unstake(_amount, true); uint256 _time = IERC20(Time).balanceOf( address(this)); - - //Determine the delta value of the accumulated TIME and OG TIME after each epoch uint256 deltaTime = _initial.sub(_time); - //take 10% of that fee and invest it into our snowglobe if (deltaTime > 0){ + // 10% locked up for future govenrnance uint256 _keep = deltaTime.mul(keep).div(keepMax); + if (_keep > 0){ _takeFeeTimeToSnob(_keep); + } } + + + } From d36cad6ba845209e721b8563ae7ef6283cec665c Mon Sep 17 00:00:00 2001 From: Abigail Date: Sun, 14 Nov 2021 00:42:17 -0500 Subject: [PATCH 09/33] wonderland interface --- contracts/interfaces/wonderland.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/interfaces/wonderland.sol b/contracts/interfaces/wonderland.sol index 636856360..a1011e132 100644 --- a/contracts/interfaces/wonderland.sol +++ b/contracts/interfaces/wonderland.sol @@ -49,6 +49,6 @@ interface ITimeStaking { function setWarmup( uint _warmupPeriod) external; function setContract( CONTRACTS _contract, address _address ) external; - - + + function rebase() external; } \ No newline at end of file From 3b8d31cd3f4ba6205e08bd989815ebb75de62a9e Mon Sep 17 00:00:00 2001 From: Abigail Date: Mon, 15 Nov 2021 10:12:11 -0500 Subject: [PATCH 10/33] breakpoint --- contracts/strategies/strategy-time-farm.sol | 72 ++++++++++--------- .../strategies/strategy-wonderland-base.sol | 27 ++++++- 2 files changed, 63 insertions(+), 36 deletions(-) diff --git a/contracts/strategies/strategy-time-farm.sol b/contracts/strategies/strategy-time-farm.sol index 8bac6a817..aa49e9f08 100644 --- a/contracts/strategies/strategy-time-farm.sol +++ b/contracts/strategies/strategy-time-farm.sol @@ -5,28 +5,34 @@ import "./strategy-wonderland-base.sol"; abstract contract StrategyTimeFarm is TimeBase{ - address public rewards; + address public rewards = 0x4456B87Af11e87E329AB7d7C7A246ed1aC2168B9; uint256 public _initial; constructor( address _rewards, - - address _wantToken, address _governance, address _strategist, address _controller, - address _timelock + address _timelock, + uint32 _epochLength, + uint _firstEpochNumber, + uint32 _firstEpochTime ) public - TimeBase(_wantToken, _governance, _strategist, _controller, _timelock) + TimeBase(_wantToken, _governance, _strategist, _controller, _timelock, _epochLength, _firstEpochNumber, _firstEpochTime) { rewards = _rewards; + + + } + + function balanceOfTime() public override view returns (uint256){ + return ITimeStaking(Time).contractBalance(); } - function balanceBeingStaked() public override view returns (uint256){ - //return ITimeStaking(rewards).contractBalance() - //return IMemo(rewards).balanceOf(address(this)) + function getHarvestable() external view returns (uint256) { + return ITimeStaking(Time).index(); } // **** State Mutations **** @@ -48,48 +54,46 @@ abstract contract StrategyTimeFarm is TimeBase{ ); } - // stakes the Time Token + // deposits the Time token in the staking contract function deposit () public override { // the amount of Time tokens that you want to stake _initial = IERC20(Time).balanceOf(address(this)); if (_initial > 0){ - // IERC20(wantToken).safeApprove(rewards, 0); - // IERC20(wantToken).safeApprove(rewards, _initial); + IERC20(wantToken).safeApprove(rewards, 0); + IERC20(wantToken).safeApprove(rewards, _initial); ITimeStaking(rewards).stake(_initial, address(this)); } } - // function _withdrawSome(uint256 _amount) internal override returns (uint256) { - // ITimeStaking(rewards).withdraw(_amount); - // return _amount; - // } + /** + @notice we have to restake time tokens whenever the epoch is over + */ + function reStake() public override { + ITimeStaking(Time).rebase(); + deposit(); + } - function harvest() public override onlyBenevolent { - uint256 _amount; - /** - call the unstake function that rebases to get the right proportion of the treasury balancer, + /** + calls the unstake function that rebases to get the right proportion of the treasury balancer, i.e. determine the amount of MEMOries tokens accumulated during vesting period. As well transfers MEMOries token to Time tokens - */ + */ + function harvest() public override onlyBenevolent { - // Collect the time tokens - ITimeStaking(Memories).unstake(_amount, true); - uint256 _time = IERC20(Time).balanceOf( address(this)); - uint256 deltaTime = _initial.sub(_time); - - if (deltaTime > 0){ - // 10% locked up for future govenrnance - uint256 _keep = deltaTime.mul(keep).div(keepMax); - if (_keep > 0){ + uint256 _amount = ITimeStaking(Time).index(); + + if (_amount > 0) { + // 10% locked up for future governance + uint256 _keep = _amount.mul(keep).div(keepMax); + if (_keep > 0) { _takeFeeTimeToSnob(_keep); - } + } } - - - - + // Collect the time tokens + ITimeStaking(Time).unstake(_amount, true); + } diff --git a/contracts/strategies/strategy-wonderland-base.sol b/contracts/strategies/strategy-wonderland-base.sol index 47fcb841c..abe18d374 100644 --- a/contracts/strategies/strategy-wonderland-base.sol +++ b/contracts/strategies/strategy-wonderland-base.sol @@ -61,14 +61,28 @@ abstract contract TimeBase { address public strategist; address public timelock; + address public distributor; + mapping(address => bool) public harvesters; + struct Epoch { + uint number; + uint distribute; + uint32 length; + uint32 endTime; + } + + Epoch public epoch; + constructor ( address _wantToken, address _governance, address _strategist, address _controller, - address _timelock + address _timelock, + uint32 _epochLength, + uint _firstEpochNumber, + uint32 _firstEpochTime ) public { require(_wantToken != address(0)); require(_governance != address(0)); @@ -81,6 +95,13 @@ abstract contract TimeBase { strategist = _strategist; controller = _controller; timelock = _timelock; + + epoch = Epoch({ + length: _epochLength, + number: _firstEpochNumber, + endTime: _firstEpochTime, + distribute: 0 + }); } // **** Modifiers **** // @@ -100,7 +121,7 @@ abstract contract TimeBase { return IERC20(wantToken).balanceOf(address(this)); } - function balanceBeingStaked() public virtual view returns (uint256); + function balanceOfTime() public virtual view returns (uint256); @@ -204,6 +225,8 @@ abstract contract TimeBase { function harvest() public virtual; + function reStake() public virtual; + function _withdrawSome(uint256 _amount) internal virtual returns (uint256); function _swapTraderJoeWithPath(address[] memory path, uint256 _amount) From ac6048def302c1dc6f86bc6e5b845a91921a242e Mon Sep 17 00:00:00 2001 From: Abigail Date: Mon, 15 Nov 2021 10:13:20 -0500 Subject: [PATCH 11/33] breakpoint --- contracts/interfaces/wonderland.sol | 6 ++++++ contracts/strategies/strategy-time-farm.sol | 6 +----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/contracts/interfaces/wonderland.sol b/contracts/interfaces/wonderland.sol index a1011e132..00166a719 100644 --- a/contracts/interfaces/wonderland.sol +++ b/contracts/interfaces/wonderland.sol @@ -51,4 +51,10 @@ interface ITimeStaking { function setContract( CONTRACTS _contract, address _address ) external; function rebase() external; +} + +interface ITreasury { + function deposit( uint _amount, address _token, uint _profit ) external returns ( bool ); + function valueOf( address _token, uint _amount ) external view returns ( uint value_ ); + function mintRewards( address _recipient, uint _amount ) external; } \ No newline at end of file diff --git a/contracts/strategies/strategy-time-farm.sol b/contracts/strategies/strategy-time-farm.sol index aa49e9f08..78a63c799 100644 --- a/contracts/strategies/strategy-time-farm.sol +++ b/contracts/strategies/strategy-time-farm.sol @@ -23,8 +23,6 @@ abstract contract StrategyTimeFarm is TimeBase{ TimeBase(_wantToken, _governance, _strategist, _controller, _timelock, _epochLength, _firstEpochNumber, _firstEpochTime) { rewards = _rewards; - - } function balanceOfTime() public override view returns (uint256){ @@ -35,7 +33,7 @@ abstract contract StrategyTimeFarm is TimeBase{ return ITimeStaking(Time).index(); } - // **** State Mutations **** + // **** State Mutations **** function _takeFeeTimeToSnob(uint256 _keep) internal { address[] memory path = new address[](3); @@ -93,8 +91,6 @@ abstract contract StrategyTimeFarm is TimeBase{ } // Collect the time tokens ITimeStaking(Time).unstake(_amount, true); - - } From bc9121f880c863a2cfe4eae5759c3edca5e347ed Mon Sep 17 00:00:00 2001 From: Abigail Date: Mon, 15 Nov 2021 16:23:39 -0500 Subject: [PATCH 12/33] breakpoint --- contracts/interfaces/wonderland.sol | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/contracts/interfaces/wonderland.sol b/contracts/interfaces/wonderland.sol index 00166a719..038b94ea4 100644 --- a/contracts/interfaces/wonderland.sol +++ b/contracts/interfaces/wonderland.sol @@ -57,4 +57,28 @@ interface ITreasury { function deposit( uint _amount, address _token, uint _profit ) external returns ( bool ); function valueOf( address _token, uint _amount ) external view returns ( uint value_ ); function mintRewards( address _recipient, uint _amount ) external; +} + +interface ITimeBondDepository { + function initializeBondTerms( + uint _controlVariable, + uint _minimumPrice, + uint _maxPayout, + uint _maxDebt, + uint _initialDebt, + uint32 _vestingTerm + ) external; + + enum PARAMETER { VESTING, PAYOUT, DEBT, MINPRICE } + + function setBondTerms ( PARAMETER _parameter, uint _input ) external; + + function setAdjustment ( bool _addition, uint _increment, uint _target, uint32 _buffer ) external; + + function setStaking( address _staking, bool _helper ) external; + + function deposit( uint _amount, uint _maxPrice, address _depositor) external payable returns ( uint ); + + function redeem( address _recipient, bool _stake ) external returns ( uint ) + } \ No newline at end of file From f2c6f8d73356a28d76d204934061436b7275a973 Mon Sep 17 00:00:00 2001 From: Abigail Date: Mon, 15 Nov 2021 16:24:06 -0500 Subject: [PATCH 13/33] breakpoint --- contracts/interfaces/wonderland.sol | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/contracts/interfaces/wonderland.sol b/contracts/interfaces/wonderland.sol index 038b94ea4..4c5c7ea8d 100644 --- a/contracts/interfaces/wonderland.sol +++ b/contracts/interfaces/wonderland.sol @@ -79,6 +79,10 @@ interface ITimeBondDepository { function deposit( uint _amount, uint _maxPrice, address _depositor) external payable returns ( uint ); - function redeem( address _recipient, bool _stake ) external returns ( uint ) + function redeem( address _recipient, bool _stake ) external returns ( uint ); + + function stakeOrSend( address _recipient, bool _stake, uint _amount ) external returns ( uint ); + + } \ No newline at end of file From a1f1f52acb6650e9d67425e6a47b3b24f80ae81b Mon Sep 17 00:00:00 2001 From: Abigail Date: Tue, 16 Nov 2021 15:28:28 -0500 Subject: [PATCH 14/33] breakpoint --- contracts/interfaces/wonderland.sol | 23 ++++++----- contracts/strategies/strategy-time-farm.sol | 38 +++++++++++-------- .../strategies/strategy-wonderland-base.sol | 32 ++++++---------- .../wonderland/strategy-time-mim.sol | 38 +++++++++++++++++++ 4 files changed, 85 insertions(+), 46 deletions(-) create mode 100644 contracts/strategies/wonderland/strategy-time-mim.sol diff --git a/contracts/interfaces/wonderland.sol b/contracts/interfaces/wonderland.sol index 4c5c7ea8d..7be2ced22 100644 --- a/contracts/interfaces/wonderland.sol +++ b/contracts/interfaces/wonderland.sol @@ -59,17 +59,11 @@ interface ITreasury { function mintRewards( address _recipient, uint _amount ) external; } -interface ITimeBondDepository { - function initializeBondTerms( - uint _controlVariable, - uint _minimumPrice, - uint _maxPayout, - uint _maxDebt, - uint _initialDebt, - uint32 _vestingTerm - ) external; - enum PARAMETER { VESTING, PAYOUT, DEBT, MINPRICE } +enum PARAMETER { VESTING, PAYOUT, DEBT, MINPRICE } + +interface ITimeBondDepository { + function initializeBondTerms(uint _controlVariable, uint _minimumPrice, uint _maxPayout, uint _maxDebt, uint _initialDebt, uint32 _vestingTerm) external; function setBondTerms ( PARAMETER _parameter, uint _input ) external; @@ -83,6 +77,15 @@ interface ITimeBondDepository { function stakeOrSend( address _recipient, bool _stake, uint _amount ) external returns ( uint ); +} + +interface ITimeTreasury { + function deposit( uint _amount, address _token, uint _profit ) external returns ( uint send_ ); + function withdraw( uint _amount, address _token ) external; + + function mintRewards( address _recipient, uint _amount ) external; + function valueOf( address _token, uint _amount ) external view returns ( uint value_ ); + } \ No newline at end of file diff --git a/contracts/strategies/strategy-time-farm.sol b/contracts/strategies/strategy-time-farm.sol index 78a63c799..01469bb20 100644 --- a/contracts/strategies/strategy-time-farm.sol +++ b/contracts/strategies/strategy-time-farm.sol @@ -3,26 +3,27 @@ pragma solidity ^0.6.7; import "./strategy-wonderland-base.sol"; -abstract contract StrategyTimeFarm is TimeBase{ +abstract contract TimeFarm is TimeBase{ - address public rewards = 0x4456B87Af11e87E329AB7d7C7A246ed1aC2168B9; + address public rewards; + address public treasury = 0x1c46450211CB2646cc1DA3c5242422967eD9e04c; + + + uint profit; uint256 public _initial; constructor( - address _rewards, - address _wantToken, + address _rewards, + address _mint, address _governance, address _strategist, address _controller, - address _timelock, - uint32 _epochLength, - uint _firstEpochNumber, - uint32 _firstEpochTime + address _timelock ) public - TimeBase(_wantToken, _governance, _strategist, _controller, _timelock, _epochLength, _firstEpochNumber, _firstEpochTime) + TimeBase(_mint, _governance, _strategist, _controller, _timelock) { - rewards = _rewards; + rewards = _rewards; } function balanceOfTime() public override view returns (uint256){ @@ -55,14 +56,21 @@ abstract contract StrategyTimeFarm is TimeBase{ // deposits the Time token in the staking contract function deposit () public override { // the amount of Time tokens that you want to stake - _initial = IERC20(Time).balanceOf(address(this)); - if (_initial > 0){ - IERC20(wantToken).safeApprove(rewards, 0); - IERC20(wantToken).safeApprove(rewards, _initial); - ITimeStaking(rewards).stake(_initial, address(this)); + uint256 _want = IERC20(Time).balanceOf(address(this)); + if (_want > 0){ + IERC20(Time).safeApprove(rewards, 0); + IERC20(Time).safeApprove(rewards, _want); + ITimeStaking(rewards).stake(_want, address(this)); } } + // deposits other asset to be minted into Time and then staked + function depositLP() public override { + uint256 _amount = IERC20(wantToken).balanceOf(address(this)); + ITimeTreasury(treasury).deposit(_amount, wantToken, profit); + deposit(); + } + /** @notice we have to restake time tokens whenever the epoch is over diff --git a/contracts/strategies/strategy-wonderland-base.sol b/contracts/strategies/strategy-wonderland-base.sol index abe18d374..9059c0030 100644 --- a/contracts/strategies/strategy-wonderland-base.sol +++ b/contracts/strategies/strategy-wonderland-base.sol @@ -65,24 +65,13 @@ abstract contract TimeBase { mapping(address => bool) public harvesters; - struct Epoch { - uint number; - uint distribute; - uint32 length; - uint32 endTime; - } - - Epoch public epoch; constructor ( address _wantToken, address _governance, address _strategist, address _controller, - address _timelock, - uint32 _epochLength, - uint _firstEpochNumber, - uint32 _firstEpochTime + address _timelock ) public { require(_wantToken != address(0)); require(_governance != address(0)); @@ -95,13 +84,6 @@ abstract contract TimeBase { strategist = _strategist; controller = _controller; timelock = _timelock; - - epoch = Epoch({ - length: _epochLength, - number: _firstEpochNumber, - endTime: _firstEpochTime, - distribute: 0 - }); } // **** Modifiers **** // @@ -117,14 +99,20 @@ abstract contract TimeBase { // **** Views **** // - function balanceOfWant() public view returns (uint256) { + function balanceOfWant() public view returns (uint256) { return IERC20(wantToken).balanceOf(address(this)); } - function balanceOfTime() public virtual view returns (uint256); + function balanceOfPool() public virtual view returns (uint256); + function balanceOf() public view returns (uint256) { + return balanceOfWant().add(balanceOfPool()); + } + function balanceOfTime() public virtual view returns (uint256); + function getName() external virtual pure returns (string memory); + function whitelistHarvester(address _harvester) external { require(msg.sender == governance || msg.sender == strategist, "not authorized"); @@ -187,6 +175,8 @@ abstract contract TimeBase { // **** State mutations **** // function deposit() public virtual; + function depositLP() public virtual; + // Controller only function for creating additional rewards from dust function withdraw(IERC20 _asset) external returns (uint256 balance) { require(msg.sender == controller, "!controller"); diff --git a/contracts/strategies/wonderland/strategy-time-mim.sol b/contracts/strategies/wonderland/strategy-time-mim.sol new file mode 100644 index 000000000..ea5d97f20 --- /dev/null +++ b/contracts/strategies/wonderland/strategy-time-mim.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.7; + +import "../strategy-time-farm.sol"; + +abstract contract StrategyTimeMim is TimeFarm { + + // want token for depositing into depositLP for minting Time + address public mim = 0x130966628846BFd36ff31a822705796e8cb8C18D; + + // staking contract for rewards + address public staking = 0x4456B87Af11e87E329AB7d7C7A246ed1aC2168B9; + + + constructor( + address _governance, + address _strategist, + address _controller, + address _timelock + ) + public + TimeFarm( + staking, + mim, + _governance, + _strategist, + _controller, + _timelock + ) + {} + + + // **** Views **** + + function getName() external pure override returns (string memory) { + return "StrategyTimeMim"; + } +} From fa90de5a5884ee611a0b1a089ac32ec7ea1c3941 Mon Sep 17 00:00:00 2001 From: Abigail Date: Mon, 29 Nov 2021 16:22:34 -0500 Subject: [PATCH 15/33] pause --- contracts/interfaces/wonderland.sol | 11 ++ .../traderJoe/snowglobe-joe-avax-craft.sol | 131 ++++++++++++++++++ contracts/strategies/strategy-time-farm.sol | 37 +++-- .../strategies/strategy-wonderland-base.sol | 7 +- 4 files changed, 172 insertions(+), 14 deletions(-) create mode 100644 contracts/snowglobes/traderJoe/snowglobe-joe-avax-craft.sol diff --git a/contracts/interfaces/wonderland.sol b/contracts/interfaces/wonderland.sol index 7be2ced22..1d00bd8fb 100644 --- a/contracts/interfaces/wonderland.sol +++ b/contracts/interfaces/wonderland.sol @@ -79,6 +79,9 @@ interface ITimeBondDepository { } + + +// needed and used interface ITimeTreasury { function deposit( uint _amount, address _token, uint _profit ) external returns ( uint send_ ); @@ -88,4 +91,12 @@ interface ITimeTreasury { function valueOf( address _token, uint _amount ) external view returns ( uint value_ ); +} + +interface IStaking { + function stake( uint _amount, address _recipient ) external returns ( bool ); +} + +interface IStakingHelper { + function stake( uint _amount, address _recipient ) external; } \ No newline at end of file diff --git a/contracts/snowglobes/traderJoe/snowglobe-joe-avax-craft.sol b/contracts/snowglobes/traderJoe/snowglobe-joe-avax-craft.sol new file mode 100644 index 000000000..93b6e82b8 --- /dev/null +++ b/contracts/snowglobes/traderJoe/snowglobe-joe-avax-craft.sol @@ -0,0 +1,131 @@ +// https://github.com/iearn-finance/vaults/blob/master/contracts/vaults/yVault.sol + +pragma solidity ^0.6.7; + +import "../../interfaces/controller.sol"; + +import "../../lib/erc20.sol"; +import "../../lib/safe-math.sol"; + +contract SnowGlobeJoeAvaxCraft is ERC20 { + using SafeERC20 for IERC20; + using Address for address; + using SafeMath for uint256; + + IERC20 public token; + + uint256 public min = 9500; + uint256 public constant max = 10000; + + address public governance; + address public timelock; + address public controller; + + constructor(address _token, address _governance, address _timelock, address _controller) + public + ERC20( + string(abi.encodePacked("freezing ", ERC20(_token).name())), + string(abi.encodePacked("s", ERC20(_token).symbol())) + ) + { + _setupDecimals(ERC20(_token).decimals()); + token = IERC20(_token); + governance = _governance; + timelock = _timelock; + controller = _controller; + } + + function balance() public view returns (uint256) { + return + token.balanceOf(address(this)).add( + IController(controller).balanceOf(address(token)) + ); + } + + function setMin(uint256 _min) external { + require(msg.sender == governance, "!governance"); + require(_min <= max, "numerator cannot be greater than denominator"); + min = _min; + } + + function setGovernance(address _governance) public { + require(msg.sender == governance, "!governance"); + governance = _governance; + } + + function setTimelock(address _timelock) public { + require(msg.sender == timelock, "!timelock"); + timelock = _timelock; + } + + function setController(address _controller) public { + require(msg.sender == timelock, "!timelock"); + controller = _controller; + } + + // Custom logic in here for how much the globes allows to be borrowed + // Sets minimum required on-hand to keep small withdrawals cheap + function available() public view returns (uint256) { + return token.balanceOf(address(this)).mul(min).div(max); + } + + function earn() public { + uint256 _bal = available(); + token.safeTransfer(controller, _bal); + IController(controller).earn(address(token), _bal); + } + + function depositAll() external { + deposit(token.balanceOf(msg.sender)); + } + + function deposit(uint256 _amount) public { + uint256 _pool = balance(); + uint256 _before = token.balanceOf(address(this)); + token.safeTransferFrom(msg.sender, address(this), _amount); + uint256 _after = token.balanceOf(address(this)); + _amount = _after.sub(_before); // Additional check for deflationary tokens + uint256 shares = 0; + if (totalSupply() == 0) { + shares = _amount; + } else { + shares = (_amount.mul(totalSupply())).div(_pool); + } + _mint(msg.sender, shares); + } + + function withdrawAll() external { + withdraw(balanceOf(msg.sender)); + } + + // Used to swap any borrowed reserve over the debt limit to liquidate to 'token' + function harvest(address reserve, uint256 amount) external { + require(msg.sender == controller, "!controller"); + require(reserve != address(token), "token"); + IERC20(reserve).safeTransfer(controller, amount); + } + + // No rebalance implementation for lower fees and faster swaps + function withdraw(uint256 _shares) public { + uint256 r = (balance().mul(_shares)).div(totalSupply()); + _burn(msg.sender, _shares); + + // Check balance + uint256 b = token.balanceOf(address(this)); + if (b < r) { + uint256 _withdraw = r.sub(b); + IController(controller).withdraw(address(token), _withdraw); + uint256 _after = token.balanceOf(address(this)); + uint256 _diff = _after.sub(b); + if (_diff < _withdraw) { + r = b.add(_diff); + } + } + + token.safeTransfer(msg.sender, r); + } + + function getRatio() public view returns (uint256) { + return balance().mul(1e18).div(totalSupply()); + } +} diff --git a/contracts/strategies/strategy-time-farm.sol b/contracts/strategies/strategy-time-farm.sol index 01469bb20..a4ceccc83 100644 --- a/contracts/strategies/strategy-time-farm.sol +++ b/contracts/strategies/strategy-time-farm.sol @@ -53,7 +53,7 @@ abstract contract TimeFarm is TimeBase{ ); } - // deposits the Time token in the staking contract + // Deposits the Time token in the staking contract function deposit () public override { // the amount of Time tokens that you want to stake uint256 _want = IERC20(Time).balanceOf(address(this)); @@ -64,23 +64,34 @@ abstract contract TimeFarm is TimeBase{ } } - // deposits other asset to be minted into Time and then staked - function depositLP() public override { - uint256 _amount = IERC20(wantToken).balanceOf(address(this)); - ITimeTreasury(treasury).deposit(_amount, wantToken, profit); - deposit(); + // Stakes Time payout in the automatically or returns to the user if they do not want to continue staking + function stakeOrSend ( address _recipient, bool _stake, uint _amount) public override returns (uint256) { + uint256 _want = IERC20(Time).balanceOf(address(this)); + // if user does not want to stake + if (!_stake) { + IERC20(Time).transfer( _recipient, _amount ); // send payout + }else { // if user wants to stake + if (useHelper) { // if stake warmup is 0 + IERC20(Time).approve(stakingHelper, _want); + IStakingHelper(stakingHelper).stake(_want, _recipient); + }else { + IERC20(Time).approve(rewards, _want); + IStaking(rewards).stake( _want, _recipient ); + } + } + + return _want; } + - /** - @notice we have to restake time tokens whenever the epoch is over - */ - function reStake() public override { - ITimeStaking(Time).rebase(); - deposit(); + // Deposits other asset to be minted into Time and then staked + function depositIntoTime() public override { + uint256 _amount = IERC20(wantToken).balanceOf(address(this)); + ITimeTreasury(treasury).deposit(_amount, wantToken, profit); + deposit(); } - /** calls the unstake function that rebases to get the right proportion of the treasury balancer, i.e. determine the amount of MEMOries tokens accumulated during vesting period. diff --git a/contracts/strategies/strategy-wonderland-base.sol b/contracts/strategies/strategy-wonderland-base.sol index 9059c0030..04702e640 100644 --- a/contracts/strategies/strategy-wonderland-base.sol +++ b/contracts/strategies/strategy-wonderland-base.sol @@ -25,6 +25,9 @@ abstract contract TimeBase { address public immutable Time = 0xb54f16fB19478766A268F172C9480f8da1a7c9C3; address public immutable Memories = 0x136Acd46C134E8269052c62A67042D6bDeDde3C9; + address public stakingHelper; // to stake and claim if no staking warmup + bool public useHelper; + // Dex address public constant joeRouter = 0x60aE616a2155Ee3d9A68541Ba4544862310933d4; @@ -175,7 +178,9 @@ abstract contract TimeBase { // **** State mutations **** // function deposit() public virtual; - function depositLP() public virtual; + function depositIntoTime() public virtual; + + function stakeOrSend ( address _recipient, bool _stake, uint _amount ) public virtual returns (uint256); // Controller only function for creating additional rewards from dust function withdraw(IERC20 _asset) external returns (uint256 balance) { From 803280f3ea0fd5bb5fe9ee2caf0e00fabb5d05c1 Mon Sep 17 00:00:00 2001 From: Abigail Date: Wed, 8 Dec 2021 16:50:25 -0500 Subject: [PATCH 16/33] pause --- contracts/strategies/strategy-time-farm.sol | 24 +--- .../strategies/strategy-wonderland-base.sol | 105 +++++++++++++++--- 2 files changed, 94 insertions(+), 35 deletions(-) diff --git a/contracts/strategies/strategy-time-farm.sol b/contracts/strategies/strategy-time-farm.sol index a4ceccc83..eaddb6a04 100644 --- a/contracts/strategies/strategy-time-farm.sol +++ b/contracts/strategies/strategy-time-farm.sol @@ -34,24 +34,6 @@ abstract contract TimeFarm is TimeBase{ return ITimeStaking(Time).index(); } - // **** State Mutations **** - - function _takeFeeTimeToSnob(uint256 _keep) internal { - address[] memory path = new address[](3); - path[0] = Time; - path[1] = wavax; - path[2] = snob; - IERC20(Time).safeApprove(joeRouter, 0); - IERC20(Time).safeApprove(joeRouter, _keep); - _swapTraderJoeWithPath(path, _keep); - uint256 _snob = IERC20(snob).balanceOf(address(this)); - uint256 _share = _snob.mul(revenueShare).div(revenueShareMax); - IERC20(snob).safeTransfer(feeDistributor, _share); - IERC20(snob).safeTransfer( - IController(controller).treasury(), - _snob.sub(_share) - ); - } // Deposits the Time token in the staking contract function deposit () public override { @@ -87,8 +69,8 @@ abstract contract TimeFarm is TimeBase{ // Deposits other asset to be minted into Time and then staked function depositIntoTime() public override { - uint256 _amount = IERC20(wantToken).balanceOf(address(this)); - ITimeTreasury(treasury).deposit(_amount, wantToken, profit); + uint256 _amount = IERC20(want).balanceOf(address(this)); + ITimeTreasury(treasury).deposit(_amount, want, profit); deposit(); } @@ -110,6 +92,8 @@ abstract contract TimeFarm is TimeBase{ } // Collect the time tokens ITimeStaking(Time).unstake(_amount, true); + + _distributePerformanceFeesAndDeposit(); } diff --git a/contracts/strategies/strategy-wonderland-base.sol b/contracts/strategies/strategy-wonderland-base.sol index 04702e640..adb56e39a 100644 --- a/contracts/strategies/strategy-wonderland-base.sol +++ b/contracts/strategies/strategy-wonderland-base.sol @@ -19,11 +19,12 @@ abstract contract TimeBase { using SafeERC20 for IERC20; // Tokens - address public wantToken; - address public wavax = 0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7; - address public snob = 0xC38f41A296A4493Ff429F1238e030924A1542e50; - address public immutable Time = 0xb54f16fB19478766A268F172C9480f8da1a7c9C3; - address public immutable Memories = 0x136Acd46C134E8269052c62A67042D6bDeDde3C9; + address public want; + address public constant joe = 0x6e84a6216eA6dACC71eE8E6b0a5B7322EEbC0fDd; + address public constant wavax = 0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7; + address public constant snob = 0xC38f41A296A4493Ff429F1238e030924A1542e50; + address public constant Time = 0xb54f16fB19478766A268F172C9480f8da1a7c9C3; + address public constant Memories = 0x136Acd46C134E8269052c62A67042D6bDeDde3C9; address public stakingHelper; // to stake and claim if no staking warmup bool public useHelper; @@ -70,19 +71,19 @@ abstract contract TimeBase { constructor ( - address _wantToken, + address _want, address _governance, address _strategist, address _controller, address _timelock ) public { - require(_wantToken != address(0)); + require(_want != address(0)); require(_governance != address(0)); require(_strategist != address(0)); require(_controller != address(0)); require(_timelock != address(0)); - wantToken = _wantToken; + want = _want; governance = _governance; strategist = _strategist; controller = _controller; @@ -103,7 +104,7 @@ abstract contract TimeBase { // **** Views **** // function balanceOfWant() public view returns (uint256) { - return IERC20(wantToken).balanceOf(address(this)); + return IERC20(want).balanceOf(address(this)); } function balanceOfPool() public virtual view returns (uint256); @@ -185,7 +186,7 @@ abstract contract TimeBase { // Controller only function for creating additional rewards from dust function withdraw(IERC20 _asset) external returns (uint256 balance) { require(msg.sender == controller, "!controller"); - require(wantToken != address(_asset), "want"); + require(want != address(_asset), "want"); balance = _asset.balanceOf(address(this)); _asset.safeTransfer(controller, balance); } @@ -193,7 +194,7 @@ abstract contract TimeBase { // Withdraw partial funds, normally used with a globe withdrawal function withdraw(uint256 _amount) external { require(msg.sender == controller, "!controller"); - uint256 _balance = IERC20(wantToken).balanceOf(address(this)); + uint256 _balance = IERC20(want).balanceOf(address(this)); if (_balance < _amount) { _amount = _withdrawSome(_amount.sub(_balance)); _amount = _amount.add(_balance); @@ -202,20 +203,20 @@ abstract contract TimeBase { uint256 _feeDev = _amount.mul(withdrawalDevFundFee).div( withdrawalDevFundMax ); - IERC20(wantToken).safeTransfer(IController(controller).devfund(), _feeDev); + IERC20(want).safeTransfer(IController(controller).devfund(), _feeDev); uint256 _feeTreasury = _amount.mul(withdrawalTreasuryFee).div( withdrawalTreasuryMax ); - IERC20(wantToken).safeTransfer( + IERC20(want).safeTransfer( IController(controller).treasury(), _feeTreasury ); - address _globe = IController(controller).globes(address(wantToken)); + address _globe = IController(controller).globes(address(want)); require(_globe != address(0), "!globe"); // additional protection so we don't burn the funds - IERC20(wantToken).safeTransfer(_globe, _amount.sub(_feeDev).sub(_feeTreasury)); + IERC20(want).safeTransfer(_globe, _amount.sub(_feeDev).sub(_feeTreasury)); } function harvest() public virtual; @@ -224,6 +225,42 @@ abstract contract TimeBase { function _withdrawSome(uint256 _amount) internal virtual returns (uint256); + // **** Internal functions **** + function _swapTraderJoe( + address _from, + address _to, + uint256 _amount + ) internal { + require(_to != address(0)); + // Swap with TraderJoe + IERC20(_from).safeApprove(joeRouter, 0); + IERC20(_from).safeApprove(joeRouter, _amount); + address[] memory path; + if (_from == joe || _to == joe) { + path = new address[](2); + path[0] = _from; + path[1] = _to; + } + else if (_from == wavax || _to == wavax) { + path = new address[](2); + path[0] = _from; + path[1] = _to; + } + else { + path = new address[](3); + path[0] = _from; + path[1] = wavax; + path[2] = _to; + } + IJoeRouter(joeRouter).swapExactTokensForTokens( + _amount, + 0, + path, + address(this), + now.add(60) + ); + } + function _swapTraderJoeWithPath(address[] memory path, uint256 _amount) internal { @@ -238,4 +275,42 @@ abstract contract TimeBase { ); } + function _takeFeeTimeToSnob(uint256 _keep) internal { + address[] memory path = new address[](3); + path[0] = Time; + path[1] = wavax; + path[2] = snob; + IERC20(Time).safeApprove(joeRouter, 0); + IERC20(Time).safeApprove(joeRouter, _keep); + _swapTraderJoeWithPath(path, _keep); + uint256 _snob = IERC20(snob).balanceOf(address(this)); + uint256 _share = _snob.mul(revenueShare).div(revenueShareMax); + IERC20(snob).safeTransfer(feeDistributor, _share); + IERC20(snob).safeTransfer( + IController(controller).treasury(), + _snob.sub(_share) + ); + } + + + function _distributePerformanceFeesAndDeposit() internal { + uint256 _want = IERC20(want).balanceOf(address(this)); + + if (_want > 0) { + // Redeposit into contract + IERC20(want).safeTransfer( + IController(controller).treasury(), + _want.mul(performanceTreasuryFee).div(performanceTreasuryMax) + ); + + // Performance fee + IERC20(want).safeTransfer( + IController(controller).devfund(), + _want.mul(performanceDevFee).div(performanceDevMax) + ); + + deposit(); + } + } + } \ No newline at end of file From 61df5c9ac96df8c644530714418769e00aff6e64 Mon Sep 17 00:00:00 2001 From: Abigail Date: Wed, 8 Dec 2021 16:51:27 -0500 Subject: [PATCH 17/33] pause --- contracts/interfaces/wonderland.sol | 17 +++++++++++++++++ contracts/strategies/strategy-time-farm.sol | 5 +++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/contracts/interfaces/wonderland.sol b/contracts/interfaces/wonderland.sol index 1d00bd8fb..1673c424f 100644 --- a/contracts/interfaces/wonderland.sol +++ b/contracts/interfaces/wonderland.sol @@ -28,14 +28,25 @@ interface IWarmup { enum CONTRACTS { DISTRIBUTOR, WARMUP, LOCKER } interface ITimeStaking { + /** @notice stake Time to enter warmup + @param _amount uint + @return bool + */ function stake(uint _amount, address _recipient) external view returns ( bool ); + + /** + @notice retrieve MEMO from warmup + @param _recipient address + */ function claim(address _recipient) external; + // returns the MEMO index, which tracks rebase growth function index() external view returns ( uint ); function unstake(uint256 _amount, bool _trigger) external; + // returns contract Time holdings, including bonuses provided function contractBalance() external view returns ( uint ); function forfeit() external; @@ -48,8 +59,14 @@ interface ITimeStaking { function setWarmup( uint _warmupPeriod) external; + /** + @notice sets the contract address for LP staking + @param _contract address + */ function setContract( CONTRACTS _contract, address _address ) external; + + // trigger rebase if epoch over function rebase() external; } diff --git a/contracts/strategies/strategy-time-farm.sol b/contracts/strategies/strategy-time-farm.sol index eaddb6a04..97970d6ef 100644 --- a/contracts/strategies/strategy-time-farm.sol +++ b/contracts/strategies/strategy-time-farm.sol @@ -70,8 +70,9 @@ abstract contract TimeFarm is TimeBase{ // Deposits other asset to be minted into Time and then staked function depositIntoTime() public override { uint256 _amount = IERC20(want).balanceOf(address(this)); - ITimeTreasury(treasury).deposit(_amount, want, profit); - deposit(); + uint256 _profit = ITimeTreasury(treasury).valueOf(Time, _amount); + ITimeTreasury(treasury).deposit(_amount, want, _profit); + //deposit(); } /** From fce9d3c2fad47ddf6e9ec776a37013f72d641769 Mon Sep 17 00:00:00 2001 From: Abigail Date: Thu, 9 Dec 2021 12:07:10 -0500 Subject: [PATCH 18/33] wonderland testing --- contracts/interfaces/wonderland.sol | 61 ++++++++++--------- contracts/strategies/strategy-time-farm.sol | 56 ++++++----------- .../strategies/strategy-wonderland-base.sol | 22 ++++++- .../wonderland/strategy-time-mim.sol | 3 - 4 files changed, 67 insertions(+), 75 deletions(-) diff --git a/contracts/interfaces/wonderland.sol b/contracts/interfaces/wonderland.sol index 1673c424f..c1f608d02 100644 --- a/contracts/interfaces/wonderland.sol +++ b/contracts/interfaces/wonderland.sol @@ -25,50 +25,50 @@ interface IWarmup { function retrieve( address staker_, uint amount_ ) external; } -enum CONTRACTS { DISTRIBUTOR, WARMUP, LOCKER } +// enum CONTRACTS { DISTRIBUTOR, WARMUP, LOCKER } -interface ITimeStaking { - /** @notice stake Time to enter warmup - @param _amount uint - @return bool - */ - function stake(uint _amount, address _recipient) external view returns ( bool ); +// interface ITimeStaking { +// /** @notice stake Time to enter warmup +// @param _amount uint +// @return bool +// */ +// function stake(uint _amount, address _recipient) external view returns ( bool ); - /** - @notice retrieve MEMO from warmup - @param _recipient address - */ - function claim(address _recipient) external; +// /** +// @notice retrieve MEMO from warmup +// @param _recipient address +// */ +// function claim(address _recipient) external; - // returns the MEMO index, which tracks rebase growth - function index() external view returns ( uint ); +// // returns the MEMO index, which tracks rebase growth +// function index() external view returns ( uint ); - function unstake(uint256 _amount, bool _trigger) external; +// function unstake(uint256 _amount, bool _trigger) external; - // returns contract Time holdings, including bonuses provided - function contractBalance() external view returns ( uint ); +// // returns contract Time holdings, including bonuses provided +// function contractBalance() external view returns ( uint ); - function forfeit() external; +// function forfeit() external; - function giveLockBonus( uint _amount) external; +// function giveLockBonus( uint _amount) external; - function returnLockBonus(uint _amount) external; +// function returnLockBonus(uint _amount) external; - function toggleDepositLock() external; +// function toggleDepositLock() external; - function setWarmup( uint _warmupPeriod) external; +// function setWarmup( uint _warmupPeriod) external; - /** - @notice sets the contract address for LP staking - @param _contract address - */ - function setContract( CONTRACTS _contract, address _address ) external; +// /** +// @notice sets the contract address for LP staking +// @param _contract address +// */ +// function setContract( CONTRACTS _contract, address _address ) external; - // trigger rebase if epoch over - function rebase() external; -} +// // trigger rebase if epoch over +// function rebase() external; +// } interface ITreasury { function deposit( uint _amount, address _token, uint _profit ) external returns ( bool ); @@ -112,6 +112,7 @@ interface ITimeTreasury { interface IStaking { function stake( uint _amount, address _recipient ) external returns ( bool ); + function claim( address _recipient ) external; } interface IStakingHelper { diff --git a/contracts/strategies/strategy-time-farm.sol b/contracts/strategies/strategy-time-farm.sol index 97970d6ef..99b813c8e 100644 --- a/contracts/strategies/strategy-time-farm.sol +++ b/contracts/strategies/strategy-time-farm.sol @@ -7,6 +7,7 @@ abstract contract TimeFarm is TimeBase{ address public rewards; address public treasury = 0x1c46450211CB2646cc1DA3c5242422967eD9e04c; + address bondToken; uint profit; @@ -26,12 +27,8 @@ abstract contract TimeFarm is TimeBase{ rewards = _rewards; } - function balanceOfTime() public override view returns (uint256){ - return ITimeStaking(Time).contractBalance(); - } - function getHarvestable() external view returns (uint256) { - return ITimeStaking(Time).index(); + return IMemo(Memories).index(); } @@ -42,37 +39,17 @@ abstract contract TimeFarm is TimeBase{ if (_want > 0){ IERC20(Time).safeApprove(rewards, 0); IERC20(Time).safeApprove(rewards, _want); - ITimeStaking(rewards).stake(_want, address(this)); - } - } - - // Stakes Time payout in the automatically or returns to the user if they do not want to continue staking - function stakeOrSend ( address _recipient, bool _stake, uint _amount) public override returns (uint256) { - uint256 _want = IERC20(Time).balanceOf(address(this)); - // if user does not want to stake - if (!_stake) { - IERC20(Time).transfer( _recipient, _amount ); // send payout - }else { // if user wants to stake - if (useHelper) { // if stake warmup is 0 - IERC20(Time).approve(stakingHelper, _want); - IStakingHelper(stakingHelper).stake(_want, _recipient); - }else { - IERC20(Time).approve(rewards, _want); - IStaking(rewards).stake( _want, _recipient ); - } + IStaking(rewards).stake(_want, address(this)); } - - return _want; } - - - // Deposits other asset to be minted into Time and then staked + // Bond deposit so that we can get discounted time minted and staked function depositIntoTime() public override { - uint256 _amount = IERC20(want).balanceOf(address(this)); - uint256 _profit = ITimeTreasury(treasury).valueOf(Time, _amount); - ITimeTreasury(treasury).deposit(_amount, want, _profit); - //deposit(); + uint256 _amount = IERC20(bondToken).balanceOf(address(this)); + + uint256 _profit = ITreasury(treasury).valueOf(bondToken, _amount); + ITreasury(treasury).deposit(_amount, want, _profit); + } /** @@ -81,8 +58,9 @@ abstract contract TimeFarm is TimeBase{ As well transfers MEMOries token to Time tokens */ function harvest() public override onlyBenevolent { - - uint256 _amount = ITimeStaking(Time).index(); + + // find how much we have grown by at a particular epoch period + uint256 _amount = IMemo(Memories).index(); if (_amount > 0) { // 10% locked up for future governance @@ -91,13 +69,13 @@ abstract contract TimeFarm is TimeBase{ _takeFeeTimeToSnob(_keep); } } - // Collect the time tokens - ITimeStaking(Time).unstake(_amount, true); - - _distributePerformanceFeesAndDeposit(); - } + // restake or unstake the current value left + _amount = IERC20(Memories).balanceOf(address(this)); + bool _stake; + stakeOrSend(address(this), _stake, _amount); + } } \ No newline at end of file diff --git a/contracts/strategies/strategy-wonderland-base.sol b/contracts/strategies/strategy-wonderland-base.sol index adb56e39a..b80a50970 100644 --- a/contracts/strategies/strategy-wonderland-base.sol +++ b/contracts/strategies/strategy-wonderland-base.sol @@ -18,12 +18,16 @@ abstract contract TimeBase { using SafeMath for uint32; using SafeERC20 for IERC20; + + // staking contract for rewards + address public staking = 0x4456B87Af11e87E329AB7d7C7A246ed1aC2168B9; + // Tokens address public want; address public constant joe = 0x6e84a6216eA6dACC71eE8E6b0a5B7322EEbC0fDd; address public constant wavax = 0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7; address public constant snob = 0xC38f41A296A4493Ff429F1238e030924A1542e50; - address public constant Time = 0xb54f16fB19478766A268F172C9480f8da1a7c9C3; + address public constant Time = 0xb54f16fB19478766A268F172C9480f8da1a7c9C3; // token given as payment for bond address public constant Memories = 0x136Acd46C134E8269052c62A67042D6bDeDde3C9; address public stakingHelper; // to stake and claim if no staking warmup @@ -181,8 +185,6 @@ abstract contract TimeBase { function depositIntoTime() public virtual; - function stakeOrSend ( address _recipient, bool _stake, uint _amount ) public virtual returns (uint256); - // Controller only function for creating additional rewards from dust function withdraw(IERC20 _asset) external returns (uint256 balance) { require(msg.sender == controller, "!controller"); @@ -292,6 +294,20 @@ abstract contract TimeBase { ); } + function stakeOrSend( address _recipient, bool _stake, uint _amount ) internal returns ( uint ) { + if ( !_stake ) { // if user does not want to stake + IERC20(Time).transfer( _recipient, _amount ); // send payout + } else { // if user wants to stake + if ( useHelper ) { // use if staking warmup is 0 + IERC20(Time).approve( address(stakingHelper), _amount ); + IStakingHelper(stakingHelper).stake( _amount, _recipient ); + } else { + IERC20(Time).approve( address(staking), _amount ); + IStaking(staking).stake( _amount, _recipient ); + } + } + return _amount; + } function _distributePerformanceFeesAndDeposit() internal { uint256 _want = IERC20(want).balanceOf(address(this)); diff --git a/contracts/strategies/wonderland/strategy-time-mim.sol b/contracts/strategies/wonderland/strategy-time-mim.sol index ea5d97f20..f9beadefc 100644 --- a/contracts/strategies/wonderland/strategy-time-mim.sol +++ b/contracts/strategies/wonderland/strategy-time-mim.sol @@ -8,9 +8,6 @@ abstract contract StrategyTimeMim is TimeFarm { // want token for depositing into depositLP for minting Time address public mim = 0x130966628846BFd36ff31a822705796e8cb8C18D; - // staking contract for rewards - address public staking = 0x4456B87Af11e87E329AB7d7C7A246ed1aC2168B9; - constructor( address _governance, From 8a2eeb5236fc6ef0b98eb79ee9f6c9daaf01b1ed Mon Sep 17 00:00:00 2001 From: Abigail Date: Thu, 9 Dec 2021 23:10:00 -0500 Subject: [PATCH 19/33] interface update --- contracts/interfaces/wonderland.sol | 60 ++--------------------------- 1 file changed, 3 insertions(+), 57 deletions(-) diff --git a/contracts/interfaces/wonderland.sol b/contracts/interfaces/wonderland.sol index c1f608d02..26e03c748 100644 --- a/contracts/interfaces/wonderland.sol +++ b/contracts/interfaces/wonderland.sol @@ -25,50 +25,6 @@ interface IWarmup { function retrieve( address staker_, uint amount_ ) external; } -// enum CONTRACTS { DISTRIBUTOR, WARMUP, LOCKER } - -// interface ITimeStaking { -// /** @notice stake Time to enter warmup -// @param _amount uint -// @return bool -// */ -// function stake(uint _amount, address _recipient) external view returns ( bool ); - - -// /** -// @notice retrieve MEMO from warmup -// @param _recipient address -// */ -// function claim(address _recipient) external; - -// // returns the MEMO index, which tracks rebase growth -// function index() external view returns ( uint ); - -// function unstake(uint256 _amount, bool _trigger) external; - -// // returns contract Time holdings, including bonuses provided -// function contractBalance() external view returns ( uint ); - -// function forfeit() external; - -// function giveLockBonus( uint _amount) external; - -// function returnLockBonus(uint _amount) external; - -// function toggleDepositLock() external; - -// function setWarmup( uint _warmupPeriod) external; - -// /** -// @notice sets the contract address for LP staking -// @param _contract address -// */ -// function setContract( CONTRACTS _contract, address _address ) external; - - -// // trigger rebase if epoch over -// function rebase() external; -// } interface ITreasury { function deposit( uint _amount, address _token, uint _profit ) external returns ( bool ); @@ -93,21 +49,11 @@ interface ITimeBondDepository { function redeem( address _recipient, bool _stake ) external returns ( uint ); function stakeOrSend( address _recipient, bool _stake, uint _amount ) external returns ( uint ); - } - - -// needed and used -interface ITimeTreasury { - function deposit( uint _amount, address _token, uint _profit ) external returns ( uint send_ ); - - function withdraw( uint _amount, address _token ) external; - - function mintRewards( address _recipient, uint _amount ) external; - - function valueOf( address _token, uint _amount ) external view returns ( uint value_ ); - +interface ITimeStaking { + function rebase() external; + function unstake( uint _amount, bool _trigger) external; } interface IStaking { From bd399bbe5f550290c46adb8b31cd1afa51d68ed1 Mon Sep 17 00:00:00 2001 From: Abigail Date: Thu, 9 Dec 2021 23:13:35 -0500 Subject: [PATCH 20/33] time-avax --- .../wonderland/strategy-time-avax.sol | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 contracts/strategies/wonderland/strategy-time-avax.sol diff --git a/contracts/strategies/wonderland/strategy-time-avax.sol b/contracts/strategies/wonderland/strategy-time-avax.sol new file mode 100644 index 000000000..ecc399d9f --- /dev/null +++ b/contracts/strategies/wonderland/strategy-time-avax.sol @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.7; + +import "../strategy-time-farm.sol"; + +abstract contract StrategyTimeAvax is TimeFarm { + + // want/lp token for depositing into depositLP for minting Time + address public avax_time_lp = 0xf64e1c5B6E17031f5504481Ac8145F4c3eab4917; + address public avaxTimeBond = 0xc26850686ce755FFb8690EA156E5A6cf03DcBDE1; + + + constructor( + address _governance, + address _strategist, + address _controller, + address _timelock + ) + public + TimeFarm( + avaxTimeBond, + avax_time_lp, + _governance, + _strategist, + _controller, + _timelock + ) + {} + + // Deposit bond (lp or other token) so that we can get mint Time at a discount and autostake + function depositBond() public override { + uint256 _wavax = IERC20(wavax).balanceOf(address(this)); + uint256 _time = IERC20(time).balanceOf(address(this)); + + if (_wavax > 0 && _time > 0){ + IERC20(wavax).safeApprove(joeRouter, 0); + IERC20(wavax).safeApprove(joeRouter, _wavax); + + IERC20(time).safeApprove(joeRouter, 0); + IERC20(time).safeApprove(joeRouter, _time); + + // Adds in liquidity for TIME/AVAX + IJoeRouter(joeRouter).addLiquidity( + wavax, + time, + _wavax, + _time, + 0, + 0, + address(this), + now + 60 + ); + } + + uint256 _amount = IERC20(want).balanceOf(address(this)); + + IJoePair(avax_time_lp).approve(avaxTimeBond, _amount); + + ITimeBondDepository(avaxTimeBond).deposit(_amount, maxPrice, address(this)); + ITimeBondDepository(avaxTimeBond).redeem(address(this), _stake); + + _initialMemo = IERC20(memo).balanceOf(address(this)); + } + + // **** Views **** + + function getName() external pure override returns (string memory) { + return "StrategyTimeAvax"; + } +} From 90e23bf24b8d7077e1473cac365c3de8a98fca64 Mon Sep 17 00:00:00 2001 From: Abigail Date: Thu, 9 Dec 2021 23:31:53 -0500 Subject: [PATCH 21/33] time-avax --- .../wonderland/strategy-time-avax.sol | 43 ++++++------------- 1 file changed, 13 insertions(+), 30 deletions(-) diff --git a/contracts/strategies/wonderland/strategy-time-avax.sol b/contracts/strategies/wonderland/strategy-time-avax.sol index ecc399d9f..c9f4129a8 100644 --- a/contracts/strategies/wonderland/strategy-time-avax.sol +++ b/contracts/strategies/wonderland/strategy-time-avax.sol @@ -5,9 +5,8 @@ import "../strategy-time-farm.sol"; abstract contract StrategyTimeAvax is TimeFarm { - // want/lp token for depositing into depositLP for minting Time - address public avax_time_lp = 0xf64e1c5B6E17031f5504481Ac8145F4c3eab4917; - address public avaxTimeBond = 0xc26850686ce755FFb8690EA156E5A6cf03DcBDE1; + // want token for depositing into depositLP for minting Time + address avaxBond = 0xE02B1AA2c4BE73093BE79d763fdFFC0E3cf67318; constructor( @@ -18,8 +17,8 @@ abstract contract StrategyTimeAvax is TimeFarm { ) public TimeFarm( - avaxTimeBond, - avax_time_lp, + avaxBond, + wavax, _governance, _strategist, _controller, @@ -27,37 +26,21 @@ abstract contract StrategyTimeAvax is TimeFarm { ) {} - // Deposit bond (lp or other token) so that we can get mint Time at a discount and autostake + // Deposit bond (lp or other token) so that we can get mint Time at a discount and autostake function depositBond() public override { - uint256 _wavax = IERC20(wavax).balanceOf(address(this)); - uint256 _time = IERC20(time).balanceOf(address(this)); - - if (_wavax > 0 && _time > 0){ - IERC20(wavax).safeApprove(joeRouter, 0); - IERC20(wavax).safeApprove(joeRouter, _wavax); - - IERC20(time).safeApprove(joeRouter, 0); - IERC20(time).safeApprove(joeRouter, _time); - - // Adds in liquidity for TIME/AVAX - IJoeRouter(joeRouter).addLiquidity( - wavax, - time, - _wavax, - _time, - 0, - 0, - address(this), - now + 60 - ); + // Wrap the avax + uint256 _avax = address(this).balance; + if (_avax > 0) { + WAVAX(wavax).deposit{value: _avax}(); } uint256 _amount = IERC20(want).balanceOf(address(this)); - IJoePair(avax_time_lp).approve(avaxTimeBond, _amount); + IERC20(want).safeApprove(avaxBond, 0); + IERC20(want).safeApprove(avaxBond, _amount); - ITimeBondDepository(avaxTimeBond).deposit(_amount, maxPrice, address(this)); - ITimeBondDepository(avaxTimeBond).redeem(address(this), _stake); + ITimeBondDepository(avaxBond).deposit(_amount, maxPrice, address(this)); + ITimeBondDepository(avaxBond).redeem(address(this), _stake); _initialMemo = IERC20(memo).balanceOf(address(this)); } From c83c3a325d6e585c67a6c1872a1a2bc974a97fdb Mon Sep 17 00:00:00 2001 From: Abigail Date: Thu, 9 Dec 2021 23:32:23 -0500 Subject: [PATCH 22/33] time-avax-time --- .../wonderland/strategy-time-avax-time.sol | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 contracts/strategies/wonderland/strategy-time-avax-time.sol diff --git a/contracts/strategies/wonderland/strategy-time-avax-time.sol b/contracts/strategies/wonderland/strategy-time-avax-time.sol new file mode 100644 index 000000000..09223fee8 --- /dev/null +++ b/contracts/strategies/wonderland/strategy-time-avax-time.sol @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.7; + +import "../strategy-time-farm.sol"; + +abstract contract StrategyTimeAvaxTime is TimeFarm { + + // want/lp token for depositing into depositLP for minting Time + address public avax_time_lp = 0xf64e1c5B6E17031f5504481Ac8145F4c3eab4917; + address public avaxTimeBond = 0xc26850686ce755FFb8690EA156E5A6cf03DcBDE1; + + + constructor( + address _governance, + address _strategist, + address _controller, + address _timelock + ) + public + TimeFarm( + avaxTimeBond, + avax_time_lp, + _governance, + _strategist, + _controller, + _timelock + ) + {} + + // Deposit bond (lp or other token) so that we can get mint Time at a discount and autostake + function depositBond() public override { + // Wrap the avax + uint256 _avax = address(this).balance; + if (_avax > 0) { + WAVAX(wavax).deposit{value: _avax}(); + } + + uint256 _wavax = IERC20(wavax).balanceOf(address(this)); + uint256 _time = IERC20(time).balanceOf(address(this)); + + if (_wavax > 0 && _time > 0){ + IERC20(wavax).safeApprove(joeRouter, 0); + IERC20(wavax).safeApprove(joeRouter, _wavax); + + IERC20(time).safeApprove(joeRouter, 0); + IERC20(time).safeApprove(joeRouter, _time); + + // Adds in liquidity for TIME/AVAX + IJoeRouter(joeRouter).addLiquidity( + wavax, + time, + _wavax, + _time, + 0, + 0, + address(this), + now + 60 + ); + } + + uint256 _amount = IERC20(want).balanceOf(address(this)); + + IJoePair(avax_time_lp).approve(avaxTimeBond, _amount); + + ITimeBondDepository(avaxTimeBond).deposit(_amount, maxPrice, address(this)); + ITimeBondDepository(avaxTimeBond).redeem(address(this), _stake); + + _initialMemo = IERC20(memo).balanceOf(address(this)); + } + + // **** Views **** + + function getName() external pure override returns (string memory) { + return "StrategyTimeAvaxTime"; + } +} From d8c75f6c4a41b0c7210e992558189404f621e5ed Mon Sep 17 00:00:00 2001 From: Abigail Date: Thu, 9 Dec 2021 23:51:05 -0500 Subject: [PATCH 23/33] wonderland base --- .../strategies/strategy-wonderland-base.sol | 48 +++++++++---------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/contracts/strategies/strategy-wonderland-base.sol b/contracts/strategies/strategy-wonderland-base.sol index b80a50970..e4cefe529 100644 --- a/contracts/strategies/strategy-wonderland-base.sol +++ b/contracts/strategies/strategy-wonderland-base.sol @@ -10,6 +10,7 @@ import "../interfaces/globe.sol"; import "../interfaces/joe.sol"; import "../interfaces/wonderland.sol"; import "../interfaces/controller.sol"; +import "../interfaces/wavax.sol"; //Wonderland Strategy Contract Basics abstract contract TimeBase { @@ -20,18 +21,22 @@ abstract contract TimeBase { // staking contract for rewards - address public staking = 0x4456B87Af11e87E329AB7d7C7A246ed1aC2168B9; + address public staking = 0x4456B87Af11e87E329AB7d7C7A246ed1aC2168B9; + + uint256 public maxPrice; + // Tokens - address public want; + address public want; address public constant joe = 0x6e84a6216eA6dACC71eE8E6b0a5B7322EEbC0fDd; address public constant wavax = 0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7; address public constant snob = 0xC38f41A296A4493Ff429F1238e030924A1542e50; - address public constant Time = 0xb54f16fB19478766A268F172C9480f8da1a7c9C3; // token given as payment for bond - address public constant Memories = 0x136Acd46C134E8269052c62A67042D6bDeDde3C9; + address public constant time = 0xb54f16fB19478766A268F172C9480f8da1a7c9C3; // token given as payment for bond + address public constant memo = 0x136Acd46C134E8269052c62A67042D6bDeDde3C9; - address public stakingHelper; // to stake and claim if no staking warmup + address public stakingHelper = 0x096BBfB78311227b805c968b070a81D358c13379; // to stake and claim if no staking warmup bool public useHelper; + bool _stake; // Dex address public constant joeRouter = 0x60aE616a2155Ee3d9A68541Ba4544862310933d4; @@ -117,7 +122,7 @@ abstract contract TimeBase { return balanceOfWant().add(balanceOfPool()); } - function balanceOfTime() public virtual view returns (uint256); + function balanceOfTime() public virtual view returns (uint256); function getName() external virtual pure returns (string memory); @@ -183,7 +188,7 @@ abstract contract TimeBase { // **** State mutations **** // function deposit() public virtual; - function depositIntoTime() public virtual; + function depositBond() public virtual; // Controller only function for creating additional rewards from dust function withdraw(IERC20 _asset) external returns (uint256 balance) { @@ -223,7 +228,9 @@ abstract contract TimeBase { function harvest() public virtual; - function reStake() public virtual; + function _withdrawAll() internal { + _withdrawSome(balanceOfPool()); + } function _withdrawSome(uint256 _amount) internal virtual returns (uint256); @@ -278,12 +285,16 @@ abstract contract TimeBase { } function _takeFeeTimeToSnob(uint256 _keep) internal { + IERC20(memo).safeApprove(staking, 0); + IERC20(memo).safeApprove(staking, _keep); + ITimeStaking(staking).unstake(_keep, true); + address[] memory path = new address[](3); - path[0] = Time; + path[0] = time; path[1] = wavax; path[2] = snob; - IERC20(Time).safeApprove(joeRouter, 0); - IERC20(Time).safeApprove(joeRouter, _keep); + IERC20(time).safeApprove(joeRouter, 0); + IERC20(time).safeApprove(joeRouter, _keep); _swapTraderJoeWithPath(path, _keep); uint256 _snob = IERC20(snob).balanceOf(address(this)); uint256 _share = _snob.mul(revenueShare).div(revenueShareMax); @@ -294,21 +305,6 @@ abstract contract TimeBase { ); } - function stakeOrSend( address _recipient, bool _stake, uint _amount ) internal returns ( uint ) { - if ( !_stake ) { // if user does not want to stake - IERC20(Time).transfer( _recipient, _amount ); // send payout - } else { // if user wants to stake - if ( useHelper ) { // use if staking warmup is 0 - IERC20(Time).approve( address(stakingHelper), _amount ); - IStakingHelper(stakingHelper).stake( _amount, _recipient ); - } else { - IERC20(Time).approve( address(staking), _amount ); - IStaking(staking).stake( _amount, _recipient ); - } - } - return _amount; - } - function _distributePerformanceFeesAndDeposit() internal { uint256 _want = IERC20(want).balanceOf(address(this)); From 188c580cb35c2f1b77ad2366fe9a6ef46a0478ef Mon Sep 17 00:00:00 2001 From: Abigail Date: Thu, 9 Dec 2021 23:51:27 -0500 Subject: [PATCH 24/33] time-farm --- contracts/strategies/strategy-time-farm.sol | 70 ++++++++++----------- 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/contracts/strategies/strategy-time-farm.sol b/contracts/strategies/strategy-time-farm.sol index 99b813c8e..140c2bf6b 100644 --- a/contracts/strategies/strategy-time-farm.sol +++ b/contracts/strategies/strategy-time-farm.sol @@ -5,62 +5,59 @@ import "./strategy-wonderland-base.sol"; abstract contract TimeFarm is TimeBase{ - address public rewards; address public treasury = 0x1c46450211CB2646cc1DA3c5242422967eD9e04c; - address bondToken; + + uint256 public _initialMemo; + address public bond; uint profit; uint256 public _initial; constructor( - address _rewards, - address _mint, + address _bond, + address _want, address _governance, address _strategist, address _controller, address _timelock ) public - TimeBase(_mint, _governance, _strategist, _controller, _timelock) + TimeBase(_want, _governance, _strategist, _controller, _timelock) { - rewards = _rewards; + bond = _bond; } - function getHarvestable() external view returns (uint256) { - return IMemo(Memories).index(); + function balanceOfPool() public view override returns (uint256) { + uint256 amount = IMemo(memo).balanceOf(address(this)); + return amount; } - // Deposits the Time token in the staking contract function deposit () public override { // the amount of Time tokens that you want to stake - uint256 _want = IERC20(Time).balanceOf(address(this)); - if (_want > 0){ - IERC20(Time).safeApprove(rewards, 0); - IERC20(Time).safeApprove(rewards, _want); - IStaking(rewards).stake(_want, address(this)); + uint256 _amount = IERC20(time).balanceOf(address(this)); + + if (_amount > 0){ + if ( useHelper ) { // use if staking warmup is 0 + IERC20(time).safeApprove( address(stakingHelper), 0 ); + IERC20(time).safeApprove( address(stakingHelper), _amount ); + IStakingHelper(stakingHelper).stake( _amount, address(this) ); + } else { + IERC20(time).safeApprove( address(staking), 0 ); + IERC20(time).safeApprove( address(staking), _amount ); + IStaking(staking).stake( _amount, address(this) ); + } } + _initialMemo = IERC20(memo).balanceOf(address(this)); } - // Bond deposit so that we can get discounted time minted and staked - function depositIntoTime() public override { - uint256 _amount = IERC20(bondToken).balanceOf(address(this)); - - uint256 _profit = ITreasury(treasury).valueOf(bondToken, _amount); - ITreasury(treasury).deposit(_amount, want, _profit); - - } - - /** - calls the unstake function that rebases to get the right proportion of the treasury balancer, - i.e. determine the amount of MEMOries tokens accumulated during vesting period. - As well transfers MEMOries token to Time tokens - */ + function harvest() public override onlyBenevolent { - - // find how much we have grown by at a particular epoch period - uint256 _amount = IMemo(Memories).index(); + ITimeStaking(staking).rebase(); + + uint256 _rebaseMemo = IERC20(memo).balanceOf(address(this)); + uint _amount = _rebaseMemo.sub(_initialMemo); if (_amount > 0) { // 10% locked up for future governance @@ -69,13 +66,14 @@ abstract contract TimeFarm is TimeBase{ _takeFeeTimeToSnob(_keep); } } + } - // restake or unstake the current value left - _amount = IERC20(Memories).balanceOf(address(this)); + function _withdrawSome(uint256 _amount) internal override returns (uint256) { + IERC20(memo).safeApprove(staking, 0); + IERC20(memo).safeApprove(staking, _amount); + ITimeStaking(staking).unstake(_amount, true); - bool _stake; - stakeOrSend(address(this), _stake, _amount); + return _amount; } - } \ No newline at end of file From 276c90a97fa8f377bc02e94df2cd862fc76b6d2e Mon Sep 17 00:00:00 2001 From: Abigail Date: Thu, 9 Dec 2021 23:52:40 -0500 Subject: [PATCH 25/33] time-mim --- .../strategies/wonderland/strategy-time-mim.sol | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/contracts/strategies/wonderland/strategy-time-mim.sol b/contracts/strategies/wonderland/strategy-time-mim.sol index f9beadefc..ba5aec8ef 100644 --- a/contracts/strategies/wonderland/strategy-time-mim.sol +++ b/contracts/strategies/wonderland/strategy-time-mim.sol @@ -7,6 +7,7 @@ abstract contract StrategyTimeMim is TimeFarm { // want token for depositing into depositLP for minting Time address public mim = 0x130966628846BFd36ff31a822705796e8cb8C18D; + address mimBond; constructor( @@ -17,7 +18,7 @@ abstract contract StrategyTimeMim is TimeFarm { ) public TimeFarm( - staking, + mimBond, mim, _governance, _strategist, @@ -25,7 +26,19 @@ abstract contract StrategyTimeMim is TimeFarm { _timelock ) {} - + + // Deposit bond (lp or other token) so that we can get mint Time at a discount and autostake + function depositBond() public override { + uint256 _amount = IERC20(want).balanceOf(address(this)); + + IERC20(want).safeApprove(mimBond, 0); + IERC20(want).safeApprove(mimBond, _amount); + + ITimeBondDepository(mimBond).deposit(_amount, maxPrice, address(this)); + ITimeBondDepository(mimBond).redeem(address(this), _stake); + + _initialMemo = IERC20(memo).balanceOf(address(this)); + } // **** Views **** From 9ce46a01c7415e14c0ab92d06513325ff5f1024a Mon Sep 17 00:00:00 2001 From: Abigail Date: Fri, 10 Dec 2021 11:39:13 -0500 Subject: [PATCH 26/33] time-mim --- contracts/strategies/wonderland/strategy-time-mim.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/strategies/wonderland/strategy-time-mim.sol b/contracts/strategies/wonderland/strategy-time-mim.sol index ba5aec8ef..7b76bb5ae 100644 --- a/contracts/strategies/wonderland/strategy-time-mim.sol +++ b/contracts/strategies/wonderland/strategy-time-mim.sol @@ -7,7 +7,7 @@ abstract contract StrategyTimeMim is TimeFarm { // want token for depositing into depositLP for minting Time address public mim = 0x130966628846BFd36ff31a822705796e8cb8C18D; - address mimBond; + address public mimBond = 0x694738E0A438d90487b4a549b201142c1a97B556; constructor( @@ -34,8 +34,8 @@ abstract contract StrategyTimeMim is TimeFarm { IERC20(want).safeApprove(mimBond, 0); IERC20(want).safeApprove(mimBond, _amount); - ITimeBondDepository(mimBond).deposit(_amount, maxPrice, address(this)); - ITimeBondDepository(mimBond).redeem(address(this), _stake); + ITimeBondDepository(mimBond).deposit(_amount, maxPrice, address(this)); // deposit mim for time tokens + ITimeBondDepository(mimBond).redeem(address(this), _stake); // stake time tokens _initialMemo = IERC20(memo).balanceOf(address(this)); } From 489fcbf4a2ee5f28706cdbb93f113f54215d5661 Mon Sep 17 00:00:00 2001 From: Abigail Date: Fri, 10 Dec 2021 12:29:55 -0500 Subject: [PATCH 27/33] lp updated --- .../wonderland/strategy-time-avax-time.sol | 3 +- .../wonderland/strategy-time-mim-time.sol | 78 +++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 contracts/strategies/wonderland/strategy-time-mim-time.sol diff --git a/contracts/strategies/wonderland/strategy-time-avax-time.sol b/contracts/strategies/wonderland/strategy-time-avax-time.sol index 09223fee8..642cd89ba 100644 --- a/contracts/strategies/wonderland/strategy-time-avax-time.sol +++ b/contracts/strategies/wonderland/strategy-time-avax-time.sol @@ -60,7 +60,8 @@ abstract contract StrategyTimeAvaxTime is TimeFarm { uint256 _amount = IERC20(want).balanceOf(address(this)); - IJoePair(avax_time_lp).approve(avaxTimeBond, _amount); + IERC20(avax_time_lp).safeApprove(avaxTimeBond, 0); + IERC20(avax_time_lp).safeApprove(avaxTimeBond, _amount); ITimeBondDepository(avaxTimeBond).deposit(_amount, maxPrice, address(this)); ITimeBondDepository(avaxTimeBond).redeem(address(this), _stake); diff --git a/contracts/strategies/wonderland/strategy-time-mim-time.sol b/contracts/strategies/wonderland/strategy-time-mim-time.sol new file mode 100644 index 000000000..70df4e03e --- /dev/null +++ b/contracts/strategies/wonderland/strategy-time-mim-time.sol @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.7; + +import "../strategy-time-farm.sol"; + +abstract contract StrategyTimeMimTime is TimeFarm { + + // want/lp token for depositing into depositLP for minting Time + address public mim_time_lp = 0x113f413371fC4CC4C9d6416cf1DE9dFd7BF747Df; + address public mimTimeBond = 0xA184AE1A71EcAD20E822cB965b99c287590c4FFe; + address public mim = 0x130966628846BFd36ff31a822705796e8cb8C18D; + + + constructor( + address _governance, + address _strategist, + address _controller, + address _timelock + ) + public + TimeFarm( + mimTimeBond, + mim_time_lp, + _governance, + _strategist, + _controller, + _timelock + ) + {} + + // Deposit bond (lp or other token) so that we can get mint Time at a discount and autostake + function depositBond() public override { + // // Wrap the avax + // uint256 _avax = address(this).balance; + // if (_avax > 0) { + // WAVAX(wavax).deposit{value: _avax}(); + // } + + uint256 _mim = IERC20(mim).balanceOf(address(this)); + uint256 _time = IERC20(time).balanceOf(address(this)); + + if (_mim > 0 && _time > 0){ + IERC20(mim).safeApprove(joeRouter, 0); + IERC20(mim).safeApprove(joeRouter, _mim); + + IERC20(time).safeApprove(joeRouter, 0); + IERC20(time).safeApprove(joeRouter, _time); + + // Adds in liquidity for TIME/MIM + IJoeRouter(joeRouter).addLiquidity( + mim, + time, + _mim, + _time, + 0, + 0, + address(this), + now + 60 + ); + } + + uint256 _amount = IERC20(want).balanceOf(address(this)); + + IERC20(mim_time_lp).safeApprove(mimTimeBond, 0); + IERC20(mim_time_lp).safeApprove(mimTimeBond, _amount); + + ITimeBondDepository(mimTimeBond).deposit(_amount, maxPrice, address(this)); + ITimeBondDepository(mimTimeBond).redeem(address(this), _stake); + + _initialMemo = IERC20(memo).balanceOf(address(this)); + } + + // **** Views **** + + function getName() external pure override returns (string memory) { + return "StrategyTimeMimTime"; + } +} From bca6ba7603aae9d16bb1cc1eedc3740f816fc0fd Mon Sep 17 00:00:00 2001 From: Abigail Date: Fri, 10 Dec 2021 12:39:42 -0500 Subject: [PATCH 28/33] time-staking --- contracts/strategies/strategy-time-farm.sol | 7 +---- .../wonderland/strategy-time-x-time.sol | 31 +++++++++++++++++++ 2 files changed, 32 insertions(+), 6 deletions(-) create mode 100644 contracts/strategies/wonderland/strategy-time-x-time.sol diff --git a/contracts/strategies/strategy-time-farm.sol b/contracts/strategies/strategy-time-farm.sol index 140c2bf6b..837bf5663 100644 --- a/contracts/strategies/strategy-time-farm.sol +++ b/contracts/strategies/strategy-time-farm.sol @@ -4,15 +4,10 @@ pragma solidity ^0.6.7; import "./strategy-wonderland-base.sol"; abstract contract TimeFarm is TimeBase{ - - address public treasury = 0x1c46450211CB2646cc1DA3c5242422967eD9e04c; - uint256 public _initialMemo; address public bond; - - uint profit; - uint256 public _initial; + uint256 public _initial; // initial amount of memories/time for harvesting later constructor( address _bond, diff --git a/contracts/strategies/wonderland/strategy-time-x-time.sol b/contracts/strategies/wonderland/strategy-time-x-time.sol new file mode 100644 index 000000000..17f3d7e71 --- /dev/null +++ b/contracts/strategies/wonderland/strategy-time-x-time.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.6.7; + +import "../strategy-time-farm.sol"; + +abstract contract StrategyTimexTime is TimeFarm { + + constructor( + address _governance, + address _strategist, + address _controller, + address _timelock + ) + public + TimeFarm( + bond, + time, + _governance, + _strategist, + _controller, + _timelock + ) + {} + + + // **** Views **** + + function getName() external pure override returns (string memory) { + return "StrategyTimeXTime"; + } +} From 3a80287d1862261dcdb0d95d27d3bcd67e34cb4b Mon Sep 17 00:00:00 2001 From: Abigail Date: Fri, 10 Dec 2021 12:45:53 -0500 Subject: [PATCH 29/33] snowglobes --- .../wonderland/snowglobe-time-avax-time.sol | 136 ++++++++++++++++++ .../wonderland/snowglobe-time-avax.sol | 136 ++++++++++++++++++ .../wonderland/snowglobe-time-mim-time.sol | 136 ++++++++++++++++++ .../wonderland/snowglobe-time-mim.sol | 136 ++++++++++++++++++ .../wonderland/snowglobe-time-x-time.sol | 136 ++++++++++++++++++ .../wonderland/strategy-time-x-time.sol | 2 +- 6 files changed, 681 insertions(+), 1 deletion(-) create mode 100644 contracts/snowglobes/wonderland/snowglobe-time-avax-time.sol create mode 100644 contracts/snowglobes/wonderland/snowglobe-time-avax.sol create mode 100644 contracts/snowglobes/wonderland/snowglobe-time-mim-time.sol create mode 100644 contracts/snowglobes/wonderland/snowglobe-time-mim.sol create mode 100644 contracts/snowglobes/wonderland/snowglobe-time-x-time.sol diff --git a/contracts/snowglobes/wonderland/snowglobe-time-avax-time.sol b/contracts/snowglobes/wonderland/snowglobe-time-avax-time.sol new file mode 100644 index 000000000..1f3fcde9f --- /dev/null +++ b/contracts/snowglobes/wonderland/snowglobe-time-avax-time.sol @@ -0,0 +1,136 @@ +// https://github.com/iearn-finance/vaults/blob/master/contracts/vaults/yVault.sol + +pragma solidity ^0.6.7; + +import "../../interfaces/controller.sol"; + +import "../../lib/erc20.sol"; +import "../../lib/safe-math.sol"; + +contract SnowGlobeTimeAvaxTime is ERC20 { + using SafeERC20 for IERC20; + using Address for address; + using SafeMath for uint256; + + IERC20 public token; + + uint256 public min = 9500; + uint256 public constant max = 10000; + + address public governance; + address public timelock; + address public controller; + + constructor( + address _token, + address _governance, + address _timelock, + address _controller + ) + public + ERC20( + string(abi.encodePacked("freezing ", ERC20(_token).name())), + string(abi.encodePacked("s", ERC20(_token).symbol())) + ) + { + _setupDecimals(ERC20(_token).decimals()); + token = IERC20(_token); + governance = _governance; + timelock = _timelock; + controller = _controller; + } + + function balance() public view returns (uint256) { + return + token.balanceOf(address(this)).add( + IController(controller).balanceOf(address(token)) + ); + } + + function setMin(uint256 _min) external { + require(msg.sender == governance, "!governance"); + require(_min <= max, "numerator cannot be greater than denominator"); + min = _min; + } + + function setGovernance(address _governance) public { + require(msg.sender == governance, "!governance"); + governance = _governance; + } + + function setTimelock(address _timelock) public { + require(msg.sender == timelock, "!timelock"); + timelock = _timelock; + } + + function setController(address _controller) public { + require(msg.sender == timelock, "!timelock"); + controller = _controller; + } + + // Custom logic in here for how much the globes allows to be borrowed + // Sets minimum required on-hand to keep small withdrawals cheap + function available() public view returns (uint256) { + return token.balanceOf(address(this)).mul(min).div(max); + } + + function earn() public { + uint256 _bal = available(); + token.safeTransfer(controller, _bal); + IController(controller).earn(address(token), _bal); + } + + function depositAll() external { + deposit(token.balanceOf(msg.sender)); + } + + function deposit(uint256 _amount) public { + uint256 _pool = balance(); + uint256 _before = token.balanceOf(address(this)); + token.safeTransferFrom(msg.sender, address(this), _amount); + uint256 _after = token.balanceOf(address(this)); + _amount = _after.sub(_before); // Additional check for deflationary tokens + uint256 shares = 0; + if (totalSupply() == 0) { + shares = _amount; + } else { + shares = (_amount.mul(totalSupply())).div(_pool); + } + _mint(msg.sender, shares); + } + + function withdrawAll() external { + withdraw(balanceOf(msg.sender)); + } + + // Used to swap any borrowed reserve over the debt limit to liquidate to 'token' + function harvest(address reserve, uint256 amount) external { + require(msg.sender == controller, "!controller"); + require(reserve != address(token), "token"); + IERC20(reserve).safeTransfer(controller, amount); + } + + // No rebalance implementation for lower fees and faster swaps + function withdraw(uint256 _shares) public { + uint256 r = (balance().mul(_shares)).div(totalSupply()); + _burn(msg.sender, _shares); + + // Check balance + uint256 b = token.balanceOf(address(this)); + if (b < r) { + uint256 _withdraw = r.sub(b); + IController(controller).withdraw(address(token), _withdraw); + uint256 _after = token.balanceOf(address(this)); + uint256 _diff = _after.sub(b); + if (_diff < _withdraw) { + r = b.add(_diff); + } + } + + token.safeTransfer(msg.sender, r); + } + + function getRatio() public view returns (uint256) { + return balance().mul(1e18).div(totalSupply()); + } +} diff --git a/contracts/snowglobes/wonderland/snowglobe-time-avax.sol b/contracts/snowglobes/wonderland/snowglobe-time-avax.sol new file mode 100644 index 000000000..601cecb43 --- /dev/null +++ b/contracts/snowglobes/wonderland/snowglobe-time-avax.sol @@ -0,0 +1,136 @@ +// https://github.com/iearn-finance/vaults/blob/master/contracts/vaults/yVault.sol + +pragma solidity ^0.6.7; + +import "../../interfaces/controller.sol"; + +import "../../lib/erc20.sol"; +import "../../lib/safe-math.sol"; + +contract SnowGlobeTimeAvax is ERC20 { + using SafeERC20 for IERC20; + using Address for address; + using SafeMath for uint256; + + IERC20 public token; + + uint256 public min = 9500; + uint256 public constant max = 10000; + + address public governance; + address public timelock; + address public controller; + + constructor( + address _token, + address _governance, + address _timelock, + address _controller + ) + public + ERC20( + string(abi.encodePacked("freezing ", ERC20(_token).name())), + string(abi.encodePacked("s", ERC20(_token).symbol())) + ) + { + _setupDecimals(ERC20(_token).decimals()); + token = IERC20(_token); + governance = _governance; + timelock = _timelock; + controller = _controller; + } + + function balance() public view returns (uint256) { + return + token.balanceOf(address(this)).add( + IController(controller).balanceOf(address(token)) + ); + } + + function setMin(uint256 _min) external { + require(msg.sender == governance, "!governance"); + require(_min <= max, "numerator cannot be greater than denominator"); + min = _min; + } + + function setGovernance(address _governance) public { + require(msg.sender == governance, "!governance"); + governance = _governance; + } + + function setTimelock(address _timelock) public { + require(msg.sender == timelock, "!timelock"); + timelock = _timelock; + } + + function setController(address _controller) public { + require(msg.sender == timelock, "!timelock"); + controller = _controller; + } + + // Custom logic in here for how much the globes allows to be borrowed + // Sets minimum required on-hand to keep small withdrawals cheap + function available() public view returns (uint256) { + return token.balanceOf(address(this)).mul(min).div(max); + } + + function earn() public { + uint256 _bal = available(); + token.safeTransfer(controller, _bal); + IController(controller).earn(address(token), _bal); + } + + function depositAll() external { + deposit(token.balanceOf(msg.sender)); + } + + function deposit(uint256 _amount) public { + uint256 _pool = balance(); + uint256 _before = token.balanceOf(address(this)); + token.safeTransferFrom(msg.sender, address(this), _amount); + uint256 _after = token.balanceOf(address(this)); + _amount = _after.sub(_before); // Additional check for deflationary tokens + uint256 shares = 0; + if (totalSupply() == 0) { + shares = _amount; + } else { + shares = (_amount.mul(totalSupply())).div(_pool); + } + _mint(msg.sender, shares); + } + + function withdrawAll() external { + withdraw(balanceOf(msg.sender)); + } + + // Used to swap any borrowed reserve over the debt limit to liquidate to 'token' + function harvest(address reserve, uint256 amount) external { + require(msg.sender == controller, "!controller"); + require(reserve != address(token), "token"); + IERC20(reserve).safeTransfer(controller, amount); + } + + // No rebalance implementation for lower fees and faster swaps + function withdraw(uint256 _shares) public { + uint256 r = (balance().mul(_shares)).div(totalSupply()); + _burn(msg.sender, _shares); + + // Check balance + uint256 b = token.balanceOf(address(this)); + if (b < r) { + uint256 _withdraw = r.sub(b); + IController(controller).withdraw(address(token), _withdraw); + uint256 _after = token.balanceOf(address(this)); + uint256 _diff = _after.sub(b); + if (_diff < _withdraw) { + r = b.add(_diff); + } + } + + token.safeTransfer(msg.sender, r); + } + + function getRatio() public view returns (uint256) { + return balance().mul(1e18).div(totalSupply()); + } +} diff --git a/contracts/snowglobes/wonderland/snowglobe-time-mim-time.sol b/contracts/snowglobes/wonderland/snowglobe-time-mim-time.sol new file mode 100644 index 000000000..efc13d0f4 --- /dev/null +++ b/contracts/snowglobes/wonderland/snowglobe-time-mim-time.sol @@ -0,0 +1,136 @@ +// https://github.com/iearn-finance/vaults/blob/master/contracts/vaults/yVault.sol + +pragma solidity ^0.6.7; + +import "../../interfaces/controller.sol"; + +import "../../lib/erc20.sol"; +import "../../lib/safe-math.sol"; + +contract SnowGlobeTimeMimTime is ERC20 { + using SafeERC20 for IERC20; + using Address for address; + using SafeMath for uint256; + + IERC20 public token; + + uint256 public min = 9500; + uint256 public constant max = 10000; + + address public governance; + address public timelock; + address public controller; + + constructor( + address _token, + address _governance, + address _timelock, + address _controller + ) + public + ERC20( + string(abi.encodePacked("freezing ", ERC20(_token).name())), + string(abi.encodePacked("s", ERC20(_token).symbol())) + ) + { + _setupDecimals(ERC20(_token).decimals()); + token = IERC20(_token); + governance = _governance; + timelock = _timelock; + controller = _controller; + } + + function balance() public view returns (uint256) { + return + token.balanceOf(address(this)).add( + IController(controller).balanceOf(address(token)) + ); + } + + function setMin(uint256 _min) external { + require(msg.sender == governance, "!governance"); + require(_min <= max, "numerator cannot be greater than denominator"); + min = _min; + } + + function setGovernance(address _governance) public { + require(msg.sender == governance, "!governance"); + governance = _governance; + } + + function setTimelock(address _timelock) public { + require(msg.sender == timelock, "!timelock"); + timelock = _timelock; + } + + function setController(address _controller) public { + require(msg.sender == timelock, "!timelock"); + controller = _controller; + } + + // Custom logic in here for how much the globes allows to be borrowed + // Sets minimum required on-hand to keep small withdrawals cheap + function available() public view returns (uint256) { + return token.balanceOf(address(this)).mul(min).div(max); + } + + function earn() public { + uint256 _bal = available(); + token.safeTransfer(controller, _bal); + IController(controller).earn(address(token), _bal); + } + + function depositAll() external { + deposit(token.balanceOf(msg.sender)); + } + + function deposit(uint256 _amount) public { + uint256 _pool = balance(); + uint256 _before = token.balanceOf(address(this)); + token.safeTransferFrom(msg.sender, address(this), _amount); + uint256 _after = token.balanceOf(address(this)); + _amount = _after.sub(_before); // Additional check for deflationary tokens + uint256 shares = 0; + if (totalSupply() == 0) { + shares = _amount; + } else { + shares = (_amount.mul(totalSupply())).div(_pool); + } + _mint(msg.sender, shares); + } + + function withdrawAll() external { + withdraw(balanceOf(msg.sender)); + } + + // Used to swap any borrowed reserve over the debt limit to liquidate to 'token' + function harvest(address reserve, uint256 amount) external { + require(msg.sender == controller, "!controller"); + require(reserve != address(token), "token"); + IERC20(reserve).safeTransfer(controller, amount); + } + + // No rebalance implementation for lower fees and faster swaps + function withdraw(uint256 _shares) public { + uint256 r = (balance().mul(_shares)).div(totalSupply()); + _burn(msg.sender, _shares); + + // Check balance + uint256 b = token.balanceOf(address(this)); + if (b < r) { + uint256 _withdraw = r.sub(b); + IController(controller).withdraw(address(token), _withdraw); + uint256 _after = token.balanceOf(address(this)); + uint256 _diff = _after.sub(b); + if (_diff < _withdraw) { + r = b.add(_diff); + } + } + + token.safeTransfer(msg.sender, r); + } + + function getRatio() public view returns (uint256) { + return balance().mul(1e18).div(totalSupply()); + } +} diff --git a/contracts/snowglobes/wonderland/snowglobe-time-mim.sol b/contracts/snowglobes/wonderland/snowglobe-time-mim.sol new file mode 100644 index 000000000..26acafea5 --- /dev/null +++ b/contracts/snowglobes/wonderland/snowglobe-time-mim.sol @@ -0,0 +1,136 @@ +// https://github.com/iearn-finance/vaults/blob/master/contracts/vaults/yVault.sol + +pragma solidity ^0.6.7; + +import "../../interfaces/controller.sol"; + +import "../../lib/erc20.sol"; +import "../../lib/safe-math.sol"; + +contract SnowGlobeTimeMim is ERC20 { + using SafeERC20 for IERC20; + using Address for address; + using SafeMath for uint256; + + IERC20 public token; + + uint256 public min = 9500; + uint256 public constant max = 10000; + + address public governance; + address public timelock; + address public controller; + + constructor( + address _token, + address _governance, + address _timelock, + address _controller + ) + public + ERC20( + string(abi.encodePacked("freezing ", ERC20(_token).name())), + string(abi.encodePacked("s", ERC20(_token).symbol())) + ) + { + _setupDecimals(ERC20(_token).decimals()); + token = IERC20(_token); + governance = _governance; + timelock = _timelock; + controller = _controller; + } + + function balance() public view returns (uint256) { + return + token.balanceOf(address(this)).add( + IController(controller).balanceOf(address(token)) + ); + } + + function setMin(uint256 _min) external { + require(msg.sender == governance, "!governance"); + require(_min <= max, "numerator cannot be greater than denominator"); + min = _min; + } + + function setGovernance(address _governance) public { + require(msg.sender == governance, "!governance"); + governance = _governance; + } + + function setTimelock(address _timelock) public { + require(msg.sender == timelock, "!timelock"); + timelock = _timelock; + } + + function setController(address _controller) public { + require(msg.sender == timelock, "!timelock"); + controller = _controller; + } + + // Custom logic in here for how much the globes allows to be borrowed + // Sets minimum required on-hand to keep small withdrawals cheap + function available() public view returns (uint256) { + return token.balanceOf(address(this)).mul(min).div(max); + } + + function earn() public { + uint256 _bal = available(); + token.safeTransfer(controller, _bal); + IController(controller).earn(address(token), _bal); + } + + function depositAll() external { + deposit(token.balanceOf(msg.sender)); + } + + function deposit(uint256 _amount) public { + uint256 _pool = balance(); + uint256 _before = token.balanceOf(address(this)); + token.safeTransferFrom(msg.sender, address(this), _amount); + uint256 _after = token.balanceOf(address(this)); + _amount = _after.sub(_before); // Additional check for deflationary tokens + uint256 shares = 0; + if (totalSupply() == 0) { + shares = _amount; + } else { + shares = (_amount.mul(totalSupply())).div(_pool); + } + _mint(msg.sender, shares); + } + + function withdrawAll() external { + withdraw(balanceOf(msg.sender)); + } + + // Used to swap any borrowed reserve over the debt limit to liquidate to 'token' + function harvest(address reserve, uint256 amount) external { + require(msg.sender == controller, "!controller"); + require(reserve != address(token), "token"); + IERC20(reserve).safeTransfer(controller, amount); + } + + // No rebalance implementation for lower fees and faster swaps + function withdraw(uint256 _shares) public { + uint256 r = (balance().mul(_shares)).div(totalSupply()); + _burn(msg.sender, _shares); + + // Check balance + uint256 b = token.balanceOf(address(this)); + if (b < r) { + uint256 _withdraw = r.sub(b); + IController(controller).withdraw(address(token), _withdraw); + uint256 _after = token.balanceOf(address(this)); + uint256 _diff = _after.sub(b); + if (_diff < _withdraw) { + r = b.add(_diff); + } + } + + token.safeTransfer(msg.sender, r); + } + + function getRatio() public view returns (uint256) { + return balance().mul(1e18).div(totalSupply()); + } +} diff --git a/contracts/snowglobes/wonderland/snowglobe-time-x-time.sol b/contracts/snowglobes/wonderland/snowglobe-time-x-time.sol new file mode 100644 index 000000000..a9c727590 --- /dev/null +++ b/contracts/snowglobes/wonderland/snowglobe-time-x-time.sol @@ -0,0 +1,136 @@ +// https://github.com/iearn-finance/vaults/blob/master/contracts/vaults/yVault.sol + +pragma solidity ^0.6.7; + +import "../../interfaces/controller.sol"; + +import "../../lib/erc20.sol"; +import "../../lib/safe-math.sol"; + +contract SnowGlobeTimeXTime is ERC20 { + using SafeERC20 for IERC20; + using Address for address; + using SafeMath for uint256; + + IERC20 public token; + + uint256 public min = 9500; + uint256 public constant max = 10000; + + address public governance; + address public timelock; + address public controller; + + constructor( + address _token, + address _governance, + address _timelock, + address _controller + ) + public + ERC20( + string(abi.encodePacked("freezing ", ERC20(_token).name())), + string(abi.encodePacked("s", ERC20(_token).symbol())) + ) + { + _setupDecimals(ERC20(_token).decimals()); + token = IERC20(_token); + governance = _governance; + timelock = _timelock; + controller = _controller; + } + + function balance() public view returns (uint256) { + return + token.balanceOf(address(this)).add( + IController(controller).balanceOf(address(token)) + ); + } + + function setMin(uint256 _min) external { + require(msg.sender == governance, "!governance"); + require(_min <= max, "numerator cannot be greater than denominator"); + min = _min; + } + + function setGovernance(address _governance) public { + require(msg.sender == governance, "!governance"); + governance = _governance; + } + + function setTimelock(address _timelock) public { + require(msg.sender == timelock, "!timelock"); + timelock = _timelock; + } + + function setController(address _controller) public { + require(msg.sender == timelock, "!timelock"); + controller = _controller; + } + + // Custom logic in here for how much the globes allows to be borrowed + // Sets minimum required on-hand to keep small withdrawals cheap + function available() public view returns (uint256) { + return token.balanceOf(address(this)).mul(min).div(max); + } + + function earn() public { + uint256 _bal = available(); + token.safeTransfer(controller, _bal); + IController(controller).earn(address(token), _bal); + } + + function depositAll() external { + deposit(token.balanceOf(msg.sender)); + } + + function deposit(uint256 _amount) public { + uint256 _pool = balance(); + uint256 _before = token.balanceOf(address(this)); + token.safeTransferFrom(msg.sender, address(this), _amount); + uint256 _after = token.balanceOf(address(this)); + _amount = _after.sub(_before); // Additional check for deflationary tokens + uint256 shares = 0; + if (totalSupply() == 0) { + shares = _amount; + } else { + shares = (_amount.mul(totalSupply())).div(_pool); + } + _mint(msg.sender, shares); + } + + function withdrawAll() external { + withdraw(balanceOf(msg.sender)); + } + + // Used to swap any borrowed reserve over the debt limit to liquidate to 'token' + function harvest(address reserve, uint256 amount) external { + require(msg.sender == controller, "!controller"); + require(reserve != address(token), "token"); + IERC20(reserve).safeTransfer(controller, amount); + } + + // No rebalance implementation for lower fees and faster swaps + function withdraw(uint256 _shares) public { + uint256 r = (balance().mul(_shares)).div(totalSupply()); + _burn(msg.sender, _shares); + + // Check balance + uint256 b = token.balanceOf(address(this)); + if (b < r) { + uint256 _withdraw = r.sub(b); + IController(controller).withdraw(address(token), _withdraw); + uint256 _after = token.balanceOf(address(this)); + uint256 _diff = _after.sub(b); + if (_diff < _withdraw) { + r = b.add(_diff); + } + } + + token.safeTransfer(msg.sender, r); + } + + function getRatio() public view returns (uint256) { + return balance().mul(1e18).div(totalSupply()); + } +} diff --git a/contracts/strategies/wonderland/strategy-time-x-time.sol b/contracts/strategies/wonderland/strategy-time-x-time.sol index 17f3d7e71..8874ca905 100644 --- a/contracts/strategies/wonderland/strategy-time-x-time.sol +++ b/contracts/strategies/wonderland/strategy-time-x-time.sol @@ -3,7 +3,7 @@ pragma solidity ^0.6.7; import "../strategy-time-farm.sol"; -abstract contract StrategyTimexTime is TimeFarm { +abstract contract StrategyTimeXTime is TimeFarm { constructor( address _governance, From dccb2913b565e57503b0eb02aab1964fb2eb98eb Mon Sep 17 00:00:00 2001 From: Abigail Date: Fri, 10 Dec 2021 13:00:29 -0500 Subject: [PATCH 30/33] wonderland base --- .../strategies/strategy-wonderland-base.sol | 100 +++++++++++++++--- 1 file changed, 85 insertions(+), 15 deletions(-) diff --git a/contracts/strategies/strategy-wonderland-base.sol b/contracts/strategies/strategy-wonderland-base.sol index e4cefe529..5a0332168 100644 --- a/contracts/strategies/strategy-wonderland-base.sol +++ b/contracts/strategies/strategy-wonderland-base.sol @@ -19,12 +19,8 @@ abstract contract TimeBase { using SafeMath for uint32; using SafeERC20 for IERC20; - // staking contract for rewards address public staking = 0x4456B87Af11e87E329AB7d7C7A246ed1aC2168B9; - - uint256 public maxPrice; - // Tokens address public want; @@ -74,8 +70,6 @@ abstract contract TimeBase { address public strategist; address public timelock; - address public distributor; - mapping(address => bool) public harvesters; @@ -122,13 +116,23 @@ abstract contract TimeBase { return balanceOfWant().add(balanceOfPool()); } - function balanceOfTime() public virtual view returns (uint256); - function getName() external virtual pure returns (string memory); - + + // **** Setters **** // + + function setKeep(uint256 _keep) external { + require(msg.sender == timelock, "!timelock"); + keep = _keep; + } + + function setRevenueShare(uint256 _share) external { + require(msg.sender == timelock, "!timelock"); + revenueShare = _share; + } + function whitelistHarvester(address _harvester) external { require(msg.sender == governance || - msg.sender == strategist, "not authorized"); + msg.sender == strategist, "not authorized"); harvesters[_harvester] = true; } @@ -138,7 +142,7 @@ abstract contract TimeBase { harvesters[_harvester] = false; } - function setFeeDistributor(address _feeDistributor) external { + function setFeeDistributor(address _feeDistributor) external { require(msg.sender == governance, "not authorized"); feeDistributor = _feeDistributor; } @@ -152,7 +156,7 @@ abstract contract TimeBase { require(msg.sender == timelock, "!timelock"); withdrawalTreasuryFee = _withdrawalTreasuryFee; } - + function setPerformanceDevFee(uint256 _performanceDevFee) external { require(msg.sender == timelock, "!timelock"); performanceDevFee = _performanceDevFee; @@ -165,7 +169,7 @@ abstract contract TimeBase { performanceTreasuryFee = _performanceTreasuryFee; } - function setStrategist(address _strategist) external { + function setStrategist(address _strategist) external { require(msg.sender == governance, "!governance"); strategist = _strategist; } @@ -184,7 +188,7 @@ abstract contract TimeBase { require(msg.sender == timelock, "!timelock"); controller = _controller; } - + // **** State mutations **** // function deposit() public virtual; @@ -226,7 +230,32 @@ abstract contract TimeBase { IERC20(want).safeTransfer(_globe, _amount.sub(_feeDev).sub(_feeTreasury)); } - function harvest() public virtual; + // Withdraw funds, used to swap between strategies + function withdrawForSwap(uint256 _amount) + external + returns (uint256 balance) + { + require(msg.sender == controller, "!controller"); + _withdrawSome(_amount); + + balance = IERC20(want).balanceOf(address(this)); + + address _globe = IController(controller).globes(address(want)); + require(_globe != address(0), "!globe"); + IERC20(want).safeTransfer(_globe, balance); + } + + // Withdraw all funds, normally used when migrating strategies + function withdrawAll() external returns (uint256 balance) { + require(msg.sender == controller, "!controller"); + _withdrawAll(); + + balance = IERC20(want).balanceOf(address(this)); + + address _globe = IController(controller).globes(address(want)); + require(_globe != address(0), "!globe"); // additional protection so we don't burn the funds + IERC20(want).safeTransfer(_globe, balance); + } function _withdrawAll() internal { _withdrawSome(balanceOfPool()); @@ -234,6 +263,47 @@ abstract contract TimeBase { function _withdrawSome(uint256 _amount) internal virtual returns (uint256); + function harvest() public virtual; + + // **** Emergency functions **** // + + function execute(address _target, bytes memory _data) + public + payable + returns (bytes memory response) + { + require(msg.sender == timelock, "!timelock"); + require(_target != address(0), "!target"); + + // call contract in current context + assembly { + let succeeded := delegatecall( + sub(gas(), 5000), + _target, + add(_data, 0x20), + mload(_data), + 0, + 0 + ) + let size := returndatasize() + + response := mload(0x40) + mstore( + 0x40, + add(response, and(add(add(size, 0x20), 0x1f), not(0x1f))) + ) + mstore(response, size) + returndatacopy(add(response, 0x20), 0, size) + + switch iszero(succeeded) + case 1 { + // throw if delegatecall failed + revert(add(response, 0x20), size) + } + } + } + + // **** Internal functions **** function _swapTraderJoe( address _from, From 084bef812d1af33fb4c2def40bc51597136fcb82 Mon Sep 17 00:00:00 2001 From: Abigail Date: Fri, 10 Dec 2021 13:11:27 -0500 Subject: [PATCH 31/33] farm --- contracts/strategies/strategy-time-farm.sol | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contracts/strategies/strategy-time-farm.sol b/contracts/strategies/strategy-time-farm.sol index 837bf5663..21418950b 100644 --- a/contracts/strategies/strategy-time-farm.sol +++ b/contracts/strategies/strategy-time-farm.sol @@ -28,6 +28,8 @@ abstract contract TimeFarm is TimeBase{ return amount; } + receive() external payable {} + // Deposits the Time token in the staking contract function deposit () public override { // the amount of Time tokens that you want to stake From 1d81f18427f4d097411e18178ff8619aacfd2c9f Mon Sep 17 00:00:00 2001 From: Abigail Date: Fri, 10 Dec 2021 13:17:24 -0500 Subject: [PATCH 32/33] price --- contracts/strategies/strategy-wonderland-base.sol | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contracts/strategies/strategy-wonderland-base.sol b/contracts/strategies/strategy-wonderland-base.sol index 5a0332168..2deedf47e 100644 --- a/contracts/strategies/strategy-wonderland-base.sol +++ b/contracts/strategies/strategy-wonderland-base.sol @@ -22,6 +22,8 @@ abstract contract TimeBase { // staking contract for rewards address public staking = 0x4456B87Af11e87E329AB7d7C7A246ed1aC2168B9; + uint256 public maxPrice; + // Tokens address public want; address public constant joe = 0x6e84a6216eA6dACC71eE8E6b0a5B7322EEbC0fDd; From 82b52fbc212c19676317d71e92d36b014a5c9b40 Mon Sep 17 00:00:00 2001 From: Abigail Date: Fri, 10 Dec 2021 20:10:10 -0500 Subject: [PATCH 33/33] running tests --- contracts/strategies/strategy-time-farm.sol | 39 +++++++------------ .../strategies/strategy-wonderland-base.sol | 2 - .../wonderland/strategy-time-avax-time.sol | 8 ++-- .../wonderland/strategy-time-avax.sol | 6 +-- .../wonderland/strategy-time-mim-time.sol | 12 ++---- .../wonderland/strategy-time-mim.sol | 7 ++-- .../wonderland/strategy-time-x-time.sol | 22 ++++++++++- test/LPStrats/all-strats.js | 35 ++++++++++------- test/lp-strategy-test.js | 2 +- 9 files changed, 68 insertions(+), 65 deletions(-) diff --git a/contracts/strategies/strategy-time-farm.sol b/contracts/strategies/strategy-time-farm.sol index 21418950b..3bcb370bf 100644 --- a/contracts/strategies/strategy-time-farm.sol +++ b/contracts/strategies/strategy-time-farm.sol @@ -29,41 +29,30 @@ abstract contract TimeFarm is TimeBase{ } receive() external payable {} - - // Deposits the Time token in the staking contract - function deposit () public override { - // the amount of Time tokens that you want to stake - uint256 _amount = IERC20(time).balanceOf(address(this)); - if (_amount > 0){ - if ( useHelper ) { // use if staking warmup is 0 - IERC20(time).safeApprove( address(stakingHelper), 0 ); - IERC20(time).safeApprove( address(stakingHelper), _amount ); - IStakingHelper(stakingHelper).stake( _amount, address(this) ); - } else { - IERC20(time).safeApprove( address(staking), 0 ); - IERC20(time).safeApprove( address(staking), _amount ); - IStaking(staking).stake( _amount, address(this) ); - } - } - _initialMemo = IERC20(memo).balanceOf(address(this)); + function getHarvestable() external view returns (uint256, uint256) { + uint256 pendingMemories = IERC20(memo).balanceOf(address(this)); + uint256 profit = _initialMemo.sub(pendingMemories); + return (pendingMemories, profit); } - function harvest() public override onlyBenevolent { ITimeStaking(staking).rebase(); - uint256 _rebaseMemo = IERC20(memo).balanceOf(address(this)); - uint _amount = _rebaseMemo.sub(_initialMemo); + if (want != time) { + uint256 _rebaseMemo = IERC20(memo).balanceOf(address(this)); + uint _amount = _rebaseMemo.sub(_initialMemo); - if (_amount > 0) { - // 10% locked up for future governance - uint256 _keep = _amount.mul(keep).div(keepMax); - if (_keep > 0) { - _takeFeeTimeToSnob(_keep); + if (_amount > 0) { + // 10% locked up for future governance + uint256 _keep = _amount.mul(keep).div(keepMax); + if (_keep > 0) { + _takeFeeTimeToSnob(_keep); + } } } } + function _withdrawSome(uint256 _amount) internal override returns (uint256) { IERC20(memo).safeApprove(staking, 0); diff --git a/contracts/strategies/strategy-wonderland-base.sol b/contracts/strategies/strategy-wonderland-base.sol index 2deedf47e..7cdd6cabb 100644 --- a/contracts/strategies/strategy-wonderland-base.sol +++ b/contracts/strategies/strategy-wonderland-base.sol @@ -194,8 +194,6 @@ abstract contract TimeBase { // **** State mutations **** // function deposit() public virtual; - function depositBond() public virtual; - // Controller only function for creating additional rewards from dust function withdraw(IERC20 _asset) external returns (uint256 balance) { require(msg.sender == controller, "!controller"); diff --git a/contracts/strategies/wonderland/strategy-time-avax-time.sol b/contracts/strategies/wonderland/strategy-time-avax-time.sol index 642cd89ba..a261b341a 100644 --- a/contracts/strategies/wonderland/strategy-time-avax-time.sol +++ b/contracts/strategies/wonderland/strategy-time-avax-time.sol @@ -3,7 +3,7 @@ pragma solidity ^0.6.7; import "../strategy-time-farm.sol"; -abstract contract StrategyTimeAvaxTime is TimeFarm { +contract StrategyTimeAvaxTimeLp is TimeFarm { // want/lp token for depositing into depositLP for minting Time address public avax_time_lp = 0xf64e1c5B6E17031f5504481Ac8145F4c3eab4917; @@ -28,7 +28,7 @@ abstract contract StrategyTimeAvaxTime is TimeFarm { {} // Deposit bond (lp or other token) so that we can get mint Time at a discount and autostake - function depositBond() public override { + function deposit() public override { // Wrap the avax uint256 _avax = address(this).balance; if (_avax > 0) { @@ -58,7 +58,7 @@ abstract contract StrategyTimeAvaxTime is TimeFarm { ); } - uint256 _amount = IERC20(want).balanceOf(address(this)); + uint256 _amount = IERC20(avax_time_lp).balanceOf(address(this)); IERC20(avax_time_lp).safeApprove(avaxTimeBond, 0); IERC20(avax_time_lp).safeApprove(avaxTimeBond, _amount); @@ -72,6 +72,6 @@ abstract contract StrategyTimeAvaxTime is TimeFarm { // **** Views **** function getName() external pure override returns (string memory) { - return "StrategyTimeAvaxTime"; + return "StrategyTimeAvaxTimeLp"; } } diff --git a/contracts/strategies/wonderland/strategy-time-avax.sol b/contracts/strategies/wonderland/strategy-time-avax.sol index c9f4129a8..ad08ea8da 100644 --- a/contracts/strategies/wonderland/strategy-time-avax.sol +++ b/contracts/strategies/wonderland/strategy-time-avax.sol @@ -3,7 +3,7 @@ pragma solidity ^0.6.7; import "../strategy-time-farm.sol"; -abstract contract StrategyTimeAvax is TimeFarm { +contract StrategyTimeAvaxLp is TimeFarm { // want token for depositing into depositLP for minting Time address avaxBond = 0xE02B1AA2c4BE73093BE79d763fdFFC0E3cf67318; @@ -27,7 +27,7 @@ abstract contract StrategyTimeAvax is TimeFarm { {} // Deposit bond (lp or other token) so that we can get mint Time at a discount and autostake - function depositBond() public override { + function deposit() public override { // Wrap the avax uint256 _avax = address(this).balance; if (_avax > 0) { @@ -48,6 +48,6 @@ abstract contract StrategyTimeAvax is TimeFarm { // **** Views **** function getName() external pure override returns (string memory) { - return "StrategyTimeAvax"; + return "StrategyTimeAvaxLp"; } } diff --git a/contracts/strategies/wonderland/strategy-time-mim-time.sol b/contracts/strategies/wonderland/strategy-time-mim-time.sol index 70df4e03e..c4165af37 100644 --- a/contracts/strategies/wonderland/strategy-time-mim-time.sol +++ b/contracts/strategies/wonderland/strategy-time-mim-time.sol @@ -3,7 +3,7 @@ pragma solidity ^0.6.7; import "../strategy-time-farm.sol"; -abstract contract StrategyTimeMimTime is TimeFarm { +contract StrategyTimeMimTimeLp is TimeFarm { // want/lp token for depositing into depositLP for minting Time address public mim_time_lp = 0x113f413371fC4CC4C9d6416cf1DE9dFd7BF747Df; @@ -29,13 +29,7 @@ abstract contract StrategyTimeMimTime is TimeFarm { {} // Deposit bond (lp or other token) so that we can get mint Time at a discount and autostake - function depositBond() public override { - // // Wrap the avax - // uint256 _avax = address(this).balance; - // if (_avax > 0) { - // WAVAX(wavax).deposit{value: _avax}(); - // } - + function deposit() public override { uint256 _mim = IERC20(mim).balanceOf(address(this)); uint256 _time = IERC20(time).balanceOf(address(this)); @@ -73,6 +67,6 @@ abstract contract StrategyTimeMimTime is TimeFarm { // **** Views **** function getName() external pure override returns (string memory) { - return "StrategyTimeMimTime"; + return "StrategyTimeMimTimeLp"; } } diff --git a/contracts/strategies/wonderland/strategy-time-mim.sol b/contracts/strategies/wonderland/strategy-time-mim.sol index 7b76bb5ae..99457c01b 100644 --- a/contracts/strategies/wonderland/strategy-time-mim.sol +++ b/contracts/strategies/wonderland/strategy-time-mim.sol @@ -3,13 +3,12 @@ pragma solidity ^0.6.7; import "../strategy-time-farm.sol"; -abstract contract StrategyTimeMim is TimeFarm { +contract StrategyTimeMimLp is TimeFarm { // want token for depositing into depositLP for minting Time address public mim = 0x130966628846BFd36ff31a822705796e8cb8C18D; address public mimBond = 0x694738E0A438d90487b4a549b201142c1a97B556; - constructor( address _governance, address _strategist, @@ -28,7 +27,7 @@ abstract contract StrategyTimeMim is TimeFarm { {} // Deposit bond (lp or other token) so that we can get mint Time at a discount and autostake - function depositBond() public override { + function deposit() public override { uint256 _amount = IERC20(want).balanceOf(address(this)); IERC20(want).safeApprove(mimBond, 0); @@ -43,6 +42,6 @@ abstract contract StrategyTimeMim is TimeFarm { // **** Views **** function getName() external pure override returns (string memory) { - return "StrategyTimeMim"; + return "StrategyTimeMimLp"; } } diff --git a/contracts/strategies/wonderland/strategy-time-x-time.sol b/contracts/strategies/wonderland/strategy-time-x-time.sol index 8874ca905..f8499e5ce 100644 --- a/contracts/strategies/wonderland/strategy-time-x-time.sol +++ b/contracts/strategies/wonderland/strategy-time-x-time.sol @@ -3,7 +3,7 @@ pragma solidity ^0.6.7; import "../strategy-time-farm.sol"; -abstract contract StrategyTimeXTime is TimeFarm { +abstract contract StrategyTimeXTimeLp is TimeFarm { constructor( address _governance, @@ -22,10 +22,28 @@ abstract contract StrategyTimeXTime is TimeFarm { ) {} + // Deposits the Time token in the staking contract + function deposit () public override { + // the amount of Time tokens that you want to stake + uint256 _amount = IERC20(time).balanceOf(address(this)); + if (_amount > 0){ + if ( useHelper ) { // use if staking warmup is 0 + IERC20(time).safeApprove( address(stakingHelper), 0 ); + IERC20(time).safeApprove( address(stakingHelper), _amount ); + IStakingHelper(stakingHelper).stake( _amount, address(this) ); + } else { + IERC20(time).safeApprove( address(staking), 0 ); + IERC20(time).safeApprove( address(staking), _amount ); + IStaking(staking).stake( _amount, address(this) ); + } + } + _initialMemo = IERC20(memo).balanceOf(address(this)); + } + // **** Views **** function getName() external pure override returns (string memory) { - return "StrategyTimeXTime"; + return "StrategyTimeXTimeLp"; } } diff --git a/test/LPStrats/all-strats.js b/test/LPStrats/all-strats.js index ccbbd91a9..0a278aa97 100644 --- a/test/LPStrats/all-strats.js +++ b/test/LPStrats/all-strats.js @@ -314,16 +314,16 @@ const tests = [ // controllerAddress: "", // snowglobeAddress: "0x07e7dF7F0612B7dc6789ba402b17c7108c932d05", // }, - { - name: "PngAvaxRoco", - controllerAddress: "", - snowglobeAddress: "", - }, - { - name: "PngAvaxFrax", - controllerAddress: "", - snowglobeAddress: "", - }, + // { + // name: "PngAvaxRoco", + // controllerAddress: "", + // snowglobeAddress: "", + // }, + // { + // name: "PngAvaxFrax", + // controllerAddress: "", + // snowglobeAddress: "", + // }, // { // name: "JoeAvaxPng", // controllerAddress: "", @@ -544,11 +544,16 @@ const tests = [ // controllerAddress: "", // snowglobeAddress: "0xAFB27fB1c5bd91A80d18A321D6dC09aDd6a94219", // }, -// { -// name: "JoeAvaxRoco", -// controllerAddress: "", -// snowglobeAddress: "", -// }, + // { + // name: "JoeAvaxRoco", + // controllerAddress: "", + // snowglobeAddress: "", + // }, + { + name: "TimeAvaxTime", + controllerAddress: "", + snowglobeAddress: "", + }, ]; for (const test of tests) { diff --git a/test/lp-strategy-test.js b/test/lp-strategy-test.js index 56c7e3399..a0e7bb7de 100644 --- a/test/lp-strategy-test.js +++ b/test/lp-strategy-test.js @@ -15,7 +15,7 @@ const doLPStrategyTest = (name, _snowglobeAddr, _controllerAddr, globeABI, strat let globeContract, strategyContract; let strategyBalance, assetAddr, strategyAddr; let snowglobeAddr = _snowglobeAddr ? _snowglobeAddr : ""; - let controllerAddr = _controllerAddr ? _controllerAddr : "0xf7B8D9f8a82a7a6dd448398aFC5c77744Bd6cb85"; + let controllerAddr = _controllerAddr ? _controllerAddr : "0xACc69DEeF119AB5bBf14e6Aaf0536eAFB3D6e046"; const txnAmt = "25000000000000000000000"; const slot = _slot ? _slot : 1;