Skip to content

Commit e4001c9

Browse files
authored
Merge branch 'develop' into feature/new-token-contracts
2 parents 9771856 + af4a8d6 commit e4001c9

16 files changed

+111
-58
lines changed

contracts/helpers/WETHOmnibridgeRouter.sol

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ pragma solidity 0.7.5;
33
import "../interfaces/IOmnibridge.sol";
44
import "../interfaces/IWETH.sol";
55
import "../libraries/AddressHelper.sol";
6+
import "../libraries/Bytes.sol";
67
import "../upgradeable_contracts/modules/OwnableModule.sol";
78
import "../upgradeable_contracts/Claimable.sol";
89

@@ -62,19 +63,15 @@ contract WETHOmnibridgeRouter is OwnableModule, Claimable {
6263
function onTokenBridged(
6364
address _token,
6465
uint256 _value,
65-
bytes calldata _data
66+
bytes memory _data
6667
) external {
6768
require(_token == address(WETH));
6869
require(msg.sender == address(bridge));
6970
require(_data.length == 20);
7071

7172
WETH.withdraw(_value);
7273

73-
address payable receiver;
74-
assembly {
75-
receiver := calldataload(120)
76-
}
77-
AddressHelper.safeSendValue(receiver, _value);
74+
AddressHelper.safeSendValue(payable(Bytes.bytesToAddress(_data)), _value);
7875
}
7976

8077
/**

contracts/libraries/SafeMint.sol

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
pragma solidity 0.7.5;
2+
3+
import "../interfaces/IBurnableMintableERC677Token.sol";
4+
5+
/**
6+
* @title SafeMint
7+
* @dev Wrapper around the mint() function in all mintable tokens that verifies the return value.
8+
*/
9+
library SafeMint {
10+
/**
11+
* @dev Wrapper around IBurnableMintableERC677Token.mint() that verifies that output value is true.
12+
* @param _token token contract.
13+
* @param _to address of the tokens receiver.
14+
* @param _value amount of tokens to mint.
15+
*/
16+
function safeMint(
17+
IBurnableMintableERC677Token _token,
18+
address _to,
19+
uint256 _value
20+
) internal {
21+
require(_token.mint(_to, _value));
22+
}
23+
}

contracts/libraries/TokenReader.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,15 @@ library TokenReader {
5858
* @param _token address of the token contract.
5959
* @return token decimals or 0 if none of the methods succeeded.
6060
*/
61-
function readDecimals(address _token) internal view returns (uint256) {
61+
function readDecimals(address _token) internal view returns (uint8) {
6262
(bool status, bytes memory data) = _token.staticcall(abi.encodeWithSelector(ITokenDetails.decimals.selector));
6363
if (!status) {
6464
(status, data) = _token.staticcall(abi.encodeWithSelector(ITokenDetails.DECIMALS.selector));
6565
if (!status) {
6666
return 0;
6767
}
6868
}
69-
return abi.decode(data, (uint256));
69+
return abi.decode(data, (uint8));
7070
}
7171

7272
/**

contracts/upgradeability/OwnedUpgradeabilityProxy.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ contract OwnedUpgradeabilityProxy is UpgradeabilityOwnerStorage, UpgradeabilityP
5454
* to initialize whatever is needed through a low level call.
5555
* @param version representing the version name of the new implementation to be set.
5656
* @param implementation representing the address of the new implementation to be set.
57-
* @param data represents the msg.data to bet sent in the low level call. This parameter may include the function
57+
* @param data represents the msg.data to be sent in the low level call. This parameter may include the function
5858
* signature of the implementation to be called with the needed payload
5959
*/
6060
function upgradeToAndCall(

contracts/upgradeability/UpgradeabilityProxy.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ contract UpgradeabilityProxy is Proxy, UpgradeabilityStorage {
3535
// This additional check verifies that provided implementation is at least a contract
3636
require(Address.isContract(implementation));
3737

38-
// This additional check guarantees that new version will be at least greater than the privios one,
38+
// This additional check guarantees that new version will be at least greater than the previous one,
3939
// so it is impossible to reuse old versions, or use the last version twice
4040
require(version > _version);
4141

contracts/upgradeable_contracts/BasicOmnibridge.sol

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import "../interfaces/IClaimable.sol";
1717
import "../interfaces/IERC20Metadata.sol";
1818
import "../interfaces/IERC20Receiver.sol";
1919
import "../libraries/TokenReader.sol";
20+
import "../libraries/SafeMint.sol";
2021

2122
/**
2223
* @title BasicOmnibridge
@@ -36,6 +37,7 @@ abstract contract BasicOmnibridge is
3637
TokensBridgeLimits
3738
{
3839
using SafeERC20 for IERC677;
40+
using SafeMint for IBurnableMintableERC677Token;
3941
using SafeMath for uint256;
4042

4143
// Workaround for storing variable up-to-32 bytes suffix
@@ -219,8 +221,13 @@ abstract contract BasicOmnibridge is
219221
require(!isTokenRegistered(_bridgedToken));
220222
require(nativeTokenAddress(_bridgedToken) == address(0));
221223
require(bridgedTokenAddress(_nativeToken) == address(0));
224+
// Unfortunately, there is no simple way to verify that the _nativeToken address
225+
// does not belong to the bridged token on the other side,
226+
// since information about bridged tokens addresses is not transferred back.
227+
// Therefore, owner account calling this function SHOULD manually verify on the other side of the bridge that
228+
// nativeTokenAddress(_nativeToken) == address(0) && isTokenRegistered(_nativeToken) == false.
222229

223-
IBurnableMintableERC677Token(_bridgedToken).mint(address(this), 1);
230+
IBurnableMintableERC677Token(_bridgedToken).safeMint(address(this), 1);
224231
IBurnableMintableERC677Token(_bridgedToken).burn(1);
225232

226233
_setTokenAddressPair(_nativeToken, _bridgedToken);
@@ -230,6 +237,9 @@ abstract contract BasicOmnibridge is
230237
* @dev Allows to send to the other network the amount of locked tokens that can be forced into the contract
231238
* without the invocation of the required methods. (e. g. regular transfer without a call to onTokenTransfer)
232239
* @param _token address of the token contract.
240+
* Before calling this method, it must be carefully investigated how imbalance happened
241+
* in order to avoid an attempt to steal the funds from a token with double addresses
242+
* (e.g. TUSD is accessible at both 0x8dd5fbCe2F6a956C3022bA3663759011Dd51e73E and 0x0000000000085d4780B73119b644AE5ecd22b376)
233243
* @param _receiver the address that will receive the tokens on the other network.
234244
*/
235245
function fixMediatorBalance(address _token, address _receiver)
@@ -250,8 +260,7 @@ abstract contract BasicOmnibridge is
250260
}
251261
addTotalSpentPerDay(_token, getCurrentDay(), diff);
252262

253-
uint8 decimals = uint8(TokenReader.readDecimals(_token));
254-
bytes memory data = _prepareMessage(address(0), _token, _receiver, diff, decimals, new bytes(0));
263+
bytes memory data = _prepareMessage(address(0), _token, _receiver, diff, new bytes(0));
255264
bytes32 _messageId = _passMessage(data, true);
256265
_recordBridgeOperation(_messageId, _token, _receiver, diff);
257266
}
@@ -310,15 +319,13 @@ abstract contract BasicOmnibridge is
310319
* @param _token bridged token address.
311320
* @param _receiver address of the tokens receiver on the other side.
312321
* @param _value bridged value.
313-
* @param _decimals token decimals parameter.
314322
* @param _data additional transfer data passed from the other side.
315323
*/
316324
function _prepareMessage(
317325
address _nativeToken,
318326
address _token,
319327
address _receiver,
320328
uint256 _value,
321-
uint8 _decimals,
322329
bytes memory _data
323330
) internal returns (bytes memory) {
324331
bool withData = _data.length > 0 || msg.sig == this.relayTokensAndCall.selector;
@@ -341,6 +348,7 @@ abstract contract BasicOmnibridge is
341348
: abi.encodeWithSelector(this.handleBridgedTokens.selector, _token, _receiver, _value);
342349
}
343350

351+
uint8 decimals = TokenReader.readDecimals(_token);
344352
string memory name = TokenReader.readName(_token);
345353
string memory symbol = TokenReader.readSymbol(_token);
346354

@@ -353,7 +361,7 @@ abstract contract BasicOmnibridge is
353361
_token,
354362
name,
355363
symbol,
356-
_decimals,
364+
decimals,
357365
_receiver,
358366
_value,
359367
_data
@@ -363,7 +371,7 @@ abstract contract BasicOmnibridge is
363371
_token,
364372
name,
365373
symbol,
366-
_decimals,
374+
decimals,
367375
_receiver,
368376
_value
369377
);
@@ -388,7 +396,7 @@ abstract contract BasicOmnibridge is
388396
* @param _token address of the token to mint.
389397
* @return address of the minter contract that should be used for calling mint(address,uint256)
390398
*/
391-
function _getMinterFor(address _token) internal view virtual returns (IBurnableMintableERC677Token) {
399+
function _getMinterFor(address _token) internal pure virtual returns (IBurnableMintableERC677Token) {
392400
return IBurnableMintableERC677Token(_token);
393401
}
394402

@@ -411,7 +419,7 @@ abstract contract BasicOmnibridge is
411419
IERC677(_token).safeTransfer(_recipient, _value);
412420
_setMediatorBalance(_token, mediatorBalance(_token).sub(_balanceChange));
413421
} else {
414-
_getMinterFor(_token).mint(_recipient, _value);
422+
_getMinterFor(_token).safeMint(_recipient, _value);
415423
}
416424
}
417425

contracts/upgradeable_contracts/Claimable.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ contract Claimable {
4242
}
4343

4444
/**
45-
* @dev Internal function for withdrawing all tokens of ssome particular ERC20 contract from this contract.
45+
* @dev Internal function for withdrawing all tokens of some particular ERC20 contract from this contract.
4646
* @param _token address of the claimed ERC20 token.
4747
* @param _to address of the tokens receiver.
4848
*/

contracts/upgradeable_contracts/ForeignOmnibridge.sol

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ pragma solidity 0.7.5;
22

33
import "./BasicOmnibridge.sol";
44
import "./components/common/GasLimitManager.sol";
5+
import "../libraries/SafeMint.sol";
56

67
/**
78
* @title ForeignOmnibridge
@@ -10,6 +11,7 @@ import "./components/common/GasLimitManager.sol";
1011
*/
1112
contract ForeignOmnibridge is BasicOmnibridge, GasLimitManager {
1213
using SafeERC20 for IERC677;
14+
using SafeMint for IBurnableMintableERC677Token;
1315
using SafeMath for uint256;
1416

1517
constructor(string memory _suffix) BasicOmnibridge(_suffix) {}
@@ -75,6 +77,10 @@ contract ForeignOmnibridge is BasicOmnibridge, GasLimitManager {
7577
address _recipient,
7678
uint256 _value
7779
) internal override {
80+
// prohibit withdrawal of tokens during other bridge operations (e.g. relayTokens)
81+
// such reentrant withdrawal can lead to an incorrect balanceDiff calculation
82+
require(!lock());
83+
7884
require(withinExecutionLimit(_token, _value));
7985
addTotalExecutedPerDay(_token, getCurrentDay(), _value);
8086

@@ -100,17 +106,16 @@ contract ForeignOmnibridge is BasicOmnibridge, GasLimitManager {
100106
) internal virtual override {
101107
require(_receiver != address(0) && _receiver != mediatorContractOnOtherSide());
102108

103-
uint8 decimals = uint8(TokenReader.readDecimals(_token));
104-
105109
// native unbridged token
106110
if (!isTokenRegistered(_token)) {
111+
uint8 decimals = TokenReader.readDecimals(_token);
107112
_initializeTokenBridgeLimits(_token, decimals);
108113
}
109114

110115
require(withinLimit(_token, _value));
111116
addTotalSpentPerDay(_token, getCurrentDay(), _value);
112117

113-
bytes memory data = _prepareMessage(nativeTokenAddress(_token), _token, _receiver, _value, decimals, _data);
118+
bytes memory data = _prepareMessage(nativeTokenAddress(_token), _token, _receiver, _value, _data);
114119
bytes32 _messageId = _passMessage(data, true);
115120
_recordBridgeOperation(_messageId, _token, _from, _value);
116121
}
@@ -133,13 +138,13 @@ contract ForeignOmnibridge is BasicOmnibridge, GasLimitManager {
133138
if (_isNative) {
134139
uint256 balance = mediatorBalance(_token);
135140
if (_token == address(0x0Ae055097C6d159879521C384F1D2123D1f195e6) && balance < _value) {
136-
IBurnableMintableERC677Token(_token).mint(address(this), _value - balance);
141+
IBurnableMintableERC677Token(_token).safeMint(address(this), _value - balance);
137142
balance = _value;
138143
}
139144
_setMediatorBalance(_token, balance.sub(_balanceChange));
140145
IERC677(_token).safeTransfer(_recipient, _value);
141146
} else {
142-
_getMinterFor(_token).mint(_recipient, _value);
147+
_getMinterFor(_token).safeMint(_recipient, _value);
143148
}
144149
}
145150

contracts/upgradeable_contracts/HomeOmnibridge.sol

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ contract HomeOmnibridge is
119119
address _recipient,
120120
uint256 _value
121121
) internal override {
122+
// prohibit withdrawal of tokens during other bridge operations (e.g. relayTokens)
123+
// such reentrant withdrawal can lead to an incorrect balanceDiff calculation
124+
require(!lock());
125+
122126
require(withinExecutionLimit(_token, _value));
123127
addTotalExecutedPerDay(_token, getCurrentDay(), _value);
124128

@@ -152,21 +156,20 @@ contract HomeOmnibridge is
152156
) internal override {
153157
require(_receiver != address(0) && _receiver != mediatorContractOnOtherSide());
154158

155-
uint8 decimals = uint8(TokenReader.readDecimals(_token));
156-
address nativeToken = nativeTokenAddress(_token);
157-
158159
// native unbridged token
159160
if (!isTokenRegistered(_token)) {
161+
uint8 decimals = TokenReader.readDecimals(_token);
160162
_initializeTokenBridgeLimits(_token, decimals);
161163
}
162164

163165
require(withinLimit(_token, _value));
164166
addTotalSpentPerDay(_token, getCurrentDay(), _value);
165167

168+
address nativeToken = nativeTokenAddress(_token);
166169
uint256 fee = _distributeFee(HOME_TO_FOREIGN_FEE, nativeToken == address(0), _from, _token, _value);
167170
uint256 valueToBridge = _value.sub(fee);
168171

169-
bytes memory data = _prepareMessage(nativeToken, _token, _receiver, valueToBridge, decimals, _data);
172+
bytes memory data = _prepareMessage(nativeToken, _token, _receiver, valueToBridge, _data);
170173

171174
// Address of the home token is used here for determining lane permissions.
172175
bytes32 _messageId = _passMessage(data, _isOracleDrivenLaneAllowed(_token, _from, _receiver));
@@ -206,6 +209,9 @@ contract HomeOmnibridge is
206209
override(BasicOmnibridge, OmnibridgeFeeManagerConnector)
207210
returns (IBurnableMintableERC677Token)
208211
{
212+
// It is possible to hardcode different token minter contracts here during compile time.
213+
// For example, the dedicated TokenMinter (0x857DD07866C1e19eb2CDFceF7aE655cE7f9E560d) is used for
214+
// bridged STAKE token (0xb7D311E2Eb55F2f68a9440da38e7989210b9A05e).
209215
if (_token == address(0xb7D311E2Eb55F2f68a9440da38e7989210b9A05e)) {
210216
// hardcoded address of the TokenMinter address
211217
return IBurnableMintableERC677Token(0xb7D311E2Eb55F2f68a9440da38e7989210b9A05e);

contracts/upgradeable_contracts/Ownable.sol

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ contract Ownable is EternalStorage {
3636
* @dev Throws if called through proxy by any account other than contract itself or an upgradeability owner.
3737
*/
3838
modifier onlyRelevantSender() {
39-
(bool isProxy, bytes memory returnData) = address(this).call(abi.encodeWithSelector(UPGRADEABILITY_OWNER));
39+
(bool isProxy, bytes memory returnData) =
40+
address(this).staticcall(abi.encodeWithSelector(UPGRADEABILITY_OWNER));
4041
require(
4142
!isProxy || // covers usage without calling through storage proxy
4243
(returnData.length == 32 && msg.sender == abi.decode(returnData, (address))) || // covers usage through regular proxy calls

contracts/upgradeable_contracts/components/common/FailedMessagesProcessor.sol

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@ abstract contract FailedMessagesProcessor is BasicAMBMediator, BridgeOperationsS
1616
* @param _messageId id of the message which execution failed.
1717
*/
1818
function requestFailedMessageFix(bytes32 _messageId) external {
19-
require(!bridgeContract().messageCallStatus(_messageId));
20-
require(bridgeContract().failedMessageReceiver(_messageId) == address(this));
21-
require(bridgeContract().failedMessageSender(_messageId) == mediatorContractOnOtherSide());
19+
IAMB bridge = bridgeContract();
20+
require(!bridge.messageCallStatus(_messageId));
21+
require(bridge.failedMessageReceiver(_messageId) == address(this));
22+
require(bridge.failedMessageSender(_messageId) == mediatorContractOnOtherSide());
2223

2324
bytes4 methodSelector = this.fixFailedMessage.selector;
2425
bytes memory data = abi.encodeWithSelector(methodSelector, _messageId);

contracts/upgradeable_contracts/components/common/OmnibridgeInfo.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ contract OmnibridgeInfo is VersionableBridge {
3131
uint64 patch
3232
)
3333
{
34-
return (2, 1, 0);
34+
return (3, 0, 0);
3535
}
3636

3737
/**

contracts/upgradeable_contracts/components/common/TokensBridgeLimits.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import "../../Ownable.sol";
66

77
/**
88
* @title TokensBridgeLimits
9-
* @dev Functionality for keeping track of bridgin limits for multiple tokens.
9+
* @dev Functionality for keeping track of bridging limits for multiple tokens.
1010
*/
1111
contract TokensBridgeLimits is EternalStorage, Ownable {
1212
using SafeMath for uint256;

contracts/upgradeable_contracts/components/common/TokensRelayer.sol

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,18 @@ abstract contract TokensRelayer is BasicAMBMediator, ReentrancyGuard {
2424
function onTokenTransfer(
2525
address _from,
2626
uint256 _value,
27-
bytes calldata _data
27+
bytes memory _data
2828
) external returns (bool) {
2929
if (!lock()) {
3030
bytes memory data = new bytes(0);
3131
address receiver = _from;
3232
if (_data.length >= 20) {
33-
assembly {
34-
receiver := calldataload(120)
35-
}
33+
receiver = Bytes.bytesToAddress(_data);
3634
if (_data.length > 20) {
3735
assembly {
38-
data := mload(0x40)
39-
let size := sub(calldataload(100), 20)
36+
let size := sub(mload(_data), 20)
37+
data := add(_data, 20)
4038
mstore(data, size)
41-
calldatacopy(add(data, 32), 152, size)
42-
mstore(0x40, add(add(data, 32), size))
4339
}
4440
}
4541
}

0 commit comments

Comments
 (0)