Skip to content

Commit

Permalink
Merge branch 'aave-stkwamGHST'
Browse files Browse the repository at this point in the history
  • Loading branch information
cinnabarhorse committed Mar 15, 2022
2 parents d4ab658 + e6a5f82 commit 0a0c161
Show file tree
Hide file tree
Showing 18 changed files with 1,452 additions and 45,880 deletions.
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,8 @@ bin
typechain
coverage
flat
frenDifferencesFinal.ts
foundry.toml
soljson-v0.6.12+commit.27d51765.js
soljson-v0.7.6+commit.7338295f.js
dep

3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "dep"]
path = dep
url = https://github.com/Timidan/aave-minimal.git
85 changes: 85 additions & 0 deletions contracts/amGHSTRouter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
pragma solidity 0.6.12;

import {IStaticATokenLM} from "../dep/protocol-v2/contracts/interfaces/IStaticATokenLM.sol";
import {ILendingPool} from "../dep/protocol-v2/contracts/interfaces/ILendingPool.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IStakingFacet} from "./interfaces/IStakingFacet.sol";

contract StaticAmGHSTRouter {
ILendingPool public aaveLendingPool = ILendingPool(0x8dFf5E27EA6b7AC08EbFdf9eB090F32ee9a30fcf);
address constant stakingDiamond = 0xA02d547512Bb90002807499F05495Fe9C4C3943f;
IERC20 GHST = IERC20(0x385Eeac5cB85A38A9a07A70c73e0a3271CfB54A7);
address constant amGHST = 0x080b5BF8f360F624628E0fb961F4e67c9e3c7CF1;
address public wamGHSTPool;
uint256 constant MAX_UINT = type(uint256).max;

constructor(address _wamGhstPoolAddress) public {
wamGHSTPool = _wamGhstPoolAddress;

//approve lendingpool to spend GHST
GHST.approve(address(aaveLendingPool), MAX_UINT);

//approve static wrapper contract to spend amGHST
IERC20(amGHST).approve(wamGHSTPool, MAX_UINT);

//approve stk diamond to spend wAmGhst
IERC20(wamGHSTPool).approve(stakingDiamond, MAX_UINT);
}

///@notice Allow an address to wrap GHST and automatically deposit resulting wamGHST in the pool
///@notice user can either provide GHST or amGHST directly
///@param _amount Amount of incoming tokens, either GHST or wamGHST
///@param _to Address to stake for
///@param _underlying true if GHST is provided, false if amGHST is provided
function wrapAndDeposit(
uint256 _amount,
address _to,
bool _underlying
) external {
if (_underlying) {
//transfer user GHST
require(GHST.transferFrom(msg.sender, address(this), _amount));
//convert to amGHST
aaveLendingPool.deposit(address(GHST), _amount, address(this), 0);
} else {
//transfer user amGHST
require(IERC20(amGHST).transferFrom(msg.sender, address(this), _amount));
}

//convert to wamGHST
uint256 deposited = IStaticATokenLM(wamGHSTPool).deposit(address(this), _amount, 0, false);

//forward tokens
IERC20(wamGHSTPool).transfer(_to, deposited);

//convert to stkWAmGhst on behalf of address(this)
IStakingFacet(stakingDiamond).stakeIntoPoolForUser(wamGHSTPool, deposited, _to);
}

///@notice Allow an address to withdraw stkwamGHST from the staking pool
///@notice user can either unwrap to amGHST or GHST directly
///@param _amount Amount of tokens to unstake
///@param _to Address to unstake for
///@param _toUnderlying true if amGHST should be converted to GHST before sending back, false if amGHST should be sent back directly
function unwrapAndWithdraw(
uint256 _amount,
address _to,
bool _toUnderlying
) external {
uint256 toWithdraw;
//get user wamGHST by burning stkWamGHST
IStakingFacet(stakingDiamond).withdrawFromPoolForUser(wamGHSTPool, _amount, _to);
//transfer to contract
require(IERC20(wamGHSTPool).transferFrom(_to, address(this), _amount));
//Convert back to GHST
if (_toUnderlying) {
//convert wamGHST back to amGHST
(, toWithdraw) = IStaticATokenLM(wamGHSTPool).withdraw(address(this), _amount, false);
//convert amGHST to GHST and send directly
aaveLendingPool.withdraw(address(GHST), toWithdraw, _to);
} else {
//withdraw amGHST and send back
IStaticATokenLM(wamGHSTPool).withdraw(_to, _amount, false);
}
}
}
117 changes: 68 additions & 49 deletions contracts/facets/StakingFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -165,26 +165,32 @@ contract StakingFacet {
}
Epoch memory epoch = s.epochs[_epoch];
address[] memory supportedPools = epoch.supportedPools;
uint256 lastFrensUpdate = s.accounts[_account].lastFrensUpdate;
uint256 sinceLastFrensUpdate = block.timestamp - s.accounts[_account].lastFrensUpdate;

uint256 duration = 0;
uint256 epochDuration = 0;

uint256 timeSinceLastFrensUpdate = block.timestamp - lastFrensUpdate;

if (epoch.endTime == 0) {
//When epoch is not over yet
epochDuration = block.timestamp - epoch.beginTime;
} else {
//When epoch is over
epochDuration = epoch.endTime - epoch.beginTime;
uint256 epochDuration = block.timestamp - epoch.beginTime;
//Time since last update is longer than the current epoch, so only use epoch time
if (sinceLastFrensUpdate > epochDuration) {
duration = epochDuration;
} else {
//Otherwise use timeSinceLastFrensUpdate
duration = sinceLastFrensUpdate;
}
}
//Time since last update is longer than the current epoch, so only use epoch time
if (timeSinceLastFrensUpdate > epochDuration) {
duration = epochDuration;
} else {
//Otherwise use timeSinceLastFrensUpdate
duration = timeSinceLastFrensUpdate;
//When epoch is over
else {
uint256 epochDuration = epoch.endTime - epoch.beginTime;

//Duration cannot exceed epochDuration
if (sinceLastFrensUpdate > epochDuration) {
duration = epochDuration;

//last update is shorter than epochDuration
} else {
duration = sinceLastFrensUpdate;
}
}

uint256 accumulatedFrens = 0;
Expand Down Expand Up @@ -331,68 +337,82 @@ contract StakingFacet {
|__________________________________*/

function stakeIntoPool(address _poolContractAddress, uint256 _amount) public {
address sender = LibMeta.msgSender();
stakeIntoPoolForUser(_poolContractAddress, _amount, LibMeta.msgSender());
}

function stakeIntoPoolForUser(
address _poolContractAddress,
uint256 _amount,
address _sender
) public {
require(LibMeta.msgSender() == _sender || tx.origin == _sender, "StakingFacet: Not authorized");
require(_validPool(_poolContractAddress) == true, "StakingFacet: Pool is not valid in this epoch");
require(IERC20(_poolContractAddress).balanceOf(_sender) >= _amount, "StakingFacet: Insufficient token balance");

require(IERC20(_poolContractAddress).balanceOf(sender) >= _amount, "StakingFacet: Insufficient token balance");

_migrateOrUpdate(sender);
_migrateOrUpdate(_sender);

//Credit the user's with their new LP token balance
s.accounts[sender].accountStakedTokens[_poolContractAddress] += _amount;
s.accounts[_sender].accountStakedTokens[_poolContractAddress] += _amount;

if (_poolContractAddress == s.ghstContract) {
//Do nothing for original GHST contract
} else if (_poolContractAddress == s.poolContract) {
//Keep the GHST-QUICK staking token balance up to date
s.accounts[sender].ghstStakingTokens += _amount;
s.accounts[_sender].ghstStakingTokens += _amount;
s.ghstStakingTokensTotalSupply += _amount;
emit Transfer(address(0), sender, _amount);
emit Transfer(address(0), _sender, _amount);
} else {
//Use mintable for minting other stkGHST- tokens
address stkTokenAddress = s.pools[_poolContractAddress].receiptToken;
IERC20Mintable(stkTokenAddress).mint(sender, _amount);
IERC20Mintable(stkTokenAddress).mint(_sender, _amount);
}

//Transfer the LP tokens into the Diamond
LibERC20.transferFrom(_poolContractAddress, sender, address(this), _amount);
LibERC20.transferFrom(_poolContractAddress, _sender, address(this), _amount);

emit StakeInEpoch(sender, _poolContractAddress, s.currentEpoch, _amount);
emit StakeInEpoch(_sender, _poolContractAddress, s.currentEpoch, _amount);
}

function withdrawFromPool(address _poolContractAddress, uint256 _amount) public {
address sender = LibMeta.msgSender();
function withdrawFromPoolForUser(
address _poolContractAddress,
uint256 _amount,
address _sender
) public {
require(LibMeta.msgSender() == _sender || tx.origin == _sender, "StakingFacet: Not authorized");

_migrateOrUpdate(sender);
_migrateOrUpdate(_sender);

address receiptTokenAddress = s.pools[_poolContractAddress].receiptToken;
uint256 stakedBalance = s.accounts[sender].accountStakedTokens[_poolContractAddress];
uint256 stakedBalance = s.accounts[_sender].accountStakedTokens[_poolContractAddress];

//GHST does not have a receipt token
if (receiptTokenAddress != address(0)) {
require(IERC20(receiptTokenAddress).balanceOf(sender) >= _amount, "StakingFacet: Receipt token insufficient");
require(IERC20(receiptTokenAddress).balanceOf(_sender) >= _amount, "StakingFacet: Receipt token insufficient");
}

require(stakedBalance >= _amount, "StakingFacet: Can't withdraw more tokens than staked");

//Reduce user balance of staked token
s.accounts[sender].accountStakedTokens[_poolContractAddress] -= _amount;
s.accounts[_sender].accountStakedTokens[_poolContractAddress] -= _amount;

if (_poolContractAddress == s.ghstContract) {
//Do nothing for GHST
} else if (_poolContractAddress == s.poolContract) {
s.accounts[sender].ghstStakingTokens -= _amount;
s.accounts[_sender].ghstStakingTokens -= _amount;
s.ghstStakingTokensTotalSupply -= _amount;

emit Transfer(sender, address(0), _amount);
emit Transfer(_sender, address(0), _amount);
} else {
IERC20Mintable(receiptTokenAddress).burn(sender, _amount);
IERC20Mintable(receiptTokenAddress).burn(_sender, _amount);
}

//Transfer stake tokens from GHST diamond
LibERC20.transfer(_poolContractAddress, sender, _amount);
emit WithdrawInEpoch(sender, _poolContractAddress, s.currentEpoch, _amount);
LibERC20.transfer(_poolContractAddress, _sender, _amount);
emit WithdrawInEpoch(_sender, _poolContractAddress, s.currentEpoch, _amount);
}

function withdrawFromPool(address _poolContractAddress, uint256 _amount) public {
withdrawFromPoolForUser(_poolContractAddress, _amount, LibMeta.msgSender());
}

/***********************************|
Expand Down Expand Up @@ -505,22 +525,21 @@ contract StakingFacet {
| Deprecated Read Functions |
|__________________________________*/

function getGhstUsdcPoolToken() external view returns (address) {
return s.ghstUsdcPoolToken;
}
// function getGhstUsdcPoolToken() external view returns (address) {
// return s.ghstUsdcPoolToken;
// }

function getStkGhstUsdcToken() external view returns (address) {
return s.stkGhstUsdcToken;
}
// function getStkGhstUsdcToken() external view returns (address) {
// return s.stkGhstUsdcToken;
// }

function getGhstWethPoolToken() external view returns (address) {
return s.ghstWethPoolToken;
}

function getStkGhstWethToken() external view returns (address) {
return s.stkGhstWethToken;
}
// function getGhstWethPoolToken() external view returns (address) {
// return s.ghstWethPoolToken;
// }

// function getStkGhstWethToken() external view returns (address) {
// return s.stkGhstWethToken;
// }
function staked(address _account)
external
view
Expand Down
108 changes: 108 additions & 0 deletions contracts/interfaces/IStakingFacet.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;

interface IStakingFacet {
struct PoolInput {
address _poolAddress;
address _poolReceiptToken; //The receipt token for staking into this pool.
uint256 _rate;
string _poolName;
string _poolUrl;
}

struct PoolStakedOutput {
address poolAddress;
string poolName;
string poolUrl;
uint256 rate;
uint256 amount;
}

function addRateManagers(address[] memory rateManagers_) external;

function bulkFrens(address[] memory _accounts) external view returns (uint256[] memory frens_);

function bumpEpoch(address _account, uint256 _epoch) external;

function claimTickets(uint256[] memory _ids, uint256[] memory _values) external;

function convertTickets(uint256[] memory _ids, uint256[] memory _values) external;

function currentEpoch() external view returns (uint256);

function frens(address _account) external view returns (uint256 frens_);

function getGhstUsdcPoolToken() external view returns (address);

function getGhstWethPoolToken() external view returns (address);

function getPoolInfo(address _poolAddress, uint256 _epoch) external view returns (PoolInput memory);

function getStkGhstUsdcToken() external view returns (address);

function getStkGhstWethToken() external view returns (address);

function hasMigrated(address _account) external view returns (bool);

function initiateEpoch(PoolInput[] memory _pools) external;

function isRateManager(address account) external view returns (bool);

function migrateToV2(address[] memory _accounts) external;

function poolRatesInEpoch(uint256 _epoch) external view returns (PoolStakedOutput[] memory _rates);

function removeRateManagers(address[] memory rateManagers_) external;

function stakeGhst(uint256 _ghstValue) external;

function stakeGhstUsdcPoolTokens(uint256 _poolTokens) external;

function stakeGhstWethPoolTokens(uint256 _poolTokens) external;

function stakeIntoPool(address _poolContractAddress, uint256 _amount) external;

function stakePoolTokens(uint256 _poolTokens) external;

function withdrawFromPoolForUser(
address _poolContractAddress,
uint256 _amount,
address _sender
) external;

function stakeIntoPoolForUser(
address _poolContractAddress,
uint256 _amount,
address _sender
) external;

function staked(address _account)
external
view
returns (
uint256 ghst_,
uint256 poolTokens_,
uint256 ghstUsdcPoolToken_,
uint256 ghstWethPoolToken_
);

function stakedInCurrentEpoch(address _account) external view returns (PoolStakedOutput[] memory _staked);

function stakedInEpoch(address _account, uint256 _epoch) external view returns (PoolStakedOutput[] memory _staked);

function ticketCost(uint256 _id) external pure returns (uint256 _frensCost);

function updateRates(uint256 _currentEpoch, PoolInput[] memory _newPools) external;

function userEpoch(address _account) external view returns (uint256);

function withdrawFromPool(address _poolContractAddress, uint256 _amount) external;

function withdrawGhstStake(uint256 _ghstValue) external;

function withdrawGhstUsdcPoolStake(uint256 _poolTokens) external;

function withdrawGhstWethPoolStake(uint256 _poolTokens) external;

function withdrawPoolStake(uint256 _poolTokens) external;
}
Loading

0 comments on commit 0a0c161

Please sign in to comment.