From ab36769162a0c1cfeb8b6ce29c0bae381a918b2f Mon Sep 17 00:00:00 2001 From: Aalavandhan <6264334+aalavandhan@users.noreply.github.com> Date: Thu, 19 Dec 2024 11:40:52 -0500 Subject: [PATCH] router (#260) --- contracts/Router/CharmGeyserRouter.sol | 104 ++++++++++++++++++ .../{RouterV1.sol => Router/GeyserRouter.sol} | 10 +- 2 files changed, 109 insertions(+), 5 deletions(-) create mode 100644 contracts/Router/CharmGeyserRouter.sol rename contracts/{RouterV1.sol => Router/GeyserRouter.sol} (95%) diff --git a/contracts/Router/CharmGeyserRouter.sol b/contracts/Router/CharmGeyserRouter.sol new file mode 100644 index 00000000..dd92c6a7 --- /dev/null +++ b/contracts/Router/CharmGeyserRouter.sol @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity 0.7.6; +pragma abicoder v2; + +import {GeyserRouter, TransferHelper, IERC20, IERC721, IGeyser} from "./GeyserRouter.sol"; + +/// @notice Interface for a Charm LP token +interface ICharmLiqToken is IERC20 { + function token0() external view returns (address); + + function token1() external view returns (address); + + function deposit( + uint256, + uint256, + uint256, + uint256, + address + ) + external + returns ( + uint256, + uint256, + uint256 + ); +} + +/// @title CharmGeyserRouter +/// @notice Convenience contract to stake Charm LP tokens on geysers +/// @dev Security contact: dev-support@ampleforth.org +contract CharmGeyserRouter is GeyserRouter { + using TransferHelper for address; + + struct LiqCreationPayload { + uint256 token0Amt; + uint256 token1Amt; + uint256 token0MinAmt; + uint256 token1MinAmt; + } + + function createLiqAndStake( + address geyser, + address vault, + bytes calldata permission, + LiqCreationPayload memory d + ) public { + // Expects the geyser's staking token to be a Charm liquidity token + ICharmLiqToken charm = ICharmLiqToken(IGeyser(geyser).getGeyserData().stakingToken); + address depositToken0 = charm.token0(); + address depositToken1 = charm.token1(); + + // Get deposit tokens from user + depositToken0.safeTransferFrom(msg.sender, address(this), d.token0Amt); + depositToken1.safeTransferFrom(msg.sender, address(this), d.token1Amt); + + // Creates a charm liquidity position and + // transfers liquidity tokens directly to the vault + _checkAndApproveMax(depositToken0, address(charm), d.token0Amt); + _checkAndApproveMax(depositToken1, address(charm), d.token1Amt); + (uint256 lpAmt,,) = charm.deposit(d.token0Amt, d.token1Amt, d.token0MinAmt, d.token1MinAmt, vault); + + // Stake liquidity tokens from the vault + IGeyser(geyser).stake(vault, lpAmt, permission); + + // Transfer any remaining dust deposit tokens + _transferAll(depositToken0, msg.sender); + _transferAll(depositToken1, msg.sender); + } + + function create2VaultCreateLiqAndStake( + address geyser, + address vaultFactory, + address vaultOwner, + bytes32 salt, + bytes calldata permission, + LiqCreationPayload memory d + ) external returns (address vault) { + // create vault + vault = create2Vault(vaultFactory, salt); + + // transfer ownership + IERC721(vaultFactory).safeTransferFrom(address(this), vaultOwner, uint256(vault)); + + // create liquidity and stake + createLiqAndStake(geyser, vault, permission, d); + } + + /// @dev Checks if the spender has sufficient allowance. If not, approves the maximum possible amount. + function _checkAndApproveMax( + address token, + address spender, + uint256 amount + ) private { + uint256 allowance = IERC20(token).allowance(address(this), spender); + if (allowance < amount) { + IERC20(token).approve(spender, type(uint256).max); + } + } + + /// @dev Transfers the entire token balance to the given address. + function _transferAll(address token, address to) private { + token.safeTransfer(to, IERC20(token).balanceOf(address(this))); + } +} diff --git a/contracts/RouterV1.sol b/contracts/Router/GeyserRouter.sol similarity index 95% rename from contracts/RouterV1.sol rename to contracts/Router/GeyserRouter.sol index f769b672..b0c3e9ba 100644 --- a/contracts/RouterV1.sol +++ b/contracts/Router/GeyserRouter.sol @@ -8,14 +8,14 @@ import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Recei import {IERC20Permit} from "@openzeppelin/contracts/drafts/IERC20Permit.sol"; import {TransferHelper} from "@uniswap/lib/contracts/libraries/TransferHelper.sol"; -import {IGeyser} from "./Geyser.sol"; -import {IUniversalVault} from "./UniversalVault.sol"; -import {IFactory} from "./Factory/IFactory.sol"; +import {IGeyser} from "../Geyser.sol"; +import {IUniversalVault} from "../UniversalVault.sol"; +import {IFactory} from "../Factory/IFactory.sol"; -/// @title RouterV1 +/// @title GeyserRouter /// @notice Convenience contract for ampleforth geyser /// @dev Security contact: dev-support@ampleforth.org -contract RouterV1 is IERC721Receiver { +contract GeyserRouter is IERC721Receiver { function onERC721Received( address, address,