Allow multiple bridges for token (#387)

This commit is contained in:
varasev 2020-03-23 15:39:27 +03:00 committed by GitHub
parent 6d19d2ee8a
commit 92f850de23
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 65 additions and 39 deletions

View File

@ -8,7 +8,8 @@ import "./interfaces/IBurnableMintableERC677Token.sol";
import "./upgradeable_contracts/Claimable.sol";
contract ERC677BridgeToken is IBurnableMintableERC677Token, DetailedERC20, BurnableToken, MintableToken, Claimable {
address public bridgeContract;
address[] internal _bridgeContracts;
mapping(address => bool) internal _isBridgeContract;
event ContractFallbackCallFailed(address from, address to, uint256 value);
@ -16,9 +17,20 @@ contract ERC677BridgeToken is IBurnableMintableERC677Token, DetailedERC20, Burna
// solhint-disable-previous-line no-empty-blocks
}
function setBridgeContract(address _bridgeContract) external onlyOwner {
require(AddressUtils.isContract(_bridgeContract));
bridgeContract = _bridgeContract;
function setBridgeContracts(address[] _contracts) external onlyOwner {
require(_contracts.length > 0);
uint256 i;
for (i = 0; i < _bridgeContracts.length; i++) {
_isBridgeContract[_bridgeContracts[i]] = false;
}
_bridgeContracts = _contracts;
for (i = 0; i < _contracts.length; i++) {
require(AddressUtils.isContract(_contracts[i]));
_isBridgeContract[_contracts[i]] = true;
}
}
modifier validRecipient(address _recipient) {
@ -27,6 +39,10 @@ contract ERC677BridgeToken is IBurnableMintableERC677Token, DetailedERC20, Burna
_;
}
function bridgeContracts() external view returns (address[]) {
return _bridgeContracts;
}
function transferAndCall(address _to, uint256 _value, bytes _data) external validRecipient(_to) returns (bool) {
require(superTransfer(_to, _value));
emit Transfer(msg.sender, _to, _value, _data);
@ -59,7 +75,7 @@ contract ERC677BridgeToken is IBurnableMintableERC677Token, DetailedERC20, Burna
function callAfterTransfer(address _from, address _to, uint256 _value) internal {
if (AddressUtils.isContract(_to) && !contractFallback(_from, _to, _value, new bytes(0))) {
require(_to != bridgeContract);
require(!_isBridgeContract[_to]);
emit ContractFallbackCallFailed(_from, _to, _value);
}
}

View File

@ -245,7 +245,7 @@ async function transferOwnership({ contract, newOwner, nonce, url }) {
}
async function setBridgeContract({ contract, bridgeAddress, nonce, url }) {
const data = await contract.methods.setBridgeContract(bridgeAddress).encodeABI()
const data = await contract.methods.setBridgeContracts([bridgeAddress]).encodeABI()
const sendTx = getSendTxMethod(url)
const result = await sendTx({
data,
@ -257,7 +257,7 @@ async function setBridgeContract({ contract, bridgeAddress, nonce, url }) {
if (result.status) {
assert.strictEqual(Web3Utils.hexToNumber(result.status), 1, 'Transaction Failed')
} else {
await assertStateWithRetry(contract.methods.bridgeContract().call, bridgeAddress)
await assertStateWithRetry(contract.methods.bridgeContracts().call, [bridgeAddress])
}
}
@ -301,7 +301,9 @@ async function initializeValidators({
async function assertStateWithRetry(fn, expected) {
return promiseRetry(async retry => {
const value = await fn()
if (value !== expected && value.toString() !== expected) {
if (Array.isArray(expected) && !value.equalsIgnoreCase(expected)) {
retry(`Transaction Failed. Expected: ${expected.toString()} Actual: ${value.toString()}`)
} else if (value !== expected && value.toString() !== expected) {
retry(`Transaction Failed. Expected: ${expected} Actual: ${value}`)
}
})
@ -316,6 +318,14 @@ async function isContract(web3, address) {
return code !== '0x' && code !== '0x0'
}
Array.prototype.equalsIgnoreCase = function(array) {
return this.length == array.length && this.every((this_v, i) => { return this_v.equalsIgnoreCase(array[i]) });
}
String.prototype.equalsIgnoreCase = function(compareString) {
return this.toLowerCase() === compareString.toLowerCase();
};
module.exports = {
deployContract,
sendRawTxHome,

View File

@ -37,10 +37,10 @@ async function preDeploy() {
if (ERC20_EXTENDED_BY_ERC677) {
const tokenContract = new web3Foreign.eth.Contract(abi, ERC20_TOKEN_ADDRESS)
try {
await tokenContract.methods.bridgeContract().call()
await tokenContract.methods.bridgeContracts().call()
} catch (e) {
throw new Error(
`ERC20_EXTENDED_BY_ERC677 is set to TRUE but bridgeContract method was not found on ERC677 token.`
`ERC20_EXTENDED_BY_ERC677 is set to TRUE but bridgeContracts method was not found on ERC677 token.`
)
}
}

View File

@ -13,7 +13,7 @@ EternalStorageProxy|deployment|378510|378510|378510
HomeBridgeErcToErc|deployment|3528509|3528509|3528509
EternalStorageProxy|upgradeTo|35871|30924|30913
ERC677BridgeToken|deployment|1498202|1499226|1498829
ERC677BridgeToken|setBridgeContract|29432|44432|39432
ERC677BridgeToken|setBridgeContracts|47552|86474|77323
ERC677BridgeToken|transferOwnership|30860|30924|30913
HomeBridgeErcToErc|initialize|212299|213195|213003
EternalStorageProxy|transferProxyOwnership|30653|30653|30653

View File

@ -31,7 +31,7 @@ ForeignBridgeNativeToErc|deployment|3931739|3931739|3931739
EternalStorageProxy|upgradeTo|35871|30924|30913
FeeManagerNativeToErc|deployment|1079956|1079956|1079956
ForeignBridgeNativeToErc|rewardableInitialize|329022|329086|329077
ERC677BridgeToken|setBridgeContract|29432|44432|39432
ERC677BridgeToken|setBridgeContracts|47552|86474|77323
ERC677BridgeToken|transferOwnership|30860|30924|30913
EternalStorageProxy|transferProxyOwnership|30653|30653|30653
Total| |9573114|9799953|9689237
@ -92,7 +92,7 @@ EternalStorageProxy|deployment|378510|378510|378510
ForeignBridgeNativeToErc|deployment|3931739|3931739|3931739
EternalStorageProxy|upgradeTo|35871|30924|30913
ForeignBridgeNativeToErc|initialize|281275|281339|281328
ERC677BridgeToken|setBridgeContract|29432|44432|39432
ERC677BridgeToken|setBridgeContracts|47552|86474|77323
ERC677BridgeToken|transferOwnership|30860|30924|30913
EternalStorageProxy|transferProxyOwnership|30653|30653|30653
Total| |8189163|8291266|8250125

View File

@ -29,7 +29,7 @@ EternalStorageProxy|deployment|378510|378510|378510
ForeignBridgeNativeToErc|deployment|3931739|3931739|3931739
EternalStorageProxy|upgradeTo|35871|30924|30913
ForeignBridgeNativeToErc|initialize|281275|281339|281328
ERC677BridgeToken|setBridgeContract|29432|44432|39432
ERC677BridgeToken|setBridgeContracts|47552|86474|77323
ERC677BridgeToken|transferOwnership|30860|30924|30913
EternalStorageProxy|transferProxyOwnership|30653|30653|30653
Total| |8189163|8291266|8250125

View File

@ -694,7 +694,7 @@ function shouldBehaveLikeBasicAMBErc677ToErc677(otherSideMediatorContract, accou
// Given
const erc677Token = await ERC677BridgeToken.new('test', 'TST', 18)
await erc677Token.mint(user, twoEthers, { from: owner }).should.be.fulfilled
await erc677Token.setBridgeContract(contract.address, { from: owner }).should.be.fulfilled
await erc677Token.setBridgeContracts([contract.address], { from: owner }).should.be.fulfilled
await erc677Token.transferOwnership(contract.address, { from: owner }).should.be.fulfilled
contract = this.bridge

View File

@ -46,32 +46,32 @@ async function testERC677BridgeToken(accounts, rewardable) {
describe('#bridgeContract', async () => {
it('can set bridge contract', async () => {
const homeErcToErcContract = await HomeErcToErcBridge.new()
;(await token.bridgeContract()).should.be.equal(ZERO_ADDRESS)
;(await token.bridgeContracts()).length.should.be.equal(0)
await token.setBridgeContract(homeErcToErcContract.address).should.be.fulfilled
;(await token.bridgeContract()).should.be.equal(homeErcToErcContract.address)
await token.setBridgeContracts([homeErcToErcContract.address]).should.be.fulfilled
;(await token.bridgeContracts()).should.be.deep.equal([homeErcToErcContract.address])
})
it('only owner can set bridge contract', async () => {
const homeErcToErcContract = await HomeErcToErcBridge.new()
;(await token.bridgeContract()).should.be.equal(ZERO_ADDRESS)
;(await token.bridgeContracts()).length.should.be.equal(0)
await token.setBridgeContract(homeErcToErcContract.address, { from: user }).should.be.rejectedWith(ERROR_MSG)
;(await token.bridgeContract()).should.be.equal(ZERO_ADDRESS)
await token.setBridgeContracts([homeErcToErcContract.address], { from: user }).should.be.rejectedWith(ERROR_MSG)
;(await token.bridgeContracts()).length.should.be.equal(0)
await token.setBridgeContract(homeErcToErcContract.address, { from: owner }).should.be.fulfilled
;(await token.bridgeContract()).should.be.equal(homeErcToErcContract.address)
await token.setBridgeContracts([homeErcToErcContract.address], { from: owner }).should.be.fulfilled
;(await token.bridgeContracts()).should.be.deep.equal([homeErcToErcContract.address])
})
it('fail to set invalid bridge contract address', async () => {
const invalidContractAddress = '0xaaB52d66283F7A1D5978bcFcB55721ACB467384b'
;(await token.bridgeContract()).should.be.equal(ZERO_ADDRESS)
;(await token.bridgeContracts()).length.should.be.equal(0)
await token.setBridgeContract(invalidContractAddress).should.be.rejectedWith(ERROR_MSG)
;(await token.bridgeContract()).should.be.equal(ZERO_ADDRESS)
await token.setBridgeContracts([invalidContractAddress]).should.be.rejectedWith(ERROR_MSG)
;(await token.bridgeContracts()).length.should.be.equal(0)
await token.setBridgeContract(ZERO_ADDRESS).should.be.rejectedWith(ERROR_MSG)
;(await token.bridgeContract()).should.be.equal(ZERO_ADDRESS)
await token.setBridgeContracts([ZERO_ADDRESS]).should.be.rejectedWith(ERROR_MSG)
;(await token.bridgeContracts()).length.should.be.equal(0)
})
})
@ -265,7 +265,7 @@ async function testERC677BridgeToken(accounts, rewardable) {
})
it('sends tokens to bridge contract', async () => {
await token.setBridgeContract(homeErcToErcContract.address).should.be.fulfilled
await token.setBridgeContracts([homeErcToErcContract.address]).should.be.fulfilled
await token.mint(user, oneEther, { from: owner }).should.be.fulfilled
const result = await token.transfer(homeErcToErcContract.address, minPerTx, { from: user }).should.be.fulfilled
@ -275,7 +275,7 @@ async function testERC677BridgeToken(accounts, rewardable) {
value: minPerTx
})
await token.setBridgeContract(foreignNativeToErcBridge.address).should.be.fulfilled
await token.setBridgeContracts([foreignNativeToErcBridge.address]).should.be.fulfilled
const result2 = await token.transfer(foreignNativeToErcBridge.address, minPerTx, {
from: user
}).should.be.fulfilled
@ -287,7 +287,7 @@ async function testERC677BridgeToken(accounts, rewardable) {
})
it('sends tokens to contract that does not contains onTokenTransfer method', async () => {
await token.setBridgeContract(homeErcToErcContract.address).should.be.fulfilled
await token.setBridgeContracts([homeErcToErcContract.address]).should.be.fulfilled
await token.mint(user, oneEther, { from: owner }).should.be.fulfilled
const result = await token.transfer(validatorContract.address, minPerTx, { from: user }).should.be.fulfilled
@ -307,10 +307,10 @@ async function testERC677BridgeToken(accounts, rewardable) {
const lessThanMin = ether('0.0001')
await token.mint(user, oneEther, { from: owner }).should.be.fulfilled
await token.setBridgeContract(homeErcToErcContract.address).should.be.fulfilled
await token.setBridgeContracts([homeErcToErcContract.address]).should.be.fulfilled
await token.transfer(homeErcToErcContract.address, lessThanMin, { from: user }).should.be.rejectedWith(ERROR_MSG)
await token.setBridgeContract(foreignNativeToErcBridge.address).should.be.fulfilled
await token.setBridgeContracts([foreignNativeToErcBridge.address]).should.be.fulfilled
await token
.transfer(foreignNativeToErcBridge.address, lessThanMin, { from: user })
.should.be.rejectedWith(ERROR_MSG)
@ -343,7 +343,7 @@ async function testERC677BridgeToken(accounts, rewardable) {
const amount = ether('1')
const user2 = accounts[2]
await token.setBridgeContract(receiver.address).should.be.fulfilled
await token.setBridgeContracts([receiver.address]).should.be.fulfilled
expect(await receiver.from()).to.be.equal(ZERO_ADDRESS)
expect(await receiver.value()).to.be.bignumber.equal(ZERO)
@ -480,7 +480,7 @@ async function testERC677BridgeToken(accounts, rewardable) {
})
it('sends tokens to bridge contract', async () => {
await token.setBridgeContract(homeErcToErcContract.address).should.be.fulfilled
await token.setBridgeContracts([homeErcToErcContract.address]).should.be.fulfilled
await token.mint(user, oneEther, { from: owner }).should.be.fulfilled
const result = await token.transferAndCall(homeErcToErcContract.address, minPerTx, '0x', {
@ -492,7 +492,7 @@ async function testERC677BridgeToken(accounts, rewardable) {
value: minPerTx
})
await token.setBridgeContract(foreignNativeToErcBridge.address).should.be.fulfilled
await token.setBridgeContracts([foreignNativeToErcBridge.address]).should.be.fulfilled
const result2 = await token.transferAndCall(foreignNativeToErcBridge.address, minPerTx, '0x', { from: user })
.should.be.fulfilled
expectEventInLogs(result2.logs, 'Transfer', {
@ -503,7 +503,7 @@ async function testERC677BridgeToken(accounts, rewardable) {
})
it('fail to sends tokens to contract that does not contains onTokenTransfer method', async () => {
await token.setBridgeContract(homeErcToErcContract.address).should.be.fulfilled
await token.setBridgeContracts([homeErcToErcContract.address]).should.be.fulfilled
await token.mint(user, oneEther, { from: owner }).should.be.fulfilled
await token
@ -515,12 +515,12 @@ async function testERC677BridgeToken(accounts, rewardable) {
const lessThanMin = ether('0.0001')
await token.mint(user, oneEther, { from: owner }).should.be.fulfilled
await token.setBridgeContract(homeErcToErcContract.address).should.be.fulfilled
await token.setBridgeContracts([homeErcToErcContract.address]).should.be.fulfilled
await token
.transferAndCall(homeErcToErcContract.address, lessThanMin, '0x', { from: user })
.should.be.rejectedWith(ERROR_MSG)
await token.setBridgeContract(foreignNativeToErcBridge.address).should.be.fulfilled
await token.setBridgeContracts([foreignNativeToErcBridge.address]).should.be.fulfilled
await token
.transferAndCall(foreignNativeToErcBridge.address, lessThanMin, '0x', { from: user })
.should.be.rejectedWith(ERROR_MSG)