-
Notifications
You must be signed in to change notification settings - Fork 226
/
BasicAMBErc677ToErc677.sol
277 lines (231 loc) · 11.3 KB
/
BasicAMBErc677ToErc677.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
pragma solidity 0.4.24;
import "../../interfaces/IAMB.sol";
import "../Ownable.sol";
import "openzeppelin-solidity/contracts/AddressUtils.sol";
import "../Initializable.sol";
import "../BaseERC677Bridge.sol";
import "../BaseOverdrawManagement.sol";
import "../ReentrancyGuard.sol";
import "../Upgradeable.sol";
import "../Claimable.sol";
import "../VersionableBridge.sol";
import "../../libraries/Bytes.sol";
contract BasicAMBErc677ToErc677 is
Initializable,
Ownable,
ReentrancyGuard,
Upgradeable,
Claimable,
VersionableBridge,
BaseOverdrawManagement,
BaseERC677Bridge
{
event FailedMessageFixed(bytes32 indexed dataHash, address recipient, uint256 value);
bytes32 internal constant BRIDGE_CONTRACT = 0x811bbb11e8899da471f0e69a3ed55090fc90215227fc5fb1cb0d6e962ea7b74f; // keccak256(abi.encodePacked("bridgeContract"))
bytes32 internal constant MEDIATOR_CONTRACT = 0x98aa806e31e94a687a31c65769cb99670064dd7f5a87526da075c5fb4eab9880; // keccak256(abi.encodePacked("mediatorContract"))
bytes32 internal constant REQUEST_GAS_LIMIT = 0x2dfd6c9f781bb6bbb5369c114e949b69ebb440ef3d4dd6b2836225eb1dc3a2be; // keccak256(abi.encodePacked("requestGasLimit"))
bytes32 internal constant NONCE = 0x7ab1577440dd7bedf920cb6de2f9fc6bf7ba98c78c85a3fa1f8311aac95e1759; // keccak256(abi.encodePacked("nonce"))
function initialize(
address _bridgeContract,
address _mediatorContract,
address _erc677token,
uint256[] _dailyLimitMaxPerTxMinPerTxArray, // [ 0 = _dailyLimit, 1 = _maxPerTx, 2 = _minPerTx ]
uint256[] _executionDailyLimitExecutionMaxPerTxArray, // [ 0 = _executionDailyLimit, 1 = _executionMaxPerTx ]
uint256 _requestGasLimit,
uint256 _decimalShift,
address _owner
) external returns (bool) {
require(!isInitialized());
require(
_dailyLimitMaxPerTxMinPerTxArray[2] > 0 && // _minPerTx > 0
_dailyLimitMaxPerTxMinPerTxArray[1] > _dailyLimitMaxPerTxMinPerTxArray[2] && // _maxPerTx > _minPerTx
_dailyLimitMaxPerTxMinPerTxArray[0] > _dailyLimitMaxPerTxMinPerTxArray[1] // _dailyLimit > _maxPerTx
);
require(_executionDailyLimitExecutionMaxPerTxArray[1] < _executionDailyLimitExecutionMaxPerTxArray[0]); // _executionMaxPerTx < _executionDailyLimit
_setBridgeContract(_bridgeContract);
_setMediatorContractOnOtherSide(_mediatorContract);
setErc677token(_erc677token);
uintStorage[DAILY_LIMIT] = _dailyLimitMaxPerTxMinPerTxArray[0];
uintStorage[MAX_PER_TX] = _dailyLimitMaxPerTxMinPerTxArray[1];
uintStorage[MIN_PER_TX] = _dailyLimitMaxPerTxMinPerTxArray[2];
uintStorage[EXECUTION_DAILY_LIMIT] = _executionDailyLimitExecutionMaxPerTxArray[0];
uintStorage[EXECUTION_MAX_PER_TX] = _executionDailyLimitExecutionMaxPerTxArray[1];
_setRequestGasLimit(_requestGasLimit);
uintStorage[DECIMAL_SHIFT] = _decimalShift;
setOwner(_owner);
setNonce(keccak256(abi.encodePacked(address(this))));
setInitialize();
emit DailyLimitChanged(_dailyLimitMaxPerTxMinPerTxArray[0]);
emit ExecutionDailyLimitChanged(_executionDailyLimitExecutionMaxPerTxArray[0]);
return isInitialized();
}
function bridgeContractOnOtherSide() internal view returns (address) {
return mediatorContractOnOtherSide();
}
function passMessage(address _from, uint256 _value) internal {
bytes4 methodSelector = this.handleBridgedTokens.selector;
bytes memory data = abi.encodeWithSelector(methodSelector, _from, _value, nonce());
bytes32 dataHash = keccak256(data);
setMessageHashValue(dataHash, _value);
setMessageHashRecipient(dataHash, _from);
setNonce(dataHash);
bridgeContract().requireToPassMessage(mediatorContractOnOtherSide(), data, requestGasLimit());
}
function relayTokens(address _from, address _receiver, uint256 _value) external {
require(_from == msg.sender || _from == _receiver);
_relayTokens(_from, _receiver, _value);
}
function _relayTokens(address _from, address _receiver, uint256 _value) internal {
// 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();
address to = address(this);
require(withinLimit(_value));
setTotalSpentPerDay(getCurrentDay(), totalSpentPerDay(getCurrentDay()).add(_value));
setLock(true);
token.transferFrom(_from, to, _value);
setLock(false);
bridgeSpecificActionsOnTokenTransfer(token, _from, _value, abi.encodePacked(_receiver));
}
function relayTokens(address _receiver, uint256 _value) external {
_relayTokens(msg.sender, _receiver, _value);
}
function getBridgeInterfacesVersion() external pure returns (uint64 major, uint64 minor, uint64 patch) {
return (1, 0, 0);
}
function getBridgeMode() external pure returns (bytes4 _data) {
return 0x76595b56; // bytes4(keccak256(abi.encodePacked("erc-to-erc-amb")))
}
function setBridgeContract(address _bridgeContract) external onlyOwner {
_setBridgeContract(_bridgeContract);
}
function _setBridgeContract(address _bridgeContract) internal {
require(AddressUtils.isContract(_bridgeContract));
addressStorage[BRIDGE_CONTRACT] = _bridgeContract;
}
function bridgeContract() public view returns (IAMB) {
return IAMB(addressStorage[BRIDGE_CONTRACT]);
}
function setMediatorContractOnOtherSide(address _mediatorContract) external onlyOwner {
_setMediatorContractOnOtherSide(_mediatorContract);
}
function _setMediatorContractOnOtherSide(address _mediatorContract) internal {
addressStorage[MEDIATOR_CONTRACT] = _mediatorContract;
}
function mediatorContractOnOtherSide() public view returns (address) {
return addressStorage[MEDIATOR_CONTRACT];
}
function setRequestGasLimit(uint256 _requestGasLimit) external onlyOwner {
_setRequestGasLimit(_requestGasLimit);
}
function _setRequestGasLimit(uint256 _requestGasLimit) internal {
require(_requestGasLimit <= maxGasPerTx());
uintStorage[REQUEST_GAS_LIMIT] = _requestGasLimit;
}
function requestGasLimit() public view returns (uint256) {
return uintStorage[REQUEST_GAS_LIMIT];
}
function messageSender() internal view returns (address) {
return bridgeContract().messageSender();
}
function transactionHash() internal view returns (bytes32) {
return bridgeContract().transactionHash();
}
function maxGasPerTx() internal view returns (uint256) {
return bridgeContract().maxGasPerTx();
}
function nonce() internal view returns (bytes32) {
return Bytes.bytesToBytes32(bytesStorage[NONCE]);
}
function setNonce(bytes32 _hash) internal {
bytesStorage[NONCE] = abi.encodePacked(_hash);
}
function setMessageHashValue(bytes32 _hash, uint256 _value) internal {
uintStorage[keccak256(abi.encodePacked("messageHashValue", _hash))] = _value;
}
function messageHashValue(bytes32 _hash) internal view returns (uint256) {
return uintStorage[keccak256(abi.encodePacked("messageHashValue", _hash))];
}
function setMessageHashRecipient(bytes32 _hash, address _recipient) internal {
addressStorage[keccak256(abi.encodePacked("messageHashRecipient", _hash))] = _recipient;
}
function messageHashRecipient(bytes32 _hash) internal view returns (address) {
return addressStorage[keccak256(abi.encodePacked("messageHashRecipient", _hash))];
}
function setMessageHashFixed(bytes32 _hash) internal {
boolStorage[keccak256(abi.encodePacked("messageHashFixed", _hash))] = true;
}
function messageHashFixed(bytes32 _hash) public view returns (bool) {
return boolStorage[keccak256(abi.encodePacked("messageHashFixed", _hash))];
}
function handleBridgedTokens(
address _recipient,
uint256 _value,
bytes32 /* nonce */
) external {
require(msg.sender == address(bridgeContract()));
require(messageSender() == mediatorContractOnOtherSide());
if (withinExecutionLimit(_value)) {
setTotalExecutedPerDay(getCurrentDay(), totalExecutedPerDay(getCurrentDay()).add(_value));
executeActionOnBridgedTokens(_recipient, _value);
} else {
bytes32 txHash = transactionHash();
address recipient;
uint256 value;
(recipient, value) = txAboveLimits(txHash);
require(recipient == address(0) && value == 0);
setOutOfLimitAmount(outOfLimitAmount().add(_value));
setTxAboveLimits(_recipient, _value, txHash);
emit AmountLimitExceeded(_recipient, _value, txHash);
}
}
function fixAssetsAboveLimits(bytes32 txHash, bool unlockOnForeign, uint256 valueToUnlock)
external
onlyIfUpgradeabilityOwner
{
require(!fixedAssets(txHash));
require(valueToUnlock <= maxPerTx());
address recipient;
uint256 value;
(recipient, value) = txAboveLimits(txHash);
require(recipient != address(0) && value > 0 && value >= valueToUnlock);
setOutOfLimitAmount(outOfLimitAmount().sub(valueToUnlock));
uint256 pendingValue = value.sub(valueToUnlock);
setTxAboveLimitsValue(pendingValue, txHash);
emit AssetAboveLimitsFixed(txHash, valueToUnlock, pendingValue);
if (pendingValue == 0) {
setFixedAssets(txHash);
}
if (unlockOnForeign) {
passMessage(recipient, valueToUnlock);
}
}
function requestFailedMessageFix(bytes32 _txHash) external {
require(!bridgeContract().messageCallStatus(_txHash));
require(bridgeContract().failedMessageReceiver(_txHash) == address(this));
require(bridgeContract().failedMessageSender(_txHash) == mediatorContractOnOtherSide());
bytes32 dataHash = bridgeContract().failedMessageDataHash(_txHash);
bytes4 methodSelector = this.fixFailedMessage.selector;
bytes memory data = abi.encodeWithSelector(methodSelector, dataHash);
bridgeContract().requireToPassMessage(mediatorContractOnOtherSide(), data, requestGasLimit());
}
function fixFailedMessage(bytes32 _dataHash) external {
require(msg.sender == address(bridgeContract()));
require(messageSender() == mediatorContractOnOtherSide());
require(!messageHashFixed(_dataHash));
address recipient = messageHashRecipient(_dataHash);
uint256 value = messageHashValue(_dataHash);
setMessageHashFixed(_dataHash);
executeActionOnFixedTokens(recipient, value);
emit FailedMessageFixed(_dataHash, recipient, value);
}
function claimTokens(address _token, address _to) public onlyIfUpgradeabilityOwner validAddress(_to) {
claimValues(_token, _to);
}
/* solcov ignore next */
function executeActionOnBridgedTokens(address _recipient, uint256 _value) internal;
/* solcov ignore next */
function executeActionOnFixedTokens(address, uint256) internal;
}