@keep-network/tbtc-v2 1.6.0-dev.5 → 1.6.0-dev.6
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/BLS.json +1 -1
- package/artifacts/Bank.json +3 -3
- package/artifacts/BeaconAuthorization.json +1 -1
- package/artifacts/BeaconDkg.json +1 -1
- package/artifacts/BeaconDkgValidator.json +1 -1
- package/artifacts/BeaconInactivity.json +1 -1
- package/artifacts/BeaconSortitionPool.json +3 -3
- package/artifacts/Bridge.json +5 -5
- package/artifacts/BridgeGovernance.json +2 -2
- package/artifacts/BridgeGovernanceParameters.json +2 -2
- package/artifacts/Deposit.json +2 -2
- package/artifacts/DepositSweep.json +2 -2
- package/artifacts/DonationVault.json +3 -3
- package/artifacts/EcdsaDkgValidator.json +1 -1
- package/artifacts/EcdsaInactivity.json +1 -1
- package/artifacts/EcdsaSortitionPool.json +3 -3
- package/artifacts/Fraud.json +2 -2
- 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/LightRelay.json +18 -18
- package/artifacts/LightRelayMaintainerProxy.json +17 -17
- package/artifacts/MaintainerProxy.json +19 -19
- package/artifacts/MovingFunds.json +2 -2
- package/artifacts/NuCypherStakingEscrow.json +1 -1
- package/artifacts/NuCypherToken.json +2 -2
- package/artifacts/RandomBeacon.json +2 -2
- package/artifacts/RandomBeaconChaosnet.json +2 -2
- package/artifacts/RandomBeaconGovernance.json +2 -2
- package/artifacts/Redemption.json +2 -2
- package/artifacts/ReimbursementPool.json +2 -2
- package/artifacts/T.json +2 -2
- package/artifacts/TBTC.json +3 -3
- package/artifacts/TBTCToken.json +3 -3
- package/artifacts/TBTCVault.json +23 -23
- package/artifacts/TokenStaking.json +1 -1
- package/artifacts/TokenholderGovernor.json +9 -9
- package/artifacts/TokenholderTimelock.json +8 -8
- package/artifacts/VendingMachine.json +3 -3
- package/artifacts/VendingMachineKeep.json +1 -1
- package/artifacts/VendingMachineNuCypher.json +1 -1
- package/artifacts/VendingMachineV2.json +3 -3
- package/artifacts/VendingMachineV3.json +3 -3
- package/artifacts/WalletProposalValidator.json +389 -0
- package/artifacts/WalletRegistry.json +5 -5
- package/artifacts/WalletRegistryGovernance.json +2 -2
- package/artifacts/Wallets.json +2 -2
- package/artifacts/solcInputs/{d2d7e276da75d7184610fe11a4a103b7.json → d46fa1d8846c35adf326ab51a3910266.json} +2 -2
- package/build/contracts/GovernanceUtils.sol/GovernanceUtils.dbg.json +1 -1
- package/build/contracts/bank/Bank.sol/Bank.dbg.json +1 -1
- package/build/contracts/bank/IReceiveBalanceApproval.sol/IReceiveBalanceApproval.dbg.json +1 -1
- package/build/contracts/bridge/BitcoinTx.sol/BitcoinTx.dbg.json +1 -1
- package/build/contracts/bridge/Bridge.sol/Bridge.dbg.json +1 -1
- package/build/contracts/bridge/BridgeGovernanceParameters.sol/BridgeGovernanceParameters.dbg.json +1 -1
- package/build/contracts/bridge/BridgeState.sol/BridgeState.dbg.json +1 -1
- package/build/contracts/bridge/Deposit.sol/Deposit.dbg.json +1 -1
- package/build/contracts/bridge/DepositSweep.sol/DepositSweep.dbg.json +1 -1
- 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/Heartbeat.sol/Heartbeat.dbg.json +1 -1
- 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/Redemption.sol/OutboundTx.dbg.json +1 -1
- package/build/contracts/bridge/Redemption.sol/Redemption.dbg.json +1 -1
- package/build/contracts/bridge/VendingMachine.sol/VendingMachine.dbg.json +1 -1
- package/build/contracts/bridge/VendingMachineV2.sol/VendingMachineV2.dbg.json +1 -1
- package/build/contracts/bridge/VendingMachineV3.sol/VendingMachineV3.dbg.json +1 -1
- package/build/contracts/bridge/WalletProposalValidator.sol/WalletProposalValidator.dbg.json +4 -0
- package/build/contracts/bridge/WalletProposalValidator.sol/WalletProposalValidator.json +287 -0
- package/build/contracts/bridge/Wallets.sol/Wallets.dbg.json +1 -1
- package/build/contracts/l2/L2TBTC.sol/L2TBTC.dbg.json +1 -1
- package/build/contracts/l2/L2WormholeGateway.sol/IWormholeTokenBridge.dbg.json +1 -1
- package/build/contracts/l2/L2WormholeGateway.sol/L2WormholeGateway.dbg.json +1 -1
- package/build/contracts/maintainer/MaintainerProxy.sol/MaintainerProxy.dbg.json +1 -1
- package/build/contracts/relay/LightRelay.sol/ILightRelay.dbg.json +1 -1
- package/build/contracts/relay/LightRelay.sol/LightRelay.dbg.json +1 -1
- package/build/contracts/relay/LightRelay.sol/RelayUtils.dbg.json +1 -1
- package/build/contracts/relay/LightRelayMaintainerProxy.sol/LightRelayMaintainerProxy.dbg.json +1 -1
- package/build/contracts/token/TBTC.sol/TBTC.dbg.json +1 -1
- package/build/contracts/vault/DonationVault.sol/DonationVault.dbg.json +1 -1
- package/build/contracts/vault/IVault.sol/IVault.dbg.json +1 -1
- package/build/contracts/vault/TBTCOptimisticMinting.sol/TBTCOptimisticMinting.dbg.json +1 -1
- package/build/contracts/vault/TBTCVault.sol/TBTCVault.dbg.json +1 -1
- package/contracts/bridge/{WalletCoordinator.sol → WalletProposalValidator.sol} +55 -448
- package/deploy/39_deploy_wallet_proposal_validator.ts +33 -0
- package/export/artifacts/contracts/bridge/Bridge.sol/Bridge.json +22 -22
- package/export/artifacts/contracts/bridge/VendingMachine.sol/VendingMachine.json +6 -6
- package/export/artifacts/contracts/bridge/VendingMachineV2.sol/VendingMachineV2.json +6 -6
- package/export/artifacts/contracts/bridge/VendingMachineV3.sol/VendingMachineV3.json +6 -6
- package/export/artifacts/contracts/bridge/WalletProposalValidator.sol/WalletProposalValidator.json +22598 -0
- package/export/artifacts/contracts/l2/L2TBTC.sol/L2TBTC.json +40 -40
- package/export/artifacts/contracts/l2/L2WormholeGateway.sol/L2WormholeGateway.json +47 -47
- package/export/artifacts/contracts/maintainer/MaintainerProxy.sol/MaintainerProxy.json +88 -88
- package/export/artifacts/contracts/relay/LightRelay.sol/LightRelay.json +57 -57
- package/export/artifacts/contracts/relay/LightRelayMaintainerProxy.sol/LightRelayMaintainerProxy.json +31 -31
- package/export/artifacts/contracts/test/BankStub.sol/BankStub.json +2 -2
- package/export/artifacts/contracts/test/BridgeStub.sol/BridgeStub.json +58 -58
- package/export/artifacts/contracts/test/GoerliLightRelay.sol/GoerliLightRelay.json +59 -59
- package/export/artifacts/contracts/test/HeartbeatStub.sol/HeartbeatStub.json +2 -2
- package/export/artifacts/contracts/test/LightRelayStub.sol/LightRelayStub.json +59 -59
- package/export/artifacts/contracts/test/ReceiveApprovalStub.sol/ReceiveApprovalStub.json +7 -7
- package/export/artifacts/contracts/test/SepoliaLightRelay.sol/SepoliaLightRelay.json +59 -59
- package/export/artifacts/contracts/test/SystemTestRelay.sol/SystemTestRelay.json +14 -14
- package/export/artifacts/contracts/test/TestERC20.sol/TestERC20.json +6 -6
- package/export/artifacts/contracts/test/TestERC721.sol/TestERC721.json +8 -8
- package/export/artifacts/contracts/test/TestEcdsaLib.sol/TestEcdsaLib.json +2 -2
- package/export/artifacts/contracts/test/WormholeBridgeStub.sol/WormholeBridgeStub.json +37 -37
- package/export/artifacts/contracts/token/TBTC.sol/TBTC.json +2 -2
- package/export/artifacts/contracts/vault/DonationVault.sol/DonationVault.json +11 -11
- package/export/artifacts/contracts/vault/TBTCVault.sol/TBTCVault.json +135 -135
- package/export/deploy/39_deploy_wallet_proposal_validator.js +82 -0
- package/export/hardhat.config.js +0 -6
- package/export/typechain/factories/WalletProposalValidator__factory.js +366 -0
- package/export/typechain/index.js +3 -3
- package/package.json +1 -1
- package/artifacts/WalletCoordinator.json +0 -1107
- package/build/contracts/bridge/WalletCoordinator.sol/WalletCoordinator.dbg.json +0 -4
- package/build/contracts/bridge/WalletCoordinator.sol/WalletCoordinator.json +0 -1042
- package/deploy/34_deploy_wallet_coordinator.ts +0 -43
- package/deploy/35_add_coordinator_address.ts +0 -20
- package/deploy/36_transfer_wallet_coordinator_ownership.ts +0 -19
- package/deploy/81_upgrade_wallet_coordinator_v2.ts +0 -99
- package/export/artifacts/contracts/bridge/WalletCoordinator.sol/WalletCoordinator.json +0 -33310
- package/export/deploy/34_deploy_wallet_coordinator.js +0 -115
- package/export/deploy/35_add_coordinator_address.js +0 -60
- package/export/deploy/36_transfer_wallet_coordinator_ownership.js +0 -60
- package/export/deploy/81_upgrade_wallet_coordinator_v2.js +0 -140
- package/export/typechain/factories/WalletCoordinator__factory.js +0 -1121
- /package/deploy/{37_deploy_light_relay_maintainer_proxy.ts → 34_deploy_light_relay_maintainer_proxy.ts} +0 -0
- /package/deploy/{38_authorize_maintainer_in_light_relay_maintainer_proxy.ts → 35_authorize_maintainer_in_light_relay_maintainer_proxy.ts} +0 -0
- /package/deploy/{39_transfer_light_relay_maintainer_proxy_ownership.ts → 36_transfer_light_relay_maintainer_proxy_ownership.ts} +0 -0
- /package/deploy/{40_authorize_light_relay_maintainer_proxy_in_reimbursement_pool.ts → 37_authorize_light_relay_maintainer_proxy_in_reimbursement_pool.ts} +0 -0
- /package/deploy/{41_authorize_light_relay_maintainer_proxy_in_light_relay.ts → 38_authorize_light_relay_maintainer_proxy_in_light_relay.ts} +0 -0
- /package/export/deploy/{37_deploy_light_relay_maintainer_proxy.js → 34_deploy_light_relay_maintainer_proxy.js} +0 -0
- /package/export/deploy/{38_authorize_maintainer_in_light_relay_maintainer_proxy.js → 35_authorize_maintainer_in_light_relay_maintainer_proxy.js} +0 -0
- /package/export/deploy/{39_transfer_light_relay_maintainer_proxy_ownership.js → 36_transfer_light_relay_maintainer_proxy_ownership.js} +0 -0
- /package/export/deploy/{40_authorize_light_relay_maintainer_proxy_in_reimbursement_pool.js → 37_authorize_light_relay_maintainer_proxy_in_reimbursement_pool.js} +0 -0
- /package/export/deploy/{41_authorize_light_relay_maintainer_proxy_in_light_relay.js → 38_authorize_light_relay_maintainer_proxy_in_light_relay.js} +0 -0
- /package/export/typechain/{WalletCoordinator.js → WalletProposalValidator.js} +0 -0
|
@@ -17,10 +17,6 @@ pragma solidity 0.8.17;
|
|
|
17
17
|
|
|
18
18
|
import {BTCUtils} from "@keep-network/bitcoin-spv-sol/contracts/BTCUtils.sol";
|
|
19
19
|
import {BytesLib} from "@keep-network/bitcoin-spv-sol/contracts/BytesLib.sol";
|
|
20
|
-
import "@keep-network/random-beacon/contracts/Reimbursable.sol";
|
|
21
|
-
import "@keep-network/random-beacon/contracts/ReimbursementPool.sol";
|
|
22
|
-
|
|
23
|
-
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
|
24
20
|
|
|
25
21
|
import "./BitcoinTx.sol";
|
|
26
22
|
import "./Bridge.sol";
|
|
@@ -28,50 +24,14 @@ import "./Deposit.sol";
|
|
|
28
24
|
import "./Redemption.sol";
|
|
29
25
|
import "./Wallets.sol";
|
|
30
26
|
|
|
31
|
-
/// @title Wallet
|
|
32
|
-
/// @notice
|
|
33
|
-
///
|
|
34
|
-
///
|
|
35
|
-
|
|
36
|
-
/// individual wallet member must do. Given the distributed nature of
|
|
37
|
-
/// the off-chain wallet software, full off-chain implementation is
|
|
38
|
-
/// challenging and prone to errors, especially byzantine faults.
|
|
39
|
-
/// This contract provides a single and trusted on-chain coordination
|
|
40
|
-
/// point thus taking the riskiest part out of the off-chain software.
|
|
41
|
-
/// The off-chain wallet members can focus on the core tasks and do not
|
|
42
|
-
/// bother about electing a trusted coordinator or aligning internal
|
|
43
|
-
/// states using complex consensus algorithms.
|
|
44
|
-
contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
|
|
27
|
+
/// @title Wallet proposal validator.
|
|
28
|
+
/// @notice This contract exposes several view functions allowing to validate
|
|
29
|
+
/// specific wallet action proposals. This contract is non-upgradeable
|
|
30
|
+
/// and does not have any write functions.
|
|
31
|
+
contract WalletProposalValidator {
|
|
45
32
|
using BTCUtils for bytes;
|
|
46
33
|
using BytesLib for bytes;
|
|
47
34
|
|
|
48
|
-
/// @notice Represents wallet action:
|
|
49
|
-
enum WalletAction {
|
|
50
|
-
/// @dev The wallet does not perform any action.
|
|
51
|
-
Idle,
|
|
52
|
-
/// @dev The wallet is executing heartbeat.
|
|
53
|
-
Heartbeat,
|
|
54
|
-
/// @dev The wallet is handling a deposit sweep action.
|
|
55
|
-
DepositSweep,
|
|
56
|
-
/// @dev The wallet is handling a redemption action.
|
|
57
|
-
Redemption,
|
|
58
|
-
/// @dev The wallet is handling a moving funds action.
|
|
59
|
-
MovingFunds,
|
|
60
|
-
/// @dev The wallet is handling a moved funds sweep action.
|
|
61
|
-
MovedFundsSweep
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/// @notice Holds information about a wallet time lock.
|
|
65
|
-
struct WalletLock {
|
|
66
|
-
/// @notice A UNIX timestamp defining the moment until which the wallet
|
|
67
|
-
/// is locked and cannot receive new proposals. The value of 0
|
|
68
|
-
/// means the wallet is not locked and can receive a proposal
|
|
69
|
-
/// at any time.
|
|
70
|
-
uint32 expiresAt;
|
|
71
|
-
/// @notice The wallet action being the cause of the lock.
|
|
72
|
-
WalletAction cause;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
35
|
/// @notice Helper structure representing a deposit sweep proposal.
|
|
76
36
|
struct DepositSweepProposal {
|
|
77
37
|
// 20-byte public key hash of the target wallet.
|
|
@@ -134,54 +94,28 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
|
|
|
134
94
|
uint256 redemptionTxFee;
|
|
135
95
|
}
|
|
136
96
|
|
|
137
|
-
/// @notice
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
97
|
+
/// @notice Helper structure representing a heartbeat proposal.
|
|
98
|
+
struct HeartbeatProposal {
|
|
99
|
+
// 20-byte public key hash of the target wallet.
|
|
100
|
+
bytes20 walletPubKeyHash;
|
|
101
|
+
// Message to be signed as part of the heartbeat.
|
|
102
|
+
bytes message;
|
|
103
|
+
}
|
|
144
104
|
|
|
145
105
|
/// @notice Handle to the Bridge contract.
|
|
146
|
-
Bridge public bridge;
|
|
147
|
-
|
|
148
|
-
/// @notice Determines the wallet heartbeat request validity time. In other
|
|
149
|
-
/// words, this is the worst-case time for a wallet heartbeat
|
|
150
|
-
/// during which the wallet is busy and canot take other actions.
|
|
151
|
-
/// This is also the duration of the time lock applied to the wallet
|
|
152
|
-
/// once a new heartbeat request is submitted.
|
|
153
|
-
///
|
|
154
|
-
/// For example, if a deposit sweep proposal was submitted at
|
|
155
|
-
/// 2 pm and heartbeatRequestValidity is 1 hour, the next request or
|
|
156
|
-
/// proposal (of any type) can be submitted after 3 pm.
|
|
157
|
-
uint32 public heartbeatRequestValidity;
|
|
158
|
-
|
|
159
|
-
/// @notice Gas that is meant to balance the heartbeat request overall cost.
|
|
160
|
-
/// Can be updated by the owner based on the current conditions.
|
|
161
|
-
uint32 public heartbeatRequestGasOffset;
|
|
162
|
-
|
|
163
|
-
/// @notice Determines the deposit sweep proposal validity time. In other
|
|
164
|
-
/// words, this is the worst-case time for a deposit sweep during
|
|
165
|
-
/// which the wallet is busy and cannot take another actions. This
|
|
166
|
-
/// is also the duration of the time lock applied to the wallet
|
|
167
|
-
/// once a new deposit sweep proposal is submitted.
|
|
168
|
-
///
|
|
169
|
-
/// For example, if a deposit sweep proposal was submitted at
|
|
170
|
-
/// 2 pm and depositSweepProposalValidity is 4 hours, the next
|
|
171
|
-
/// proposal (of any type) can be submitted after 6 pm.
|
|
172
|
-
uint32 public depositSweepProposalValidity;
|
|
106
|
+
Bridge public immutable bridge;
|
|
173
107
|
|
|
174
108
|
/// @notice The minimum time that must elapse since the deposit reveal
|
|
175
109
|
/// before a deposit becomes eligible for a deposit sweep.
|
|
176
110
|
///
|
|
177
|
-
/// For example, if a deposit was revealed at 9 am and
|
|
111
|
+
/// For example, if a deposit was revealed at 9 am and DEPOSIT_MIN_AGE
|
|
178
112
|
/// is 2 hours, the deposit is eligible for sweep after 11 am.
|
|
179
113
|
///
|
|
180
114
|
/// @dev Forcing deposit minimum age ensures block finality for Ethereum.
|
|
181
115
|
/// In the happy path case, i.e. where the deposit is revealed immediately
|
|
182
116
|
/// after being broadcast on the Bitcoin network, the minimum age
|
|
183
117
|
/// check also ensures block finality for Bitcoin.
|
|
184
|
-
uint32 public
|
|
118
|
+
uint32 public constant DEPOSIT_MIN_AGE = 2 hours;
|
|
185
119
|
|
|
186
120
|
/// @notice Each deposit can be technically swept until it reaches its
|
|
187
121
|
/// refund timestamp after which it can be taken back by the depositor.
|
|
@@ -196,39 +130,23 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
|
|
|
196
130
|
/// the deposit becomes refundable.
|
|
197
131
|
///
|
|
198
132
|
/// For example, if a deposit becomes refundable after 8 pm and
|
|
199
|
-
///
|
|
133
|
+
/// DEPOSIT_REFUND_SAFETY_MARGIN is 6 hours, the deposit is valid
|
|
200
134
|
/// for a sweep only before 2 pm.
|
|
201
|
-
uint32 public
|
|
135
|
+
uint32 public constant DEPOSIT_REFUND_SAFETY_MARGIN = 24 hours;
|
|
202
136
|
|
|
203
137
|
/// @notice The maximum count of deposits that can be swept within a
|
|
204
138
|
/// single sweep.
|
|
205
|
-
uint16 public
|
|
206
|
-
|
|
207
|
-
/// @notice Gas that is meant to balance the deposit sweep proposal
|
|
208
|
-
/// submission overall cost. Can be updated by the owner based on
|
|
209
|
-
/// the current conditions.
|
|
210
|
-
uint32 public depositSweepProposalSubmissionGasOffset;
|
|
211
|
-
|
|
212
|
-
/// @notice Determines the redemption proposal validity time. In other
|
|
213
|
-
/// words, this is the worst-case time for a redemption during
|
|
214
|
-
/// which the wallet is busy and cannot take another actions. This
|
|
215
|
-
/// is also the duration of the time lock applied to the wallet
|
|
216
|
-
/// once a new redemption proposal is submitted.
|
|
217
|
-
///
|
|
218
|
-
/// For example, if a redemption proposal was submitted at
|
|
219
|
-
/// 2 pm and redemptionProposalValidity is 2 hours, the next
|
|
220
|
-
/// proposal (of any type) can be submitted after 4 pm.
|
|
221
|
-
uint32 public redemptionProposalValidity;
|
|
139
|
+
uint16 public constant DEPOSIT_SWEEP_MAX_SIZE = 20;
|
|
222
140
|
|
|
223
141
|
/// @notice The minimum time that must elapse since the redemption request
|
|
224
142
|
/// creation before a request becomes eligible for a processing.
|
|
225
143
|
///
|
|
226
144
|
/// For example, if a request was created at 9 am and
|
|
227
|
-
///
|
|
228
|
-
/// processing after 11 am.
|
|
145
|
+
/// REDEMPTION_REQUEST_MIN_AGE is 2 hours, the request is
|
|
146
|
+
/// eligible for processing after 11 am.
|
|
229
147
|
///
|
|
230
148
|
/// @dev Forcing request minimum age ensures block finality for Ethereum.
|
|
231
|
-
uint32 public
|
|
149
|
+
uint32 public constant REDEMPTION_REQUEST_MIN_AGE = 600; // 10 minutes or ~50 blocks.
|
|
232
150
|
|
|
233
151
|
/// @notice Each redemption request can be technically handled until it
|
|
234
152
|
/// reaches its timeout timestamp after which it can be reported
|
|
@@ -245,276 +163,16 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
|
|
|
245
163
|
/// point after which the request can be reported as timed out.
|
|
246
164
|
///
|
|
247
165
|
/// For example, if a request times out after 8 pm and
|
|
248
|
-
///
|
|
249
|
-
/// valid for processing only before 6 pm.
|
|
250
|
-
uint32 public
|
|
166
|
+
/// REDEMPTION_REQUEST_TIMEOUT_SAFETY_MARGIN is 2 hours, the
|
|
167
|
+
/// request is valid for processing only before 6 pm.
|
|
168
|
+
uint32 public constant REDEMPTION_REQUEST_TIMEOUT_SAFETY_MARGIN = 2 hours;
|
|
251
169
|
|
|
252
170
|
/// @notice The maximum count of redemption requests that can be processed
|
|
253
171
|
/// within a single redemption.
|
|
254
|
-
uint16 public
|
|
255
|
-
|
|
256
|
-
/// @notice Gas that is meant to balance the redemption proposal
|
|
257
|
-
/// submission overall cost. Can be updated by the owner based on
|
|
258
|
-
/// the current conditions.
|
|
259
|
-
uint32 public redemptionProposalSubmissionGasOffset;
|
|
260
|
-
|
|
261
|
-
event CoordinatorAdded(address indexed coordinator);
|
|
262
|
-
|
|
263
|
-
event CoordinatorRemoved(address indexed coordinator);
|
|
264
|
-
|
|
265
|
-
event WalletManuallyUnlocked(bytes20 indexed walletPubKeyHash);
|
|
266
|
-
|
|
267
|
-
event HeartbeatRequestParametersUpdated(
|
|
268
|
-
uint32 heartbeatRequestValidity,
|
|
269
|
-
uint32 heartbeatRequestGasOffset
|
|
270
|
-
);
|
|
271
|
-
|
|
272
|
-
event HeartbeatRequestSubmitted(
|
|
273
|
-
bytes20 walletPubKeyHash,
|
|
274
|
-
bytes message,
|
|
275
|
-
address indexed coordinator
|
|
276
|
-
);
|
|
277
|
-
|
|
278
|
-
event DepositSweepProposalParametersUpdated(
|
|
279
|
-
uint32 depositSweepProposalValidity,
|
|
280
|
-
uint32 depositMinAge,
|
|
281
|
-
uint32 depositRefundSafetyMargin,
|
|
282
|
-
uint16 depositSweepMaxSize,
|
|
283
|
-
uint32 depositSweepProposalSubmissionGasOffset
|
|
284
|
-
);
|
|
285
|
-
|
|
286
|
-
event DepositSweepProposalSubmitted(
|
|
287
|
-
DepositSweepProposal proposal,
|
|
288
|
-
address indexed coordinator
|
|
289
|
-
);
|
|
290
|
-
|
|
291
|
-
event RedemptionProposalParametersUpdated(
|
|
292
|
-
uint32 redemptionProposalValidity,
|
|
293
|
-
uint32 redemptionRequestMinAge,
|
|
294
|
-
uint32 redemptionRequestTimeoutSafetyMargin,
|
|
295
|
-
uint16 redemptionMaxSize,
|
|
296
|
-
uint32 redemptionProposalSubmissionGasOffset
|
|
297
|
-
);
|
|
298
|
-
|
|
299
|
-
event RedemptionProposalSubmitted(
|
|
300
|
-
RedemptionProposal proposal,
|
|
301
|
-
address indexed coordinator
|
|
302
|
-
);
|
|
303
|
-
|
|
304
|
-
modifier onlyCoordinator() {
|
|
305
|
-
require(isCoordinator[msg.sender], "Caller is not a coordinator");
|
|
306
|
-
_;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
modifier onlyAfterWalletLock(bytes20 walletPubKeyHash) {
|
|
310
|
-
require(
|
|
311
|
-
/* solhint-disable-next-line not-rely-on-time */
|
|
312
|
-
block.timestamp > walletLock[walletPubKeyHash].expiresAt,
|
|
313
|
-
"Wallet locked"
|
|
314
|
-
);
|
|
315
|
-
_;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
modifier onlyReimbursableAdmin() override {
|
|
319
|
-
require(owner() == msg.sender, "Caller is not the owner");
|
|
320
|
-
_;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
function initialize(Bridge _bridge) external initializer {
|
|
324
|
-
__Ownable_init();
|
|
172
|
+
uint16 public constant REDEMPTION_MAX_SIZE = 20;
|
|
325
173
|
|
|
174
|
+
constructor(Bridge _bridge) {
|
|
326
175
|
bridge = _bridge;
|
|
327
|
-
// Pre-fetch addresses to save gas later.
|
|
328
|
-
(, , , reimbursementPool) = _bridge.contractReferences();
|
|
329
|
-
|
|
330
|
-
heartbeatRequestValidity = 1 hours;
|
|
331
|
-
heartbeatRequestGasOffset = 10_000;
|
|
332
|
-
|
|
333
|
-
depositSweepProposalValidity = 4 hours;
|
|
334
|
-
depositMinAge = 2 hours;
|
|
335
|
-
depositRefundSafetyMargin = 24 hours;
|
|
336
|
-
depositSweepMaxSize = 5;
|
|
337
|
-
depositSweepProposalSubmissionGasOffset = 20_000; // optimized for 10 inputs
|
|
338
|
-
|
|
339
|
-
redemptionProposalValidity = 2 hours;
|
|
340
|
-
redemptionRequestMinAge = 600; // 10 minutes or ~50 blocks.
|
|
341
|
-
redemptionRequestTimeoutSafetyMargin = 2 hours;
|
|
342
|
-
redemptionMaxSize = 20;
|
|
343
|
-
redemptionProposalSubmissionGasOffset = 20_000;
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
/// @notice Adds the given address to the set of coordinator addresses.
|
|
347
|
-
/// @param coordinator Address of the new coordinator.
|
|
348
|
-
/// @dev Requirements:
|
|
349
|
-
/// - The caller must be the owner,
|
|
350
|
-
/// - The `coordinator` must not be an existing coordinator.
|
|
351
|
-
function addCoordinator(address coordinator) external onlyOwner {
|
|
352
|
-
require(
|
|
353
|
-
!isCoordinator[coordinator],
|
|
354
|
-
"This address is already a coordinator"
|
|
355
|
-
);
|
|
356
|
-
isCoordinator[coordinator] = true;
|
|
357
|
-
emit CoordinatorAdded(coordinator);
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
/// @notice Removes the given address from the set of coordinator addresses.
|
|
361
|
-
/// @param coordinator Address of the existing coordinator.
|
|
362
|
-
/// @dev Requirements:
|
|
363
|
-
/// - The caller must be the owner,
|
|
364
|
-
/// - The `coordinator` must be an existing coordinator.
|
|
365
|
-
function removeCoordinator(address coordinator) external onlyOwner {
|
|
366
|
-
require(
|
|
367
|
-
isCoordinator[coordinator],
|
|
368
|
-
"This address is not a coordinator"
|
|
369
|
-
);
|
|
370
|
-
delete isCoordinator[coordinator];
|
|
371
|
-
emit CoordinatorRemoved(coordinator);
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
/// @notice Allows to unlock the given wallet before their time lock expires.
|
|
375
|
-
/// This function should be used in exceptional cases where
|
|
376
|
-
/// something went wrong and there is a need to unlock the wallet
|
|
377
|
-
/// without waiting.
|
|
378
|
-
/// @param walletPubKeyHash 20-byte public key hash of the wallet
|
|
379
|
-
/// @dev Requirements:
|
|
380
|
-
/// - The caller must be the owner.
|
|
381
|
-
function unlockWallet(bytes20 walletPubKeyHash) external onlyOwner {
|
|
382
|
-
// Just in case, allow the owner to unlock the wallet earlier.
|
|
383
|
-
walletLock[walletPubKeyHash] = WalletLock(0, WalletAction.Idle);
|
|
384
|
-
emit WalletManuallyUnlocked(walletPubKeyHash);
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
/// @notice Updates parameters related to heartbeat request.
|
|
388
|
-
/// @param _heartbeatRequestValidity The new value of `heartbeatRequestValidity`.
|
|
389
|
-
/// @param _heartbeatRequestGasOffset The new value of `heartbeatRequestGasOffset`.
|
|
390
|
-
/// @dev Requirements:
|
|
391
|
-
/// - The caller must be the owner.
|
|
392
|
-
function updateHeartbeatRequestParameters(
|
|
393
|
-
uint32 _heartbeatRequestValidity,
|
|
394
|
-
uint32 _heartbeatRequestGasOffset
|
|
395
|
-
) external onlyOwner {
|
|
396
|
-
heartbeatRequestValidity = _heartbeatRequestValidity;
|
|
397
|
-
heartbeatRequestGasOffset = _heartbeatRequestGasOffset;
|
|
398
|
-
emit HeartbeatRequestParametersUpdated(
|
|
399
|
-
_heartbeatRequestValidity,
|
|
400
|
-
_heartbeatRequestGasOffset
|
|
401
|
-
);
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
/// @notice Updates parameters related to deposit sweep proposal.
|
|
405
|
-
/// @param _depositSweepProposalValidity The new value of `depositSweepProposalValidity`.
|
|
406
|
-
/// @param _depositMinAge The new value of `depositMinAge`.
|
|
407
|
-
/// @param _depositRefundSafetyMargin The new value of `depositRefundSafetyMargin`.
|
|
408
|
-
/// @param _depositSweepMaxSize The new value of `depositSweepMaxSize`.
|
|
409
|
-
/// @dev Requirements:
|
|
410
|
-
/// - The caller must be the owner.
|
|
411
|
-
function updateDepositSweepProposalParameters(
|
|
412
|
-
uint32 _depositSweepProposalValidity,
|
|
413
|
-
uint32 _depositMinAge,
|
|
414
|
-
uint32 _depositRefundSafetyMargin,
|
|
415
|
-
uint16 _depositSweepMaxSize,
|
|
416
|
-
uint32 _depositSweepProposalSubmissionGasOffset
|
|
417
|
-
) external onlyOwner {
|
|
418
|
-
depositSweepProposalValidity = _depositSweepProposalValidity;
|
|
419
|
-
depositMinAge = _depositMinAge;
|
|
420
|
-
depositRefundSafetyMargin = _depositRefundSafetyMargin;
|
|
421
|
-
depositSweepMaxSize = _depositSweepMaxSize;
|
|
422
|
-
depositSweepProposalSubmissionGasOffset = _depositSweepProposalSubmissionGasOffset;
|
|
423
|
-
|
|
424
|
-
emit DepositSweepProposalParametersUpdated(
|
|
425
|
-
_depositSweepProposalValidity,
|
|
426
|
-
_depositMinAge,
|
|
427
|
-
_depositRefundSafetyMargin,
|
|
428
|
-
_depositSweepMaxSize,
|
|
429
|
-
_depositSweepProposalSubmissionGasOffset
|
|
430
|
-
);
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
/// @notice Submits a heartbeat request from the wallet. Locks the wallet
|
|
434
|
-
/// for a specific time, equal to the request validity period.
|
|
435
|
-
/// This function validates the proposed heartbeat messge to see
|
|
436
|
-
/// if it matches the heartbeat format expected by the Bridge.
|
|
437
|
-
/// @param walletPubKeyHash 20-byte public key hash of the wallet that is
|
|
438
|
-
/// supposed to execute the heartbeat.
|
|
439
|
-
/// @param message The proposed heartbeat message for the wallet to sign.
|
|
440
|
-
/// @dev Requirements:
|
|
441
|
-
/// - The caller is a coordinator,
|
|
442
|
-
/// - The wallet is not time-locked,
|
|
443
|
-
/// - The message to sign is a valid heartbeat message.
|
|
444
|
-
function requestHeartbeat(bytes20 walletPubKeyHash, bytes calldata message)
|
|
445
|
-
public
|
|
446
|
-
onlyCoordinator
|
|
447
|
-
onlyAfterWalletLock(walletPubKeyHash)
|
|
448
|
-
{
|
|
449
|
-
require(
|
|
450
|
-
Heartbeat.isValidHeartbeatMessage(message),
|
|
451
|
-
"Not a valid heartbeat message"
|
|
452
|
-
);
|
|
453
|
-
|
|
454
|
-
walletLock[walletPubKeyHash] = WalletLock(
|
|
455
|
-
/* solhint-disable-next-line not-rely-on-time */
|
|
456
|
-
uint32(block.timestamp) + heartbeatRequestValidity,
|
|
457
|
-
WalletAction.Heartbeat
|
|
458
|
-
);
|
|
459
|
-
|
|
460
|
-
emit HeartbeatRequestSubmitted(walletPubKeyHash, message, msg.sender);
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
/// @notice Wraps `requestHeartbeat` call and reimburses the caller's
|
|
464
|
-
/// transaction cost.
|
|
465
|
-
/// @dev See `requestHeartbeat` function documentation.
|
|
466
|
-
function requestHeartbeatWithReimbursement(
|
|
467
|
-
bytes20 walletPubKeyHash,
|
|
468
|
-
bytes calldata message
|
|
469
|
-
) external {
|
|
470
|
-
uint256 gasStart = gasleft();
|
|
471
|
-
|
|
472
|
-
requestHeartbeat(walletPubKeyHash, message);
|
|
473
|
-
|
|
474
|
-
reimbursementPool.refund(
|
|
475
|
-
(gasStart - gasleft()) + heartbeatRequestGasOffset,
|
|
476
|
-
msg.sender
|
|
477
|
-
);
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
/// @notice Submits a deposit sweep proposal. Locks the target wallet
|
|
481
|
-
/// for a specific time, equal to the proposal validity period.
|
|
482
|
-
/// This function does not store the proposal in the state but
|
|
483
|
-
/// just emits an event that serves as a guiding light for wallet
|
|
484
|
-
/// off-chain members. Wallet members are supposed to validate
|
|
485
|
-
/// the proposal on their own, before taking any action.
|
|
486
|
-
/// @param proposal The deposit sweep proposal
|
|
487
|
-
/// @dev Requirements:
|
|
488
|
-
/// - The caller is a coordinator,
|
|
489
|
-
/// - The wallet is not time-locked.
|
|
490
|
-
function submitDepositSweepProposal(DepositSweepProposal calldata proposal)
|
|
491
|
-
public
|
|
492
|
-
onlyCoordinator
|
|
493
|
-
onlyAfterWalletLock(proposal.walletPubKeyHash)
|
|
494
|
-
{
|
|
495
|
-
walletLock[proposal.walletPubKeyHash] = WalletLock(
|
|
496
|
-
/* solhint-disable-next-line not-rely-on-time */
|
|
497
|
-
uint32(block.timestamp) + depositSweepProposalValidity,
|
|
498
|
-
WalletAction.DepositSweep
|
|
499
|
-
);
|
|
500
|
-
|
|
501
|
-
emit DepositSweepProposalSubmitted(proposal, msg.sender);
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
/// @notice Wraps `submitDepositSweepProposal` call and reimburses the
|
|
505
|
-
/// caller's transaction cost.
|
|
506
|
-
/// @dev See `submitDepositSweepProposal` function documentation.
|
|
507
|
-
function submitDepositSweepProposalWithReimbursement(
|
|
508
|
-
DepositSweepProposal calldata proposal
|
|
509
|
-
) external {
|
|
510
|
-
uint256 gasStart = gasleft();
|
|
511
|
-
|
|
512
|
-
submitDepositSweepProposal(proposal);
|
|
513
|
-
|
|
514
|
-
reimbursementPool.refund(
|
|
515
|
-
(gasStart - gasleft()) + depositSweepProposalSubmissionGasOffset,
|
|
516
|
-
msg.sender
|
|
517
|
-
);
|
|
518
176
|
}
|
|
519
177
|
|
|
520
178
|
/// @notice View function encapsulating the main rules of a valid deposit
|
|
@@ -535,7 +193,7 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
|
|
|
535
193
|
/// @dev Requirements:
|
|
536
194
|
/// - The target wallet must be in the Live state,
|
|
537
195
|
/// - The number of deposits included in the sweep must be in
|
|
538
|
-
/// the range [1, `
|
|
196
|
+
/// the range [1, `DEPOSIT_SWEEP_MAX_SIZE`],
|
|
539
197
|
/// - The length of `depositsExtraInfo` array must be equal to the
|
|
540
198
|
/// length of `proposal.depositsKeys`, i.e. each deposit must
|
|
541
199
|
/// have exactly one set of corresponding extra data,
|
|
@@ -543,7 +201,7 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
|
|
|
543
201
|
/// - The proposed maximum per-deposit sweep tx fee must be lesser than
|
|
544
202
|
/// or equal the maximum fee allowed by the Bridge (`Bridge.depositTxMaxFee`),
|
|
545
203
|
/// - Each deposit must be revealed to the Bridge,
|
|
546
|
-
/// - Each deposit must be old enough, i.e. at least `
|
|
204
|
+
/// - Each deposit must be old enough, i.e. at least `DEPOSIT_MIN_AGE
|
|
547
205
|
/// elapsed since their reveal time,
|
|
548
206
|
/// - Each deposit must not be swept yet,
|
|
549
207
|
/// - Each deposit must have valid extra data (see `validateDepositExtraInfo`),
|
|
@@ -568,7 +226,7 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
|
|
|
568
226
|
require(proposal.depositsKeys.length > 0, "Sweep below the min size");
|
|
569
227
|
|
|
570
228
|
require(
|
|
571
|
-
proposal.depositsKeys.length <=
|
|
229
|
+
proposal.depositsKeys.length <= DEPOSIT_SWEEP_MAX_SIZE,
|
|
572
230
|
"Sweep exceeds the max size"
|
|
573
231
|
);
|
|
574
232
|
|
|
@@ -607,7 +265,7 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
|
|
|
607
265
|
|
|
608
266
|
require(
|
|
609
267
|
/* solhint-disable-next-line not-rely-on-time */
|
|
610
|
-
block.timestamp > depositRequest.revealedAt +
|
|
268
|
+
block.timestamp > depositRequest.revealedAt + DEPOSIT_MIN_AGE,
|
|
611
269
|
"Deposit min age not achieved yet"
|
|
612
270
|
);
|
|
613
271
|
|
|
@@ -625,7 +283,7 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
|
|
|
625
283
|
require(
|
|
626
284
|
/* solhint-disable-next-line not-rely-on-time */
|
|
627
285
|
block.timestamp <
|
|
628
|
-
depositRefundableTimestamp -
|
|
286
|
+
depositRefundableTimestamp - DEPOSIT_REFUND_SAFETY_MARGIN,
|
|
629
287
|
"Deposit refund safety margin is not preserved"
|
|
630
288
|
);
|
|
631
289
|
|
|
@@ -787,78 +445,6 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
|
|
|
787
445
|
revert("Extra info funding output script does not match");
|
|
788
446
|
}
|
|
789
447
|
|
|
790
|
-
/// @notice Updates parameters related to redemption proposal.
|
|
791
|
-
/// @param _redemptionProposalValidity The new value of `redemptionProposalValidity`.
|
|
792
|
-
/// @param _redemptionRequestMinAge The new value of `redemptionRequestMinAge`.
|
|
793
|
-
/// @param _redemptionRequestTimeoutSafetyMargin The new value of
|
|
794
|
-
/// `redemptionRequestTimeoutSafetyMargin`.
|
|
795
|
-
/// @param _redemptionMaxSize The new value of `redemptionMaxSize`.
|
|
796
|
-
/// @param _redemptionProposalSubmissionGasOffset The new value of
|
|
797
|
-
/// `redemptionProposalSubmissionGasOffset`.
|
|
798
|
-
/// @dev Requirements:
|
|
799
|
-
/// - The caller must be the owner.
|
|
800
|
-
function updateRedemptionProposalParameters(
|
|
801
|
-
uint32 _redemptionProposalValidity,
|
|
802
|
-
uint32 _redemptionRequestMinAge,
|
|
803
|
-
uint32 _redemptionRequestTimeoutSafetyMargin,
|
|
804
|
-
uint16 _redemptionMaxSize,
|
|
805
|
-
uint32 _redemptionProposalSubmissionGasOffset
|
|
806
|
-
) external onlyOwner {
|
|
807
|
-
redemptionProposalValidity = _redemptionProposalValidity;
|
|
808
|
-
redemptionRequestMinAge = _redemptionRequestMinAge;
|
|
809
|
-
redemptionRequestTimeoutSafetyMargin = _redemptionRequestTimeoutSafetyMargin;
|
|
810
|
-
redemptionMaxSize = _redemptionMaxSize;
|
|
811
|
-
redemptionProposalSubmissionGasOffset = _redemptionProposalSubmissionGasOffset;
|
|
812
|
-
|
|
813
|
-
emit RedemptionProposalParametersUpdated(
|
|
814
|
-
_redemptionProposalValidity,
|
|
815
|
-
_redemptionRequestMinAge,
|
|
816
|
-
_redemptionRequestTimeoutSafetyMargin,
|
|
817
|
-
_redemptionMaxSize,
|
|
818
|
-
_redemptionProposalSubmissionGasOffset
|
|
819
|
-
);
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
/// @notice Submits a redemption proposal. Locks the target wallet
|
|
823
|
-
/// for a specific time, equal to the proposal validity period.
|
|
824
|
-
/// This function does not store the proposal in the state but
|
|
825
|
-
/// just emits an event that serves as a guiding light for wallet
|
|
826
|
-
/// off-chain members. Wallet members are supposed to validate
|
|
827
|
-
/// the proposal on their own, before taking any action.
|
|
828
|
-
/// @param proposal The redemption proposal
|
|
829
|
-
/// @dev Requirements:
|
|
830
|
-
/// - The caller is a coordinator,
|
|
831
|
-
/// - The wallet is not time-locked.
|
|
832
|
-
function submitRedemptionProposal(RedemptionProposal calldata proposal)
|
|
833
|
-
public
|
|
834
|
-
onlyCoordinator
|
|
835
|
-
onlyAfterWalletLock(proposal.walletPubKeyHash)
|
|
836
|
-
{
|
|
837
|
-
walletLock[proposal.walletPubKeyHash] = WalletLock(
|
|
838
|
-
/* solhint-disable-next-line not-rely-on-time */
|
|
839
|
-
uint32(block.timestamp) + redemptionProposalValidity,
|
|
840
|
-
WalletAction.Redemption
|
|
841
|
-
);
|
|
842
|
-
|
|
843
|
-
emit RedemptionProposalSubmitted(proposal, msg.sender);
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
/// @notice Wraps `submitRedemptionProposal` call and reimburses the
|
|
847
|
-
/// caller's transaction cost.
|
|
848
|
-
/// @dev See `submitRedemptionProposal` function documentation.
|
|
849
|
-
function submitRedemptionProposalWithReimbursement(
|
|
850
|
-
RedemptionProposal calldata proposal
|
|
851
|
-
) external {
|
|
852
|
-
uint256 gasStart = gasleft();
|
|
853
|
-
|
|
854
|
-
submitRedemptionProposal(proposal);
|
|
855
|
-
|
|
856
|
-
reimbursementPool.refund(
|
|
857
|
-
(gasStart - gasleft()) + redemptionProposalSubmissionGasOffset,
|
|
858
|
-
msg.sender
|
|
859
|
-
);
|
|
860
|
-
}
|
|
861
|
-
|
|
862
448
|
/// @notice View function encapsulating the main rules of a valid redemption
|
|
863
449
|
/// proposal. This function is meant to facilitate the off-chain
|
|
864
450
|
/// validation of the incoming proposals. Thanks to it, most
|
|
@@ -897,7 +483,7 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
|
|
|
897
483
|
require(requestsCount > 0, "Redemption below the min size");
|
|
898
484
|
|
|
899
485
|
require(
|
|
900
|
-
requestsCount <=
|
|
486
|
+
requestsCount <= REDEMPTION_MAX_SIZE,
|
|
901
487
|
"Redemption exceeds the max size"
|
|
902
488
|
);
|
|
903
489
|
|
|
@@ -960,7 +546,7 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
|
|
|
960
546
|
require(
|
|
961
547
|
/* solhint-disable-next-line not-rely-on-time */
|
|
962
548
|
block.timestamp >
|
|
963
|
-
redemptionRequest.requestedAt +
|
|
549
|
+
redemptionRequest.requestedAt + REDEMPTION_REQUEST_MIN_AGE,
|
|
964
550
|
"Redemption request min age not achieved yet"
|
|
965
551
|
);
|
|
966
552
|
|
|
@@ -971,7 +557,7 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
|
|
|
971
557
|
require(
|
|
972
558
|
/* solhint-disable-next-line not-rely-on-time */
|
|
973
559
|
block.timestamp <
|
|
974
|
-
requestTimeout -
|
|
560
|
+
requestTimeout - REDEMPTION_REQUEST_TIMEOUT_SAFETY_MARGIN,
|
|
975
561
|
"Redemption request timeout safety margin is not preserved"
|
|
976
562
|
);
|
|
977
563
|
|
|
@@ -1000,4 +586,25 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
|
|
|
1000
586
|
|
|
1001
587
|
return true;
|
|
1002
588
|
}
|
|
589
|
+
|
|
590
|
+
/// @notice View function encapsulating the main rules of a valid heartbeat
|
|
591
|
+
/// proposal. This function is meant to facilitate the off-chain
|
|
592
|
+
/// validation of the incoming proposals. Thanks to it, most
|
|
593
|
+
/// of the work can be done using a single readonly contract call.
|
|
594
|
+
/// @param proposal The heartbeat proposal to validate.
|
|
595
|
+
/// @return True if the proposal is valid. Reverts otherwise.
|
|
596
|
+
/// @dev Requirements:
|
|
597
|
+
/// - The message to sign is a valid heartbeat message.
|
|
598
|
+
function validateHeartbeatProposal(HeartbeatProposal calldata proposal)
|
|
599
|
+
external
|
|
600
|
+
view
|
|
601
|
+
returns (bool)
|
|
602
|
+
{
|
|
603
|
+
require(
|
|
604
|
+
Heartbeat.isValidHeartbeatMessage(proposal.message),
|
|
605
|
+
"Not a valid heartbeat message"
|
|
606
|
+
);
|
|
607
|
+
|
|
608
|
+
return true;
|
|
609
|
+
}
|
|
1003
610
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { HardhatRuntimeEnvironment } from "hardhat/types"
|
|
2
|
+
import { DeployFunction } from "hardhat-deploy/types"
|
|
3
|
+
|
|
4
|
+
const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
|
|
5
|
+
const { deployments, helpers, getNamedAccounts } = hre
|
|
6
|
+
const { deploy } = deployments
|
|
7
|
+
const { deployer } = await getNamedAccounts()
|
|
8
|
+
|
|
9
|
+
const Bridge = await deployments.get("Bridge")
|
|
10
|
+
|
|
11
|
+
const walletProposalValidator = await deploy("WalletProposalValidator", {
|
|
12
|
+
from: deployer,
|
|
13
|
+
args: [Bridge.address],
|
|
14
|
+
log: true,
|
|
15
|
+
waitConfirmations: 1,
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
if (hre.network.tags.etherscan) {
|
|
19
|
+
await helpers.etherscan.verify(walletProposalValidator)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (hre.network.tags.tenderly) {
|
|
23
|
+
await hre.tenderly.verify({
|
|
24
|
+
name: "WalletProposalValidator",
|
|
25
|
+
address: walletProposalValidator.address,
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default func
|
|
31
|
+
|
|
32
|
+
func.tags = ["WalletProposalValidator"]
|
|
33
|
+
func.dependencies = ["Bridge"]
|