@keep-network/tbtc-v2 0.1.1-dev.41 → 0.1.1-dev.44
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/Bank.json +742 -0
- package/artifacts/Bridge.json +2914 -0
- package/artifacts/Deposit.json +117 -0
- package/artifacts/EcdsaDkgValidator.json +532 -0
- package/artifacts/EcdsaInactivity.json +156 -0
- package/artifacts/Fraud.json +153 -0
- package/artifacts/KeepRegistry.json +99 -0
- package/artifacts/KeepStake.json +286 -0
- package/artifacts/KeepToken.json +711 -0
- package/artifacts/KeepTokenStaking.json +483 -0
- package/artifacts/MovingFunds.json +137 -0
- package/artifacts/NuCypherStakingEscrow.json +256 -0
- package/artifacts/NuCypherToken.json +711 -0
- package/artifacts/RandomBeaconStub.json +141 -0
- package/artifacts/Redemption.json +161 -0
- package/artifacts/ReimbursementPool.json +509 -0
- package/artifacts/Relay.json +123 -0
- package/artifacts/SortitionPool.json +944 -0
- package/artifacts/Sweep.json +76 -0
- package/artifacts/T.json +1148 -0
- package/artifacts/TBTC.json +21 -21
- package/artifacts/TBTCToken.json +21 -21
- package/artifacts/TokenStaking.json +2288 -0
- package/artifacts/TokenholderGovernor.json +1795 -0
- package/artifacts/TokenholderTimelock.json +1058 -0
- package/artifacts/VendingMachine.json +24 -24
- package/artifacts/VendingMachineKeep.json +400 -0
- package/artifacts/VendingMachineNuCypher.json +400 -0
- package/artifacts/WalletRegistry.json +2709 -0
- package/artifacts/WalletRegistryGovernance.json +2364 -0
- package/artifacts/Wallets.json +186 -0
- package/artifacts/solcInputs/{e9b173393b9fd7287a0bfaa6d4eb4b71.json → bbe44823ec28554a9429cce5cafee035.json} +34 -34
- 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 +535 -273
- package/build/contracts/bridge/BridgeState.sol/BridgeState.dbg.json +1 -1
- package/build/contracts/bridge/BridgeState.sol/BridgeState.json +147 -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 +1 -1
- package/build/contracts/bridge/Fraud.sol/Fraud.json +5 -57
- 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 +41 -21
- 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 +12 -38
- 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 +765 -524
- package/contracts/bridge/BridgeState.sol +312 -23
- package/contracts/bridge/Deposit.sol +25 -6
- package/contracts/bridge/EcdsaLib.sol +15 -0
- package/contracts/bridge/Fraud.sol +65 -33
- package/contracts/bridge/MovingFunds.sol +196 -10
- package/contracts/bridge/{Redeem.sol → Redemption.sol} +26 -29
- package/contracts/bridge/Sweep.sol +16 -12
- package/contracts/bridge/Wallets.sol +90 -153
- package/deploy/00_resolve_relay.ts +28 -0
- package/deploy/04_deploy_bank.ts +25 -0
- package/deploy/05_deploy_bridge.ts +60 -0
- package/deploy/06_bank_update_bridge.ts +19 -0
- package/deploy/07_transfer_ownership.ts +17 -0
- package/export.json +14797 -459
- package/package.json +2 -2
- 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
|
@@ -15,23 +15,28 @@
|
|
|
15
15
|
|
|
16
16
|
pragma solidity ^0.8.9;
|
|
17
17
|
|
|
18
|
+
import {IWalletRegistry as EcdsaWalletRegistry} from "@keep-network/ecdsa/contracts/api/IWalletRegistry.sol";
|
|
19
|
+
|
|
18
20
|
import "./IRelay.sol";
|
|
19
21
|
import "./Deposit.sol";
|
|
20
|
-
import "./
|
|
22
|
+
import "./Redemption.sol";
|
|
21
23
|
import "./Fraud.sol";
|
|
24
|
+
import "./Wallets.sol";
|
|
22
25
|
|
|
23
26
|
import "../bank/Bank.sol";
|
|
24
27
|
|
|
25
28
|
library BridgeState {
|
|
26
29
|
// TODO: Make parameters governable
|
|
27
30
|
struct Storage {
|
|
28
|
-
//
|
|
29
|
-
// successfully evaluate an SPV proof.
|
|
30
|
-
uint256 txProofDifficultyFactor;
|
|
31
|
-
// Address of the Bank this Bridge belongs to.
|
|
31
|
+
// Address of the Bank the Bridge belongs to.
|
|
32
32
|
Bank bank;
|
|
33
33
|
// Bitcoin relay providing the current Bitcoin network difficulty.
|
|
34
34
|
IRelay relay;
|
|
35
|
+
// ECDSA Wallet Registry contract handle.
|
|
36
|
+
EcdsaWalletRegistry ecdsaWalletRegistry;
|
|
37
|
+
// The number of confirmations on the Bitcoin chain required to
|
|
38
|
+
// successfully evaluate an SPV proof.
|
|
39
|
+
uint256 txProofDifficultyFactor;
|
|
35
40
|
// Address where the deposit and redemption treasury fees will be sent
|
|
36
41
|
// to. Treasury takes part in the operators rewarding process.
|
|
37
42
|
address treasury;
|
|
@@ -78,6 +83,11 @@ library BridgeState {
|
|
|
78
83
|
// if per single redemption. `movingFundsTxMaxTotalFee` is a total
|
|
79
84
|
// fee for the entire transaction.
|
|
80
85
|
uint64 movingFundsTxMaxTotalFee;
|
|
86
|
+
// Time after which the moving funds process can be reported as
|
|
87
|
+
// timed out. It is counted from the moment when the wallet
|
|
88
|
+
// was requested to move their funds and switched to the MovingFunds
|
|
89
|
+
// state. Value in seconds.
|
|
90
|
+
uint32 movingFundsTimeout;
|
|
81
91
|
// The minimal amount that can be requested for redemption.
|
|
82
92
|
// Value of this parameter must take into account the value of
|
|
83
93
|
// `redemptionTreasuryFeeDivisor` and `redemptionTxMaxFee`
|
|
@@ -120,7 +130,7 @@ library BridgeState {
|
|
|
120
130
|
// successfully
|
|
121
131
|
// - `notifyRedemptionTimeout` in case the request was reported
|
|
122
132
|
// to be timed out
|
|
123
|
-
mapping(uint256 =>
|
|
133
|
+
mapping(uint256 => Redemption.RedemptionRequest) pendingRedemptions;
|
|
124
134
|
// Collection of all timed out redemptions requests indexed by
|
|
125
135
|
// redemption key built as
|
|
126
136
|
// `keccak256(walletPubKeyHash | redeemerOutputScript)`. The
|
|
@@ -134,7 +144,7 @@ library BridgeState {
|
|
|
134
144
|
// - `notifyRedemptionTimeout` which puts the redemption key to this
|
|
135
145
|
// mapping basing on a timed out request stored previously in
|
|
136
146
|
// `pendingRedemptions` mapping.
|
|
137
|
-
mapping(uint256 =>
|
|
147
|
+
mapping(uint256 => Redemption.RedemptionRequest) timedOutRedemptions;
|
|
138
148
|
// The amount of stake slashed from each member of a wallet for a fraud.
|
|
139
149
|
uint256 fraudSlashingAmount;
|
|
140
150
|
// The percentage of the notifier reward from the staking contract
|
|
@@ -155,23 +165,302 @@ library BridgeState {
|
|
|
155
165
|
// spent if it was used as an input of a transaction that have been
|
|
156
166
|
// proven in the Bridge.
|
|
157
167
|
mapping(uint256 => bool) spentMainUTXOs;
|
|
168
|
+
// Determines how frequently a new wallet creation can be requested.
|
|
169
|
+
// Value in seconds.
|
|
170
|
+
uint32 walletCreationPeriod;
|
|
171
|
+
// The minimum BTC threshold in satoshi that is used to decide about
|
|
172
|
+
// wallet creation or closing.
|
|
173
|
+
uint64 walletMinBtcBalance;
|
|
174
|
+
// The maximum BTC threshold in satoshi that is used to decide about
|
|
175
|
+
// wallet creation.
|
|
176
|
+
uint64 walletMaxBtcBalance;
|
|
177
|
+
// The maximum age of a wallet in seconds, after which the wallet
|
|
178
|
+
// moving funds process can be requested.
|
|
179
|
+
uint32 walletMaxAge;
|
|
180
|
+
// 20-byte wallet public key hash being reference to the currently
|
|
181
|
+
// active wallet. Can be unset to the zero value under certain
|
|
182
|
+
// circumstances.
|
|
183
|
+
bytes20 activeWalletPubKeyHash;
|
|
184
|
+
// The current number of wallets in the Live state.
|
|
185
|
+
uint32 liveWalletsCount;
|
|
186
|
+
// The maximum BTC amount in satoshi than can be transferred to a single
|
|
187
|
+
// target wallet during the moving funds process.
|
|
188
|
+
uint64 walletMaxBtcTransfer;
|
|
189
|
+
// Maps the 20-byte wallet public key hash (computed using Bitcoin
|
|
190
|
+
// HASH160 over the compressed ECDSA public key) to the basic wallet
|
|
191
|
+
// information like state and pending redemptions value.
|
|
192
|
+
mapping(bytes20 => Wallets.Wallet) registeredWallets;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
event DepositParametersUpdated(
|
|
196
|
+
uint64 depositDustThreshold,
|
|
197
|
+
uint64 depositTreasuryFeeDivisor,
|
|
198
|
+
uint64 depositTxMaxFee
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
event RedemptionParametersUpdated(
|
|
202
|
+
uint64 redemptionDustThreshold,
|
|
203
|
+
uint64 redemptionTreasuryFeeDivisor,
|
|
204
|
+
uint64 redemptionTxMaxFee,
|
|
205
|
+
uint256 redemptionTimeout
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
event MovingFundsParametersUpdated(
|
|
209
|
+
uint64 movingFundsTxMaxTotalFee,
|
|
210
|
+
uint32 movingFundsTimeout
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
event WalletParametersUpdated(
|
|
214
|
+
uint32 walletCreationPeriod,
|
|
215
|
+
uint64 walletMinBtcBalance,
|
|
216
|
+
uint64 walletMaxBtcBalance,
|
|
217
|
+
uint32 walletMaxAge,
|
|
218
|
+
uint64 walletMaxBtcTransfer
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
event FraudParametersUpdated(
|
|
222
|
+
uint256 fraudSlashingAmount,
|
|
223
|
+
uint256 fraudNotifierRewardMultiplier,
|
|
224
|
+
uint256 fraudChallengeDefeatTimeout,
|
|
225
|
+
uint256 fraudChallengeDepositAmount
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
/// @notice Updates parameters of deposits.
|
|
229
|
+
/// @param _depositDustThreshold New value of the deposit dust threshold in
|
|
230
|
+
/// satoshis. It is the minimal amount that can be requested to
|
|
231
|
+
//// deposit. Value of this parameter must take into account the value
|
|
232
|
+
/// of `depositTreasuryFeeDivisor` and `depositTxMaxFee` parameters
|
|
233
|
+
/// in order to make requests that can incur the treasury and
|
|
234
|
+
/// transaction fee and still satisfy the depositor
|
|
235
|
+
/// @param _depositTreasuryFeeDivisor New value of the treasury fee divisor.
|
|
236
|
+
/// It is the divisor used to compute the treasury fee taken from
|
|
237
|
+
/// each deposit and transferred to the treasury upon sweep proof
|
|
238
|
+
/// submission. That fee is computed as follows:
|
|
239
|
+
/// `treasuryFee = depositedAmount / depositTreasuryFeeDivisor`
|
|
240
|
+
/// For example, if the treasury fee needs to be 2% of each deposit,
|
|
241
|
+
/// the `depositTreasuryFeeDivisor` should be set to `50`
|
|
242
|
+
/// because `1/50 = 0.02 = 2%`
|
|
243
|
+
/// @param _depositTxMaxFee New value of the deposit tx max fee in satoshis.
|
|
244
|
+
/// It is the maximum amount of BTC transaction fee that can
|
|
245
|
+
/// be incurred by each swept deposit being part of the given sweep
|
|
246
|
+
/// transaction. If the maximum BTC transaction fee is exceeded,
|
|
247
|
+
/// such transaction is considered a fraud
|
|
248
|
+
/// @dev Requirements:
|
|
249
|
+
/// - Deposit treasury fee divisor must be greater than zero
|
|
250
|
+
function updateDepositParameters(
|
|
251
|
+
Storage storage self,
|
|
252
|
+
uint64 _depositDustThreshold,
|
|
253
|
+
uint64 _depositTreasuryFeeDivisor,
|
|
254
|
+
uint64 _depositTxMaxFee
|
|
255
|
+
) internal {
|
|
256
|
+
require(
|
|
257
|
+
_depositTreasuryFeeDivisor > 0,
|
|
258
|
+
"Deposit treasury fee divisor must be greater than zero"
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
self.depositDustThreshold = _depositDustThreshold;
|
|
262
|
+
self.depositTreasuryFeeDivisor = _depositTreasuryFeeDivisor;
|
|
263
|
+
self.depositTxMaxFee = _depositTxMaxFee;
|
|
264
|
+
|
|
265
|
+
emit DepositParametersUpdated(
|
|
266
|
+
_depositDustThreshold,
|
|
267
|
+
_depositTreasuryFeeDivisor,
|
|
268
|
+
_depositTxMaxFee
|
|
269
|
+
);
|
|
158
270
|
}
|
|
159
271
|
|
|
160
|
-
|
|
161
|
-
/// @
|
|
162
|
-
///
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
272
|
+
/// @notice Updates parameters of redemptions.
|
|
273
|
+
/// @param _redemptionDustThreshold New value of the redemption dust
|
|
274
|
+
/// threshold in satoshis. It is the minimal amount that can be
|
|
275
|
+
/// requested for redemption. Value of this parameter must take into
|
|
276
|
+
/// account the value of `redemptionTreasuryFeeDivisor` and
|
|
277
|
+
/// `redemptionTxMaxFee` parameters in order to make requests that
|
|
278
|
+
/// can incur the treasury and transaction fee and still satisfy the
|
|
279
|
+
/// redeemer.
|
|
280
|
+
/// @param _redemptionTreasuryFeeDivisor New value of the redemption
|
|
281
|
+
/// treasury fee divisor. It is the divisor used to compute the
|
|
282
|
+
/// treasury fee taken from each redemption request and transferred
|
|
283
|
+
/// to the treasury upon successful request finalization. That fee is
|
|
284
|
+
/// computed as follows:
|
|
285
|
+
/// `treasuryFee = requestedAmount / redemptionTreasuryFeeDivisor`
|
|
286
|
+
/// For example, if the treasury fee needs to be 2% of each
|
|
287
|
+
/// redemption request, the `redemptionTreasuryFeeDivisor` should
|
|
288
|
+
/// be set to `50` because `1/50 = 0.02 = 2%`.
|
|
289
|
+
/// @param _redemptionTxMaxFee New value of the redemption transaction max
|
|
290
|
+
/// fee in satoshis. It is the maximum amount of BTC transaction fee
|
|
291
|
+
/// that can be incurred by each redemption request being part of the
|
|
292
|
+
/// given redemption transaction. If the maximum BTC transaction fee
|
|
293
|
+
/// is exceeded, such transaction is considered a fraud.
|
|
294
|
+
/// @param _redemptionTimeout New value of the redemption timeout in seconds.
|
|
295
|
+
/// It is the time after which the redemption request can be reported
|
|
296
|
+
/// as timed out. It is counted from the moment when the redemption
|
|
297
|
+
/// request was created via `requestRedemption` call. Reported timed
|
|
298
|
+
/// out requests are cancelled and locked TBTC is returned to the
|
|
299
|
+
/// redeemer in full amount.
|
|
300
|
+
/// @dev Requirements:
|
|
301
|
+
/// - Redemption treasury fee divisor must be greater than zero
|
|
302
|
+
/// - Redemption timeout must be greater than zero
|
|
303
|
+
function updateRedemptionParameters(
|
|
304
|
+
Storage storage self,
|
|
305
|
+
uint64 _redemptionDustThreshold,
|
|
306
|
+
uint64 _redemptionTreasuryFeeDivisor,
|
|
307
|
+
uint64 _redemptionTxMaxFee,
|
|
308
|
+
uint256 _redemptionTimeout
|
|
309
|
+
) internal {
|
|
310
|
+
require(
|
|
311
|
+
_redemptionTreasuryFeeDivisor > 0,
|
|
312
|
+
"Redemption treasury fee divisor must be greater than zero"
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
require(
|
|
316
|
+
_redemptionTimeout > 0,
|
|
317
|
+
"Redemption timeout must be greater than zero"
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
self.redemptionDustThreshold = _redemptionDustThreshold;
|
|
321
|
+
self.redemptionTreasuryFeeDivisor = _redemptionTreasuryFeeDivisor;
|
|
322
|
+
self.redemptionTxMaxFee = _redemptionTxMaxFee;
|
|
323
|
+
self.redemptionTimeout = _redemptionTimeout;
|
|
324
|
+
|
|
325
|
+
emit RedemptionParametersUpdated(
|
|
326
|
+
_redemptionDustThreshold,
|
|
327
|
+
_redemptionTreasuryFeeDivisor,
|
|
328
|
+
_redemptionTxMaxFee,
|
|
329
|
+
_redemptionTimeout
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/// @notice Updates parameters of moving funds.
|
|
334
|
+
/// @param _movingFundsTxMaxTotalFee New value of the moving funds transaction
|
|
335
|
+
/// max total fee in satoshis. It is the maximum amount of the total
|
|
336
|
+
/// BTC transaction fee that is acceptable in a single moving funds
|
|
337
|
+
/// transaction. This is a _total_ max fee for the entire moving
|
|
338
|
+
/// funds transaction.
|
|
339
|
+
/// @param _movingFundsTimeout New value of the moving funds timeout in
|
|
340
|
+
/// seconds. It is the time after which the moving funds process can
|
|
341
|
+
/// be reported as timed out. It is counted from the moment when the
|
|
342
|
+
/// wallet was requested to move their funds and switched to the
|
|
343
|
+
/// MovingFunds state.
|
|
344
|
+
/// @dev Requirements:
|
|
345
|
+
/// - Moving funds timeout must be greater than zero
|
|
346
|
+
function updateMovingFundsParameters(
|
|
347
|
+
Storage storage self,
|
|
348
|
+
uint64 _movingFundsTxMaxTotalFee,
|
|
349
|
+
uint32 _movingFundsTimeout
|
|
350
|
+
) internal {
|
|
351
|
+
require(
|
|
352
|
+
_movingFundsTimeout > 0,
|
|
353
|
+
"Moving funds timeout must be greater than zero"
|
|
354
|
+
);
|
|
355
|
+
|
|
356
|
+
self.movingFundsTxMaxTotalFee = _movingFundsTxMaxTotalFee;
|
|
357
|
+
self.movingFundsTimeout = _movingFundsTimeout;
|
|
358
|
+
|
|
359
|
+
emit MovingFundsParametersUpdated(
|
|
360
|
+
_movingFundsTxMaxTotalFee,
|
|
361
|
+
_movingFundsTimeout
|
|
362
|
+
);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/// @notice Updates parameters of wallets.
|
|
366
|
+
/// @param _walletCreationPeriod New value of the wallet creation period in
|
|
367
|
+
/// seconds, determines how frequently a new wallet creation can be
|
|
368
|
+
/// requested
|
|
369
|
+
/// @param _walletMinBtcBalance New value of the wallet minimum BTC balance
|
|
370
|
+
/// in satoshi, used to decide about wallet creation or closing
|
|
371
|
+
/// @param _walletMaxBtcBalance New value of the wallet maximum BTC balance
|
|
372
|
+
/// in satoshi, used to decide about wallet creation
|
|
373
|
+
/// @param _walletMaxAge New value of the wallet maximum age in seconds,
|
|
374
|
+
/// indicates the maximum age of a wallet in seconds, after which
|
|
375
|
+
/// the wallet moving funds process can be requested
|
|
376
|
+
/// @param _walletMaxBtcTransfer New value of the wallet maximum BTC transfer
|
|
377
|
+
/// in satoshi, determines the maximum amount that can be transferred
|
|
378
|
+
// to a single target wallet during the moving funds process
|
|
379
|
+
/// @dev Requirements:
|
|
380
|
+
/// - Wallet minimum BTC balance must be greater than zero
|
|
381
|
+
/// - Wallet maximum BTC balance must be greater than the wallet
|
|
382
|
+
/// minimum BTC balance
|
|
383
|
+
/// - Wallet maximum BTC transfer must be greater than zero
|
|
384
|
+
function updateWalletParameters(
|
|
385
|
+
Storage storage self,
|
|
386
|
+
uint32 _walletCreationPeriod,
|
|
387
|
+
uint64 _walletMinBtcBalance,
|
|
388
|
+
uint64 _walletMaxBtcBalance,
|
|
389
|
+
uint32 _walletMaxAge,
|
|
390
|
+
uint64 _walletMaxBtcTransfer
|
|
391
|
+
) internal {
|
|
392
|
+
require(
|
|
393
|
+
_walletMinBtcBalance > 0,
|
|
394
|
+
"Wallet minimum BTC balance must be greater than zero"
|
|
395
|
+
);
|
|
396
|
+
require(
|
|
397
|
+
_walletMaxBtcBalance > _walletMinBtcBalance,
|
|
398
|
+
"Wallet maximum BTC balance must be greater than the minimum"
|
|
399
|
+
);
|
|
400
|
+
require(
|
|
401
|
+
_walletMaxBtcTransfer > 0,
|
|
402
|
+
"Wallet maximum BTC transfer must be greater than zero"
|
|
403
|
+
);
|
|
404
|
+
|
|
405
|
+
self.walletCreationPeriod = _walletCreationPeriod;
|
|
406
|
+
self.walletMinBtcBalance = _walletMinBtcBalance;
|
|
407
|
+
self.walletMaxBtcBalance = _walletMaxBtcBalance;
|
|
408
|
+
self.walletMaxAge = _walletMaxAge;
|
|
409
|
+
self.walletMaxBtcTransfer = _walletMaxBtcTransfer;
|
|
410
|
+
|
|
411
|
+
emit WalletParametersUpdated(
|
|
412
|
+
_walletCreationPeriod,
|
|
413
|
+
_walletMinBtcBalance,
|
|
414
|
+
_walletMaxBtcBalance,
|
|
415
|
+
_walletMaxAge,
|
|
416
|
+
_walletMaxBtcTransfer
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/// @notice Updates parameters related to frauds.
|
|
421
|
+
/// @param _fraudSlashingAmount New value of the fraud slashing amount in T,
|
|
422
|
+
/// it is the amount slashed from each wallet member for committing
|
|
423
|
+
/// a fraud
|
|
424
|
+
/// @param _fraudNotifierRewardMultiplier New value of the fraud notifier
|
|
425
|
+
/// reward multiplier as percentage, it determines the percentage of
|
|
426
|
+
/// the notifier reward from the staking contact the notifier of
|
|
427
|
+
/// a fraud receives. The value must be in the range [0, 100]
|
|
428
|
+
/// @param _fraudChallengeDefeatTimeout New value of the challenge defeat
|
|
429
|
+
/// timeout in seconds, it is the amount of time the wallet has to
|
|
430
|
+
/// defeat a fraud challenge. The value must be greater than zero
|
|
431
|
+
/// @param _fraudChallengeDepositAmount New value of the fraud challenge
|
|
432
|
+
/// deposit amount in wei, it is the amount of ETH the party
|
|
433
|
+
/// challenging the wallet for fraud needs to deposit
|
|
434
|
+
/// @dev Requirements:
|
|
435
|
+
/// - Fraud notifier reward multiplier must be in the range [0, 100]
|
|
436
|
+
/// - Fraud challenge defeat timeout must be greater than 0
|
|
437
|
+
function updateFraudParameters(
|
|
438
|
+
Storage storage self,
|
|
439
|
+
uint256 _fraudSlashingAmount,
|
|
440
|
+
uint256 _fraudNotifierRewardMultiplier,
|
|
441
|
+
uint256 _fraudChallengeDefeatTimeout,
|
|
442
|
+
uint256 _fraudChallengeDepositAmount
|
|
443
|
+
) internal {
|
|
444
|
+
require(
|
|
445
|
+
_fraudNotifierRewardMultiplier <= 100,
|
|
446
|
+
"Fraud notifier reward multiplier must be in the range [0, 100]"
|
|
447
|
+
);
|
|
448
|
+
|
|
449
|
+
require(
|
|
450
|
+
_fraudChallengeDefeatTimeout > 0,
|
|
451
|
+
"Fraud challenge defeat timeout must be greater than zero"
|
|
452
|
+
);
|
|
453
|
+
|
|
454
|
+
self.fraudSlashingAmount = _fraudSlashingAmount;
|
|
455
|
+
self.fraudNotifierRewardMultiplier = _fraudNotifierRewardMultiplier;
|
|
456
|
+
self.fraudChallengeDefeatTimeout = _fraudChallengeDefeatTimeout;
|
|
457
|
+
self.fraudChallengeDepositAmount = _fraudChallengeDepositAmount;
|
|
458
|
+
|
|
459
|
+
emit FraudParametersUpdated(
|
|
460
|
+
_fraudSlashingAmount,
|
|
461
|
+
_fraudNotifierRewardMultiplier,
|
|
462
|
+
_fraudChallengeDefeatTimeout,
|
|
463
|
+
_fraudChallengeDepositAmount
|
|
464
|
+
);
|
|
176
465
|
}
|
|
177
466
|
}
|
|
@@ -22,9 +22,29 @@ import "./BitcoinTx.sol";
|
|
|
22
22
|
import "./BridgeState.sol";
|
|
23
23
|
import "./Wallets.sol";
|
|
24
24
|
|
|
25
|
+
/// @title Bridge deposit
|
|
26
|
+
/// @notice The library handles the logic for revealing Bitcoin deposits to
|
|
27
|
+
/// the Bridge.
|
|
28
|
+
/// @dev The depositor puts together a P2SH or P2WSH address to deposit the
|
|
29
|
+
/// funds. This script is unique to each depositor and looks like this:
|
|
30
|
+
///
|
|
31
|
+
/// ```
|
|
32
|
+
/// <depositorAddress> DROP
|
|
33
|
+
/// <blindingFactor> DROP
|
|
34
|
+
/// DUP HASH160 <walletPubKeyHash> EQUAL
|
|
35
|
+
/// IF
|
|
36
|
+
/// CHECKSIG
|
|
37
|
+
/// ELSE
|
|
38
|
+
/// DUP HASH160 <refundPubkeyHash> EQUALVERIFY
|
|
39
|
+
/// <refundLocktime> CHECKLOCKTIMEVERIFY DROP
|
|
40
|
+
/// CHECKSIG
|
|
41
|
+
/// ENDIF
|
|
42
|
+
/// ```
|
|
43
|
+
///
|
|
44
|
+
/// Since each depositor has their own Ethereum address and their own
|
|
45
|
+
/// secret blinding factor, each depositor’s script is unique, and the hash
|
|
46
|
+
/// of each depositor’s script is unique.
|
|
25
47
|
library Deposit {
|
|
26
|
-
using Wallets for Wallets.Data;
|
|
27
|
-
|
|
28
48
|
using BTCUtils for bytes;
|
|
29
49
|
using BytesLib for bytes;
|
|
30
50
|
|
|
@@ -123,14 +143,13 @@ library Deposit {
|
|
|
123
143
|
/// deposit script unlocks to receive their BTC back.
|
|
124
144
|
function revealDeposit(
|
|
125
145
|
BridgeState.Storage storage self,
|
|
126
|
-
Wallets.Data storage wallets,
|
|
127
146
|
BitcoinTx.Info calldata fundingTx,
|
|
128
147
|
DepositRevealInfo calldata reveal
|
|
129
148
|
) external {
|
|
130
149
|
require(
|
|
131
|
-
|
|
150
|
+
self.registeredWallets[reveal.walletPubKeyHash].state ==
|
|
132
151
|
Wallets.WalletState.Live,
|
|
133
|
-
"Wallet
|
|
152
|
+
"Wallet must be in Live state"
|
|
134
153
|
);
|
|
135
154
|
|
|
136
155
|
require(
|
|
@@ -231,7 +250,7 @@ library Deposit {
|
|
|
231
250
|
deposit.treasuryFee = self.depositTreasuryFeeDivisor > 0
|
|
232
251
|
? fundingOutputAmount / self.depositTreasuryFeeDivisor
|
|
233
252
|
: 0;
|
|
234
|
-
|
|
253
|
+
// slither-disable-next-line reentrancy-events
|
|
235
254
|
emit DepositRevealed(
|
|
236
255
|
fundingTxHash,
|
|
237
256
|
reveal.fundingOutputIndex,
|
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
// ██████████████ ▐████▌ ██████████████
|
|
4
|
+
// ██████████████ ▐████▌ ██████████████
|
|
5
|
+
// ▐████▌ ▐████▌
|
|
6
|
+
// ▐████▌ ▐████▌
|
|
7
|
+
// ██████████████ ▐████▌ ██████████████
|
|
8
|
+
// ██████████████ ▐████▌ ██████████████
|
|
9
|
+
// ▐████▌ ▐████▌
|
|
10
|
+
// ▐████▌ ▐████▌
|
|
11
|
+
// ▐████▌ ▐████▌
|
|
12
|
+
// ▐████▌ ▐████▌
|
|
13
|
+
// ▐████▌ ▐████▌
|
|
14
|
+
// ▐████▌ ▐████▌
|
|
15
|
+
|
|
1
16
|
pragma solidity ^0.8.9;
|
|
2
17
|
|
|
3
18
|
import "@keep-network/bitcoin-spv-sol/contracts/BytesLib.sol";
|
|
@@ -24,7 +24,26 @@ import "./EcdsaLib.sol";
|
|
|
24
24
|
import "./BridgeState.sol";
|
|
25
25
|
import "./Wallets.sol";
|
|
26
26
|
|
|
27
|
+
/// @title Bridge fraud
|
|
28
|
+
/// @notice The library handles the logic for challenging Bridge wallets that
|
|
29
|
+
/// committed fraud.
|
|
30
|
+
/// @dev Anyone can submit a fraud challenge indicating that a UTXO being under
|
|
31
|
+
/// the wallet control was unlocked by the wallet but was not used
|
|
32
|
+
/// according to the protocol rules. That means the wallet signed
|
|
33
|
+
/// a transaction input pointing to that UTXO and there is a unique
|
|
34
|
+
/// sighash and signature pair associated with that input.
|
|
35
|
+
///
|
|
36
|
+
/// In order to defeat the challenge, the same wallet public key and
|
|
37
|
+
/// signature must be provided as were used to calculate the sighash during
|
|
38
|
+
/// the challenge. The wallet provides the preimage which produces sighash
|
|
39
|
+
/// used to generate the ECDSA signature that is the subject of the fraud
|
|
40
|
+
/// claim. The fraud challenge defeat attempt will only succeed if the
|
|
41
|
+
/// inputs in the preimage are considered honestly spent by the wallet.
|
|
42
|
+
/// Therefore the transaction spending the UTXO must be proven in the
|
|
43
|
+
/// Bridge before a challenge defeat is called.
|
|
27
44
|
library Fraud {
|
|
45
|
+
using Wallets for BridgeState.Storage;
|
|
46
|
+
|
|
28
47
|
using BytesLib for bytes;
|
|
29
48
|
using BTCUtils for bytes;
|
|
30
49
|
using BTCUtils for uint32;
|
|
@@ -41,32 +60,18 @@ library Fraud {
|
|
|
41
60
|
bool resolved;
|
|
42
61
|
}
|
|
43
62
|
|
|
44
|
-
event FraudSlashingAmountUpdated(uint256 newFraudSlashingAmount);
|
|
45
|
-
|
|
46
|
-
event FraudNotifierRewardMultiplierUpdated(
|
|
47
|
-
uint256 newFraudNotifierRewardMultiplier
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
event FraudChallengeDefeatTimeoutUpdated(
|
|
51
|
-
uint256 newFraudChallengeDefeatTimeout
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
event FraudChallengeDepositAmountUpdated(
|
|
55
|
-
uint256 newFraudChallengeDepositAmount
|
|
56
|
-
);
|
|
57
|
-
|
|
58
63
|
event FraudChallengeSubmitted(
|
|
59
|
-
bytes20
|
|
64
|
+
bytes20 walletPubKeyHash,
|
|
60
65
|
bytes32 sighash,
|
|
61
66
|
uint8 v,
|
|
62
67
|
bytes32 r,
|
|
63
68
|
bytes32 s
|
|
64
69
|
);
|
|
65
70
|
|
|
66
|
-
event FraudChallengeDefeated(bytes20
|
|
71
|
+
event FraudChallengeDefeated(bytes20 walletPubKeyHash, bytes32 sighash);
|
|
67
72
|
|
|
68
73
|
event FraudChallengeDefeatTimedOut(
|
|
69
|
-
bytes20
|
|
74
|
+
bytes20 walletPubKeyHash,
|
|
70
75
|
bytes32 sighash
|
|
71
76
|
);
|
|
72
77
|
|
|
@@ -95,8 +100,8 @@ library Fraud {
|
|
|
95
100
|
/// for reference
|
|
96
101
|
/// @param signature Bitcoin signature in the R/S/V format
|
|
97
102
|
/// @dev Requirements:
|
|
98
|
-
/// - Wallet behind `walletPublicKey` must be in
|
|
99
|
-
/// state
|
|
103
|
+
/// - Wallet behind `walletPublicKey` must be in Live or MovingFunds
|
|
104
|
+
/// or Closing state
|
|
100
105
|
/// - The challenger must send appropriate amount of ETH used as
|
|
101
106
|
/// fraud challenge deposit
|
|
102
107
|
/// - The signature (represented by r, s and v) must be generated by
|
|
@@ -104,7 +109,6 @@ library Fraud {
|
|
|
104
109
|
/// - Wallet can be challenged for the given signature only once
|
|
105
110
|
function submitFraudChallenge(
|
|
106
111
|
BridgeState.Storage storage self,
|
|
107
|
-
Wallets.Data storage wallets,
|
|
108
112
|
bytes calldata walletPublicKey,
|
|
109
113
|
bytes32 sighash,
|
|
110
114
|
BitcoinTx.RSVSignature calldata signature
|
|
@@ -131,14 +135,15 @@ library Fraud {
|
|
|
131
135
|
);
|
|
132
136
|
bytes20 walletPubKeyHash = compressedWalletPublicKey.hash160View();
|
|
133
137
|
|
|
134
|
-
Wallets.Wallet storage wallet =
|
|
138
|
+
Wallets.Wallet storage wallet = self.registeredWallets[
|
|
135
139
|
walletPubKeyHash
|
|
136
140
|
];
|
|
137
141
|
|
|
138
142
|
require(
|
|
139
143
|
wallet.state == Wallets.WalletState.Live ||
|
|
140
|
-
wallet.state == Wallets.WalletState.MovingFunds
|
|
141
|
-
|
|
144
|
+
wallet.state == Wallets.WalletState.MovingFunds ||
|
|
145
|
+
wallet.state == Wallets.WalletState.Closing,
|
|
146
|
+
"Wallet must be in Live or MovingFunds or Closing state"
|
|
142
147
|
);
|
|
143
148
|
|
|
144
149
|
uint256 challengeKey = uint256(
|
|
@@ -153,7 +158,7 @@ library Fraud {
|
|
|
153
158
|
/* solhint-disable-next-line not-rely-on-time */
|
|
154
159
|
challenge.reportedAt = uint32(block.timestamp);
|
|
155
160
|
challenge.resolved = false;
|
|
156
|
-
|
|
161
|
+
// slither-disable-next-line reentrancy-events
|
|
157
162
|
emit FraudChallengeSubmitted(
|
|
158
163
|
walletPubKeyHash,
|
|
159
164
|
sighash,
|
|
@@ -230,7 +235,7 @@ library Fraud {
|
|
|
230
235
|
|
|
231
236
|
// Send the ether deposited by the challenger to the treasury
|
|
232
237
|
/* solhint-disable avoid-low-level-calls */
|
|
233
|
-
// slither-disable-next-line low-level-calls
|
|
238
|
+
// slither-disable-next-line low-level-calls,unchecked-lowlevel,arbitrary-send
|
|
234
239
|
self.treasury.call{gas: 100000, value: challenge.depositAmount}("");
|
|
235
240
|
/* solhint-enable avoid-low-level-calls */
|
|
236
241
|
|
|
@@ -239,7 +244,7 @@ library Fraud {
|
|
|
239
244
|
walletPublicKey.slice32(32)
|
|
240
245
|
);
|
|
241
246
|
bytes20 walletPubKeyHash = compressedWalletPublicKey.hash160View();
|
|
242
|
-
|
|
247
|
+
// slither-disable-next-line reentrancy-events
|
|
243
248
|
emit FraudChallengeDefeated(walletPubKeyHash, sighash);
|
|
244
249
|
}
|
|
245
250
|
|
|
@@ -262,9 +267,11 @@ library Fraud {
|
|
|
262
267
|
/// the transaction input the signature is produced for. See BIP-143
|
|
263
268
|
/// for reference
|
|
264
269
|
/// @dev Requirements:
|
|
265
|
-
/// -
|
|
270
|
+
/// - The wallet must be in the Live or MovingFunds or Closing or
|
|
271
|
+
/// Terminated state
|
|
272
|
+
/// - The `walletPublicKey` and `sighash` must identify an open fraud
|
|
266
273
|
/// challenge
|
|
267
|
-
/// -
|
|
274
|
+
/// - The amount of time indicated by `challengeDefeatTimeout` must pass
|
|
268
275
|
/// after the challenge was reported
|
|
269
276
|
function notifyFraudChallengeDefeatTimeout(
|
|
270
277
|
BridgeState.Storage storage self,
|
|
@@ -276,11 +283,14 @@ library Fraud {
|
|
|
276
283
|
);
|
|
277
284
|
|
|
278
285
|
FraudChallenge storage challenge = self.fraudChallenges[challengeKey];
|
|
286
|
+
|
|
279
287
|
require(challenge.reportedAt > 0, "Fraud challenge does not exist");
|
|
288
|
+
|
|
280
289
|
require(
|
|
281
290
|
!challenge.resolved,
|
|
282
291
|
"Fraud challenge has already been resolved"
|
|
283
292
|
);
|
|
293
|
+
|
|
284
294
|
require(
|
|
285
295
|
/* solhint-disable-next-line not-rely-on-time */
|
|
286
296
|
block.timestamp >=
|
|
@@ -288,14 +298,10 @@ library Fraud {
|
|
|
288
298
|
"Fraud challenge defeat period did not time out yet"
|
|
289
299
|
);
|
|
290
300
|
|
|
291
|
-
// TODO: Call notifyFraud from Wallets library
|
|
292
|
-
// TODO: Reward the challenger
|
|
293
|
-
|
|
294
301
|
challenge.resolved = true;
|
|
295
|
-
|
|
296
302
|
// Return the ether deposited by the challenger
|
|
297
303
|
/* solhint-disable avoid-low-level-calls */
|
|
298
|
-
// slither-disable-next-line low-level-calls
|
|
304
|
+
// slither-disable-next-line low-level-calls,unchecked-lowlevel
|
|
299
305
|
challenge.challenger.call{gas: 100000, value: challenge.depositAmount}(
|
|
300
306
|
""
|
|
301
307
|
);
|
|
@@ -306,7 +312,33 @@ library Fraud {
|
|
|
306
312
|
walletPublicKey.slice32(32)
|
|
307
313
|
);
|
|
308
314
|
bytes20 walletPubKeyHash = compressedWalletPublicKey.hash160View();
|
|
315
|
+
Wallets.WalletState walletState = self
|
|
316
|
+
.registeredWallets[walletPubKeyHash]
|
|
317
|
+
.state;
|
|
318
|
+
|
|
319
|
+
if (
|
|
320
|
+
walletState == Wallets.WalletState.Live ||
|
|
321
|
+
walletState == Wallets.WalletState.MovingFunds ||
|
|
322
|
+
walletState == Wallets.WalletState.Closing
|
|
323
|
+
) {
|
|
324
|
+
self.terminateWallet(walletPubKeyHash);
|
|
325
|
+
|
|
326
|
+
// TODO: Perform slashing of the wallet operators, reward the
|
|
327
|
+
// challenger, and add unit tests for that.
|
|
328
|
+
} else if (walletState == Wallets.WalletState.Terminated) {
|
|
329
|
+
// This is a special case when the wallet was already terminated
|
|
330
|
+
// due to a previous deliberate protocol violation. In that
|
|
331
|
+
// case, this function should be still callable for other fraud
|
|
332
|
+
// challenges timeouts in order to let the challenger unlock its
|
|
333
|
+
// ETH deposit back. However, the wallet termination logic is
|
|
334
|
+
// not called and the challenger is not rewarded.
|
|
335
|
+
} else {
|
|
336
|
+
revert(
|
|
337
|
+
"Wallet must be in Live or MovingFunds or Closing or Terminated state"
|
|
338
|
+
);
|
|
339
|
+
}
|
|
309
340
|
|
|
341
|
+
// slither-disable-next-line reentrancy-events
|
|
310
342
|
emit FraudChallengeDefeatTimedOut(walletPubKeyHash, sighash);
|
|
311
343
|
}
|
|
312
344
|
|