Add method to migrate from SCD to MCD (#311)

This commit is contained in:
Gerardo Nardelli 2019-11-05 03:07:19 -03:00 committed by Alexander Kolotov
parent 7bf4e0629a
commit cc7718284d
5 changed files with 137 additions and 1 deletions

View File

@ -0,0 +1,10 @@
pragma solidity 0.4.24;
interface IScdMcdMigration {
function swapSaiToDai(uint256 wad) external;
function daiJoin() external returns (address);
}
interface IDaiAdapter {
function dai() public returns (address);
}

View File

@ -0,0 +1,9 @@
pragma solidity 0.4.24;
contract DaiAdapterMock {
address public dai;
constructor(address _dai) public {
dai = _dai;
}
}

View File

@ -0,0 +1,24 @@
pragma solidity 0.4.24;
import "../interfaces/IScdMcdMigration.sol";
import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import "openzeppelin-solidity/contracts/token/ERC20/MintableToken.sol";
contract ScdMcdMigrationMock is IScdMcdMigration {
address public sai;
IDaiAdapter public daiJoin;
constructor(address _sai, address _daiJoin) public {
sai = _sai;
daiJoin = IDaiAdapter(_daiJoin);
}
function swapSaiToDai(uint256 wad) external {
ERC20(sai).transferFrom(msg.sender, address(this), wad);
MintableToken(daiJoin.dai()).mint(msg.sender, wad);
}
function daiJoin() external returns (address) {
return daiJoin;
}
}

View File

@ -3,8 +3,11 @@ pragma solidity 0.4.24;
import "../BasicForeignBridge.sol";
import "../ERC20Bridge.sol";
import "../OtherSideBridgeStorage.sol";
import "../../interfaces/IScdMcdMigration.sol";
contract ForeignBridgeErcToNative is BasicForeignBridge, ERC20Bridge, OtherSideBridgeStorage {
event TokensSwapped(address indexed from, address indexed to, uint256 value);
function initialize(
address _validatorContract,
address _erc20token,
@ -79,4 +82,24 @@ contract ForeignBridgeErcToNative is BasicForeignBridge, ERC20Bridge, OtherSideB
require(_receiver != bridgeContractOnOtherSide());
super._relayTokens(_sender, _receiver, _amount);
}
function migrateToMCD(address _migrationContract) external onlyOwner {
bytes32 storageAddress = 0x3378953eb16363e06fd9ea9701d36ed7285d206d9de7df55b778462d74596a89; // keccak256(abi.encodePacked("migrationToMcdCompleted"))
require(!boolStorage[storageAddress]);
require(AddressUtils.isContract(_migrationContract));
uint256 curBalance = erc20token().balanceOf(address(this));
require(erc20token().approve(_migrationContract, curBalance));
//It is important to note that this action will cause appearing of `Transfer`
//event as part of the tokens minting
IScdMcdMigration(_migrationContract).swapSaiToDai(curBalance);
address saiContract = erc20token();
address mcdContract = IDaiAdapter(IScdMcdMigration(_migrationContract).daiJoin()).dai();
setErc20token(mcdContract);
require(erc20token().balanceOf(address(this)) == curBalance);
emit TokensSwapped(saiContract, erc20token(), curBalance);
boolStorage[storageAddress] = true;
}
}

View File

@ -3,10 +3,13 @@ const ForeignBridgeV2 = artifacts.require('ForeignBridgeV2.sol')
const BridgeValidators = artifacts.require('BridgeValidators.sol')
const EternalStorageProxy = artifacts.require('EternalStorageProxy.sol')
const ERC677BridgeToken = artifacts.require('ERC677BridgeToken.sol')
const ERC20Mock = artifacts.require('ERC20Mock.sol')
const ScdMcdMigrationMock = artifacts.require('ScdMcdMigrationMock.sol')
const DaiAdapterMock = artifacts.require('DaiAdapterMock.sol')
const { expect } = require('chai')
const { ERROR_MSG, ZERO_ADDRESS, toBN } = require('../setup')
const { createMessage, sign, signatureToVRS, ether, expectEventInLogs } = require('../helpers/helpers')
const { createMessage, sign, signatureToVRS, ether, expectEventInLogs, getEvents } = require('../helpers/helpers')
const halfEther = ether('0.5')
const requireBlockConfirmations = 8
@ -834,4 +837,71 @@ contract('ForeignBridge_ERC20_to_Native', async accounts => {
})
})
})
describe('migrateToMCD', () => {
let foreignBridge
let sai
let dai
let migrationContract
beforeEach(async () => {
foreignBridge = await ForeignBridge.new()
sai = await ERC20Mock.new('sai', 'SAI', 18)
dai = await ERC20Mock.new('dai', 'DAI', 18)
const daiAdapterMock = await DaiAdapterMock.new(dai.address)
migrationContract = await ScdMcdMigrationMock.new(sai.address, daiAdapterMock.address)
await foreignBridge.initialize(
validatorContract.address,
sai.address,
requireBlockConfirmations,
gasPrice,
[dailyLimit, maxPerTx, minPerTx],
[homeDailyLimit, homeMaxPerTx],
owner,
decimalShiftZero,
otherSideBridge.address
)
// Mint the bridge some sai tokens
await sai.mint(foreignBridge.address, oneEther)
// migration contract can mint dai
await dai.transferOwnership(migrationContract.address)
})
it('should be able to swap tokens', async () => {
// Given
expect(await sai.balanceOf(foreignBridge.address)).to.be.bignumber.equal(oneEther)
expect(await dai.balanceOf(foreignBridge.address)).to.be.bignumber.equal(ZERO)
expect(await foreignBridge.erc20token()).to.be.equal(sai.address)
// When
// migration address should be a contract
await foreignBridge.migrateToMCD(accounts[3], { from: owner }).should.be.rejectedWith(ERROR_MSG)
// should be called by owner
await foreignBridge
.migrateToMCD(migrationContract.address, { from: accounts[5] })
.should.be.rejectedWith(ERROR_MSG)
const { logs } = await foreignBridge.migrateToMCD(migrationContract.address, { from: owner }).should.be.fulfilled
// can't migrate token again
await foreignBridge.migrateToMCD(migrationContract.address, { from: owner }).should.be.rejectedWith(ERROR_MSG)
// Then
expect(await sai.balanceOf(foreignBridge.address)).to.be.bignumber.equal(ZERO)
expect(await dai.balanceOf(foreignBridge.address)).to.be.bignumber.equal(oneEther)
expect(await foreignBridge.erc20token()).to.be.equal(dai.address)
expectEventInLogs(logs, 'TokensSwapped', {
from: sai.address,
to: dai.address,
value: oneEther
})
const transferEvent = await getEvents(dai, { event: 'Transfer' })
expect(transferEvent.length).to.be.equal(1)
expect(transferEvent[0].returnValues.from).to.be.equal(ZERO_ADDRESS)
expect(transferEvent[0].returnValues.to).to.be.equal(foreignBridge.address)
expect(transferEvent[0].returnValues.value).to.be.equal(oneEther.toString())
})
})
})