Skip to content

Commit c937711

Browse files
authored
Merge the develop branch to the master branch, preparation to v5.7.0-rc0
2 parents cdef2c6 + 37e92f3 commit c937711

16 files changed

+392
-30
lines changed

contracts/helpers/AMBBridgeHelper.sol

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
pragma solidity 0.4.24;
2+
3+
interface IHomeBridge {
4+
function numMessagesSigned(bytes32 _message) external view returns (uint256);
5+
function isAlreadyProcessed(uint256 _number) external pure returns (bool);
6+
function signature(bytes32 _hash, uint256 _index) external view returns (bytes memory);
7+
}
8+
9+
contract Helper {
10+
function unpackSignature(bytes memory _signature) internal pure returns (bytes32 r, bytes32 s, uint8 v) {
11+
require(_signature.length == 65);
12+
13+
assembly {
14+
r := mload(add(_signature, 0x20))
15+
s := mload(add(_signature, 0x40))
16+
v := mload(add(_signature, 0x41))
17+
}
18+
return (r, s, v);
19+
}
20+
}
21+
22+
contract AMBBridgeHelper is Helper {
23+
address public owner;
24+
IHomeBridge public ambBridge;
25+
26+
constructor(address _homeBridge) public {
27+
owner = msg.sender;
28+
ambBridge = IHomeBridge(_homeBridge);
29+
}
30+
31+
function getSignatures(bytes _message) external view returns (bytes memory) {
32+
bytes32 msgHash = keccak256(abi.encodePacked(_message));
33+
uint256 signed = ambBridge.numMessagesSigned(msgHash);
34+
35+
require(ambBridge.isAlreadyProcessed(signed), "message hasn't been confirmed");
36+
37+
// recover number of confirmations sent by oracles
38+
signed = signed & 0x8fffffffffffffffffffffffffffffffffffffffffff;
39+
40+
require(signed < 0x100);
41+
42+
bytes memory signatures = new bytes(1 + signed * 65);
43+
44+
assembly {
45+
mstore8(add(signatures, 32), signed)
46+
}
47+
48+
for (uint256 i = 0; i < signed; i++) {
49+
bytes memory sig = ambBridge.signature(msgHash, i);
50+
(bytes32 r, bytes32 s, uint8 v) = unpackSignature(sig);
51+
assembly {
52+
mstore8(add(add(signatures, 33), i), v)
53+
mstore(add(add(add(signatures, 33), signed), mul(i, 32)), r)
54+
mstore(add(add(add(signatures, 33), mul(signed, 33)), mul(i, 32)), s)
55+
}
56+
}
57+
58+
return signatures;
59+
}
60+
61+
function clean() external {
62+
require(msg.sender == owner, "not an owner");
63+
selfdestruct(owner);
64+
}
65+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
pragma solidity 0.4.24;
2+
3+
interface IHomeErc20ToNativeBridge {
4+
function numMessagesSigned(bytes32 _message) external view returns (uint256);
5+
function isAlreadyProcessed(uint256 _number) external pure returns (bool);
6+
function message(bytes32 _hash) external view returns (bytes memory);
7+
function signature(bytes32 _hash, uint256 _index) external view returns (bytes memory);
8+
}
9+
10+
contract Helper {
11+
function unpackSignature(bytes memory _signature) internal pure returns (bytes32 r, bytes32 s, uint8 v) {
12+
require(_signature.length == 65);
13+
14+
assembly {
15+
r := mload(add(_signature, 0x20))
16+
s := mload(add(_signature, 0x40))
17+
v := mload(add(_signature, 0x41))
18+
}
19+
return (r, s, v);
20+
}
21+
}
22+
23+
contract Erc20ToNativeBridgeHelper is Helper {
24+
address public owner;
25+
IHomeErc20ToNativeBridge public bridge;
26+
address public foreignBridge;
27+
28+
constructor(address _homeBridge, address _foreignBridge) public {
29+
owner = msg.sender;
30+
bridge = IHomeErc20ToNativeBridge(_homeBridge);
31+
foreignBridge = _foreignBridge;
32+
}
33+
34+
function getMessage(bytes32 _msgHash) external view returns (bytes memory result) {
35+
result = bridge.message(_msgHash);
36+
}
37+
38+
function getMessageHash(address _recipient, uint256 _value, bytes32 _origTxHash) external view returns (bytes32) {
39+
bytes32 result = keccak256(abi.encodePacked(_recipient, _value, _origTxHash, foreignBridge));
40+
return result;
41+
}
42+
43+
function getSignatures(bytes32 _msgHash) external view returns (bytes memory) {
44+
uint256 signed = bridge.numMessagesSigned(_msgHash);
45+
46+
require(bridge.isAlreadyProcessed(signed), "message hasn't been confirmed");
47+
48+
// recover number of confirmations sent by oracles
49+
signed = signed & 0x8fffffffffffffffffffffffffffffffffffffffffff;
50+
51+
require(signed < 0x100);
52+
53+
bytes memory signatures = new bytes(1 + signed * 65);
54+
55+
assembly {
56+
mstore8(add(signatures, 32), signed)
57+
}
58+
59+
for (uint256 i = 0; i < signed; i++) {
60+
bytes memory sig = bridge.signature(_msgHash, i);
61+
(bytes32 r, bytes32 s, uint8 v) = unpackSignature(sig);
62+
assembly {
63+
let ptr := add(signatures, 33)
64+
mstore8(add(ptr, i), v)
65+
ptr := add(ptr, signed)
66+
mstore(add(ptr, mul(i, 32)), r)
67+
ptr := add(ptr, mul(signed, 32))
68+
mstore(add(ptr, mul(i, 32)), s)
69+
}
70+
}
71+
72+
return signatures;
73+
}
74+
75+
function clean() external {
76+
require(msg.sender == owner, "not an owner");
77+
selfdestruct(owner);
78+
}
79+
}

contracts/upgradeable_contracts/arbitrary_message/BasicForeignAMB.sol

Lines changed: 95 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,111 @@ contract BasicForeignAMB is BasicAMB, MessageRelay, MessageDelivery {
1212
* @param _data bytes to be relayed
1313
* @param _signatures bytes blob with signatures to be validated
1414
*/
15-
function executeSignatures(bytes _data, bytes _signatures) external {
16-
Message.hasEnoughValidSignatures(_data, _signatures, validatorContract(), true);
15+
function executeSignatures(bytes _data, bytes _signatures) public {
16+
_allowMessageExecution(_data, _signatures);
1717

18-
bytes32 messageId;
18+
bytes32 msgId;
1919
address sender;
2020
address executor;
2121
uint32 gasLimit;
2222
uint8 dataType;
2323
uint256[2] memory chainIds;
2424
bytes memory data;
2525

26-
(messageId, sender, executor, gasLimit, dataType, chainIds, data) = ArbitraryMessage.unpackData(_data);
26+
(msgId, sender, executor, gasLimit, dataType, chainIds, data) = ArbitraryMessage.unpackData(_data);
27+
28+
_executeMessage(msgId, sender, executor, gasLimit, dataType, chainIds, data);
29+
}
30+
31+
/**
32+
* @dev Validates provided signatures and relays a given message.
33+
* The message is not allowed to fail. The whole tx will be revered if message fails.
34+
* @param _data bytes to be relayed
35+
* @param _signatures bytes blob with signatures to be validated
36+
*/
37+
function safeExecuteSignatures(bytes _data, bytes _signatures) external {
38+
executeSignatures(_data, _signatures);
39+
}
40+
41+
/**
42+
* @dev Validates provided signatures and relays a given message. Allows to override the gas limit of the passed message.
43+
* Usually it makes sense to provide a higher amount of gas for the execution.
44+
* The message is not allowed to fail. The whole tx will be revered if message fails.
45+
* @param _data bytes to be relayed
46+
* @param _signatures bytes blob with signatures to be validated
47+
*/
48+
function safeExecuteSignaturesWithGasLimit(bytes _data, bytes _signatures, uint32 _gas) public {
49+
_allowMessageExecution(_data, _signatures);
50+
51+
bytes32 msgId;
52+
address sender;
53+
address executor;
54+
uint8 dataType;
55+
uint256[2] memory chainIds;
56+
bytes memory data;
57+
58+
(msgId, sender, executor, , dataType, chainIds, data) = ArbitraryMessage.unpackData(_data);
2759

28-
require(_isMessageVersionValid(messageId));
60+
_executeMessage(msgId, sender, executor, _gas, dataType, chainIds, data);
61+
}
62+
63+
/**
64+
* @dev Validates provided signatures and relays a given message. Passes all available gas for the execution.
65+
* The message is not allowed to fail. The whole tx will be revered if message fails.
66+
* @param _data bytes to be relayed
67+
* @param _signatures bytes blob with signatures to be validated
68+
*/
69+
function safeExecuteSignaturesWithAutoGasLimit(bytes _data, bytes _signatures) external {
70+
safeExecuteSignaturesWithGasLimit(_data, _signatures, 0xffffffff);
71+
}
72+
73+
/**
74+
* @dev Internal function for validating pre-execution requirements.
75+
* @param _data bytes to be relayed.
76+
* @param _signatures bytes blob with signatures to be validated.
77+
*/
78+
function _allowMessageExecution(bytes _data, bytes _signatures) internal {
79+
// this checks prevents execution of other messages, while some other message is being processed
80+
// nested executeSignatures is considered to be unsafe,
81+
// since it allows to change/reset the AMB context variables (messageId, messageSender, messageSourceChainId)
82+
// while processing nested message
83+
require(messageId() == bytes32(0));
84+
85+
Message.hasEnoughValidSignatures(_data, _signatures, validatorContract(), true);
86+
}
87+
88+
/**
89+
* @dev Internal function for executing decoded message. Performs additional validation on the message fields.
90+
* @param msgId id of the processed message.
91+
* @param sender sender address on the other side.
92+
* @param executor address of an executor.
93+
* @param gasLimit gas limit for a call to executor.
94+
* @param dataType AMB message dataType to be included as a part of the header.
95+
* @param chainIds pair of source and destination chain ids.
96+
* @param data calldata for a call to executor.
97+
*/
98+
function _executeMessage(
99+
bytes32 msgId,
100+
address sender,
101+
address executor,
102+
uint32 gasLimit,
103+
uint8 dataType,
104+
uint256[2] memory chainIds,
105+
bytes memory data
106+
) internal {
107+
require(_isMessageVersionValid(msgId));
29108
require(_isDestinationChainIdValid(chainIds[1]));
30-
require(!relayedMessages(messageId));
31-
setRelayedMessages(messageId, true);
32-
processMessage(sender, executor, messageId, gasLimit, dataType, chainIds[0], data);
109+
require(!relayedMessages(msgId));
110+
setRelayedMessages(msgId, true);
111+
processMessage(sender, executor, msgId, gasLimit, dataType, chainIds[0], data);
112+
}
113+
114+
/**
115+
* @dev Validates message execution status. Reverts if message is was executed in safe mode and reverted.
116+
* @param _status message execution status.
117+
*/
118+
function _validateExecutionStatus(bool _status) internal {
119+
require(_status || msg.sig == this.executeSignatures.selector);
33120
}
34121

35122
/**

contracts/upgradeable_contracts/arbitrary_message/MessageProcessor.sol

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ contract MessageProcessor is EternalStorage {
204204
* @param _sender sender address on the other side.
205205
* @param _contract address of an executor contract.
206206
* @param _data calldata for a call to executor.
207-
* @param _gas gas limit for a call to executor.
207+
* @param _gas gas limit for a call to executor. 2^32 - 1, if caller will pass all available gas for the execution.
208208
* @param _messageId id of the processed message.
209209
* @param _sourceChainId source chain id is of the received message.
210210
*/
@@ -230,15 +230,24 @@ contract MessageProcessor is EternalStorage {
230230
// only because the oracle provides incorrect gas limit for the transaction
231231
// This check is needed here in order to force contract to pass exactly the requested amount of gas.
232232
// Avoiding it may lead to the unwanted message failure in some extreme cases.
233-
require((gasleft() * 63) / 64 > _gas);
233+
require(_gas == 0xffffffff || (gasleft() * 63) / 64 > _gas);
234234

235235
bool status = _contract.call.gas(_gas)(_data);
236+
_validateExecutionStatus(status);
236237
setMessageSender(address(0));
237238
setMessageId(bytes32(0));
238239
setMessageSourceChainId(0);
239240
return status;
240241
}
241242

243+
/**
244+
* @dev Validates message execution status. In simplest case, does nothing.
245+
* @param _status message execution status.
246+
*/
247+
function _validateExecutionStatus(bool _status) internal {
248+
(_status);
249+
}
250+
242251
/* solcov ignore next */
243252
function emitEventOnMessageProcessed(address sender, address executor, bytes32 messageId, bool status) internal;
244253
}

contracts/upgradeable_contracts/arbitrary_message/VersionableAMB.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ contract VersionableAMB is VersionableBridge {
1717
* @return (major, minor, patch) version triple
1818
*/
1919
function getBridgeInterfacesVersion() external pure returns (uint64 major, uint64 minor, uint64 patch) {
20-
return (5, 6, 0);
20+
return (5, 7, 0);
2121
}
2222
}

contracts/upgradeable_contracts/multi_amb_erc20_to_erc677/BasicMultiAMBErc20ToErc677.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ contract BasicMultiAMBErc20ToErc677 is
5858
* @return patch value of the version
5959
*/
6060
function getBridgeInterfacesVersion() external pure returns (uint64 major, uint64 minor, uint64 patch) {
61-
return (1, 4, 0);
61+
return (1, 5, 0);
6262
}
6363

6464
/**

contracts/upgradeable_contracts/multi_amb_erc20_to_erc677/BasicMultiTokenBridge.sol

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,11 @@ contract BasicMultiTokenBridge is EternalStorage, Ownable {
8282
* @return minimum amount on tokens that can be sent through the bridge in one transfer.
8383
*/
8484
function minPerTx(address _token) public view returns (uint256) {
85-
return uintStorage[keccak256(abi.encodePacked("minPerTx", _token))];
85+
uint256 limit = uintStorage[keccak256(abi.encodePacked("minPerTx", _token))];
86+
if (_token == address(0)) {
87+
return limit;
88+
}
89+
return limit > 0 ? 1 : 0;
8690
}
8791

8892
/**

contracts/upgradeable_contracts/multi_amb_erc20_to_erc677/ForeignMultiAMBErc20ToErc677.sol

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,13 @@ contract ForeignMultiAMBErc20ToErc677 is BasicMultiAMBErc20ToErc677 {
100100
// which will call passMessage.
101101
require(!lock());
102102

103+
uint256 balanceBefore = token.balanceOf(address(this));
103104
setLock(true);
104105
token.safeTransferFrom(msg.sender, _value);
105106
setLock(false);
106-
bridgeSpecificActionsOnTokenTransfer(token, msg.sender, _receiver, _value);
107+
uint256 balanceDiff = token.balanceOf(address(this)).sub(balanceBefore);
108+
require(balanceDiff <= _value);
109+
bridgeSpecificActionsOnTokenTransfer(token, msg.sender, _receiver, balanceDiff);
107110
}
108111

109112
/**

contracts/upgradeable_contracts/multi_amb_erc20_to_erc677/HomeFeeManagerMultiAMBErc20ToErc677.sol

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ contract HomeFeeManagerMultiAMBErc20ToErc677 is BaseRewardAddressList, Ownable,
6666
* @param _fee new fee value, in percentage (1 ether == 10**18 == 100%).
6767
*/
6868
function setFee(bytes32 _feeType, address _token, uint256 _fee) external onlyOwner {
69+
require(isTokenRegistered(_token));
6970
_setFee(_feeType, _token, _fee);
7071
}
7172

@@ -76,6 +77,19 @@ contract HomeFeeManagerMultiAMBErc20ToErc677 is BaseRewardAddressList, Ownable,
7677
* @return fee value associated with the requested fee type.
7778
*/
7879
function getFee(bytes32 _feeType, address _token) public view validFeeType(_feeType) returns (uint256) {
80+
if (_getFee(_feeType, _token) > 0) {
81+
return _getFee(_feeType, address(0));
82+
}
83+
return 0;
84+
}
85+
86+
/**
87+
* @dev Internal function for reading fee values mapping.
88+
* @param _feeType type of the fee, can be one of [HOME_TO_FOREIGN_FEE, FOREIGN_TO_HOME_FEE].
89+
* @param _token address of the token contract for which fee should apply.
90+
* @return fee value associated with the requested fee type.
91+
*/
92+
function _getFee(bytes32 _feeType, address _token) internal returns (uint256) {
7993
return uintStorage[keccak256(abi.encodePacked(_feeType, _token))];
8094
}
8195

@@ -98,7 +112,6 @@ contract HomeFeeManagerMultiAMBErc20ToErc677 is BaseRewardAddressList, Ownable,
98112
* @param _fee new fee value, in percentage (1 ether == 10**18 == 100%).
99113
*/
100114
function _setFee(bytes32 _feeType, address _token, uint256 _fee) internal validFeeType(_feeType) validFee(_fee) {
101-
require(isTokenRegistered(_token));
102115
uintStorage[keccak256(abi.encodePacked(_feeType, _token))] = _fee;
103116
emit FeeUpdated(_feeType, _token, _fee);
104117
}

0 commit comments

Comments
 (0)