@keep-network/tbtc-v2 0.1.1-dev.60 → 0.1.1-dev.63
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 +3 -3
- package/artifacts/Bridge.json +141 -113
- package/artifacts/Deposit.json +7 -7
- package/artifacts/DepositSweep.json +7 -7
- package/artifacts/EcdsaDkgValidator.json +1 -1
- package/artifacts/EcdsaInactivity.json +1 -1
- package/artifacts/Fraud.json +20 -10
- package/artifacts/KeepRegistry.json +1 -1
- package/artifacts/KeepStake.json +2 -2
- package/artifacts/KeepToken.json +2 -2
- package/artifacts/KeepTokenStaking.json +1 -1
- package/artifacts/MovingFunds.json +7 -7
- package/artifacts/NuCypherStakingEscrow.json +1 -1
- package/artifacts/NuCypherToken.json +2 -2
- package/artifacts/RandomBeaconStub.json +1 -1
- package/artifacts/Redemption.json +9 -9
- package/artifacts/ReimbursementPool.json +2 -2
- package/artifacts/Relay.json +9 -9
- package/artifacts/SortitionPool.json +2 -2
- package/artifacts/T.json +2 -2
- package/artifacts/TBTC.json +3 -3
- package/artifacts/TBTCToken.json +3 -3
- package/artifacts/TokenStaking.json +1 -1
- package/artifacts/TokenholderGovernor.json +9 -9
- package/artifacts/TokenholderTimelock.json +8 -8
- package/artifacts/VendingMachine.json +10 -10
- package/artifacts/VendingMachineKeep.json +1 -1
- package/artifacts/VendingMachineNuCypher.json +1 -1
- package/artifacts/WalletRegistry.json +2 -2
- package/artifacts/WalletRegistryGovernance.json +2 -2
- package/artifacts/Wallets.json +7 -7
- package/artifacts/solcInputs/{59994c0eff9c9c3b454733a65b82146c.json → 888980850d09abe497842d2096dd7e11.json} +13 -4
- 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 +64 -38
- package/build/contracts/bridge/BridgeState.sol/BridgeState.dbg.json +1 -1
- package/build/contracts/bridge/BridgeState.sol/BridgeState.json +2 -2
- 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/DepositSweep.sol/DepositSweep.dbg.json +1 -1
- package/build/contracts/bridge/DepositSweep.sol/DepositSweep.json +2 -2
- package/build/contracts/bridge/EcdsaLib.sol/EcdsaLib.dbg.json +1 -1
- package/build/contracts/bridge/Fraud.sol/Fraud.dbg.json +1 -1
- package/build/contracts/bridge/Fraud.sol/Fraud.json +2 -2
- package/build/contracts/bridge/Heartbeat.sol/Heartbeat.dbg.json +4 -0
- package/build/contracts/bridge/Heartbeat.sol/Heartbeat.json +10 -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 +2 -2
- package/build/contracts/bridge/Redemption.sol/OutboundTx.dbg.json +1 -1
- package/build/contracts/bridge/Redemption.sol/OutboundTx.json +2 -2
- package/build/contracts/bridge/Redemption.sol/Redemption.dbg.json +1 -1
- package/build/contracts/bridge/Redemption.sol/Redemption.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 -2
- package/build/contracts/token/TBTC.sol/TBTC.dbg.json +1 -1
- package/build/contracts/vault/DonationVault.sol/DonationVault.dbg.json +4 -0
- package/build/contracts/vault/DonationVault.sol/DonationVault.json +103 -0
- 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 +18 -3
- package/contracts/bridge/Bridge.sol +34 -2
- package/contracts/bridge/Fraud.sol +81 -4
- package/contracts/bridge/Heartbeat.sol +112 -0
- package/contracts/vault/DonationVault.sol +125 -0
- package/export.json +18 -0
- package/package.json +1 -1
|
@@ -844,8 +844,8 @@ contract Bridge is Governable, EcdsaWalletOwner {
|
|
|
844
844
|
/// to protocol rules. To prevent spurious allegations, the caller
|
|
845
845
|
/// must deposit ETH that is returned back upon justified fraud
|
|
846
846
|
/// challenge or confiscated otherwise.
|
|
847
|
-
|
|
848
|
-
///
|
|
847
|
+
/// @param walletPublicKey The public key of the wallet in the uncompressed
|
|
848
|
+
/// and unprefixed format (64 bytes)
|
|
849
849
|
/// @param sighash The hash that was used to produce the ECDSA signature
|
|
850
850
|
/// that is the subject of the fraud claim. This hash is constructed
|
|
851
851
|
/// by applying double SHA-256 over a serialized subset of the
|
|
@@ -905,6 +905,38 @@ contract Bridge is Governable, EcdsaWalletOwner {
|
|
|
905
905
|
self.defeatFraudChallenge(walletPublicKey, preimage, witness);
|
|
906
906
|
}
|
|
907
907
|
|
|
908
|
+
/// @notice Allows to defeat a pending fraud challenge against a wallet by
|
|
909
|
+
/// proving the sighash and signature were produced for an off-chain
|
|
910
|
+
/// wallet heartbeat message following a strict format.
|
|
911
|
+
/// In order to defeat the challenge the same `walletPublicKey` and
|
|
912
|
+
/// signature (represented by `r`, `s` and `v`) must be provided as
|
|
913
|
+
/// were used to calculate the sighash during heartbeat message
|
|
914
|
+
/// signing. The fraud challenge defeat attempt will only succeed if
|
|
915
|
+
/// the signed message follows a strict format required for
|
|
916
|
+
/// heartbeat messages. If successfully defeated, the fraud
|
|
917
|
+
/// challenge is marked as resolved and the amount of ether
|
|
918
|
+
/// deposited by the challenger is sent to the treasury.
|
|
919
|
+
/// @param walletPublicKey The public key of the wallet in the uncompressed
|
|
920
|
+
/// and unprefixed format (64 bytes)
|
|
921
|
+
/// @param heartbeatMessage Off-chain heartbeat message meeting the heartbeat
|
|
922
|
+
/// message format requirements which produces sighash used to
|
|
923
|
+
/// generate the ECDSA signature that is the subject of the fraud
|
|
924
|
+
/// claim
|
|
925
|
+
/// @dev Requirements:
|
|
926
|
+
/// - `walletPublicKey` and `sighash` calculated as
|
|
927
|
+
/// `hash256(heartbeatMessage)` must identify an open fraud challenge
|
|
928
|
+
/// - `heartbeatMessage` must follow a strict format of heartbeat
|
|
929
|
+
/// messages
|
|
930
|
+
function defeatFraudChallengeWithHeartbeat(
|
|
931
|
+
bytes calldata walletPublicKey,
|
|
932
|
+
bytes calldata heartbeatMessage
|
|
933
|
+
) external {
|
|
934
|
+
self.defeatFraudChallengeWithHeartbeat(
|
|
935
|
+
walletPublicKey,
|
|
936
|
+
heartbeatMessage
|
|
937
|
+
);
|
|
938
|
+
}
|
|
939
|
+
|
|
908
940
|
/// @notice Notifies about defeat timeout for the given fraud challenge.
|
|
909
941
|
/// Can be called only if there was a fraud challenge identified by
|
|
910
942
|
/// the provided `walletPublicKey` and `sighash` and it was not
|
|
@@ -22,6 +22,7 @@ import {CheckBitcoinSigs} from "@keep-network/bitcoin-spv-sol/contracts/CheckBit
|
|
|
22
22
|
import "./BitcoinTx.sol";
|
|
23
23
|
import "./EcdsaLib.sol";
|
|
24
24
|
import "./BridgeState.sol";
|
|
25
|
+
import "./Heartbeat.sol";
|
|
25
26
|
import "./MovingFunds.sol";
|
|
26
27
|
import "./Wallets.sol";
|
|
27
28
|
|
|
@@ -38,10 +39,18 @@ import "./Wallets.sol";
|
|
|
38
39
|
/// signature must be provided as were used to calculate the sighash during
|
|
39
40
|
/// the challenge. The wallet provides the preimage which produces sighash
|
|
40
41
|
/// used to generate the ECDSA signature that is the subject of the fraud
|
|
41
|
-
/// claim.
|
|
42
|
-
///
|
|
43
|
-
///
|
|
44
|
-
///
|
|
42
|
+
/// claim.
|
|
43
|
+
///
|
|
44
|
+
/// The fraud challenge defeat attempt will succeed if the inputs in the
|
|
45
|
+
/// preimage are considered honestly spent by the wallet. Therefore the
|
|
46
|
+
/// transaction spending the UTXO must be proven in the Bridge before
|
|
47
|
+
/// a challenge defeat is called.
|
|
48
|
+
///
|
|
49
|
+
/// Another option is when a malicious wallet member used a signed heartbeat
|
|
50
|
+
/// message periodically produced by the wallet off-chain to challenge the
|
|
51
|
+
/// wallet for a fraud. Anyone from the wallet can defeat the challenge by
|
|
52
|
+
/// proving the sighash and signature were produced for a heartbeat message
|
|
53
|
+
/// following a strict format.
|
|
45
54
|
library Fraud {
|
|
46
55
|
using Wallets for BridgeState.Storage;
|
|
47
56
|
|
|
@@ -73,6 +82,10 @@ library Fraud {
|
|
|
73
82
|
|
|
74
83
|
event FraudChallengeDefeatTimedOut(
|
|
75
84
|
bytes20 walletPubKeyHash,
|
|
85
|
+
// Sighash calculated as a Bitcoin's hash256 (double sha2) of:
|
|
86
|
+
// - a preimage of a transaction spending UTXO according to the protocol
|
|
87
|
+
// rules OR
|
|
88
|
+
// - a valid heartbeat message produced by the wallet off-chain.
|
|
76
89
|
bytes32 sighash
|
|
77
90
|
);
|
|
78
91
|
|
|
@@ -234,6 +247,69 @@ library Fraud {
|
|
|
234
247
|
"Spent UTXO not found among correctly spent UTXOs"
|
|
235
248
|
);
|
|
236
249
|
|
|
250
|
+
resolveFraudChallenge(self, walletPublicKey, challenge, sighash);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/// @notice Allows to defeat a pending fraud challenge against a wallet by
|
|
254
|
+
/// proving the sighash and signature were produced for an off-chain
|
|
255
|
+
/// wallet heartbeat message following a strict format.
|
|
256
|
+
/// In order to defeat the challenge the same `walletPublicKey` and
|
|
257
|
+
/// signature (represented by `r`, `s` and `v`) must be provided as
|
|
258
|
+
/// were used to calculate the sighash during heartbeat message
|
|
259
|
+
/// signing. The fraud challenge defeat attempt will only succeed if
|
|
260
|
+
/// the signed message follows a strict format required for
|
|
261
|
+
/// heartbeat messages. If successfully defeated, the fraud
|
|
262
|
+
/// challenge is marked as resolved and the amount of ether
|
|
263
|
+
/// deposited by the challenger is sent to the treasury.
|
|
264
|
+
/// @param walletPublicKey The public key of the wallet in the uncompressed
|
|
265
|
+
/// and unprefixed format (64 bytes)
|
|
266
|
+
/// @param heartbeatMessage Off-chain heartbeat message meeting the heartbeat
|
|
267
|
+
/// message format requirements which produces sighash used to
|
|
268
|
+
/// generate the ECDSA signature that is the subject of the fraud
|
|
269
|
+
/// claim
|
|
270
|
+
/// @dev Requirements:
|
|
271
|
+
/// - `walletPublicKey` and `sighash` calculated as
|
|
272
|
+
/// `hash256(heartbeatMessage)` must identify an open fraud challenge
|
|
273
|
+
/// - `heartbeatMessage` must follow a strict format of heartbeat
|
|
274
|
+
/// messages
|
|
275
|
+
function defeatFraudChallengeWithHeartbeat(
|
|
276
|
+
BridgeState.Storage storage self,
|
|
277
|
+
bytes calldata walletPublicKey,
|
|
278
|
+
bytes calldata heartbeatMessage
|
|
279
|
+
) external {
|
|
280
|
+
bytes32 sighash = heartbeatMessage.hash256();
|
|
281
|
+
|
|
282
|
+
uint256 challengeKey = uint256(
|
|
283
|
+
keccak256(abi.encodePacked(walletPublicKey, sighash))
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
FraudChallenge storage challenge = self.fraudChallenges[challengeKey];
|
|
287
|
+
|
|
288
|
+
require(challenge.reportedAt > 0, "Fraud challenge does not exist");
|
|
289
|
+
require(
|
|
290
|
+
!challenge.resolved,
|
|
291
|
+
"Fraud challenge has already been resolved"
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
require(
|
|
295
|
+
Heartbeat.isValidHeartbeatMessage(heartbeatMessage),
|
|
296
|
+
"Not a valid heartbeat message"
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
resolveFraudChallenge(self, walletPublicKey, challenge, sighash);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/// @notice Called only for successfully defeated fraud challenges.
|
|
303
|
+
/// The fraud challenge is marked as resolved and the amount of
|
|
304
|
+
/// ether deposited by the challenger is sent to the treasury.
|
|
305
|
+
/// @dev Requirements:
|
|
306
|
+
/// - Must be called only for successfully defeated fraud challenges.
|
|
307
|
+
function resolveFraudChallenge(
|
|
308
|
+
BridgeState.Storage storage self,
|
|
309
|
+
bytes calldata walletPublicKey,
|
|
310
|
+
FraudChallenge storage challenge,
|
|
311
|
+
bytes32 sighash
|
|
312
|
+
) internal {
|
|
237
313
|
// Mark the challenge as resolved as it was successfully defeated
|
|
238
314
|
challenge.resolved = true;
|
|
239
315
|
|
|
@@ -248,6 +324,7 @@ library Fraud {
|
|
|
248
324
|
walletPublicKey.slice32(32)
|
|
249
325
|
);
|
|
250
326
|
bytes20 walletPubKeyHash = compressedWalletPublicKey.hash160View();
|
|
327
|
+
|
|
251
328
|
// slither-disable-next-line reentrancy-events
|
|
252
329
|
emit FraudChallengeDefeated(walletPubKeyHash, sighash);
|
|
253
330
|
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
// ██████████████ ▐████▌ ██████████████
|
|
4
|
+
// ██████████████ ▐████▌ ██████████████
|
|
5
|
+
// ▐████▌ ▐████▌
|
|
6
|
+
// ▐████▌ ▐████▌
|
|
7
|
+
// ██████████████ ▐████▌ ██████████████
|
|
8
|
+
// ██████████████ ▐████▌ ██████████████
|
|
9
|
+
// ▐████▌ ▐████▌
|
|
10
|
+
// ▐████▌ ▐████▌
|
|
11
|
+
// ▐████▌ ▐████▌
|
|
12
|
+
// ▐████▌ ▐████▌
|
|
13
|
+
// ▐████▌ ▐████▌
|
|
14
|
+
// ▐████▌ ▐████▌
|
|
15
|
+
|
|
16
|
+
pragma solidity ^0.8.9;
|
|
17
|
+
|
|
18
|
+
import {BytesLib} from "@keep-network/bitcoin-spv-sol/contracts/BytesLib.sol";
|
|
19
|
+
|
|
20
|
+
/// @title Bridge wallet heartbeat
|
|
21
|
+
/// @notice The library establishes expected format for heartbeat messages
|
|
22
|
+
/// signed by wallet ECDSA signing group. Heartbeat messages are
|
|
23
|
+
/// constructed in such a way that they can not be used as a Bitcoin
|
|
24
|
+
/// transaction preimages.
|
|
25
|
+
/// @dev The smallest Bitcoin non-coinbase transaction is a one spending an
|
|
26
|
+
/// OP_TRUE anyonecanspend output and creating 1 OP_TRUE anyonecanspend
|
|
27
|
+
/// output. Such a transaction has 61 bytes (see `BitcoinTx` documentation):
|
|
28
|
+
/// 4 bytes for version
|
|
29
|
+
/// 1 byte for tx_in_count
|
|
30
|
+
/// 36 bytes for tx_in.previous_output
|
|
31
|
+
/// 1 byte for tx_in.script_bytes (value: 0)
|
|
32
|
+
/// 0 bytes for tx_in.signature_script
|
|
33
|
+
/// 4 bytes for tx_in.sequence
|
|
34
|
+
/// 1 byte for tx_out_count
|
|
35
|
+
/// 8 bytes for tx_out.value
|
|
36
|
+
/// 1 byte for tx_out.pk_script_bytes
|
|
37
|
+
/// 1 byte for tx_out.pk_script
|
|
38
|
+
/// 4 bytes for lock_time
|
|
39
|
+
///
|
|
40
|
+
///
|
|
41
|
+
/// The smallest Bitcoin coinbase transaction is a one creating
|
|
42
|
+
/// 1 OP_TRUE anyonecanspend output and having an empty coinbase script.
|
|
43
|
+
/// Such a transaction has 65 bytes:
|
|
44
|
+
/// 4 bytes for version
|
|
45
|
+
/// 1 byte for tx_in_count
|
|
46
|
+
/// 32 bytes for tx_in.hash (all 0x00)
|
|
47
|
+
/// 4 bytes for tx_in.index (all 0xff)
|
|
48
|
+
/// 1 byte for tx_in.script_bytes (value: 0)
|
|
49
|
+
/// 4 bytes for tx_in.height
|
|
50
|
+
/// 0 byte for tx_in.coinbase_script
|
|
51
|
+
/// 4 bytes for tx_in.sequence
|
|
52
|
+
/// 1 byte for tx_out_count
|
|
53
|
+
/// 8 bytes for tx_out.value
|
|
54
|
+
/// 1 byte for tx_out.pk_script_bytes
|
|
55
|
+
/// 1 byte for tx_out.pk_script
|
|
56
|
+
/// 4 bytes for lock_time
|
|
57
|
+
///
|
|
58
|
+
///
|
|
59
|
+
/// A SIGHASH flag is used to indicate which part of the transaction is
|
|
60
|
+
/// signed by the ECDSA signature. There are currently 3 flags:
|
|
61
|
+
/// SIGHASH_ALL, SIGHASH_NONE, SIGHASH_SINGLE, and different combinations
|
|
62
|
+
/// of these flags.
|
|
63
|
+
///
|
|
64
|
+
/// No matter the SIGHASH flag and no matter the combination, the following
|
|
65
|
+
/// fields from the transaction are always included in the constructed
|
|
66
|
+
/// preimage:
|
|
67
|
+
/// 4 bytes for version
|
|
68
|
+
/// 36 bytes for tx_in.previous_output (or tx_in.hash + tx_in.index for coinbase)
|
|
69
|
+
/// 4 bytes for lock_time
|
|
70
|
+
///
|
|
71
|
+
/// Additionally, the last 4 bytes of the preimage determines the SIGHASH
|
|
72
|
+
/// flag.
|
|
73
|
+
///
|
|
74
|
+
/// This is enough to say there is no way the preimage could be shorter
|
|
75
|
+
/// than 4 + 36 + 4 + 4 = 48 bytes.
|
|
76
|
+
///
|
|
77
|
+
/// For this reason, we construct the heartbeat message, as a 16-byte
|
|
78
|
+
/// message. The first 8 bytes are 0xffffffffffffffff. The last 8 bytes
|
|
79
|
+
/// are for an arbitrary uint64, being a signed heartbeat nonce (for
|
|
80
|
+
/// example, the last Ethereum block hash).
|
|
81
|
+
///
|
|
82
|
+
/// The message being signed by the wallet when executing the heartbeat
|
|
83
|
+
/// protocol should be Bitcoin's hash256 (double SHA-256) of the heartbeat
|
|
84
|
+
/// message:
|
|
85
|
+
/// heartbeat_sighash = hash256(heartbeat_message)
|
|
86
|
+
library Heartbeat {
|
|
87
|
+
using BytesLib for bytes;
|
|
88
|
+
|
|
89
|
+
/// @notice Determines if the signed byte array is a valid, non-fraudulent
|
|
90
|
+
/// heartbeat message.
|
|
91
|
+
/// @param message Message signed by the wallet. It is a potential heartbeat
|
|
92
|
+
/// message, Bitcoin transaction preimage, or an arbitrary signed
|
|
93
|
+
/// bytes
|
|
94
|
+
/// @dev Wallet heartbeat message must be exactly 16 bytes long with the first
|
|
95
|
+
/// 8 bytes set to 0xffffffffffffffff.
|
|
96
|
+
/// @return True if valid heartbeat message, false otherwise.
|
|
97
|
+
function isValidHeartbeatMessage(bytes calldata message)
|
|
98
|
+
internal
|
|
99
|
+
pure
|
|
100
|
+
returns (bool)
|
|
101
|
+
{
|
|
102
|
+
if (message.length != 16) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (message.slice8(0) != 0xffffffffffffffff) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
// ██████████████ ▐████▌ ██████████████
|
|
4
|
+
// ██████████████ ▐████▌ ██████████████
|
|
5
|
+
// ▐████▌ ▐████▌
|
|
6
|
+
// ▐████▌ ▐████▌
|
|
7
|
+
// ██████████████ ▐████▌ ██████████████
|
|
8
|
+
// ██████████████ ▐████▌ ██████████████
|
|
9
|
+
// ▐████▌ ▐████▌
|
|
10
|
+
// ▐████▌ ▐████▌
|
|
11
|
+
// ▐████▌ ▐████▌
|
|
12
|
+
// ▐████▌ ▐████▌
|
|
13
|
+
// ▐████▌ ▐████▌
|
|
14
|
+
// ▐████▌ ▐████▌
|
|
15
|
+
|
|
16
|
+
pragma solidity ^0.8.9;
|
|
17
|
+
|
|
18
|
+
import "./IVault.sol";
|
|
19
|
+
import "../bank/Bank.sol";
|
|
20
|
+
|
|
21
|
+
/// @title BTC donation vault
|
|
22
|
+
/// @notice Vault that allows making BTC donations to the system. Upon deposit,
|
|
23
|
+
/// this vault does not increase depositors' balances and always
|
|
24
|
+
/// decreases its own balance in the same transaction. The vault also
|
|
25
|
+
/// allows making donations using existing Bank balances.
|
|
26
|
+
///
|
|
27
|
+
/// BEWARE: ALL BTC DEPOSITS TARGETING THIS VAULT ARE NOT REDEEMABLE
|
|
28
|
+
/// AND THERE IS NO WAY TO RESTORE THE DONATED BALANCE.
|
|
29
|
+
/// USE THIS VAULT ONLY WHEN YOU REALLY KNOW WHAT YOU ARE DOING!
|
|
30
|
+
contract DonationVault is IVault {
|
|
31
|
+
Bank public bank;
|
|
32
|
+
|
|
33
|
+
event DonationReceived(address donor, uint256 donatedAmount);
|
|
34
|
+
|
|
35
|
+
modifier onlyBank() {
|
|
36
|
+
require(msg.sender == address(bank), "Caller is not the Bank");
|
|
37
|
+
_;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
constructor(Bank _bank) {
|
|
41
|
+
require(
|
|
42
|
+
address(_bank) != address(0),
|
|
43
|
+
"Bank can not be the zero address"
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
bank = _bank;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/// @notice Transfers the given `amount` of the Bank balance from the
|
|
50
|
+
/// caller to the Donation Vault and immediately decreases the
|
|
51
|
+
/// vault's balance in the Bank by the transferred `amount`.
|
|
52
|
+
/// @param amount Amount of the Bank balance to donate
|
|
53
|
+
/// @dev Requirements:
|
|
54
|
+
/// - The caller's balance in the Bank must be greater than or equal
|
|
55
|
+
/// to the `amount`.
|
|
56
|
+
/// - Donation Vault must have an allowance for caller's balance in
|
|
57
|
+
/// the Bank for at least `amount`.
|
|
58
|
+
function donate(uint256 amount) external {
|
|
59
|
+
address donor = msg.sender;
|
|
60
|
+
|
|
61
|
+
require(
|
|
62
|
+
bank.balanceOf(donor) >= amount,
|
|
63
|
+
"Amount exceeds balance in the bank"
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
emit DonationReceived(donor, amount);
|
|
67
|
+
|
|
68
|
+
bank.transferBalanceFrom(donor, address(this), amount);
|
|
69
|
+
bank.decreaseBalance(amount);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/// @notice Transfers the given `amount` of the Bank balance from the
|
|
73
|
+
/// `owner` to the Donation Vault and immediately decreases the
|
|
74
|
+
/// vault's balance in the Bank by the transferred `amount`.
|
|
75
|
+
/// @param owner Address of the Bank balance owner who approved their
|
|
76
|
+
/// balance to be used by the vault
|
|
77
|
+
/// @param amount The amount of the Bank balance approved by the owner
|
|
78
|
+
/// to be used by the vault
|
|
79
|
+
/// @dev Requirements:
|
|
80
|
+
/// - Can only be called by the Bank via `approveBalanceAndCall`.
|
|
81
|
+
/// - The `owner` balance in the Bank must be greater than or equal
|
|
82
|
+
/// to the `amount`.
|
|
83
|
+
function receiveBalanceApproval(address owner, uint256 amount)
|
|
84
|
+
external
|
|
85
|
+
override
|
|
86
|
+
onlyBank
|
|
87
|
+
{
|
|
88
|
+
require(
|
|
89
|
+
bank.balanceOf(owner) >= amount,
|
|
90
|
+
"Amount exceeds balance in the bank"
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
emit DonationReceived(owner, amount);
|
|
94
|
+
|
|
95
|
+
bank.transferBalanceFrom(owner, address(this), amount);
|
|
96
|
+
bank.decreaseBalance(amount);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/// @notice Ignores the deposited amounts and does not increase depositors'
|
|
100
|
+
/// individual balances. The vault decreases its own tBTC balance
|
|
101
|
+
/// in the Bank by the total deposited amount.
|
|
102
|
+
/// @param depositors Addresses of depositors whose deposits have been swept
|
|
103
|
+
/// @param depositedAmounts Amounts deposited by individual depositors and
|
|
104
|
+
/// swept
|
|
105
|
+
/// @dev Requirements:
|
|
106
|
+
/// - Can only be called by the Bank after the Bridge swept deposits
|
|
107
|
+
/// and Bank increased balance for the vault.
|
|
108
|
+
/// - The `depositors` array must not be empty.
|
|
109
|
+
/// - The `depositors` array length must be equal to the
|
|
110
|
+
/// `depositedAmounts` array length.
|
|
111
|
+
function receiveBalanceIncrease(
|
|
112
|
+
address[] calldata depositors,
|
|
113
|
+
uint256[] calldata depositedAmounts
|
|
114
|
+
) external override onlyBank {
|
|
115
|
+
require(depositors.length != 0, "No depositors specified");
|
|
116
|
+
|
|
117
|
+
uint256 totalAmount = 0;
|
|
118
|
+
for (uint256 i = 0; i < depositors.length; i++) {
|
|
119
|
+
totalAmount += depositedAmounts[i];
|
|
120
|
+
emit DonationReceived(depositors[i], depositedAmounts[i]);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
bank.decreaseBalance(totalAmount);
|
|
124
|
+
}
|
|
125
|
+
}
|
package/export.json
CHANGED
|
@@ -14871,6 +14871,24 @@
|
|
|
14871
14871
|
"stateMutability": "nonpayable",
|
|
14872
14872
|
"type": "function"
|
|
14873
14873
|
},
|
|
14874
|
+
{
|
|
14875
|
+
"inputs": [
|
|
14876
|
+
{
|
|
14877
|
+
"internalType": "bytes",
|
|
14878
|
+
"name": "walletPublicKey",
|
|
14879
|
+
"type": "bytes"
|
|
14880
|
+
},
|
|
14881
|
+
{
|
|
14882
|
+
"internalType": "bytes",
|
|
14883
|
+
"name": "heartbeatMessage",
|
|
14884
|
+
"type": "bytes"
|
|
14885
|
+
}
|
|
14886
|
+
],
|
|
14887
|
+
"name": "defeatFraudChallengeWithHeartbeat",
|
|
14888
|
+
"outputs": [],
|
|
14889
|
+
"stateMutability": "nonpayable",
|
|
14890
|
+
"type": "function"
|
|
14891
|
+
},
|
|
14874
14892
|
{
|
|
14875
14893
|
"inputs": [],
|
|
14876
14894
|
"name": "depositParameters",
|