Avoid doublespending for transfers above limits (#509)
This commit is contained in:
parent
b22383f351
commit
2b51dcf0c4
|
@ -2,42 +2,63 @@ pragma solidity 0.4.24;
|
|||
|
||||
import "../upgradeability/EternalStorage.sol";
|
||||
|
||||
/**
|
||||
* @title BaseOverdrawManagement
|
||||
* @dev This contract implements basic functionality for tracking execution bridge operations that are out of limits.
|
||||
*/
|
||||
contract BaseOverdrawManagement is EternalStorage {
|
||||
event AmountLimitExceeded(address recipient, uint256 value, bytes32 transactionHash);
|
||||
event AssetAboveLimitsFixed(bytes32 indexed transactionHash, uint256 value, uint256 remaining);
|
||||
event MediatorAmountLimitExceeded(address recipient, uint256 value, bytes32 indexed messageId);
|
||||
event AmountLimitExceeded(address recipient, uint256 value, bytes32 indexed transactionHash, bytes32 messageId);
|
||||
event AssetAboveLimitsFixed(bytes32 indexed messageId, uint256 value, uint256 remaining);
|
||||
|
||||
bytes32 internal constant OUT_OF_LIMIT_AMOUNT = 0x145286dc85799b6fb9fe322391ba2d95683077b2adf34dd576dedc437e537ba7; // keccak256(abi.encodePacked("outOfLimitAmount"))
|
||||
|
||||
/**
|
||||
* @dev Total amount coins/tokens that were bridged from the other side and are out of execution limits.
|
||||
* @return total amount of all bridge operations above limits.
|
||||
*/
|
||||
function outOfLimitAmount() public view returns (uint256) {
|
||||
return uintStorage[OUT_OF_LIMIT_AMOUNT];
|
||||
}
|
||||
|
||||
function fixedAssets(bytes32 _txHash) public view returns (bool) {
|
||||
return boolStorage[keccak256(abi.encodePacked("fixedAssets", _txHash))];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Internal function for updating a total amount that is out of execution limits.
|
||||
* @param _value new value for the total amount of bridge operations above limits.
|
||||
*/
|
||||
function setOutOfLimitAmount(uint256 _value) internal {
|
||||
uintStorage[OUT_OF_LIMIT_AMOUNT] = _value;
|
||||
}
|
||||
|
||||
function txAboveLimits(bytes32 _txHash) internal view returns (address recipient, uint256 value) {
|
||||
recipient = addressStorage[keccak256(abi.encodePacked("txOutOfLimitRecipient", _txHash))];
|
||||
value = uintStorage[keccak256(abi.encodePacked("txOutOfLimitValue", _txHash))];
|
||||
/**
|
||||
* @dev Internal function for retrieving information about out-of-limits bridge operation.
|
||||
* @param _messageId id of the message that cause above-limits error.
|
||||
* @return (address of the receiver, amount of coins/tokens in the bridge operation)
|
||||
*/
|
||||
function txAboveLimits(bytes32 _messageId) internal view returns (address recipient, uint256 value) {
|
||||
recipient = addressStorage[keccak256(abi.encodePacked("txOutOfLimitRecipient", _messageId))];
|
||||
value = uintStorage[keccak256(abi.encodePacked("txOutOfLimitValue", _messageId))];
|
||||
}
|
||||
|
||||
function setTxAboveLimits(address _recipient, uint256 _value, bytes32 _txHash) internal {
|
||||
addressStorage[keccak256(abi.encodePacked("txOutOfLimitRecipient", _txHash))] = _recipient;
|
||||
setTxAboveLimitsValue(_value, _txHash);
|
||||
/**
|
||||
* @dev Internal function for updating information about tbe out-of-limits bridge operation.
|
||||
* @param _recipient receiver specified in the bridge operation.
|
||||
* @param _value amount of coins/tokens inside the bridge operation.
|
||||
* @param _messageId id of the message that cause above-limits error.
|
||||
*/
|
||||
function setTxAboveLimits(address _recipient, uint256 _value, bytes32 _messageId) internal {
|
||||
addressStorage[keccak256(abi.encodePacked("txOutOfLimitRecipient", _messageId))] = _recipient;
|
||||
setTxAboveLimitsValue(_value, _messageId);
|
||||
}
|
||||
|
||||
function setTxAboveLimitsValue(uint256 _value, bytes32 _txHash) internal {
|
||||
uintStorage[keccak256(abi.encodePacked("txOutOfLimitValue", _txHash))] = _value;
|
||||
}
|
||||
|
||||
function setFixedAssets(bytes32 _txHash) internal {
|
||||
boolStorage[keccak256(abi.encodePacked("fixedAssets", _txHash))] = true;
|
||||
/**
|
||||
* @dev Internal function for updating information about the remaining value of out-of-limits bridge operation.
|
||||
* @param _value amount of coins/tokens inside the bridge operation.
|
||||
* @param _messageId id of the message that cause above-limits error.
|
||||
*/
|
||||
function setTxAboveLimitsValue(uint256 _value, bytes32 _messageId) internal {
|
||||
uintStorage[keccak256(abi.encodePacked("txOutOfLimitValue", _messageId))] = _value;
|
||||
}
|
||||
|
||||
/* solcov ignore next */
|
||||
function fixAssetsAboveLimits(bytes32 txHash, bool unlockOnForeign, uint256 valueToUnlock) external;
|
||||
function fixAssetsAboveLimits(bytes32 messageId, bool unlockOnForeign, uint256 valueToUnlock) external;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,10 @@ import "../libraries/Message.sol";
|
|||
import "./BasicBridge.sol";
|
||||
import "./BasicTokenBridge.sol";
|
||||
|
||||
/**
|
||||
* @title BasicHomeBridge
|
||||
* @dev This contract implements common functionality for all vanilla bridge modes on the Home side.
|
||||
*/
|
||||
contract BasicHomeBridge is EternalStorage, Validatable, BasicBridge, BasicTokenBridge {
|
||||
using SafeMath for uint256;
|
||||
|
||||
|
@ -21,9 +25,16 @@ contract BasicHomeBridge is EternalStorage, Validatable, BasicBridge, BasicToken
|
|||
uint256 NumberOfCollectedSignatures
|
||||
);
|
||||
|
||||
/**
|
||||
* @dev Executes a message affirmation for some Foreign side event.
|
||||
* Can be called only by a current bridge validator.
|
||||
* @param recipient tokens/coins of receiver address, where the assets should be unlocked/minted.
|
||||
* @param value amount of assets to unlock/mint.
|
||||
* @param transactionHash reference event transaction hash on the Foreign side of the bridge.
|
||||
*/
|
||||
function executeAffirmation(address recipient, uint256 value, bytes32 transactionHash) external onlyValidator {
|
||||
bytes32 hashMsg = keccak256(abi.encodePacked(recipient, value, transactionHash));
|
||||
if (withinExecutionLimit(value)) {
|
||||
bytes32 hashMsg = keccak256(abi.encodePacked(recipient, value, transactionHash));
|
||||
bytes32 hashSender = keccak256(abi.encodePacked(msg.sender, hashMsg));
|
||||
// Duplicated affirmations
|
||||
require(!affirmationsSigned(hashSender));
|
||||
|
@ -43,12 +54,12 @@ contract BasicHomeBridge is EternalStorage, Validatable, BasicBridge, BasicToken
|
|||
// it will couse funds lock on the home side of the bridge
|
||||
setNumAffirmationsSigned(hashMsg, markAsProcessed(signed));
|
||||
if (value > 0) {
|
||||
require(onExecuteAffirmation(recipient, value, transactionHash));
|
||||
require(onExecuteAffirmation(recipient, value, transactionHash, hashMsg));
|
||||
}
|
||||
emit AffirmationCompleted(recipient, value, transactionHash);
|
||||
}
|
||||
} else {
|
||||
onFailedAffirmation(recipient, value, transactionHash);
|
||||
onFailedAffirmation(recipient, value, transactionHash, hashMsg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,7 +103,10 @@ contract BasicHomeBridge is EternalStorage, Validatable, BasicBridge, BasicToken
|
|||
}
|
||||
|
||||
/* solcov ignore next */
|
||||
function onExecuteAffirmation(address, uint256, bytes32) internal returns (bool);
|
||||
function onExecuteAffirmation(address, uint256, bytes32, bytes32) internal returns (bool);
|
||||
|
||||
/* solcov ignore next */
|
||||
function onFailedAffirmation(address, uint256, bytes32, bytes32) internal;
|
||||
|
||||
/* solcov ignore next */
|
||||
function onSignaturesCollected(bytes) internal;
|
||||
|
@ -153,7 +167,4 @@ contract BasicHomeBridge is EternalStorage, Validatable, BasicBridge, BasicToken
|
|||
function requiredMessageLength() public pure returns (uint256) {
|
||||
return Message.requiredMessageLength();
|
||||
}
|
||||
|
||||
/* solcov ignore next */
|
||||
function onFailedAffirmation(address, uint256, bytes32) internal;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
pragma solidity 0.4.24;
|
||||
|
||||
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
|
||||
import "./Upgradeable.sol";
|
||||
import "./RewardableBridge.sol";
|
||||
import "./BasicHomeBridge.sol";
|
||||
import "./BaseOverdrawManagement.sol";
|
||||
|
||||
/**
|
||||
* @title HomeOverdrawManagement
|
||||
* @dev This contract implements functionality for recovering from out-of-limits executions in Home side vanilla bridges.
|
||||
*/
|
||||
contract HomeOverdrawManagement is BaseOverdrawManagement, RewardableBridge, Upgradeable, BasicHomeBridge {
|
||||
using SafeMath for uint256;
|
||||
|
||||
/**
|
||||
* @dev Fixes locked tokens, that were out of execution limits during the call to executeAffirmation.
|
||||
* @param hashMsg reference for bridge operation that was out of execution limits.
|
||||
* @param unlockOnForeign true if fixed tokens should be unlocked to the other side of the bridge.
|
||||
* @param valueToUnlock unlocked amount of tokens, should be less than txAboveLimitsValue.
|
||||
* Should be less than maxPerTx(), if tokens need to be unlocked on the other side.
|
||||
*/
|
||||
function fixAssetsAboveLimits(bytes32 hashMsg, bool unlockOnForeign, uint256 valueToUnlock)
|
||||
external
|
||||
onlyIfUpgradeabilityOwner
|
||||
{
|
||||
uint256 signed = numAffirmationsSigned(hashMsg);
|
||||
require(!isAlreadyProcessed(signed));
|
||||
(address recipient, uint256 value) = txAboveLimits(hashMsg);
|
||||
require(recipient != address(0) && value > 0 && value >= valueToUnlock);
|
||||
setOutOfLimitAmount(outOfLimitAmount().sub(valueToUnlock));
|
||||
uint256 pendingValue = value.sub(valueToUnlock);
|
||||
setTxAboveLimitsValue(pendingValue, hashMsg);
|
||||
emit AssetAboveLimitsFixed(hashMsg, valueToUnlock, pendingValue);
|
||||
if (unlockOnForeign) {
|
||||
require(valueToUnlock <= maxPerTx());
|
||||
address feeManager = feeManagerContract();
|
||||
uint256 eventValue = valueToUnlock;
|
||||
if (feeManager != address(0)) {
|
||||
uint256 fee = calculateFee(valueToUnlock, false, feeManager, HOME_FEE);
|
||||
eventValue = valueToUnlock.sub(fee);
|
||||
}
|
||||
emit UserRequestForSignature(recipient, eventValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Internal function for clearing above limits markers for some failed transfer.
|
||||
* Useful when transfer is being reprocessed on a new day or after limits were updated.
|
||||
* It is required that fixAssetsAboveLimits was not called on the failed transfer before prior to this function.
|
||||
* @param _hashMsg hash of the message, works as a unique indentifier.
|
||||
* @param _value transferred amount of tokens/coins in the fixed message.
|
||||
*/
|
||||
function _clearAboveLimitsMarker(bytes32 _hashMsg, uint256 _value) internal {
|
||||
(address aboveLimitsRecipient, uint256 aboveLimitsValue) = txAboveLimits(_hashMsg);
|
||||
// check if transfer was marked as out of limits
|
||||
if (aboveLimitsRecipient != address(0)) {
|
||||
// revert if a given transaction hash was already processed by the call to fixAssetsAboveLimits
|
||||
require(aboveLimitsValue == _value);
|
||||
setTxAboveLimits(address(0), 0, _hashMsg);
|
||||
setOutOfLimitAmount(outOfLimitAmount().sub(_value));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
pragma solidity 0.4.24;
|
||||
|
||||
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
|
||||
import "./Upgradeable.sol";
|
||||
import "./RewardableBridge.sol";
|
||||
import "./BasicTokenBridge.sol";
|
||||
import "./BaseOverdrawManagement.sol";
|
||||
|
||||
contract OverdrawManagement is BaseOverdrawManagement, RewardableBridge, Upgradeable, BasicTokenBridge {
|
||||
using SafeMath for uint256;
|
||||
|
||||
event UserRequestForSignature(address recipient, uint256 value);
|
||||
|
||||
function fixAssetsAboveLimits(bytes32 txHash, bool unlockOnForeign, uint256 valueToUnlock)
|
||||
external
|
||||
onlyIfUpgradeabilityOwner
|
||||
{
|
||||
require(!fixedAssets(txHash));
|
||||
require(valueToUnlock <= maxPerTx());
|
||||
address recipient;
|
||||
uint256 value;
|
||||
(recipient, value) = txAboveLimits(txHash);
|
||||
require(recipient != address(0) && value > 0 && value >= valueToUnlock);
|
||||
setOutOfLimitAmount(outOfLimitAmount().sub(valueToUnlock));
|
||||
uint256 pendingValue = value.sub(valueToUnlock);
|
||||
setTxAboveLimitsValue(pendingValue, txHash);
|
||||
emit AssetAboveLimitsFixed(txHash, valueToUnlock, pendingValue);
|
||||
if (pendingValue == 0) {
|
||||
setFixedAssets(txHash);
|
||||
}
|
||||
if (unlockOnForeign) {
|
||||
address feeManager = feeManagerContract();
|
||||
uint256 eventValue = valueToUnlock;
|
||||
if (feeManager != address(0)) {
|
||||
uint256 fee = calculateFee(valueToUnlock, false, feeManager, HOME_FEE);
|
||||
eventValue = valueToUnlock.sub(fee);
|
||||
}
|
||||
emit UserRequestForSignature(recipient, eventValue);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -116,33 +116,28 @@ contract BasicAMBErc677ToErc677 is
|
|||
require(recipient == address(0) && value == 0);
|
||||
setOutOfLimitAmount(outOfLimitAmount().add(_value));
|
||||
setTxAboveLimits(_recipient, _value, _messageId);
|
||||
emit AmountLimitExceeded(_recipient, _value, _messageId);
|
||||
emit MediatorAmountLimitExceeded(_recipient, _value, _messageId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Fixes locked tokens, that were out of execution limits during the call to handleBridgedTokens
|
||||
* @param messageId reference for bridge operation that was out of execution limits
|
||||
* @param unlockOnForeign true if fixed tokens should be unlocked to the other side of the bridge
|
||||
* @param valueToUnlock unlocked amount of tokens, should be less than maxPerTx() and saved txAboveLimitsValue
|
||||
* @param unlockOnOtherSide true if fixed tokens should be unlocked to the other side of the bridge
|
||||
* @param valueToUnlock unlocked amount of tokens, should be less than saved txAboveLimitsValue.
|
||||
* Should be less than maxPerTx(), if tokens need to be unlocked on the other side.
|
||||
*/
|
||||
function fixAssetsAboveLimits(bytes32 messageId, bool unlockOnForeign, uint256 valueToUnlock)
|
||||
function fixAssetsAboveLimits(bytes32 messageId, bool unlockOnOtherSide, uint256 valueToUnlock)
|
||||
external
|
||||
onlyIfUpgradeabilityOwner
|
||||
{
|
||||
require(!fixedAssets(messageId));
|
||||
require(valueToUnlock <= maxPerTx());
|
||||
address recipient;
|
||||
uint256 value;
|
||||
(recipient, value) = txAboveLimits(messageId);
|
||||
(address recipient, uint256 value) = txAboveLimits(messageId);
|
||||
require(recipient != address(0) && value > 0 && value >= valueToUnlock);
|
||||
setOutOfLimitAmount(outOfLimitAmount().sub(valueToUnlock));
|
||||
uint256 pendingValue = value.sub(valueToUnlock);
|
||||
setTxAboveLimitsValue(pendingValue, messageId);
|
||||
emit AssetAboveLimitsFixed(messageId, valueToUnlock, pendingValue);
|
||||
if (pendingValue == 0) {
|
||||
setFixedAssets(messageId);
|
||||
}
|
||||
if (unlockOnForeign) {
|
||||
if (unlockOnOtherSide) {
|
||||
require(valueToUnlock <= maxPerTx());
|
||||
passMessage(recipient, recipient, valueToUnlock);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,15 +4,20 @@ import "../../libraries/Message.sol";
|
|||
import "../../upgradeability/EternalStorage.sol";
|
||||
import "../../interfaces/IBurnableMintableERC677Token.sol";
|
||||
import "../BasicHomeBridge.sol";
|
||||
import "../OverdrawManagement.sol";
|
||||
import "../HomeOverdrawManagement.sol";
|
||||
import "./RewardableHomeBridgeErcToErc.sol";
|
||||
import "../ERC677BridgeForBurnableMintableToken.sol";
|
||||
|
||||
/**
|
||||
* @title HomeBridgeErcToErc
|
||||
* @dev This contract Home side logic for the erc-to-erc vanilla bridge mode.
|
||||
* It is designed to be used as an implementation contract of EternalStorageProxy contract.
|
||||
*/
|
||||
contract HomeBridgeErcToErc is
|
||||
EternalStorage,
|
||||
BasicHomeBridge,
|
||||
ERC677BridgeForBurnableMintableToken,
|
||||
OverdrawManagement,
|
||||
HomeOverdrawManagement,
|
||||
RewardableHomeBridgeErcToErc
|
||||
{
|
||||
function initialize(
|
||||
|
@ -134,13 +139,26 @@ contract HomeBridgeErcToErc is
|
|||
return 0xba4690f5; // bytes4(keccak256(abi.encodePacked("erc-to-erc-core")))
|
||||
}
|
||||
|
||||
function onExecuteAffirmation(address _recipient, uint256 _value, bytes32 txHash) internal returns (bool) {
|
||||
/**
|
||||
* @dev Internal callback to be called on successfull message execution.
|
||||
* Should be called only after enough affirmations from the validators are already collected.
|
||||
* @param _recipient address of the receiver where the new tokens should be minted.
|
||||
* @param _value amount of tokens to mint.
|
||||
* @param _txHash reference transaction hash on the Foreign side of the bridge which cause this operation.
|
||||
* @param _hashMsg unique identifier of the particular bridge operation.
|
||||
* @return true, if execution completed successfully.
|
||||
*/
|
||||
function onExecuteAffirmation(address _recipient, uint256 _value, bytes32 _txHash, bytes32 _hashMsg)
|
||||
internal
|
||||
returns (bool)
|
||||
{
|
||||
_clearAboveLimitsMarker(_hashMsg, _value);
|
||||
addTotalExecutedPerDay(getCurrentDay(), _value);
|
||||
uint256 valueToMint = _shiftValue(_value);
|
||||
address feeManager = feeManagerContract();
|
||||
if (feeManager != address(0)) {
|
||||
uint256 fee = calculateFee(valueToMint, false, feeManager, FOREIGN_FEE);
|
||||
distributeFeeFromAffirmation(fee, feeManager, txHash);
|
||||
distributeFeeFromAffirmation(fee, feeManager, _txHash);
|
||||
valueToMint = valueToMint.sub(fee);
|
||||
}
|
||||
return IBurnableMintableERC677Token(erc677token()).mint(_recipient, valueToMint);
|
||||
|
@ -169,13 +187,19 @@ contract HomeBridgeErcToErc is
|
|||
}
|
||||
}
|
||||
|
||||
function onFailedAffirmation(address _recipient, uint256 _value, bytes32 _txHash) internal {
|
||||
address recipient;
|
||||
uint256 value;
|
||||
(recipient, value) = txAboveLimits(_txHash);
|
||||
/**
|
||||
* @dev Internal callback to be called on failed message execution due to the out-of-limits error.
|
||||
* This function saves the bridge operation information for further processing.
|
||||
* @param _recipient address of the receiver where the new tokens should be minted.
|
||||
* @param _value amount of tokens to mint.
|
||||
* @param _txHash reference transaction hash on the Foreign side of the bridge which cause this operation.
|
||||
* @param _hashMsg unique identifier of the particular bridge operation.
|
||||
*/
|
||||
function onFailedAffirmation(address _recipient, uint256 _value, bytes32 _txHash, bytes32 _hashMsg) internal {
|
||||
(address recipient, uint256 value) = txAboveLimits(_hashMsg);
|
||||
require(recipient == address(0) && value == 0);
|
||||
setOutOfLimitAmount(outOfLimitAmount().add(_value));
|
||||
setTxAboveLimits(_recipient, _value, _txHash);
|
||||
emit AmountLimitExceeded(_recipient, _value, _txHash);
|
||||
setTxAboveLimits(_recipient, _value, _hashMsg);
|
||||
emit AmountLimitExceeded(_recipient, _value, _txHash, _hashMsg);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,14 +4,19 @@ import "../../libraries/Message.sol";
|
|||
import "../../upgradeability/EternalStorage.sol";
|
||||
import "../../interfaces/IBlockReward.sol";
|
||||
import "../BasicHomeBridge.sol";
|
||||
import "../OverdrawManagement.sol";
|
||||
import "../HomeOverdrawManagement.sol";
|
||||
import "./RewardableHomeBridgeErcToNative.sol";
|
||||
import "../BlockRewardBridge.sol";
|
||||
|
||||
/**
|
||||
* @title HomeBridgeErcToNative
|
||||
* @dev This contract Home side logic for the erc-to-native vanilla bridge mode.
|
||||
* It is designed to be used as an implementation contract of EternalStorageProxy contract.
|
||||
*/
|
||||
contract HomeBridgeErcToNative is
|
||||
EternalStorage,
|
||||
BasicHomeBridge,
|
||||
OverdrawManagement,
|
||||
HomeOverdrawManagement,
|
||||
RewardableHomeBridgeErcToNative,
|
||||
BlockRewardBridge
|
||||
{
|
||||
|
@ -158,7 +163,20 @@ contract HomeBridgeErcToNative is
|
|||
_setOwner(_owner);
|
||||
}
|
||||
|
||||
function onExecuteAffirmation(address _recipient, uint256 _value, bytes32 txHash) internal returns (bool) {
|
||||
/**
|
||||
* @dev Internal callback to be called on successfull message execution.
|
||||
* Should be called only after enough affirmations from the validators are already collected.
|
||||
* @param _recipient address of the receiver where the new coins should be minted.
|
||||
* @param _value amount of coins to mint.
|
||||
* @param _txHash reference transaction hash on the Foreign side of the bridge which cause this operation.
|
||||
* @param _hashMsg unique identifier of the particular bridge operation.
|
||||
* @return true, if execution completed successfully.
|
||||
*/
|
||||
function onExecuteAffirmation(address _recipient, uint256 _value, bytes32 _txHash, bytes32 _hashMsg)
|
||||
internal
|
||||
returns (bool)
|
||||
{
|
||||
_clearAboveLimitsMarker(_hashMsg, _value);
|
||||
addTotalExecutedPerDay(getCurrentDay(), _value);
|
||||
IBlockReward blockReward = blockRewardContract();
|
||||
require(blockReward != address(0));
|
||||
|
@ -166,7 +184,7 @@ contract HomeBridgeErcToNative is
|
|||
address feeManager = feeManagerContract();
|
||||
if (feeManager != address(0)) {
|
||||
uint256 fee = calculateFee(valueToMint, false, feeManager, FOREIGN_FEE);
|
||||
distributeFeeFromAffirmation(fee, feeManager, txHash);
|
||||
distributeFeeFromAffirmation(fee, feeManager, _txHash);
|
||||
valueToMint = valueToMint.sub(fee);
|
||||
}
|
||||
blockReward.addExtraReceiver(valueToMint, _recipient);
|
||||
|
@ -190,13 +208,19 @@ contract HomeBridgeErcToNative is
|
|||
uintStorage[TOTAL_BURNT_COINS] = _amount;
|
||||
}
|
||||
|
||||
function onFailedAffirmation(address _recipient, uint256 _value, bytes32 _txHash) internal {
|
||||
address recipient;
|
||||
uint256 value;
|
||||
(recipient, value) = txAboveLimits(_txHash);
|
||||
/**
|
||||
* @dev Internal callback to be called on failed message execution due to the out-of-limits error.
|
||||
* This function saves the bridge operation information for further processing.
|
||||
* @param _recipient address of the receiver where the new coins should be minted.
|
||||
* @param _value amount of coins to mint.
|
||||
* @param _txHash reference transaction hash on the Foreign side of the bridge which cause this operation.
|
||||
* @param _hashMsg unique identifier of the particular bridge operation.
|
||||
*/
|
||||
function onFailedAffirmation(address _recipient, uint256 _value, bytes32 _txHash, bytes32 _hashMsg) internal {
|
||||
(address recipient, uint256 value) = txAboveLimits(_hashMsg);
|
||||
require(recipient == address(0) && value == 0);
|
||||
setOutOfLimitAmount(outOfLimitAmount().add(_value));
|
||||
setTxAboveLimits(_recipient, _value, _txHash);
|
||||
emit AmountLimitExceeded(_recipient, _value, _txHash);
|
||||
setTxAboveLimits(_recipient, _value, _hashMsg);
|
||||
emit AmountLimitExceeded(_recipient, _value, _txHash, _hashMsg);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,11 @@ import "../BasicHomeBridge.sol";
|
|||
import "./RewardableHomeBridgeNativeToErc.sol";
|
||||
import "../../libraries/Address.sol";
|
||||
|
||||
/**
|
||||
* @title HomeBridgeNativeToErc
|
||||
* @dev This contract Home side logic for the native-to-erc vanilla bridge mode.
|
||||
* It is designed to be used as an implementation contract of EternalStorageProxy contract.
|
||||
*/
|
||||
contract HomeBridgeNativeToErc is EternalStorage, BasicHomeBridge, RewardableHomeBridgeNativeToErc {
|
||||
function() public payable {
|
||||
require(msg.data.length == 0);
|
||||
|
@ -132,14 +137,27 @@ contract HomeBridgeNativeToErc is EternalStorage, BasicHomeBridge, RewardableHom
|
|||
}
|
||||
}
|
||||
|
||||
function onExecuteAffirmation(address _recipient, uint256 _value, bytes32 txHash) internal returns (bool) {
|
||||
/**
|
||||
* @dev Internal callback to be called on successfull message execution.
|
||||
* Should be called only after enough affirmations from the validators are already collected.
|
||||
* @param _recipient address of the receiver where the new coins should be unlocked.
|
||||
* @param _value amount of coins to unlock.
|
||||
* @param _txHash reference transaction hash on the Foreign side of the bridge which cause this operation.
|
||||
* @param _hashMsg unique identifier of the particular bridge operation.
|
||||
* Not used in this bridge mode, but required for interface unification with other bridge modes.
|
||||
* @return true, if execution completed successfully.
|
||||
*/
|
||||
function onExecuteAffirmation(address _recipient, uint256 _value, bytes32 _txHash, bytes32 _hashMsg)
|
||||
internal
|
||||
returns (bool)
|
||||
{
|
||||
addTotalExecutedPerDay(getCurrentDay(), _value);
|
||||
uint256 valueToTransfer = _shiftValue(_value);
|
||||
|
||||
address feeManager = feeManagerContract();
|
||||
if (feeManager != address(0)) {
|
||||
uint256 fee = calculateFee(valueToTransfer, false, feeManager, FOREIGN_FEE);
|
||||
distributeFeeFromAffirmation(fee, feeManager, txHash);
|
||||
distributeFeeFromAffirmation(fee, feeManager, _txHash);
|
||||
valueToTransfer = valueToTransfer.sub(fee);
|
||||
}
|
||||
|
||||
|
@ -147,11 +165,16 @@ contract HomeBridgeNativeToErc is EternalStorage, BasicHomeBridge, RewardableHom
|
|||
return true;
|
||||
}
|
||||
|
||||
function onFailedAffirmation(
|
||||
address, /*_recipient*/
|
||||
uint256, /*_value*/
|
||||
bytes32 /*_txHash*/
|
||||
) internal {
|
||||
/**
|
||||
* @dev Internal callback to be called on failed message execution due to the out-of-limits error.
|
||||
* This function saves the bridge operation information for further processing.
|
||||
* @param _recipient address of the receiver where the new coins should be unlocked.
|
||||
* @param _value amount of coins to unlock.
|
||||
* @param _txHash reference transaction hash on the Foreign side of the bridge which cause this operation.
|
||||
* @param _hashMsg unique identifier of the particular bridge operation.
|
||||
*/
|
||||
function onFailedAffirmation(address _recipient, uint256 _value, bytes32 _txHash, bytes32 _hashMsg) internal {
|
||||
// solhint-disable-previous-line no-unused-vars
|
||||
revert();
|
||||
}
|
||||
|
||||
|
|
|
@ -391,21 +391,21 @@ function shouldBehaveLikeBasicAMBErc677ToErc677(otherSideMediatorContract, accou
|
|||
1000000
|
||||
).should.be.fulfilled
|
||||
|
||||
const outOfLimitEvent = await getEvents(contract, { event: 'AmountLimitExceeded' })
|
||||
const outOfLimitEvent = await getEvents(contract, { event: 'MediatorAmountLimitExceeded' })
|
||||
expect(outOfLimitEvent.length).to.be.equal(1)
|
||||
expect(outOfLimitEvent[0].returnValues.recipient).to.be.equal(user)
|
||||
expect(outOfLimitEvent[0].returnValues.value).to.be.equal(twoEthers.toString())
|
||||
expect(outOfLimitEvent[0].returnValues.transactionHash).to.be.equal(exampleMessageId)
|
||||
expect(outOfLimitEvent[0].returnValues.messageId).to.be.equal(exampleMessageId)
|
||||
})
|
||||
it('Should revert if value to unlock is bigger than max per transaction', async function() {
|
||||
await contract.fixAssetsAboveLimits(exampleMessageId, false, twoEthers).should.be.rejectedWith(ERROR_MSG)
|
||||
await contract.fixAssetsAboveLimits(exampleMessageId, true, twoEthers).should.be.rejectedWith(ERROR_MSG)
|
||||
})
|
||||
it('Should allow to partially reduce outOfLimitAmount and not emit amb event', async function() {
|
||||
const { logs } = await contract.fixAssetsAboveLimits(exampleMessageId, false, halfEther).should.be.fulfilled
|
||||
|
||||
logs.length.should.be.equal(1)
|
||||
expectEventInLogs(logs, 'AssetAboveLimitsFixed', {
|
||||
transactionHash: exampleMessageId,
|
||||
messageId: exampleMessageId,
|
||||
value: halfEther,
|
||||
remaining: ether('1.5')
|
||||
})
|
||||
|
@ -418,7 +418,7 @@ function shouldBehaveLikeBasicAMBErc677ToErc677(otherSideMediatorContract, accou
|
|||
|
||||
logsSecondTx.length.should.be.equal(1)
|
||||
expectEventInLogs(logsSecondTx, 'AssetAboveLimitsFixed', {
|
||||
transactionHash: exampleMessageId,
|
||||
messageId: exampleMessageId,
|
||||
value: halfEther,
|
||||
remaining: oneEther
|
||||
})
|
||||
|
@ -431,7 +431,7 @@ function shouldBehaveLikeBasicAMBErc677ToErc677(otherSideMediatorContract, accou
|
|||
|
||||
logs.length.should.be.equal(1)
|
||||
expectEventInLogs(logs, 'AssetAboveLimitsFixed', {
|
||||
transactionHash: exampleMessageId,
|
||||
messageId: exampleMessageId,
|
||||
value: halfEther,
|
||||
remaining: ether('1.5')
|
||||
})
|
||||
|
@ -444,7 +444,7 @@ function shouldBehaveLikeBasicAMBErc677ToErc677(otherSideMediatorContract, accou
|
|||
|
||||
logsSecondTx.length.should.be.equal(1)
|
||||
expectEventInLogs(logsSecondTx, 'AssetAboveLimitsFixed', {
|
||||
transactionHash: exampleMessageId,
|
||||
messageId: exampleMessageId,
|
||||
value: halfEther,
|
||||
remaining: oneEther
|
||||
})
|
||||
|
@ -457,7 +457,7 @@ function shouldBehaveLikeBasicAMBErc677ToErc677(otherSideMediatorContract, accou
|
|||
|
||||
logs.length.should.be.equal(1)
|
||||
expectEventInLogs(logs, 'AssetAboveLimitsFixed', {
|
||||
transactionHash: exampleMessageId,
|
||||
messageId: exampleMessageId,
|
||||
value: halfEther,
|
||||
remaining: ether('1.5')
|
||||
})
|
||||
|
@ -467,7 +467,7 @@ function shouldBehaveLikeBasicAMBErc677ToErc677(otherSideMediatorContract, accou
|
|||
|
||||
logsSecondTx.length.should.be.equal(1)
|
||||
expectEventInLogs(logsSecondTx, 'AssetAboveLimitsFixed', {
|
||||
transactionHash: exampleMessageId,
|
||||
messageId: exampleMessageId,
|
||||
value: halfEther,
|
||||
remaining: oneEther
|
||||
})
|
||||
|
@ -477,7 +477,7 @@ function shouldBehaveLikeBasicAMBErc677ToErc677(otherSideMediatorContract, accou
|
|||
|
||||
logsThirdTx.length.should.be.equal(1)
|
||||
expectEventInLogs(logsThirdTx, 'AssetAboveLimitsFixed', {
|
||||
transactionHash: exampleMessageId,
|
||||
messageId: exampleMessageId,
|
||||
value: halfEther,
|
||||
remaining: halfEther
|
||||
})
|
||||
|
@ -489,7 +489,7 @@ function shouldBehaveLikeBasicAMBErc677ToErc677(otherSideMediatorContract, accou
|
|||
|
||||
logs.length.should.be.equal(1)
|
||||
expectEventInLogs(logs, 'AssetAboveLimitsFixed', {
|
||||
transactionHash: exampleMessageId,
|
||||
messageId: exampleMessageId,
|
||||
value: oneEther,
|
||||
remaining: oneEther
|
||||
})
|
||||
|
@ -499,7 +499,7 @@ function shouldBehaveLikeBasicAMBErc677ToErc677(otherSideMediatorContract, accou
|
|||
|
||||
logsSecondTx.length.should.be.equal(1)
|
||||
expectEventInLogs(logsSecondTx, 'AssetAboveLimitsFixed', {
|
||||
transactionHash: exampleMessageId,
|
||||
messageId: exampleMessageId,
|
||||
value: oneEther,
|
||||
remaining: ZERO
|
||||
})
|
||||
|
|
|
@ -255,7 +255,7 @@ contract('ForeignAMBErc677ToErc677', async accounts => {
|
|||
expect(TokensBridgedEvent[0].returnValues.messageId).to.be.equal(exampleMessageId)
|
||||
})
|
||||
}
|
||||
it('should emit AmountLimitExceeded and not transfer tokens when out of execution limits', async () => {
|
||||
it('should emit MediatorAmountLimitExceeded and not transfer tokens when out of execution limits', async () => {
|
||||
// Given
|
||||
const currentDay = await foreignBridge.getCurrentDay()
|
||||
expect(await foreignBridge.totalExecutedPerDay(currentDay)).to.be.bignumber.equal(ZERO)
|
||||
|
@ -285,11 +285,11 @@ contract('ForeignAMBErc677ToErc677', async accounts => {
|
|||
expect(await erc677Token.balanceOf(user)).to.be.bignumber.equal(ZERO)
|
||||
|
||||
expect(await foreignBridge.outOfLimitAmount()).to.be.bignumber.equal(twoEthers)
|
||||
const outOfLimitEvent = await getEvents(foreignBridge, { event: 'AmountLimitExceeded' })
|
||||
const outOfLimitEvent = await getEvents(foreignBridge, { event: 'MediatorAmountLimitExceeded' })
|
||||
expect(outOfLimitEvent.length).to.be.equal(1)
|
||||
expect(outOfLimitEvent[0].returnValues.recipient).to.be.equal(user)
|
||||
expect(outOfLimitEvent[0].returnValues.value).to.be.equal(twoEthers.toString())
|
||||
expect(outOfLimitEvent[0].returnValues.transactionHash).to.be.equal(exampleMessageId)
|
||||
expect(outOfLimitEvent[0].returnValues.messageId).to.be.equal(exampleMessageId)
|
||||
|
||||
const TokensBridgedEvent = await getEvents(foreignBridge, { event: 'TokensBridged' })
|
||||
expect(TokensBridgedEvent.length).to.be.equal(0)
|
||||
|
|
|
@ -261,7 +261,7 @@ contract('HomeAMBErc677ToErc677', async accounts => {
|
|||
expect(TokensBridgedEvent[0].returnValues.messageId).to.be.equal(exampleMessageId)
|
||||
})
|
||||
}
|
||||
it('should emit AmountLimitExceeded and not mint tokens when out of execution limits', async () => {
|
||||
it('should emit MediatorAmountLimitExceeded and not mint tokens when out of execution limits', async () => {
|
||||
// Given
|
||||
const currentDay = await homeBridge.getCurrentDay()
|
||||
expect(await homeBridge.totalExecutedPerDay(currentDay)).to.be.bignumber.equal(ZERO)
|
||||
|
@ -292,11 +292,11 @@ contract('HomeAMBErc677ToErc677', async accounts => {
|
|||
expect(await erc677Token.balanceOf(user)).to.be.bignumber.equal(ZERO)
|
||||
|
||||
expect(await homeBridge.outOfLimitAmount()).to.be.bignumber.equal(twoEthers)
|
||||
const outOfLimitEvent = await getEvents(homeBridge, { event: 'AmountLimitExceeded' })
|
||||
const outOfLimitEvent = await getEvents(homeBridge, { event: 'MediatorAmountLimitExceeded' })
|
||||
expect(outOfLimitEvent.length).to.be.equal(1)
|
||||
expect(outOfLimitEvent[0].returnValues.recipient).to.be.equal(user)
|
||||
expect(outOfLimitEvent[0].returnValues.value).to.be.equal(twoEthers.toString())
|
||||
expect(outOfLimitEvent[0].returnValues.transactionHash).to.be.equal(exampleMessageId)
|
||||
expect(outOfLimitEvent[0].returnValues.messageId).to.be.equal(exampleMessageId)
|
||||
|
||||
const TokensBridgedEvent = await getEvents(homeBridge, { event: 'TokensBridged' })
|
||||
expect(TokensBridgedEvent.length).to.be.equal(0)
|
||||
|
|
|
@ -600,12 +600,13 @@ contract('HomeBridge_ERC20_to_ERC20', async accounts => {
|
|||
transactionHash
|
||||
})
|
||||
|
||||
// should fail for the same message
|
||||
await homeBridge
|
||||
.executeAffirmation(recipient, value, transactionHash, { from: authorities[0] })
|
||||
.should.be.rejectedWith(ERROR_MSG)
|
||||
await homeBridge
|
||||
.executeAffirmation(accounts[6], value, transactionHash, { from: authorities[0] })
|
||||
.should.be.rejectedWith(ERROR_MSG)
|
||||
// should succeed for different transfer in the same message
|
||||
await homeBridge.executeAffirmation(accounts[6], value, transactionHash, { from: authorities[0] }).should.be
|
||||
.fulfilled
|
||||
})
|
||||
it('should not allow execute affirmation over daily foreign limit', async () => {
|
||||
const recipient = accounts[5]
|
||||
|
@ -869,6 +870,7 @@ contract('HomeBridge_ERC20_to_ERC20', async accounts => {
|
|||
const storageProxy = await EternalStorageProxy.new().should.be.fulfilled
|
||||
await storageProxy.upgradeTo('1', homeBridgeImpl.address).should.be.fulfilled
|
||||
homeBridge = await HomeBridge.at(storageProxy.address)
|
||||
token = await ERC677BridgeToken.new('TEST', 'TST', 18)
|
||||
await homeBridge.initialize(
|
||||
validatorContract.address,
|
||||
[oneEther, halfEther, minPerTx],
|
||||
|
@ -879,6 +881,7 @@ contract('HomeBridge_ERC20_to_ERC20', async accounts => {
|
|||
owner,
|
||||
decimalShiftZero
|
||||
).should.be.fulfilled
|
||||
await token.transferOwnership(homeBridge.address).should.be.fulfilled
|
||||
})
|
||||
it('Should revert if value to unlock is bigger than max per transaction', async () => {
|
||||
const recipient = accounts[5]
|
||||
|
@ -889,11 +892,13 @@ contract('HomeBridge_ERC20_to_ERC20', async accounts => {
|
|||
}).should.be.fulfilled
|
||||
|
||||
affirmationLogs[0].event.should.be.equal('AmountLimitExceeded')
|
||||
const messageId = affirmationLogs[0].args.messageId
|
||||
|
||||
const outOfLimitAmount = await homeBridge.outOfLimitAmount()
|
||||
outOfLimitAmount.should.be.bignumber.equal(value)
|
||||
|
||||
await homeBridge.fixAssetsAboveLimits(transactionHash, false, value).should.be.rejectedWith(ERROR_MSG)
|
||||
await homeBridge.fixAssetsAboveLimits(messageId, true, value).should.be.rejectedWith(ERROR_MSG)
|
||||
await homeBridge.fixAssetsAboveLimits(messageId, false, value).should.be.fulfilled
|
||||
})
|
||||
it('Should allow to partially reduce outOfLimitAmount and not emit UserRequestForSignature', async () => {
|
||||
const recipient = accounts[5]
|
||||
|
@ -904,26 +909,27 @@ contract('HomeBridge_ERC20_to_ERC20', async accounts => {
|
|||
}).should.be.fulfilled
|
||||
|
||||
affirmationLogs[0].event.should.be.equal('AmountLimitExceeded')
|
||||
const messageId = affirmationLogs[0].args.messageId
|
||||
|
||||
const outOfLimitAmount = await homeBridge.outOfLimitAmount()
|
||||
outOfLimitAmount.should.be.bignumber.equal(value)
|
||||
|
||||
const { logs } = await homeBridge.fixAssetsAboveLimits(transactionHash, false, halfEther).should.be.fulfilled
|
||||
const { logs } = await homeBridge.fixAssetsAboveLimits(messageId, false, halfEther).should.be.fulfilled
|
||||
|
||||
logs.length.should.be.equal(1)
|
||||
expectEventInLogs(logs, 'AssetAboveLimitsFixed', {
|
||||
transactionHash,
|
||||
messageId,
|
||||
value: halfEther,
|
||||
remaining: halfEther
|
||||
})
|
||||
expect(await homeBridge.outOfLimitAmount()).to.be.bignumber.equal(halfEther)
|
||||
|
||||
const { logs: logsSecondTx } = await homeBridge.fixAssetsAboveLimits(transactionHash, false, halfEther).should.be
|
||||
const { logs: logsSecondTx } = await homeBridge.fixAssetsAboveLimits(messageId, false, halfEther).should.be
|
||||
.fulfilled
|
||||
|
||||
logsSecondTx.length.should.be.equal(1)
|
||||
expectEventInLogs(logsSecondTx, 'AssetAboveLimitsFixed', {
|
||||
transactionHash,
|
||||
messageId,
|
||||
value: halfEther,
|
||||
remaining: ZERO
|
||||
})
|
||||
|
@ -938,15 +944,16 @@ contract('HomeBridge_ERC20_to_ERC20', async accounts => {
|
|||
}).should.be.fulfilled
|
||||
|
||||
affirmationLogs[0].event.should.be.equal('AmountLimitExceeded')
|
||||
const messageId = affirmationLogs[0].args.messageId
|
||||
|
||||
const outOfLimitAmount = await homeBridge.outOfLimitAmount()
|
||||
outOfLimitAmount.should.be.bignumber.equal(value)
|
||||
|
||||
const { logs } = await homeBridge.fixAssetsAboveLimits(transactionHash, true, halfEther).should.be.fulfilled
|
||||
const { logs } = await homeBridge.fixAssetsAboveLimits(messageId, true, halfEther).should.be.fulfilled
|
||||
|
||||
logs.length.should.be.equal(2)
|
||||
expectEventInLogs(logs, 'AssetAboveLimitsFixed', {
|
||||
transactionHash,
|
||||
messageId,
|
||||
value: halfEther,
|
||||
remaining: halfEther
|
||||
})
|
||||
|
@ -957,12 +964,12 @@ contract('HomeBridge_ERC20_to_ERC20', async accounts => {
|
|||
|
||||
expect(await homeBridge.outOfLimitAmount()).to.be.bignumber.equal(halfEther)
|
||||
|
||||
const { logs: logsSecondTx } = await homeBridge.fixAssetsAboveLimits(transactionHash, true, halfEther).should.be
|
||||
const { logs: logsSecondTx } = await homeBridge.fixAssetsAboveLimits(messageId, true, halfEther).should.be
|
||||
.fulfilled
|
||||
|
||||
logsSecondTx.length.should.be.equal(2)
|
||||
expectEventInLogs(logsSecondTx, 'AssetAboveLimitsFixed', {
|
||||
transactionHash,
|
||||
messageId,
|
||||
value: halfEther,
|
||||
remaining: ZERO
|
||||
})
|
||||
|
@ -982,15 +989,16 @@ contract('HomeBridge_ERC20_to_ERC20', async accounts => {
|
|||
}).should.be.fulfilled
|
||||
|
||||
affirmationLogs[0].event.should.be.equal('AmountLimitExceeded')
|
||||
const messageId = affirmationLogs[0].args.messageId
|
||||
|
||||
const outOfLimitAmount = await homeBridge.outOfLimitAmount()
|
||||
outOfLimitAmount.should.be.bignumber.equal(value)
|
||||
|
||||
const { logs } = await homeBridge.fixAssetsAboveLimits(transactionHash, true, halfEther).should.be.fulfilled
|
||||
const { logs } = await homeBridge.fixAssetsAboveLimits(messageId, true, halfEther).should.be.fulfilled
|
||||
|
||||
logs.length.should.be.equal(2)
|
||||
expectEventInLogs(logs, 'AssetAboveLimitsFixed', {
|
||||
transactionHash,
|
||||
messageId,
|
||||
value: halfEther,
|
||||
remaining: halfEther
|
||||
})
|
||||
|
@ -1001,12 +1009,12 @@ contract('HomeBridge_ERC20_to_ERC20', async accounts => {
|
|||
|
||||
expect(await homeBridge.outOfLimitAmount()).to.be.bignumber.equal(halfEther)
|
||||
|
||||
const { logs: logsSecondTx } = await homeBridge.fixAssetsAboveLimits(transactionHash, true, quarterEther).should
|
||||
.be.fulfilled
|
||||
const { logs: logsSecondTx } = await homeBridge.fixAssetsAboveLimits(messageId, true, quarterEther).should.be
|
||||
.fulfilled
|
||||
|
||||
logsSecondTx.length.should.be.equal(2)
|
||||
expectEventInLogs(logsSecondTx, 'AssetAboveLimitsFixed', {
|
||||
transactionHash,
|
||||
messageId,
|
||||
value: quarterEther,
|
||||
remaining: quarterEther
|
||||
})
|
||||
|
@ -1017,11 +1025,11 @@ contract('HomeBridge_ERC20_to_ERC20', async accounts => {
|
|||
|
||||
expect(await homeBridge.outOfLimitAmount()).to.be.bignumber.equal(quarterEther)
|
||||
|
||||
await homeBridge.fixAssetsAboveLimits(transactionHash, true, halfEther).should.be.rejectedWith(ERROR_MSG)
|
||||
const { logs: logsThirdTx } = await homeBridge.fixAssetsAboveLimits(transactionHash, true, quarterEther).should.be
|
||||
await homeBridge.fixAssetsAboveLimits(messageId, true, halfEther).should.be.rejectedWith(ERROR_MSG)
|
||||
const { logs: logsThirdTx } = await homeBridge.fixAssetsAboveLimits(messageId, true, quarterEther).should.be
|
||||
.fulfilled
|
||||
expectEventInLogs(logsThirdTx, 'AssetAboveLimitsFixed', {
|
||||
transactionHash,
|
||||
messageId,
|
||||
value: quarterEther,
|
||||
remaining: ZERO
|
||||
})
|
||||
|
@ -1038,36 +1046,39 @@ contract('HomeBridge_ERC20_to_ERC20', async accounts => {
|
|||
const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415'
|
||||
const transactionHash2 = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121'
|
||||
|
||||
await homeBridge.executeAffirmation(recipient, value, transactionHash, {
|
||||
const { logs: logs1 } = await homeBridge.executeAffirmation(recipient, value, transactionHash, {
|
||||
from: authorities[0]
|
||||
}).should.be.fulfilled
|
||||
await homeBridge.executeAffirmation(recipient, value, transactionHash2, {
|
||||
const { logs: logs2 } = await homeBridge.executeAffirmation(recipient, value, transactionHash2, {
|
||||
from: authorities[0]
|
||||
}).should.be.fulfilled
|
||||
|
||||
const messageId1 = logs1[0].args.messageId
|
||||
const messageId2 = logs2[0].args.messageId
|
||||
|
||||
const outOfLimitAmount = await homeBridge.outOfLimitAmount()
|
||||
outOfLimitAmount.should.be.bignumber.equal(value.add(value))
|
||||
|
||||
await homeBridge.fixAssetsAboveLimits(transactionHash, false, halfEther).should.be.fulfilled
|
||||
await homeBridge.fixAssetsAboveLimits(transactionHash, false, halfEther).should.be.fulfilled
|
||||
await homeBridge.fixAssetsAboveLimits(messageId1, false, halfEther).should.be.fulfilled
|
||||
await homeBridge.fixAssetsAboveLimits(messageId1, false, halfEther).should.be.fulfilled
|
||||
|
||||
const newOutOfLimitAmount = await homeBridge.outOfLimitAmount()
|
||||
newOutOfLimitAmount.should.be.bignumber.equal(value)
|
||||
|
||||
await homeBridge.fixAssetsAboveLimits(transactionHash, false, halfEther).should.be.rejectedWith(ERROR_MSG)
|
||||
await homeBridge.fixAssetsAboveLimits(messageId1, false, halfEther).should.be.rejectedWith(ERROR_MSG)
|
||||
|
||||
await homeBridge.fixAssetsAboveLimits(transactionHash2, false, halfEther).should.be.fulfilled
|
||||
await homeBridge.fixAssetsAboveLimits(transactionHash2, false, halfEther).should.be.fulfilled
|
||||
await homeBridge.fixAssetsAboveLimits(messageId2, false, halfEther).should.be.fulfilled
|
||||
await homeBridge.fixAssetsAboveLimits(messageId2, false, halfEther).should.be.fulfilled
|
||||
|
||||
expect(await homeBridge.outOfLimitAmount()).to.be.bignumber.equal(ZERO)
|
||||
|
||||
await homeBridge.fixAssetsAboveLimits(transactionHash2, false, halfEther).should.be.rejectedWith(ERROR_MSG)
|
||||
await homeBridge.fixAssetsAboveLimits(messageId2, false, halfEther).should.be.rejectedWith(ERROR_MSG)
|
||||
})
|
||||
it('Should fail if txHash didnt increase out of limit amount', async () => {
|
||||
const recipient = accounts[5]
|
||||
const value = oneEther
|
||||
const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415'
|
||||
const invalidTxHash = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121'
|
||||
const invalidMessageId = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121'
|
||||
|
||||
const { logs: affirmationLogs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, {
|
||||
from: authorities[0]
|
||||
|
@ -1075,7 +1086,7 @@ contract('HomeBridge_ERC20_to_ERC20', async accounts => {
|
|||
|
||||
affirmationLogs[0].event.should.be.equal('AmountLimitExceeded')
|
||||
|
||||
await homeBridge.fixAssetsAboveLimits(invalidTxHash, true, halfEther).should.be.rejectedWith(ERROR_MSG)
|
||||
await homeBridge.fixAssetsAboveLimits(invalidMessageId, true, halfEther).should.be.rejectedWith(ERROR_MSG)
|
||||
})
|
||||
it('Should fail if not called by proxyOwner', async () => {
|
||||
const recipient = accounts[5]
|
||||
|
@ -1087,11 +1098,12 @@ contract('HomeBridge_ERC20_to_ERC20', async accounts => {
|
|||
}).should.be.fulfilled
|
||||
|
||||
affirmationLogs[0].event.should.be.equal('AmountLimitExceeded')
|
||||
const messageId = affirmationLogs[0].args.messageId
|
||||
|
||||
await homeBridge
|
||||
.fixAssetsAboveLimits(transactionHash, true, halfEther, { from: recipient })
|
||||
.fixAssetsAboveLimits(messageId, true, halfEther, { from: recipient })
|
||||
.should.be.rejectedWith(ERROR_MSG)
|
||||
await homeBridge.fixAssetsAboveLimits(transactionHash, true, halfEther, { from: owner }).should.be.fulfilled
|
||||
await homeBridge.fixAssetsAboveLimits(messageId, true, halfEther, { from: owner }).should.be.fulfilled
|
||||
})
|
||||
it('Should emit UserRequestForSignature with value reduced by fee', async () => {
|
||||
const recipient = accounts[5]
|
||||
|
@ -1115,15 +1127,16 @@ contract('HomeBridge_ERC20_to_ERC20', async accounts => {
|
|||
value,
|
||||
transactionHash
|
||||
})
|
||||
const messageId = affirmationLogs[0].args.messageId
|
||||
|
||||
const outOfLimitAmount = await homeBridge.outOfLimitAmount()
|
||||
outOfLimitAmount.should.be.bignumber.equal(value)
|
||||
|
||||
const { logs } = await homeBridge.fixAssetsAboveLimits(transactionHash, true, halfEther).should.be.fulfilled
|
||||
const { logs } = await homeBridge.fixAssetsAboveLimits(messageId, true, halfEther).should.be.fulfilled
|
||||
|
||||
logs.length.should.be.equal(2)
|
||||
expectEventInLogs(logs, 'AssetAboveLimitsFixed', {
|
||||
transactionHash,
|
||||
messageId,
|
||||
value: halfEther,
|
||||
remaining: halfEther
|
||||
})
|
||||
|
@ -1132,6 +1145,61 @@ contract('HomeBridge_ERC20_to_ERC20', async accounts => {
|
|||
value: finalValue
|
||||
})
|
||||
})
|
||||
|
||||
it('should not allow to fix assets after they were already processed', async () => {
|
||||
const recipient = accounts[5]
|
||||
const value = oneEther
|
||||
const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415'
|
||||
const { logs: affirmationLogs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, {
|
||||
from: authorities[0]
|
||||
}).should.be.fulfilled
|
||||
|
||||
affirmationLogs[0].event.should.be.equal('AmountLimitExceeded')
|
||||
const messageId = affirmationLogs[0].args.messageId
|
||||
|
||||
await homeBridge.setExecutionDailyLimit(ether('2'), { from: owner }).should.be.fulfilled
|
||||
await homeBridge.setExecutionMaxPerTx(value, { from: owner }).should.be.fulfilled
|
||||
await homeBridge.setDailyLimit(ether('2'), { from: owner }).should.be.fulfilled
|
||||
await homeBridge.setMaxPerTx(value, { from: owner }).should.be.fulfilled
|
||||
|
||||
await homeBridge.executeAffirmation(recipient, value, transactionHash, { from: authorities[0] }).should.be
|
||||
.fulfilled
|
||||
|
||||
const outOfLimitAmount = await homeBridge.outOfLimitAmount()
|
||||
outOfLimitAmount.should.be.bignumber.equal(ZERO)
|
||||
|
||||
await homeBridge.fixAssetsAboveLimits(messageId, false, value).should.be.rejectedWith(ERROR_MSG)
|
||||
})
|
||||
|
||||
it('should not allow to executeAffirmation after assets were fixed', async () => {
|
||||
const recipient = accounts[5]
|
||||
const value = oneEther
|
||||
const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415'
|
||||
const { logs: affirmationLogs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, {
|
||||
from: authorities[0]
|
||||
}).should.be.fulfilled
|
||||
|
||||
affirmationLogs[0].event.should.be.equal('AmountLimitExceeded')
|
||||
const messageId = affirmationLogs[0].args.messageId
|
||||
|
||||
const outOfLimitAmount = await homeBridge.outOfLimitAmount()
|
||||
outOfLimitAmount.should.be.bignumber.equal(value)
|
||||
|
||||
await homeBridge.fixAssetsAboveLimits(messageId, false, halfEther).should.be.fulfilled
|
||||
|
||||
await homeBridge.setExecutionDailyLimit(ether('2'), { from: owner }).should.be.fulfilled
|
||||
await homeBridge.setExecutionMaxPerTx(value, { from: owner }).should.be.fulfilled
|
||||
await homeBridge.setDailyLimit(ether('2'), { from: owner }).should.be.fulfilled
|
||||
await homeBridge.setMaxPerTx(value, { from: owner }).should.be.fulfilled
|
||||
|
||||
await homeBridge.executeAffirmation(recipient, value, transactionHash, { from: authorities[0] }).should.be
|
||||
.rejected
|
||||
|
||||
await homeBridge.fixAssetsAboveLimits(messageId, false, halfEther).should.be.fulfilled
|
||||
|
||||
await homeBridge.executeAffirmation(recipient, value, transactionHash, { from: authorities[0] }).should.be
|
||||
.rejected
|
||||
})
|
||||
})
|
||||
describe('#claimTokens', () => {
|
||||
it('should be able to call claimTokens on tokenAddress', async () => {
|
||||
|
|
|
@ -1135,12 +1135,13 @@ contract('HomeBridge_ERC20_to_Native', async accounts => {
|
|||
transactionHash
|
||||
})
|
||||
|
||||
// should fail for the same message
|
||||
await homeBridge
|
||||
.executeAffirmation(recipient, value, transactionHash, { from: authorities[0] })
|
||||
.should.be.rejectedWith(ERROR_MSG)
|
||||
await homeBridge
|
||||
.executeAffirmation(accounts[6], value, transactionHash, { from: authorities[0] })
|
||||
.should.be.rejectedWith(ERROR_MSG)
|
||||
// should succeed for different transfer in the same message
|
||||
await homeBridge.executeAffirmation(accounts[6], value, transactionHash, { from: authorities[0] }).should.be
|
||||
.fulfilled
|
||||
})
|
||||
it('should not allow execute affirmation over daily foreign limit', async () => {
|
||||
await blockRewardContract.sendTransaction({
|
||||
|
@ -1414,11 +1415,13 @@ contract('HomeBridge_ERC20_to_Native', async accounts => {
|
|||
}).should.be.fulfilled
|
||||
|
||||
affirmationLogs[0].event.should.be.equal('AmountLimitExceeded')
|
||||
const messageId = affirmationLogs[0].args.messageId
|
||||
|
||||
const outOfLimitAmount = await homeBridge.outOfLimitAmount()
|
||||
outOfLimitAmount.should.be.bignumber.equal(value)
|
||||
|
||||
await homeBridge.fixAssetsAboveLimits(transactionHash, false, value).should.be.rejectedWith(ERROR_MSG)
|
||||
await homeBridge.fixAssetsAboveLimits(messageId, true, value).should.be.rejectedWith(ERROR_MSG)
|
||||
await homeBridge.fixAssetsAboveLimits(messageId, false, value).should.be.fulfilled
|
||||
})
|
||||
it('Should allow to partially reduce outOfLimitAmount and not emit UserRequestForSignature', async () => {
|
||||
const recipient = accounts[5]
|
||||
|
@ -1429,26 +1432,27 @@ contract('HomeBridge_ERC20_to_Native', async accounts => {
|
|||
}).should.be.fulfilled
|
||||
|
||||
affirmationLogs[0].event.should.be.equal('AmountLimitExceeded')
|
||||
const messageId = affirmationLogs[0].args.messageId
|
||||
|
||||
const outOfLimitAmount = await homeBridge.outOfLimitAmount()
|
||||
outOfLimitAmount.should.be.bignumber.equal(value)
|
||||
|
||||
const { logs } = await homeBridge.fixAssetsAboveLimits(transactionHash, false, halfEther).should.be.fulfilled
|
||||
const { logs } = await homeBridge.fixAssetsAboveLimits(messageId, false, halfEther).should.be.fulfilled
|
||||
|
||||
logs.length.should.be.equal(1)
|
||||
expectEventInLogs(logs, 'AssetAboveLimitsFixed', {
|
||||
transactionHash,
|
||||
messageId,
|
||||
value: halfEther,
|
||||
remaining: halfEther
|
||||
})
|
||||
expect(await homeBridge.outOfLimitAmount()).to.be.bignumber.equal(halfEther)
|
||||
|
||||
const { logs: logsSecondTx } = await homeBridge.fixAssetsAboveLimits(transactionHash, false, halfEther).should.be
|
||||
const { logs: logsSecondTx } = await homeBridge.fixAssetsAboveLimits(messageId, false, halfEther).should.be
|
||||
.fulfilled
|
||||
|
||||
logsSecondTx.length.should.be.equal(1)
|
||||
expectEventInLogs(logsSecondTx, 'AssetAboveLimitsFixed', {
|
||||
transactionHash,
|
||||
messageId,
|
||||
value: halfEther,
|
||||
remaining: ZERO
|
||||
})
|
||||
|
@ -1463,15 +1467,16 @@ contract('HomeBridge_ERC20_to_Native', async accounts => {
|
|||
}).should.be.fulfilled
|
||||
|
||||
affirmationLogs[0].event.should.be.equal('AmountLimitExceeded')
|
||||
const messageId = affirmationLogs[0].args.messageId
|
||||
|
||||
const outOfLimitAmount = await homeBridge.outOfLimitAmount()
|
||||
outOfLimitAmount.should.be.bignumber.equal(value)
|
||||
|
||||
const { logs } = await homeBridge.fixAssetsAboveLimits(transactionHash, true, halfEther).should.be.fulfilled
|
||||
const { logs } = await homeBridge.fixAssetsAboveLimits(messageId, true, halfEther).should.be.fulfilled
|
||||
|
||||
logs.length.should.be.equal(2)
|
||||
expectEventInLogs(logs, 'AssetAboveLimitsFixed', {
|
||||
transactionHash,
|
||||
messageId,
|
||||
value: halfEther,
|
||||
remaining: halfEther
|
||||
})
|
||||
|
@ -1482,12 +1487,12 @@ contract('HomeBridge_ERC20_to_Native', async accounts => {
|
|||
|
||||
expect(await homeBridge.outOfLimitAmount()).to.be.bignumber.equal(halfEther)
|
||||
|
||||
const { logs: logsSecondTx } = await homeBridge.fixAssetsAboveLimits(transactionHash, true, halfEther).should.be
|
||||
const { logs: logsSecondTx } = await homeBridge.fixAssetsAboveLimits(messageId, true, halfEther).should.be
|
||||
.fulfilled
|
||||
|
||||
logsSecondTx.length.should.be.equal(2)
|
||||
expectEventInLogs(logsSecondTx, 'AssetAboveLimitsFixed', {
|
||||
transactionHash,
|
||||
messageId,
|
||||
value: halfEther,
|
||||
remaining: ZERO
|
||||
})
|
||||
|
@ -1507,15 +1512,16 @@ contract('HomeBridge_ERC20_to_Native', async accounts => {
|
|||
}).should.be.fulfilled
|
||||
|
||||
affirmationLogs[0].event.should.be.equal('AmountLimitExceeded')
|
||||
const messageId = affirmationLogs[0].args.messageId
|
||||
|
||||
const outOfLimitAmount = await homeBridge.outOfLimitAmount()
|
||||
outOfLimitAmount.should.be.bignumber.equal(value)
|
||||
|
||||
const { logs } = await homeBridge.fixAssetsAboveLimits(transactionHash, true, halfEther).should.be.fulfilled
|
||||
const { logs } = await homeBridge.fixAssetsAboveLimits(messageId, true, halfEther).should.be.fulfilled
|
||||
|
||||
logs.length.should.be.equal(2)
|
||||
expectEventInLogs(logs, 'AssetAboveLimitsFixed', {
|
||||
transactionHash,
|
||||
messageId,
|
||||
value: halfEther,
|
||||
remaining: halfEther
|
||||
})
|
||||
|
@ -1526,12 +1532,12 @@ contract('HomeBridge_ERC20_to_Native', async accounts => {
|
|||
|
||||
expect(await homeBridge.outOfLimitAmount()).to.be.bignumber.equal(halfEther)
|
||||
|
||||
const { logs: logsSecondTx } = await homeBridge.fixAssetsAboveLimits(transactionHash, true, quarterEther).should
|
||||
.be.fulfilled
|
||||
const { logs: logsSecondTx } = await homeBridge.fixAssetsAboveLimits(messageId, true, quarterEther).should.be
|
||||
.fulfilled
|
||||
|
||||
logsSecondTx.length.should.be.equal(2)
|
||||
expectEventInLogs(logsSecondTx, 'AssetAboveLimitsFixed', {
|
||||
transactionHash,
|
||||
messageId,
|
||||
value: quarterEther,
|
||||
remaining: quarterEther
|
||||
})
|
||||
|
@ -1542,11 +1548,11 @@ contract('HomeBridge_ERC20_to_Native', async accounts => {
|
|||
|
||||
expect(await homeBridge.outOfLimitAmount()).to.be.bignumber.equal(quarterEther)
|
||||
|
||||
await homeBridge.fixAssetsAboveLimits(transactionHash, true, halfEther).should.be.rejectedWith(ERROR_MSG)
|
||||
const { logs: logsThirdTx } = await homeBridge.fixAssetsAboveLimits(transactionHash, true, quarterEther).should.be
|
||||
await homeBridge.fixAssetsAboveLimits(messageId, true, halfEther).should.be.rejectedWith(ERROR_MSG)
|
||||
const { logs: logsThirdTx } = await homeBridge.fixAssetsAboveLimits(messageId, true, quarterEther).should.be
|
||||
.fulfilled
|
||||
expectEventInLogs(logsThirdTx, 'AssetAboveLimitsFixed', {
|
||||
transactionHash,
|
||||
messageId,
|
||||
value: quarterEther,
|
||||
remaining: ZERO
|
||||
})
|
||||
|
@ -1563,36 +1569,38 @@ contract('HomeBridge_ERC20_to_Native', async accounts => {
|
|||
const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415'
|
||||
const transactionHash2 = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121'
|
||||
|
||||
await homeBridge.executeAffirmation(recipient, value, transactionHash, {
|
||||
const { logs: logs1 } = await homeBridge.executeAffirmation(recipient, value, transactionHash, {
|
||||
from: authorities[0]
|
||||
}).should.be.fulfilled
|
||||
await homeBridge.executeAffirmation(recipient, value, transactionHash2, {
|
||||
const { logs: logs2 } = await homeBridge.executeAffirmation(recipient, value, transactionHash2, {
|
||||
from: authorities[0]
|
||||
}).should.be.fulfilled
|
||||
|
||||
const messageId1 = logs1[0].args.messageId
|
||||
const messageId2 = logs2[0].args.messageId
|
||||
const outOfLimitAmount = await homeBridge.outOfLimitAmount()
|
||||
outOfLimitAmount.should.be.bignumber.equal(value.add(value))
|
||||
|
||||
await homeBridge.fixAssetsAboveLimits(transactionHash, false, halfEther).should.be.fulfilled
|
||||
await homeBridge.fixAssetsAboveLimits(transactionHash, false, halfEther).should.be.fulfilled
|
||||
await homeBridge.fixAssetsAboveLimits(messageId1, false, halfEther).should.be.fulfilled
|
||||
await homeBridge.fixAssetsAboveLimits(messageId1, false, halfEther).should.be.fulfilled
|
||||
|
||||
const newOutOfLimitAmount = await homeBridge.outOfLimitAmount()
|
||||
newOutOfLimitAmount.should.be.bignumber.equal(value)
|
||||
|
||||
await homeBridge.fixAssetsAboveLimits(transactionHash, false, halfEther).should.be.rejectedWith(ERROR_MSG)
|
||||
await homeBridge.fixAssetsAboveLimits(messageId1, false, halfEther).should.be.rejectedWith(ERROR_MSG)
|
||||
|
||||
await homeBridge.fixAssetsAboveLimits(transactionHash2, false, halfEther).should.be.fulfilled
|
||||
await homeBridge.fixAssetsAboveLimits(transactionHash2, false, halfEther).should.be.fulfilled
|
||||
await homeBridge.fixAssetsAboveLimits(messageId2, false, halfEther).should.be.fulfilled
|
||||
await homeBridge.fixAssetsAboveLimits(messageId2, false, halfEther).should.be.fulfilled
|
||||
|
||||
expect(await homeBridge.outOfLimitAmount()).to.be.bignumber.equal(ZERO)
|
||||
|
||||
await homeBridge.fixAssetsAboveLimits(transactionHash2, false, halfEther).should.be.rejectedWith(ERROR_MSG)
|
||||
await homeBridge.fixAssetsAboveLimits(messageId2, false, halfEther).should.be.rejectedWith(ERROR_MSG)
|
||||
})
|
||||
it('Should fail if txHash didnt increase out of limit amount', async () => {
|
||||
const recipient = accounts[5]
|
||||
const value = oneEther
|
||||
const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415'
|
||||
const invalidTxHash = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121'
|
||||
const invalidMessageId = '0x35d3818e50234655f6aebb2a1cfbf30f59568d8a4ec72066fac5a25dbe7b8121'
|
||||
|
||||
const { logs: affirmationLogs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, {
|
||||
from: authorities[0]
|
||||
|
@ -1600,7 +1608,7 @@ contract('HomeBridge_ERC20_to_Native', async accounts => {
|
|||
|
||||
affirmationLogs[0].event.should.be.equal('AmountLimitExceeded')
|
||||
|
||||
await homeBridge.fixAssetsAboveLimits(invalidTxHash, true, halfEther).should.be.rejectedWith(ERROR_MSG)
|
||||
await homeBridge.fixAssetsAboveLimits(invalidMessageId, true, halfEther).should.be.rejectedWith(ERROR_MSG)
|
||||
})
|
||||
it('Should fail if not called by proxyOwner', async () => {
|
||||
const recipient = accounts[5]
|
||||
|
@ -1612,11 +1620,12 @@ contract('HomeBridge_ERC20_to_Native', async accounts => {
|
|||
}).should.be.fulfilled
|
||||
|
||||
affirmationLogs[0].event.should.be.equal('AmountLimitExceeded')
|
||||
const messageId = affirmationLogs[0].args.messageId
|
||||
|
||||
await homeBridge
|
||||
.fixAssetsAboveLimits(transactionHash, true, halfEther, { from: recipient })
|
||||
.fixAssetsAboveLimits(messageId, true, halfEther, { from: recipient })
|
||||
.should.be.rejectedWith(ERROR_MSG)
|
||||
await homeBridge.fixAssetsAboveLimits(transactionHash, true, halfEther, { from: owner }).should.be.fulfilled
|
||||
await homeBridge.fixAssetsAboveLimits(messageId, true, halfEther, { from: owner }).should.be.fulfilled
|
||||
})
|
||||
it('Should emit UserRequestForSignature with value reduced by fee', async () => {
|
||||
// Initialize
|
||||
|
@ -1671,13 +1680,14 @@ contract('HomeBridge_ERC20_to_Native', async accounts => {
|
|||
value,
|
||||
transactionHash
|
||||
})
|
||||
const messageId = affirmationLogs[0].args.messageId
|
||||
|
||||
const { logs } = await homeBridge.fixAssetsAboveLimits(transactionHash, true, halfEther).should.be.fulfilled
|
||||
const { logs } = await homeBridge.fixAssetsAboveLimits(messageId, true, halfEther).should.be.fulfilled
|
||||
|
||||
// Then
|
||||
logs.length.should.be.equal(2)
|
||||
expectEventInLogs(logs, 'AssetAboveLimitsFixed', {
|
||||
transactionHash,
|
||||
messageId,
|
||||
value: halfEther,
|
||||
remaining: halfEther
|
||||
})
|
||||
|
@ -1686,6 +1696,61 @@ contract('HomeBridge_ERC20_to_Native', async accounts => {
|
|||
value: finalValue
|
||||
})
|
||||
})
|
||||
|
||||
it('should not allow to fix assets after they were already processed', async () => {
|
||||
const recipient = accounts[5]
|
||||
const value = oneEther
|
||||
const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415'
|
||||
const { logs: affirmationLogs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, {
|
||||
from: authorities[0]
|
||||
}).should.be.fulfilled
|
||||
|
||||
affirmationLogs[0].event.should.be.equal('AmountLimitExceeded')
|
||||
const messageId = affirmationLogs[0].args.messageId
|
||||
|
||||
await homeBridge.setExecutionDailyLimit(ether('2'), { from: owner }).should.be.fulfilled
|
||||
await homeBridge.setExecutionMaxPerTx(value, { from: owner }).should.be.fulfilled
|
||||
await homeBridge.setDailyLimit(ether('2'), { from: owner }).should.be.fulfilled
|
||||
await homeBridge.setMaxPerTx(value, { from: owner }).should.be.fulfilled
|
||||
|
||||
await homeBridge.executeAffirmation(recipient, value, transactionHash, { from: authorities[0] }).should.be
|
||||
.fulfilled
|
||||
|
||||
const outOfLimitAmount = await homeBridge.outOfLimitAmount()
|
||||
outOfLimitAmount.should.be.bignumber.equal(ZERO)
|
||||
|
||||
await homeBridge.fixAssetsAboveLimits(messageId, false, value).should.be.rejectedWith(ERROR_MSG)
|
||||
})
|
||||
|
||||
it('should not allow to executeAffirmation after assets were fixed', async () => {
|
||||
const recipient = accounts[5]
|
||||
const value = oneEther
|
||||
const transactionHash = '0x806335163828a8eda675cff9c84fa6e6c7cf06bb44cc6ec832e42fe789d01415'
|
||||
const { logs: affirmationLogs } = await homeBridge.executeAffirmation(recipient, value, transactionHash, {
|
||||
from: authorities[0]
|
||||
}).should.be.fulfilled
|
||||
|
||||
affirmationLogs[0].event.should.be.equal('AmountLimitExceeded')
|
||||
const messageId = affirmationLogs[0].args.messageId
|
||||
|
||||
const outOfLimitAmount = await homeBridge.outOfLimitAmount()
|
||||
outOfLimitAmount.should.be.bignumber.equal(value)
|
||||
|
||||
await homeBridge.fixAssetsAboveLimits(messageId, false, halfEther).should.be.fulfilled
|
||||
|
||||
await homeBridge.setExecutionDailyLimit(ether('2'), { from: owner }).should.be.fulfilled
|
||||
await homeBridge.setExecutionMaxPerTx(value, { from: owner }).should.be.fulfilled
|
||||
await homeBridge.setDailyLimit(ether('2'), { from: owner }).should.be.fulfilled
|
||||
await homeBridge.setMaxPerTx(value, { from: owner }).should.be.fulfilled
|
||||
|
||||
await homeBridge.executeAffirmation(recipient, value, transactionHash, { from: authorities[0] }).should.be
|
||||
.rejected
|
||||
|
||||
await homeBridge.fixAssetsAboveLimits(messageId, false, halfEther).should.be.fulfilled
|
||||
|
||||
await homeBridge.executeAffirmation(recipient, value, transactionHash, { from: authorities[0] }).should.be
|
||||
.rejected
|
||||
})
|
||||
})
|
||||
describe('#feeManager', async () => {
|
||||
let homeBridge
|
||||
|
|
Loading…
Reference in New Issue