Skip to content

Commit

Permalink
Extra check for balance increase (#479)
Browse files Browse the repository at this point in the history
  • Loading branch information
k1rill-fedoseev authored Aug 29, 2020
1 parent 2820a03 commit 3f1f04d
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 13 deletions.
49 changes: 49 additions & 0 deletions contracts/libraries/SafeERC20.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
pragma solidity 0.4.24;

import "openzeppelin-solidity/contracts/math/SafeMath.sol";
import "../interfaces/ERC677.sol";

/**
* @title SafeERC20
* @dev Helper methods for safe token transfers.
* Functions perform additional checks to be sure that token transfer really happened.
*/
library SafeERC20 {
using SafeMath for uint256;

/**
* @dev Same as ERC20.transfer(address,uint256) but with extra consistency checks.
* @param _token address of the token contract
* @param _to address of the receiver
* @param _value amount of tokens to send
*/
function safeTransfer(address _token, address _to, uint256 _value) internal {
LegacyERC20(_token).transfer(_to, _value);
assembly {
if returndatasize {
returndatacopy(0, 0, 32)
if iszero(mload(0)) {
revert(0, 0)
}
}
}
}

/**
* @dev Same as ERC20.transferFrom(address,address,uint256) but with extra consistency checks.
* @param _token address of the token contract
* @param _from address of the sender
* @param _value amount of tokens to send
*/
function safeTransferFrom(address _token, address _from, uint256 _value) internal {
LegacyERC20(_token).transferFrom(_from, address(this), _value);
assembly {
if returndatasize {
returndatacopy(0, 0, 32)
if iszero(mload(0)) {
revert(0, 0)
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ contract BasicAMBErc20ToNative is Initializable, Upgradeable, Claimable, Version
* @return patch value of the version
*/
function getBridgeInterfacesVersion() external pure returns (uint64 major, uint64 minor, uint64 patch) {
return (1, 1, 0);
return (1, 1, 1);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ pragma solidity 0.4.24;
import "./BasicAMBErc20ToNative.sol";
import "../BaseERC677Bridge.sol";
import "../ReentrancyGuard.sol";
import "../../libraries/SafeERC20.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 {
using SafeERC20 for ERC677;

bytes32 internal constant MEDIATOR_BALANCE = 0x3db340e280667ee926fa8c51e8f9fcf88a0ff221a66d84d63b4778127d97d139; // keccak256(abi.encodePacked("mediatorBalance"))

/**
Expand Down Expand Up @@ -70,13 +73,12 @@ contract ForeignAMBErc20ToNative is BasicAMBErc20ToNative, ReentrancyGuard, Base
// which will call passMessage.
require(!lock());
ERC677 token = _erc677token();
address to = address(this);
require(withinLimit(_value));
addTotalSpentPerDay(getCurrentDay(), _value);
_setMediatorBalance(mediatorBalance().add(_value));

setLock(true);
token.transferFrom(msg.sender, to, _value);
token.safeTransferFrom(msg.sender, _value);
setLock(false);
bridgeSpecificActionsOnTokenTransfer(token, msg.sender, _value, abi.encodePacked(_receiver));
}
Expand Down Expand Up @@ -150,7 +152,7 @@ contract ForeignAMBErc20ToNative is BasicAMBErc20ToNative, ReentrancyGuard, Base
bytes32 _messageId = messageId();

_setMediatorBalance(mediatorBalance().sub(valueToTransfer));
_erc677token().transfer(_receiver, valueToTransfer);
_erc677token().safeTransfer(_receiver, valueToTransfer);
emit TokensBridged(_receiver, valueToTransfer, _messageId);
}

Expand All @@ -161,7 +163,7 @@ contract ForeignAMBErc20ToNative is BasicAMBErc20ToNative, ReentrancyGuard, Base
*/
function executeActionOnFixedTokens(address _receiver, uint256 _value) internal {
_setMediatorBalance(mediatorBalance().sub(_value));
_erc677token().transfer(_receiver, _value);
_erc677token().safeTransfer(_receiver, _value);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ contract BasicAMBErc677ToErc677 is
return mediatorContractOnOtherSide();
}

/**
* @dev Initiates the bridge operation that will lock the amount of tokens transferred and mint the tokens on
* the other network. The user should first call Approve method of the ERC677 token.
* @param _receiver address that will receive the minted tokens on the other network.
* @param _value amount of tokens to be transferred to the other network.
*/
function relayTokens(address _receiver, uint256 _value) external {
// This lock is to prevent calling passMessage twice if a ERC677 token is used.
// When transferFrom is called, after the transfer, the ERC677 token will call onTokenTransfer from this contract
Expand Down Expand Up @@ -90,7 +96,7 @@ contract BasicAMBErc677ToErc677 is
}

function getBridgeInterfacesVersion() external pure returns (uint64 major, uint64 minor, uint64 patch) {
return (1, 2, 0);
return (1, 2, 1);
}

function getBridgeMode() external pure returns (bytes4 _data) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
pragma solidity 0.4.24;

import "./BasicAMBErc677ToErc677.sol";
import "../../libraries/SafeERC20.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 {
using SafeERC20 for ERC677;

/**
* @dev Executes action on the request to withdraw tokens relayed from the other network
* @param _recipient address of tokens receiver
Expand All @@ -16,10 +19,31 @@ contract ForeignAMBErc677ToErc677 is BasicAMBErc677ToErc677 {
function executeActionOnBridgedTokens(address _recipient, uint256 _value) internal {
uint256 value = _unshiftValue(_value);
bytes32 _messageId = messageId();
erc677token().transfer(_recipient, value);
erc677token().safeTransfer(_recipient, value);
emit TokensBridged(_recipient, value, _messageId);
}

/**
* @dev Initiates the bridge operation that will lock the amount of tokens transferred and mint the tokens on
* the other network. The user should first call Approve method of the ERC677 token.
* @param _receiver address that will receive the minted tokens on the other network.
* @param _value amount of tokens to be transferred to the other network.
*/
function relayTokens(address _receiver, uint256 _value) external {
// This lock is to prevent calling passMessage twice if a ERC677 token is used.
// When transferFrom is called, after the transfer, the ERC677 token will call onTokenTransfer from this contract
// which will call passMessage.
require(!lock());
ERC677 token = erc677token();
require(withinLimit(_value));
addTotalSpentPerDay(getCurrentDay(), _value);

setLock(true);
token.safeTransferFrom(msg.sender, _value);
setLock(false);
bridgeSpecificActionsOnTokenTransfer(token, msg.sender, _value, abi.encodePacked(_receiver));
}

/**
* @dev Executes action on deposit of bridged tokens
* @param _from address of tokens sender
Expand All @@ -38,6 +62,6 @@ contract ForeignAMBErc677ToErc677 is BasicAMBErc677ToErc677 {
}

function executeActionOnFixedTokens(address _recipient, uint256 _value) internal {
erc677token().transfer(_recipient, _value);
erc677token().safeTransfer(_recipient, _value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ contract BasicMultiAMBErc20ToErc677 is
* @return patch value of the version
*/
function getBridgeInterfacesVersion() external pure returns (uint64 major, uint64 minor, uint64 patch) {
return (1, 1, 0);
return (1, 1, 1);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ import "openzeppelin-solidity/contracts/token/ERC20/DetailedERC20.sol";
import "./BasicMultiAMBErc20ToErc677.sol";
import "./HomeMultiAMBErc20ToErc677.sol";
import "../../libraries/TokenReader.sol";
import "../../libraries/SafeERC20.sol";

/**
* @title ForeignMultiAMBErc20ToErc677
* @dev Foreign side implementation for multi-erc20-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 ForeignMultiAMBErc20ToErc677 is BasicMultiAMBErc20ToErc677 {
using SafeERC20 for address;
using SafeERC20 for ERC677;

/**
* @dev Stores the initial parameters of the mediator.
* @param _bridgeContract the address of the AMB bridge contract.
Expand Down Expand Up @@ -53,7 +57,7 @@ contract ForeignMultiAMBErc20ToErc677 is BasicMultiAMBErc20ToErc677 {
*/
function executeActionOnBridgedTokens(address _token, address _recipient, uint256 _value) internal {
bytes32 _messageId = messageId();
LegacyERC20(_token).transfer(_recipient, _value);
_token.safeTransfer(_recipient, _value);
_setMediatorBalance(_token, mediatorBalance(_token).sub(_value));
emit TokensBridged(_token, _recipient, _value, _messageId);
}
Expand Down Expand Up @@ -97,10 +101,9 @@ contract ForeignMultiAMBErc20ToErc677 is BasicMultiAMBErc20ToErc677 {
// When transferFrom is called, after the transfer, the ERC677 token will call onTokenTransfer from this contract
// which will call passMessage.
require(!lock());
address to = address(this);

setLock(true);
LegacyERC20(token).transferFrom(msg.sender, to, _value);
token.safeTransferFrom(msg.sender, _value);
setLock(false);
bridgeSpecificActionsOnTokenTransfer(token, msg.sender, _value, abi.encodePacked(_receiver));
}
Expand Down Expand Up @@ -189,7 +192,7 @@ contract ForeignMultiAMBErc20ToErc677 is BasicMultiAMBErc20ToErc677 {
*/
function executeActionOnFixedTokens(address _token, address _recipient, uint256 _value) internal {
_setMediatorBalance(_token, mediatorBalance(_token).sub(_value));
LegacyERC20(_token).transfer(_recipient, _value);
_token.safeTransfer(_recipient, _value);
}

/**
Expand Down

0 comments on commit 3f1f04d

Please sign in to comment.