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

Feat/same asset migration #99

Merged
merged 11 commits into from
Jan 21, 2022
103 changes: 103 additions & 0 deletions contracts/migrations/SameAssetTransferMigration.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "../libs/Details.sol";
import "../vaults/Vault.sol";
import "../interfaces/IMigration.sol";
import "../interfaces/ISingleAssetVault.sol";

/// @title Same asset vault migrator
/// @author Carl Farterson (@carlfarterson)
/// @notice create a vault to hold an asset if a meToken is resubscribing
/// to a different hub with the same asset
contract SameAssetTransferMigration is ReentrancyGuard, Vault, IMigration {
struct SameAssetMigration {
// if migration is active
bool isMigrating;
// if startMigration() has been triggered
bool started;
}

mapping(address => SameAssetMigration) private _sameAssetMigration;

constructor(
address _dao,
address _foundry,
IHub _hub,
IMeTokenRegistry _meTokenRegistry,
IMigrationRegistry _migrationRegistry
) Vault(_dao, _foundry, _hub, _meTokenRegistry, _migrationRegistry) {}

function initMigration(
address _meToken,
bytes memory /* _encodedArgs */
) external override {
require(msg.sender == address(meTokenRegistry), "!meTokenRegistry");

Details.MeToken memory meToken_ = meTokenRegistry.getDetails(_meToken);
Details.Hub memory hub_ = hub.getDetails(meToken_.hubId);
Details.Hub memory targetHub_ = hub.getDetails(meToken_.targetHubId);

require(hub_.asset == targetHub_.asset, "asset different");

_sameAssetMigration[_meToken].isMigrating = true;
}

function poke(address _meToken) external override nonReentrant {
SameAssetMigration storage usts_ = _sameAssetMigration[_meToken];
Details.MeToken memory meToken_ = meTokenRegistry.getDetails(_meToken);
Details.Hub memory hub_ = hub.getDetails(meToken_.hubId);
if (usts_.isMigrating && !usts_.started) {
ISingleAssetVault(hub_.vault).startMigration(_meToken);
usts_.started = true;
}
}

function finishMigration(address _meToken)
external
override
nonReentrant
returns (uint256 amountOut)
{
require(msg.sender == address(meTokenRegistry), "!meTokenRegistry");
SameAssetMigration storage usts_ = _sameAssetMigration[_meToken];
require(usts_.isMigrating, "!migrating");
pegahcarter marked this conversation as resolved.
Show resolved Hide resolved

Details.MeToken memory meToken_ = meTokenRegistry.getDetails(_meToken);
Details.Hub memory hub_ = hub.getDetails(meToken_.hubId);
Details.Hub memory targetHub_ = hub.getDetails(meToken_.targetHubId);

if (!usts_.started) {
ISingleAssetVault(hub_.vault).startMigration(_meToken);
usts_.started = true;
}
amountOut = meToken_.balancePooled + meToken_.balanceLocked;

// Send asset to new vault only if there's a migration vault
IERC20(targetHub_.asset).transfer(targetHub_.vault, amountOut);

// reset mappings
delete _sameAssetMigration[_meToken];
}

function getDetails(address _meToken)
external
view
returns (SameAssetMigration memory usts_)
{
usts_ = _sameAssetMigration[_meToken];
}

// Kicks off meToken warmup period
function isValid(
address _meToken,
bytes memory /* _encodedArgs */
) public view override returns (bool) {
Details.MeToken memory meToken_ = meTokenRegistry.getDetails(_meToken);
// MeToken not subscribed to a hub
if (meToken_.hubId == 0) return false;
return true;
}
}
10 changes: 1 addition & 9 deletions contracts/migrations/UniswapSingleTransferMigration.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ pragma solidity ^0.8.0;

import {ISwapRouter} from "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "../libs/Details.sol";
import "../vaults/Vault.sol";
Expand All @@ -17,13 +15,7 @@ import "../interfaces/ISingleAssetVault.sol";
/// when recollateralizing to a vault with a different base token
/// @dev This contract moves the pooled/locked balances from
/// one erc20 to another
contract UniswapSingleTransferMigration is
Initializable,
pegahcarter marked this conversation as resolved.
Show resolved Hide resolved
Ownable,
ReentrancyGuard,
Vault,
IMigration
{
contract UniswapSingleTransferMigration is ReentrancyGuard, Vault, IMigration {
struct UniswapSingleTransfer {
// The earliest time that the swap can occur
uint256 soonest;
Expand Down
16 changes: 7 additions & 9 deletions contracts/registries/MeTokenRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,13 @@ contract MeTokenRegistry is Ownable, IMeTokenRegistry {
require(!hub_.updating, "hub updating");
require(!targetHub_.updating, "targetHub updating");

// TODO: what if asset is same? Is a migration vault needed since it'll start/end
// at the same and not change to a different asset?
require(hub_.asset != targetHub_.asset, "asset same");
require(_migration != address(0), "migration address(0)");

require(
IVault(_migration).isValid(_meToken, _encodedMigrationArgs),
"Invalid _encodedMigrationArgs"
);

// Ensure the migration we're using is approved
require(
migrationRegistry.isApproved(
Expand All @@ -147,12 +149,6 @@ contract MeTokenRegistry is Ownable, IMeTokenRegistry {
"!approved"
);

require(
IVault(_migration).isValid(_meToken, _encodedMigrationArgs),
"Invalid _encodedMigrationArgs"
);
IMigration(_migration).initMigration(_meToken, _encodedMigrationArgs);

meToken_.startTime = block.timestamp + _warmup;
meToken_.endTime = block.timestamp + _warmup + _duration;
meToken_.endCooldown =
Expand All @@ -163,6 +159,8 @@ contract MeTokenRegistry is Ownable, IMeTokenRegistry {
meToken_.targetHubId = _targetHubId;
meToken_.migration = _migration;

IMigration(_migration).initMigration(_meToken, _encodedMigrationArgs);

emit InitResubscribe(
_meToken,
_targetHubId,
Expand Down
11 changes: 4 additions & 7 deletions contracts/vaults/SingleAssetVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,10 @@ contract SingleAssetVault is Vault, ISingleAssetVault {
emit StartMigration(_meToken);
}

// solhint-disable-next-line
function isValid(address _asset, bytes memory _encodedArgs)
public
pure
override
returns (bool)
{
function isValid(
address _asset,
bytes memory /* _encodedArgs */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice 🙌

) public pure override returns (bool) {
if (_asset == address(0)) {
return false;
}
Expand Down
Loading