Skip to content

Commit

Permalink
Merge pull request #154 from meTokens/yieltoken-uni-migration
Browse files Browse the repository at this point in the history
Yieltoken uni migration
  • Loading branch information
zgorizzo69 authored May 2, 2022
2 parents 6f9a014 + 008cac9 commit 5ad5333
Show file tree
Hide file tree
Showing 17 changed files with 1,577 additions and 173 deletions.
4 changes: 4 additions & 0 deletions contracts/interfaces/IMigration.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ pragma solidity 0.8.9;
/// @title Generic migration vault interface
/// @author Carter Carlson (@cartercarlson)
interface IMigration {
/// @notice Method returns true is the migration has started
/// @param meToken Address of meToken
function isStarted(address meToken) external view returns (bool);

/// @notice Method to trigger actions from the migration vault if needed
/// @param meToken Address of meToken
function poke(address meToken) external;
Expand Down
180 changes: 122 additions & 58 deletions contracts/libs/LibFoundry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -53,38 +53,42 @@ library LibFoundry {
address sender = LibMeta.msgSender();
MeTokenInfo memory meTokenInfo = s.meTokens[meToken];
HubInfo memory hubInfo = s.hubs[meTokenInfo.hubId];

// Handling changes
if (hubInfo.updating && block.timestamp > hubInfo.endTime) {
LibHub.finishUpdate(meTokenInfo.hubId);
} else if (meTokenInfo.targetHubId != 0) {
if (block.timestamp > meTokenInfo.endTime) {
hubInfo = s.hubs[meTokenInfo.targetHubId];
meTokenInfo = LibMeToken.finishResubscribe(meToken);
} else if (block.timestamp > meTokenInfo.startTime) {
// Handle migration actions if needed
IMigration(meTokenInfo.migration).poke(meToken);
meTokenInfo = s.meTokens[meToken];
}
}
uint256[3] memory amounts;
amounts[1] = (assetsDeposited * s.mintFee) / s.PRECISION; // fee
amounts[2] = assetsDeposited - amounts[1]; //assetsDepositedAfterFees

amounts[0] = _calculateMeTokensMinted(meToken, amounts[2]); // meTokensMinted
IVault vault = IVault(hubInfo.vault);
address asset = hubInfo.asset;

// Check if meToken is using a migration vault and in the active stage of resubscribing.
// Sometimes a meToken may be resubscribing to a hub w/ the same asset,
// in which case a migration vault isn't needed
if (
meTokenInfo.migration != address(0) &&
block.timestamp > meTokenInfo.startTime
block.timestamp > meTokenInfo.startTime &&
IMigration(meTokenInfo.migration).isStarted(meToken)
) {
// Use meToken address to get the asset address from the migration vault
vault = IVault(meTokenInfo.migration);
asset = s.hubs[meTokenInfo.targetHubId].asset;
}
vault.handleDeposit(sender, asset, assetsDeposited, amounts[1]);
LibMeToken.updateBalancePooled(true, meToken, amounts[2]);

// Handling changes
if (hubInfo.updating && block.timestamp > hubInfo.endTime) {
LibHub.finishUpdate(meTokenInfo.hubId);
} else if (meTokenInfo.targetHubId != 0) {
if (block.timestamp > meTokenInfo.endTime) {
//hubInfo = s.hubs[meTokenInfo.targetHubId];
LibMeToken.finishResubscribe(meToken);
} else if (block.timestamp > meTokenInfo.startTime) {
// Handle migration actions if needed
IMigration(meTokenInfo.migration).poke(meToken);
}
}

return (vault, asset, sender, amounts);
}

Expand All @@ -94,14 +98,12 @@ library LibFoundry {
address recipient
) internal {
(
IVault vault,
,
address asset,
address sender,
uint256[3] memory amounts // 0-meTokensMinted 1-fee 2-assetsDepositedAfterFees
) = handleMint(meToken, assetsDeposited);
vault.handleDeposit(sender, asset, assetsDeposited, amounts[1]);

LibMeToken.updateBalancePooled(true, meToken, amounts[2]);
// Mint meToken to user
IMeToken(meToken).mint(recipient, amounts[0]);
emit Mint(
Expand All @@ -119,28 +121,24 @@ library LibFoundry {
uint256 assetsDeposited,
address recipient,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
uint8 vSig,
bytes32 rSig,
bytes32 sSig
) internal {
(
IVault vault,
address asset,
address sender,
uint256[3] memory amounts // 0-meTokensMinted 1-fee 2-assetsDepositedAfterFees
) = handleMint(meToken, assetsDeposited);
vault.handleDepositWithPermit(
sender,
asset,
assetsDeposited,
amounts[1],
deadline,
v,
r,
s
);
uint256[2] memory amounts // 0-meTokensMinted 1-assetsDepositedAfterFees
) = _handleMintWithPermit(
meToken,
assetsDeposited,
deadline,
vSig,
rSig,
sSig
);

LibMeToken.updateBalancePooled(true, meToken, amounts[2]);
LibMeToken.updateBalancePooled(true, meToken, amounts[1]);
// Mint meToken to user
IMeToken(meToken).mint(recipient, amounts[0]);
emit Mint(
Expand All @@ -166,15 +164,12 @@ library LibFoundry {
// Handling changes
if (hubInfo.updating && block.timestamp > hubInfo.endTime) {
LibHub.finishUpdate(meTokenInfo.hubId);
} else if (meTokenInfo.targetHubId != 0) {
if (block.timestamp > meTokenInfo.endTime) {
hubInfo = s.hubs[meTokenInfo.targetHubId];
meTokenInfo = LibMeToken.finishResubscribe(meToken);
} else if (block.timestamp > meTokenInfo.startTime) {
// Handle migration actions if needed
IMigration(meTokenInfo.migration).poke(meToken);
meTokenInfo = s.meTokens[meToken];
}
} else if (
meTokenInfo.targetHubId != 0 &&
block.timestamp > meTokenInfo.endTime
) {
hubInfo = s.hubs[meTokenInfo.targetHubId];
meTokenInfo = LibMeToken.finishResubscribe(meToken);
}
// Calculate how many tokens are returned
uint256 rawAssetsReturned = _calculateRawAssetsReturned(
Expand Down Expand Up @@ -218,6 +213,7 @@ library LibFoundry {
rawAssetsReturned - assetsReturned
);
}

_vaultWithdrawal(
sender,
recipient,
Expand All @@ -228,29 +224,97 @@ library LibFoundry {
assetsReturned,
feeRate
);
/* uint256 fee = (assetsReturned * feeRate) / s.PRECISION;
assetsReturned = assetsReturned - fee;
}

function _handleMintWithPermit(
address meToken,
uint256 assetsDeposited,
uint256 deadline,
uint8 vSig,
bytes32 rSig,
bytes32 sSig
)
private
returns (
address asset,
address sender,
uint256[2] memory amounts
)
{
AppStorage storage s = LibAppStorage.diamondStorage();
// 0-meTokensMinted 1-fee 2-assetsDepositedAfterFees

MeTokenInfo memory meTokenInfo = s.meTokens[meToken];
HubInfo memory hubInfo = s.hubs[meTokenInfo.hubId];

// uint256[2] memory amounts;
// amounts[1] = (assetsDeposited * s.mintFee) / s.PRECISION; // fee
amounts[1] =
assetsDeposited -
((assetsDeposited * s.mintFee) / s.PRECISION); //assetsDepositedAfterFees

amounts[0] = _calculateMeTokensMinted(meToken, amounts[1]); // meTokensMinted

asset = _handlingChangesWithPermit(
amounts[1],
meToken,
meTokenInfo,
hubInfo,
assetsDeposited,
deadline,
vSig,
rSig,
sSig
);
return (asset, sender, amounts);
}

function _handlingChangesWithPermit(
uint256 assetsDepositedAfterFees,
address meToken,
MeTokenInfo memory meTokenInfo,
HubInfo memory hubInfo,
uint256 assetsDeposited,
uint256 deadline,
uint8 vSig,
bytes32 rSig,
bytes32 sSig
) private returns (address asset) {
AppStorage storage s = LibAppStorage.diamondStorage();
address sender = LibMeta.msgSender();
IVault vault = IVault(hubInfo.vault);
address asset = hubInfo.asset;
asset = hubInfo.asset;

if (
meTokenInfo.migration != address(0) &&
block.timestamp > meTokenInfo.startTime
block.timestamp > meTokenInfo.startTime &&
IMigration(meTokenInfo.migration).isStarted(meToken)
) {
// Use meToken address to get the asset address from the migration vault
vault = IVault(meTokenInfo.migration);
asset = s.hubs[meTokenInfo.targetHubId].asset;
}
vault.handleWithdrawal(recipient, asset, assetsReturned, fee);
emit Burn(
meToken,
asset,
vault.handleDepositWithPermit(
sender,
recipient,
meTokensBurned,
assetsReturned
); */
asset,
assetsDeposited,
(assetsDeposited * s.mintFee) / s.PRECISION,
deadline,
vSig,
rSig,
sSig
);
LibMeToken.updateBalancePooled(true, meToken, assetsDepositedAfterFees);
if (hubInfo.updating && block.timestamp > hubInfo.endTime) {
LibHub.finishUpdate(meTokenInfo.hubId);
} else if (meTokenInfo.targetHubId != 0) {
if (block.timestamp > meTokenInfo.endTime) {
LibMeToken.finishResubscribe(meToken);
} else if (block.timestamp > meTokenInfo.startTime) {
// Handle migration actions if needed
IMigration(meTokenInfo.migration).poke(meToken);
}
}
}

function _vaultWithdrawal(
Expand Down
5 changes: 5 additions & 0 deletions contracts/migrations/SameAssetTransferMigration.sol
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ contract SameAssetTransferMigration is ReentrancyGuard, Vault, IMigration {
delete _sameAssetMigration[meToken];
}

/// @inheritdoc IMigration
function isStarted(address meToken) external view override returns (bool) {
return _sameAssetMigration[meToken].started;
}

function getDetails(address meToken)
external
view
Expand Down
16 changes: 9 additions & 7 deletions contracts/migrations/UniswapSingleTransferMigration.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {IHubFacet} from "../interfaces/IHubFacet.sol";
import {IMeTokenRegistryFacet} from "../interfaces/IMeTokenRegistryFacet.sol";
import {IMigration} from "../interfaces/IMigration.sol";
import {ISingleAssetVault} from "../interfaces/ISingleAssetVault.sol";
import {ISwapRouter} from "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
import {IV3SwapRouter} from "@uniswap/swap-router-contracts/contracts/interfaces/IV3SwapRouter.sol";
import {HubInfo} from "../libs/LibHub.sol";
import {MeTokenInfo} from "../libs/LibMeToken.sol";
import {Vault} from "../vaults/Vault.sol";
Expand All @@ -33,8 +33,8 @@ contract UniswapSingleTransferMigration is ReentrancyGuard, Vault, IMigration {

// NOTE: this can be found at
// github.com/Uniswap/uniswap-v3-periphery/blob/main/contracts/interfaces/ISwapRouter.sol
ISwapRouter private immutable _router =
ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564);
IV3SwapRouter private immutable _router =
IV3SwapRouter(0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45);

// args for uniswap router
uint24 public constant MINFEE = 500; // 0.05%
Expand All @@ -56,7 +56,6 @@ contract UniswapSingleTransferMigration is ReentrancyGuard, Vault, IMigration {
{
MeTokenInfo memory meTokenInfo = IMeTokenRegistryFacet(diamond)
.getMeTokenInfo(meToken);

require(
IHubFacet(diamond).getHubInfo(meTokenInfo.hubId).asset !=
IHubFacet(diamond).getHubInfo(meTokenInfo.targetHubId).asset,
Expand Down Expand Up @@ -100,7 +99,6 @@ contract UniswapSingleTransferMigration is ReentrancyGuard, Vault, IMigration {
HubInfo memory targetHubInfo = IHubFacet(diamond).getHubInfo(
meTokenInfo.targetHubId
);

uint256 amountOut;
if (!_uniswapSingleTransfers[meToken].started) {
ISingleAssetVault(
Expand All @@ -122,6 +120,11 @@ contract UniswapSingleTransferMigration is ReentrancyGuard, Vault, IMigration {
delete _uniswapSingleTransfers[meToken];
}

/// @inheritdoc IMigration
function isStarted(address meToken) external view override returns (bool) {
return _uniswapSingleTransfers[meToken].started;
}

function getDetails(address meToken)
external
view
Expand Down Expand Up @@ -191,13 +194,12 @@ contract UniswapSingleTransferMigration is ReentrancyGuard, Vault, IMigration {
IERC20(hubInfo.asset).safeApprove(address(_router), amountIn);

// https://docs.uniswap.org/protocol/guides/swaps/single-swaps
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter
IV3SwapRouter.ExactInputSingleParams memory params = IV3SwapRouter
.ExactInputSingleParams({
tokenIn: hubInfo.asset,
tokenOut: targetHubInfo.asset,
fee: usts.fee,
recipient: address(this),
deadline: block.timestamp,
amountIn: amountIn,
amountOutMinimum: 0,
sqrtPriceLimitX96: 0
Expand Down
7 changes: 5 additions & 2 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,12 @@ const config: HardhatUserConfig = {
},
mocha: {
delay: true,
timeout: 60000, // Here is 2min but can be whatever timeout is suitable for you.
timeout: 120000, // Here is 2min but can be whatever timeout is suitable for you.
},
namedAccounts: {
SwapRouter: "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45",
Quoter: "0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6",
UNIV3Factory: "0x1F98431c8aD98523631AE4a59f267346ea31F984",
DAI: {
default: "0x6B175474E89094C44Da98b954EedeAC495271d0F", // here this will by default take the first account as deployer
1: "0x6B175474E89094C44Da98b954EedeAC495271d0F", // similarly on mainnet it will take the first account as deployer. Note though that depending on how hardhat network are configured, the account 0 on one network can be different than on another
Expand All @@ -108,7 +111,7 @@ const config: HardhatUserConfig = {
forking: {
url: `https://eth-mainnet.alchemyapi.io/v2/${ALCHEMY_API_KEY}`,
accounts,
blockNumber: 13310410,
blockNumber: 14448329,
},
gas: "auto",
timeout: 1800000,
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"@openzeppelin/contracts": "^4.5.0",
"@uniswap/sdk-core": "^3.0.1",
"@uniswap/v3-core": "^1.0.0",
"@uniswap/smart-order-router": "^2.5.22",
"@uniswap/v3-periphery": "^1.4.1",
"@uniswap/v3-sdk": "^3.8.1",
"yarn": "^1.22.18"
Expand Down
Loading

0 comments on commit 5ad5333

Please sign in to comment.