@keep-network/tbtc-v2 1.6.0-dev.5 → 1.6.0-dev.7
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 +6 -6
- package/artifacts/Bank.json +17 -17
- package/artifacts/BeaconAuthorization.json +6 -6
- package/artifacts/BeaconDkg.json +6 -6
- package/artifacts/BeaconDkgValidator.json +9 -9
- package/artifacts/BeaconInactivity.json +6 -6
- package/artifacts/BeaconSortitionPool.json +16 -16
- package/artifacts/Bridge.json +32 -32
- package/artifacts/BridgeGovernance.json +14 -14
- package/artifacts/BridgeGovernanceParameters.json +7 -7
- package/artifacts/Deposit.json +7 -7
- package/artifacts/DepositSweep.json +7 -7
- package/artifacts/DonationVault.json +11 -11
- package/artifacts/EcdsaDkgValidator.json +7 -7
- package/artifacts/EcdsaInactivity.json +6 -6
- package/artifacts/EcdsaSortitionPool.json +16 -16
- package/artifacts/Fraud.json +7 -7
- package/artifacts/LightRelay.json +28 -28
- package/artifacts/LightRelayMaintainerProxy.json +24 -24
- package/artifacts/MaintainerProxy.json +37 -37
- package/artifacts/MovingFunds.json +7 -7
- package/artifacts/NuCypherToken.json +11 -11
- package/artifacts/RandomBeacon.json +23 -23
- package/artifacts/RandomBeaconChaosnet.json +11 -11
- package/artifacts/RandomBeaconGovernance.json +12 -12
- package/artifacts/Redemption.json +7 -7
- package/artifacts/ReimbursementPool.json +11 -11
- package/artifacts/T.json +11 -11
- package/artifacts/TBTC.json +19 -19
- package/artifacts/TBTCToken.json +19 -19
- package/artifacts/TBTCVault.json +36 -36
- package/artifacts/TokenStaking.json +156 -308
- package/artifacts/TokenholderGovernor.json +47 -47
- package/artifacts/TokenholderTimelock.json +36 -36
- package/artifacts/VendingMachine.json +22 -22
- package/artifacts/VendingMachineNuCypher.json +9 -9
- package/artifacts/VendingMachineV2.json +15 -15
- package/artifacts/VendingMachineV3.json +15 -15
- package/artifacts/WalletProposalValidator.json +437 -0
- package/artifacts/WalletRegistry.json +31 -31
- package/artifacts/WalletRegistryGovernance.json +56 -56
- package/artifacts/Wallets.json +7 -7
- package/artifacts/solcInputs/{d2d7e276da75d7184610fe11a4a103b7.json → b4e1c442421284b256fcad9f86102ecc.json} +4 -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/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 +323 -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} +129 -447
- package/deploy/39_deploy_wallet_proposal_validator.ts +33 -0
- package/export/artifacts/@keep-network/ecdsa/contracts/EcdsaDkgValidator.sol/EcdsaDkgValidator.json +24 -24
- package/export/artifacts/@keep-network/ecdsa/contracts/WalletRegistry.sol/WalletRegistry.json +4999 -4814
- package/export/artifacts/@keep-network/ecdsa/contracts/libraries/EcdsaDkg.sol/EcdsaDkg.json +2 -2
- package/export/artifacts/@keep-network/ecdsa/contracts/libraries/EcdsaInactivity.sol/EcdsaInactivity.json +23 -23
- package/export/artifacts/@keep-network/random-beacon/contracts/ReimbursementPool.sol/ReimbursementPool.json +53 -53
- package/export/artifacts/@keep-network/sortition-pools/contracts/Chaosnet.sol/Chaosnet.json +21 -21
- package/export/artifacts/@keep-network/sortition-pools/contracts/Rewards.sol/Rewards.json +16 -16
- package/export/artifacts/@keep-network/sortition-pools/contracts/SortitionPool.sol/SortitionPool.json +206 -206
- package/export/artifacts/@keep-network/sortition-pools/contracts/SortitionTree.sol/SortitionTree.json +26 -26
- package/export/artifacts/@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol/ERC1967Proxy.json +46 -46
- package/export/artifacts/@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol/ProxyAdmin.json +36 -36
- package/export/artifacts/@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json +78 -78
- package/export/artifacts/@openzeppelin/contracts/token/ERC721/ERC721.sol/ERC721.json +68 -68
- package/export/artifacts/@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol/ERC20Upgradeable.json +43 -43
- package/export/artifacts/@thesis/solidity-contracts/contracts/token/ERC20WithPermit.sol/ERC20WithPermit.json +79 -79
- package/export/artifacts/@thesis/solidity-contracts/contracts/token/MisfundRecovery.sol/MisfundRecovery.json +42 -42
- package/export/artifacts/contracts/bank/Bank.sol/Bank.json +77 -77
- package/export/artifacts/contracts/bridge/Bridge.sol/Bridge.json +320 -320
- package/export/artifacts/contracts/bridge/VendingMachine.sol/VendingMachine.json +108 -108
- package/export/artifacts/contracts/bridge/VendingMachineV2.sol/VendingMachineV2.json +63 -63
- package/export/artifacts/contracts/bridge/VendingMachineV3.sol/VendingMachineV3.json +65 -65
- package/export/artifacts/contracts/bridge/WalletProposalValidator.sol/WalletProposalValidator.json +25381 -0
- package/export/artifacts/contracts/l2/L2TBTC.sol/L2TBTC.json +194 -194
- package/export/artifacts/contracts/l2/L2WormholeGateway.sol/L2WormholeGateway.json +98 -98
- package/export/artifacts/contracts/maintainer/MaintainerProxy.sol/MaintainerProxy.json +149 -149
- package/export/artifacts/contracts/relay/LightRelay.sol/LightRelay.json +76 -76
- package/export/artifacts/contracts/relay/LightRelayMaintainerProxy.sol/LightRelayMaintainerProxy.json +62 -62
- package/export/artifacts/contracts/test/BankStub.sol/BankStub.json +79 -79
- package/export/artifacts/contracts/test/BridgeStub.sol/BridgeStub.json +358 -358
- package/export/artifacts/contracts/test/GoerliLightRelay.sol/GoerliLightRelay.json +78 -78
- package/export/artifacts/contracts/test/HeartbeatStub.sol/HeartbeatStub.json +4 -4
- package/export/artifacts/contracts/test/LightRelayStub.sol/LightRelayStub.json +78 -78
- package/export/artifacts/contracts/test/ReceiveApprovalStub.sol/ReceiveApprovalStub.json +7 -7
- package/export/artifacts/contracts/test/SepoliaLightRelay.sol/SepoliaLightRelay.json +78 -78
- package/export/artifacts/contracts/test/SystemTestRelay.sol/SystemTestRelay.json +14 -14
- package/export/artifacts/contracts/test/TestERC20.sol/TestERC20.json +85 -85
- package/export/artifacts/contracts/test/TestERC721.sol/TestERC721.json +78 -78
- package/export/artifacts/contracts/test/TestEcdsaLib.sol/TestEcdsaLib.json +4 -4
- package/export/artifacts/contracts/test/WormholeBridgeStub.sol/WormholeBridgeStub.json +37 -37
- package/export/artifacts/contracts/token/TBTC.sol/TBTC.json +104 -104
- package/export/artifacts/contracts/vault/DonationVault.sol/DonationVault.json +19 -19
- package/export/artifacts/contracts/vault/TBTCVault.sol/TBTCVault.json +184 -184
- package/export/deploy/39_deploy_wallet_proposal_validator.js +82 -0
- package/export/hardhat.config.js +0 -6
- package/export/typechain/factories/EcdsaAuthorization__factory.js +1 -1
- package/export/typechain/factories/IStaking__factory.js +24 -103
- package/export/typechain/factories/WalletProposalValidator__factory.js +402 -0
- package/export/typechain/factories/WalletRegistry__factory.js +1 -1
- package/export/typechain/index.js +3 -3
- package/package.json +2 -2
- package/artifacts/KeepRegistry.json +0 -99
- package/artifacts/KeepStake.json +0 -286
- package/artifacts/KeepToken.json +0 -711
- package/artifacts/KeepTokenStaking.json +0 -483
- package/artifacts/NuCypherStakingEscrow.json +0 -287
- package/artifacts/VendingMachineKeep.json +0 -400
- 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,38 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
|
|
|
134
94
|
uint256 redemptionTxFee;
|
|
135
95
|
}
|
|
136
96
|
|
|
137
|
-
/// @notice
|
|
138
|
-
|
|
139
|
-
|
|
97
|
+
/// @notice Helper structure representing a moving funds proposal.
|
|
98
|
+
struct MovingFundsProposal {
|
|
99
|
+
// 20-byte public key hash of the source wallet.
|
|
100
|
+
bytes20 walletPubKeyHash;
|
|
101
|
+
// List of 20-byte public key hashes of target wallets.
|
|
102
|
+
bytes20[] targetWallets;
|
|
103
|
+
// Proposed BTC fee for the entire transaction.
|
|
104
|
+
uint256 movingFundsTxFee;
|
|
105
|
+
}
|
|
140
106
|
|
|
141
|
-
/// @notice
|
|
142
|
-
|
|
143
|
-
|
|
107
|
+
/// @notice Helper structure representing a heartbeat proposal.
|
|
108
|
+
struct HeartbeatProposal {
|
|
109
|
+
// 20-byte public key hash of the target wallet.
|
|
110
|
+
bytes20 walletPubKeyHash;
|
|
111
|
+
// Message to be signed as part of the heartbeat.
|
|
112
|
+
bytes message;
|
|
113
|
+
}
|
|
144
114
|
|
|
145
115
|
/// @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;
|
|
116
|
+
Bridge public immutable bridge;
|
|
173
117
|
|
|
174
118
|
/// @notice The minimum time that must elapse since the deposit reveal
|
|
175
119
|
/// before a deposit becomes eligible for a deposit sweep.
|
|
176
120
|
///
|
|
177
|
-
/// For example, if a deposit was revealed at 9 am and
|
|
121
|
+
/// For example, if a deposit was revealed at 9 am and DEPOSIT_MIN_AGE
|
|
178
122
|
/// is 2 hours, the deposit is eligible for sweep after 11 am.
|
|
179
123
|
///
|
|
180
124
|
/// @dev Forcing deposit minimum age ensures block finality for Ethereum.
|
|
181
125
|
/// In the happy path case, i.e. where the deposit is revealed immediately
|
|
182
126
|
/// after being broadcast on the Bitcoin network, the minimum age
|
|
183
127
|
/// check also ensures block finality for Bitcoin.
|
|
184
|
-
uint32 public
|
|
128
|
+
uint32 public constant DEPOSIT_MIN_AGE = 2 hours;
|
|
185
129
|
|
|
186
130
|
/// @notice Each deposit can be technically swept until it reaches its
|
|
187
131
|
/// refund timestamp after which it can be taken back by the depositor.
|
|
@@ -196,39 +140,23 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
|
|
|
196
140
|
/// the deposit becomes refundable.
|
|
197
141
|
///
|
|
198
142
|
/// For example, if a deposit becomes refundable after 8 pm and
|
|
199
|
-
///
|
|
143
|
+
/// DEPOSIT_REFUND_SAFETY_MARGIN is 6 hours, the deposit is valid
|
|
200
144
|
/// for a sweep only before 2 pm.
|
|
201
|
-
uint32 public
|
|
145
|
+
uint32 public constant DEPOSIT_REFUND_SAFETY_MARGIN = 24 hours;
|
|
202
146
|
|
|
203
147
|
/// @notice The maximum count of deposits that can be swept within a
|
|
204
148
|
/// 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;
|
|
149
|
+
uint16 public constant DEPOSIT_SWEEP_MAX_SIZE = 20;
|
|
222
150
|
|
|
223
151
|
/// @notice The minimum time that must elapse since the redemption request
|
|
224
152
|
/// creation before a request becomes eligible for a processing.
|
|
225
153
|
///
|
|
226
154
|
/// For example, if a request was created at 9 am and
|
|
227
|
-
///
|
|
228
|
-
/// processing after 11 am.
|
|
155
|
+
/// REDEMPTION_REQUEST_MIN_AGE is 2 hours, the request is
|
|
156
|
+
/// eligible for processing after 11 am.
|
|
229
157
|
///
|
|
230
158
|
/// @dev Forcing request minimum age ensures block finality for Ethereum.
|
|
231
|
-
uint32 public
|
|
159
|
+
uint32 public constant REDEMPTION_REQUEST_MIN_AGE = 600; // 10 minutes or ~50 blocks.
|
|
232
160
|
|
|
233
161
|
/// @notice Each redemption request can be technically handled until it
|
|
234
162
|
/// reaches its timeout timestamp after which it can be reported
|
|
@@ -245,276 +173,16 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
|
|
|
245
173
|
/// point after which the request can be reported as timed out.
|
|
246
174
|
///
|
|
247
175
|
/// For example, if a request times out after 8 pm and
|
|
248
|
-
///
|
|
249
|
-
/// valid for processing only before 6 pm.
|
|
250
|
-
uint32 public
|
|
176
|
+
/// REDEMPTION_REQUEST_TIMEOUT_SAFETY_MARGIN is 2 hours, the
|
|
177
|
+
/// request is valid for processing only before 6 pm.
|
|
178
|
+
uint32 public constant REDEMPTION_REQUEST_TIMEOUT_SAFETY_MARGIN = 2 hours;
|
|
251
179
|
|
|
252
180
|
/// @notice The maximum count of redemption requests that can be processed
|
|
253
181
|
/// 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();
|
|
182
|
+
uint16 public constant REDEMPTION_MAX_SIZE = 20;
|
|
325
183
|
|
|
184
|
+
constructor(Bridge _bridge) {
|
|
326
185
|
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
186
|
}
|
|
519
187
|
|
|
520
188
|
/// @notice View function encapsulating the main rules of a valid deposit
|
|
@@ -535,7 +203,7 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
|
|
|
535
203
|
/// @dev Requirements:
|
|
536
204
|
/// - The target wallet must be in the Live state,
|
|
537
205
|
/// - The number of deposits included in the sweep must be in
|
|
538
|
-
/// the range [1, `
|
|
206
|
+
/// the range [1, `DEPOSIT_SWEEP_MAX_SIZE`],
|
|
539
207
|
/// - The length of `depositsExtraInfo` array must be equal to the
|
|
540
208
|
/// length of `proposal.depositsKeys`, i.e. each deposit must
|
|
541
209
|
/// have exactly one set of corresponding extra data,
|
|
@@ -543,7 +211,7 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
|
|
|
543
211
|
/// - The proposed maximum per-deposit sweep tx fee must be lesser than
|
|
544
212
|
/// or equal the maximum fee allowed by the Bridge (`Bridge.depositTxMaxFee`),
|
|
545
213
|
/// - Each deposit must be revealed to the Bridge,
|
|
546
|
-
/// - Each deposit must be old enough, i.e. at least `
|
|
214
|
+
/// - Each deposit must be old enough, i.e. at least `DEPOSIT_MIN_AGE
|
|
547
215
|
/// elapsed since their reveal time,
|
|
548
216
|
/// - Each deposit must not be swept yet,
|
|
549
217
|
/// - Each deposit must have valid extra data (see `validateDepositExtraInfo`),
|
|
@@ -568,7 +236,7 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
|
|
|
568
236
|
require(proposal.depositsKeys.length > 0, "Sweep below the min size");
|
|
569
237
|
|
|
570
238
|
require(
|
|
571
|
-
proposal.depositsKeys.length <=
|
|
239
|
+
proposal.depositsKeys.length <= DEPOSIT_SWEEP_MAX_SIZE,
|
|
572
240
|
"Sweep exceeds the max size"
|
|
573
241
|
);
|
|
574
242
|
|
|
@@ -607,7 +275,7 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
|
|
|
607
275
|
|
|
608
276
|
require(
|
|
609
277
|
/* solhint-disable-next-line not-rely-on-time */
|
|
610
|
-
block.timestamp > depositRequest.revealedAt +
|
|
278
|
+
block.timestamp > depositRequest.revealedAt + DEPOSIT_MIN_AGE,
|
|
611
279
|
"Deposit min age not achieved yet"
|
|
612
280
|
);
|
|
613
281
|
|
|
@@ -625,7 +293,7 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
|
|
|
625
293
|
require(
|
|
626
294
|
/* solhint-disable-next-line not-rely-on-time */
|
|
627
295
|
block.timestamp <
|
|
628
|
-
depositRefundableTimestamp -
|
|
296
|
+
depositRefundableTimestamp - DEPOSIT_REFUND_SAFETY_MARGIN,
|
|
629
297
|
"Deposit refund safety margin is not preserved"
|
|
630
298
|
);
|
|
631
299
|
|
|
@@ -787,78 +455,6 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
|
|
|
787
455
|
revert("Extra info funding output script does not match");
|
|
788
456
|
}
|
|
789
457
|
|
|
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
458
|
/// @notice View function encapsulating the main rules of a valid redemption
|
|
863
459
|
/// proposal. This function is meant to facilitate the off-chain
|
|
864
460
|
/// validation of the incoming proposals. Thanks to it, most
|
|
@@ -897,7 +493,7 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
|
|
|
897
493
|
require(requestsCount > 0, "Redemption below the min size");
|
|
898
494
|
|
|
899
495
|
require(
|
|
900
|
-
requestsCount <=
|
|
496
|
+
requestsCount <= REDEMPTION_MAX_SIZE,
|
|
901
497
|
"Redemption exceeds the max size"
|
|
902
498
|
);
|
|
903
499
|
|
|
@@ -960,7 +556,7 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
|
|
|
960
556
|
require(
|
|
961
557
|
/* solhint-disable-next-line not-rely-on-time */
|
|
962
558
|
block.timestamp >
|
|
963
|
-
redemptionRequest.requestedAt +
|
|
559
|
+
redemptionRequest.requestedAt + REDEMPTION_REQUEST_MIN_AGE,
|
|
964
560
|
"Redemption request min age not achieved yet"
|
|
965
561
|
);
|
|
966
562
|
|
|
@@ -971,7 +567,7 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
|
|
|
971
567
|
require(
|
|
972
568
|
/* solhint-disable-next-line not-rely-on-time */
|
|
973
569
|
block.timestamp <
|
|
974
|
-
requestTimeout -
|
|
570
|
+
requestTimeout - REDEMPTION_REQUEST_TIMEOUT_SAFETY_MARGIN,
|
|
975
571
|
"Redemption request timeout safety margin is not preserved"
|
|
976
572
|
);
|
|
977
573
|
|
|
@@ -1000,4 +596,90 @@ contract WalletCoordinator is OwnableUpgradeable, Reimbursable {
|
|
|
1000
596
|
|
|
1001
597
|
return true;
|
|
1002
598
|
}
|
|
599
|
+
|
|
600
|
+
/// @notice View function encapsulating the main rules of a valid moving
|
|
601
|
+
/// funds proposal. This function is meant to facilitate the
|
|
602
|
+
/// off-chain validation of the incoming proposals. Thanks to it,
|
|
603
|
+
/// most of the work can be done using a single readonly contract
|
|
604
|
+
/// call.
|
|
605
|
+
/// @param proposal The moving funds proposal to validate.
|
|
606
|
+
/// @return True if the proposal is valid. Reverts otherwise.
|
|
607
|
+
/// @dev Notice that this function is meant to be invoked after the moving
|
|
608
|
+
/// funds commitment has already been submitted. This function skips
|
|
609
|
+
/// some checks related to the moving funds procedure as they were
|
|
610
|
+
/// already checked on the commitment submission.
|
|
611
|
+
/// Requirements:
|
|
612
|
+
/// - The source wallet must be in the MovingFunds state,
|
|
613
|
+
/// - The target wallets commitment must be submitted,
|
|
614
|
+
/// - The target wallets commitment hash must match the target wallets
|
|
615
|
+
/// from the proposal,
|
|
616
|
+
/// - The proposed moving funds transaction fee must be greater than
|
|
617
|
+
/// zero,
|
|
618
|
+
/// - The proposed moving funds transaction fee must not exceed the
|
|
619
|
+
/// maximum total fee allowed for moving funds.
|
|
620
|
+
function validateMovingFundsProposal(MovingFundsProposal calldata proposal)
|
|
621
|
+
external
|
|
622
|
+
view
|
|
623
|
+
returns (bool)
|
|
624
|
+
{
|
|
625
|
+
Wallets.Wallet memory sourceWallet = bridge.wallets(
|
|
626
|
+
proposal.walletPubKeyHash
|
|
627
|
+
);
|
|
628
|
+
|
|
629
|
+
// Make sure the source wallet is in MovingFunds state.
|
|
630
|
+
require(
|
|
631
|
+
sourceWallet.state == Wallets.WalletState.MovingFunds,
|
|
632
|
+
"Source wallet is not in MovingFunds state"
|
|
633
|
+
);
|
|
634
|
+
|
|
635
|
+
// Make sure the moving funds commitment has been submitted and
|
|
636
|
+
// the commitment hash matches the target wallets from the proposal.
|
|
637
|
+
require(
|
|
638
|
+
sourceWallet.movingFundsTargetWalletsCommitmentHash != bytes32(0),
|
|
639
|
+
"Target wallets commitment is not submitted"
|
|
640
|
+
);
|
|
641
|
+
|
|
642
|
+
require(
|
|
643
|
+
sourceWallet.movingFundsTargetWalletsCommitmentHash ==
|
|
644
|
+
keccak256(abi.encodePacked(proposal.targetWallets)),
|
|
645
|
+
"Target wallets do not match target wallets commitment hash"
|
|
646
|
+
);
|
|
647
|
+
|
|
648
|
+
// Make sure the proposed fee is valid.
|
|
649
|
+
(uint64 movingFundsTxMaxTotalFee, , , , , , , , , , ) = bridge
|
|
650
|
+
.movingFundsParameters();
|
|
651
|
+
|
|
652
|
+
require(
|
|
653
|
+
proposal.movingFundsTxFee > 0,
|
|
654
|
+
"Proposed transaction fee cannot be zero"
|
|
655
|
+
);
|
|
656
|
+
|
|
657
|
+
require(
|
|
658
|
+
proposal.movingFundsTxFee <= movingFundsTxMaxTotalFee,
|
|
659
|
+
"Proposed transaction fee is too high"
|
|
660
|
+
);
|
|
661
|
+
|
|
662
|
+
return true;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
/// @notice View function encapsulating the main rules of a valid heartbeat
|
|
666
|
+
/// proposal. This function is meant to facilitate the off-chain
|
|
667
|
+
/// validation of the incoming proposals. Thanks to it, most
|
|
668
|
+
/// of the work can be done using a single readonly contract call.
|
|
669
|
+
/// @param proposal The heartbeat proposal to validate.
|
|
670
|
+
/// @return True if the proposal is valid. Reverts otherwise.
|
|
671
|
+
/// @dev Requirements:
|
|
672
|
+
/// - The message to sign is a valid heartbeat message.
|
|
673
|
+
function validateHeartbeatProposal(HeartbeatProposal calldata proposal)
|
|
674
|
+
external
|
|
675
|
+
view
|
|
676
|
+
returns (bool)
|
|
677
|
+
{
|
|
678
|
+
require(
|
|
679
|
+
Heartbeat.isValidHeartbeatMessage(proposal.message),
|
|
680
|
+
"Not a valid heartbeat message"
|
|
681
|
+
);
|
|
682
|
+
|
|
683
|
+
return true;
|
|
684
|
+
}
|
|
1003
685
|
}
|