diff --git a/contracts/mainnet/connectors/erc20_staking/events.sol b/contracts/mainnet/connectors/erc20_staking/events.sol new file mode 100644 index 00000000..a8b5ce2d --- /dev/null +++ b/contracts/mainnet/connectors/erc20_staking/events.sol @@ -0,0 +1,30 @@ +pragma solidity ^0.7.0; + +contract Events { + + event LogDeposit( + address indexed stakingToken, + bytes32 indexed stakingType, + uint256 amount, + uint getId, + uint setId + ); + + event LogWithdrawAndClaimedReward( + address indexed stakingToken, + bytes32 indexed stakingType, + uint256 amount, + uint256 rewardAmt, + uint getId, + uint setIdAmount, + uint setIdReward + ); + + event LogClaimedReward( + address indexed rewardToken, + bytes32 indexed stakingType, + uint256 rewardAmt, + uint setId + ); + +} \ No newline at end of file diff --git a/contracts/mainnet/connectors/erc20_staking/helpers.sol b/contracts/mainnet/connectors/erc20_staking/helpers.sol new file mode 100644 index 00000000..f559e69e --- /dev/null +++ b/contracts/mainnet/connectors/erc20_staking/helpers.sol @@ -0,0 +1,48 @@ +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; + + +import { DSMath } from "../../common/math.sol"; +import { Basic } from "../../common/basic.sol"; +import { TokenInterface } from "../../common/interfaces.sol"; +import { IStakingRewards, StakingERC20Mapping } from "./interface.sol"; + +abstract contract Helpers is DSMath, Basic { + + /** + * @dev Convert String to bytes32. + */ + function stringToBytes32(string memory str) internal pure returns (bytes32 result) { + require(bytes(str).length != 0, "string-empty"); + // solium-disable-next-line security/no-inline-assembly + assembly { + result := mload(add(str, 32)) + } + } + + /** + * @dev Get staking data + */ + function getStakingData(string memory stakingName) + internal + view + returns ( + IStakingRewards stakingContract, + TokenInterface stakingToken, + TokenInterface rewardToken, + bytes32 stakingType + ) + { + stakingType = stringToBytes32(stakingName); + StakingERC20Mapping.StakingData memory stakingData = StakingERC20Mapping(getMappingAddr()).stakingMapping(stakingType); + require(stakingData.stakingPool != address(0) && stakingData.stakingToken != address(0), "Wrong Staking Name"); + stakingContract = IStakingRewards(stakingData.stakingPool); + stakingToken = TokenInterface(stakingData.stakingToken); + rewardToken = TokenInterface(stakingData.rewardToken); + } + + function getMappingAddr() internal virtual view returns (address) { + return 0xbE658233bA9990d86155b3902fd05a7AfC7eBdB5; // InstaMapping Address + } + +} \ No newline at end of file diff --git a/contracts/mainnet/connectors/erc20_staking/interface.sol b/contracts/mainnet/connectors/erc20_staking/interface.sol new file mode 100644 index 00000000..d9a209fd --- /dev/null +++ b/contracts/mainnet/connectors/erc20_staking/interface.sol @@ -0,0 +1,21 @@ +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; + +interface IStakingRewards { + function stake(uint256 amount) external; + function withdraw(uint256 amount) external; + function getReward() external; + function balanceOf(address) external view returns(uint); +} + +interface StakingERC20Mapping { + + struct StakingData { + address stakingPool; + address stakingToken; + address rewardToken; + } + + function stakingMapping(bytes32) external view returns(StakingData memory); + +} \ No newline at end of file diff --git a/contracts/mainnet/connectors/erc20_staking/main.sol b/contracts/mainnet/connectors/erc20_staking/main.sol new file mode 100644 index 00000000..176b21fa --- /dev/null +++ b/contracts/mainnet/connectors/erc20_staking/main.sol @@ -0,0 +1,120 @@ +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; + +/** + * @title Token Staking. + * @dev Stake ERC20 for earning rewards. + */ + +import { TokenInterface } from "../../common/interfaces.sol"; +import { Stores } from "../../common/stores.sol"; +import { Helpers } from "./helpers.sol"; +import { Events } from "./events.sol"; +import { IStakingRewards, StakingERC20Mapping } from "./interface.sol"; + +contract Main is Helpers, Events { + + /** + * @dev Deposit ERC20. + * @notice Deposit Tokens to staking pool. + * @param stakingPoolName staking pool name. + * @param amt staking token amount. + * @param getId ID to retrieve amount. + * @param setId ID stores the amount of staked tokens. + */ + function deposit( + string calldata stakingPoolName, + uint amt, + uint getId, + uint setId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + uint _amt = getUint(getId, amt); + ( + IStakingRewards stakingContract, + TokenInterface stakingToken, + , + bytes32 stakingType + ) = getStakingData(stakingPoolName); + + _amt = _amt == uint(-1) ? stakingToken.balanceOf(address(this)) : _amt; + + stakingToken.approve(address(stakingContract), _amt); + stakingContract.stake(_amt); + + setUint(setId, _amt); + _eventName = "LogDeposit(address,bytes32,uint256,uint256,uint256)"; + _eventParam = abi.encode(address(stakingToken), stakingType, _amt, getId, setId); + } + + /** + * @dev Withdraw ERC20. + * @notice Withdraw Tokens from the staking pool. + * @param stakingPoolName staking pool name. + * @param amt staking token amount. + * @param getId ID to retrieve amount. + * @param setIdAmount ID stores the amount of stake tokens withdrawn. + * @param setIdReward ID stores the amount of reward tokens claimed. + */ + function withdraw( + string calldata stakingPoolName, + uint amt, + uint getId, + uint setIdAmount, + uint setIdReward + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + uint _amt = getUint(getId, amt); + ( + IStakingRewards stakingContract, + TokenInterface stakingToken, + TokenInterface rewardToken, + bytes32 stakingType + ) = getStakingData(stakingPoolName); + + _amt = _amt == uint(-1) ? stakingContract.balanceOf(address(this)) : _amt; + uint intialBal = rewardToken.balanceOf(address(this)); + stakingContract.withdraw(_amt); + stakingContract.getReward(); + + uint rewardAmt = sub(rewardToken.balanceOf(address(this)), intialBal); + + setUint(setIdAmount, _amt); + setUint(setIdReward, rewardAmt); + { + _eventName = "LogWithdrawAndClaimedReward(address,bytes32,uint256,uint256,uint256,uint256,uint256)"; + _eventParam = abi.encode(address(stakingToken), stakingType, _amt, rewardAmt, getId, setIdAmount, setIdReward); + } + } + + /** + * @dev Claim Reward. + * @notice Claim Pending Rewards of tokens staked. + * @param stakingPoolName staking pool name. + * @param setId ID stores the amount of reward tokens claimed. + */ + function claimReward( + string calldata stakingPoolName, + uint setId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + ( + IStakingRewards stakingContract, + , + TokenInterface rewardToken, + bytes32 stakingType + ) = getStakingData(stakingPoolName); + + uint intialBal = rewardToken.balanceOf(address(this)); + stakingContract.getReward(); + uint finalBal = rewardToken.balanceOf(address(this)); + + uint rewardAmt = sub(finalBal, intialBal); + + setUint(setId, rewardAmt); + _eventName = "LogClaimedReward(address,bytes32,uint256,uint256)"; + _eventParam = abi.encode(address(rewardToken), stakingType, rewardAmt, setId); + } + +} + +contract connectV2StakeERC20 is Main { + string public constant name = "Stake-ERC20-v1.0"; +} \ No newline at end of file diff --git a/contracts/mainnet/connectors/uniswap_v3_erc20/events.sol b/contracts/mainnet/connectors/uniswap_v3_erc20/events.sol new file mode 100644 index 00000000..e5ed811d --- /dev/null +++ b/contracts/mainnet/connectors/uniswap_v3_erc20/events.sol @@ -0,0 +1,34 @@ +pragma solidity ^0.7.0; + +contract Events { + + event LogDepositLiquidity( + address indexed pool, + uint256 amtA, + uint256 amtB, + uint256 mintAmount, + uint256[] getIds, + uint256 setId + ); + + event LogWithdrawLiquidity( + address indexed pool, + uint256 amountA, + uint256 amountB, + uint256 burnAmount, + uint256 getId, + uint256[] setIds + ); + + event LogSwapAndDepositLiquidity( + address indexed pool, + uint256 amtA, + uint256 amtB, + uint256 mintAmount, + bool zeroForOne, + uint swapAmount, + uint256 getId, + uint256 setId + ); + +} \ No newline at end of file diff --git a/contracts/mainnet/connectors/uniswap_v3_erc20/helpers.sol b/contracts/mainnet/connectors/uniswap_v3_erc20/helpers.sol new file mode 100644 index 00000000..9f30150f --- /dev/null +++ b/contracts/mainnet/connectors/uniswap_v3_erc20/helpers.sol @@ -0,0 +1,32 @@ +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; + +import { DSMath } from "../../common/math.sol"; +import { Basic } from "../../common/basic.sol"; + +import { IGUniRouter, IGUniPool, IERC20 } from "./interface.sol"; + + +abstract contract Helpers is DSMath, Basic { + + IGUniRouter public constant gUniRouter = IGUniRouter(0x8CA6fa325bc32f86a12cC4964Edf1f71655007A7); + + struct DepositAndSwap { + IGUniPool poolContract; + IERC20 _token0; + IERC20 _token1; + uint amount0; + uint amount1; + uint mintAmount; + } + + struct Deposit { + IGUniPool poolContract; + IERC20 _token0; + IERC20 _token1; + uint amount0In; + uint amount1In; + uint mintAmount; + } + +} diff --git a/contracts/mainnet/connectors/uniswap_v3_erc20/interface.sol b/contracts/mainnet/connectors/uniswap_v3_erc20/interface.sol new file mode 100644 index 00000000..52b45e77 --- /dev/null +++ b/contracts/mainnet/connectors/uniswap_v3_erc20/interface.sol @@ -0,0 +1,120 @@ +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; + + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +interface IGUniPool { + + function token0() external view returns (IERC20); + + function token1() external view returns (IERC20); + + function mint( + uint256 amount, + address receiver + ) external + returns ( + uint256 amount0, + uint256 amount1, + uint256 mintAmount + ); + + function burn( + uint256 _burnAmount, + address _receiver + ) external + returns ( + uint256 amount0, + uint256 amount1, + uint128 liquidityBurned + ); + + function getMintAmounts( + uint256 amount0Max, + uint256 amount1Max + ) external view + returns ( + uint256 amount0, + uint256 amount1, + uint256 mintAmount + ); + +} + + +interface IGUniRouter { + function rebalanceAndAddLiquidity( + IGUniPool pool, + uint256 amount0In, + uint256 amount1In, + bool zeroForOne, + uint256 swapAmount, + uint160 swapThreshold, + uint256 amount0Min, + uint256 amount1Min, + address receiver + ) + external + returns ( + uint256 amount0, + uint256 amount1, + uint256 mintAmount + ); + + function rebalanceAndAddLiquidityETH( + IGUniPool pool, + uint256 amount0In, + uint256 amount1In, + bool zeroForOne, + uint256 swapAmount, + uint160 swapThreshold, + uint256 amount0Min, + uint256 amount1Min, + address receiver + ) + external + payable + returns ( + uint256 amount0, + uint256 amount1, + uint256 mintAmount + ); + + function removeLiquidity( + IGUniPool pool, + uint256 burnAmount, + uint256 amount0Min, + uint256 amount1Min, + address receiver + ) + external + returns ( + uint256 amount0, + uint256 amount1, + uint128 liquidityBurned + ); + + function removeLiquidityETH( + IGUniPool pool, + uint256 burnAmount, + uint256 amount0Min, + uint256 amount1Min, + address payable receiver + ) + external + returns ( + uint256 amount0, + uint256 amount1, + uint128 liquidityBurned + ); +} + +interface TokenInterface { + function approve(address, uint256) external; + function transfer(address, uint) external; + function transferFrom(address, address, uint) external; + function deposit() external payable; + function withdraw(uint) external; + function balanceOf(address) external view returns (uint); + function decimals() external view returns (uint); +} \ No newline at end of file diff --git a/contracts/mainnet/connectors/uniswap_v3_erc20/main.sol b/contracts/mainnet/connectors/uniswap_v3_erc20/main.sol new file mode 100644 index 00000000..3c7895bd --- /dev/null +++ b/contracts/mainnet/connectors/uniswap_v3_erc20/main.sol @@ -0,0 +1,220 @@ +pragma solidity ^0.7.0; + +/** + * @title G-Uniswap V3 ERC20 Wrapper. + * @dev G-Uniswap V3 Wrapper to deposit and withdraw. + */ + +import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; + +import { TokenInterface } from "../../common/interfaces.sol"; +import { IGUniPool, IERC20 } from "./interface.sol"; +import { Helpers } from "./helpers.sol"; +import { Events } from "./events.sol"; + +abstract contract UniswapV3Resolver is Events, Helpers { + using SafeERC20 for IERC20; + + /** + * @dev Deposit Liquidity. + * @notice Deposit Liquidity to Gelato Uniswap V3 pool. + * @param pool The address of pool. + * @param amt0Max Amount0 Max amount + * @param amt1Max Amount1 Max amount + * @param slippage use to calculate minimum deposit. 100% = 1e18 + * @param getIds Array of IDs to retrieve amounts. + * @param setId ID stores the amount of pools tokens received. + */ + function deposit( + address pool, + uint256 amt0Max, + uint256 amt1Max, + uint slippage, + uint256[] calldata getIds, + uint256 setId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + + amt0Max = getUint(getIds[0], amt0Max); + amt1Max = getUint(getIds[1], amt1Max); + + Deposit memory depositData; + depositData.poolContract = IGUniPool(pool); + + (depositData.amount0In, depositData.amount1In, depositData.mintAmount) = + depositData.poolContract.getMintAmounts(amt0Max, amt1Max); + + uint amt0Min = wmul(amt0Max, slippage); + uint amt1Min = wmul(amt1Max, slippage); + + require( + depositData.amount0In >= amt0Min && depositData.amount1In >= amt1Min, + "below min amounts" + ); + + if (depositData.amount0In > 0) { + IERC20 _token0 = depositData.poolContract.token0(); + convertEthToWeth(address(_token0) == wethAddr, TokenInterface(address(_token0)), depositData.amount0In); + _token0.safeApprove(address(pool), depositData.amount0In); + } + if (depositData.amount1In > 0) { + IERC20 _token1 = depositData.poolContract.token1(); + convertEthToWeth(address(_token1) == wethAddr, TokenInterface(address(_token1)), depositData.amount1In); + _token1.safeApprove(address(pool), depositData.amount1In); + } + + (uint amount0, uint amount1,) = depositData.poolContract.mint(depositData.mintAmount, address(this)); + + require( + amount0 == depositData.amount0In && + amount1 == depositData.amount1In, "unexpected amounts deposited"); + + setUint(setId, depositData.mintAmount); + + _eventName = "LogDepositLiquidity(address,uint256,uint256,uint256,uint256[],uint256)"; + _eventParam = abi.encode(pool, amount0, amount1, depositData.mintAmount, getIds, setId); + } + + + /** + * @dev Withdraw Liquidity. + * @notice Withdraw Liquidity from Gelato Uniswap V3 pool. + * @param pool The address of pool. + * @param liqAmt Amount0 Max amount + * @param minAmtA Min AmountA amount + * @param minAmtB Min AmountB amount + * @param getId ID to retrieve liqAmt. + * @param setIds Array of IDs tp stores the amounts of pools tokens received. + */ + function withdraw( + address pool, + uint256 liqAmt, + uint256 minAmtA, + uint256 minAmtB, + uint256 getId, + uint256[] calldata setIds + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + + liqAmt = getUint(getId, liqAmt); + + IGUniPool poolContract = IGUniPool(pool); + + (uint amount0, uint amount1, uint128 liquidityBurned) = poolContract.burn(liqAmt, address(this)); + + if (amount0 > 0) { + IERC20 _token0 = poolContract.token0(); + convertWethToEth(address(_token0) == wethAddr, TokenInterface(address(_token0)), amount0); + } + + if (amount1 > 0) { + IERC20 _token1 = poolContract.token1(); + convertWethToEth(address(_token1) == wethAddr, TokenInterface(address(_token1)), amount1); + } + + require(amount0 >= minAmtA && amount1 >= minAmtB, "received below minimum"); + + setUint(setIds[0], amount0); + setUint(setIds[1], amount1); + + _eventName = "LogWithdrawLiquidity(address,uint256,uint256,uint256,uint256,uint256[])"; + _eventParam = abi.encode(pool, amount0, amount1, uint256(liquidityBurned), getId, setIds); + } + + /** + * @dev Swap & Deposit Liquidity. + * @notice Withdraw Liquidity to Gelato Uniswap V3 pool. + * @param pool The address of pool. + * @param amount0In amount of token0 to deposit. + * @param amount1In amount of token1 to deposit. + * @param zeroForOne Swap excess of one token to deposit in equal ratio. + * @param swapAmount Amount of tokens to swap + * @param swapThreshold Slippage that the swap could take. + * @param getId Not used anywhere here. + * @param setId Set the amount of tokens minted. + */ + function swapAndDeposit( + address pool, + uint256 amount0In, + uint256 amount1In, + bool zeroForOne, + uint256 swapAmount, + uint160 swapThreshold, + uint256 getId, + uint256 setId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + DepositAndSwap memory depositAndSwap; + depositAndSwap.poolContract = IGUniPool(pool); + depositAndSwap._token0 = depositAndSwap.poolContract.token0(); + depositAndSwap._token1 = depositAndSwap.poolContract.token1(); + + depositAndSwap.amount0; + depositAndSwap.amount1; + depositAndSwap.mintAmount; + + if (address(depositAndSwap._token0) == wethAddr) { + depositAndSwap._token1.approve(address(gUniRouter), amount1In); + + (depositAndSwap.amount0, depositAndSwap.amount1, depositAndSwap.mintAmount) = + gUniRouter.rebalanceAndAddLiquidityETH{value: amount0In}( + depositAndSwap.poolContract, + amount0In, + amount1In, + zeroForOne, + swapAmount, + swapThreshold, + 0, + 0, + address(this) + ); + } else if (address(depositAndSwap._token1) == wethAddr) { + depositAndSwap._token0.approve(address(gUniRouter), amount0In); + + (depositAndSwap.amount0, depositAndSwap.amount1,depositAndSwap. mintAmount) = + gUniRouter.rebalanceAndAddLiquidityETH{value: amount1In}( + depositAndSwap.poolContract, + amount0In, + amount1In, + zeroForOne, + swapAmount, + swapThreshold, + 0, + 0, + address(this) + ); + } else { + depositAndSwap._token0.approve(address(gUniRouter), amount0In); + depositAndSwap._token1.approve(address(gUniRouter), amount1In); + (depositAndSwap.amount0, depositAndSwap.amount1, depositAndSwap.mintAmount) = + gUniRouter.rebalanceAndAddLiquidity( + depositAndSwap.poolContract, + amount0In, + amount1In, + zeroForOne, + swapAmount, + swapThreshold, + 0, + 0, + address(this) + ); + } + + setUint(setId, depositAndSwap.mintAmount); + + _eventName = "LogSwapAndDepositLiquidity(address,uint256,uint256,uint256,bool,uint256,uint256,uint256)"; + _eventParam = abi.encode( + pool, + depositAndSwap.amount0, + depositAndSwap.amount1, + depositAndSwap.mintAmount, + zeroForOne, + swapAmount, + getId, + setId + ); + + } + +} + +contract ConnectV2GUniswapV3ERC20 is UniswapV3Resolver { + string public constant name = "G-Uniswap-v3-ERC20-v1.0"; +} diff --git a/contracts/mainnet/connectors/uniswap_v3_erc20_staking/events.sol b/contracts/mainnet/connectors/uniswap_v3_erc20_staking/events.sol new file mode 100644 index 00000000..4e75acd1 --- /dev/null +++ b/contracts/mainnet/connectors/uniswap_v3_erc20_staking/events.sol @@ -0,0 +1,27 @@ +pragma solidity ^0.7.0; + +contract Events { + + event LogDeposit( + address indexed stakingToken, + uint256 amount, + uint getId, + uint setId + ); + + event LogWithdrawAndClaimedReward( + address indexed stakingToken, + uint256 amount, + uint256 rewardAmt, + uint getId, + uint setIdAmount, + uint setIdReward + ); + + event LogClaimedReward( + address indexed rewardToken, + uint256 rewardAmt, + uint setId + ); + +} \ No newline at end of file diff --git a/contracts/mainnet/connectors/uniswap_v3_erc20_staking/helpers.sol b/contracts/mainnet/connectors/uniswap_v3_erc20_staking/helpers.sol new file mode 100644 index 00000000..1d0c6d94 --- /dev/null +++ b/contracts/mainnet/connectors/uniswap_v3_erc20_staking/helpers.sol @@ -0,0 +1,24 @@ +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; + + +import { DSMath } from "../../common/math.sol"; +import { Basic } from "../../common/basic.sol"; +import { TokenInterface } from "../../common/interfaces.sol"; +import { IStakingRewards, IStakingRewardsFactory, IGUniPoolResolver } from "./interface.sol"; + +abstract contract Helpers is DSMath, Basic { + + IGUniPoolResolver constant internal guniResolver = + IGUniPoolResolver(0x729BF02a9A786529Fc80498f8fd0051116061B13); + + TokenInterface constant internal rewardToken = TokenInterface(0x6f40d4A6237C257fff2dB00FA0510DeEECd303eb); + + function getStakingContract(address stakingToken) internal view returns (address) { + IStakingRewardsFactory.StakingRewardsInfo memory stakingRewardsInfo = + guniResolver.getStakingFactory().stakingRewardsInfoByStakingToken(stakingToken); + + return stakingRewardsInfo.stakingRewards; + } + +} \ No newline at end of file diff --git a/contracts/mainnet/connectors/uniswap_v3_erc20_staking/interface.sol b/contracts/mainnet/connectors/uniswap_v3_erc20_staking/interface.sol new file mode 100644 index 00000000..73ccbe03 --- /dev/null +++ b/contracts/mainnet/connectors/uniswap_v3_erc20_staking/interface.sol @@ -0,0 +1,26 @@ +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; + +interface IStakingRewards { + function stake(uint256 amount) external; + function withdraw(uint256 amount) external; + function getReward() external; + function balanceOf(address) external view returns(uint); +} + +interface IStakingRewardsFactory { + + struct StakingRewardsInfo { + address stakingRewards; + uint rewardAmount; + } + + function stakingRewardsInfoByStakingToken(address) external view returns(StakingRewardsInfo memory); + +} + +interface IGUniPoolResolver { + + function getStakingFactory() external view returns(IStakingRewardsFactory); + +} \ No newline at end of file diff --git a/contracts/mainnet/connectors/uniswap_v3_erc20_staking/main.sol b/contracts/mainnet/connectors/uniswap_v3_erc20_staking/main.sol new file mode 100644 index 00000000..4cd4fbcc --- /dev/null +++ b/contracts/mainnet/connectors/uniswap_v3_erc20_staking/main.sol @@ -0,0 +1,108 @@ +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; + +/** + * @title G-UNI Staking. + * @dev Stake G-UNI for earning rewards. + */ + +import { TokenInterface } from "../../common/interfaces.sol"; +import { Stores } from "../../common/stores.sol"; +import { Helpers } from "./helpers.sol"; +import { Events } from "./events.sol"; +import { IStakingRewards, IStakingRewardsFactory } from "./interface.sol"; + +contract Main is Helpers, Events { + + /** + * @dev Deposit ERC20. + * @notice Deposit Tokens to staking pool. + * @param stakingToken staking token address. + * @param amt staking token amount. + * @param getId ID to retrieve amount. + * @param setId ID stores the amount of staked tokens. + */ + function deposit( + address stakingToken, + uint amt, + uint getId, + uint setId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + uint _amt = getUint(getId, amt); + + IStakingRewards stakingContract = IStakingRewards(getStakingContract(stakingToken)); + TokenInterface stakingTokenContract = TokenInterface(stakingToken); + + _amt = _amt == uint(-1) ? stakingTokenContract.balanceOf(address(this)) : _amt; + + stakingTokenContract.approve(address(stakingContract), _amt); + stakingContract.stake(_amt); + + setUint(setId, _amt); + _eventName = "LogDeposit(address,uint256,uint256,uint256)"; + _eventParam = abi.encode(address(stakingToken), _amt, getId, setId); + } + + /** + * @dev Withdraw ERC20. + * @notice Withdraw Tokens from the staking pool. + * @param stakingToken staking token address. + * @param amt staking token amount. + * @param getId ID to retrieve amount. + * @param setIdAmount ID stores the amount of stake tokens withdrawn. + * @param setIdReward ID stores the amount of reward tokens claimed. + */ + function withdraw( + address stakingToken, + uint amt, + uint getId, + uint setIdAmount, + uint setIdReward + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + uint _amt = getUint(getId, amt); + + IStakingRewards stakingContract = IStakingRewards(getStakingContract(stakingToken)); + + _amt = _amt == uint(-1) ? stakingContract.balanceOf(address(this)) : _amt; + uint intialBal = rewardToken.balanceOf(address(this)); + stakingContract.withdraw(_amt); + stakingContract.getReward(); + + uint rewardAmt = sub(rewardToken.balanceOf(address(this)), intialBal); + + setUint(setIdAmount, _amt); + setUint(setIdReward, rewardAmt); + { + _eventName = "LogWithdrawAndClaimedReward(address,uint256,uint256,uint256,uint256,uint256)"; + _eventParam = abi.encode(address(stakingToken), _amt, rewardAmt, getId, setIdAmount, setIdReward); + } + } + + /** + * @dev Claim Reward. + * @notice Claim Pending Rewards of tokens staked. + * @param stakingToken staking token address. + * @param setId ID stores the amount of reward tokens claimed. + */ + function claimReward( + address stakingToken, + uint setId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + IStakingRewards stakingContract = IStakingRewards(getStakingContract(stakingToken)); + + uint intialBal = rewardToken.balanceOf(address(this)); + stakingContract.getReward(); + uint finalBal = rewardToken.balanceOf(address(this)); + + uint rewardAmt = sub(finalBal, intialBal); + + setUint(setId, rewardAmt); + _eventName = "LogClaimedReward(address,uint256,uint256)"; + _eventParam = abi.encode(address(rewardToken), rewardAmt, setId); + } + +} + +contract connectV2StakeGUNI is Main { + string public constant name = "Stake-G-UNI-v1.0"; +} \ No newline at end of file diff --git a/contracts/mainnet/mapping/StakeERC20.sol b/contracts/mainnet/mapping/StakeERC20.sol new file mode 100644 index 00000000..4594d9b8 --- /dev/null +++ b/contracts/mainnet/mapping/StakeERC20.sol @@ -0,0 +1,119 @@ +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; + +interface ConnectorsInterface { + function chief(address) external view returns (bool); +} + +interface IndexInterface { + function master() external view returns (address); +} + +contract BytesHelper { + /** + * @dev Convert String to bytes32. + */ + function stringToBytes32(string memory str) internal pure returns (bytes32 result) { + require(bytes(str).length != 0, "String-Empty"); + // solium-disable-next-line security/no-inline-assembly + assembly { + result := mload(add(str, 32)) + } + } + + /** + * @dev Convert bytes32 to String. + */ + function bytes32ToString(bytes32 _bytes32) internal pure returns (string memory) { + bytes32 _temp; + uint count; + for (uint256 i; i < 32; i++) { + _temp = _bytes32[i]; + if( _temp != bytes32(0)) { + count += 1; + } + } + bytes memory bytesArray = new bytes(count); + for (uint256 i; i < count; i++) { + bytesArray[i] = (_bytes32[i]); + } + return (string(bytesArray)); + } +} + +contract Helpers is BytesHelper { + address public constant connectorsV2 = 0x97b0B3A8bDeFE8cB9563a3c610019Ad10DB8aD11; + address public constant instaIndex = 0x2971AdFa57b20E5a416aE5a708A8655A9c74f723; + + mapping (bytes32 => StakingData) public stakingMapping; + + struct StakingData { + address stakingPool; + address stakingToken; + address rewardToken; + } + + event LogAddStakingMapping( + string stakingName, + bytes32 stakingType, + address stakingAddress, + address stakingToken, + address rewardToken + ); + event LogRemoveStakingMapping( + string stakingName, + bytes32 stakingType, + address stakingAddress, + address stakingToken, + address rewardToken + ); + + modifier isChief virtual { + require( + ConnectorsInterface(connectorsV2).chief(msg.sender) || + IndexInterface(instaIndex).master() == msg.sender, "not-Chief"); + _; + } + + function addStakingMapping( + string memory stakingName, + address stakingAddress, + address stakingToken, + address rewardToken + ) public isChief { + require(stakingAddress != address(0), "stakingAddress-not-vaild"); + require(stakingToken != address(0), "stakingToken-not-vaild"); + require(rewardToken != address(0), "rewardToken-not-vaild"); + require(bytes(stakingName).length <= 32, "Length-exceeds"); + bytes32 stakeType = stringToBytes32(stakingName); + require(stakingMapping[stakeType].stakingPool == address(0), "StakingPool-already-added"); + require(stakingMapping[stakeType].stakingToken == address(0), "StakingToken-already-added"); + require(stakingMapping[stakeType].rewardToken == address(0), "rewardToken-already-added"); + + stakingMapping[stakeType] = StakingData( + stakingAddress, + stakingToken, + rewardToken + ); + emit LogAddStakingMapping(stakingName, stakeType, stakingAddress, stakingToken, rewardToken); + } + + function removeStakingMapping(string memory stakingName, address stakingAddress) public isChief { + require(stakingAddress != address(0), "stakingAddress-not-vaild"); + bytes32 stakeType = stringToBytes32(stakingName); + require(stakingMapping[stakeType].stakingPool == stakingAddress, "different-staking-pool"); + + emit LogRemoveStakingMapping( + stakingName, + stakeType, + stakingAddress, + stakingMapping[stakeType].stakingToken, + stakingMapping[stakeType].rewardToken + ); + delete stakingMapping[stakeType]; + } +} + +contract InstaStakingERC20Mapping is Helpers { + string constant public name = "Staking-ERC20-Mapping-v1"; +}