文件 1 的 5:ERC20Helper.sol
pragma solidity ^0.8.7;
import { IERC20Like } from "./interfaces/IERC20Like.sol";
library ERC20Helper {
function transfer(address token_, address to_, uint256 amount_) internal returns (bool success_) {
return _call(token_, abi.encodeWithSelector(IERC20Like.transfer.selector, to_, amount_));
}
function transferFrom(address token_, address from_, address to_, uint256 amount_) internal returns (bool success_) {
return _call(token_, abi.encodeWithSelector(IERC20Like.transferFrom.selector, from_, to_, amount_));
}
function approve(address token_, address spender_, uint256 amount_) internal returns (bool success_) {
if (!_call(token_, abi.encodeWithSelector(IERC20Like.approve.selector, spender_, uint256(0)))) return false;
if (amount_ == uint256(0)) return true;
return _call(token_, abi.encodeWithSelector(IERC20Like.approve.selector, spender_, amount_));
}
function _call(address token_, bytes memory data_) private returns (bool success_) {
if (token_.code.length == uint256(0)) return false;
bytes memory returnData;
( success_, returnData ) = token_.call(data_);
return success_ && (returnData.length == uint256(0) || abi.decode(returnData, (bool)));
}
}
文件 2 的 5:IERC20Like.sol
pragma solidity ^0.8.7;
interface IERC20Like {
function approve(address spender_, uint256 amount_) external returns (bool success_);
function transfer(address recipient_, uint256 amount_) external returns (bool success_);
function transferFrom(address owner_, address recipient_, uint256 amount_) external returns (bool success_);
}
文件 3 的 5:IMigrator.sol
pragma solidity ^0.8.7;
interface IMigrator {
function active() external view returns (bool active_);
function globals() external view returns (address globals_);
function newToken() external view returns (address newToken_);
function oldToken() external view returns (address oldToken_);
function migrate(uint256 oldTokenAmount_) external returns (uint256 newTokenAmount_);
function migrate(address recipient_, uint256 oldTokenAmount_) external returns (uint256 newTokenAmount_);
function setActive(bool active_) external;
function tokenSplitScalar() external view returns (uint256 tokenSplitScalar_);
}
文件 4 的 5:Interfaces.sol
pragma solidity 0.8.7;
interface IERC20Like {
function decimals() external view returns (uint8 decimals_);
}
interface IGlobalsLike {
function governor() external view returns (address governor_);
function operationalAdmin() external view returns (address operationalAdmin_);
}
文件 5 的 5:Migrator.sol
pragma solidity 0.8.7;
import { ERC20Helper } from "../modules/erc20-helper/src/ERC20Helper.sol";
import { IERC20Like, IGlobalsLike } from "./interfaces/Interfaces.sol";
import { IMigrator } from "./interfaces/IMigrator.sol";
contract Migrator is IMigrator {
address public immutable override globals;
address public immutable override newToken;
address public immutable override oldToken;
uint256 public immutable override tokenSplitScalar;
bool public override active;
constructor(address globals_, address oldToken_, address newToken_, uint256 scalar_) {
require(scalar_ > 0, "M:C:ZERO_SCALAR");
require(IERC20Like(newToken_).decimals() == IERC20Like(oldToken_).decimals(), "M:C:DECIMAL_MISMATCH");
globals = globals_;
oldToken = oldToken_;
newToken = newToken_;
tokenSplitScalar = scalar_;
}
function migrate(uint256 oldTokenAmount_) external override returns (uint256 newTokenAmount_) {
newTokenAmount_ = migrate(msg.sender, oldTokenAmount_);
}
function migrate(address recipient_, uint256 oldTokenAmount_) public override returns (uint256 newTokenAmount_) {
require(active, "M:M:INACTIVE");
require(oldTokenAmount_ != uint256(0), "M:M:ZERO_AMOUNT");
newTokenAmount_ = oldTokenAmount_ * tokenSplitScalar;
require(ERC20Helper.transferFrom(oldToken, msg.sender, address(this), oldTokenAmount_), "M:M:TRANSFER_FROM_FAILED");
require(ERC20Helper.transfer(newToken, recipient_, newTokenAmount_), "M:M:TRANSFER_FAILED");
}
function setActive(bool active_) external override {
require(
msg.sender == IGlobalsLike(globals).governor() ||
msg.sender == IGlobalsLike(globals).operationalAdmin(),
"M:SA:NOT_PROTOCOL_ADMIN"
);
active = active_;
}
}
{
"compilationTarget": {
"modules/migrator/contracts/Migrator.sol": "Migrator"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":address-registry/=modules/address-registry/contracts/",
":contract-test-utils/=modules/globals/modules/contract-test-utils/contracts/",
":ds-test/=modules/forge-std/lib/ds-test/src/",
":erc20-helper/=modules/migrator/modules/erc20-helper/src/",
":erc20/=modules/erc20/",
":forge-std/=modules/forge-std/src/",
":globals/=modules/globals/",
":migrator/=modules/migrator/",
":mpl-migration/=modules/xmpl/modules/mpl-migration/modules/erc20-helper/src/",
":non-transparent-proxy/=modules/globals/modules/non-transparent-proxy/",
":ntp/=modules/ntp/",
":revenue-distribution-token/=modules/xmpl/modules/revenue-distribution-token/contracts/",
":xmpl/=modules/xmpl/"
]
}
[{"inputs":[{"internalType":"address","name":"globals_","type":"address"},{"internalType":"address","name":"oldToken_","type":"address"},{"internalType":"address","name":"newToken_","type":"address"},{"internalType":"uint256","name":"scalar_","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"active","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"globals","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"oldTokenAmount_","type":"uint256"}],"name":"migrate","outputs":[{"internalType":"uint256","name":"newTokenAmount_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient_","type":"address"},{"internalType":"uint256","name":"oldTokenAmount_","type":"uint256"}],"name":"migrate","outputs":[{"internalType":"uint256","name":"newTokenAmount_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"newToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oldToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"active_","type":"bool"}],"name":"setActive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tokenSplitScalar","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]