@keep-network/tbtc-v2 0.1.1-dev.40 → 0.1.1-dev.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/artifacts/TBTC.json +3 -3
- package/artifacts/TBTCToken.json +3 -3
- package/artifacts/VendingMachine.json +10 -10
- package/artifacts/solcInputs/{f1a50b67569d88ee54efa3e22c6b484e.json → f2c15d3cf1bd9566483f595c5ed30ccc.json} +25 -25
- package/build/contracts/GovernanceUtils.sol/GovernanceUtils.dbg.json +1 -1
- package/build/contracts/bank/Bank.sol/Bank.dbg.json +1 -1
- package/build/contracts/bridge/BitcoinTx.sol/BitcoinTx.dbg.json +1 -1
- package/build/contracts/bridge/BitcoinTx.sol/BitcoinTx.json +2 -2
- package/build/contracts/bridge/Bridge.sol/Bridge.dbg.json +1 -1
- package/build/contracts/bridge/Bridge.sol/Bridge.json +191 -331
- package/build/contracts/bridge/BridgeState.sol/BridgeState.dbg.json +1 -1
- package/build/contracts/bridge/BridgeState.sol/BridgeState.json +35 -3
- package/build/contracts/bridge/Deposit.sol/Deposit.dbg.json +1 -1
- package/build/contracts/bridge/Deposit.sol/Deposit.json +2 -2
- package/build/contracts/bridge/EcdsaLib.sol/EcdsaLib.dbg.json +1 -1
- package/build/contracts/bridge/EcdsaLib.sol/EcdsaLib.json +2 -2
- package/build/contracts/bridge/Fraud.sol/Fraud.dbg.json +4 -0
- package/build/contracts/bridge/Fraud.sol/Fraud.json +86 -0
- package/build/contracts/bridge/IRelay.sol/IRelay.dbg.json +1 -1
- package/build/contracts/bridge/MovingFunds.sol/MovingFunds.dbg.json +1 -1
- package/build/contracts/bridge/MovingFunds.sol/MovingFunds.json +4 -22
- package/build/contracts/bridge/Redemption.sol/OutboundTx.dbg.json +4 -0
- package/build/contracts/bridge/{Redeem.sol → Redemption.sol}/OutboundTx.json +3 -3
- package/build/contracts/bridge/Redemption.sol/Redemption.dbg.json +4 -0
- package/build/contracts/bridge/Redemption.sol/Redemption.json +92 -0
- package/build/contracts/bridge/Sweep.sol/Sweep.dbg.json +1 -1
- package/build/contracts/bridge/Sweep.sol/Sweep.json +2 -2
- package/build/contracts/bridge/VendingMachine.sol/VendingMachine.dbg.json +1 -1
- package/build/contracts/bridge/Wallets.sol/Wallets.dbg.json +1 -1
- package/build/contracts/bridge/Wallets.sol/Wallets.json +2 -47
- package/build/contracts/token/TBTC.sol/TBTC.dbg.json +1 -1
- package/build/contracts/vault/IVault.sol/IVault.dbg.json +1 -1
- package/build/contracts/vault/TBTCVault.sol/TBTCVault.dbg.json +1 -1
- package/contracts/bridge/BitcoinTx.sol +19 -26
- package/contracts/bridge/Bridge.sol +476 -534
- package/contracts/bridge/BridgeState.sol +190 -129
- package/contracts/bridge/Deposit.sol +23 -4
- package/contracts/bridge/EcdsaLib.sol +15 -0
- package/contracts/bridge/{Frauds.sol → Fraud.sol} +75 -146
- package/contracts/bridge/MovingFunds.sol +15 -9
- package/contracts/bridge/{Redeem.sol → Redemption.sol} +19 -17
- package/contracts/bridge/Sweep.sol +16 -9
- package/contracts/bridge/Wallets.sol +40 -121
- package/package.json +1 -1
- package/build/contracts/bridge/Frauds.sol/Frauds.dbg.json +0 -4
- package/build/contracts/bridge/Frauds.sol/Frauds.json +0 -138
- package/build/contracts/bridge/Redeem.sol/OutboundTx.dbg.json +0 -4
- package/build/contracts/bridge/Redeem.sol/Redeem.dbg.json +0 -4
- package/build/contracts/bridge/Redeem.sol/Redeem.json +0 -110
|
@@ -17,20 +17,17 @@ pragma solidity ^0.8.9;
|
|
|
17
17
|
|
|
18
18
|
import "@openzeppelin/contracts/access/Ownable.sol";
|
|
19
19
|
|
|
20
|
-
import {BTCUtils} from "@keep-network/bitcoin-spv-sol/contracts/BTCUtils.sol";
|
|
21
|
-
import {BytesLib} from "@keep-network/bitcoin-spv-sol/contracts/BytesLib.sol";
|
|
22
|
-
|
|
23
20
|
import {IWalletOwner as EcdsaWalletOwner} from "@keep-network/ecdsa/contracts/api/IWalletOwner.sol";
|
|
24
21
|
|
|
25
22
|
import "./IRelay.sol";
|
|
26
23
|
import "./BridgeState.sol";
|
|
27
24
|
import "./Deposit.sol";
|
|
28
25
|
import "./Sweep.sol";
|
|
29
|
-
import "./
|
|
26
|
+
import "./Redemption.sol";
|
|
30
27
|
import "./BitcoinTx.sol";
|
|
31
28
|
import "./EcdsaLib.sol";
|
|
32
29
|
import "./Wallets.sol";
|
|
33
|
-
import "./
|
|
30
|
+
import "./Fraud.sol";
|
|
34
31
|
import "./MovingFunds.sol";
|
|
35
32
|
|
|
36
33
|
import "../bank/Bank.sol";
|
|
@@ -53,81 +50,20 @@ import "../bank/Bank.sol";
|
|
|
53
50
|
/// the sweep operation is confirmed on the Bitcoin network, the ECDSA
|
|
54
51
|
/// wallet informs the Bridge about the sweep increasing appropriate
|
|
55
52
|
/// balances in the Bank.
|
|
56
|
-
/// @dev Bridge is an upgradeable component of the Bank.
|
|
57
|
-
///
|
|
58
|
-
|
|
59
|
-
// by the Bridge can be probably delegated to the Wallets library.
|
|
60
|
-
// Examples of such operations are main UTXO or pending redemptions
|
|
61
|
-
// value updates.
|
|
53
|
+
/// @dev Bridge is an upgradeable component of the Bank. The order of
|
|
54
|
+
/// functionalities in this contract is: deposit, sweep, redemption,
|
|
55
|
+
/// moving funds, wallet lifecycle, frauds, parameters.
|
|
62
56
|
contract Bridge is Ownable, EcdsaWalletOwner {
|
|
63
57
|
using BridgeState for BridgeState.Storage;
|
|
64
58
|
using Deposit for BridgeState.Storage;
|
|
65
59
|
using Sweep for BridgeState.Storage;
|
|
66
|
-
using
|
|
60
|
+
using Redemption for BridgeState.Storage;
|
|
67
61
|
using MovingFunds for BridgeState.Storage;
|
|
68
|
-
using
|
|
69
|
-
using
|
|
70
|
-
|
|
71
|
-
using BTCUtils for bytes;
|
|
72
|
-
using BTCUtils for uint256;
|
|
73
|
-
using BytesLib for bytes;
|
|
62
|
+
using Wallets for BridgeState.Storage;
|
|
63
|
+
using Fraud for BridgeState.Storage;
|
|
74
64
|
|
|
75
65
|
BridgeState.Storage internal self;
|
|
76
66
|
|
|
77
|
-
/// @notice Contains parameters related to frauds and the collection of all
|
|
78
|
-
/// submitted fraud challenges.
|
|
79
|
-
Frauds.Data internal frauds;
|
|
80
|
-
|
|
81
|
-
/// @notice State related with wallets.
|
|
82
|
-
Wallets.Data internal wallets;
|
|
83
|
-
|
|
84
|
-
event WalletCreationPeriodUpdated(uint32 newCreationPeriod);
|
|
85
|
-
|
|
86
|
-
event WalletBtcBalanceRangeUpdated(
|
|
87
|
-
uint64 newMinBtcBalance,
|
|
88
|
-
uint64 newMaxBtcBalance
|
|
89
|
-
);
|
|
90
|
-
|
|
91
|
-
event WalletMaxAgeUpdated(uint32 newMaxAge);
|
|
92
|
-
|
|
93
|
-
event NewWalletRequested();
|
|
94
|
-
|
|
95
|
-
event NewWalletRegistered(
|
|
96
|
-
bytes32 indexed ecdsaWalletID,
|
|
97
|
-
bytes20 indexed walletPubKeyHash
|
|
98
|
-
);
|
|
99
|
-
|
|
100
|
-
event WalletMovingFunds(
|
|
101
|
-
bytes32 indexed ecdsaWalletID,
|
|
102
|
-
bytes20 indexed walletPubKeyHash
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
event WalletClosed(
|
|
106
|
-
bytes32 indexed ecdsaWalletID,
|
|
107
|
-
bytes20 indexed walletPubKeyHash
|
|
108
|
-
);
|
|
109
|
-
|
|
110
|
-
event WalletTerminated(
|
|
111
|
-
bytes32 indexed ecdsaWalletID,
|
|
112
|
-
bytes20 indexed walletPubKeyHash
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
event VaultStatusUpdated(address indexed vault, bool isTrusted);
|
|
116
|
-
|
|
117
|
-
event FraudSlashingAmountUpdated(uint256 newFraudSlashingAmount);
|
|
118
|
-
|
|
119
|
-
event FraudNotifierRewardMultiplierUpdated(
|
|
120
|
-
uint256 newFraudNotifierRewardMultiplier
|
|
121
|
-
);
|
|
122
|
-
|
|
123
|
-
event FraudChallengeDefeatTimeoutUpdated(
|
|
124
|
-
uint256 newFraudChallengeDefeatTimeout
|
|
125
|
-
);
|
|
126
|
-
|
|
127
|
-
event FraudChallengeDepositAmountUpdated(
|
|
128
|
-
uint256 newFraudChallengeDepositAmount
|
|
129
|
-
);
|
|
130
|
-
|
|
131
67
|
event DepositRevealed(
|
|
132
68
|
bytes32 fundingTxHash,
|
|
133
69
|
uint32 fundingOutputIndex,
|
|
@@ -161,6 +97,33 @@ contract Bridge is Ownable, EcdsaWalletOwner {
|
|
|
161
97
|
bytes redeemerOutputScript
|
|
162
98
|
);
|
|
163
99
|
|
|
100
|
+
event WalletMovingFunds(
|
|
101
|
+
bytes32 indexed ecdsaWalletID,
|
|
102
|
+
bytes20 indexed walletPubKeyHash
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
event MovingFundsCompleted(
|
|
106
|
+
bytes20 walletPubKeyHash,
|
|
107
|
+
bytes32 movingFundsTxHash
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
event NewWalletRequested();
|
|
111
|
+
|
|
112
|
+
event NewWalletRegistered(
|
|
113
|
+
bytes32 indexed ecdsaWalletID,
|
|
114
|
+
bytes20 indexed walletPubKeyHash
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
event WalletClosed(
|
|
118
|
+
bytes32 indexed ecdsaWalletID,
|
|
119
|
+
bytes20 indexed walletPubKeyHash
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
event WalletTerminated(
|
|
123
|
+
bytes32 indexed ecdsaWalletID,
|
|
124
|
+
bytes20 indexed walletPubKeyHash
|
|
125
|
+
);
|
|
126
|
+
|
|
164
127
|
event FraudChallengeSubmitted(
|
|
165
128
|
bytes20 walletPublicKeyHash,
|
|
166
129
|
bytes32 sighash,
|
|
@@ -176,9 +139,13 @@ contract Bridge is Ownable, EcdsaWalletOwner {
|
|
|
176
139
|
bytes32 sighash
|
|
177
140
|
);
|
|
178
141
|
|
|
179
|
-
event
|
|
180
|
-
|
|
181
|
-
|
|
142
|
+
event VaultStatusUpdated(address indexed vault, bool isTrusted);
|
|
143
|
+
|
|
144
|
+
event WalletParametersUpdated(
|
|
145
|
+
uint32 walletCreationPeriod,
|
|
146
|
+
uint64 walletMinBtcBalance,
|
|
147
|
+
uint64 walletMaxBtcBalance,
|
|
148
|
+
uint32 walletMaxAge
|
|
182
149
|
);
|
|
183
150
|
|
|
184
151
|
constructor(
|
|
@@ -194,6 +161,12 @@ contract Bridge is Ownable, EcdsaWalletOwner {
|
|
|
194
161
|
require(_relay != address(0), "Relay address cannot be zero");
|
|
195
162
|
self.relay = IRelay(_relay);
|
|
196
163
|
|
|
164
|
+
require(
|
|
165
|
+
_ecdsaWalletRegistry != address(0),
|
|
166
|
+
"ECDSA Wallet Registry address cannot be zero"
|
|
167
|
+
);
|
|
168
|
+
self.ecdsaWalletRegistry = EcdsaWalletRegistry(_ecdsaWalletRegistry);
|
|
169
|
+
|
|
197
170
|
require(_treasury != address(0), "Treasury address cannot be zero");
|
|
198
171
|
self.treasury = _treasury;
|
|
199
172
|
|
|
@@ -208,177 +181,14 @@ contract Bridge is Ownable, EcdsaWalletOwner {
|
|
|
208
181
|
self.redemptionTxMaxFee = 10000; // 10000 satoshi
|
|
209
182
|
self.redemptionTimeout = 172800; // 48 hours
|
|
210
183
|
self.movingFundsTxMaxTotalFee = 10000; // 10000 satoshi
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
wallets.init(_ecdsaWalletRegistry);
|
|
220
|
-
wallets.setCreationPeriod(1 weeks);
|
|
221
|
-
wallets.setBtcBalanceRange(1 * 1e8, 10 * 1e8); // [1 BTC, 10 BTC]
|
|
222
|
-
wallets.setMaxAge(26 weeks); // ~6 months
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
/// @notice Updates parameters used by the `Wallets` library.
|
|
226
|
-
/// @param creationPeriod New value of the wallet creation period
|
|
227
|
-
/// @param minBtcBalance New value of the minimum BTC balance
|
|
228
|
-
/// @param maxBtcBalance New value of the maximum BTC balance
|
|
229
|
-
/// @param maxAge New value of the wallet maximum age
|
|
230
|
-
/// @dev Requirements:
|
|
231
|
-
/// - Caller must be the contract owner.
|
|
232
|
-
/// - Minimum BTC balance must be greater than zero
|
|
233
|
-
/// - Maximum BTC balance must be greater than minimum BTC balance
|
|
234
|
-
function updateWalletsParameters(
|
|
235
|
-
uint32 creationPeriod,
|
|
236
|
-
uint64 minBtcBalance,
|
|
237
|
-
uint64 maxBtcBalance,
|
|
238
|
-
uint32 maxAge
|
|
239
|
-
) external onlyOwner {
|
|
240
|
-
wallets.setCreationPeriod(creationPeriod);
|
|
241
|
-
wallets.setBtcBalanceRange(minBtcBalance, maxBtcBalance);
|
|
242
|
-
wallets.setMaxAge(maxAge);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
/// @return creationPeriod Value of the wallet creation period
|
|
246
|
-
/// @return minBtcBalance Value of the minimum BTC balance
|
|
247
|
-
/// @return maxBtcBalance Value of the maximum BTC balance
|
|
248
|
-
/// @return maxAge Value of the wallet max age
|
|
249
|
-
function getWalletsParameters()
|
|
250
|
-
external
|
|
251
|
-
view
|
|
252
|
-
returns (
|
|
253
|
-
uint32 creationPeriod,
|
|
254
|
-
uint64 minBtcBalance,
|
|
255
|
-
uint64 maxBtcBalance,
|
|
256
|
-
uint32 maxAge
|
|
257
|
-
)
|
|
258
|
-
{
|
|
259
|
-
creationPeriod = wallets.creationPeriod;
|
|
260
|
-
minBtcBalance = wallets.minBtcBalance;
|
|
261
|
-
maxBtcBalance = wallets.maxBtcBalance;
|
|
262
|
-
maxAge = wallets.maxAge;
|
|
263
|
-
|
|
264
|
-
return (creationPeriod, minBtcBalance, maxBtcBalance, maxAge);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
/// @notice Allows the Governance to mark the given vault address as trusted
|
|
268
|
-
/// or no longer trusted. Vaults are not trusted by default.
|
|
269
|
-
/// Trusted vault must meet the following criteria:
|
|
270
|
-
/// - `IVault.receiveBalanceIncrease` must have a known, low gas
|
|
271
|
-
/// cost.
|
|
272
|
-
/// - `IVault.receiveBalanceIncrease` must never revert.
|
|
273
|
-
/// @dev Without restricting reveal only to trusted vaults, malicious
|
|
274
|
-
/// vaults not meeting the criteria would be able to nuke sweep proof
|
|
275
|
-
/// transactions executed by ECDSA wallet with deposits routed to
|
|
276
|
-
/// them.
|
|
277
|
-
/// @param vault The address of the vault
|
|
278
|
-
/// @param isTrusted flag indicating whether the vault is trusted or not
|
|
279
|
-
/// @dev Can only be called by the Governance.
|
|
280
|
-
function setVaultStatus(address vault, bool isTrusted) external onlyOwner {
|
|
281
|
-
self.isVaultTrusted[vault] = isTrusted;
|
|
282
|
-
emit VaultStatusUpdated(vault, isTrusted);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/// @notice Requests creation of a new wallet. This function just
|
|
286
|
-
/// forms a request and the creation process is performed
|
|
287
|
-
/// asynchronously. Once a wallet is created, the ECDSA Wallet
|
|
288
|
-
/// Registry will notify this contract by calling the
|
|
289
|
-
/// `__ecdsaWalletCreatedCallback` function.
|
|
290
|
-
/// @param activeWalletMainUtxo Data of the active wallet's main UTXO, as
|
|
291
|
-
/// currently known on the Ethereum chain.
|
|
292
|
-
/// @dev Requirements:
|
|
293
|
-
/// - `activeWalletMainUtxo` components must point to the recent main
|
|
294
|
-
/// UTXO of the given active wallet, as currently known on the
|
|
295
|
-
/// Ethereum chain. If there is no active wallet at the moment, or
|
|
296
|
-
/// the active wallet has no main UTXO, this parameter can be
|
|
297
|
-
/// empty as it is ignored.
|
|
298
|
-
/// - Wallet creation must not be in progress
|
|
299
|
-
/// - If the active wallet is set, one of the following
|
|
300
|
-
/// conditions must be true:
|
|
301
|
-
/// - The active wallet BTC balance is above the minimum threshold
|
|
302
|
-
/// and the active wallet is old enough, i.e. the creation period
|
|
303
|
-
/// was elapsed since its creation time
|
|
304
|
-
/// - The active wallet BTC balance is above the maximum threshold
|
|
305
|
-
function requestNewWallet(BitcoinTx.UTXO calldata activeWalletMainUtxo)
|
|
306
|
-
external
|
|
307
|
-
{
|
|
308
|
-
wallets.requestNewWallet(activeWalletMainUtxo);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/// @notice A callback function that is called by the ECDSA Wallet Registry
|
|
312
|
-
/// once a new ECDSA wallet is created.
|
|
313
|
-
/// @param ecdsaWalletID Wallet's unique identifier.
|
|
314
|
-
/// @param publicKeyX Wallet's public key's X coordinate.
|
|
315
|
-
/// @param publicKeyY Wallet's public key's Y coordinate.
|
|
316
|
-
/// @dev Requirements:
|
|
317
|
-
/// - The only caller authorized to call this function is `registry`
|
|
318
|
-
/// - Given wallet data must not belong to an already registered wallet
|
|
319
|
-
function __ecdsaWalletCreatedCallback(
|
|
320
|
-
bytes32 ecdsaWalletID,
|
|
321
|
-
bytes32 publicKeyX,
|
|
322
|
-
bytes32 publicKeyY
|
|
323
|
-
) external override {
|
|
324
|
-
wallets.registerNewWallet(ecdsaWalletID, publicKeyX, publicKeyY);
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
/// @notice A callback function that is called by the ECDSA Wallet Registry
|
|
328
|
-
/// once a wallet heartbeat failure is detected.
|
|
329
|
-
/// @param publicKeyX Wallet's public key's X coordinate
|
|
330
|
-
/// @param publicKeyY Wallet's public key's Y coordinate
|
|
331
|
-
/// @dev Requirements:
|
|
332
|
-
/// - The only caller authorized to call this function is `registry`
|
|
333
|
-
/// - Wallet must be in Live state
|
|
334
|
-
function __ecdsaWalletHeartbeatFailedCallback(
|
|
335
|
-
bytes32,
|
|
336
|
-
bytes32 publicKeyX,
|
|
337
|
-
bytes32 publicKeyY
|
|
338
|
-
) external override {
|
|
339
|
-
wallets.notifyWalletHeartbeatFailed(publicKeyX, publicKeyY);
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
/// @notice Notifies that the wallet is either old enough or has too few
|
|
343
|
-
/// satoshis left and qualifies to be closed.
|
|
344
|
-
/// @param walletPubKeyHash 20-byte public key hash of the wallet
|
|
345
|
-
/// @param walletMainUtxo Data of the wallet's main UTXO, as currently
|
|
346
|
-
/// known on the Ethereum chain.
|
|
347
|
-
/// @dev Requirements:
|
|
348
|
-
/// - Wallet must not be set as the current active wallet
|
|
349
|
-
/// - Wallet must exceed the wallet maximum age OR the wallet BTC
|
|
350
|
-
/// balance must be lesser than the minimum threshold. If the latter
|
|
351
|
-
/// case is true, the `walletMainUtxo` components must point to the
|
|
352
|
-
/// recent main UTXO of the given wallet, as currently known on the
|
|
353
|
-
/// Ethereum chain. If the wallet has no main UTXO, this parameter
|
|
354
|
-
/// can be empty as it is ignored since the wallet balance is
|
|
355
|
-
/// assumed to be zero.
|
|
356
|
-
/// - Wallet must be in Live state
|
|
357
|
-
function notifyCloseableWallet(
|
|
358
|
-
bytes20 walletPubKeyHash,
|
|
359
|
-
BitcoinTx.UTXO calldata walletMainUtxo
|
|
360
|
-
) external {
|
|
361
|
-
wallets.notifyCloseableWallet(walletPubKeyHash, walletMainUtxo);
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
/// @notice Gets details about a registered wallet.
|
|
365
|
-
/// @param walletPubKeyHash The 20-byte wallet public key hash (computed
|
|
366
|
-
/// using Bitcoin HASH160 over the compressed ECDSA public key)
|
|
367
|
-
/// @return Wallet details.
|
|
368
|
-
function getWallet(bytes20 walletPubKeyHash)
|
|
369
|
-
external
|
|
370
|
-
view
|
|
371
|
-
returns (Wallets.Wallet memory)
|
|
372
|
-
{
|
|
373
|
-
return wallets.registeredWallets[walletPubKeyHash];
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
/// @notice Gets the public key hash of the active wallet.
|
|
377
|
-
/// @return The 20-byte public key hash (computed using Bitcoin HASH160
|
|
378
|
-
/// over the compressed ECDSA public key) of the active wallet.
|
|
379
|
-
/// Returns bytes20(0) if there is no active wallet at the moment.
|
|
380
|
-
function getActiveWalletPubKeyHash() external view returns (bytes20) {
|
|
381
|
-
return wallets.activeWalletPubKeyHash;
|
|
184
|
+
self.fraudSlashingAmount = 10000 * 1e18; // 10000 T
|
|
185
|
+
self.fraudNotifierRewardMultiplier = 100; // 100%
|
|
186
|
+
self.fraudChallengeDefeatTimeout = 7 days;
|
|
187
|
+
self.fraudChallengeDepositAmount = 2 ether;
|
|
188
|
+
self.walletCreationPeriod = 1 weeks;
|
|
189
|
+
self.walletMinBtcBalance = 1e8; // 1 BTC
|
|
190
|
+
self.walletMaxBtcBalance = 10e8; // 10 BTC
|
|
191
|
+
self.walletMaxAge = 26 weeks; // ~6 months
|
|
382
192
|
}
|
|
383
193
|
|
|
384
194
|
/// @notice Used by the depositor to reveal information about their P2(W)SH
|
|
@@ -419,7 +229,7 @@ contract Bridge is Ownable, EcdsaWalletOwner {
|
|
|
419
229
|
BitcoinTx.Info calldata fundingTx,
|
|
420
230
|
Deposit.DepositRevealInfo calldata reveal
|
|
421
231
|
) external {
|
|
422
|
-
self.revealDeposit(
|
|
232
|
+
self.revealDeposit(fundingTx, reveal);
|
|
423
233
|
}
|
|
424
234
|
|
|
425
235
|
/// @notice Used by the wallet to prove the BTC deposit sweep transaction
|
|
@@ -463,203 +273,26 @@ contract Bridge is Ownable, EcdsaWalletOwner {
|
|
|
463
273
|
BitcoinTx.Proof calldata sweepProof,
|
|
464
274
|
BitcoinTx.UTXO calldata mainUtxo
|
|
465
275
|
) external {
|
|
466
|
-
self.submitSweepProof(
|
|
276
|
+
self.submitSweepProof(sweepTx, sweepProof, mainUtxo);
|
|
467
277
|
}
|
|
468
278
|
|
|
469
|
-
/// @notice
|
|
470
|
-
/// wallet
|
|
471
|
-
///
|
|
472
|
-
///
|
|
473
|
-
///
|
|
474
|
-
///
|
|
475
|
-
///
|
|
476
|
-
///
|
|
477
|
-
///
|
|
478
|
-
///
|
|
479
|
-
///
|
|
480
|
-
///
|
|
481
|
-
///
|
|
482
|
-
///
|
|
483
|
-
///
|
|
484
|
-
|
|
485
|
-
///
|
|
486
|
-
/// @param sighash The hash that was used to produce the ECDSA signature
|
|
487
|
-
/// that is the subject of the fraud claim. This hash is constructed
|
|
488
|
-
/// by applying double SHA-256 over a serialized subset of the
|
|
489
|
-
/// transaction. The exact subset used as hash preimage depends on
|
|
490
|
-
/// the transaction input the signature is produced for. See BIP-143
|
|
491
|
-
/// for reference
|
|
492
|
-
/// @param signature Bitcoin signature in the R/S/V format
|
|
493
|
-
/// @dev Requirements:
|
|
494
|
-
/// - Wallet behind `walletPubKey` must be in `Live` or `MovingFunds`
|
|
495
|
-
/// state
|
|
496
|
-
/// - The challenger must send appropriate amount of ETH used as
|
|
497
|
-
/// fraud challenge deposit
|
|
498
|
-
/// - The signature (represented by r, s and v) must be generated by
|
|
499
|
-
/// the wallet behind `walletPubKey` during signing of `sighash`
|
|
500
|
-
/// - Wallet can be challenged for the given signature only once
|
|
501
|
-
function submitFraudChallenge(
|
|
502
|
-
bytes calldata walletPublicKey,
|
|
503
|
-
bytes32 sighash,
|
|
504
|
-
BitcoinTx.RSVSignature calldata signature
|
|
505
|
-
) external payable {
|
|
506
|
-
bytes memory compressedWalletPublicKey = EcdsaLib.compressPublicKey(
|
|
507
|
-
walletPublicKey.slice32(0),
|
|
508
|
-
walletPublicKey.slice32(32)
|
|
509
|
-
);
|
|
510
|
-
bytes20 walletPubKeyHash = compressedWalletPublicKey.hash160View();
|
|
511
|
-
|
|
512
|
-
Wallets.Wallet storage wallet = wallets.registeredWallets[
|
|
513
|
-
walletPubKeyHash
|
|
514
|
-
];
|
|
515
|
-
|
|
516
|
-
require(
|
|
517
|
-
wallet.state == Wallets.WalletState.Live ||
|
|
518
|
-
wallet.state == Wallets.WalletState.MovingFunds,
|
|
519
|
-
"Wallet is neither in Live nor MovingFunds state"
|
|
520
|
-
);
|
|
521
|
-
|
|
522
|
-
frauds.submitChallenge(
|
|
523
|
-
walletPublicKey,
|
|
524
|
-
walletPubKeyHash,
|
|
525
|
-
sighash,
|
|
526
|
-
signature
|
|
527
|
-
);
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
/// @notice Allows to defeat a pending fraud challenge against a wallet if
|
|
531
|
-
/// the transaction that spends the UTXO follows the protocol rules.
|
|
532
|
-
/// In order to defeat the challenge the same `walletPublicKey` and
|
|
533
|
-
/// signature (represented by `r`, `s` and `v`) must be provided as
|
|
534
|
-
/// were used to calculate the sighash during input signing.
|
|
535
|
-
/// The fraud challenge defeat attempt will only succeed if the
|
|
536
|
-
/// inputs in the preimage are considered honestly spent by the
|
|
537
|
-
/// wallet. Therefore the transaction spending the UTXO must be
|
|
538
|
-
/// proven in the Bridge before a challenge defeat is called.
|
|
539
|
-
/// If successfully defeated, the fraud challenge is marked as
|
|
540
|
-
/// resolved and the amount of ether deposited by the challenger is
|
|
541
|
-
/// sent to the treasury.
|
|
542
|
-
/// @param walletPublicKey The public key of the wallet in the uncompressed
|
|
543
|
-
/// and unprefixed format (64 bytes)
|
|
544
|
-
/// @param preimage The preimage which produces sighash used to generate the
|
|
545
|
-
/// ECDSA signature that is the subject of the fraud claim. It is a
|
|
546
|
-
/// serialized subset of the transaction. The exact subset used as
|
|
547
|
-
/// the preimage depends on the transaction input the signature is
|
|
548
|
-
/// produced for. See BIP-143 for reference
|
|
549
|
-
/// @param witness Flag indicating whether the preimage was produced for a
|
|
550
|
-
/// witness input. True for witness, false for non-witness input
|
|
551
|
-
/// @dev Requirements:
|
|
552
|
-
/// - `walletPublicKey` and `sighash` calculated as `hash256(preimage)`
|
|
553
|
-
/// must identify an open fraud challenge
|
|
554
|
-
/// - the preimage must be a valid preimage of a transaction generated
|
|
555
|
-
/// according to the protocol rules and already proved in the Bridge
|
|
556
|
-
/// - before a defeat attempt is made the transaction that spends the
|
|
557
|
-
/// given UTXO must be proven in the Bridge
|
|
558
|
-
function defeatFraudChallenge(
|
|
559
|
-
bytes calldata walletPublicKey,
|
|
560
|
-
bytes calldata preimage,
|
|
561
|
-
bool witness
|
|
562
|
-
) external {
|
|
563
|
-
uint256 utxoKey = frauds.unwrapChallenge(
|
|
564
|
-
walletPublicKey,
|
|
565
|
-
preimage,
|
|
566
|
-
witness
|
|
567
|
-
);
|
|
568
|
-
|
|
569
|
-
// Check that the UTXO key identifies a correctly spent UTXO.
|
|
570
|
-
require(
|
|
571
|
-
self.deposits[utxoKey].sweptAt > 0 || self.spentMainUTXOs[utxoKey],
|
|
572
|
-
"Spent UTXO not found among correctly spent UTXOs"
|
|
573
|
-
);
|
|
574
|
-
|
|
575
|
-
frauds.defeatChallenge(walletPublicKey, preimage, self.treasury);
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
/// @notice Notifies about defeat timeout for the given fraud challenge.
|
|
579
|
-
/// Can be called only if there was a fraud challenge identified by
|
|
580
|
-
/// the provided `walletPublicKey` and `sighash` and it was not
|
|
581
|
-
/// defeated on time. The amount of time that needs to pass after
|
|
582
|
-
/// a fraud challenge is reported is indicated by the
|
|
583
|
-
/// `challengeDefeatTimeout`. After a successful fraud challenge
|
|
584
|
-
/// defeat timeout notification the fraud challenge is marked as
|
|
585
|
-
/// resolved, the stake of each operator is slashed, the ether
|
|
586
|
-
/// deposited is returned to the challenger and the challenger is
|
|
587
|
-
/// rewarded.
|
|
588
|
-
/// @param walletPublicKey The public key of the wallet in the uncompressed
|
|
589
|
-
/// and unprefixed format (64 bytes)
|
|
590
|
-
/// @param sighash The hash that was used to produce the ECDSA signature
|
|
591
|
-
/// that is the subject of the fraud claim. This hash is constructed
|
|
592
|
-
/// by applying double SHA-256 over a serialized subset of the
|
|
593
|
-
/// transaction. The exact subset used as hash preimage depends on
|
|
594
|
-
/// the transaction input the signature is produced for. See BIP-143
|
|
595
|
-
/// for reference
|
|
596
|
-
/// @dev Requirements:
|
|
597
|
-
/// - `walletPublicKey`and `sighash` must identify an open fraud
|
|
598
|
-
/// challenge
|
|
599
|
-
/// - the amount of time indicated by `challengeDefeatTimeout` must
|
|
600
|
-
/// pass after the challenge was reported
|
|
601
|
-
function notifyFraudChallengeDefeatTimeout(
|
|
602
|
-
bytes calldata walletPublicKey,
|
|
603
|
-
bytes32 sighash
|
|
604
|
-
) external {
|
|
605
|
-
frauds.notifyChallengeDefeatTimeout(walletPublicKey, sighash);
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
/// @notice Returns parameters used by the `Frauds` library.
|
|
609
|
-
/// @return slashingAmount Value of the slashing amount
|
|
610
|
-
/// @return notifierRewardMultiplier Value of the notifier reward multiplier
|
|
611
|
-
/// @return challengeDefeatTimeout Value of the challenge defeat timeout
|
|
612
|
-
/// @return challengeDepositAmount Value of the challenge deposit amount
|
|
613
|
-
function getFraudParameters()
|
|
614
|
-
external
|
|
615
|
-
view
|
|
616
|
-
returns (
|
|
617
|
-
uint256 slashingAmount,
|
|
618
|
-
uint256 notifierRewardMultiplier,
|
|
619
|
-
uint256 challengeDefeatTimeout,
|
|
620
|
-
uint256 challengeDepositAmount
|
|
621
|
-
)
|
|
622
|
-
{
|
|
623
|
-
slashingAmount = frauds.slashingAmount;
|
|
624
|
-
notifierRewardMultiplier = frauds.notifierRewardMultiplier;
|
|
625
|
-
challengeDefeatTimeout = frauds.challengeDefeatTimeout;
|
|
626
|
-
challengeDepositAmount = frauds.challengeDepositAmount;
|
|
627
|
-
|
|
628
|
-
return (
|
|
629
|
-
slashingAmount,
|
|
630
|
-
notifierRewardMultiplier,
|
|
631
|
-
challengeDefeatTimeout,
|
|
632
|
-
challengeDepositAmount
|
|
633
|
-
);
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
/// @notice Returns the fraud challenge identified by the given key built
|
|
637
|
-
/// as keccak256(walletPublicKey|sighash).
|
|
638
|
-
function fraudChallenges(uint256 challengeKey)
|
|
639
|
-
external
|
|
640
|
-
view
|
|
641
|
-
returns (Frauds.FraudChallenge memory)
|
|
642
|
-
{
|
|
643
|
-
return frauds.challenges[challengeKey];
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
/// @notice Requests redemption of the given amount from the specified
|
|
647
|
-
/// wallet to the redeemer Bitcoin output script.
|
|
648
|
-
/// @param walletPubKeyHash The 20-byte wallet public key hash (computed
|
|
649
|
-
/// using Bitcoin HASH160 over the compressed ECDSA public key)
|
|
650
|
-
/// @param mainUtxo Data of the wallet's main UTXO, as currently known on
|
|
651
|
-
/// the Ethereum chain
|
|
652
|
-
/// @param redeemerOutputScript The redeemer's length-prefixed output
|
|
653
|
-
/// script (P2PKH, P2WPKH, P2SH or P2WSH) that will be used to lock
|
|
654
|
-
/// redeemed BTC
|
|
655
|
-
/// @param amount Requested amount in satoshi. This is also the TBTC amount
|
|
656
|
-
/// that is taken from redeemer's balance in the Bank upon request.
|
|
657
|
-
/// Once the request is handled, the actual amount of BTC locked
|
|
658
|
-
/// on the redeemer output script will be always lower than this value
|
|
659
|
-
/// since the treasury and Bitcoin transaction fees must be incurred.
|
|
660
|
-
/// The minimal amount satisfying the request can be computed as:
|
|
661
|
-
/// `amount - (amount / redemptionTreasuryFeeDivisor) - redemptionTxMaxFee`.
|
|
662
|
-
/// Fees values are taken at the moment of request creation.
|
|
279
|
+
/// @notice Requests redemption of the given amount from the specified
|
|
280
|
+
/// wallet to the redeemer Bitcoin output script.
|
|
281
|
+
/// @param walletPubKeyHash The 20-byte wallet public key hash (computed
|
|
282
|
+
/// using Bitcoin HASH160 over the compressed ECDSA public key)
|
|
283
|
+
/// @param mainUtxo Data of the wallet's main UTXO, as currently known on
|
|
284
|
+
/// the Ethereum chain
|
|
285
|
+
/// @param redeemerOutputScript The redeemer's length-prefixed output
|
|
286
|
+
/// script (P2PKH, P2WPKH, P2SH or P2WSH) that will be used to lock
|
|
287
|
+
/// redeemed BTC
|
|
288
|
+
/// @param amount Requested amount in satoshi. This is also the TBTC amount
|
|
289
|
+
/// that is taken from redeemer's balance in the Bank upon request.
|
|
290
|
+
/// Once the request is handled, the actual amount of BTC locked
|
|
291
|
+
/// on the redeemer output script will be always lower than this value
|
|
292
|
+
/// since the treasury and Bitcoin transaction fees must be incurred.
|
|
293
|
+
/// The minimal amount satisfying the request can be computed as:
|
|
294
|
+
/// `amount - (amount / redemptionTreasuryFeeDivisor) - redemptionTxMaxFee`.
|
|
295
|
+
/// Fees values are taken at the moment of request creation.
|
|
663
296
|
/// @dev Requirements:
|
|
664
297
|
/// - Wallet behind `walletPubKeyHash` must be live
|
|
665
298
|
/// - `mainUtxo` components must point to the recent main UTXO
|
|
@@ -679,7 +312,6 @@ contract Bridge is Ownable, EcdsaWalletOwner {
|
|
|
679
312
|
uint64 amount
|
|
680
313
|
) external {
|
|
681
314
|
self.requestRedemption(
|
|
682
|
-
wallets,
|
|
683
315
|
walletPubKeyHash,
|
|
684
316
|
mainUtxo,
|
|
685
317
|
redeemerOutputScript,
|
|
@@ -738,7 +370,6 @@ contract Bridge is Ownable, EcdsaWalletOwner {
|
|
|
738
370
|
bytes20 walletPubKeyHash
|
|
739
371
|
) external {
|
|
740
372
|
self.submitRedemptionProof(
|
|
741
|
-
wallets,
|
|
742
373
|
redemptionTx,
|
|
743
374
|
redemptionProof,
|
|
744
375
|
mainUtxo,
|
|
@@ -774,11 +405,7 @@ contract Bridge is Ownable, EcdsaWalletOwner {
|
|
|
774
405
|
bytes20 walletPubKeyHash,
|
|
775
406
|
bytes calldata redeemerOutputScript
|
|
776
407
|
) external {
|
|
777
|
-
self.notifyRedemptionTimeout(
|
|
778
|
-
wallets,
|
|
779
|
-
walletPubKeyHash,
|
|
780
|
-
redeemerOutputScript
|
|
781
|
-
);
|
|
408
|
+
self.notifyRedemptionTimeout(walletPubKeyHash, redeemerOutputScript);
|
|
782
409
|
}
|
|
783
410
|
|
|
784
411
|
/// @notice Used by the wallet to prove the BTC moving funds transaction
|
|
@@ -833,7 +460,6 @@ contract Bridge is Ownable, EcdsaWalletOwner {
|
|
|
833
460
|
bytes20 walletPubKeyHash
|
|
834
461
|
) external {
|
|
835
462
|
self.submitMovingFundsProof(
|
|
836
|
-
wallets,
|
|
837
463
|
movingFundsTx,
|
|
838
464
|
movingFundsProof,
|
|
839
465
|
mainUtxo,
|
|
@@ -841,29 +467,350 @@ contract Bridge is Ownable, EcdsaWalletOwner {
|
|
|
841
467
|
);
|
|
842
468
|
}
|
|
843
469
|
|
|
844
|
-
/// @notice
|
|
845
|
-
///
|
|
846
|
-
///
|
|
847
|
-
///
|
|
848
|
-
function
|
|
849
|
-
|
|
850
|
-
|
|
470
|
+
/// @notice Requests creation of a new wallet. This function just
|
|
471
|
+
/// forms a request and the creation process is performed
|
|
472
|
+
/// asynchronously. Once a wallet is created, the ECDSA Wallet
|
|
473
|
+
/// Registry will notify this contract by calling the
|
|
474
|
+
/// `__ecdsaWalletCreatedCallback` function.
|
|
475
|
+
/// @param activeWalletMainUtxo Data of the active wallet's main UTXO, as
|
|
476
|
+
/// currently known on the Ethereum chain.
|
|
477
|
+
/// @dev Requirements:
|
|
478
|
+
/// - `activeWalletMainUtxo` components must point to the recent main
|
|
479
|
+
/// UTXO of the given active wallet, as currently known on the
|
|
480
|
+
/// Ethereum chain. If there is no active wallet at the moment, or
|
|
481
|
+
/// the active wallet has no main UTXO, this parameter can be
|
|
482
|
+
/// empty as it is ignored.
|
|
483
|
+
/// - Wallet creation must not be in progress
|
|
484
|
+
/// - If the active wallet is set, one of the following
|
|
485
|
+
/// conditions must be true:
|
|
486
|
+
/// - The active wallet BTC balance is above the minimum threshold
|
|
487
|
+
/// and the active wallet is old enough, i.e. the creation period
|
|
488
|
+
/// was elapsed since its creation time
|
|
489
|
+
/// - The active wallet BTC balance is above the maximum threshold
|
|
490
|
+
function requestNewWallet(BitcoinTx.UTXO calldata activeWalletMainUtxo)
|
|
491
|
+
external
|
|
492
|
+
{
|
|
493
|
+
self.requestNewWallet(activeWalletMainUtxo);
|
|
851
494
|
}
|
|
852
495
|
|
|
853
|
-
/// @notice
|
|
854
|
-
///
|
|
855
|
-
|
|
856
|
-
|
|
496
|
+
/// @notice A callback function that is called by the ECDSA Wallet Registry
|
|
497
|
+
/// once a new ECDSA wallet is created.
|
|
498
|
+
/// @param ecdsaWalletID Wallet's unique identifier.
|
|
499
|
+
/// @param publicKeyX Wallet's public key's X coordinate.
|
|
500
|
+
/// @param publicKeyY Wallet's public key's Y coordinate.
|
|
501
|
+
/// @dev Requirements:
|
|
502
|
+
/// - The only caller authorized to call this function is `registry`
|
|
503
|
+
/// - Given wallet data must not belong to an already registered wallet
|
|
504
|
+
function __ecdsaWalletCreatedCallback(
|
|
505
|
+
bytes32 ecdsaWalletID,
|
|
506
|
+
bytes32 publicKeyX,
|
|
507
|
+
bytes32 publicKeyY
|
|
508
|
+
) external override {
|
|
509
|
+
self.registerNewWallet(ecdsaWalletID, publicKeyX, publicKeyY);
|
|
857
510
|
}
|
|
858
511
|
|
|
859
|
-
/// @notice
|
|
860
|
-
///
|
|
861
|
-
|
|
512
|
+
/// @notice A callback function that is called by the ECDSA Wallet Registry
|
|
513
|
+
/// once a wallet heartbeat failure is detected.
|
|
514
|
+
/// @param publicKeyX Wallet's public key's X coordinate
|
|
515
|
+
/// @param publicKeyY Wallet's public key's Y coordinate
|
|
516
|
+
/// @dev Requirements:
|
|
517
|
+
/// - The only caller authorized to call this function is `registry`
|
|
518
|
+
/// - Wallet must be in Live state
|
|
519
|
+
function __ecdsaWalletHeartbeatFailedCallback(
|
|
520
|
+
bytes32,
|
|
521
|
+
bytes32 publicKeyX,
|
|
522
|
+
bytes32 publicKeyY
|
|
523
|
+
) external override {
|
|
524
|
+
self.notifyWalletHeartbeatFailed(publicKeyX, publicKeyY);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/// @notice Notifies that the wallet is either old enough or has too few
|
|
528
|
+
/// satoshis left and qualifies to be closed.
|
|
529
|
+
/// @param walletPubKeyHash 20-byte public key hash of the wallet
|
|
530
|
+
/// @param walletMainUtxo Data of the wallet's main UTXO, as currently
|
|
531
|
+
/// known on the Ethereum chain.
|
|
532
|
+
/// @dev Requirements:
|
|
533
|
+
/// - Wallet must not be set as the current active wallet
|
|
534
|
+
/// - Wallet must exceed the wallet maximum age OR the wallet BTC
|
|
535
|
+
/// balance must be lesser than the minimum threshold. If the latter
|
|
536
|
+
/// case is true, the `walletMainUtxo` components must point to the
|
|
537
|
+
/// recent main UTXO of the given wallet, as currently known on the
|
|
538
|
+
/// Ethereum chain. If the wallet has no main UTXO, this parameter
|
|
539
|
+
/// can be empty as it is ignored since the wallet balance is
|
|
540
|
+
/// assumed to be zero.
|
|
541
|
+
/// - Wallet must be in Live state
|
|
542
|
+
function notifyCloseableWallet(
|
|
543
|
+
bytes20 walletPubKeyHash,
|
|
544
|
+
BitcoinTx.UTXO calldata walletMainUtxo
|
|
545
|
+
) external {
|
|
546
|
+
self.notifyCloseableWallet(walletPubKeyHash, walletMainUtxo);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/// @notice Submits a fraud challenge indicating that a UTXO being under
|
|
550
|
+
/// wallet control was unlocked by the wallet but was not used
|
|
551
|
+
/// according to the protocol rules. That means the wallet signed
|
|
552
|
+
/// a transaction input pointing to that UTXO and there is a unique
|
|
553
|
+
/// sighash and signature pair associated with that input. This
|
|
554
|
+
/// function uses those parameters to create a fraud accusation that
|
|
555
|
+
/// proves a given transaction input unlocking the given UTXO was
|
|
556
|
+
/// actually signed by the wallet. This function cannot determine
|
|
557
|
+
/// whether the transaction was actually broadcast and the input was
|
|
558
|
+
/// consumed in a fraudulent way so it just opens a challenge period
|
|
559
|
+
/// during which the wallet can defeat the challenge by submitting
|
|
560
|
+
/// proof of a transaction that consumes the given input according
|
|
561
|
+
/// to protocol rules. To prevent spurious allegations, the caller
|
|
562
|
+
/// must deposit ETH that is returned back upon justified fraud
|
|
563
|
+
/// challenge or confiscated otherwise.
|
|
564
|
+
///@param walletPublicKey The public key of the wallet in the uncompressed
|
|
565
|
+
/// and unprefixed format (64 bytes)
|
|
566
|
+
/// @param sighash The hash that was used to produce the ECDSA signature
|
|
567
|
+
/// that is the subject of the fraud claim. This hash is constructed
|
|
568
|
+
/// by applying double SHA-256 over a serialized subset of the
|
|
569
|
+
/// transaction. The exact subset used as hash preimage depends on
|
|
570
|
+
/// the transaction input the signature is produced for. See BIP-143
|
|
571
|
+
/// for reference
|
|
572
|
+
/// @param signature Bitcoin signature in the R/S/V format
|
|
573
|
+
/// @dev Requirements:
|
|
574
|
+
/// - Wallet behind `walletPubKey` must be in `Live` or `MovingFunds`
|
|
575
|
+
/// state
|
|
576
|
+
/// - The challenger must send appropriate amount of ETH used as
|
|
577
|
+
/// fraud challenge deposit
|
|
578
|
+
/// - The signature (represented by r, s and v) must be generated by
|
|
579
|
+
/// the wallet behind `walletPubKey` during signing of `sighash`
|
|
580
|
+
/// - Wallet can be challenged for the given signature only once
|
|
581
|
+
function submitFraudChallenge(
|
|
582
|
+
bytes calldata walletPublicKey,
|
|
583
|
+
bytes32 sighash,
|
|
584
|
+
BitcoinTx.RSVSignature calldata signature
|
|
585
|
+
) external payable {
|
|
586
|
+
self.submitFraudChallenge(walletPublicKey, sighash, signature);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/// @notice Allows to defeat a pending fraud challenge against a wallet if
|
|
590
|
+
/// the transaction that spends the UTXO follows the protocol rules.
|
|
591
|
+
/// In order to defeat the challenge the same `walletPublicKey` and
|
|
592
|
+
/// signature (represented by `r`, `s` and `v`) must be provided as
|
|
593
|
+
/// were used to calculate the sighash during input signing.
|
|
594
|
+
/// The fraud challenge defeat attempt will only succeed if the
|
|
595
|
+
/// inputs in the preimage are considered honestly spent by the
|
|
596
|
+
/// wallet. Therefore the transaction spending the UTXO must be
|
|
597
|
+
/// proven in the Bridge before a challenge defeat is called.
|
|
598
|
+
/// If successfully defeated, the fraud challenge is marked as
|
|
599
|
+
/// resolved and the amount of ether deposited by the challenger is
|
|
600
|
+
/// sent to the treasury.
|
|
601
|
+
/// @param walletPublicKey The public key of the wallet in the uncompressed
|
|
602
|
+
/// and unprefixed format (64 bytes)
|
|
603
|
+
/// @param preimage The preimage which produces sighash used to generate the
|
|
604
|
+
/// ECDSA signature that is the subject of the fraud claim. It is a
|
|
605
|
+
/// serialized subset of the transaction. The exact subset used as
|
|
606
|
+
/// the preimage depends on the transaction input the signature is
|
|
607
|
+
/// produced for. See BIP-143 for reference
|
|
608
|
+
/// @param witness Flag indicating whether the preimage was produced for a
|
|
609
|
+
/// witness input. True for witness, false for non-witness input
|
|
610
|
+
/// @dev Requirements:
|
|
611
|
+
/// - `walletPublicKey` and `sighash` calculated as `hash256(preimage)`
|
|
612
|
+
/// must identify an open fraud challenge
|
|
613
|
+
/// - the preimage must be a valid preimage of a transaction generated
|
|
614
|
+
/// according to the protocol rules and already proved in the Bridge
|
|
615
|
+
/// - before a defeat attempt is made the transaction that spends the
|
|
616
|
+
/// given UTXO must be proven in the Bridge
|
|
617
|
+
function defeatFraudChallenge(
|
|
618
|
+
bytes calldata walletPublicKey,
|
|
619
|
+
bytes calldata preimage,
|
|
620
|
+
bool witness
|
|
621
|
+
) external {
|
|
622
|
+
self.defeatFraudChallenge(walletPublicKey, preimage, witness);
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
/// @notice Notifies about defeat timeout for the given fraud challenge.
|
|
626
|
+
/// Can be called only if there was a fraud challenge identified by
|
|
627
|
+
/// the provided `walletPublicKey` and `sighash` and it was not
|
|
628
|
+
/// defeated on time. The amount of time that needs to pass after
|
|
629
|
+
/// a fraud challenge is reported is indicated by the
|
|
630
|
+
/// `challengeDefeatTimeout`. After a successful fraud challenge
|
|
631
|
+
/// defeat timeout notification the fraud challenge is marked as
|
|
632
|
+
/// resolved, the stake of each operator is slashed, the ether
|
|
633
|
+
/// deposited is returned to the challenger and the challenger is
|
|
634
|
+
/// rewarded.
|
|
635
|
+
/// @param walletPublicKey The public key of the wallet in the uncompressed
|
|
636
|
+
/// and unprefixed format (64 bytes)
|
|
637
|
+
/// @param sighash The hash that was used to produce the ECDSA signature
|
|
638
|
+
/// that is the subject of the fraud claim. This hash is constructed
|
|
639
|
+
/// by applying double SHA-256 over a serialized subset of the
|
|
640
|
+
/// transaction. The exact subset used as hash preimage depends on
|
|
641
|
+
/// the transaction input the signature is produced for. See BIP-143
|
|
642
|
+
/// for reference
|
|
643
|
+
/// @dev Requirements:
|
|
644
|
+
/// - `walletPublicKey`and `sighash` must identify an open fraud
|
|
645
|
+
/// challenge
|
|
646
|
+
/// - the amount of time indicated by `challengeDefeatTimeout` must
|
|
647
|
+
/// pass after the challenge was reported
|
|
648
|
+
function notifyFraudChallengeDefeatTimeout(
|
|
649
|
+
bytes calldata walletPublicKey,
|
|
650
|
+
bytes32 sighash
|
|
651
|
+
) external {
|
|
652
|
+
self.notifyFraudChallengeDefeatTimeout(walletPublicKey, sighash);
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
/// @notice Allows the Governance to mark the given vault address as trusted
|
|
656
|
+
/// or no longer trusted. Vaults are not trusted by default.
|
|
657
|
+
/// Trusted vault must meet the following criteria:
|
|
658
|
+
/// - `IVault.receiveBalanceIncrease` must have a known, low gas
|
|
659
|
+
/// cost.
|
|
660
|
+
/// - `IVault.receiveBalanceIncrease` must never revert.
|
|
661
|
+
/// @dev Without restricting reveal only to trusted vaults, malicious
|
|
662
|
+
/// vaults not meeting the criteria would be able to nuke sweep proof
|
|
663
|
+
/// transactions executed by ECDSA wallet with deposits routed to
|
|
664
|
+
/// them.
|
|
665
|
+
/// @param vault The address of the vault
|
|
666
|
+
/// @param isTrusted flag indicating whether the vault is trusted or not
|
|
667
|
+
/// @dev Can only be called by the Governance.
|
|
668
|
+
function setVaultStatus(address vault, bool isTrusted) external onlyOwner {
|
|
669
|
+
self.isVaultTrusted[vault] = isTrusted;
|
|
670
|
+
emit VaultStatusUpdated(vault, isTrusted);
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// TODO: updateDepositParameters
|
|
674
|
+
// TODO: updateRedemptionParameters
|
|
675
|
+
// TODO: updateMovingFundsParameters
|
|
676
|
+
|
|
677
|
+
/// @notice Updates parameters of wallets.
|
|
678
|
+
/// @param walletCreationPeriod New value of the wallet creation period in
|
|
679
|
+
/// seconds, determines how frequently a new wallet creation can be
|
|
680
|
+
/// requested
|
|
681
|
+
/// @param walletMinBtcBalance New value of the wallet minimum BTC balance
|
|
682
|
+
/// in satoshis, used to decide about wallet creation or closing
|
|
683
|
+
/// @param walletMaxBtcBalance New value of the wallet maximum BTC balance
|
|
684
|
+
/// in satoshis, used to decide about wallet creation
|
|
685
|
+
/// @param walletMaxAge New value of the wallet maximum age in seconds,
|
|
686
|
+
/// indicates the maximum age of a wallet in seconds, after which
|
|
687
|
+
/// the wallet moving funds process can be requested
|
|
688
|
+
/// @dev Requirements:
|
|
689
|
+
/// - Wallet minimum BTC balance must be greater than zero
|
|
690
|
+
/// - Wallet maximum BTC balance must be greater than the wallet
|
|
691
|
+
/// minimum BTC balance
|
|
692
|
+
function updateWalletParameters(
|
|
693
|
+
uint32 walletCreationPeriod,
|
|
694
|
+
uint64 walletMinBtcBalance,
|
|
695
|
+
uint64 walletMaxBtcBalance,
|
|
696
|
+
uint32 walletMaxAge
|
|
697
|
+
) external onlyOwner {
|
|
698
|
+
self.updateWalletParameters(
|
|
699
|
+
walletCreationPeriod,
|
|
700
|
+
walletMinBtcBalance,
|
|
701
|
+
walletMaxBtcBalance,
|
|
702
|
+
walletMaxAge
|
|
703
|
+
);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// TODO: updateFraudParameters
|
|
707
|
+
|
|
708
|
+
/// @notice Collection of all revealed deposits indexed by
|
|
709
|
+
/// keccak256(fundingTxHash | fundingOutputIndex).
|
|
710
|
+
/// The fundingTxHash is bytes32 (ordered as in Bitcoin internally)
|
|
711
|
+
/// and fundingOutputIndex an uint32. This mapping may contain valid
|
|
712
|
+
/// and invalid deposits and the wallet is responsible for
|
|
713
|
+
/// validating them before attempting to execute a sweep.
|
|
714
|
+
function deposits(uint256 depositKey)
|
|
715
|
+
external
|
|
716
|
+
view
|
|
717
|
+
returns (Deposit.DepositRequest memory)
|
|
718
|
+
{
|
|
719
|
+
return self.deposits[depositKey];
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
/// @notice Collection of all pending redemption requests indexed by
|
|
723
|
+
/// redemption key built as
|
|
724
|
+
/// keccak256(walletPubKeyHash | redeemerOutputScript). The
|
|
725
|
+
/// walletPubKeyHash is the 20-byte wallet's public key hash
|
|
726
|
+
/// (computed using Bitcoin HASH160 over the compressed ECDSA
|
|
727
|
+
/// public key) and redeemerOutputScript is a Bitcoin script
|
|
728
|
+
/// (P2PKH, P2WPKH, P2SH or P2WSH) that will be used to lock
|
|
729
|
+
/// redeemed BTC as requested by the redeemer. Requests are added
|
|
730
|
+
/// to this mapping by the `requestRedemption` method (duplicates
|
|
731
|
+
/// not allowed) and are removed by one of the following methods:
|
|
732
|
+
/// - `submitRedemptionProof` in case the request was handled
|
|
733
|
+
/// successfully
|
|
734
|
+
/// - `notifyRedemptionTimeout` in case the request was reported
|
|
735
|
+
/// to be timed out
|
|
736
|
+
function pendingRedemptions(uint256 redemptionKey)
|
|
862
737
|
external
|
|
863
738
|
view
|
|
864
|
-
returns (
|
|
739
|
+
returns (Redemption.RedemptionRequest memory)
|
|
865
740
|
{
|
|
866
|
-
|
|
741
|
+
return self.pendingRedemptions[redemptionKey];
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
/// @notice Collection of all timed out redemptions requests indexed by
|
|
745
|
+
/// redemption key built as
|
|
746
|
+
/// keccak256(walletPubKeyHash | redeemerOutputScript). The
|
|
747
|
+
/// walletPubKeyHash is the 20-byte wallet's public key hash
|
|
748
|
+
/// (computed using Bitcoin HASH160 over the compressed ECDSA
|
|
749
|
+
/// public key) and redeemerOutputScript is the Bitcoin script
|
|
750
|
+
/// (P2PKH, P2WPKH, P2SH or P2WSH) that is involved in the timed
|
|
751
|
+
/// out request. Timed out requests are stored in this mapping to
|
|
752
|
+
/// avoid slashing the wallets multiple times for the same timeout.
|
|
753
|
+
/// Only one method can add to this mapping:
|
|
754
|
+
/// - `notifyRedemptionTimeout` which puts the redemption key
|
|
755
|
+
/// to this mapping basing on a timed out request stored
|
|
756
|
+
/// previously in `pendingRedemptions` mapping.
|
|
757
|
+
function timedOutRedemptions(uint256 redemptionKey)
|
|
758
|
+
external
|
|
759
|
+
view
|
|
760
|
+
returns (Redemption.RedemptionRequest memory)
|
|
761
|
+
{
|
|
762
|
+
return self.timedOutRedemptions[redemptionKey];
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
/// @notice Collection of main UTXOs that are honestly spent indexed by
|
|
766
|
+
/// keccak256(fundingTxHash | fundingOutputIndex). The fundingTxHash
|
|
767
|
+
/// is bytes32 (ordered as in Bitcoin internally) and
|
|
768
|
+
/// fundingOutputIndex an uint32. A main UTXO is considered honestly
|
|
769
|
+
/// spent if it was used as an input of a transaction that have been
|
|
770
|
+
/// proven in the Bridge.
|
|
771
|
+
function spentMainUTXOs(uint256 utxoKey) external view returns (bool) {
|
|
772
|
+
return self.spentMainUTXOs[utxoKey];
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
/// @notice Gets details about a registered wallet.
|
|
776
|
+
/// @param walletPubKeyHash The 20-byte wallet public key hash (computed
|
|
777
|
+
/// using Bitcoin HASH160 over the compressed ECDSA public key)
|
|
778
|
+
/// @return Wallet details.
|
|
779
|
+
function wallets(bytes20 walletPubKeyHash)
|
|
780
|
+
external
|
|
781
|
+
view
|
|
782
|
+
returns (Wallets.Wallet memory)
|
|
783
|
+
{
|
|
784
|
+
return self.registeredWallets[walletPubKeyHash];
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
/// @notice Gets the public key hash of the active wallet.
|
|
788
|
+
/// @return The 20-byte public key hash (computed using Bitcoin HASH160
|
|
789
|
+
/// over the compressed ECDSA public key) of the active wallet.
|
|
790
|
+
/// Returns bytes20(0) if there is no active wallet at the moment.
|
|
791
|
+
function activeWalletPubKeyHash() external view returns (bytes20) {
|
|
792
|
+
return self.activeWalletPubKeyHash;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
/// @notice Returns the fraud challenge identified by the given key built
|
|
796
|
+
/// as keccak256(walletPublicKey|sighash).
|
|
797
|
+
function fraudChallenges(uint256 challengeKey)
|
|
798
|
+
external
|
|
799
|
+
view
|
|
800
|
+
returns (Fraud.FraudChallenge memory)
|
|
801
|
+
{
|
|
802
|
+
return self.fraudChallenges[challengeKey];
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
/// @notice Indicates if the vault with the given address is trusted or not.
|
|
806
|
+
/// Depositors can route their revealed deposits only to trusted
|
|
807
|
+
/// vaults and have trusted vaults notified about new deposits as
|
|
808
|
+
/// soon as these deposits get swept. Vaults not trusted by the
|
|
809
|
+
/// Bridge can still be used by Bank balance owners on their own
|
|
810
|
+
/// responsibility - anyone can approve their Bank balance to any
|
|
811
|
+
/// address.
|
|
812
|
+
function isVaultTrusted(address vault) external view returns (bool) {
|
|
813
|
+
return self.isVaultTrusted[vault];
|
|
867
814
|
}
|
|
868
815
|
|
|
869
816
|
/// @notice Returns the current values of Bridge deposit parameters.
|
|
@@ -927,9 +874,7 @@ contract Bridge is Ownable, EcdsaWalletOwner {
|
|
|
927
874
|
uint64 redemptionDustThreshold,
|
|
928
875
|
uint64 redemptionTreasuryFeeDivisor,
|
|
929
876
|
uint64 redemptionTxMaxFee,
|
|
930
|
-
uint256 redemptionTimeout
|
|
931
|
-
address treasury,
|
|
932
|
-
uint256 txProofDifficultyFactor
|
|
877
|
+
uint256 redemptionTimeout
|
|
933
878
|
)
|
|
934
879
|
{
|
|
935
880
|
redemptionDustThreshold = self.redemptionDustThreshold;
|
|
@@ -953,81 +898,78 @@ contract Bridge is Ownable, EcdsaWalletOwner {
|
|
|
953
898
|
movingFundsTxMaxTotalFee = self.movingFundsTxMaxTotalFee;
|
|
954
899
|
}
|
|
955
900
|
|
|
956
|
-
/// @
|
|
957
|
-
///
|
|
958
|
-
///
|
|
959
|
-
///
|
|
960
|
-
///
|
|
961
|
-
///
|
|
962
|
-
///
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
}
|
|
966
|
-
|
|
967
|
-
/// @notice Collection of all revealed deposits indexed by
|
|
968
|
-
/// keccak256(fundingTxHash | fundingOutputIndex).
|
|
969
|
-
/// The fundingTxHash is bytes32 (ordered as in Bitcoin internally)
|
|
970
|
-
/// and fundingOutputIndex an uint32. This mapping may contain valid
|
|
971
|
-
/// and invalid deposits and the wallet is responsible for
|
|
972
|
-
/// validating them before attempting to execute a sweep.
|
|
973
|
-
function deposits(uint256 depositKey)
|
|
901
|
+
/// @return walletCreationPeriod Determines how frequently a new wallet
|
|
902
|
+
/// creation can be requested. Value in seconds.
|
|
903
|
+
/// @return walletMinBtcBalance The minimum BTC threshold in satoshi that is
|
|
904
|
+
/// used to decide about wallet creation or closing.
|
|
905
|
+
/// @return walletMaxBtcBalance The maximum BTC threshold in satoshi that is
|
|
906
|
+
/// used to decide about wallet creation.
|
|
907
|
+
/// @return walletMaxAge The maximum age of a wallet in seconds, after which
|
|
908
|
+
/// the wallet moving funds process can be requested.
|
|
909
|
+
function walletParameters()
|
|
974
910
|
external
|
|
975
911
|
view
|
|
976
|
-
returns (
|
|
912
|
+
returns (
|
|
913
|
+
uint32 walletCreationPeriod,
|
|
914
|
+
uint64 walletMinBtcBalance,
|
|
915
|
+
uint64 walletMaxBtcBalance,
|
|
916
|
+
uint32 walletMaxAge
|
|
917
|
+
)
|
|
977
918
|
{
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
///
|
|
985
|
-
///
|
|
986
|
-
///
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
///
|
|
992
|
-
///
|
|
993
|
-
///
|
|
994
|
-
|
|
995
|
-
/// (computed using Bitcoin HASH160 over the compressed ECDSA
|
|
996
|
-
/// public key) and redeemerOutputScript is a Bitcoin script
|
|
997
|
-
/// (P2PKH, P2WPKH, P2SH or P2WSH) that will be used to lock
|
|
998
|
-
/// redeemed BTC as requested by the redeemer. Requests are added
|
|
999
|
-
/// to this mapping by the `requestRedemption` method (duplicates
|
|
1000
|
-
/// not allowed) and are removed by one of the following methods:
|
|
1001
|
-
/// - `submitRedemptionProof` in case the request was handled
|
|
1002
|
-
/// successfully
|
|
1003
|
-
/// - `notifyRedemptionTimeout` in case the request was reported
|
|
1004
|
-
/// to be timed out
|
|
1005
|
-
function pendingRedemptions(uint256 redemptionKey)
|
|
919
|
+
walletCreationPeriod = self.walletCreationPeriod;
|
|
920
|
+
walletMinBtcBalance = self.walletMinBtcBalance;
|
|
921
|
+
walletMaxBtcBalance = self.walletMaxBtcBalance;
|
|
922
|
+
walletMaxAge = self.walletMaxAge;
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
/// @notice Returns the current values of Bridge fraud parameters.
|
|
926
|
+
/// @return fraudSlashingAmount The amount slashed from each wallet member
|
|
927
|
+
/// for committing a fraud.
|
|
928
|
+
/// @return fraudNotifierRewardMultiplier The percentage of the notifier
|
|
929
|
+
/// reward from the staking contract the notifier of a fraud
|
|
930
|
+
/// receives. The value is in the range [0, 100].
|
|
931
|
+
/// @return fraudChallengeDefeatTimeout The amount of time the wallet has to
|
|
932
|
+
/// defeat a fraud challenge.
|
|
933
|
+
/// @return fraudChallengeDepositAmount The amount of ETH in wei the party
|
|
934
|
+
/// challenging the wallet for fraud needs to deposit.
|
|
935
|
+
function fraudParameters()
|
|
1006
936
|
external
|
|
1007
937
|
view
|
|
1008
|
-
returns (
|
|
938
|
+
returns (
|
|
939
|
+
uint256 fraudSlashingAmount,
|
|
940
|
+
uint256 fraudNotifierRewardMultiplier,
|
|
941
|
+
uint256 fraudChallengeDefeatTimeout,
|
|
942
|
+
uint256 fraudChallengeDepositAmount
|
|
943
|
+
)
|
|
1009
944
|
{
|
|
1010
|
-
|
|
945
|
+
fraudSlashingAmount = self.fraudSlashingAmount;
|
|
946
|
+
fraudNotifierRewardMultiplier = self.fraudNotifierRewardMultiplier;
|
|
947
|
+
fraudChallengeDefeatTimeout = self.fraudChallengeDefeatTimeout;
|
|
948
|
+
fraudChallengeDepositAmount = self.fraudChallengeDepositAmount;
|
|
1011
949
|
}
|
|
1012
950
|
|
|
1013
|
-
/// @notice
|
|
1014
|
-
///
|
|
1015
|
-
///
|
|
1016
|
-
///
|
|
1017
|
-
|
|
1018
|
-
/// public key) and redeemerOutputScript is the Bitcoin script
|
|
1019
|
-
/// (P2PKH, P2WPKH, P2SH or P2WSH) that is involved in the timed
|
|
1020
|
-
/// out request. Timed out requests are stored in this mapping to
|
|
1021
|
-
/// avoid slashing the wallets multiple times for the same timeout.
|
|
1022
|
-
/// Only one method can add to this mapping:
|
|
1023
|
-
/// - `notifyRedemptionTimeout` which puts the redemption key
|
|
1024
|
-
/// to this mapping basing on a timed out request stored
|
|
1025
|
-
/// previously in `pendingRedemptions` mapping.
|
|
1026
|
-
function timedOutRedemptions(uint256 redemptionKey)
|
|
951
|
+
/// @notice Returns the addresses of contracts Bridge is interacting with.
|
|
952
|
+
/// @return bank Address of the Bank the Bridge belongs to.
|
|
953
|
+
/// @return relay Address of the Bitcoin relay providing the current Bitcoin
|
|
954
|
+
/// network difficulty.
|
|
955
|
+
function contractReferences()
|
|
1027
956
|
external
|
|
1028
957
|
view
|
|
1029
|
-
returns (
|
|
958
|
+
returns (Bank bank, IRelay relay)
|
|
1030
959
|
{
|
|
1031
|
-
|
|
960
|
+
bank = self.bank;
|
|
961
|
+
relay = self.relay;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
/// @notice Address where the deposit treasury fees will be sent to.
|
|
965
|
+
/// Treasury takes part in the operators rewarding process.
|
|
966
|
+
function treasury() external view returns (address) {
|
|
967
|
+
return self.treasury;
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
/// @notice The number of confirmations on the Bitcoin chain required to
|
|
971
|
+
/// successfully evaluate an SPV proof.
|
|
972
|
+
function txProofDifficultyFactor() external view returns (uint256) {
|
|
973
|
+
return self.txProofDifficultyFactor;
|
|
1032
974
|
}
|
|
1033
975
|
}
|