123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- pragma solidity ^0.5.0;
- import "../token/ERC20/IERC20.sol";
- import "../token/ERC20/ERC20Mintable.sol";
- import "../token/ERC20/SafeERC20.sol";
- import "../math/Math.sol";
- /**
- * @title ERC20Migrator
- * @dev This contract can be used to migrate an ERC20 token from one
- * contract to another, where each token holder has to opt-in to the migration.
- * To opt-in, users must approve for this contract the number of tokens they
- * want to migrate. Once the allowance is set up, anyone can trigger the
- * migration to the new token contract. In this way, token holders "turn in"
- * their old balance and will be minted an equal amount in the new token.
- * The new token contract must be mintable. For the precise interface refer to
- * OpenZeppelin's {ERC20Mintable}, but the only functions that are needed are
- * {MinterRole-isMinter} and {ERC20Mintable-mint}. The migrator will check
- * that it is a minter for the token.
- * The balance from the legacy token will be transferred to the migrator, as it
- * is migrated, and remain there forever.
- * Although this contract can be used in many different scenarios, the main
- * motivation was to provide a way to migrate ERC20 tokens into an upgradeable
- * version of it using ZeppelinOS. To read more about how this can be done
- * using this implementation, please follow the official documentation site of
- * ZeppelinOS: https://docs.zeppelinos.org/docs/erc20_onboarding.html
- *
- * Example of usage:
- * ```
- * const migrator = await ERC20Migrator.new(legacyToken.address);
- * await newToken.addMinter(migrator.address);
- * await migrator.beginMigration(newToken.address);
- * ```
- */
- contract ERC20Migrator {
- using SafeERC20 for IERC20;
- /// Address of the old token contract
- IERC20 private _legacyToken;
- /// Address of the new token contract
- ERC20Mintable private _newToken;
- /**
- * @param legacyToken address of the old token contract
- */
- constructor (IERC20 legacyToken) public {
- require(address(legacyToken) != address(0), "ERC20Migrator: legacy token is the zero address");
- _legacyToken = legacyToken;
- }
- /**
- * @dev Returns the legacy token that is being migrated.
- */
- function legacyToken() public view returns (IERC20) {
- return _legacyToken;
- }
- /**
- * @dev Returns the new token to which we are migrating.
- */
- function newToken() public view returns (IERC20) {
- return _newToken;
- }
- /**
- * @dev Begins the migration by setting which is the new token that will be
- * minted. This contract must be a minter for the new token.
- * @param newToken_ the token that will be minted
- */
- function beginMigration(ERC20Mintable newToken_) public {
- require(address(_newToken) == address(0), "ERC20Migrator: migration already started");
- require(address(newToken_) != address(0), "ERC20Migrator: new token is the zero address");
- //solhint-disable-next-line max-line-length
- require(newToken_.isMinter(address(this)), "ERC20Migrator: not a minter for new token");
- _newToken = newToken_;
- }
- /**
- * @dev Transfers part of an account's balance in the old token to this
- * contract, and mints the same amount of new tokens for that account.
- * @param account whose tokens will be migrated
- * @param amount amount of tokens to be migrated
- */
- function migrate(address account, uint256 amount) public {
- require(address(_newToken) != address(0), "ERC20Migrator: migration not started");
- _legacyToken.safeTransferFrom(account, address(this), amount);
- _newToken.mint(account, amount);
- }
- /**
- * @dev Transfers all of an account's allowed balance in the old token to
- * this contract, and mints the same amount of new tokens for that account.
- * @param account whose tokens will be migrated
- */
- function migrateAll(address account) public {
- uint256 balance = _legacyToken.balanceOf(account);
- uint256 allowance = _legacyToken.allowance(account, address(this));
- uint256 amount = Math.min(balance, allowance);
- migrate(account, amount);
- }
- }
|