Add missing fix mediator balance (#510)
This commit is contained in:
parent
f70426c841
commit
2def0318bb
|
@ -102,7 +102,12 @@ contract ERC677BridgeToken is IBurnableMintableERC677Token, DetailedERC20, Burna
|
|||
revert();
|
||||
}
|
||||
|
||||
function claimTokens(address _token, address _to) public onlyOwner validAddress(_to) {
|
||||
/**
|
||||
* @dev Withdraws the erc20 tokens or native coins from this contract.
|
||||
* @param _token address of the claimed token or address(0) for native coins.
|
||||
* @param _to address of the tokens/coins receiver.
|
||||
*/
|
||||
function claimTokens(address _token, address _to) external onlyOwner {
|
||||
claimValues(_token, _to);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,5 +4,5 @@ import "../interfaces/ERC677.sol";
|
|||
contract IBurnableMintableERC677Token is ERC677 {
|
||||
function mint(address _to, uint256 _amount) public returns (bool);
|
||||
function burn(uint256 _value) public;
|
||||
function claimTokens(address _token, address _to) public;
|
||||
function claimTokens(address _token, address _to) external;
|
||||
}
|
||||
|
|
|
@ -50,10 +50,6 @@ contract BasicBridge is
|
|||
return uintStorage[REQUIRED_BLOCK_CONFIRMATIONS];
|
||||
}
|
||||
|
||||
function claimTokens(address _token, address _to) public onlyIfUpgradeabilityOwner validAddress(_to) {
|
||||
claimValues(_token, _to);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Internal function for updating fallback gas price value.
|
||||
* @param _gasPrice new value for the gas price, zero gas price is allowed.
|
||||
|
|
|
@ -1,18 +1,31 @@
|
|||
pragma solidity 0.4.24;
|
||||
|
||||
import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
|
||||
import "../libraries/Address.sol";
|
||||
import "../libraries/SafeERC20.sol";
|
||||
|
||||
/**
|
||||
* @title Claimable
|
||||
* @dev Implementation of the claiming utils that can be useful for withdrawing accidentally sent tokens that are not used in bridge operations.
|
||||
*/
|
||||
contract Claimable {
|
||||
bytes4 internal constant TRANSFER = 0xa9059cbb; // transfer(address,uint256)
|
||||
using SafeERC20 for address;
|
||||
|
||||
/**
|
||||
* Throws if a given address is equal to address(0)
|
||||
*/
|
||||
modifier validAddress(address _to) {
|
||||
require(_to != address(0));
|
||||
/* solcov ignore next */
|
||||
_;
|
||||
}
|
||||
|
||||
function claimValues(address _token, address _to) internal {
|
||||
/**
|
||||
* @dev Withdraws the erc20 tokens or native coins from this contract.
|
||||
* Caller should additionally check that the claimed token is not a part of bridge operations (i.e. that token != erc20token()).
|
||||
* @param _token address of the claimed token or address(0) for native coins.
|
||||
* @param _to address of the tokens/coins receiver.
|
||||
*/
|
||||
function claimValues(address _token, address _to) internal validAddress(_to) {
|
||||
if (_token == address(0)) {
|
||||
claimNativeCoins(_to);
|
||||
} else {
|
||||
|
@ -20,35 +33,23 @@ contract Claimable {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Internal function for withdrawing all native coins from the contract.
|
||||
* @param _to address of the coins receiver.
|
||||
*/
|
||||
function claimNativeCoins(address _to) internal {
|
||||
uint256 value = address(this).balance;
|
||||
Address.safeSendValue(_to, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Internal function for withdrawing all tokens of ssome particular ERC20 contract from this contract.
|
||||
* @param _token address of the claimed ERC20 token.
|
||||
* @param _to address of the tokens receiver.
|
||||
*/
|
||||
function claimErc20Tokens(address _token, address _to) internal {
|
||||
ERC20Basic token = ERC20Basic(_token);
|
||||
uint256 balance = token.balanceOf(this);
|
||||
safeTransfer(_token, _to, balance);
|
||||
}
|
||||
|
||||
function safeTransfer(address _token, address _to, uint256 _value) internal {
|
||||
bytes memory returnData;
|
||||
bool returnDataResult;
|
||||
bytes memory callData = abi.encodeWithSelector(TRANSFER, _to, _value);
|
||||
assembly {
|
||||
let result := call(gas, _token, 0x0, add(callData, 0x20), mload(callData), 0, 32)
|
||||
returnData := mload(0)
|
||||
returnDataResult := mload(0)
|
||||
|
||||
switch result
|
||||
case 0 {
|
||||
revert(0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
// Return data is optional
|
||||
if (returnData.length > 0) {
|
||||
require(returnDataResult);
|
||||
}
|
||||
_token.safeTransfer(_to, balance);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,7 +100,8 @@ contract InterestReceiver is ERC677Receiver, Ownable, Claimable, TokenSwapper {
|
|||
* @param _token address of claimed token, address(0) for native
|
||||
* @param _to address of tokens receiver
|
||||
*/
|
||||
function claimTokens(address _token, address _to) external onlyOwner validAddress(_to) {
|
||||
function claimTokens(address _token, address _to) external onlyOwner {
|
||||
// Only tokens other than CHAI/DAI can be claimed from this contract.
|
||||
require(_token != address(chaiToken()) && _token != address(daiToken()));
|
||||
claimValues(_token, _to);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
pragma solidity 0.4.24;
|
||||
|
||||
import "../upgradeability/EternalStorage.sol";
|
||||
|
||||
/**
|
||||
* @title MediatorBalanceStorage
|
||||
* @dev Storage helpers for the mediator balance tracking.
|
||||
*/
|
||||
contract MediatorBalanceStorage is EternalStorage {
|
||||
bytes32 internal constant MEDIATOR_BALANCE = 0x3db340e280667ee926fa8c51e8f9fcf88a0ff221a66d84d63b4778127d97d139; // keccak256(abi.encodePacked("mediatorBalance"))
|
||||
|
||||
/**
|
||||
* @dev Tells the expected mediator balance.
|
||||
* @return the current expected mediator balance.
|
||||
*/
|
||||
function mediatorBalance() public view returns (uint256) {
|
||||
return uintStorage[MEDIATOR_BALANCE];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sets the expected mediator balance of the contract.
|
||||
* @param _balance the new expected mediator balance value.
|
||||
*/
|
||||
function _setMediatorBalance(uint256 _balance) internal {
|
||||
uintStorage[MEDIATOR_BALANCE] = _balance;
|
||||
}
|
||||
}
|
|
@ -4,17 +4,16 @@ import "./BasicAMBErc20ToNative.sol";
|
|||
import "../BaseERC677Bridge.sol";
|
||||
import "../ReentrancyGuard.sol";
|
||||
import "../../libraries/SafeERC20.sol";
|
||||
import "../MediatorBalanceStorage.sol";
|
||||
|
||||
/**
|
||||
* @title ForeignAMBErc20ToNative
|
||||
* @dev Foreign mediator implementation for erc20-to-native bridge intended to work on top of AMB bridge.
|
||||
* It is design to be used as implementation contract of EternalStorageProxy contract.
|
||||
*/
|
||||
contract ForeignAMBErc20ToNative is BasicAMBErc20ToNative, ReentrancyGuard, BaseERC677Bridge {
|
||||
contract ForeignAMBErc20ToNative is BasicAMBErc20ToNative, ReentrancyGuard, BaseERC677Bridge, MediatorBalanceStorage {
|
||||
using SafeERC20 for ERC677;
|
||||
|
||||
bytes32 internal constant MEDIATOR_BALANCE = 0x3db340e280667ee926fa8c51e8f9fcf88a0ff221a66d84d63b4778127d97d139; // keccak256(abi.encodePacked("mediatorBalance"))
|
||||
|
||||
/**
|
||||
* @dev Stores the initial parameters of the mediator.
|
||||
* @param _bridgeContract the address of the AMB bridge contract.
|
||||
|
@ -109,25 +108,18 @@ contract ForeignAMBErc20ToNative is BasicAMBErc20ToNative, ReentrancyGuard, Base
|
|||
* @param _token address of the token, if it is not provided, native tokens will be transferred.
|
||||
* @param _to address that will receive the locked tokens on this contract.
|
||||
*/
|
||||
function claimTokens(address _token, address _to) public onlyIfUpgradeabilityOwner validAddress(_to) {
|
||||
function claimTokens(address _token, address _to) external onlyIfUpgradeabilityOwner {
|
||||
// Since bridged tokens are locked at this contract, it is not allowed to claim them with the use of claimTokens function
|
||||
require(_token != address(_erc677token()));
|
||||
claimValues(_token, _to);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Tells the token balance of the contract.
|
||||
* @return the current tracked token balance of the contract.
|
||||
*/
|
||||
function mediatorBalance() public view returns (uint256) {
|
||||
return uintStorage[MEDIATOR_BALANCE];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Allows to send to the other network the amount of locked native tokens that can be forced into the contract
|
||||
* @dev Allows to send to the other network the amount of locked tokens that can be forced into the contract
|
||||
* without the invocation of the required methods.
|
||||
* @param _receiver the address that will receive the tokens on the other network
|
||||
* @param _receiver the address that will receive the native coins on the other network
|
||||
*/
|
||||
function fixMediatorBalance(address _receiver) public onlyIfUpgradeabilityOwner {
|
||||
function fixMediatorBalance(address _receiver) external onlyIfUpgradeabilityOwner validAddress(_receiver) {
|
||||
uint256 balance = _erc677token().balanceOf(address(this));
|
||||
uint256 expectedBalance = mediatorBalance();
|
||||
require(balance > expectedBalance);
|
||||
|
@ -192,12 +184,4 @@ contract ForeignAMBErc20ToNative is BasicAMBErc20ToNative, ReentrancyGuard, Base
|
|||
function bridgeContractOnOtherSide() internal view returns (address) {
|
||||
return mediatorContractOnOtherSide();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sets the updated token balance of the contract.
|
||||
* @param _balance the new token balance of the contract.
|
||||
*/
|
||||
function _setMediatorBalance(uint256 _balance) internal {
|
||||
uintStorage[MEDIATOR_BALANCE] = _balance;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -202,12 +202,13 @@ contract HomeAMBErc20ToNative is BasicAMBErc20ToNative, BlockRewardBridge, HomeF
|
|||
}
|
||||
|
||||
/**
|
||||
* @dev Allows to transfer any locked token on this contract that is not part of the bridge operations.
|
||||
* Native tokens are not allowed to be claimed.
|
||||
* @param _token address of the token.
|
||||
* @dev Allows to transfer any locked tokens or native coins on this contract.
|
||||
* @param _token address of the token, address(0) for native coins.
|
||||
* @param _to address that will receive the locked tokens on this contract.
|
||||
*/
|
||||
function claimTokens(address _token, address _to) external onlyIfUpgradeabilityOwner validAddress(_to) {
|
||||
function claimTokens(address _token, address _to) external onlyIfUpgradeabilityOwner {
|
||||
// In case native coins were forced into this contract by using a selfdestruct opcode,
|
||||
// they should be handled by a call to fixMediatorBalance, instead of using a claimTokens function.
|
||||
require(_token != address(0));
|
||||
claimValues(_token, _to);
|
||||
}
|
||||
|
@ -217,7 +218,7 @@ contract HomeAMBErc20ToNative is BasicAMBErc20ToNative, BlockRewardBridge, HomeF
|
|||
* without the invocation of the required methods.
|
||||
* @param _receiver the address that will receive the tokens on the other network
|
||||
*/
|
||||
function fixMediatorBalance(address _receiver) external onlyIfUpgradeabilityOwner {
|
||||
function fixMediatorBalance(address _receiver) external onlyIfUpgradeabilityOwner validAddress(_receiver) {
|
||||
uint256 balance = address(this).balance;
|
||||
uint256 available = maxAvailablePerTx();
|
||||
if (balance > available) {
|
||||
|
|
|
@ -146,8 +146,4 @@ contract BasicAMBErc677ToErc677 is
|
|||
passMessage(recipient, recipient, valueToUnlock);
|
||||
}
|
||||
}
|
||||
|
||||
function claimTokens(address _token, address _to) public onlyIfUpgradeabilityOwner validAddress(_to) {
|
||||
claimValues(_token, _to);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,13 +2,14 @@ pragma solidity 0.4.24;
|
|||
|
||||
import "./BasicAMBErc677ToErc677.sol";
|
||||
import "../../libraries/SafeERC20.sol";
|
||||
import "../MediatorBalanceStorage.sol";
|
||||
|
||||
/**
|
||||
* @title ForeignAMBErc677ToErc677
|
||||
* @dev Foreign side implementation for erc677-to-erc677 mediator intended to work on top of AMB bridge.
|
||||
* It is designed to be used as an implementation contract of EternalStorageProxy contract.
|
||||
*/
|
||||
contract ForeignAMBErc677ToErc677 is BasicAMBErc677ToErc677 {
|
||||
contract ForeignAMBErc677ToErc677 is BasicAMBErc677ToErc677, MediatorBalanceStorage {
|
||||
using SafeERC20 for ERC677;
|
||||
|
||||
/**
|
||||
|
@ -19,7 +20,10 @@ contract ForeignAMBErc677ToErc677 is BasicAMBErc677ToErc677 {
|
|||
function executeActionOnBridgedTokens(address _recipient, uint256 _value) internal {
|
||||
uint256 value = _unshiftValue(_value);
|
||||
bytes32 _messageId = messageId();
|
||||
|
||||
_setMediatorBalance(mediatorBalance().sub(value));
|
||||
erc677token().safeTransfer(_recipient, value);
|
||||
|
||||
emit TokensBridged(_recipient, value, _messageId);
|
||||
}
|
||||
|
||||
|
@ -44,6 +48,26 @@ contract ForeignAMBErc677ToErc677 is BasicAMBErc677ToErc677 {
|
|||
bridgeSpecificActionsOnTokenTransfer(token, msg.sender, _value, abi.encodePacked(_receiver));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Allows to send to the other network the amount of locked tokens that can be forced into the contract
|
||||
* without the invocation of the required methods.
|
||||
* @param _receiver the address that will receive the tokens on the other network
|
||||
*/
|
||||
function fixMediatorBalance(address _receiver) external onlyIfUpgradeabilityOwner validAddress(_receiver) {
|
||||
uint256 balance = _erc677token().balanceOf(address(this));
|
||||
uint256 expectedBalance = mediatorBalance();
|
||||
require(balance > expectedBalance);
|
||||
uint256 diff = balance - expectedBalance;
|
||||
uint256 available = maxAvailablePerTx();
|
||||
require(available > 0);
|
||||
if (diff > available) {
|
||||
diff = available;
|
||||
}
|
||||
addTotalSpentPerDay(getCurrentDay(), diff);
|
||||
_setMediatorBalance(expectedBalance.add(diff));
|
||||
passMessage(_receiver, _receiver, diff);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Executes action on deposit of bridged tokens
|
||||
* @param _from address of tokens sender
|
||||
|
@ -57,11 +81,28 @@ contract ForeignAMBErc677ToErc677 is BasicAMBErc677ToErc677 {
|
|||
bytes _data
|
||||
) internal {
|
||||
if (!lock()) {
|
||||
_setMediatorBalance(mediatorBalance().add(_value));
|
||||
passMessage(_from, chooseReceiver(_from, _data), _value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Unlock back the amount of tokens that were bridged to the other network but failed.
|
||||
* @param _recipient address that will receive the tokens
|
||||
* @param _value amount of tokens to be received
|
||||
*/
|
||||
function executeActionOnFixedTokens(address _recipient, uint256 _value) internal {
|
||||
_setMediatorBalance(mediatorBalance().sub(_value));
|
||||
erc677token().safeTransfer(_recipient, _value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Allows to transfer any locked token on this contract that is not part of the bridge operations.
|
||||
* @param _token address of the token, if it is not provided, native tokens will be transferred.
|
||||
* @param _to address that will receive the locked tokens on this contract.
|
||||
*/
|
||||
function claimTokens(address _token, address _to) external onlyIfUpgradeabilityOwner {
|
||||
require(_token != address(_erc677token()));
|
||||
claimValues(_token, _to);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,4 +64,14 @@ contract ForeignStakeTokenMediator is BasicStakeTokenMediator {
|
|||
token.transfer(_recipient, _value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Allows to transfer any locked token on this contract other than stake token.
|
||||
* @param _token address of the token, if it is not provided, native tokens will be transferred.
|
||||
* @param _to address that will receive the locked tokens on this contract.
|
||||
*/
|
||||
function claimTokens(address _token, address _to) external onlyIfUpgradeabilityOwner {
|
||||
require(_token != address(_erc677token()));
|
||||
claimValues(_token, _to);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,17 @@ contract HomeAMBErc677ToErc677 is BasicAMBErc677ToErc677 {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Withdraws the erc20 tokens or native coins from this contract.
|
||||
* @param _token address of the claimed token or address(0) for native coins.
|
||||
* @param _to address of the tokens/coins receiver.
|
||||
*/
|
||||
function claimTokens(address _token, address _to) external onlyIfUpgradeabilityOwner {
|
||||
// For home side of the bridge, tokens are not locked at the contract, they are minted and burned instead.
|
||||
// So, its is safe to allow claiming of any tokens. Native coins are allowed as well.
|
||||
claimValues(_token, _to);
|
||||
}
|
||||
|
||||
function executeActionOnFixedTokens(address _recipient, uint256 _value) internal {
|
||||
IBurnableMintableERC677Token(erc677token()).mint(_recipient, _value);
|
||||
}
|
||||
|
|
|
@ -154,6 +154,17 @@ contract HomeStakeTokenMediator is BasicStakeTokenMediator, HomeStakeTokenFeeMan
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Withdraws the erc20 tokens or native coins from this contract.
|
||||
* @param _token address of the claimed token or address(0) for native coins.
|
||||
* @param _to address of the tokens/coins receiver.
|
||||
*/
|
||||
function claimTokens(address _token, address _to) external onlyIfUpgradeabilityOwner {
|
||||
// For home side of the bridge, tokens are not locked at the contract, they are minted and burned instead.
|
||||
// So, its is safe to allow claiming of any tokens. Native coins are allowed as well.
|
||||
claimValues(_token, _to);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Executes action on relayed request to fix the failed transfer of tokens
|
||||
* @param _recipient address of tokens receiver
|
||||
|
|
|
@ -81,13 +81,4 @@ contract BasicAMBNativeToErc20 is
|
|||
) internal {
|
||||
revert();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Allows to transfer any locked token on this contract that is not part of the bridge operations.
|
||||
* @param _token address of the token, if it is not provided, native tokens will be transferred.
|
||||
* @param _to address that will receive the locked tokens on this contract.
|
||||
*/
|
||||
function claimTokens(address _token, address _to) public onlyIfUpgradeabilityOwner validAddress(_to) {
|
||||
claimValues(_token, _to);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -157,6 +157,17 @@ contract ForeignAMBNativeToErc20 is BasicAMBNativeToErc20, ReentrancyGuard, Base
|
|||
IBurnableMintableERC677Token(erc677token()).mint(_feeManager, _fee);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Allows to transfer any locked token on this contract that is not part of the bridge operations.
|
||||
* @param _token address of the token, if it is not provided, native tokens will be transferred.
|
||||
* @param _to address that will receive the locked tokens on this contract.
|
||||
*/
|
||||
function claimTokens(address _token, address _to) external onlyIfUpgradeabilityOwner {
|
||||
// For foreign side of the bridge, tokens are not locked at the contract, they are minted and burned instead.
|
||||
// So, its is safe to allow claiming of any tokens. Native coins are allowed as well.
|
||||
claimValues(_token, _to);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Allows to transfer any locked token on the ERC677 token contract.
|
||||
* @param _token address of the token, if it is not provided, native tokens will be transferred.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
pragma solidity 0.4.24;
|
||||
|
||||
import "../MediatorBalanceStorage.sol";
|
||||
import "./BasicAMBNativeToErc20.sol";
|
||||
|
||||
/**
|
||||
|
@ -7,9 +8,7 @@ import "./BasicAMBNativeToErc20.sol";
|
|||
* @dev Home mediator implementation for native-to-erc20 bridge intended to work on top of AMB bridge.
|
||||
* It is design to be used as implementation contract of EternalStorageProxy contract.
|
||||
*/
|
||||
contract HomeAMBNativeToErc20 is BasicAMBNativeToErc20 {
|
||||
bytes32 internal constant MEDIATOR_BALANCE = 0x3db340e280667ee926fa8c51e8f9fcf88a0ff221a66d84d63b4778127d97d139; // keccak256(abi.encodePacked("mediatorBalance"))
|
||||
|
||||
contract HomeAMBNativeToErc20 is BasicAMBNativeToErc20, MediatorBalanceStorage {
|
||||
/**
|
||||
* @dev Stores the initial parameters of the mediator.
|
||||
* @param _bridgeContract the address of the AMB bridge contract.
|
||||
|
@ -73,7 +72,7 @@ contract HomeAMBNativeToErc20 is BasicAMBNativeToErc20 {
|
|||
require(msg.value > 0);
|
||||
require(withinLimit(msg.value));
|
||||
addTotalSpentPerDay(getCurrentDay(), msg.value);
|
||||
setMediatorBalance(mediatorBalance().add(msg.value));
|
||||
_setMediatorBalance(mediatorBalance().add(msg.value));
|
||||
passMessage(msg.sender, _receiver, msg.value);
|
||||
}
|
||||
|
||||
|
@ -85,7 +84,7 @@ contract HomeAMBNativeToErc20 is BasicAMBNativeToErc20 {
|
|||
*/
|
||||
function executeActionOnBridgedTokens(address _receiver, uint256 _value) internal {
|
||||
uint256 valueToTransfer = _shiftValue(_value);
|
||||
setMediatorBalance(mediatorBalance().sub(valueToTransfer));
|
||||
_setMediatorBalance(mediatorBalance().sub(valueToTransfer));
|
||||
|
||||
bytes32 _messageId = messageId();
|
||||
IMediatorFeeManager feeManager = feeManagerContract();
|
||||
|
@ -107,7 +106,7 @@ contract HomeAMBNativeToErc20 is BasicAMBNativeToErc20 {
|
|||
* @param _value amount of native tokens to be received
|
||||
*/
|
||||
function executeActionOnFixedTokens(address _receiver, uint256 _value) internal {
|
||||
setMediatorBalance(mediatorBalance().sub(_value));
|
||||
_setMediatorBalance(mediatorBalance().sub(_value));
|
||||
Address.safeSendValue(_receiver, _value);
|
||||
}
|
||||
|
||||
|
@ -120,31 +119,16 @@ contract HomeAMBNativeToErc20 is BasicAMBNativeToErc20 {
|
|||
Address.safeSendValue(_feeManager, _fee);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Tells the native balance of the contract.
|
||||
* @return the current tracked native balance of the contract.
|
||||
*/
|
||||
function mediatorBalance() public view returns (uint256) {
|
||||
return uintStorage[MEDIATOR_BALANCE];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Sets the updated native balance of the contract.
|
||||
* @param _balance the new native balance of the contract.
|
||||
*/
|
||||
function setMediatorBalance(uint256 _balance) internal {
|
||||
uintStorage[MEDIATOR_BALANCE] = _balance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Allows to transfer any locked token on this contract that is not part of the bridge operations.
|
||||
* Native tokens are not allowed to be claimed.
|
||||
* @param _token address of the token.
|
||||
* @param _to address that will receive the locked tokens on this contract.
|
||||
*/
|
||||
function claimTokens(address _token, address _to) public {
|
||||
function claimTokens(address _token, address _to) external onlyIfUpgradeabilityOwner {
|
||||
// Since bridged coins are locked at this contract, it is not allowed to claim them with the use of claimTokens function
|
||||
require(_token != address(0));
|
||||
super.claimTokens(_token, _to);
|
||||
claimValues(_token, _to);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -152,7 +136,7 @@ contract HomeAMBNativeToErc20 is BasicAMBNativeToErc20 {
|
|||
* without the invocation of the required methods.
|
||||
* @param _receiver the address that will receive the tokens on the other network
|
||||
*/
|
||||
function fixMediatorBalance(address _receiver) public onlyIfUpgradeabilityOwner {
|
||||
function fixMediatorBalance(address _receiver) external onlyIfUpgradeabilityOwner validAddress(_receiver) {
|
||||
uint256 balance = address(this).balance;
|
||||
uint256 expectedBalance = mediatorBalance();
|
||||
require(balance > expectedBalance);
|
||||
|
@ -163,7 +147,7 @@ contract HomeAMBNativeToErc20 is BasicAMBNativeToErc20 {
|
|||
diff = available;
|
||||
}
|
||||
addTotalSpentPerDay(getCurrentDay(), diff);
|
||||
setMediatorBalance(expectedBalance.add(diff));
|
||||
_setMediatorBalance(expectedBalance.add(diff));
|
||||
passMessage(_receiver, _receiver, diff);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,6 +123,7 @@ BasicHomeAMB::executeAffirmation
|
|||
>>Mediator
|
||||
........TokenBridgeMediator::handleBridgedTokens
|
||||
..........HomeAMBNativeToErc20::executeActionOnBridgedTokens
|
||||
............MediatorBalanceStorage::_setMediatorBalance
|
||||
............RewardableMediator::distributeFee
|
||||
..............HomeAMBNativeToErc20::onFeeDistribution
|
||||
................Address::safeSendValue
|
||||
|
@ -214,6 +215,7 @@ BasicHomeAMB::executeAffirmation
|
|||
..........TokenBridgeMediator::messageHashRecipient
|
||||
..........TokenBridgeMediator::messageHashValue
|
||||
..........HomeAMBNativeToErc20::executeActionOnFixedTokens
|
||||
............MediatorBalanceStorage::_setMediatorBalance
|
||||
............Address::safeSendValue
|
||||
..........emit FailedMessageFixed
|
||||
>>Bridge
|
||||
|
@ -308,6 +310,7 @@ The mediator on the Home side has the `relayTokens` method which is payable. The
|
|||
>>Mediator
|
||||
HomeAMBNativeToErc20::relayTokens
|
||||
..HomeAMBNativeToErc20::nativeTransfer
|
||||
....MediatorBalanceStorage::_setMediatorBalance
|
||||
....TokenBridgeMediator::passMessage
|
||||
......TokenBridgeMediator::setMessageHashValue
|
||||
......TokenBridgeMediator::setMessageHashRecipient
|
||||
|
|
|
@ -33,9 +33,15 @@ contract BasicForeignBridgeErcToErc is BasicForeignBridge {
|
|||
return 0xba4690f5; // bytes4(keccak256(abi.encodePacked("erc-to-erc-core")))
|
||||
}
|
||||
|
||||
function claimTokens(address _token, address _to) public {
|
||||
/**
|
||||
* @dev Withdraws the erc20 tokens or native coins from this contract. Bridged token cannot be withdrawn by this function.
|
||||
* @param _token address of the claimed token or address(0) for native coins.
|
||||
* @param _to address of the tokens/coins receiver.
|
||||
*/
|
||||
function claimTokens(address _token, address _to) external onlyIfUpgradeabilityOwner {
|
||||
// Since bridged tokens are locked at this contract, it is not allowed to claim them with the use of claimTokens function
|
||||
require(_token != address(erc20token()));
|
||||
super.claimTokens(_token, _to);
|
||||
claimValues(_token, _to);
|
||||
}
|
||||
|
||||
function onExecuteMessage(
|
||||
|
|
|
@ -121,6 +121,11 @@ contract HomeBridgeErcToErc is
|
|||
setErc677token(_erc677token);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Withdraws erc20 tokens or native coins from the token contract. It is required since the bridge contract is the owner of the token contract.
|
||||
* @param _token address of the claimed token or address(0) for native coins.
|
||||
* @param _to address of the tokens/coins receiver.
|
||||
*/
|
||||
function claimTokensFromErc677(address _token, address _to) external onlyIfUpgradeabilityOwner {
|
||||
IBurnableMintableERC677Token(erc677token()).claimTokens(_token, _to);
|
||||
}
|
||||
|
|
|
@ -39,11 +39,17 @@ contract ForeignBridgeErcToNative is BasicForeignBridge, ERC20Bridge, OtherSideB
|
|||
return 0x18762d46; // bytes4(keccak256(abi.encodePacked("erc-to-native-core")))
|
||||
}
|
||||
|
||||
function claimTokens(address _token, address _to) public {
|
||||
/**
|
||||
* @dev Withdraws the erc20 tokens or native coins from this contract.
|
||||
* @param _token address of the claimed token or address(0) for native coins.
|
||||
* @param _to address of the tokens/coins receiver.
|
||||
*/
|
||||
function claimTokens(address _token, address _to) external onlyIfUpgradeabilityOwner {
|
||||
// Since bridged tokens are locked at this contract, it is not allowed to claim them with the use of claimTokens function
|
||||
require(_token != address(erc20token()));
|
||||
// Chai token is not claimable if investing into Chai is enabled
|
||||
require(_token != address(chaiToken()) || !isChaiTokenEnabled());
|
||||
super.claimTokens(_token, _to);
|
||||
claimValues(_token, _to);
|
||||
}
|
||||
|
||||
function onExecuteMessage(
|
||||
|
|
|
@ -119,6 +119,20 @@ contract HomeBridgeErcToNative is
|
|||
_setBlockRewardContract(_blockReward);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Withdraws the erc20 tokens or native coins from this contract.
|
||||
* @param _token address of the claimed token or address(0) for native coins.
|
||||
* @param _to address of the tokens/coins receiver.
|
||||
*/
|
||||
function claimTokens(address _token, address _to) external onlyIfUpgradeabilityOwner {
|
||||
// Since native coins are being minted by the blockReward contract and burned by sending them to the address(0),
|
||||
// they are not locked at the contract during the normal operation. However, they can be still forced into this contract
|
||||
// by using a selfdestruct opcode, or by using this contract address as a coinbase account.
|
||||
// In this case it is necessary to allow claiming native coins back.
|
||||
// Any other erc20 token can be safely claimed as well.
|
||||
claimValues(_token, _to);
|
||||
}
|
||||
|
||||
function _initialize(
|
||||
address _validatorContract,
|
||||
uint256[3] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = _dailyLimit, 1 = _maxPerTx, 2 = _minPerTx ]
|
||||
|
|
|
@ -75,8 +75,9 @@ contract BasicMultiAMBErc20ToErc677 is
|
|||
* @param _token address of claimed token, address(0) for native
|
||||
* @param _to address of tokens receiver
|
||||
*/
|
||||
function claimTokens(address _token, address _to) external onlyIfUpgradeabilityOwner validAddress(_to) {
|
||||
require(_token == address(0) || !isTokenRegistered(_token)); // native coins or token not registered
|
||||
function claimTokens(address _token, address _to) external onlyIfUpgradeabilityOwner {
|
||||
// Only unregistered tokens and native coins are allowed to be claimed with the use of this function
|
||||
require(_token == address(0) || !isTokenRegistered(_token));
|
||||
claimValues(_token, _to);
|
||||
}
|
||||
|
||||
|
|
|
@ -200,7 +200,11 @@ contract ForeignMultiAMBErc20ToErc677 is BasicMultiAMBErc20ToErc677 {
|
|||
* @param _token address of the token contract.
|
||||
* @param _receiver the address that will receive the tokens on the other network.
|
||||
*/
|
||||
function fixMediatorBalance(address _token, address _receiver) public onlyIfUpgradeabilityOwner {
|
||||
function fixMediatorBalance(address _token, address _receiver)
|
||||
external
|
||||
onlyIfUpgradeabilityOwner
|
||||
validAddress(_receiver)
|
||||
{
|
||||
require(isTokenRegistered(_token));
|
||||
uint256 balance = ERC677(_token).balanceOf(address(this));
|
||||
uint256 expectedBalance = mediatorBalance(_token);
|
||||
|
|
|
@ -72,10 +72,26 @@ contract ForeignBridgeNativeToErc is
|
|||
return 0x92a8d7fe; // bytes4(keccak256(abi.encodePacked("native-to-erc-core")))
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Withdraws erc20 tokens or native coins from the token contract. It is required since the bridge contract is the owner of the token contract.
|
||||
* @param _token address of the claimed token or address(0) for native coins.
|
||||
* @param _to address of the tokens/coins receiver.
|
||||
*/
|
||||
function claimTokensFromErc677(address _token, address _to) external onlyIfUpgradeabilityOwner {
|
||||
IBurnableMintableERC677Token(erc677token()).claimTokens(_token, _to);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Withdraws the erc20 tokens or native coins from this contract.
|
||||
* @param _token address of the claimed token or address(0) for native coins.
|
||||
* @param _to address of the tokens/coins receiver.
|
||||
*/
|
||||
function claimTokens(address _token, address _to) external onlyIfUpgradeabilityOwner {
|
||||
// For foreign side of the bridge, tokens are not locked at the contract, they are minted and burned instead.
|
||||
// So, its is safe to allow claiming of any tokens. Native coins are allowed as well.
|
||||
claimValues(_token, _to);
|
||||
}
|
||||
|
||||
function _initialize(
|
||||
address _validatorContract,
|
||||
address _erc677token,
|
||||
|
|
|
@ -83,6 +83,18 @@ contract HomeBridgeNativeToErc is EternalStorage, BasicHomeBridge, RewardableHom
|
|||
return 0x92a8d7fe; // bytes4(keccak256(abi.encodePacked("native-to-erc-core")))
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Allows to transfer any locked token on this contract that is not part of the bridge operations.
|
||||
* Native tokens are not allowed to be claimed.
|
||||
* @param _token address of the token.
|
||||
* @param _to address that will receive the locked tokens on this contract.
|
||||
*/
|
||||
function claimTokens(address _token, address _to) external onlyIfUpgradeabilityOwner {
|
||||
// Since bridged coins are locked at this contract, it is not allowed to claim them with the use of claimTokens function
|
||||
require(_token != address(0));
|
||||
claimValues(_token, _to);
|
||||
}
|
||||
|
||||
function _initialize(
|
||||
address _validatorContract,
|
||||
uint256[3] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = _dailyLimit, 1 = _maxPerTx, 2 = _minPerTx ]
|
||||
|
|
|
@ -751,6 +751,7 @@ contract('ForeignAMBErc20ToNative', async accounts => {
|
|||
expect(events.length).to.be.equal(1)
|
||||
|
||||
await contract.fixMediatorBalance(owner, { from: user }).should.be.rejected
|
||||
await contract.fixMediatorBalance(ZERO_ADDRESS, { from: owner }).should.be.rejected
|
||||
await contract.fixMediatorBalance(owner, { from: owner }).should.be.fulfilled
|
||||
await contract.fixMediatorBalance(owner, { from: owner }).should.be.rejected
|
||||
|
||||
|
|
|
@ -969,6 +969,8 @@ contract('HomeAMBErc20ToNative', async accounts => {
|
|||
// only owner can call the method
|
||||
await contract.fixMediatorBalance(user, { from: user }).should.be.rejected
|
||||
|
||||
await contract.fixMediatorBalance(ZERO_ADDRESS, { from: owner }).should.be.rejected
|
||||
|
||||
await contract.fixMediatorBalance(user, { from: owner }).should.be.fulfilled
|
||||
|
||||
expect(await contract.totalBurntCoins()).to.be.bignumber.equal(ether('0.1'))
|
||||
|
|
|
@ -10,7 +10,7 @@ const { expect } = require('chai')
|
|||
const { shouldBehaveLikeBasicAMBErc677ToErc677 } = require('./AMBErc677ToErc677Behavior.test')
|
||||
const { ether } = require('../helpers/helpers')
|
||||
const { getEvents, strip0x } = require('../helpers/helpers')
|
||||
const { ERROR_MSG, toBN } = require('../setup')
|
||||
const { ERROR_MSG, toBN, ZERO_ADDRESS } = require('../setup')
|
||||
|
||||
const ZERO = toBN(0)
|
||||
const halfEther = ether('0.5')
|
||||
|
@ -98,6 +98,7 @@ contract('ForeignAMBErc677ToErc677', async accounts => {
|
|||
expect(events.length).to.be.equal(1)
|
||||
expect(events[0].returnValues.encodedData.includes(strip0x(user).toLowerCase())).to.be.equal(true)
|
||||
expect(await foreignBridge.totalSpentPerDay(currentDay)).to.be.bignumber.equal(halfEther)
|
||||
expect(await foreignBridge.mediatorBalance()).to.be.bignumber.equal(halfEther)
|
||||
})
|
||||
it('should be able to specify a different receiver', async () => {
|
||||
// Given
|
||||
|
@ -126,6 +127,7 @@ contract('ForeignAMBErc677ToErc677', async accounts => {
|
|||
expect(events.length).to.be.equal(1)
|
||||
expect(events[0].returnValues.encodedData.includes(strip0x(user2).toLowerCase())).to.be.equal(true)
|
||||
expect(await foreignBridge.totalSpentPerDay(currentDay)).to.be.bignumber.equal(halfEther)
|
||||
expect(await foreignBridge.mediatorBalance()).to.be.bignumber.equal(halfEther)
|
||||
})
|
||||
})
|
||||
describe('handleBridgedTokens', () => {
|
||||
|
@ -146,8 +148,9 @@ contract('ForeignAMBErc677ToErc677', async accounts => {
|
|||
decimalShiftZero,
|
||||
owner
|
||||
).should.be.fulfilled
|
||||
await erc677Token.mint(foreignBridge.address, twoEthers, { from: owner }).should.be.fulfilled
|
||||
await erc677Token.transferOwnership(foreignBridge.address)
|
||||
await erc677Token.mint(user, twoEthers, { from: owner }).should.be.fulfilled
|
||||
await erc677Token.transfer(foreignBridge.address, oneEther, { from: user }).should.be.fulfilled
|
||||
await erc677Token.transfer(foreignBridge.address, oneEther, { from: user }).should.be.fulfilled
|
||||
})
|
||||
it('should transfer locked tokens on message from amb', async () => {
|
||||
// Given
|
||||
|
@ -156,6 +159,7 @@ contract('ForeignAMBErc677ToErc677', async accounts => {
|
|||
const initialEvents = await getEvents(erc677Token, { event: 'Transfer' })
|
||||
expect(initialEvents.length).to.be.equal(0)
|
||||
expect(await erc677Token.balanceOf(foreignBridge.address)).to.be.bignumber.equal(twoEthers)
|
||||
expect(await foreignBridge.mediatorBalance()).to.be.bignumber.equal(twoEthers)
|
||||
expect(await erc677Token.balanceOf(user)).to.be.bignumber.equal(ZERO)
|
||||
|
||||
// can't be called by user
|
||||
|
@ -184,6 +188,7 @@ contract('ForeignAMBErc677ToErc677', async accounts => {
|
|||
// Then
|
||||
expect(await foreignBridge.totalExecutedPerDay(currentDay)).to.be.bignumber.equal(oneEther)
|
||||
expect(await erc677Token.balanceOf(foreignBridge.address)).to.be.bignumber.equal(oneEther)
|
||||
expect(await foreignBridge.mediatorBalance()).to.be.bignumber.equal(oneEther)
|
||||
expect(await erc677Token.balanceOf(user)).to.be.bignumber.equal(oneEther)
|
||||
|
||||
const TokensBridgedEvent = await getEvents(foreignBridge, { event: 'TokensBridged' })
|
||||
|
@ -208,14 +213,16 @@ contract('ForeignAMBErc677ToErc677', async accounts => {
|
|||
decimalShift,
|
||||
owner
|
||||
).should.be.fulfilled
|
||||
await erc677Token.mint(foreignBridge.address, twoEthers, { from: owner }).should.be.fulfilled
|
||||
await erc677Token.transferOwnership(foreignBridge.address)
|
||||
await erc677Token.mint(user, twoEthers, { from: owner }).should.be.fulfilled
|
||||
await erc677Token.transfer(foreignBridge.address, oneEther, { from: user }).should.be.fulfilled
|
||||
await erc677Token.transfer(foreignBridge.address, oneEther, { from: user }).should.be.fulfilled
|
||||
|
||||
const currentDay = await foreignBridge.getCurrentDay()
|
||||
expect(await foreignBridge.totalExecutedPerDay(currentDay)).to.be.bignumber.equal(ZERO)
|
||||
const initialEvents = await getEvents(erc677Token, { event: 'Transfer' })
|
||||
expect(initialEvents.length).to.be.equal(0)
|
||||
expect(await erc677Token.balanceOf(foreignBridge.address)).to.be.bignumber.equal(twoEthers)
|
||||
expect(await foreignBridge.mediatorBalance()).to.be.bignumber.equal(twoEthers)
|
||||
expect(await erc677Token.balanceOf(user)).to.be.bignumber.equal(ZERO)
|
||||
|
||||
const valueOnForeign = toBN('1000')
|
||||
|
@ -242,6 +249,7 @@ contract('ForeignAMBErc677ToErc677', async accounts => {
|
|||
// Then
|
||||
expect(await foreignBridge.totalExecutedPerDay(currentDay)).to.be.bignumber.equal(valueOnHome)
|
||||
expect(await erc677Token.balanceOf(foreignBridge.address)).to.be.bignumber.equal(twoEthers.sub(valueOnForeign))
|
||||
expect(await foreignBridge.mediatorBalance()).to.be.bignumber.equal(twoEthers.sub(valueOnForeign))
|
||||
expect(await erc677Token.balanceOf(user)).to.be.bignumber.equal(valueOnForeign)
|
||||
|
||||
const TokensBridgedEvent = await getEvents(foreignBridge, { event: 'TokensBridged' })
|
||||
|
@ -258,6 +266,7 @@ contract('ForeignAMBErc677ToErc677', async accounts => {
|
|||
const initialEvents = await getEvents(erc677Token, { event: 'Transfer' })
|
||||
expect(initialEvents.length).to.be.equal(0)
|
||||
expect(await erc677Token.balanceOf(foreignBridge.address)).to.be.bignumber.equal(twoEthers)
|
||||
expect(await foreignBridge.mediatorBalance()).to.be.bignumber.equal(twoEthers)
|
||||
expect(await erc677Token.balanceOf(user)).to.be.bignumber.equal(ZERO)
|
||||
|
||||
const outOfLimitValueData = await foreignBridge.contract.methods
|
||||
|
@ -278,6 +287,7 @@ contract('ForeignAMBErc677ToErc677', async accounts => {
|
|||
// Then
|
||||
expect(await foreignBridge.totalExecutedPerDay(currentDay)).to.be.bignumber.equal(ZERO)
|
||||
expect(await erc677Token.balanceOf(foreignBridge.address)).to.be.bignumber.equal(twoEthers)
|
||||
expect(await foreignBridge.mediatorBalance()).to.be.bignumber.equal(twoEthers)
|
||||
expect(await erc677Token.balanceOf(user)).to.be.bignumber.equal(ZERO)
|
||||
|
||||
expect(await foreignBridge.outOfLimitAmount()).to.be.bignumber.equal(twoEthers)
|
||||
|
@ -291,4 +301,186 @@ contract('ForeignAMBErc677ToErc677', async accounts => {
|
|||
expect(TokensBridgedEvent.length).to.be.equal(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe('fixFailedMessage', () => {
|
||||
it('should update mediatorBalance ', async () => {
|
||||
ambBridgeContract = await AMBMock.new()
|
||||
await ambBridgeContract.setMaxGasPerTx(maxGasPerTx)
|
||||
mediatorContract = await HomeAMBErc677ToErc677.new()
|
||||
erc677Token = await ERC677BridgeToken.new('test', 'TST', 18)
|
||||
await erc677Token.mint(user, twoEthers, { from: owner }).should.be.fulfilled
|
||||
|
||||
foreignBridge = await ForeignAMBErc677ToErc677.new()
|
||||
|
||||
await foreignBridge.initialize(
|
||||
ambBridgeContract.address,
|
||||
mediatorContract.address,
|
||||
erc677Token.address,
|
||||
[dailyLimit, maxPerTx, minPerTx],
|
||||
[executionDailyLimit, executionMaxPerTx],
|
||||
maxGasPerTx,
|
||||
decimalShiftZero,
|
||||
owner
|
||||
).should.be.fulfilled
|
||||
await erc677Token.transferOwnership(foreignBridge.address)
|
||||
|
||||
expect(await erc677Token.balanceOf(user)).to.be.bignumber.equal(twoEthers)
|
||||
expect(await erc677Token.totalSupply()).to.be.bignumber.equal(twoEthers)
|
||||
|
||||
// User transfer tokens
|
||||
await erc677Token.transferAndCall(foreignBridge.address, oneEther, '0x', { from: user }).should.be.fulfilled
|
||||
|
||||
expect(await erc677Token.balanceOf(user)).to.be.bignumber.equal(oneEther)
|
||||
expect(await foreignBridge.mediatorBalance()).to.be.bignumber.equal(oneEther)
|
||||
|
||||
const events = await getEvents(ambBridgeContract, { event: 'MockedEvent' })
|
||||
expect(events.length).to.be.equal(1)
|
||||
const transferMessageId = events[0].returnValues.messageId
|
||||
// Given
|
||||
expect(await foreignBridge.messageFixed(transferMessageId)).to.be.equal(false)
|
||||
|
||||
// When
|
||||
const fixData = await foreignBridge.contract.methods.fixFailedMessage(transferMessageId).encodeABI()
|
||||
await ambBridgeContract.executeMessageCall(
|
||||
foreignBridge.address,
|
||||
mediatorContract.address,
|
||||
fixData,
|
||||
exampleMessageId,
|
||||
1000000
|
||||
).should.be.fulfilled
|
||||
|
||||
// Then
|
||||
expect(await ambBridgeContract.messageCallStatus(exampleMessageId)).to.be.equal(true)
|
||||
expect(await foreignBridge.mediatorBalance()).to.be.bignumber.equal(ZERO)
|
||||
expect(await erc677Token.balanceOf(user)).to.be.bignumber.equal(twoEthers)
|
||||
expect(await erc677Token.totalSupply()).to.be.bignumber.equal(twoEthers)
|
||||
expect(await foreignBridge.messageFixed(transferMessageId)).to.be.equal(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('fixMediatorBalance', () => {
|
||||
let currentDay
|
||||
beforeEach(async () => {
|
||||
const storageProxy = await EternalStorageProxy.new()
|
||||
foreignBridge = await ForeignAMBErc677ToErc677.new()
|
||||
await storageProxy.upgradeTo('1', foreignBridge.address).should.be.fulfilled
|
||||
foreignBridge = await ForeignAMBErc677ToErc677.at(storageProxy.address)
|
||||
|
||||
erc677Token = await ERC677BridgeToken.new('test', 'TST', 18)
|
||||
await erc677Token.mint(user, twoEthers, { from: owner }).should.be.fulfilled
|
||||
await erc677Token.mint(foreignBridge.address, twoEthers, { from: owner }).should.be.fulfilled
|
||||
|
||||
ambBridgeContract = await AMBMock.new()
|
||||
await ambBridgeContract.setMaxGasPerTx(maxGasPerTx)
|
||||
await foreignBridge.initialize(
|
||||
ambBridgeContract.address,
|
||||
mediatorContract.address,
|
||||
erc677Token.address,
|
||||
[dailyLimit, maxPerTx, minPerTx],
|
||||
[executionDailyLimit, executionMaxPerTx],
|
||||
maxGasPerTx,
|
||||
decimalShiftZero,
|
||||
owner
|
||||
).should.be.fulfilled
|
||||
|
||||
currentDay = await foreignBridge.getCurrentDay()
|
||||
expect(await foreignBridge.totalSpentPerDay(currentDay)).to.be.bignumber.equal(ZERO)
|
||||
const initialEvents = await getEvents(ambBridgeContract, { event: 'MockedEvent' })
|
||||
expect(initialEvents.length).to.be.equal(0)
|
||||
})
|
||||
|
||||
it('should allow to fix extra mediator balance', async () => {
|
||||
expect(await foreignBridge.mediatorBalance()).to.be.bignumber.equal(ZERO)
|
||||
expect(await erc677Token.balanceOf(foreignBridge.address)).to.be.bignumber.equal(twoEthers)
|
||||
|
||||
await erc677Token.transferAndCall(foreignBridge.address, halfEther, '0x', { from: user }).should.be.fulfilled
|
||||
await foreignBridge.setDailyLimit(ether('3')).should.be.fulfilled
|
||||
await foreignBridge.setMaxPerTx(twoEthers).should.be.fulfilled
|
||||
|
||||
expect(await foreignBridge.mediatorBalance()).to.be.bignumber.equal(halfEther)
|
||||
expect(await erc677Token.balanceOf(foreignBridge.address)).to.be.bignumber.equal(twoEthers.add(halfEther))
|
||||
expect(await foreignBridge.totalSpentPerDay(currentDay)).to.be.bignumber.equal(halfEther)
|
||||
let events = await getEvents(ambBridgeContract, { event: 'MockedEvent' })
|
||||
expect(events.length).to.be.equal(1)
|
||||
|
||||
await foreignBridge.fixMediatorBalance(owner, { from: user }).should.be.rejected
|
||||
await foreignBridge.fixMediatorBalance(ZERO_ADDRESS, { from: owner }).should.be.rejected
|
||||
await foreignBridge.fixMediatorBalance(owner, { from: owner }).should.be.fulfilled
|
||||
await foreignBridge.fixMediatorBalance(owner, { from: owner }).should.be.rejected
|
||||
|
||||
expect(await foreignBridge.mediatorBalance()).to.be.bignumber.equal(twoEthers.add(halfEther))
|
||||
expect(await erc677Token.balanceOf(foreignBridge.address)).to.be.bignumber.equal(twoEthers.add(halfEther))
|
||||
|
||||
expect(await foreignBridge.totalSpentPerDay(currentDay)).to.be.bignumber.equal(twoEthers.add(halfEther))
|
||||
events = await getEvents(ambBridgeContract, { event: 'MockedEvent' })
|
||||
expect(events.length).to.be.equal(2)
|
||||
})
|
||||
|
||||
it('should allow to fix extra mediator balance with respect to limits', async () => {
|
||||
expect(await foreignBridge.mediatorBalance()).to.be.bignumber.equal(ZERO)
|
||||
expect(await erc677Token.balanceOf(foreignBridge.address)).to.be.bignumber.equal(twoEthers)
|
||||
|
||||
await erc677Token.transferAndCall(foreignBridge.address, halfEther, '0x', { from: user }).should.be.fulfilled
|
||||
await foreignBridge.setMinPerTx('1').should.be.fulfilled
|
||||
await foreignBridge.setMaxPerTx(halfEther).should.be.fulfilled
|
||||
await foreignBridge.setDailyLimit(ether('1.25')).should.be.fulfilled
|
||||
|
||||
expect(await foreignBridge.mediatorBalance()).to.be.bignumber.equal(halfEther)
|
||||
expect(await erc677Token.balanceOf(foreignBridge.address)).to.be.bignumber.equal(twoEthers.add(halfEther))
|
||||
expect(await foreignBridge.totalSpentPerDay(currentDay)).to.be.bignumber.equal(halfEther)
|
||||
let events = await getEvents(ambBridgeContract, { event: 'MockedEvent' })
|
||||
expect(events.length).to.be.equal(1)
|
||||
|
||||
await foreignBridge.fixMediatorBalance(owner, { from: user }).should.be.rejected
|
||||
// should fix 0.5 ether
|
||||
await foreignBridge.fixMediatorBalance(owner, { from: owner }).should.be.fulfilled
|
||||
|
||||
expect(await foreignBridge.mediatorBalance()).to.be.bignumber.equal(oneEther)
|
||||
expect(await foreignBridge.totalSpentPerDay(currentDay)).to.be.bignumber.equal(oneEther)
|
||||
|
||||
// should fix 0.25 ether
|
||||
await foreignBridge.fixMediatorBalance(owner, { from: owner }).should.be.fulfilled
|
||||
// no remaining daily quota
|
||||
await foreignBridge.fixMediatorBalance(owner, { from: owner }).should.be.rejected
|
||||
|
||||
await foreignBridge.setDailyLimit(oneEther).should.be.fulfilled
|
||||
|
||||
// no remaining daily quota
|
||||
await foreignBridge.fixMediatorBalance(owner, { from: owner }).should.be.rejected
|
||||
|
||||
expect(await foreignBridge.mediatorBalance()).to.be.bignumber.equal(ether('1.25'))
|
||||
expect(await foreignBridge.totalSpentPerDay(currentDay)).to.be.bignumber.equal(ether('1.25'))
|
||||
|
||||
expect(await erc677Token.balanceOf(foreignBridge.address)).to.be.bignumber.equal(twoEthers.add(halfEther))
|
||||
events = await getEvents(ambBridgeContract, { event: 'MockedEvent' })
|
||||
expect(events.length).to.be.equal(3)
|
||||
})
|
||||
})
|
||||
|
||||
describe('claimTokens', () => {
|
||||
it('should not allow to claim bridged token', async () => {
|
||||
const storageProxy = await EternalStorageProxy.new()
|
||||
foreignBridge = await ForeignAMBErc677ToErc677.new()
|
||||
await storageProxy.upgradeTo('1', foreignBridge.address).should.be.fulfilled
|
||||
foreignBridge = await ForeignAMBErc677ToErc677.at(storageProxy.address)
|
||||
erc677Token = await ERC677BridgeToken.new('test', 'TST', 18)
|
||||
await erc677Token.mint(foreignBridge.address, twoEthers, { from: owner }).should.be.fulfilled
|
||||
|
||||
ambBridgeContract = await AMBMock.new()
|
||||
await ambBridgeContract.setMaxGasPerTx(maxGasPerTx)
|
||||
await foreignBridge.initialize(
|
||||
ambBridgeContract.address,
|
||||
mediatorContract.address,
|
||||
erc677Token.address,
|
||||
[dailyLimit, maxPerTx, minPerTx],
|
||||
[executionDailyLimit, executionMaxPerTx],
|
||||
maxGasPerTx,
|
||||
decimalShiftZero,
|
||||
owner
|
||||
).should.be.fulfilled
|
||||
|
||||
await foreignBridge.claimTokens(erc677Token.address, accounts[3], { from: accounts[3] }).should.be.rejected
|
||||
await foreignBridge.claimTokens(erc677Token.address, accounts[3], { from: owner }).should.be.rejected
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1442,6 +1442,8 @@ contract('HomeAMBNativeToErc20', async accounts => {
|
|||
// only owner can call the method
|
||||
await contract.fixMediatorBalance(user, { from: user }).should.be.rejectedWith(ERROR_MSG)
|
||||
|
||||
await contract.fixMediatorBalance(ZERO_ADDRESS, { from: owner }).should.be.rejected
|
||||
|
||||
await contract.fixMediatorBalance(user, { from: owner }).should.be.fulfilled
|
||||
|
||||
// imbalance was already fixed
|
||||
|
|
|
@ -865,6 +865,7 @@ contract('ForeignMultiAMBErc20ToErc677', async accounts => {
|
|||
|
||||
await contract.fixMediatorBalance(token.address, owner, { from: user }).should.be.rejected
|
||||
await contract.fixMediatorBalance(ZERO_ADDRESS, owner, { from: owner }).should.be.rejected
|
||||
await contract.fixMediatorBalance(token.address, ZERO_ADDRESS, { from: owner }).should.be.rejected
|
||||
await contract.fixMediatorBalance(token.address, owner, { from: owner }).should.be.fulfilled
|
||||
await contract.fixMediatorBalance(token.address, owner, { from: owner }).should.be.rejected
|
||||
|
||||
|
|
|
@ -1083,7 +1083,7 @@ contract('HomeBridge', async accounts => {
|
|||
expect(await tokenMock.balanceOf(homeBridge.address)).to.be.bignumber.equal(ZERO)
|
||||
expect(await tokenMock.balanceOf(accounts[3])).to.be.bignumber.equal(halfEther)
|
||||
})
|
||||
it('should work for native coins', async () => {
|
||||
it('should not work for native coins', async () => {
|
||||
const storageProxy = await EternalStorageProxy.new()
|
||||
const data = homeContract.contract.methods
|
||||
.initialize(
|
||||
|
@ -1099,14 +1099,11 @@ contract('HomeBridge', async accounts => {
|
|||
await storageProxy.upgradeToAndCall('1', homeContract.address, data).should.be.fulfilled
|
||||
const homeBridge = await HomeBridge.at(storageProxy.address)
|
||||
|
||||
const balanceBefore = toBN(await web3.eth.getBalance(accounts[3]))
|
||||
|
||||
await homeBridge.sendTransaction({ from: accounts[2], value: halfEther }).should.be.fulfilled
|
||||
expect(toBN(await web3.eth.getBalance(homeBridge.address))).to.be.bignumber.equal(halfEther)
|
||||
|
||||
await homeBridge.claimTokens(ZERO_ADDRESS, accounts[3], { from: owner }).should.be.fulfilled
|
||||
expect(toBN(await web3.eth.getBalance(homeBridge.address))).to.be.bignumber.equal(ZERO)
|
||||
expect(toBN(await web3.eth.getBalance(accounts[3]))).to.be.bignumber.equal(balanceBefore.add(halfEther))
|
||||
await homeBridge.claimTokens(ZERO_ADDRESS, accounts[3], { from: accounts[3] }).should.be.rejected
|
||||
await homeBridge.claimTokens(ZERO_ADDRESS, accounts[3], { from: owner }).should.be.rejected
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
const ForeignStakeTokenMediator = artifacts.require('ForeignStakeTokenMediator.sol')
|
||||
const HomeStakeTokenMediator = artifacts.require('HomeStakeTokenMediator.sol')
|
||||
const EternalStorageProxy = artifacts.require('EternalStorageProxy.sol')
|
||||
const ERC677BridgeToken = artifacts.require('ERC677BridgeToken.sol')
|
||||
const AMBMock = artifacts.require('AMBMock.sol')
|
||||
|
||||
|
@ -263,4 +264,28 @@ contract('ForeignStakeTokenMediator', async accounts => {
|
|||
await token.transferAndCall(foreignMediator.address, halfEther, user, { from: user }).should.be.fulfilled
|
||||
})
|
||||
})
|
||||
|
||||
describe('claimTokens', () => {
|
||||
it('should not allow to claim bridged token', async () => {
|
||||
const storageProxy = await EternalStorageProxy.new()
|
||||
await storageProxy.upgradeTo('1', foreignMediator.address).should.be.fulfilled
|
||||
foreignMediator = await ForeignStakeTokenMediator.at(storageProxy.address)
|
||||
token = await ERC677BridgeToken.new('test', 'TST', 18)
|
||||
await token.mint(foreignMediator.address, twoEthers, { from: owner }).should.be.fulfilled
|
||||
|
||||
await foreignMediator.initialize(
|
||||
foreignBridge.address,
|
||||
homeMediator.address,
|
||||
token.address,
|
||||
[dailyLimit, maxPerTx, minPerTx],
|
||||
[executionDailyLimit, executionMaxPerTx],
|
||||
maxGasPerTx,
|
||||
decimalShiftZero,
|
||||
owner
|
||||
).should.be.fulfilled
|
||||
|
||||
await foreignMediator.claimTokens(token.address, accounts[3], { from: accounts[3] }).should.be.rejected
|
||||
await foreignMediator.claimTokens(token.address, accounts[3], { from: owner }).should.be.rejected
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue