Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add wamGHST pool #19

Merged
merged 34 commits into from
Mar 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
45800cb
forge install: protocol-v2
Timidan Jan 31, 2022
4e4bd37
push all changes
Timidan Feb 8, 2022
98b9bb2
remvoe unused interfaces and add console.logs, matic rewards
Timidan Feb 9, 2022
2f552cf
fix names
cinnabarhorse Feb 10, 2022
aabaf0f
Update staticAmGHST.sol
cinnabarhorse Feb 10, 2022
0bffea8
make little changes
Timidan Feb 10, 2022
eff082f
make changes based on Nicks review
Timidan Feb 13, 2022
9982e10
make name changes
Timidan Feb 13, 2022
de72bd8
allow permissionless staking
Timidan Feb 17, 2022
4d62dfe
add address checks
Timidan Feb 19, 2022
915505b
update imports
cinnabarhorse Feb 20, 2022
3dc9265
add StakingFacet sanity checks
Timidan Feb 21, 2022
7d28750
allow permissionless mints
Timidan Feb 28, 2022
b6c888f
remove router privileges
Timidan Feb 28, 2022
56cbe49
make changes
Timidan Mar 1, 2022
c43fa0b
allow direct deposits and withdrawals for amGHST
Timidan Mar 3, 2022
d1c8714
Update amGHSTRouter.sol
cinnabarhorse Mar 3, 2022
72ccd05
Update amGHSTRouter.sol
cinnabarhorse Mar 3, 2022
1cca0a0
remove unused files
Timidan Mar 3, 2022
1979f8f
Delete yarn.lock
Timidan Mar 3, 2022
2c01d23
remove extra files
Timidan Mar 4, 2022
fab7d67
Removed aave dependencies
Timidan Mar 5, 2022
b14f806
update rates in stkwamghst script
cinnabarhorse Mar 7, 2022
79b8108
Update stkwamGHSTTest.ts
cinnabarhorse Mar 7, 2022
5ba1018
Update deploystkwamGHST.ts
cinnabarhorse Mar 7, 2022
fb55fc3
check frens
Timidan Mar 7, 2022
1d45a9c
fix epoch time issue
cinnabarhorse Mar 7, 2022
ecc164c
fix duration
cinnabarhorse Mar 8, 2022
1b520ff
Update StakingFacet.sol
cinnabarhorse Mar 9, 2022
14cbc86
fix bug
Timidan Mar 10, 2022
6c1d6ff
correct commit
Timidan Mar 11, 2022
82b65da
add in owner methods
cinnabarhorse Mar 15, 2022
651a5d8
preparing to deploy
cinnabarhorse Mar 15, 2022
e6a5f82
finalize upgrade
cinnabarhorse Mar 15, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,8 @@ bin
typechain
coverage
flat
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);
}
}
}
100 changes: 61 additions & 39 deletions contracts/facets/StakingFacet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -153,25 +153,34 @@ contract StakingFacet {
function _frensForEpoch(address _account, uint256 _epoch) internal view returns (uint256) {
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;

//When epoch is not over yet
if (epoch.endTime == 0) {
uint256 epochDuration = block.timestamp - epoch.beginTime;
uint256 timeSinceLastFrensUpdate = block.timestamp - lastFrensUpdate;

//Time since last update is longer than the current epoch, so only use epoch time
if (timeSinceLastFrensUpdate > epochDuration) {
if (sinceLastFrensUpdate > epochDuration) {
duration = epochDuration;
} else {
//Otherwise use timeSinceLastFrensUpdate
duration = timeSinceLastFrensUpdate;
duration = sinceLastFrensUpdate;
}
}
//When epoch is over
else {
duration = epoch.endTime - epoch.beginTime;
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 @@ -294,68 +303,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 @@ -468,22 +491,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