Allow multiple bridges for token (#387)
This commit is contained in:
parent
6d19d2ee8a
commit
92f850de23
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue