Add alternative receiver for transfer in native to erc20 mode (#302)

This commit is contained in:
Gerardo Nardelli 2019-10-23 12:46:48 -03:00 committed by Alexander Kolotov
parent 7d033bde33
commit c0ee60806d
18 changed files with 389 additions and 102 deletions

View File

@ -5,6 +5,7 @@ import "./BasicTokenBridge.sol";
import "../interfaces/ERC677.sol";
import "../interfaces/ERC677Receiver.sol";
import "./ERC677Storage.sol";
import "../libraries/Bytes.sol";
contract BaseERC677Bridge is BasicTokenBridge, ERC677Receiver, ERC677Storage {
function erc677token() public view returns (ERC677) {
@ -25,6 +26,19 @@ contract BaseERC677Bridge is BasicTokenBridge, ERC677Receiver, ERC677Storage {
return true;
}
function chooseReceiver(address _from, bytes _data) internal view returns (address recipient) {
recipient = _from;
if (_data.length > 0) {
require(_data.length == 20);
recipient = Bytes.bytesToAddress(_data);
require(recipient != address(0));
require(recipient != bridgeContractOnOtherSide());
}
}
/* solcov ignore next */
function bridgeSpecificActionsOnTokenTransfer(ERC677 _token, address _from, uint256 _value, bytes _data) internal;
/* solcov ignore next */
function bridgeContractOnOtherSide() internal view returns (address);
}

View File

@ -1,8 +1,9 @@
pragma solidity 0.4.24;
import "./BaseERC677Bridge.sol";
import "./OtherSideBridgeStorage.sol";
contract ERC677Bridge is BaseERC677Bridge {
contract ERC677Bridge is BaseERC677Bridge, OtherSideBridgeStorage {
function bridgeSpecificActionsOnTokenTransfer(
ERC677, /*_token*/
address _from,

View File

@ -4,13 +4,8 @@ import "./ERC677Bridge.sol";
import "../interfaces/IBurnableMintableERC677Token.sol";
contract ERC677BridgeForBurnableMintableToken is ERC677Bridge {
function bridgeSpecificActionsOnTokenTransfer(
ERC677 _token,
address _from,
uint256 _value,
bytes /*_data*/
) internal {
function bridgeSpecificActionsOnTokenTransfer(ERC677 _token, address _from, uint256 _value, bytes _data) internal {
IBurnableMintableERC677Token(_token).burn(_value);
fireEventOnTokenTransfer(_from, _value);
fireEventOnTokenTransfer(chooseReceiver(_from, _data), _value);
}
}

View File

@ -3,7 +3,7 @@ pragma solidity 0.4.24;
import "./Initializable.sol";
contract InitializableBridge is Initializable {
bytes32 internal constant DEPLOYED_AT_BLOCK = 0xb120ceec05576ad0c710bc6e85f1768535e27554458f05dcbb5c65b8c7a749b0; // keccak256(abi.encodePacked("deployedAtBlock"));
bytes32 internal constant DEPLOYED_AT_BLOCK = 0xb120ceec05576ad0c710bc6e85f1768535e27554458f05dcbb5c65b8c7a749b0; // keccak256(abi.encodePacked("deployedAtBlock"))
function deployedAtBlock() external view returns (uint256) {
return uintStorage[DEPLOYED_AT_BLOCK];

View File

@ -0,0 +1,15 @@
pragma solidity 0.4.24;
import "../upgradeability/EternalStorage.sol";
contract OtherSideBridgeStorage is EternalStorage {
bytes32 internal constant BRIDGE_CONTRACT = 0x71483949fe7a14d16644d63320f24d10cf1d60abecc30cc677a340e82b699dd2; // keccak256(abi.encodePacked("bridgeOnOtherSide"))
function _setBridgeContractOnOtherSide(address _bridgeContract) internal {
addressStorage[BRIDGE_CONTRACT] = _bridgeContract;
}
function bridgeContractOnOtherSide() internal view returns (address) {
return addressStorage[BRIDGE_CONTRACT];
}
}

View File

@ -67,14 +67,8 @@ contract BasicAMBErc677ToErc677 is
return isInitialized();
}
function chooseReceiver(address _from, bytes _data) internal view returns (address recipient) {
recipient = _from;
if (_data.length > 0) {
require(_data.length == 20);
recipient = Bytes.bytesToAddress(_data);
require(recipient != address(0));
require(recipient != mediatorContractOnOtherSide());
}
function bridgeContractOnOtherSide() internal view returns (address) {
return mediatorContractOnOtherSide();
}
function passMessage(address _from, uint256 _value) internal {

View File

@ -1,8 +1,6 @@
pragma solidity 0.4.24;
import "./BasicAMBErc677ToErc677.sol";
import "../ERC677Bridge.sol";
import "openzeppelin-solidity/contracts/AddressUtils.sol";
contract ForeignAMBErc677ToErc677 is BasicAMBErc677ToErc677 {
function executeActionOnBridgedTokens(address _recipient, uint256 _value) internal {

View File

@ -2,7 +2,6 @@ pragma solidity 0.4.24;
import "./BasicAMBErc677ToErc677.sol";
import "../../interfaces/IBurnableMintableERC677Token.sol";
import "openzeppelin-solidity/contracts/AddressUtils.sol";
contract HomeAMBErc677ToErc677 is BasicAMBErc677ToErc677 {
function executeActionOnBridgedTokens(address _recipient, uint256 _value) internal {

View File

@ -2,13 +2,12 @@ pragma solidity 0.4.24;
import "../BasicForeignBridge.sol";
import "../ERC20Bridge.sol";
import "../OtherSideBridgeStorage.sol";
contract ForeignBridgeErcToNative is BasicForeignBridge, ERC20Bridge {
contract ForeignBridgeErcToNative is BasicForeignBridge, ERC20Bridge, OtherSideBridgeStorage {
event RelayedMessage(address recipient, uint256 value, bytes32 transactionHash);
event UserRequestForAffirmation(address recipient, uint256 value);
bytes32 internal constant BRIDGE_CONTRACT = 0x71483949fe7a14d16644d63320f24d10cf1d60abecc30cc677a340e82b699dd2; // keccak256(abi.encodePacked("bridgeOnOtherSide"))
function initialize(
address _validatorContract,
address _erc20token,
@ -79,14 +78,6 @@ contract ForeignBridgeErcToNative is BasicForeignBridge, ERC20Bridge {
revert();
}
function _setBridgeContractOnOtherSide(address _bridgeContract) internal {
addressStorage[BRIDGE_CONTRACT] = _bridgeContract;
}
function bridgeContractOnOtherSide() public view returns (address) {
return addressStorage[BRIDGE_CONTRACT];
}
function _relayTokens(address _sender, address _receiver, uint256 _amount) internal {
require(_receiver != address(0));
require(_receiver != address(this));

View File

@ -4,7 +4,6 @@ import "../../libraries/Message.sol";
import "../../upgradeability/EternalStorage.sol";
import "../../interfaces/IBlockReward.sol";
import "../BasicHomeBridge.sol";
import "../ERC677Bridge.sol";
import "../OverdrawManagement.sol";
import "./RewardableHomeBridgeErcToNative.sol";
import "../BlockRewardBridge.sol";

View File

@ -22,7 +22,8 @@ contract ForeignBridgeNativeToErc is
uint256 _requiredBlockConfirmations,
uint256[] _homeDailyLimitHomeMaxPerTxArray, // [ 0 = _homeDailyLimit, 1 = _homeMaxPerTx ]
address _owner,
uint256 _decimalShift
uint256 _decimalShift,
address _bridgeOnOtherSide
) external returns (bool) {
_initialize(
_validatorContract,
@ -32,7 +33,8 @@ contract ForeignBridgeNativeToErc is
_requiredBlockConfirmations,
_homeDailyLimitHomeMaxPerTxArray,
_owner,
_decimalShift
_decimalShift,
_bridgeOnOtherSide
);
setInitialize();
return isInitialized();
@ -48,7 +50,8 @@ contract ForeignBridgeNativeToErc is
address _owner,
address _feeManager,
uint256 _homeFee,
uint256 _decimalShift
uint256 _decimalShift,
address _bridgeOnOtherSide
) external returns (bool) {
_initialize(
_validatorContract,
@ -58,7 +61,8 @@ contract ForeignBridgeNativeToErc is
_requiredBlockConfirmations,
_homeDailyLimitHomeMaxPerTxArray,
_owner,
_decimalShift
_decimalShift,
_bridgeOnOtherSide
);
require(AddressUtils.isContract(_feeManager));
addressStorage[FEE_MANAGER_CONTRACT] = _feeManager;
@ -83,7 +87,8 @@ contract ForeignBridgeNativeToErc is
uint256 _requiredBlockConfirmations,
uint256[] _homeDailyLimitHomeMaxPerTxArray, // [ 0 = _homeDailyLimit, 1 = _homeMaxPerTx ]
address _owner,
uint256 _decimalShift
uint256 _decimalShift,
address _bridgeOnOtherSide
) internal {
require(!isInitialized());
require(AddressUtils.isContract(_validatorContract));
@ -109,6 +114,7 @@ contract ForeignBridgeNativeToErc is
uintStorage[EXECUTION_MAX_PER_TX] = _homeDailyLimitHomeMaxPerTxArray[1];
uintStorage[DECIMAL_SHIFT] = _decimalShift;
setOwner(_owner);
_setBridgeContractOnOtherSide(_bridgeOnOtherSide);
emit RequiredBlockConfirmationChanged(_requiredBlockConfirmations);
emit GasPriceChanged(_foreignGasPrice);

View File

@ -8,12 +8,12 @@ import "../Sacrifice.sol";
contract HomeBridgeNativeToErc is EternalStorage, BasicHomeBridge, RewardableHomeBridgeNativeToErc {
function() public payable {
nativeTransfer();
require(msg.data.length == 0);
nativeTransfer(msg.sender);
}
function nativeTransfer() internal {
function nativeTransfer(address _receiver) internal {
require(msg.value > 0);
require(msg.data.length == 0);
require(withinLimit(msg.value));
setTotalSpentPerDay(getCurrentDay(), totalSpentPerDay(getCurrentDay()).add(msg.value));
uint256 valueToTransfer = msg.value;
@ -22,7 +22,11 @@ contract HomeBridgeNativeToErc is EternalStorage, BasicHomeBridge, RewardableHom
uint256 fee = calculateFee(valueToTransfer, false, feeManager, HOME_FEE);
valueToTransfer = valueToTransfer.sub(fee);
}
emit UserRequestForSignature(msg.sender, valueToTransfer);
emit UserRequestForSignature(_receiver, valueToTransfer);
}
function relayTokens(address _receiver) external payable {
nativeTransfer(_receiver);
}
function initialize(

View File

@ -12,7 +12,7 @@ async function deployNativeToErc() {
const deployForeign = require('./src/native_to_erc/foreign')
await preDeploy()
const { homeBridge } = await deployHome()
const { foreignBridge, erc677 } = await deployForeign()
const { foreignBridge, erc677 } = await deployForeign(homeBridge.address)
console.log('\nDeployment has been completed.\n\n')
console.log(`[ Home ] HomeBridge: ${homeBridge.address} at block ${homeBridge.deployedBlockNumber}`)
console.log(`[ Foreign ] ForeignBridge: ${foreignBridge.address} at block ${foreignBridge.deployedBlockNumber}`)

View File

@ -64,7 +64,7 @@ if (isRewardableBridge) {
VALIDATORS_REWARD_ACCOUNTS = env.VALIDATORS_REWARD_ACCOUNTS.split(' ')
}
async function initializeBridge({ validatorsBridge, bridge, erc677bridgeToken, initialNonce }) {
async function initializeBridge({ validatorsBridge, bridge, erc677bridgeToken, initialNonce, homeBridgeAddress }) {
let nonce = initialNonce
let initializeFBridgeData
@ -95,7 +95,8 @@ async function initializeBridge({ validatorsBridge, bridge, erc677bridgeToken, i
FOREIGN_BRIDGE_OWNER: ${FOREIGN_BRIDGE_OWNER},
Fee Manager: ${feeManager.options.address},
Home Fee: ${homeFeeInWei} which is ${HOME_TRANSACTIONS_FEE * 100}%,
FOREIGN_TO_HOME_DECIMAL_SHIFT: ${foreignToHomeDecimalShift}`)
FOREIGN_TO_HOME_DECIMAL_SHIFT: ${foreignToHomeDecimalShift}
Home bridge Address: ${homeBridgeAddress}`)
initializeFBridgeData = await bridge.methods
.rewardableInitialize(
@ -108,7 +109,8 @@ async function initializeBridge({ validatorsBridge, bridge, erc677bridgeToken, i
FOREIGN_BRIDGE_OWNER,
feeManager.options.address,
homeFeeInWei,
foreignToHomeDecimalShift
foreignToHomeDecimalShift,
homeBridgeAddress
)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
} else {
@ -126,6 +128,7 @@ async function initializeBridge({ validatorsBridge, bridge, erc677bridgeToken, i
HOME_MAX_AMOUNT_PER_TX: ${HOME_MAX_AMOUNT_PER_TX} which is ${Web3Utils.fromWei(HOME_MAX_AMOUNT_PER_TX)} in eth,
FOREIGN_BRIDGE_OWNER: ${FOREIGN_BRIDGE_OWNER},
FOREIGN_TO_HOME_DECIMAL_SHIFT: ${foreignToHomeDecimalShift}
Home bridge Address: ${homeBridgeAddress}
`)
initializeFBridgeData = await bridge.methods
@ -137,7 +140,8 @@ async function initializeBridge({ validatorsBridge, bridge, erc677bridgeToken, i
FOREIGN_REQUIRED_BLOCK_CONFIRMATIONS,
[HOME_DAILY_LIMIT, HOME_MAX_AMOUNT_PER_TX],
FOREIGN_BRIDGE_OWNER,
foreignToHomeDecimalShift
foreignToHomeDecimalShift,
homeBridgeAddress
)
.encodeABI({ from: DEPLOYMENT_ACCOUNT_ADDRESS })
}
@ -159,7 +163,7 @@ async function initializeBridge({ validatorsBridge, bridge, erc677bridgeToken, i
return nonce
}
async function deployForeign() {
async function deployForeign(homeBridgeAddress) {
let nonce = await web3Foreign.eth.getTransactionCount(DEPLOYMENT_ACCOUNT_ADDRESS)
console.log('========================================')
console.log('deploying ForeignBridge')
@ -259,7 +263,8 @@ async function deployForeign() {
validatorsBridge: storageValidatorsForeign,
bridge: foreignBridgeImplementation,
erc677bridgeToken,
initialNonce: nonce
initialNonce: nonce,
homeBridgeAddress
})
console.log('\nset bridge contract on ERC677BridgeToken')

View File

@ -1439,7 +1439,7 @@ contract('HomeBridge_ERC20_to_ERC20', async accounts => {
await token.mint(user, value, { from: owner }).should.be.fulfilled
// When
await token.transferAndCall(homeBridge.address, value, '0x00', { from: user }).should.be.fulfilled
await token.transferAndCall(homeBridge.address, value, '0x', { from: user }).should.be.fulfilled
// Then
const events = await getEvents(homeBridge, { event: 'UserRequestForSignature' })
@ -1481,7 +1481,7 @@ contract('HomeBridge_ERC20_to_ERC20', async accounts => {
await token.mint(user, value, { from: owner }).should.be.fulfilled
// When
await token.transferAndCall(homeBridge.address, value, '0x00', { from: user }).should.be.fulfilled
await token.transferAndCall(homeBridge.address, value, '0x', { from: user }).should.be.fulfilled
// Then
const events = await getEvents(homeBridge, { event: 'UserRequestForSignature' })
@ -1969,7 +1969,7 @@ contract('HomeBridge_ERC20_to_ERC20', async accounts => {
await token.mint(user, value, { from: owner }).should.be.fulfilled
// When
await token.transferAndCall(homeBridge.address, value, '0x00', { from: user }).should.be.fulfilled
await token.transferAndCall(homeBridge.address, value, '0x', { from: user }).should.be.fulfilled
// Then
const events = await getEvents(homeBridge, { event: 'UserRequestForSignature' })

View File

@ -1,5 +1,6 @@
const ForeignBridge = artifacts.require('ForeignBridgeNativeToErc.sol')
const ForeignBridgeV2 = artifacts.require('ForeignBridgeV2.sol')
const HomeBridge = artifacts.require('HomeBridgeNativeToErc.sol')
const BridgeValidators = artifacts.require('BridgeValidators.sol')
const EternalStorageProxy = artifacts.require('EternalStorageProxy.sol')
const FeeManagerNativeToErc = artifacts.require('FeeManagerNativeToErc.sol')
@ -26,11 +27,14 @@ contract('ForeignBridge', async accounts => {
let authorities
let owner
let token
let otherSideBridgeAddress
before(async () => {
validatorContract = await BridgeValidators.new()
authorities = [accounts[1], accounts[2]]
owner = accounts[0]
await validatorContract.initialize(1, authorities, owner)
const otherSideBridge = await HomeBridge.new()
otherSideBridgeAddress = otherSideBridge.address
})
describe('#initialize', async () => {
@ -55,7 +59,8 @@ contract('ForeignBridge', async accounts => {
requireBlockConfirmations,
[homeDailyLimit, homeMaxPerTx],
owner,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
)
.should.be.rejectedWith(ERROR_MSG)
await foreignBridge
@ -67,7 +72,8 @@ contract('ForeignBridge', async accounts => {
requireBlockConfirmations,
[homeDailyLimit, homeMaxPerTx],
owner,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
)
.should.be.rejectedWith(ERROR_MSG)
await foreignBridge
@ -79,7 +85,8 @@ contract('ForeignBridge', async accounts => {
requireBlockConfirmations,
[homeDailyLimit, homeMaxPerTx],
owner,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
)
.should.be.rejectedWith(ERROR_MSG)
await foreignBridge
@ -91,7 +98,8 @@ contract('ForeignBridge', async accounts => {
gasPrice,
[homeDailyLimit, homeMaxPerTx],
owner,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
)
.should.be.rejectedWith(ERROR_MSG)
await foreignBridge
@ -103,7 +111,8 @@ contract('ForeignBridge', async accounts => {
gasPrice,
[homeDailyLimit, homeMaxPerTx],
owner,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
)
.should.be.rejectedWith(ERROR_MSG)
await foreignBridge
@ -115,7 +124,8 @@ contract('ForeignBridge', async accounts => {
0,
[homeDailyLimit, homeMaxPerTx],
owner,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
)
.should.be.rejectedWith(ERROR_MSG)
const { logs } = await foreignBridge.initialize(
@ -126,7 +136,8 @@ contract('ForeignBridge', async accounts => {
requireBlockConfirmations,
[homeDailyLimit, homeMaxPerTx],
owner,
'9'
'9',
otherSideBridgeAddress
)
expect(await foreignBridge.isInitialized()).to.be.equal(true)
@ -169,7 +180,8 @@ contract('ForeignBridge', async accounts => {
requireBlockConfirmations,
[homeDailyLimit, homeMaxPerTx],
owner,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
)
await token.transferOwnership(foreignBridge.address)
})
@ -315,6 +327,7 @@ contract('ForeignBridge', async accounts => {
[homeDailyLimit, homeMaxPerTx],
owner,
decimalShiftZero,
otherSideBridgeAddress,
{ from: ownerOfValidatorContract }
)
await token.transferOwnership(foreignBridgeWithMultiSignatures.address)
@ -378,7 +391,8 @@ contract('ForeignBridge', async accounts => {
requireBlockConfirmations,
[homeDailyLimit, homeMaxPerTx],
owner,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
)
await erc20Token.transferOwnership(foreignBridgeWithThreeSigs.address)
@ -426,7 +440,8 @@ contract('ForeignBridge', async accounts => {
requireBlockConfirmations,
[homeDailyLimit, homeMaxPerTx],
owner,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
)
await erc20Token.transferOwnership(foreignBridgeWithThreeSigs.address)
@ -474,12 +489,13 @@ contract('ForeignBridge', async accounts => {
requireBlockConfirmations,
[homeDailyLimit, homeMaxPerTx],
owner,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
)
await token.mint(user, halfEther, { from: owner }).should.be.fulfilled
await token.transferOwnership(foreignBridge.address, { from: owner })
await foreignBridge.onTokenTransfer(user, halfEther, '0x00', { from: owner }).should.be.rejectedWith(ERROR_MSG)
await token.transferAndCall(foreignBridge.address, halfEther, '0x00', { from: user }).should.be.fulfilled
await foreignBridge.onTokenTransfer(user, halfEther, '0x', { from: owner }).should.be.rejectedWith(ERROR_MSG)
await token.transferAndCall(foreignBridge.address, halfEther, '0x', { from: user }).should.be.fulfilled
expect(await token.totalSupply()).to.be.bignumber.equal(ZERO)
expect(await token.balanceOf(user)).to.be.bignumber.equal(ZERO)
})
@ -498,19 +514,20 @@ contract('ForeignBridge', async accounts => {
requireBlockConfirmations,
[homeDailyLimit, homeMaxPerTx],
owner,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
)
await token.mint(user, valueMoreThanLimit, { from: owner }).should.be.fulfilled
await token.transferOwnership(foreignBridge.address, { from: owner })
await token
.transferAndCall(foreignBridge.address, valueMoreThanLimit, '0x00', { from: user })
.transferAndCall(foreignBridge.address, valueMoreThanLimit, '0x', { from: user })
.should.be.rejectedWith(ERROR_MSG)
valueMoreThanLimit.should.be.bignumber.equal(await token.totalSupply())
valueMoreThanLimit.should.be.bignumber.equal(await token.balanceOf(user))
await token.transferAndCall(foreignBridge.address, halfEther, '0x00', { from: user }).should.be.fulfilled
await token.transferAndCall(foreignBridge.address, halfEther, '0x', { from: user }).should.be.fulfilled
expect(await token.totalSupply()).to.be.bignumber.equal('1')
expect(await token.balanceOf(user)).to.be.bignumber.equal('1')
@ -533,31 +550,31 @@ contract('ForeignBridge', async accounts => {
requireBlockConfirmations,
[homeDailyLimit, homeMaxPerTx],
owner,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
)
await token.mint(user, oneEther.add(toBN(1)), { from: owner }).should.be.fulfilled
await token.transferOwnership(foreignBridge.address, { from: owner })
await token
.transferAndCall(foreignBridge.address, valueMoreThanLimit, '0x00', { from: user })
.transferAndCall(foreignBridge.address, valueMoreThanLimit, '0x', { from: user })
.should.be.rejectedWith(ERROR_MSG)
oneEther.add(toBN(1)).should.be.bignumber.equal(await token.totalSupply())
oneEther.add(toBN(1)).should.be.bignumber.equal(await token.balanceOf(user))
await token.transferAndCall(foreignBridge.address, halfEther, '0x00', { from: user }).should.be.fulfilled
await token.transferAndCall(foreignBridge.address, halfEther, '0x', { from: user }).should.be.fulfilled
valueMoreThanLimit.should.be.bignumber.equal(await token.totalSupply())
valueMoreThanLimit.should.be.bignumber.equal(await token.balanceOf(user))
await token.transferAndCall(foreignBridge.address, halfEther, '0x00', { from: user }).should.be.fulfilled
await token.transferAndCall(foreignBridge.address, halfEther, '0x', { from: user }).should.be.fulfilled
expect(await token.totalSupply()).to.be.bignumber.equal('1')
expect(await token.balanceOf(user)).to.be.bignumber.equal('1')
await token.transferAndCall(foreignBridge.address, '1', '0x00', { from: user }).should.be.rejectedWith(ERROR_MSG)
await token.transferAndCall(foreignBridge.address, '1', '0x', { from: user }).should.be.rejectedWith(ERROR_MSG)
})
it('should not let to withdraw less than minPerTx', async () => {
const owner = accounts[3]
const user = accounts[4]
@ -572,23 +589,56 @@ contract('ForeignBridge', async accounts => {
requireBlockConfirmations,
[homeDailyLimit, homeMaxPerTx],
owner,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
)
await token.mint(user, oneEther, { from: owner }).should.be.fulfilled
await token.transferOwnership(foreignBridge.address, { from: owner })
await token
.transferAndCall(foreignBridge.address, valueLessThanMinPerTx, '0x00', { from: user })
.transferAndCall(foreignBridge.address, valueLessThanMinPerTx, '0x', { from: user })
.should.be.rejectedWith(ERROR_MSG)
oneEther.should.be.bignumber.equal(await token.totalSupply())
oneEther.should.be.bignumber.equal(await token.balanceOf(user))
await token.transferAndCall(foreignBridge.address, minPerTx, '0x00', { from: user }).should.be.fulfilled
await token.transferAndCall(foreignBridge.address, minPerTx, '0x', { from: user }).should.be.fulfilled
oneEther.sub(minPerTx).should.be.bignumber.equal(await token.totalSupply())
oneEther.sub(minPerTx).should.be.bignumber.equal(await token.balanceOf(user))
})
it('should be able to specify a different receiver', async () => {
const owner = accounts[3]
const user = accounts[4]
const user2 = accounts[5]
token = await POA20.new('POA ERC20 Foundation', 'POA20', 18, { from: owner })
const foreignBridge = await ForeignBridge.new()
await foreignBridge.initialize(
validatorContract.address,
token.address,
[oneEther, halfEther, minPerTx],
gasPrice,
requireBlockConfirmations,
[homeDailyLimit, homeMaxPerTx],
owner,
decimalShiftZero,
otherSideBridgeAddress
)
await token.mint(user, halfEther, { from: owner }).should.be.fulfilled
await token.transferOwnership(foreignBridge.address, { from: owner })
await token
.transferAndCall(foreignBridge.address, halfEther, otherSideBridgeAddress, { from: user })
.should.be.rejectedWith(ERROR_MSG)
await token
.transferAndCall(foreignBridge.address, halfEther, '0x00', { from: user })
.should.be.rejectedWith(ERROR_MSG)
await token.transferAndCall(foreignBridge.address, halfEther, user2, { from: user }).should.be.fulfilled
expect(await token.totalSupply()).to.be.bignumber.equal(ZERO)
expect(await token.balanceOf(user)).to.be.bignumber.equal(ZERO)
const events = await getEvents(foreignBridge, { event: 'UserRequestForAffirmation' })
expect(events[0].returnValues.recipient).to.be.equal(user2)
expect(toBN(events[0].returnValues.value)).to.be.bignumber.equal(halfEther)
})
})
describe('#setting limits', async () => {
@ -604,7 +654,8 @@ contract('ForeignBridge', async accounts => {
requireBlockConfirmations,
[homeDailyLimit, homeMaxPerTx],
owner,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
)
await token.transferOwnership(foreignBridge.address)
})
@ -657,7 +708,8 @@ contract('ForeignBridge', async accounts => {
requireBlockConfirmations,
[homeDailyLimit, homeMaxPerTx],
owner,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
)
await token.transferOwnership(foreignBridgeProxy.address).should.be.fulfilled
@ -687,7 +739,8 @@ contract('ForeignBridge', async accounts => {
requireBlockConfirmations,
['3', '2'],
owner,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
)
.encodeABI()
await storageProxy.upgradeToAndCall('1', foreignBridge.address, data).should.be.fulfilled
@ -712,7 +765,8 @@ contract('ForeignBridge', async accounts => {
requireBlockConfirmations,
['3', '2'],
owner,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
)
.encodeABI()
await storageProxy.upgradeToAndCall('1', foreignBridge.address, data).should.be.fulfilled
@ -736,7 +790,8 @@ contract('ForeignBridge', async accounts => {
requireBlockConfirmations,
[homeDailyLimit, homeMaxPerTx],
owner,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
)
await token.transferOwnership(foreignBridge.address)
@ -768,7 +823,8 @@ contract('ForeignBridge', async accounts => {
requireBlockConfirmations,
[homeDailyLimit, homeMaxPerTx],
owner,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
)
await token.transferOwnership(foreignBridge.address)
@ -800,7 +856,8 @@ contract('ForeignBridge', async accounts => {
requireBlockConfirmations,
[homeDailyLimit, homeMaxPerTx],
owner,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
)
const tokenMock = await NoReturnTransferTokenMock.new()
@ -854,7 +911,8 @@ contract('ForeignBridge', async accounts => {
owner,
feeManager.address,
homeFee,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
)
.should.be.rejectedWith(ERROR_MSG)
await foreignBridge
@ -868,7 +926,8 @@ contract('ForeignBridge', async accounts => {
owner,
feeManager.address,
homeFee,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
)
.should.be.rejectedWith(ERROR_MSG)
await foreignBridge
@ -882,7 +941,8 @@ contract('ForeignBridge', async accounts => {
owner,
feeManager.address,
homeFee,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
)
.should.be.rejectedWith(ERROR_MSG)
await foreignBridge
@ -896,7 +956,8 @@ contract('ForeignBridge', async accounts => {
owner,
feeManager.address,
homeFee,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
)
.should.be.rejectedWith(ERROR_MSG)
await foreignBridge
@ -910,7 +971,8 @@ contract('ForeignBridge', async accounts => {
owner,
feeManager.address,
homeFee,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
)
.should.be.rejectedWith(ERROR_MSG)
await foreignBridge
@ -924,7 +986,8 @@ contract('ForeignBridge', async accounts => {
owner,
ZERO_ADDRESS,
homeFee,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
)
.should.be.rejectedWith(ERROR_MSG)
await foreignBridge.rewardableInitialize(
@ -937,7 +1000,8 @@ contract('ForeignBridge', async accounts => {
owner,
feeManager.address,
homeFee,
'9'
'9',
otherSideBridgeAddress
).should.be.fulfilled
expect(await foreignBridge.isInitialized()).to.be.equal(true)
@ -974,7 +1038,8 @@ contract('ForeignBridge', async accounts => {
owner,
feeManager.address,
homeFee,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
).should.be.fulfilled
// Given
@ -999,7 +1064,8 @@ contract('ForeignBridge', async accounts => {
owner,
feeManager.address,
homeFee,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
).should.be.fulfilled
// Given
@ -1023,7 +1089,8 @@ contract('ForeignBridge', async accounts => {
owner,
feeManager.address,
homeFee,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
).should.be.fulfilled
// Given
@ -1056,7 +1123,8 @@ contract('ForeignBridge', async accounts => {
owner,
feeManager.address,
homeFee,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
).should.be.fulfilled
// Then
@ -1098,7 +1166,8 @@ contract('ForeignBridge', async accounts => {
owner,
feeManager.address,
feeInWei,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
).should.be.fulfilled
await token.transferOwnership(foreignBridge.address)
@ -1156,7 +1225,8 @@ contract('ForeignBridge', async accounts => {
owner,
feeManager.address,
feeInWei,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
).should.be.fulfilled
await token.transferOwnership(foreignBridge.address)
@ -1242,7 +1312,8 @@ contract('ForeignBridge', async accounts => {
owner,
feeManager.address,
feeInWei,
decimalShiftZero
decimalShiftZero,
otherSideBridgeAddress
).should.be.fulfilled
await token.transferOwnership(foreignBridge.address)
@ -1322,7 +1393,8 @@ contract('ForeignBridge', async accounts => {
requireBlockConfirmations,
[homeDailyLimit, homeMaxPerTx],
owner,
decimalShiftTwo
decimalShiftTwo,
otherSideBridgeAddress
)
await erc20Token.transferOwnership(foreignBridgeWithThreeSigs.address)
@ -1371,12 +1443,13 @@ contract('ForeignBridge', async accounts => {
requireBlockConfirmations,
[homeDailyLimit, homeMaxPerTx],
owner,
decimalShiftTwo
decimalShiftTwo,
otherSideBridgeAddress
)
await token.mint(user, value, { from: owner }).should.be.fulfilled
expect(await token.balanceOf(user)).to.be.bignumber.equal(value)
await token.transferOwnership(foreignBridge.address, { from: owner })
const { logs } = await token.transferAndCall(foreignBridge.address, value, '0x00', { from: user })
const { logs } = await token.transferAndCall(foreignBridge.address, value, '0x', { from: user })
logs[0].event.should.be.equal('Transfer')
logs[0].args.value.should.be.bignumber.equal(value)
expect(await token.balanceOf(user)).to.be.bignumber.equal(ZERO)

View File

@ -364,6 +364,98 @@ contract('HomeBridge', async accounts => {
})
})
describe('#relayTokens', async () => {
const user = accounts[1]
const user2 = accounts[2]
beforeEach(async () => {
homeContract = await HomeBridge.new()
await homeContract.initialize(
validatorContract.address,
['3', '2', '1'],
gasPrice,
requireBlockConfirmations,
[foreignDailyLimit, foreignMaxPerTx],
owner,
decimalShiftZero
)
})
it('should accept native coins and alternative receiver', async () => {
const currentDay = await homeContract.getCurrentDay()
expect(await homeContract.totalSpentPerDay(currentDay)).to.be.bignumber.equal(ZERO)
const { logs } = await homeContract.relayTokens(user2, {
from: user,
value: 1
}).should.be.fulfilled
expect(await homeContract.totalSpentPerDay(currentDay)).to.be.bignumber.equal('1')
expectEventInLogs(logs, 'UserRequestForSignature', { recipient: user2, value: toBN(1) })
await homeContract
.relayTokens(user2, {
from: user,
value: 3
})
.should.be.rejectedWith(ERROR_MSG)
await homeContract.setDailyLimit(4).should.be.fulfilled
await homeContract.relayTokens(user2, {
from: user,
value: 1
}).should.be.fulfilled
expect(await homeContract.totalSpentPerDay(currentDay)).to.be.bignumber.equal('2')
})
it('doesnt let you send more than max amount per tx', async () => {
await homeContract.relayTokens(user2, {
from: user,
value: 1
}).should.be.fulfilled
await homeContract
.relayTokens(user2, {
from: user,
value: 3
})
.should.be.rejectedWith(ERROR_MSG)
await homeContract.setMaxPerTx(100).should.be.rejectedWith(ERROR_MSG)
await homeContract.setDailyLimit(100).should.be.fulfilled
await homeContract.setMaxPerTx(99).should.be.fulfilled
// meets max per tx and daily limit
await homeContract.relayTokens(user2, {
from: user,
value: 99
}).should.be.fulfilled
// above daily limit
await homeContract
.relayTokens(user2, {
from: user,
value: 1
})
.should.be.rejectedWith(ERROR_MSG)
})
it('should not let to deposit less than minPerTx', async () => {
const newDailyLimit = 100
const newMaxPerTx = 50
const newMinPerTx = 20
await homeContract.setDailyLimit(newDailyLimit).should.be.fulfilled
await homeContract.setMaxPerTx(newMaxPerTx).should.be.fulfilled
await homeContract.setMinPerTx(newMinPerTx).should.be.fulfilled
await homeContract.relayTokens(user2, {
from: user,
value: newMinPerTx
}).should.be.fulfilled
await homeContract
.relayTokens(user2, {
from: user,
value: newMinPerTx - 1
})
.should.be.rejectedWith(ERROR_MSG)
})
})
describe('#setting limits', async () => {
let homeContract
beforeEach(async () => {
@ -1281,6 +1373,55 @@ contract('HomeBridge', async accounts => {
})
})
describe('#feeManager_OneDirection_relayRequest', () => {
it('should not subtract fee from value', async () => {
// Initialize
const user = accounts[0]
const user2 = accounts[4]
const owner = accounts[9]
const validators = [accounts[1]]
const rewards = [accounts[2]]
const requiredSignatures = 1
const rewardableValidators = await RewardableValidators.new()
const homeBridge = await HomeBridge.new()
await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner, {
from: owner
}).should.be.fulfilled
const feeManager = await FeeManagerNativeToErc.new()
// Given
// 0.1% fee
const fee = 0.001
const feeInWei = ether(fee.toString())
const notUsedFee = ZERO
const value = halfEther
await homeBridge.rewardableInitialize(
rewardableValidators.address,
[oneEther, halfEther, minPerTx],
gasPrice,
requireBlockConfirmations,
[foreignDailyLimit, foreignMaxPerTx],
owner,
feeManager.address,
[notUsedFee, feeInWei],
decimalShiftZero
).should.be.fulfilled
// When
const { logs } = await homeBridge.relayTokens(user2, {
from: user,
value
}).should.be.fulfilled
// Then
expectEventInLogs(logs, 'UserRequestForSignature', {
recipient: user2,
value
})
})
})
describe('#feeManager_OneDirection_submitSignature', () => {
it('should not distribute fee to validator', async () => {
// Initialize
@ -1659,6 +1800,56 @@ contract('HomeBridge', async accounts => {
})
})
describe('#feeManager_BothDirections_relayRequest', () => {
it('should subtract fee from value', async () => {
// Initialize
const user = accounts[0]
const user2 = accounts[4]
const owner = accounts[9]
const validators = [accounts[1]]
const rewards = [accounts[2]]
const requiredSignatures = 1
const rewardableValidators = await RewardableValidators.new()
const homeBridge = await HomeBridge.new()
await rewardableValidators.initialize(requiredSignatures, validators, rewards, owner, {
from: owner
}).should.be.fulfilled
const feeManager = await FeeManagerNativeToErcBothDirections.new()
// Given
// 0.1% fee
const fee = 0.001
const feeInWei = ether(fee.toString())
const value = halfEther
await homeBridge.rewardableInitialize(
rewardableValidators.address,
[oneEther, halfEther, minPerTx],
gasPrice,
requireBlockConfirmations,
[foreignDailyLimit, foreignMaxPerTx],
owner,
feeManager.address,
[feeInWei, feeInWei],
decimalShiftZero
).should.be.fulfilled
// When
const { logs } = await homeBridge.relayTokens(user2, {
from: user,
value
}).should.be.fulfilled
// Then
const valueCalc = 0.5 * (1 - fee)
const finalValue = ether(valueCalc.toString())
expectEventInLogs(logs, 'UserRequestForSignature', {
recipient: user2,
value: finalValue
})
})
})
describe('#feeManager_BothDirections_submitSignature', () => {
it('should distribute fee to validator', async () => {
// Initialize

View File

@ -247,7 +247,8 @@ async function testERC677BridgeToken(accounts, rewardable) {
requireBlockConfirmations,
[executionDailyLimit, executionMaxPerTx],
owner,
decimalShiftZero
decimalShiftZero,
homeErcToErcContract.address
)
})
it('sends tokens to recipient', async () => {
@ -424,7 +425,8 @@ async function testERC677BridgeToken(accounts, rewardable) {
requireBlockConfirmations,
[executionDailyLimit, executionMaxPerTx],
owner,
decimalShiftZero
decimalShiftZero,
homeErcToErcContract.address
)
})
it('calls contractFallback', async () => {