Skip to content

Commit

Permalink
Add escrow migration spell (#418)
Browse files Browse the repository at this point in the history
* Add escrow migration spell

* Archive deployed spell

* Add escrow migration spell (#83)

* Add escrow migration spell

* Archive deployed spell
  • Loading branch information
hieronx authored Jan 13, 2025
1 parent 8725085 commit e556c1a
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.26;

import {IERC20} from "forge-std/interfaces/IERC20.sol";

interface RootLike {
function relyContract(address, address) external;
function executeScheduledRely(address) external;
function delay() external view returns (uint64);
}

interface AuthLike {
function rely(address) external;
function deny(address) external;
}

interface OldEscrowLike {
function approve(address token, address spender, uint256 value) external;
}

// Spell to migrate the escrow balances
contract Spell {
bool public done;
string public constant description = "Liquidity Pool escrow migration spell";

address public constant LP_MULTISIG = 0xD9D30ab47c0f096b0AA67e9B8B1624504a63e7FD;
address public constant OLD_DELAYED_ADMIN = 0x2559998026796Ca6fd057f3aa66F2d6ecdEd9028;
address public constant OLD_ROOT = 0x498016d30Cd5f0db50d7ACE329C07313a0420502;
address public constant OLD_ESCROW = 0xd595E1483c507E74E2E6A3dE8e7D08d8f6F74936;
address public constant NEW_ESCROW = 0x0000000005F458Fd6ba9EEb5f365D83b7dA913dD;
address public constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;

function cast() public {
require(!done, "spell-already-cast");
done = true;
execute();
}

function execute() internal {
RootLike root = RootLike(OLD_ROOT);
root.relyContract(OLD_ESCROW, address(this));

migrateBalance(USDC);

AuthLike(OLD_ROOT).deny(address(this));
AuthLike(OLD_ESCROW).deny(address(this));
}

function migrateBalance(address token) internal {
OldEscrowLike escrow = OldEscrowLike(OLD_ESCROW);
escrow.approve(token, address(this), type(uint256).max);
IERC20(token).transferFrom(OLD_ESCROW, NEW_ESCROW, IERC20(token).balanceOf(OLD_ESCROW));
escrow.approve(token, address(this), 0);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.26;

import {ICentrifugeRouter} from "src/interfaces/ICentrifugeRouter.sol";
import "forge-std/Test.sol";
import "src/002.sol";

interface DelayedAdminLike {
function scheduleRely(address spell) external;
}

contract SpellTest is Test {
Spell spell;

// Details related to pending redemption that is failing
address investor1 = 0x32f5eF78AA9C7b8882D748331AdcFe0dfA4f1a14;
address investor2 = 0xbe19e6AdF267248beE015dd3fbBa363E12ca8cE6;
address vault = 0xa7607A638df0117E6718b93f8cFf53503A815D2f;
ICentrifugeRouter router = ICentrifugeRouter(0x2F445BA946044C5F508a63eEaF7EAb673c69a1F4);

IERC20 usdc;

function setUp() public {
spell = new Spell();
usdc = IERC20(spell.USDC());
}

function testCastSuccessful() public {
assertEq(usdc.balanceOf(spell.OLD_ESCROW()), 143360978110);
assertEq(usdc.balanceOf(spell.NEW_ESCROW()), 0);

vm.expectRevert(bytes("SafeTransferLib/safe-transfer-from-failed"));
vm.prank(investor1);
router.claimRedeem(vault, investor1, investor1);

vm.expectRevert(bytes("SafeTransferLib/safe-transfer-from-failed"));
vm.prank(investor2);
router.claimRedeem(vault, investor2, investor2);

castSpell();

assertEq(usdc.balanceOf(spell.OLD_ESCROW()), 0);
assertEq(usdc.balanceOf(spell.NEW_ESCROW()), 143360978110);

vm.prank(investor1);
router.claimRedeem(vault, investor1, investor1);

vm.prank(investor2);
router.claimRedeem(vault, investor2, investor2);
}

function castSpell() internal {
// Admin submits a tx to delayedAdmin in order to rely spell -> to be done manually before spell cast
DelayedAdminLike delayedAdmin = DelayedAdminLike(spell.OLD_DELAYED_ADMIN());
vm.prank(spell.LP_MULTISIG());
delayedAdmin.scheduleRely(address(spell));

// Warp to the time when the spell can be cast -> current block + delay
vm.warp(block.timestamp + RootLike(spell.OLD_ROOT()).delay());
RootLike(spell.OLD_ROOT()).executeScheduledRely(address(spell)); // --> to be called after delay has passed
spell.cast();
}
}

0 comments on commit e556c1a

Please sign in to comment.