Add opposite side limits WIP
This commit is contained in:
parent
d2d6903200
commit
5bd6f5d58e
|
@ -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)) {
|
||||
|
|
|
@ -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 {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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";
|
||||
|
|
Loading…
Reference in New Issue