Skip to content

Commit cdef2c6

Browse files
authored
Merge the develop branch to the master branch, preparation to v5.6.0
2 parents b858c96 + a4094e2 commit cdef2c6

File tree

12 files changed

+168
-13
lines changed

12 files changed

+168
-13
lines changed

contracts/upgradeable_contracts/arbitrary_message/BasicAMB.sol

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ contract BasicAMB is BasicBridge, VersionableAMB {
1010
bytes32 internal constant SOURCE_CHAIN_ID_LENGTH = 0xe504ae1fd6471eea80f18b8532a61a9bb91fba4f5b837f80a1cfb6752350af44; // keccak256(abi.encodePacked("sourceChainIdLength"))
1111
bytes32 internal constant DESTINATION_CHAIN_ID = 0xbbd454018e72a3f6c02bbd785bacc49e46292744f3f6761276723823aa332320; // keccak256(abi.encodePacked("destinationChainId"))
1212
bytes32 internal constant DESTINATION_CHAIN_ID_LENGTH = 0xfb792ae4ad11102b93f26a51b3749c2b3667f8b561566a4806d4989692811594; // keccak256(abi.encodePacked("destinationChainIdLength"))
13+
bytes32 internal constant ALLOW_REENTRANT_REQUESTS = 0xffa3a5a0e192028fc343362a39c5688e5a60819a4dc5ab3ee70c25bc25b78dd6; // keccak256(abi.encodePacked("allowReentrantRequests"))
1314

1415
/**
1516
* Initializes AMB contract
@@ -82,6 +83,24 @@ contract BasicAMB is BasicBridge, VersionableAMB {
8283
_setChainIds(_sourceChainId, _destinationChainId);
8384
}
8485

86+
/**
87+
* Sets the flag to allow passing new AMB requests in the opposite direction,
88+
* while other AMB message is being processed.
89+
* Only owner can call this method.
90+
* @param _enable true, if reentrant requests are allowed.
91+
*/
92+
function setAllowReentrantRequests(bool _enable) external onlyOwner {
93+
boolStorage[ALLOW_REENTRANT_REQUESTS] = _enable;
94+
}
95+
96+
/**
97+
* Tells if passing reentrant requests is allowed.
98+
* @return true, if reentrant requests are allowed.
99+
*/
100+
function allowReentrantRequests() public view returns (bool) {
101+
return boolStorage[ALLOW_REENTRANT_REQUESTS];
102+
}
103+
85104
/**
86105
* Internal function for retrieving current nonce value
87106
* @return nonce value

contracts/upgradeable_contracts/arbitrary_message/MessageDelivery.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ contract MessageDelivery is BasicAMB, MessageProcessor {
3030
*/
3131
function _sendMessage(address _contract, bytes _data, uint256 _gas, uint256 _dataType) public returns (bytes32) {
3232
// it is not allowed to pass messages while other messages are processed
33-
require(messageId() == bytes32(0));
34-
33+
// if other is not explicitly configured
34+
require(messageId() == bytes32(0) || allowReentrantRequests());
3535
require(_gas >= getMinimumGasUsage(_data) && _gas <= maxGasPerTx());
3636

3737
bytes32 _messageId;

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, 5, 0);
20+
return (5, 6, 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, 3, 0);
61+
return (1, 4, 0);
6262
}
6363

6464
/**

contracts/upgradeable_contracts/multi_amb_erc20_to_erc677/ForeignMultiAMBErc20ToErc677.sol

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,7 @@ contract ForeignMultiAMBErc20ToErc677 is BasicMultiAMBErc20ToErc677 {
5656
*/
5757
function executeActionOnBridgedTokens(address _token, address _recipient, uint256 _value) internal {
5858
bytes32 _messageId = messageId();
59-
_token.safeTransfer(_recipient, _value);
60-
_setMediatorBalance(_token, mediatorBalance(_token).sub(_value));
59+
_releaseTokens(_token, _recipient, _value);
6160
emit TokensBridged(_token, _recipient, _value, _messageId);
6261
}
6362

@@ -191,8 +190,7 @@ contract ForeignMultiAMBErc20ToErc677 is BasicMultiAMBErc20ToErc677 {
191190
* @param _value amount of tokens to be received.
192191
*/
193192
function executeActionOnFixedTokens(address _token, address _recipient, uint256 _value) internal {
194-
_setMediatorBalance(_token, mediatorBalance(_token).sub(_value));
195-
_token.safeTransfer(_recipient, _value);
193+
_releaseTokens(_token, _recipient, _value);
196194
}
197195

198196
/**
@@ -267,4 +265,32 @@ contract ForeignMultiAMBErc20ToErc677 is BasicMultiAMBErc20ToErc677 {
267265
function _setTokenRegistrationMessageId(address _token, bytes32 _messageId) internal {
268266
uintStorage[keccak256(abi.encodePacked("tokenRegistrationMessageId", _token))] = uint256(_messageId);
269267
}
268+
269+
/**
270+
* Internal function for unlocking some amount of tokens.
271+
* In case of bridging STAKE token, the insufficient amount of tokens can be additionally minted.
272+
*/
273+
function _releaseTokens(address _token, address _recipient, uint256 _value) internal {
274+
// It is necessary to use mediatorBalance(STAKE) instead of STAKE.balanceOf(this) to disallow user
275+
// withdraw mistakenly locked funds (via regular transfer()) instead of minting new tokens.
276+
// It should be possible to process mistakenly locked funds by calling fixMediatorBalance.
277+
uint256 balance = mediatorBalance(_token);
278+
279+
// STAKE total supply on xDai can be higher than the native STAKE supply on Mainnet
280+
// Omnibridge is allowed to mint extra native STAKE tokens.
281+
if (_token == address(0x0Ae055097C6d159879521C384F1D2123D1f195e6) && balance < _value) {
282+
// if all locked tokens were already withdrawn, mint new tokens directly to receiver
283+
// mediatorBalance(STAKE) remains 0 in this case.
284+
if (balance == 0) {
285+
IBurnableMintableERC677Token(_token).mint(_recipient, _value);
286+
return;
287+
}
288+
289+
// otherwise, mint insufficient tokens to the contract
290+
IBurnableMintableERC677Token(_token).mint(address(this), _value - balance);
291+
balance = _value;
292+
}
293+
_token.safeTransfer(_recipient, _value);
294+
_setMediatorBalance(_token, balance.sub(_value));
295+
}
270296
}

contracts/upgradeable_contracts/multi_amb_erc20_to_erc677/HomeFeeManagerMultiAMBErc20ToErc677.sol

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ contract HomeFeeManagerMultiAMBErc20ToErc677 is BaseRewardAddressList, Ownable,
145145
if (_feeType == HOME_TO_FOREIGN_FEE) {
146146
ERC677(_token).transfer(nextAddr, feeToDistribute);
147147
} else {
148-
IBurnableMintableERC677Token(_token).mint(nextAddr, feeToDistribute);
148+
_getMinterFor(_token).mint(nextAddr, feeToDistribute);
149149
}
150150

151151
nextAddr = getNextRewardAddress(nextAddr);
@@ -154,4 +154,6 @@ contract HomeFeeManagerMultiAMBErc20ToErc677 is BaseRewardAddressList, Ownable,
154154
}
155155
return _fee;
156156
}
157+
158+
function _getMinterFor(address _token) internal view returns (IBurnableMintableERC677Token);
157159
}

contracts/upgradeable_contracts/multi_amb_erc20_to_erc677/HomeMultiAMBErc20ToErc677.sol

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,23 @@ contract HomeMultiAMBErc20ToErc677 is
2020

2121
event NewTokenRegistered(address indexed foreignToken, address indexed homeToken);
2222

23+
/**
24+
* @dev Throws if called by any account other than the owner.
25+
* Overrides modifier from the Ownable contract in order to reduce bytecode size.
26+
*/
27+
modifier onlyOwner() {
28+
_onlyOwner();
29+
/* solcov ignore next */
30+
_;
31+
}
32+
33+
/**
34+
* @dev Internal function for reducing onlyOwner modifier bytecode size overhead.
35+
*/
36+
function _onlyOwner() internal {
37+
require(msg.sender == owner());
38+
}
39+
2340
/**
2441
* @dev Stores the initial parameters of the mediator.
2542
* @param _bridgeContract the address of the AMB bridge contract.
@@ -192,7 +209,7 @@ contract HomeMultiAMBErc20ToErc677 is
192209
emit FeeDistributed(fee, _token, _messageId);
193210
valueToMint = valueToMint.sub(fee);
194211
}
195-
IBurnableMintableERC677Token(_token).mint(_recipient, valueToMint);
212+
_getMinterFor(_token).mint(_recipient, valueToMint);
196213
emit TokensBridged(_token, _recipient, valueToMint, _messageId);
197214
}
198215

@@ -203,7 +220,7 @@ contract HomeMultiAMBErc20ToErc677 is
203220
* @param _value amount of tokens to be received.
204221
*/
205222
function executeActionOnFixedTokens(address _token, address _recipient, uint256 _value) internal {
206-
IBurnableMintableERC677Token(_token).mint(_recipient, _value);
223+
_getMinterFor(_token).mint(_recipient, _value);
207224
}
208225

209226
/**
@@ -303,4 +320,33 @@ contract HomeMultiAMBErc20ToErc677 is
303320

304321
return _messageId;
305322
}
323+
324+
/**
325+
* @dev Internal function for getting minter proxy address.
326+
* Returns the token address itself, expect for the case with bridged STAKE token.
327+
* For bridged STAKE token, returns the hardcoded TokenMinter contract address.
328+
* @param _token address of the token to mint.
329+
* @return address of the minter contract that should be used for calling mint(address,uint256)
330+
*/
331+
function _getMinterFor(address _token) internal view returns (IBurnableMintableERC677Token) {
332+
if (_token == address(0xb7D311E2Eb55F2f68a9440da38e7989210b9A05e)) {
333+
// hardcoded address of the TokenMinter address
334+
return IBurnableMintableERC677Token(0xb7D311E2Eb55F2f68a9440da38e7989210b9A05e);
335+
}
336+
return IBurnableMintableERC677Token(_token);
337+
}
338+
339+
/**
340+
* @dev Withdraws erc20 tokens or native coins from the bridged token contract.
341+
* Only the proxy owner is allowed to call this method.
342+
* @param _bridgedToken address of the bridged token contract.
343+
* @param _token address of the claimed token or address(0) for native coins.
344+
* @param _to address of the tokens/coins receiver.
345+
*/
346+
function claimTokensFromTokenContract(address _bridgedToken, address _token, address _to)
347+
external
348+
onlyIfUpgradeabilityOwner
349+
{
350+
IBurnableMintableERC677Token(_bridgedToken).claimTokens(_token, _to);
351+
}
306352
}

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "tokenbridge-contracts",
3-
"version": "5.6.0-rc0",
3+
"version": "5.6.0",
44
"description": "Bridge",
55
"main": "index.js",
66
"scripts": {

test/arbitrary_message/foreign_bridge.test.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -736,6 +736,33 @@ contract('ForeignAMB', async accounts => {
736736
// means that call to requireToPassMessage inside MessageProcessor reverted, since messageId flag was set up
737737
expect(await foreignBridge.messageCallStatus(messageId)).to.be.equal(false)
738738
})
739+
it('should allow to pass message back through the bridge if configured', async () => {
740+
const user = accounts[8]
741+
await foreignBridge.setAllowReentrantRequests(true, { from: user }).should.be.rejected
742+
await foreignBridge.setAllowReentrantRequests(true, { from: owner }).should.be.fulfilled
743+
expect(await foreignBridge.allowReentrantRequests()).to.be.equal(true)
744+
745+
const data = await foreignBridge.contract.methods
746+
.requireToPassMessage(box.address, setValueData, 100000)
747+
.encodeABI()
748+
// Use these calls to simulate home bridge on home network
749+
const resultPassMessageTx = await homeBridge.requireToPassMessage(foreignBridge.address, data, 821254, {
750+
from: user
751+
})
752+
753+
const { encodedData: message, messageId } = resultPassMessageTx.logs[0].args
754+
755+
const signature = await sign(authorities[0], message)
756+
const vrs = signatureToVRS(signature)
757+
const signatures = packSignatures([vrs])
758+
759+
await foreignBridge.executeSignatures(message, signatures, {
760+
from: authorities[0],
761+
gasPrice
762+
}).should.be.fulfilled
763+
764+
expect(await foreignBridge.messageCallStatus(messageId)).to.be.equal(true)
765+
})
739766
})
740767

741768
describe('gasToken functionality', async () => {

0 commit comments

Comments
 (0)