Update ERC677 to call onTokenTransfer only for the bridge contract (#530)

This commit is contained in:
Kirill Fedoseev 2020-10-15 11:36:17 +03:00 committed by GitHub
parent d94ad55f52
commit f70426c841
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 33 additions and 49 deletions

View File

@ -16,8 +16,6 @@ contract ERC677BridgeToken is IBurnableMintableERC677Token, DetailedERC20, Burna
address internal bridgeContractAddr;
event ContractFallbackCallFailed(address from, address to, uint256 value);
constructor(string _name, string _symbol, uint8 _decimals) public DetailedERC20(_name, _symbol, _decimals) {
// solhint-disable-previous-line no-empty-blocks
}
@ -67,10 +65,17 @@ contract ERC677BridgeToken is IBurnableMintableERC677Token, DetailedERC20, Burna
return true;
}
/**
* @dev Internal function that calls onTokenTransfer callback on the receiver after the successful transfer.
* Since it is not present in the original ERC677 standard, the callback is only called on the bridge contract,
* in order to simplify UX. In other cases, this token complies with the ERC677/ERC20 standard.
* @param _from tokens sender address.
* @param _to tokens receiver address.
* @param _value amount of sent tokens.
*/
function callAfterTransfer(address _from, address _to, uint256 _value) internal {
if (AddressUtils.isContract(_to) && !contractFallback(_from, _to, _value, new bytes(0))) {
require(!isBridge(_to));
emit ContractFallbackCallFailed(_from, _to, _value);
if (isBridge(_to)) {
require(contractFallback(_from, _to, _value, new bytes(0)));
}
}

View File

@ -38,7 +38,6 @@ contract('ForeignAMBErc20ToNative', async accounts => {
await ambBridgeContract.setMaxGasPerTx(maxGasPerTx)
otherSideMediator = await HomeAMBErc20ToNative.new()
token = await ERC677BridgeToken.new('TEST', 'TST', 18)
await token.setBridgeContract(contract.address)
})
describe('initialize', () => {
@ -373,8 +372,8 @@ contract('ForeignAMBErc20ToNative', async accounts => {
describe('handleBridgedTokens', () => {
it('should unlock tokens on message from amb', async () => {
await token.transfer(contract.address, value, { from: user }).should.be.fulfilled
await token.transfer(contract.address, value, { from: user }).should.be.fulfilled
await token.transferAndCall(contract.address, value, '0x', { from: user }).should.be.fulfilled
await token.transferAndCall(contract.address, value, '0x', { from: user }).should.be.fulfilled
expect(await token.balanceOf(contract.address)).to.be.bignumber.equal(twoEthers)
expect(await contract.mediatorBalance()).to.be.bignumber.equal(twoEthers)
@ -429,8 +428,8 @@ contract('ForeignAMBErc20ToNative', async accounts => {
owner,
token.address
).should.be.fulfilled
await token.transfer(contract.address, value, { from: user }).should.be.fulfilled
await token.transfer(contract.address, value, { from: user }).should.be.fulfilled
await token.transferAndCall(contract.address, value, '0x', { from: user }).should.be.fulfilled
await token.transferAndCall(contract.address, value, '0x', { from: user }).should.be.fulfilled
expect(await token.balanceOf(contract.address)).to.be.bignumber.equal(twoEthers)
expect(await contract.mediatorBalance()).to.be.bignumber.equal(twoEthers)
@ -462,8 +461,8 @@ contract('ForeignAMBErc20ToNative', async accounts => {
})
it('should revert when out of execution limits on message from amb', async () => {
await token.transfer(contract.address, value, { from: user }).should.be.fulfilled
await token.transfer(contract.address, value, { from: user }).should.be.fulfilled
await token.transferAndCall(contract.address, value, '0x', { from: user }).should.be.fulfilled
await token.transferAndCall(contract.address, value, '0x', { from: user }).should.be.fulfilled
expect(await token.balanceOf(contract.address)).to.be.bignumber.equal(twoEthers)
expect(await contract.mediatorBalance()).to.be.bignumber.equal(twoEthers)
@ -515,7 +514,7 @@ contract('ForeignAMBErc20ToNative', async accounts => {
})
it('should be a failed transaction', async () => {
await token.transfer(contract.address, value, { from: user }).should.be.fulfilled
await token.transferAndCall(contract.address, value, '0x', { from: user }).should.be.fulfilled
// Given
const data = await contract.contract.methods.handleBridgedTokens(user, value.toString()).encodeABI()

View File

@ -44,10 +44,6 @@ contract('ForeignMultiAMBErc20ToErc677', async accounts => {
})
const sendFunctions = [
async function simpleTransfer() {
await token.transfer(contract.address, value, { from: user }).should.be.fulfilled
return user
},
async function emptyAlternativeReceiver() {
await token.transferAndCall(contract.address, value, '0x', { from: user }).should.be.fulfilled
return user
@ -221,7 +217,7 @@ contract('ForeignMultiAMBErc20ToErc677', async accounts => {
await token.mint(user, oneEther).should.be.fulfilled
expect(await token.balanceOf(user)).to.be.bignumber.equal(oneEther)
await token.transfer(contract.address, oneEther, { from: user }).should.be.fulfilled
await token.transferAndCall(contract.address, oneEther, '0x', { from: user }).should.be.fulfilled
expect(await token.balanceOf(user)).to.be.bignumber.equal(ZERO)
expect(await token.balanceOf(contract.address)).to.be.bignumber.equal(oneEther)
@ -329,7 +325,7 @@ contract('ForeignMultiAMBErc20ToErc677', async accounts => {
await contract.setExecutionDailyLimit(token.address, ether('5'), { from: owner }).should.be.rejected
await contract.setExecutionMaxPerTx(token.address, ether('1.5'), { from: owner }).should.be.rejected
await token.transfer(contract.address, value, { from: user })
await token.transferAndCall(contract.address, value, '0x', { from: user })
await contract.setDailyLimit(token.address, ether('5'), { from: owner }).should.be.fulfilled
await contract.setMaxPerTx(token.address, ether('1.5'), { from: owner }).should.be.fulfilled
@ -513,7 +509,7 @@ contract('ForeignMultiAMBErc20ToErc677', async accounts => {
token = await ERC677BridgeToken.new('TEST', 'TST', decimals)
await token.mint(user, value.mul(f1).div(f2)).should.be.fulfilled
await token.transfer(contract.address, value.mul(f1).div(f2), { from: user }).should.be.fulfilled
await token.transferAndCall(contract.address, value.mul(f1).div(f2), '0x', { from: user }).should.be.fulfilled
expect(await contract.dailyLimit(token.address)).to.be.bignumber.equal(dailyLimit.mul(f1).div(f2))
expect(await contract.maxPerTx(token.address)).to.be.bignumber.equal(maxPerTx.mul(f1).div(f2))
@ -530,7 +526,7 @@ contract('ForeignMultiAMBErc20ToErc677', async accounts => {
it(`should initialize limits according to decimals = 0`, async () => {
token = await ERC677BridgeToken.new('TEST', 'TST', 0)
await token.mint(user, '1').should.be.fulfilled
await token.transfer(contract.address, '1', { from: user }).should.be.fulfilled
await token.transferAndCall(contract.address, '1', '0x', { from: user }).should.be.fulfilled
expect(await contract.dailyLimit(token.address)).to.be.bignumber.equal('10000')
expect(await contract.maxPerTx(token.address)).to.be.bignumber.equal('100')
@ -542,8 +538,8 @@ contract('ForeignMultiAMBErc20ToErc677', async accounts => {
describe('handleBridgedTokens', () => {
it('should unlock tokens on message from amb', async () => {
await token.transfer(contract.address, value, { from: user }).should.be.fulfilled
await token.transfer(contract.address, value, { from: user }).should.be.fulfilled
await token.transferAndCall(contract.address, value, '0x', { from: user }).should.be.fulfilled
await token.transferAndCall(contract.address, value, '0x', { from: user }).should.be.fulfilled
expect(await token.balanceOf(contract.address)).to.be.bignumber.equal(twoEthers)
expect(await contract.mediatorBalance(token.address)).to.be.bignumber.equal(twoEthers)
@ -605,8 +601,8 @@ contract('ForeignMultiAMBErc20ToErc677', async accounts => {
})
it('should not allow to operate when global shutdown is enabled', async () => {
await token.transfer(contract.address, value, { from: user }).should.be.fulfilled
await token.transfer(contract.address, value, { from: user }).should.be.fulfilled
await token.transferAndCall(contract.address, value, '0x', { from: user }).should.be.fulfilled
await token.transferAndCall(contract.address, value, '0x', { from: user }).should.be.fulfilled
const data = await contract.contract.methods
.handleBridgedTokens(token.address, user, value.toString())
@ -662,7 +658,7 @@ contract('ForeignMultiAMBErc20ToErc677', async accounts => {
})
it('should be a failed transaction', async () => {
await token.transfer(contract.address, value, { from: user }).should.be.fulfilled
await token.transferAndCall(contract.address, value, '0x', { from: user }).should.be.fulfilled
// Given
const data = await contract.contract.methods
.handleBridgedTokens(token.address, user, value.toString())
@ -857,7 +853,7 @@ contract('ForeignMultiAMBErc20ToErc677', async accounts => {
expect(await contract.mediatorBalance(token.address)).to.be.bignumber.equal(ZERO)
expect(await token.balanceOf(contract.address)).to.be.bignumber.equal(twoEthers)
await token.transfer(contract.address, halfEther, { from: user }).should.be.fulfilled
await token.transferAndCall(contract.address, halfEther, '0x', { from: user }).should.be.fulfilled
await contract.setDailyLimit(token.address, ether('5')).should.be.fulfilled
await contract.setMaxPerTx(token.address, ether('2')).should.be.fulfilled
@ -884,7 +880,7 @@ contract('ForeignMultiAMBErc20ToErc677', async accounts => {
expect(await contract.mediatorBalance(token.address)).to.be.bignumber.equal(ZERO)
expect(await token.balanceOf(contract.address)).to.be.bignumber.equal(twoEthers)
await token.transfer(contract.address, halfEther, { from: user }).should.be.fulfilled
await token.transferAndCall(contract.address, halfEther, '0x', { from: user }).should.be.fulfilled
expect(await contract.mediatorBalance(token.address)).to.be.bignumber.equal(halfEther)
expect(await token.balanceOf(contract.address)).to.be.bignumber.equal(twoEthers.add(halfEther))

View File

@ -97,7 +97,8 @@ contract('HomeMultiAMBErc20ToErc677', async accounts => {
async function bridgeToken(token, value = oneEther, forceFail = false) {
await token.mint(user, value).should.be.fulfilled
const { receipt } = await token.transfer(otherSideMediator.address, value, { from: user }).should.be.fulfilled
const { receipt } = await token.transferAndCall(otherSideMediator.address, value, '0x', { from: user }).should.be
.fulfilled
const encodedData = strip0x(
web3.eth.abi.decodeParameters(
['bytes'],

View File

@ -309,23 +309,6 @@ function testERC677BridgeToken(accounts, rewardable, permittable, createToken) {
})
})
it('sends tokens to contract that does not contains onTokenTransfer method', async () => {
await addBridge(token, 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
expectEventInLogs(result.logs, 'Transfer', {
from: user,
to: validatorContract.address,
value: minPerTx
})
expectEventInLogs(result.logs, 'ContractFallbackCallFailed', {
from: user,
to: validatorContract.address,
value: minPerTx
})
})
it('fail to send tokens to bridge contract out of limits', async () => {
const lessThanMin = ether('0.0001')
await token.mint(user, oneEther, { from: owner }).should.be.fulfilled
@ -588,7 +571,7 @@ function testERC677BridgeToken(accounts, rewardable, permittable, createToken) {
})
})
describe('#transfer', async () => {
it('if transfer called on contract, onTokenTransfer is also invoked', async () => {
it('if transfer called on contract, onTokenTransfer is not invoked', async () => {
const receiver = await ERC677ReceiverTest.new()
expect(await receiver.from()).to.be.equal(ZERO_ADDRESS)
expect(await receiver.value()).to.be.bignumber.equal(ZERO)
@ -600,8 +583,8 @@ function testERC677BridgeToken(accounts, rewardable, permittable, createToken) {
expect(await token.balanceOf(receiver.address)).to.be.bignumber.equal('1')
expect(await token.balanceOf(user)).to.be.bignumber.equal(ZERO)
expect(await receiver.from()).to.be.equal(user)
expect(await receiver.value()).to.be.bignumber.equal('1')
expect(await receiver.from()).to.be.equal(ZERO_ADDRESS)
expect(await receiver.value()).to.be.bignumber.equal(ZERO)
expect(await receiver.data()).to.be.equal(null)
expect(logs[0].event).to.be.equal('Transfer')
})