Skip to content

Commit

Permalink
Merge branch 'main' of github.com:Abracadabra-money/abracadabra-money…
Browse files Browse the repository at this point in the history
…-contracts
  • Loading branch information
0xCalibur committed Feb 3, 2025
2 parents a16136f + 8f3fe25 commit 2983d6c
Show file tree
Hide file tree
Showing 5 changed files with 324 additions and 21 deletions.
241 changes: 241 additions & 0 deletions deployments/42161/Arbitrum_SpellMigrator.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ via_ir = false
remappings = [
"/=src/",
"forge-std/=dependencies/forge-std-1.9.5/src/",
"halmos-cheatcodes/=dependencies/halmos-cheatcodes-3ca0e11/src/",
"halmos-cheatcodes/=dependencies/halmos-cheatcodes-7328abe/src/",
"@openzeppelin/contracts/=dependencies/openzeppelin-contracts-5.0.2/contracts/",
"@openzeppelin/contracts-upgradeable/=dependencies/openzeppelin-contracts-upgradeable-5.0.2/contracts/",
"@BoringSolidity/=dependencies/BoringSolidity-1.0.0/contracts/",
Expand Down Expand Up @@ -79,5 +79,5 @@ recursive_deps = false
"safe-contracts" = { version = "1.3.0", git = "https://github.com/safe-global/safe-smart-account.git", rev = "186a21a74b327f17fc41217a927dea7064f74604" }
"fuzzlib" = { version = "0.0.1", git = "https://github.com/perimetersec/fuzzlib.git", rev = "c63837c6b716c0813f1a22ca287f0f24f6479e77" }
"abracadabra-oft-v1" = { version = "0.0.1", git = "https://github.com/Abracadabra-money/abracadabra-oft-v1.git", rev = "a20f79661ea083d13e0df6000de6045ff167e142" }
halmos-cheatcodes = { version = "3ca0e11", git = "https://github.com/a16z/halmos-cheatcodes.git", rev = "3ca0e11cf6ea5b3f73997a44932ab9c048c5ed57" }
halmos-cheatcodes = { version = "7328abe", git = "https://github.com/a16z/halmos-cheatcodes.git", rev = "7328abe100445fc53885c21d0e713b95293cf14c" }
# See more config options https://book.getfoundry.sh/reference/config/
16 changes: 16 additions & 0 deletions script/SpellMigrator.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.0;

import "utils/BaseScript.sol";

contract SpellMigratorScript is BaseScript {
function deploy() public {
vm.startBroadcast();
deploy(
"SpellMigrator",
"TokenMigrator.sol:TokenMigrator",
abi.encode(toolkit.getAddress("spell"), toolkit.getAddress("spellV2"), tx.origin)
);
vm.stopBroadcast();
}
}
3 changes: 3 additions & 0 deletions src/periphery/TokenMigrator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ contract TokenMigrator is Owned {
using SafeTransferLib for address;

event LogMigrated(uint256 amount);
event LogRecovered(address indexed token, address indexed to, uint256 amount);

address public immutable tokenIn;
address public immutable tokenOut;
Expand All @@ -20,9 +21,11 @@ contract TokenMigrator is Owned {
function migrate(uint256 amount) external {
tokenIn.safeTransferFrom(msg.sender, address(this), amount);
tokenOut.safeTransfer(msg.sender, amount);
emit LogMigrated(amount);
}

function recover(address token, uint256 amount, address to) external onlyOwner {
token.safeTransfer(to, amount);
emit LogRecovered(token, to, amount);
}
}
81 changes: 62 additions & 19 deletions test/TokenMigrator.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {SafeTransferLib} from "@solady/utils/SafeTransferLib.sol";
import "utils/BaseTest.sol";
import {TokenMigrator} from "/periphery/TokenMigrator.sol";
import {ERC20Mock} from "./mocks/ERC20Mock.sol";
import {SymTest} from "halmos-cheatcodes/SymTest.sol";

contract TokenMigratorTest is BaseTest {
using SafeTransferLib for address;
Expand Down Expand Up @@ -53,38 +54,80 @@ contract TokenMigratorTest is BaseTest {
}
}

contract TokenMigratorSymTest is Test {
contract TokenMigratorSymTest is SymTest, Test {
using SafeTransferLib for address;

TokenMigrator migrator;
address tokenIn;
address tokenOut;
address tokenOther;
address owner;

function setUp() public {
tokenIn = address(new ERC20Mock("TokenIn", "TIN"));
tokenOut = address(new ERC20Mock("TokenOut", "TOUT"));
tokenOther = address(new ERC20Mock("TokenOther", "TOTHER"));

migrator = new TokenMigrator(tokenIn, tokenOut, address(this));
svm.enableSymbolicStorage(address(tokenIn));
svm.enableSymbolicStorage(address(tokenOut));
svm.enableSymbolicStorage(address(tokenOther));

owner = svm.createAddress("Owner");

migrator = new TokenMigrator(tokenIn, tokenOut, owner);
}

function proveMigrationBalance(
address alice,
uint256 aliceTokenInBalance,
uint256 aliceTokenInMigratorAllowance,
uint256 tokenMigratorOutBalance,
uint256 amountToMigrate
) public {
vm.assume(alice != address(migrator) && alice != tokenIn && alice != tokenOut);
function proveMigrationBalance(address alice, uint256 amountToMigrate) public {
uint256 aliceTokenInBalance = tokenIn.balanceOf(alice);
uint256 aliceTokenOutBalance = tokenOut.balanceOf(alice);
uint256 tokenMigratorInBalance = tokenIn.balanceOf(address(migrator));
uint256 tokenMigratorOutBalance = tokenOut.balanceOf(address(migrator));

ERC20Mock(tokenIn).mint(alice, aliceTokenInBalance);
ERC20Mock(tokenOut).mint(address(migrator), tokenMigratorOutBalance);
vm.assume(alice != address(migrator));

vm.startPrank(alice);
ERC20Mock(tokenIn).approve(address(migrator), aliceTokenInMigratorAllowance);
vm.prank(alice);
migrator.migrate(amountToMigrate);
vm.stopPrank();

assertEq(ERC20Mock(tokenIn).balanceOf(alice), aliceTokenInBalance - amountToMigrate);
assertEq(ERC20Mock(tokenOut).balanceOf(alice), amountToMigrate);
assertEq(ERC20Mock(tokenIn).balanceOf(address(migrator)), amountToMigrate);
assertEq(ERC20Mock(tokenOut).balanceOf(address(migrator)), tokenMigratorOutBalance - amountToMigrate);
assertEq(tokenIn.balanceOf(alice), aliceTokenInBalance - amountToMigrate);
assertEq(tokenOut.balanceOf(alice), aliceTokenOutBalance + amountToMigrate);
assertEq(tokenIn.balanceOf(address(migrator)), tokenMigratorInBalance + amountToMigrate);
assertEq(tokenOut.balanceOf(address(migrator)), tokenMigratorOutBalance - amountToMigrate);
}

function proveMigrateEnoughBalanceNeverRevert(address alice, uint256 amountToMigrate) public {
vm.assume(alice != address(migrator) && alice != address(0));
vm.assume(tokenIn.balanceOf(alice) >= amountToMigrate);
vm.assume(ERC20Mock(tokenIn).allowance(alice, address(migrator)) >= amountToMigrate);
vm.assume(tokenOut.balanceOf(address(migrator)) >= amountToMigrate);

vm.prank(alice);
(bool success, ) = address(migrator).call(abi.encodeWithSelector(migrator.migrate.selector, amountToMigrate));
assertTrue(success);
}

function proveOnlyOwnerRecover(address alice, address token, uint256 amount, address to) public {
vm.prank(alice);
migrator.recover(token, amount, to);
assertEq(alice, owner);
}

function proveOwnerRecoverAnything(address token, uint256 amount, address to) public {
vm.assume(to != address(migrator));

uint256 tokenBalance = token.balanceOf(to);

vm.prank(owner);
migrator.recover(token, amount, to);
assertEq(token.balanceOf(to), tokenBalance + amount);
}

function proveRecoverEnoughBalanceNeverRevert(address token, uint256 amount, address to) public {
vm.assume(to != address(0));
vm.assume(amount > 0);
vm.assume(token.balanceOf(address(migrator)) >= amount);

vm.prank(owner);
(bool success, ) = address(migrator).call(abi.encodeWithSelector(migrator.recover.selector, token, amount, to));
assertTrue(success);
}
}

0 comments on commit 2983d6c

Please sign in to comment.