Add opposite side limits WIP

This commit is contained in:
Gerardo Nardelli 2018-11-23 16:37:39 -03:00
parent d2d6903200
commit 5bd6f5d58e
7 changed files with 248 additions and 56 deletions

View File

@ -57,6 +57,10 @@ contract BasicBridge is EternalStorage, Validatable {
return uintStorage[keccak256(abi.encodePacked("maxPerTx"))];
}
function oppositeSideMaxPerTx() public view returns(uint256) {
return uintStorage[keccak256(abi.encodePacked("oppositeSideMaxPerTx"))];
}
function setInitialize(bool _status) internal {
boolStorage[keccak256(abi.encodePacked("isInitialized"))] = _status;
}
@ -78,6 +82,19 @@ contract BasicBridge is EternalStorage, Validatable {
return uintStorage[keccak256(abi.encodePacked("dailyLimit"))];
}
function setOppositeSideDailyLimit(uint256 _dailyLimit) public onlyOwner {
uintStorage[keccak256(abi.encodePacked("oppositeSideDailyLimit"))] = _dailyLimit;
}
function oppositeSideDailyLimit() public view returns(uint256) {
return uintStorage[keccak256(abi.encodePacked("oppositeSideDailyLimit"))];
}
function setOppositeSideMaxPerTx(uint256 _maxPerTx) external onlyOwner {
require(_maxPerTx < oppositeSideDailyLimit());
uintStorage[keccak256(abi.encodePacked("oppositeSideDailyLimit"))] = _maxPerTx;
}
function setMaxPerTx(uint256 _maxPerTx) external onlyOwner {
require(_maxPerTx < dailyLimit());
uintStorage[keccak256(abi.encodePacked("maxPerTx"))] = _maxPerTx;
@ -93,6 +110,19 @@ contract BasicBridge is EternalStorage, Validatable {
return dailyLimit() >= nextLimit && _amount <= maxPerTx() && _amount >= minPerTx();
}
function withinOppositeSideLimit(uint256 _amount) public view returns(bool) {
uint256 nextLimit = totalSpentPerDay(getCurrentDay()).add(_amount);
return oppositeSideDailyLimit() >= nextLimit && _amount <= oppositeSideMaxPerTx();
}
function outOfLimitAmount() public view returns(uint256) {
return uintStorage[keccak256(abi.encodePacked("outOfLimitAmount"))];
}
function setOutOfLimitAmount(uint256 _value) internal {
uintStorage[keccak256(abi.encodePacked("outOfLimitAmount"))] = _value;
}
function claimTokens(address _token, address _to) public onlyOwner {
require(_to != address(0));
if (_token == address(0)) {

View File

@ -17,11 +17,15 @@ contract BasicForeignBridge is EternalStorage, Validatable {
bytes32 txHash;
address contractAddress;
(recipient, amount, txHash, contractAddress) = Message.parseMessage(message);
require(contractAddress == address(this));
require(!relayedMessages(txHash));
setRelayedMessages(txHash, true);
require(onExecuteMessage(recipient, amount));
emit RelayedMessage(recipient, amount, txHash);
if (messageWithinLimits(amount)) {
require(contractAddress == address(this));
require(!relayedMessages(txHash));
setRelayedMessages(txHash, true);
require(onExecuteMessage(recipient, amount));
emit RelayedMessage(recipient, amount, txHash);
} else {
onFailedMessage(recipient, amount, txHash);
}
}
function onExecuteMessage(address, uint256) internal returns(bool){
@ -35,4 +39,11 @@ contract BasicForeignBridge is EternalStorage, Validatable {
function relayedMessages(bytes32 _txHash) public view returns(bool) {
return boolStorage[keccak256(abi.encodePacked("relayedMessages", _txHash))];
}
function messageWithinLimits(uint256) internal returns(bool) {
return true;
}
function onFailedMessage(address, uint256, bytes32) internal {
}
}

View File

@ -16,27 +16,31 @@ contract BasicHomeBridge is EternalStorage, Validatable {
event CollectedSignatures(address authorityResponsibleForRelay, bytes32 messageHash, uint256 NumberOfCollectedSignatures);
function executeAffirmation(address recipient, uint256 value, bytes32 transactionHash) external onlyValidator {
bytes32 hashMsg = keccak256(abi.encodePacked(recipient, value, transactionHash));
bytes32 hashSender = keccak256(abi.encodePacked(msg.sender, hashMsg));
// Duplicated affirmations
require(!affirmationsSigned(hashSender));
setAffirmationsSigned(hashSender, true);
if (affirmationWithinLimits(value)) {
bytes32 hashMsg = keccak256(abi.encodePacked(recipient, value, transactionHash));
bytes32 hashSender = keccak256(abi.encodePacked(msg.sender, hashMsg));
// Duplicated affirmations
require(!affirmationsSigned(hashSender));
setAffirmationsSigned(hashSender, true);
uint256 signed = numAffirmationsSigned(hashMsg);
require(!isAlreadyProcessed(signed));
// the check above assumes that the case when the value could be overflew will not happen in the addition operation below
signed = signed + 1;
uint256 signed = numAffirmationsSigned(hashMsg);
require(!isAlreadyProcessed(signed));
// the check above assumes that the case when the value could be overflew will not happen in the addition operation below
signed = signed + 1;
setNumAffirmationsSigned(hashMsg, signed);
setNumAffirmationsSigned(hashMsg, signed);
emit SignedForAffirmation(msg.sender, transactionHash);
emit SignedForAffirmation(msg.sender, transactionHash);
if (signed >= requiredSignatures()) {
// If the bridge contract does not own enough tokens to transfer
// it will couse funds lock on the home side of the bridge
setNumAffirmationsSigned(hashMsg, markAsProcessed(signed));
require(onExecuteAffirmation(recipient, value));
emit AffirmationCompleted(recipient, value, transactionHash);
if (signed >= requiredSignatures()) {
// If the bridge contract does not own enough tokens to transfer
// it will couse funds lock on the home side of the bridge
setNumAffirmationsSigned(hashMsg, markAsProcessed(signed));
require(onExecuteAffirmation(recipient, value));
emit AffirmationCompleted(recipient, value, transactionHash);
}
} else {
onFailedAffirmation(recipient, value, transactionHash);
}
}
@ -144,4 +148,11 @@ contract BasicHomeBridge is EternalStorage, Validatable {
function requiredMessageLength() public pure returns(uint256) {
return Message.requiredMessageLength();
}
function affirmationWithinLimits(uint256) internal returns(bool) {
return true;
}
function onFailedAffirmation(address, uint256, bytes32) internal {
}
}

View File

@ -15,17 +15,24 @@ contract ForeignBridgeErcToNative is BasicBridge, BasicForeignBridge {
address _validatorContract,
address _erc20token,
uint256 _requiredBlockConfirmations,
uint256 _gasPrice
uint256 _gasPrice,
uint256 _maxPerTx,
uint256 _homeDailyLimit,
uint256 _homeMaxPerTx
) public returns(bool) {
require(!isInitialized());
require(_validatorContract != address(0) && isContract(_validatorContract));
require(_requiredBlockConfirmations != 0);
require(_gasPrice > 0);
require(_homeMaxPerTx < _homeDailyLimit);
addressStorage[keccak256(abi.encodePacked("validatorContract"))] = _validatorContract;
setErc20token(_erc20token);
uintStorage[keccak256(abi.encodePacked("deployedAtBlock"))] = block.number;
uintStorage[keccak256(abi.encodePacked("requiredBlockConfirmations"))] = _requiredBlockConfirmations;
uintStorage[keccak256(abi.encodePacked("gasPrice"))] = _gasPrice;
uintStorage[keccak256(abi.encodePacked("maxPerTx"))] = _maxPerTx;
uintStorage[keccak256(abi.encodePacked("oppositeSideDailyLimit"))] = _homeDailyLimit;
uintStorage[keccak256(abi.encodePacked("oppositeSideMaxPerTx"))] = _homeMaxPerTx;
setInitialize(true);
return isInitialized();
}
@ -44,6 +51,7 @@ contract ForeignBridgeErcToNative is BasicBridge, BasicForeignBridge {
}
function onExecuteMessage(address _recipient, uint256 _amount) internal returns(bool) {
setTotalSpentPerDay(getCurrentDay(), totalSpentPerDay(getCurrentDay()).add(_amount));
return erc20token().transfer(_recipient, _amount);
}
@ -51,4 +59,12 @@ contract ForeignBridgeErcToNative is BasicBridge, BasicForeignBridge {
require(_token != address(0) && isContract(_token));
addressStorage[keccak256(abi.encodePacked("erc20token"))] = _token;
}
function messageWithinLimits(uint256 _amount) internal returns(bool) {
return withinOppositeSideLimit(_amount);
}
function onFailedMessage(address, uint256, bytes32) internal {
revert();
}
}

View File

@ -11,6 +11,8 @@ import "../ERC677Bridge.sol";
contract HomeBridgeErcToNative is EternalStorage, BasicBridge, BasicHomeBridge {
event AmountLimitExceeded(address recipient, uint256 value, bytes32 transactionHash);
function () public payable {
require(msg.value > 0);
require(msg.data.length == 0);
@ -31,8 +33,9 @@ contract HomeBridgeErcToNative is EternalStorage, BasicBridge, BasicHomeBridge {
uint256 _minPerTx,
uint256 _homeGasPrice,
uint256 _requiredBlockConfirmations,
address _blockReward
address _blockReward,
uint256 _foreignDailyLimit,
uint256 _foreignMaxPerTx
) public returns(bool)
{
require(!isInitialized());
@ -40,6 +43,7 @@ contract HomeBridgeErcToNative is EternalStorage, BasicBridge, BasicHomeBridge {
require(_requiredBlockConfirmations > 0);
require(_minPerTx > 0 && _maxPerTx > _minPerTx && _dailyLimit > _maxPerTx);
require(_blockReward == address(0) || isContract(_blockReward));
require(_foreignMaxPerTx < _foreignDailyLimit);
addressStorage[keccak256(abi.encodePacked("validatorContract"))] = _validatorContract;
uintStorage[keccak256(abi.encodePacked("deployedAtBlock"))] = block.number;
uintStorage[keccak256(abi.encodePacked("dailyLimit"))] = _dailyLimit;
@ -48,6 +52,8 @@ contract HomeBridgeErcToNative is EternalStorage, BasicBridge, BasicHomeBridge {
uintStorage[keccak256(abi.encodePacked("gasPrice"))] = _homeGasPrice;
uintStorage[keccak256(abi.encodePacked("requiredBlockConfirmations"))] = _requiredBlockConfirmations;
addressStorage[keccak256(abi.encodePacked("blockRewardContract"))] = _blockReward;
uintStorage[keccak256(abi.encodePacked("oppositeSideDailyLimit"))] = _foreignDailyLimit;
uintStorage[keccak256(abi.encodePacked("oppositeSideMaxPerTx"))] = _foreignMaxPerTx;
setInitialize(true);
return isInitialized();
@ -84,4 +90,13 @@ contract HomeBridgeErcToNative is EternalStorage, BasicBridge, BasicHomeBridge {
function setTotalBurntCoins(uint256 _amount) internal {
uintStorage[keccak256(abi.encodePacked("totalBurntCoins"))] = _amount;
}
function affirmationWithinLimits(uint256 _amount) internal returns(bool) {
return withinOppositeSideLimit(_amount);
}
function onFailedAffirmation(address _recipient, uint256 _value, bytes32 _txHash) internal {
setOutOfLimitAmount(outOfLimitAmount().add(_value));
emit AmountLimitExceeded(_recipient, _value, _txHash);
}
}

View File

@ -9,6 +9,10 @@ const { createMessage, sign, signatureToVRS } = require('../helpers/helpers');
const halfEther = web3.toBigNumber(web3.toWei(0.5, "ether"));
const requireBlockConfirmations = 8;
const gasPrice = web3.toWei('1', 'gwei');
const oneEther = web3.toBigNumber(web3.toWei(1, "ether"));
const homeDailyLimit = oneEther
const homeMaxPerTx = halfEther
const maxPerTx = halfEther
contract('ForeignBridge_ERC20_to_Native', async (accounts) => {
let validatorContract, authorities, owner, token;
@ -30,14 +34,15 @@ contract('ForeignBridge_ERC20_to_Native', async (accounts) => {
false.should.be.equal(await foreignBridge.isInitialized())
'0'.should.be.bignumber.equal(await foreignBridge.requiredBlockConfirmations())
await foreignBridge.initialize(ZERO_ADDRESS, token.address, requireBlockConfirmations, gasPrice).should.be.rejectedWith(ERROR_MSG);
await foreignBridge.initialize(validatorContract.address, ZERO_ADDRESS, requireBlockConfirmations, gasPrice).should.be.rejectedWith(ERROR_MSG);
await foreignBridge.initialize(validatorContract.address, token.address, 0, gasPrice).should.be.rejectedWith(ERROR_MSG);
await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations, 0).should.be.rejectedWith(ERROR_MSG);
await foreignBridge.initialize(validatorContract.address, owner, requireBlockConfirmations, gasPrice).should.be.rejectedWith(ERROR_MSG);
await foreignBridge.initialize(owner, token.address, requireBlockConfirmations, gasPrice).should.be.rejectedWith(ERROR_MSG);
await foreignBridge.initialize(ZERO_ADDRESS, token.address, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx).should.be.rejectedWith(ERROR_MSG);
await foreignBridge.initialize(validatorContract.address, ZERO_ADDRESS, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx).should.be.rejectedWith(ERROR_MSG);
await foreignBridge.initialize(validatorContract.address, token.address, 0, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx).should.be.rejectedWith(ERROR_MSG);
await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations, 0, maxPerTx, homeDailyLimit, homeMaxPerTx).should.be.rejectedWith(ERROR_MSG);
await foreignBridge.initialize(validatorContract.address, owner, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx).should.be.rejectedWith(ERROR_MSG);
await foreignBridge.initialize(owner, token.address, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx).should.be.rejectedWith(ERROR_MSG);
await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations, gasPrice, maxPerTx, halfEther, homeMaxPerTx).should.be.rejectedWith(ERROR_MSG);
await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations, gasPrice);
await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx);
token.address.should.be.equal(await foreignBridge.erc20token());
true.should.be.equal(await foreignBridge.isInitialized())
@ -63,7 +68,7 @@ contract('ForeignBridge_ERC20_to_Native', async (accounts) => {
beforeEach(async () => {
foreignBridge = await ForeignBridge.new()
token = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18);
await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations, gasPrice);
await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx);
await token.mint(foreignBridge.address,value);
})
@ -143,6 +148,45 @@ contract('ForeignBridge_ERC20_to_Native', async (accounts) => {
await foreignBridge.executeSignatures([vrs2.v], [vrs2.r], [vrs2.s], message2).should.be.rejectedWith(ERROR_MSG)
})
it('should not allow withdraw over home max tx limit', async () => {
const recipientAccount = accounts[3];
const invalidValue = web3.toBigNumber(web3.toWei(0.75, "ether"));
await token.mint(foreignBridge.address, web3.toBigNumber(web3.toWei(5, "ether")));
const transactionHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121";
const message = createMessage(recipientAccount, invalidValue, transactionHash, foreignBridge.address);
const signature = await sign(authorities[0], message)
const vrs = signatureToVRS(signature);
await foreignBridge.executeSignatures([vrs.v], [vrs.r], [vrs.s], message).should.be.rejectedWith(ERROR_MSG)
})
it('should not allow withdraw over daily home limit', async () => {
const recipientAccount = accounts[3];
await token.mint(foreignBridge.address, web3.toBigNumber(web3.toWei(5, "ether")));
const transactionHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121";
const message = createMessage(recipientAccount, halfEther, transactionHash, foreignBridge.address);
const signature = await sign(authorities[0], message)
const vrs = signatureToVRS(signature);
await foreignBridge.executeSignatures([vrs.v], [vrs.r], [vrs.s], message).should.be.fulfilled
const transactionHash2 = "0x69debd8fd1923c9cb3cd8ef6461e2740b2d037943b941729d5a47671a2bb8712";
const message2 = createMessage(recipientAccount, halfEther, transactionHash2, foreignBridge.address);
const signature2 = await sign(authorities[0], message2)
const vrs2 = signatureToVRS(signature2);
await foreignBridge.executeSignatures([vrs2.v], [vrs2.r], [vrs2.s], message2).should.be.fulfilled
const transactionHash3 = "0x022695428093bb292db8e48bd1417c5e1b84c0bf673bd0fff23ed0fb6495b872";
const message3 = createMessage(recipientAccount, halfEther, transactionHash3, foreignBridge.address);
const signature3 = await sign(authorities[0], message3)
const vrs3 = signatureToVRS(signature3);
await foreignBridge.executeSignatures([vrs3.v], [vrs3.r], [vrs3.s], message3).should.be.rejectedWith(ERROR_MSG)
})
})
describe('#withdraw with 2 minimum signatures', async () => {
@ -155,7 +199,7 @@ contract('ForeignBridge_ERC20_to_Native', async (accounts) => {
ownerOfValidatorContract = accounts[3]
await multisigValidatorContract.initialize(2, twoAuthorities, ownerOfValidatorContract, {from: ownerOfValidatorContract})
foreignBridgeWithMultiSignatures = await ForeignBridge.new()
await foreignBridgeWithMultiSignatures.initialize(multisigValidatorContract.address, token.address, requireBlockConfirmations, gasPrice, {from: ownerOfValidatorContract});
await foreignBridgeWithMultiSignatures.initialize(multisigValidatorContract.address, token.address, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx, {from: ownerOfValidatorContract});
await token.mint(foreignBridgeWithMultiSignatures.address,value);
})
@ -203,7 +247,7 @@ contract('ForeignBridge_ERC20_to_Native', async (accounts) => {
const value = web3.toBigNumber(web3.toWei(0.5, "ether"));
const foreignBridgeWithThreeSigs = await ForeignBridge.new()
await foreignBridgeWithThreeSigs.initialize(validatorContractWith3Signatures.address, erc20Token.address, requireBlockConfirmations, gasPrice);
await foreignBridgeWithThreeSigs.initialize(validatorContractWith3Signatures.address, erc20Token.address, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx);
await erc20Token.mint(foreignBridgeWithThreeSigs.address, value);
const txHash = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121";
@ -252,7 +296,7 @@ contract('ForeignBridge_ERC20_to_Native', async (accounts) => {
await foreignBridgeProxy.upgradeTo('1', foreignBridgeImpl.address).should.be.fulfilled;
foreignBridgeProxy = await ForeignBridge.at(foreignBridgeProxy.address);
await foreignBridgeProxy.initialize(validatorsProxy.address, token.address, requireBlockConfirmations, gasPrice)
await foreignBridgeProxy.initialize(validatorsProxy.address, token.address, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx)
// Deploy V2
let foreignImplV2 = await ForeignBridgeV2.new();
@ -272,7 +316,7 @@ contract('ForeignBridge_ERC20_to_Native', async (accounts) => {
const storageProxy = await EternalStorageProxy.new().should.be.fulfilled;
const foreignBridge = await ForeignBridge.new();
const data = foreignBridge.initialize.request(validatorsAddress, tokenAddress, requireBlockConfirmations, gasPrice).params[0].data
const data = foreignBridge.initialize.request(validatorsAddress, tokenAddress, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx).params[0].data
await storageProxy.upgradeToAndCall('1', foreignBridge.address, data).should.be.fulfilled;
@ -288,7 +332,7 @@ contract('ForeignBridge_ERC20_to_Native', async (accounts) => {
token = await ERC677BridgeToken.new("Some ERC20", "RSZT", 18);
const foreignBridge = await ForeignBridge.new();
await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations, gasPrice);
await foreignBridge.initialize(validatorContract.address, token.address, requireBlockConfirmations, gasPrice, maxPerTx, homeDailyLimit, homeMaxPerTx);
const tokenSecond = await ERC677BridgeToken.new("Roman Token", "RST", 18);
await tokenSecond.mint(accounts[0], halfEther).should.be.fulfilled;

View File

@ -10,6 +10,9 @@ const requireBlockConfirmations = 8;
const gasPrice = Web3Utils.toWei('1', 'gwei');
const oneEther = web3.toBigNumber(web3.toWei(1, "ether"));
const halfEther = web3.toBigNumber(web3.toWei(0.5, "ether"));
const foreignDailyLimit = oneEther
const foreignMaxPerTx = halfEther
contract('HomeBridge_ERC20_to_Native', async (accounts) => {
let homeContract, validatorContract, blockRewardContract, authorities, owner;
@ -33,7 +36,7 @@ contract('HomeBridge_ERC20_to_Native', async (accounts) => {
false.should.be.equal(await homeContract.isInitialized())
ZERO_ADDRESS.should.be.equal(await homeContract.blockRewardContract())
await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address).should.be.fulfilled
await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx).should.be.fulfilled
true.should.be.equal(await homeContract.isInitialized())
validatorContract.address.should.be.equal(await homeContract.validatorContract())
@ -56,7 +59,7 @@ contract('HomeBridge_ERC20_to_Native', async (accounts) => {
it('can update block reward contract', async () => {
ZERO_ADDRESS.should.be.equal(await homeContract.blockRewardContract())
await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address).should.be.fulfilled
await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx).should.be.fulfilled
blockRewardContract.address.should.be.equal(await homeContract.blockRewardContract())
@ -79,15 +82,15 @@ contract('HomeBridge_ERC20_to_Native', async (accounts) => {
it('cant set maxPerTx > dailyLimit', async () => {
false.should.be.equal(await homeContract.isInitialized())
await homeContract.initialize(validatorContract.address, '1', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address).should.be.rejectedWith(ERROR_MSG)
await homeContract.initialize(validatorContract.address, '3', '2', '2', gasPrice, requireBlockConfirmations, blockRewardContract.address).should.be.rejectedWith(ERROR_MSG)
await homeContract.initialize(validatorContract.address, '1', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx).should.be.rejectedWith(ERROR_MSG)
await homeContract.initialize(validatorContract.address, '3', '2', '2', gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx).should.be.rejectedWith(ERROR_MSG)
false.should.be.equal(await homeContract.isInitialized())
})
it('can be deployed via upgradeToAndCall', async () => {
let storageProxy = await EternalStorageProxy.new().should.be.fulfilled;
let data = homeContract.initialize.request(validatorContract.address, "3", "2", "1", gasPrice, requireBlockConfirmations, blockRewardContract.address).params[0].data
let data = homeContract.initialize.request(validatorContract.address, "3", "2", "1", gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx).params[0].data
await storageProxy.upgradeToAndCall('1', homeContract.address, data).should.be.fulfilled
let finalContract = await HomeBridge.at(storageProxy.address);
@ -101,11 +104,12 @@ contract('HomeBridge_ERC20_to_Native', async (accounts) => {
})
it('cant initialize with invalid arguments', async () => {
false.should.be.equal(await homeContract.isInitialized())
await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, 0, blockRewardContract.address).should.be.rejectedWith(ERROR_MSG);
await homeContract.initialize(owner, '3', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address).should.be.rejectedWith(ERROR_MSG);
await homeContract.initialize(ZERO_ADDRESS, '3', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address).should.be.rejectedWith(ERROR_MSG);
await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, owner).should.be.rejectedWith(ERROR_MSG);
await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address).should.be.fulfilled;
await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, 0, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx).should.be.rejectedWith(ERROR_MSG);
await homeContract.initialize(owner, '3', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx).should.be.rejectedWith(ERROR_MSG);
await homeContract.initialize(ZERO_ADDRESS, '3', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx).should.be.rejectedWith(ERROR_MSG);
await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, owner, foreignDailyLimit, foreignMaxPerTx).should.be.rejectedWith(ERROR_MSG);
await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address, halfEther, oneEther).should.be.rejectedWith(ERROR_MSG);
await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx).should.be.fulfilled;
true.should.be.equal(await homeContract.isInitialized())
})
})
@ -113,7 +117,7 @@ contract('HomeBridge_ERC20_to_Native', async (accounts) => {
describe('#fallback', async () => {
beforeEach(async () => {
homeContract = await HomeBridge.new()
await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address)
await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx)
})
it('should accept native coins', async () => {
@ -244,7 +248,7 @@ contract('HomeBridge_ERC20_to_Native', async (accounts) => {
let homeContract;
beforeEach(async () => {
homeContract = await HomeBridge.new()
await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address)
await homeContract.initialize(validatorContract.address, '3', '2', '1', gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx)
})
it('setMaxPerTx allows to set only to owner and cannot be more than daily limit', async () => {
await homeContract.setMaxPerTx(2, {from: authorities[0]}).should.be.rejectedWith(ERROR_MSG);
@ -265,7 +269,7 @@ contract('HomeBridge_ERC20_to_Native', async (accounts) => {
let homeBridge;
beforeEach(async () => {
homeBridge = await HomeBridge.new();
await homeBridge.initialize(validatorContract.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, blockRewardContract.address);
await homeBridge.initialize(validatorContract.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx);
await blockRewardContract.sendTransaction({
from: accounts[2],
value: oneEther
@ -304,7 +308,7 @@ contract('HomeBridge_ERC20_to_Native', async (accounts) => {
const ownerOfValidators = accounts[0]
await validatorContractWith2Signatures.initialize(2, authoritiesTwoAccs, ownerOfValidators)
const homeBridgeWithTwoSigs = await HomeBridge.new();
await homeBridgeWithTwoSigs.initialize(validatorContractWith2Signatures.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, blockRewardContract.address);
await homeBridgeWithTwoSigs.initialize(validatorContractWith2Signatures.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx);
const recipient = accounts[5];
const value = halfEther;
const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415";
@ -346,7 +350,7 @@ contract('HomeBridge_ERC20_to_Native', async (accounts) => {
it('should fail if the block reward contract is not set', async () => {
homeBridge = await HomeBridge.new();
await homeBridge.initialize(validatorContract.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, ZERO_ADDRESS);
await homeBridge.initialize(validatorContract.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, ZERO_ADDRESS, foreignDailyLimit, foreignMaxPerTx);
const recipient = accounts[5];
const value = halfEther;
@ -361,7 +365,7 @@ contract('HomeBridge_ERC20_to_Native', async (accounts) => {
await validatorContractWith3Signatures.initialize(3, authoritiesFiveAccs, ownerOfValidators)
const homeBridgeWithThreeSigs = await HomeBridge.new();
await homeBridgeWithThreeSigs.initialize(validatorContractWith3Signatures.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, blockRewardContract.address);
await homeBridgeWithThreeSigs.initialize(validatorContractWith3Signatures.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx);
const value = web3.toBigNumber(web3.toWei(0.5, "ether"));
const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415";
@ -383,6 +387,67 @@ contract('HomeBridge_ERC20_to_Native', async (accounts) => {
transactionHash
})
})
it('should not allow execute affirmation over foreign max tx limit', async () => {
const recipient = accounts[5];
const value = oneEther;
const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415";
const {logs} = await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.fulfilled;
logs[0].event.should.be.equal("AmountLimitExceeded");
logs[0].args.should.be.deep.equal({
recipient,
value,
transactionHash
});
})
it('should not allow execute affirmation over daily foreign limit', async () => {
await blockRewardContract.sendTransaction({
from: accounts[2],
value: oneEther
}).should.be.fulfilled
const recipient = accounts[5];
const value = halfEther;
const transactionHash = "0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415";
const { logs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, {from: authorities[0]}).should.be.fulfilled;
logs[0].event.should.be.equal("SignedForAffirmation");
logs[0].args.should.be.deep.equal({
signer: authorities[0],
transactionHash
});
logs[1].event.should.be.equal("AffirmationCompleted");
logs[1].args.should.be.deep.equal({
recipient,
value,
transactionHash
})
const transactionHash2 = "0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121";
const { logs: logs2 } = await homeBridge.executeAffirmation(recipient, value, transactionHash2, {from: authorities[0]}).should.be.fulfilled;
logs2[0].event.should.be.equal("SignedForAffirmation");
logs2[0].args.should.be.deep.equal({
signer: authorities[0],
transactionHash: transactionHash2
});
logs2[1].event.should.be.equal("AffirmationCompleted");
logs2[1].args.should.be.deep.equal({
recipient,
value,
transactionHash: transactionHash2
})
const transactionHash3 = "0x69debd8fd1923c9cb3cd8ef6461e2740b2d037943b941729d5a47671a2bb8712";
const { logs: logs3 } = await homeBridge.executeAffirmation(recipient, value, transactionHash3, {from: authorities[0]}).should.be.fulfilled;
logs3[0].event.should.be.equal("AmountLimitExceeded");
logs3[0].args.should.be.deep.equal({
recipient,
value,
transactionHash: transactionHash3
});
})
})
describe('#submitSignature', async () => {
@ -393,7 +458,7 @@ contract('HomeBridge_ERC20_to_Native', async (accounts) => {
ownerOfValidators = accounts[0]
await validatorContractWith2Signatures.initialize(2, authoritiesTwoAccs, ownerOfValidators)
homeBridgeWithTwoSigs = await HomeBridge.new();
await homeBridgeWithTwoSigs.initialize(validatorContractWith2Signatures.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, blockRewardContract.address);
await homeBridgeWithTwoSigs.initialize(validatorContractWith2Signatures.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx);
})
it('allows a validator to submit a signature', async () => {
@ -442,7 +507,7 @@ contract('HomeBridge_ERC20_to_Native', async (accounts) => {
await validatorContractWith3Signatures.initialize(3, authoritiesFiveAccs, ownerOfValidators)
const homeBridgeWithThreeSigs = await HomeBridge.new();
await homeBridgeWithThreeSigs.initialize(validatorContractWith3Signatures.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, blockRewardContract.address);
await homeBridgeWithThreeSigs.initialize(validatorContractWith3Signatures.address, oneEther, halfEther, minPerTx, gasPrice, requireBlockConfirmations, blockRewardContract.address, foreignDailyLimit, foreignMaxPerTx);
const value = web3.toBigNumber(web3.toWei(0.5, "ether"));
const transactionHash = "0x1045bfe274b88120a6b1e5d01b5ec00ab5d01098346e90e7c7a3c9b8f0181c80";