@keep-network/tbtc-v2 0.1.1-dev.107 → 0.1.1-dev.108
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 +5 -5
- package/artifacts/BridgeGovernance.json +3 -3
- package/artifacts/BridgeGovernanceParameters.json +2 -2
- package/artifacts/Deposit.json +2 -2
- package/artifacts/DepositSweep.json +2 -2
- package/artifacts/EcdsaDkgValidator.json +1 -1
- package/artifacts/EcdsaInactivity.json +1 -1
- package/artifacts/EcdsaSortitionPool.json +2 -2
- 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/MaintainerProxy.json +3 -3
- package/artifacts/MovingFunds.json +2 -2
- package/artifacts/NuCypherStakingEscrow.json +1 -1
- package/artifacts/NuCypherToken.json +2 -2
- package/artifacts/RandomBeaconStub.json +1 -1
- package/artifacts/Redemption.json +2 -2
- package/artifacts/ReimbursementPool.json +2 -2
- package/artifacts/Relay.json +4 -4
- package/artifacts/T.json +2 -2
- package/artifacts/TBTC.json +3 -3
- package/artifacts/TBTCToken.json +3 -3
- package/artifacts/TBTCVault.json +9 -9
- 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/WalletRegistry.json +5 -5
- package/artifacts/WalletRegistryGovernance.json +2 -2
- package/artifacts/Wallets.json +2 -2
- package/artifacts/solcInputs/{2463cada7efb9c191b0fd4a22734bbd0.json → ca06d7336565753de6867fd69d3e145d.json} +12 -6
- 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/BridgeGovernance.sol/BridgeGovernance.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/Wallets.sol/Wallets.dbg.json +1 -1
- package/build/contracts/maintainer/MaintainerProxy.sol/MaintainerProxy.dbg.json +1 -1
- package/build/contracts/relay/LightRelay.sol/ILightRelay.dbg.json +4 -0
- package/build/contracts/relay/LightRelay.sol/ILightRelay.json +214 -0
- package/build/contracts/relay/LightRelay.sol/LightRelay.dbg.json +4 -0
- package/build/contracts/relay/LightRelay.sol/LightRelay.json +443 -0
- package/build/contracts/relay/LightRelay.sol/RelayUtils.dbg.json +4 -0
- package/build/contracts/relay/LightRelay.sol/RelayUtils.json +10 -0
- 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/TBTCVault.sol/TBTCVault.dbg.json +1 -1
- package/contracts/relay/LightRelay.sol +606 -0
- package/package.json +1 -1
|
@@ -196,6 +196,12 @@
|
|
|
196
196
|
"contracts/test/TestRelay.sol": {
|
|
197
197
|
"content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.9;\n\nimport {BTCUtils} from \"@keep-network/bitcoin-spv-sol/contracts/BTCUtils.sol\";\n\nimport \"../bridge/Bridge.sol\";\n\ncontract TestRelay is IRelay {\n using BTCUtils for bytes;\n using BTCUtils for uint256;\n\n uint256 private currentEpochDifficulty;\n uint256 private prevEpochDifficulty;\n\n function setCurrentEpochDifficulty(uint256 _difficulty) external {\n currentEpochDifficulty = _difficulty;\n }\n\n function setPrevEpochDifficulty(uint256 _difficulty) external {\n prevEpochDifficulty = _difficulty;\n }\n\n function setCurrentEpochDifficultyFromHeaders(bytes memory bitcoinHeaders)\n external\n {\n uint256 firstHeaderDiff = bitcoinHeaders\n .extractTarget()\n .calculateDifficulty();\n\n currentEpochDifficulty = firstHeaderDiff;\n }\n\n function setPrevEpochDifficultyFromHeaders(bytes memory bitcoinHeaders)\n external\n {\n uint256 firstHeaderDiff = bitcoinHeaders\n .extractTarget()\n .calculateDifficulty();\n\n prevEpochDifficulty = firstHeaderDiff;\n }\n\n function getCurrentEpochDifficulty()\n external\n view\n override\n returns (uint256)\n {\n return currentEpochDifficulty;\n }\n\n function getPrevEpochDifficulty() external view override returns (uint256) {\n return prevEpochDifficulty;\n }\n}\n"
|
|
198
198
|
},
|
|
199
|
+
"contracts/relay/LightRelay.sol": {
|
|
200
|
+
"content": "// SPDX-License-Identifier: MIT\n\n// ██████████████ ▐████▌ ██████████████\n// ██████████████ ▐████▌ ██████████████\n// ▐████▌ ▐████▌\n// ▐████▌ ▐████▌\n// ██████████████ ▐████▌ ██████████████\n// ██████████████ ▐████▌ ██████████████\n// ▐████▌ ▐████▌\n// ▐████▌ ▐████▌\n// ▐████▌ ▐████▌\n// ▐████▌ ▐████▌\n// ▐████▌ ▐████▌\n// ▐████▌ ▐████▌\n\npragma solidity ^0.8.9;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\nimport {BytesLib} from \"@keep-network/bitcoin-spv-sol/contracts/BytesLib.sol\";\nimport {BTCUtils} from \"@keep-network/bitcoin-spv-sol/contracts/BTCUtils.sol\";\nimport {ValidateSPV} from \"@keep-network/bitcoin-spv-sol/contracts/ValidateSPV.sol\";\n\nimport \"../bridge/IRelay.sol\";\n\nstruct Epoch {\n uint32 timestamp;\n // By definition, bitcoin targets have at least 32 leading zero bits.\n // Thus we can only store the bits that aren't guaranteed to be 0.\n uint224 target;\n}\n\ninterface ILightRelay is IRelay {\n event Genesis(uint256 blockHeight);\n event Retarget(uint256 oldDifficulty, uint256 newDifficulty);\n event ProofLengthChanged(uint256 newLength);\n event AuthorizationRequirementChanged(bool newStatus);\n event SubmitterAuthorized(address submitter);\n event SubmitterDeauthorized(address submitter);\n\n function retarget(bytes memory headers) external;\n\n function validateChain(bytes memory headers)\n external\n view\n returns (uint256 startingHeaderTimestamp, uint256 headerCount);\n\n function getBlockDifficulty(uint256 blockNumber)\n external\n view\n returns (uint256);\n\n function getEpochDifficulty(uint256 epochNumber)\n external\n view\n returns (uint256);\n\n function getRelayRange()\n external\n view\n returns (uint256 relayGenesis, uint256 currentEpochEnd);\n}\n\nlibrary RelayUtils {\n using BytesLib for bytes;\n\n /// @notice Extract the timestamp of the header at the given position.\n /// @param headers Byte array containing the header of interest.\n /// @param at The start of the header in the array.\n /// @return The timestamp of the header.\n /// @dev Assumes that the specified position contains a valid header.\n /// Performs no validation whatsoever.\n function extractTimestampAt(bytes memory headers, uint256 at)\n internal\n pure\n returns (uint32)\n {\n return BTCUtils.reverseUint32(uint32(headers.slice4(68 + at)));\n }\n}\n\n/// @dev THE RELAY MUST NOT BE USED BEFORE GENESIS AND AT LEAST ONE RETARGET.\ncontract LightRelay is Ownable, ILightRelay {\n using BytesLib for bytes;\n using BTCUtils for bytes;\n using ValidateSPV for bytes;\n using RelayUtils for bytes;\n\n bool public ready;\n // Whether the relay requires the address submitting a retarget to be\n // authorised in advance by governance.\n bool public authorizationRequired;\n // Number of blocks required for each side of a retarget proof:\n // a retarget must provide `proofLength` blocks before the retarget\n // and `proofLength` blocks after it.\n // Governable\n // Should be set to a fairly high number (e.g. 20-50) in production.\n uint64 public proofLength;\n // The number of the first epoch recorded by the relay.\n // This should equal the height of the block starting the genesis epoch,\n // divided by 2016, but this is not enforced as the relay has no\n // information about block numbers.\n uint64 public genesisEpoch;\n // The number of the latest epoch whose difficulty is proven to the relay.\n // If the genesis epoch's number is set correctly, and retargets along the\n // way have been legitimate, this equals the height of the block starting\n // the most recent epoch, divided by 2016.\n uint64 public currentEpoch;\n\n uint256 internal currentEpochDifficulty;\n uint256 internal prevEpochDifficulty;\n\n // Each epoch from genesis to the current one, keyed by their numbers.\n mapping(uint256 => Epoch) internal epochs;\n\n mapping(address => bool) public isAuthorized;\n\n modifier relayActive() {\n require(ready, \"Relay is not ready for use\");\n _;\n }\n\n /// @notice Establish a starting point for the relay by providing the\n /// target, timestamp and blockheight of the first block of the relay\n /// genesis epoch.\n /// @param genesisHeader The first block header of the genesis epoch.\n /// @param genesisHeight The block number of the first block of the epoch.\n /// @param genesisProofLength The number of blocks required to accept a\n /// proof.\n /// @dev If the relay is used by querying the current and previous epoch\n /// difficulty, at least one retarget needs to be provided after genesis;\n /// otherwise the prevEpochDifficulty will be uninitialised and zero.\n function genesis(\n bytes calldata genesisHeader,\n uint256 genesisHeight,\n uint64 genesisProofLength\n ) external onlyOwner {\n require(!ready, \"Genesis already performed\");\n\n require(genesisHeader.length == 80, \"Invalid genesis header length\");\n\n require(\n genesisHeight % 2016 == 0,\n \"Invalid height of relay genesis block\"\n );\n\n require(genesisProofLength < 2016, \"Proof length excessive\");\n require(genesisProofLength > 0, \"Proof length may not be zero\");\n\n genesisEpoch = uint64(genesisHeight / 2016);\n currentEpoch = genesisEpoch;\n uint256 genesisTarget = genesisHeader.extractTarget();\n uint256 genesisTimestamp = genesisHeader.extractTimestamp();\n epochs[genesisEpoch] = Epoch(\n uint32(genesisTimestamp),\n uint224(genesisTarget)\n );\n proofLength = genesisProofLength;\n currentEpochDifficulty = BTCUtils.calculateDifficulty(genesisTarget);\n ready = true;\n\n emit Genesis(genesisHeight);\n }\n\n /// @notice Set the number of blocks required to accept a header chain.\n /// @param newLength The required number of blocks. Must be less than 2016.\n /// @dev For production, a high number (e.g. 20-50) is recommended.\n /// Small numbers are accepted but should only be used for testing.\n function setProofLength(uint64 newLength) external relayActive onlyOwner {\n require(newLength < 2016, \"Proof length excessive\");\n require(newLength > 0, \"Proof length may not be zero\");\n require(newLength != proofLength, \"Proof length unchanged\");\n proofLength = newLength;\n emit ProofLengthChanged(newLength);\n }\n\n /// @notice Set whether the relay requires retarget submitters to be\n /// pre-authorised by governance.\n /// @param status True if authorisation is to be required, false if not.\n function setAuthorizationStatus(bool status) external onlyOwner {\n authorizationRequired = status;\n emit AuthorizationRequirementChanged(status);\n }\n\n /// @notice Authorise the given address to submit retarget proofs.\n /// @param submitter The address to be authorised.\n function authorize(address submitter) external onlyOwner {\n isAuthorized[submitter] = true;\n emit SubmitterAuthorized(submitter);\n }\n\n /// @notice Rescind the authorisation of the submitter to retarget.\n /// @param submitter The address to be deauthorised.\n function deauthorize(address submitter) external onlyOwner {\n isAuthorized[submitter] = false;\n emit SubmitterDeauthorized(submitter);\n }\n\n /// @notice Add a new epoch to the relay by providing a proof\n /// of the difficulty before and after the retarget.\n /// @param headers A chain of headers including the last X blocks before\n /// the retarget, followed by the first X blocks after the retarget,\n /// where X equals the current proof length.\n /// @dev Checks that the first X blocks are valid in the most recent epoch,\n /// that the difficulty of the new epoch is calculated correctly according\n /// to the block timestamps, and that the next X blocks would be valid in\n /// the new epoch.\n /// We have no information of block heights, so we cannot enforce that\n /// retargets only happen every 2016 blocks; instead, we assume that this\n /// is the case if a valid proof of work is provided.\n /// It is possible to cheat the relay by providing X blocks from earlier in\n /// the most recent epoch, and then mining X new blocks after them.\n /// However, each of these malicious blocks would have to be mined to a\n /// higher difficulty than the legitimate ones.\n /// Alternatively, if the retarget has not been performed yet, one could\n /// first mine X blocks in the old difficulty with timestamps set far in\n /// the future, and then another X blocks at a greatly reduced difficulty.\n /// In either case, cheating the realy requires more work than mining X\n /// legitimate blocks.\n /// Only the most recent epoch is vulnerable to these attacks; once a\n /// retarget has been proven to the relay, the epoch is immutable even if a\n /// contradictory proof were to be presented later.\n function retarget(bytes memory headers) external relayActive {\n if (authorizationRequired) {\n require(isAuthorized[msg.sender], \"Submitter unauthorized\");\n }\n\n require(\n // Require proofLength headers on both sides of the retarget\n headers.length == (proofLength * 2 * 80),\n \"Invalid header length\"\n );\n\n Epoch storage latest = epochs[currentEpoch];\n\n uint256 oldTarget = latest.target;\n\n bytes32 previousHeaderDigest = bytes32(0);\n\n // Validate old chain\n for (uint256 i = 0; i < proofLength; i++) {\n (\n bytes32 currentDigest,\n uint256 currentHeaderTarget\n ) = validateHeader(headers, i * 80, previousHeaderDigest);\n\n require(\n currentHeaderTarget == oldTarget,\n \"Invalid target in pre-retarget headers\"\n );\n\n previousHeaderDigest = currentDigest;\n }\n\n // get timestamp of retarget block\n uint256 epochEndTimestamp = headers.extractTimestampAt(\n (proofLength - 1) * 80\n );\n\n // An attacker could produce blocks with timestamps in the future,\n // in an attempt to reduce the difficulty after the retarget\n // to make mining the second part of the retarget proof easier.\n // In particular, the attacker could reuse all but one block\n // from the legitimate chain, and only mine the last block.\n // To hinder this, require that the epoch end timestamp does not\n // exceed the ethereum timestamp.\n // NOTE: both are unix seconds, so this comparison should be valid.\n require(\n /* solhint-disable-next-line not-rely-on-time */\n epochEndTimestamp < block.timestamp,\n \"Epoch cannot end in the future\"\n );\n\n // Expected target is the full-length target\n uint256 expectedTarget = BTCUtils.retargetAlgorithm(\n oldTarget,\n latest.timestamp,\n epochEndTimestamp\n );\n\n // Mined target is the header-encoded target\n uint256 minedTarget = 0;\n\n uint256 epochStartTimestamp = headers.extractTimestampAt(\n proofLength * 80\n );\n\n // validate new chain\n for (uint256 j = proofLength; j < proofLength * 2; j++) {\n (\n bytes32 _currentDigest,\n uint256 _currentHeaderTarget\n ) = validateHeader(headers, j * 80, previousHeaderDigest);\n\n if (minedTarget == 0) {\n // The new target has not been set, so check its correctness\n minedTarget = _currentHeaderTarget;\n require(\n // Although the target is a 256-bit number, there are only 32 bits of\n // space in the Bitcoin header. Because of that, the version stored in\n // the header is a less-precise representation of the actual target\n // using base-256 version of scientific notation.\n //\n // The 256-bit unsigned integer returned from BTCUtils.retargetAlgorithm\n // is the precise target value.\n // The 256-bit unsigned integer returned from validateHeader is the less\n // precise target value because it was read from 32 bits of space of\n // Bitcoin block header.\n //\n // We can't compare the precise and less precise representations together\n // so we first mask them to obtain the less precise version:\n // (full & truncated) == truncated\n _currentHeaderTarget ==\n (expectedTarget & _currentHeaderTarget),\n \"Invalid target in new epoch\"\n );\n } else {\n // The new target has been set, so remaining targets should match.\n require(\n _currentHeaderTarget == minedTarget,\n \"Unexpected target change after retarget\"\n );\n }\n\n previousHeaderDigest = _currentDigest;\n }\n\n currentEpoch = currentEpoch + 1;\n\n epochs[currentEpoch] = Epoch(\n uint32(epochStartTimestamp),\n uint224(minedTarget)\n );\n\n uint256 oldDifficulty = currentEpochDifficulty;\n uint256 newDifficulty = BTCUtils.calculateDifficulty(minedTarget);\n\n prevEpochDifficulty = oldDifficulty;\n currentEpochDifficulty = newDifficulty;\n\n emit Retarget(oldDifficulty, newDifficulty);\n }\n\n /// @notice Check whether a given chain of headers should be accepted as\n /// valid within the rules of the relay.\n /// If the validation fails, this function throws an exception.\n /// @param headers A chain of 2 to 2015 bitcoin headers.\n /// @return startingHeaderTimestamp The timestamp of the first header.\n /// @return headerCount The number of headers.\n /// @dev A chain of headers is accepted as valid if:\n /// - Its length is between 2 and 2015 headers.\n /// - Headers in the chain are sequential and refer to previous digests.\n /// - Each header is mined with the correct amount of work.\n /// - The difficulty in each header matches an epoch of the relay,\n /// as determined by the headers' timestamps. The headers must be between\n /// the genesis epoch and the latest proven epoch (inclusive).\n /// If the chain contains a retarget, it is accepted if the retarget has\n /// already been proven to the relay.\n /// If the chain contains blocks of an epoch that has not been proven to\n /// the relay (after a retarget within the header chain, or when the entire\n /// chain falls within an epoch that has not been proven yet), it will be\n /// rejected.\n /// One exception to this is when two subsequent epochs have exactly the\n /// same difficulty; headers from the latter epoch will be accepted if the\n /// previous epoch has been proven to the relay.\n /// This is because it is not possible to distinguish such headers from\n /// headers of the previous epoch.\n ///\n /// If the difficulty increases significantly between relay genesis and the\n /// present, creating fraudulent proofs for earlier epochs becomes easier.\n /// Users of the relay should check the timestamps of valid headers and\n /// only accept appropriately recent ones.\n function validateChain(bytes memory headers)\n external\n view\n returns (uint256 startingHeaderTimestamp, uint256 headerCount)\n {\n require(headers.length % 80 == 0, \"Invalid header length\");\n\n headerCount = headers.length / 80;\n\n require(\n headerCount > 1 && headerCount < 2016,\n \"Invalid number of headers\"\n );\n\n startingHeaderTimestamp = headers.extractTimestamp();\n\n // Short-circuit the first header's validation.\n // We validate the header here to get the target which is needed to\n // precisely identify the epoch.\n (\n bytes32 previousHeaderDigest,\n uint256 currentHeaderTarget\n ) = validateHeader(headers, 0, bytes32(0));\n\n Epoch memory nullEpoch = Epoch(0, 0);\n\n uint256 startingEpochNumber = currentEpoch;\n Epoch memory startingEpoch = epochs[startingEpochNumber];\n Epoch memory nextEpoch = nullEpoch;\n\n // Find the correct epoch for the given chain\n // Fastest with recent epochs, but able to handle anything after genesis\n //\n // The rules for bitcoin timestamps are:\n // - must be greater than the median of the last 11 blocks' timestamps\n // - must be less than the network-adjusted time +2 hours\n //\n // Because of this, the timestamp of a header may be smaller than the\n // starting time, or greater than the ending time of its epoch.\n // However, a valid timestamp is guaranteed to fall within the window\n // formed by the epochs immediately before and after its timestamp.\n // We can identify cases like these by comparing the targets.\n while (startingHeaderTimestamp < startingEpoch.timestamp) {\n startingEpochNumber -= 1;\n nextEpoch = startingEpoch;\n startingEpoch = epochs[startingEpochNumber];\n }\n\n // We have identified the centre of the window,\n // by reaching the most recent epoch whose starting timestamp\n // or reached before the genesis where epoch slots are empty.\n // Therefore check that the timestamp is nonzero.\n require(\n startingEpoch.timestamp > 0,\n \"Cannot validate chains before relay genesis\"\n );\n\n // The targets don't match. This could be because the block is invalid,\n // or it could be because of timestamp inaccuracy.\n // To cover the latter case, check adjacent epochs.\n if (currentHeaderTarget != startingEpoch.target) {\n // The target matches the next epoch.\n // This means we are right at the beginning of the next epoch,\n // and retargets during the chain should not be possible.\n if (currentHeaderTarget == nextEpoch.target) {\n startingEpoch = nextEpoch;\n nextEpoch = nullEpoch;\n }\n // The target doesn't match the next epoch.\n // Therefore the only valid epoch is the previous one.\n // Because the timestamp can't be more than 2 hours into the future\n // we must be right near the end of the epoch,\n // so a retarget is possible.\n else {\n startingEpochNumber -= 1;\n nextEpoch = startingEpoch;\n startingEpoch = epochs[startingEpochNumber];\n\n // We have failed to find a match,\n // therefore the target has to be invalid.\n require(\n currentHeaderTarget == startingEpoch.target,\n \"Invalid target in header chain\"\n );\n }\n }\n\n // We've found the correct epoch for the first header.\n // Validate the rest.\n for (uint256 i = 1; i < headerCount; i++) {\n bytes32 currentDigest;\n (currentDigest, currentHeaderTarget) = validateHeader(\n headers,\n i * 80,\n previousHeaderDigest\n );\n\n // If the header's target does not match the expected target,\n // check if a retarget is possible.\n //\n // If next epoch timestamp exists, a valid retarget is possible\n // (if next epoch timestamp doesn't exist, either a retarget has\n // already happened in this chain, the relay needs a retarget\n // before this chain can be validated, or a retarget is not allowed\n // because we know the headers are within a timestamp irregularity\n // of the previous retarget).\n //\n // In this case the target must match the next epoch's target,\n // and the header's timestamp must match the epoch's start.\n if (currentHeaderTarget != startingEpoch.target) {\n uint256 currentHeaderTimestamp = headers.extractTimestampAt(\n i * 80\n );\n\n require(\n nextEpoch.timestamp != 0 &&\n currentHeaderTarget == nextEpoch.target &&\n currentHeaderTimestamp == nextEpoch.timestamp,\n \"Invalid target in header chain\"\n );\n\n startingEpoch = nextEpoch;\n nextEpoch = nullEpoch;\n }\n\n previousHeaderDigest = currentDigest;\n }\n\n return (startingHeaderTimestamp, headerCount);\n }\n\n /// @notice Get the difficulty of the specified block.\n /// @param blockNumber The number of the block. Must fall within the relay\n /// range (at or after the relay genesis, and at or before the end of the\n /// most recent epoch proven to the relay).\n /// @return The difficulty of the epoch.\n function getBlockDifficulty(uint256 blockNumber)\n external\n view\n returns (uint256)\n {\n return getEpochDifficulty(blockNumber / 2016);\n }\n\n /// @notice Get the range of blocks the relay can accept proofs for.\n /// @dev Assumes that the genesis has been set correctly.\n /// Additionally, if the next epoch after the current one has the exact\n /// same difficulty, headers for it can be validated as well.\n /// This function should be used for informative purposes,\n /// e.g. to determine whether a retarget must be provided before submitting\n /// a header chain for validation.\n /// @return relayGenesis The height of the earliest block that can be\n /// included in header chains for the relay to validate.\n /// @return currentEpochEnd The height of the last block that can be\n /// included in header chains for the relay to validate.\n function getRelayRange()\n external\n view\n returns (uint256 relayGenesis, uint256 currentEpochEnd)\n {\n relayGenesis = genesisEpoch * 2016;\n currentEpochEnd = (currentEpoch * 2016) + 2015;\n }\n\n /// @notice Returns the difficulty of the current epoch.\n /// @dev returns 0 if the relay is not ready.\n /// @return The difficulty of the current epoch.\n function getCurrentEpochDifficulty() external view returns (uint256) {\n return currentEpochDifficulty;\n }\n\n /// @notice Returns the difficulty of the previous epoch.\n /// @dev Returns 0 if the relay is not ready or has not had a retarget.\n /// @return The difficulty of the previous epoch.\n function getPrevEpochDifficulty() external view returns (uint256) {\n return prevEpochDifficulty;\n }\n\n function getCurrentAndPrevEpochDifficulty()\n external\n view\n returns (uint256 current, uint256 previous)\n {\n return (currentEpochDifficulty, prevEpochDifficulty);\n }\n\n /// @notice Get the difficulty of the specified epoch.\n /// @param epochNumber The number of the epoch (the height of the first\n /// block of the epoch, divided by 2016). Must fall within the relay range.\n /// @return The difficulty of the epoch.\n function getEpochDifficulty(uint256 epochNumber)\n public\n view\n returns (uint256)\n {\n require(epochNumber >= genesisEpoch, \"Epoch is before relay genesis\");\n require(\n epochNumber <= currentEpoch,\n \"Epoch is not proven to the relay yet\"\n );\n return BTCUtils.calculateDifficulty(epochs[epochNumber].target);\n }\n\n /// @notice Check that the specified header forms a correct chain with the\n /// digest of the previous header (if provided), and has sufficient work.\n /// @param headers The byte array containing the header of interest.\n /// @param start The start of the header in the array.\n /// @param prevDigest The digest of the previous header\n /// (optional; providing zeros for the digest skips the check).\n /// @return digest The digest of the current header.\n /// @return target The PoW target of the header.\n /// @dev Throws an exception if the header's chain or PoW are invalid.\n /// Performs no other validation.\n function validateHeader(\n bytes memory headers,\n uint256 start,\n bytes32 prevDigest\n ) internal view returns (bytes32 digest, uint256 target) {\n // If previous block digest has been provided, require that it matches\n if (prevDigest != bytes32(0)) {\n require(\n headers.validateHeaderPrevHash(start, prevDigest),\n \"Invalid chain\"\n );\n }\n\n // Require that the header has sufficient work for its stated target\n target = headers.extractTargetAt(start);\n digest = headers.hash256Slice(start, 80);\n require(ValidateSPV.validateHeaderWork(digest, target), \"Invalid work\");\n\n return (digest, target);\n }\n}\n"
|
|
201
|
+
},
|
|
202
|
+
"contracts/test/RelayStub.sol": {
|
|
203
|
+
"content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.9;\n\nimport \"../relay/LightRelay.sol\";\n\ncontract RelayStub is LightRelay {\n // Gas-reporting version of validateChain\n function validateChainGasReport(bytes memory headers)\n external\n returns (uint256, uint256)\n {\n return this.validateChain(headers);\n }\n}\n"
|
|
204
|
+
},
|
|
199
205
|
"contracts/test/BridgeStub.sol": {
|
|
200
206
|
"content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.9;\n\nimport \"../bridge/BitcoinTx.sol\";\nimport \"../bridge/Bridge.sol\";\nimport \"../bridge/MovingFunds.sol\";\nimport \"../bridge/Wallets.sol\";\n\ncontract BridgeStub is Bridge {\n function setSweptDeposits(BitcoinTx.UTXO[] calldata utxos) external {\n for (uint256 i = 0; i < utxos.length; i++) {\n uint256 utxoKey = uint256(\n keccak256(\n abi.encodePacked(utxos[i].txHash, utxos[i].txOutputIndex)\n )\n );\n self.deposits[utxoKey].sweptAt = 1641650400;\n }\n }\n\n function setSpentMainUtxos(BitcoinTx.UTXO[] calldata utxos) external {\n for (uint256 i = 0; i < utxos.length; i++) {\n uint256 utxoKey = uint256(\n keccak256(\n abi.encodePacked(utxos[i].txHash, utxos[i].txOutputIndex)\n )\n );\n self.spentMainUTXOs[utxoKey] = true;\n }\n }\n\n function setProcessedMovedFundsSweepRequests(\n BitcoinTx.UTXO[] calldata utxos\n ) external {\n for (uint256 i = 0; i < utxos.length; i++) {\n uint256 utxoKey = uint256(\n keccak256(\n abi.encodePacked(utxos[i].txHash, utxos[i].txOutputIndex)\n )\n );\n self.movedFundsSweepRequests[utxoKey].state = MovingFunds\n .MovedFundsSweepRequestState\n .Processed;\n }\n }\n\n function setActiveWallet(bytes20 activeWalletPubKeyHash) external {\n self.activeWalletPubKeyHash = activeWalletPubKeyHash;\n }\n\n function setWalletMainUtxo(\n bytes20 walletPubKeyHash,\n BitcoinTx.UTXO calldata utxo\n ) external {\n self.registeredWallets[walletPubKeyHash].mainUtxoHash = keccak256(\n abi.encodePacked(\n utxo.txHash,\n utxo.txOutputIndex,\n utxo.txOutputValue\n )\n );\n }\n\n function setWallet(bytes20 walletPubKeyHash, Wallets.Wallet calldata wallet)\n external\n {\n self.registeredWallets[walletPubKeyHash] = wallet;\n\n if (wallet.state == Wallets.WalletState.Live) {\n self.liveWalletsCount++;\n }\n }\n\n function setDepositDustThreshold(uint64 _depositDustThreshold) external {\n self.depositDustThreshold = _depositDustThreshold;\n }\n\n function setDepositTxMaxFee(uint64 _depositTxMaxFee) external {\n self.depositTxMaxFee = _depositTxMaxFee;\n }\n\n function setRedemptionDustThreshold(uint64 _redemptionDustThreshold)\n external\n {\n self.redemptionDustThreshold = _redemptionDustThreshold;\n }\n\n function setRedemptionTxMaxFee(uint64 _redemptionTxMaxFee) external {\n self.redemptionTxMaxFee = _redemptionTxMaxFee;\n }\n\n function setRedemptionTreasuryFeeDivisor(\n uint64 _redemptionTreasuryFeeDivisor\n ) external {\n self.redemptionTreasuryFeeDivisor = _redemptionTreasuryFeeDivisor;\n }\n\n function setMovingFundsTxMaxTotalFee(uint64 _movingFundsTxMaxTotalFee)\n external\n {\n self.movingFundsTxMaxTotalFee = _movingFundsTxMaxTotalFee;\n }\n\n function setPendingMovedFundsSweepRequest(\n bytes20 walletPubKeyHash,\n BitcoinTx.UTXO calldata utxo\n ) external {\n uint256 requestKey = uint256(\n keccak256(abi.encodePacked(utxo.txHash, utxo.txOutputIndex))\n );\n\n self.movedFundsSweepRequests[requestKey] = MovingFunds\n .MovedFundsSweepRequest(\n walletPubKeyHash,\n utxo.txOutputValue,\n /* solhint-disable-next-line not-rely-on-time */\n uint32(block.timestamp),\n MovingFunds.MovedFundsSweepRequestState.Pending\n );\n\n self\n .registeredWallets[walletPubKeyHash]\n .pendingMovedFundsSweepRequestsCount++;\n }\n\n function processPendingMovedFundsSweepRequest(\n bytes20 walletPubKeyHash,\n BitcoinTx.UTXO calldata utxo\n ) external {\n uint256 requestKey = uint256(\n keccak256(abi.encodePacked(utxo.txHash, utxo.txOutputIndex))\n );\n\n MovingFunds.MovedFundsSweepRequest storage request = self\n .movedFundsSweepRequests[requestKey];\n\n require(\n request.state == MovingFunds.MovedFundsSweepRequestState.Pending,\n \"Stub sweep request must be in Pending state\"\n );\n\n request.state = MovingFunds.MovedFundsSweepRequestState.Processed;\n\n self\n .registeredWallets[walletPubKeyHash]\n .pendingMovedFundsSweepRequestsCount--;\n }\n\n function timeoutPendingMovedFundsSweepRequest(\n bytes20 walletPubKeyHash,\n BitcoinTx.UTXO calldata utxo\n ) external {\n uint256 requestKey = uint256(\n keccak256(abi.encodePacked(utxo.txHash, utxo.txOutputIndex))\n );\n\n MovingFunds.MovedFundsSweepRequest storage request = self\n .movedFundsSweepRequests[requestKey];\n\n require(\n request.state == MovingFunds.MovedFundsSweepRequestState.Pending,\n \"Stub sweep request must be in Pending state\"\n );\n\n request.state = MovingFunds.MovedFundsSweepRequestState.TimedOut;\n\n self\n .registeredWallets[walletPubKeyHash]\n .pendingMovedFundsSweepRequestsCount--;\n }\n\n function setMovedFundsSweepTxMaxTotalFee(\n uint64 _movedFundsSweepTxMaxTotalFee\n ) external {\n self.movedFundsSweepTxMaxTotalFee = _movedFundsSweepTxMaxTotalFee;\n }\n}\n"
|
|
201
207
|
},
|
|
@@ -247,12 +253,6 @@
|
|
|
247
253
|
"@keep-network/ecdsa/contracts/libraries/Wallets.sol": {
|
|
248
254
|
"content": "// SPDX-License-Identifier: MIT\n//\n// ▓▓▌ ▓▓ ▐▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▄\n// ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓\n// ▓▓▓▓▓▓ ▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓ ▐▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓\n// ▓▓▓▓▓▓▄▄▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▄▄▄▄ ▓▓▓▓▓▓▄▄▄▄ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓\n// ▓▓▓▓▓▓▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓\n// ▓▓▓▓▓▓▀▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓▀▀▀▀ ▓▓▓▓▓▓▀▀▀▀ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▀\n// ▓▓▓▓▓▓ ▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌\n// ▓▓▓▓▓▓▓▓▓▓ █▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓\n// ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓\n//\n// Trust math, not hardware.\n\npragma solidity ^0.8.9;\n\nlibrary Wallets {\n struct Wallet {\n // Keccak256 hash of group members identifiers array. Group members do not\n // include operators selected by the sortition pool that misbehaved during DKG.\n bytes32 membersIdsHash;\n // Uncompressed ECDSA public key stored as X and Y coordinates (32 bytes each).\n bytes32 publicKeyX;\n bytes32 publicKeyY;\n // This struct doesn't contain `__gap` property as the structure is stored\n // in a mapping, mappings store values in different slots and they are\n // not contiguous with other values.\n }\n\n struct Data {\n // Mapping of keccak256 hashes of wallet public keys to wallet details.\n // Hash of public key is considered an unique wallet identifier.\n mapping(bytes32 => Wallet) registry;\n // Reserved storage space in case we need to add more variables.\n // See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n // slither-disable-next-line unused-state\n uint256[49] __gap;\n }\n\n /// @notice Registers a new wallet.\n /// @dev Uses a public key hash as a unique identifier of a wallet.\n /// @param membersIdsHash Keccak256 hash of group members identifiers array\n /// @param publicKey Uncompressed public key\n /// @return walletID Wallet's ID\n /// @return publicKeyX Wallet's public key's X coordinate\n /// @return publicKeyY Wallet's public key's Y coordinate\n function addWallet(\n Data storage self,\n bytes32 membersIdsHash,\n bytes calldata publicKey\n )\n internal\n returns (\n bytes32 walletID,\n bytes32 publicKeyX,\n bytes32 publicKeyY\n )\n {\n walletID = keccak256(publicKey);\n\n require(\n self.registry[walletID].publicKeyX == bytes32(0),\n \"Wallet with the given public key already exists\"\n );\n require(publicKey.length == 64, \"Invalid length of the public key\");\n\n publicKeyX = bytes32(publicKey[:32]);\n publicKeyY = bytes32(publicKey[32:]);\n\n self.registry[walletID].membersIdsHash = membersIdsHash;\n self.registry[walletID].publicKeyX = publicKeyX;\n self.registry[walletID].publicKeyY = publicKeyY;\n }\n\n /// @notice Deletes wallet with the given ID from the registry. Reverts\n /// if wallet with the given ID has not been registered or if it\n /// has already been closed.\n function deleteWallet(Data storage self, bytes32 walletID) internal {\n require(\n isWalletRegistered(self, walletID),\n \"Wallet with the given ID has not been registered\"\n );\n\n delete self.registry[walletID];\n }\n\n /// @notice Checks if a wallet with the given ID is registered.\n /// @param walletID Wallet's ID\n /// @return True if a wallet is registered, false otherwise\n function isWalletRegistered(Data storage self, bytes32 walletID)\n internal\n view\n returns (bool)\n {\n return self.registry[walletID].publicKeyX != bytes32(0);\n }\n\n /// @notice Returns Keccak256 hash of the wallet signing group members\n /// identifiers array. Group members do not include operators\n /// selected by the sortition pool that misbehaved during DKG.\n /// Reverts if wallet with the given ID is not registered.\n /// @param walletID ID of the wallet\n /// @return Wallet signing group members hash\n function getWalletMembersIdsHash(Data storage self, bytes32 walletID)\n internal\n view\n returns (bytes32)\n {\n require(\n isWalletRegistered(self, walletID),\n \"Wallet with the given ID has not been registered\"\n );\n\n return self.registry[walletID].membersIdsHash;\n }\n\n /// @notice Gets public key of a wallet with the given wallet ID.\n /// The public key is returned as X and Y coordinates.\n /// Reverts if wallet with the given ID is not registered.\n /// @param walletID ID of the wallet\n /// @return x Public key X coordinate\n /// @return y Public key Y coordinate\n function getWalletPublicKeyCoordinates(Data storage self, bytes32 walletID)\n internal\n view\n returns (bytes32 x, bytes32 y)\n {\n require(\n isWalletRegistered(self, walletID),\n \"Wallet with the given ID has not been registered\"\n );\n\n Wallet storage wallet = self.registry[walletID];\n\n return (wallet.publicKeyX, wallet.publicKeyY);\n }\n\n /// @notice Gets public key of a wallet with the given wallet ID.\n /// The public key is returned in an uncompressed format as a 64-byte\n /// concatenation of X and Y coordinates.\n /// Reverts if wallet with the given ID is not registered.\n /// @param walletID ID of the wallet\n /// @return Uncompressed public key of the wallet\n function getWalletPublicKey(Data storage self, bytes32 walletID)\n internal\n view\n returns (bytes memory)\n {\n (bytes32 x, bytes32 y) = getWalletPublicKeyCoordinates(self, walletID);\n return bytes.concat(x, y);\n }\n}\n"
|
|
249
255
|
},
|
|
250
|
-
"contracts/test/HeartbeatStub.sol": {
|
|
251
|
-
"content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.9;\n\nimport \"../bridge/Heartbeat.sol\";\n\n/// @dev This is a contract implemented to test Heartbeat library directly.\ncontract HeartbeatStub {\n function isValidHeartbeatMessage(bytes calldata message)\n public\n pure\n returns (bool)\n {\n return Heartbeat.isValidHeartbeatMessage(message);\n }\n}\n"
|
|
252
|
-
},
|
|
253
|
-
"contracts/test/TestEcdsaLib.sol": {
|
|
254
|
-
"content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.9;\n\nimport \"../bridge/EcdsaLib.sol\";\n\n// TODO: Rename to EcdsLibStub\n/// @dev This is a contract implemented to test EcdsaLib library directly.\ncontract TestEcdsaLib {\n function compressPublicKey(bytes32 x, bytes32 y)\n public\n pure\n returns (bytes memory)\n {\n return EcdsaLib.compressPublicKey(x, y);\n }\n}\n"
|
|
255
|
-
},
|
|
256
256
|
"@keep-network/ecdsa/contracts/libraries/EcdsaAuthorization.sol": {
|
|
257
257
|
"content": "// SPDX-License-Identifier: MIT\n//\n// ▓▓▌ ▓▓ ▐▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▄\n// ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▌▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓\n// ▓▓▓▓▓▓ ▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓ ▐▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓\n// ▓▓▓▓▓▓▄▄▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▄▄▄▄ ▓▓▓▓▓▓▄▄▄▄ ▐▓▓▓▓▓▌ ▐▓▓▓▓▓▓\n// ▓▓▓▓▓▓▓▓▓▓▓▓▓▀ ▐▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓\n// ▓▓▓▓▓▓▀▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓▀▀▀▀ ▓▓▓▓▓▓▀▀▀▀ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▀\n// ▓▓▓▓▓▓ ▀▓▓▓▓▓▓▄ ▐▓▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▐▓▓▓▓▓▌\n// ▓▓▓▓▓▓▓▓▓▓ █▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓\n// ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▐▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓\n//\n//\n\npragma solidity ^0.8.9;\n\nimport \"@keep-network/sortition-pools/contracts/SortitionPool.sol\";\nimport \"@threshold-network/solidity-contracts/contracts/staking/IStaking.sol\";\n\n/// @notice Library managing the state of stake authorizations for ECDSA\n/// operator contract and the presence of operators in the sortition\n/// pool based on the stake authorized for them.\nlibrary EcdsaAuthorization {\n struct Parameters {\n // The minimum authorization required by ECDSA application so that\n // operator can join the sortition pool and do the work.\n uint96 minimumAuthorization;\n // Authorization decrease delay in seconds between the time\n // authorization decrease is requested and the time the authorization\n // decrease can be approved. It is always the same value, no matter if\n // authorization decrease amount is small, significant, or if it is\n // a decrease to zero.\n uint64 authorizationDecreaseDelay;\n // The time period before the authorization decrease delay end,\n // during which the authorization decrease request can be overwritten.\n //\n // When the request is overwritten, the authorization decrease delay is\n // reset.\n //\n // For example, if `authorizationDecraseChangePeriod` is set to 4\n // days, `authorizationDecreaseDelay` is set to 14 days, and someone\n // requested authorization decrease, it means they can not\n // request another decrease for the first 10 days. After 10 days pass,\n // they can request again and overwrite the previous authorization\n // decrease request. The delay time will reset for them and they\n // will have to wait another 10 days to alter it and 14 days to\n // approve it.\n //\n // This value protects against malicious operators who manipulate\n // their weight by overwriting authorization decrease request, and\n // lowering or increasing their eligible stake this way.\n //\n // If set to a value equal to `authorizationDecreaseDelay, it means\n // that authorization decrease request can be always overwritten.\n // If set to zero, it means authorization decrease request can not be\n // overwritten until the delay end, and one needs to wait for the entire\n // authorization decrease delay to approve their decrease and request\n // for another one or to overwrite the pending one.\n //\n // (1) authorization decrease requested timestamp\n // (2) from this moment authorization decrease request can be\n // overwritten\n // (3) from this moment authorization decrease request can be\n // approved, assuming it was NOT overwritten in (2)\n //\n // (1) (2) (3)\n // --x------------------------------x--------------------------x---->\n // | \\________________________/\n // | authorizationDecreaseChangePeriod\n // \\______________________________________________________/\n // authorizationDecreaseDelay\n //\n uint64 authorizationDecreaseChangePeriod;\n // This struct doesn't contain `__gap` property as the structure is\n // stored inside `Data` struct, that already have a gap that can be used\n // on upgrade.\n }\n\n struct AuthorizationDecrease {\n uint96 decreasingBy; // amount\n uint64 decreasingAt; // timestamp\n }\n\n struct Data {\n Parameters parameters;\n mapping(address => address) stakingProviderToOperator;\n mapping(address => address) operatorToStakingProvider;\n mapping(address => AuthorizationDecrease) pendingDecreases;\n // Reserved storage space in case we need to add more variables.\n // See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n // slither-disable-next-line unused-state\n uint256[46] __gap;\n }\n\n event OperatorRegistered(\n address indexed stakingProvider,\n address indexed operator\n );\n\n event AuthorizationIncreased(\n address indexed stakingProvider,\n address indexed operator,\n uint96 fromAmount,\n uint96 toAmount\n );\n\n event AuthorizationDecreaseRequested(\n address indexed stakingProvider,\n address indexed operator,\n uint96 fromAmount,\n uint96 toAmount,\n uint64 decreasingAt\n );\n\n event AuthorizationDecreaseApproved(address indexed stakingProvider);\n\n event InvoluntaryAuthorizationDecreaseFailed(\n address indexed stakingProvider,\n address indexed operator,\n uint96 fromAmount,\n uint96 toAmount\n );\n\n event OperatorJoinedSortitionPool(\n address indexed stakingProvider,\n address indexed operator\n );\n\n event OperatorStatusUpdated(\n address indexed stakingProvider,\n address indexed operator\n );\n\n /// @notice Sets the minimum authorization for ECDSA application. Without\n /// at least the minimum authorization, staking provider is not\n /// eligible to join and operate in the network.\n function setMinimumAuthorization(\n Data storage self,\n uint96 _minimumAuthorization\n ) internal {\n self.parameters.minimumAuthorization = _minimumAuthorization;\n }\n\n /// @notice Sets the authorization decrease delay. It is the time in seconds\n /// that needs to pass between the time authorization decrease is\n /// requested and the time the authorization decrease can be\n /// approved, no matter the authorization decrease amount.\n function setAuthorizationDecreaseDelay(\n Data storage self,\n uint64 _authorizationDecreaseDelay\n ) internal {\n self\n .parameters\n .authorizationDecreaseDelay = _authorizationDecreaseDelay;\n }\n\n /// @notice Sets the authorization decrease change period. It is the time\n /// period before the authorization decrease delay end,\n /// during which the authorization decrease request can be\n /// overwritten.\n function setAuthorizationDecreaseChangePeriod(\n Data storage self,\n uint64 _authorizationDecreaseChangePeriod\n ) internal {\n self\n .parameters\n .authorizationDecreaseChangePeriod = _authorizationDecreaseChangePeriod;\n }\n\n /// @notice Used by staking provider to set operator address that will\n /// operate ECDSA node. The given staking provider can set operator\n /// address only one time. The operator address can not be changed\n /// and must be unique. Reverts if the operator is already set for\n /// the staking provider or if the operator address is already in\n /// use. Reverts if there is a pending authorization decrease for\n /// the staking provider.\n function registerOperator(Data storage self, address operator) internal {\n address stakingProvider = msg.sender;\n\n require(operator != address(0), \"Operator can not be zero address\");\n require(\n self.stakingProviderToOperator[stakingProvider] == address(0),\n \"Operator already set for the staking provider\"\n );\n require(\n self.operatorToStakingProvider[operator] == address(0),\n \"Operator address already in use\"\n );\n\n // Authorization request for a staking provider who has not yet\n // registered their operator can be approved immediately.\n // We need to make sure that the approval happens before operator\n // is registered to do not let the operator join the sortition pool\n // with an unresolved authorization decrease request that can be\n // approved at any point.\n AuthorizationDecrease storage decrease = self.pendingDecreases[\n stakingProvider\n ];\n require(\n decrease.decreasingAt == 0,\n \"There is a pending authorization decrease request\"\n );\n\n emit OperatorRegistered(stakingProvider, operator);\n\n self.stakingProviderToOperator[stakingProvider] = operator;\n self.operatorToStakingProvider[operator] = stakingProvider;\n }\n\n /// @notice Used by T staking contract to inform the application that the\n /// authorized stake amount for the given staking provider increased.\n ///\n /// Reverts if the authorization amount is below the minimum.\n ///\n /// The function is not updating the sortition pool. Sortition pool\n /// state needs to be updated by the operator with a call to\n /// `joinSortitionPool` or `updateOperatorStatus`.\n ///\n /// @dev Should only be callable by T staking contract.\n function authorizationIncreased(\n Data storage self,\n address stakingProvider,\n uint96 fromAmount,\n uint96 toAmount\n ) internal {\n require(\n toAmount >= self.parameters.minimumAuthorization,\n \"Authorization below the minimum\"\n );\n\n // Note that this function does not require the operator address to be\n // set for the given staking provider. This allows the stake owner\n // who is also an authorizer to increase the authorization before the\n // staking provider sets the operator. This allows delegating stake\n // and increasing authorization immediately one after another without\n // having to wait for the staking provider to do their part.\n\n address operator = self.stakingProviderToOperator[stakingProvider];\n emit AuthorizationIncreased(\n stakingProvider,\n operator,\n fromAmount,\n toAmount\n );\n }\n\n /// @notice Used by T staking contract to inform the application that the\n /// authorization decrease for the given staking provider has been\n /// requested.\n ///\n /// Reverts if the amount after deauthorization would be non-zero\n /// and lower than the minimum authorization.\n ///\n /// Reverts if another authorization decrease request is pending for\n /// the staking provider and not enough time passed since the\n /// original request (see `authorizationDecreaseChangePeriod`).\n ///\n /// If the operator is not known (`registerOperator` was not called)\n /// it lets to `approveAuthorizationDecrease` immediately. If the\n /// operator is known (`registerOperator` was called), the operator\n /// needs to update state of the sortition pool with a call to\n /// `joinSortitionPool` or `updateOperatorStatus`. After the\n /// sortition pool state is in sync, authorization decrease delay\n /// starts.\n ///\n /// After authorization decrease delay passes, authorization\n /// decrease request needs to be approved with a call to\n /// `approveAuthorizationDecrease` function.\n ///\n /// If there is a pending authorization decrease request, it is\n /// overwritten, but only if enough time passed since the original\n /// request. Otherwise, the function reverts.\n ///\n /// @dev Should only be callable by T staking contract.\n function authorizationDecreaseRequested(\n Data storage self,\n address stakingProvider,\n uint96 fromAmount,\n uint96 toAmount\n ) internal {\n require(\n toAmount == 0 || toAmount >= self.parameters.minimumAuthorization,\n \"Authorization amount should be 0 or above the minimum\"\n );\n\n address operator = self.stakingProviderToOperator[stakingProvider];\n\n uint64 decreasingAt;\n\n if (operator == address(0)) {\n // Operator is not known. It means `registerOperator` was not\n // called yet, and there is no chance the operator could\n // call `joinSortitionPool`. We can let to approve authorization\n // decrease immediately because that operator was never in the\n // sortition pool.\n\n // solhint-disable-next-line not-rely-on-time\n decreasingAt = uint64(block.timestamp);\n } else {\n // Operator is known. It means that this operator is or was in\n // the sortition pool. Before authorization decrease delay starts,\n // the operator needs to update the state of the sortition pool\n // with a call to `joinSortitionPool` or `updateOperatorStatus`.\n // For now, we set `decreasingAt` as \"never decreasing\" and let\n // it be updated by `joinSortitionPool` or `updateOperatorStatus`\n // once we know the sortition pool is in sync.\n decreasingAt = type(uint64).max;\n }\n\n uint96 decreasingBy = fromAmount - toAmount;\n\n AuthorizationDecrease storage decreaseRequest = self.pendingDecreases[\n stakingProvider\n ];\n\n uint64 pendingDecreaseAt = decreaseRequest.decreasingAt;\n if (pendingDecreaseAt != 0 && pendingDecreaseAt != type(uint64).max) {\n // If there is already a pending authorization decrease request for\n // this staking provider and that request has been activated\n // (sortition pool was updated), require enough time to pass before\n // it can be overwritten.\n require(\n // solhint-disable-next-line not-rely-on-time\n block.timestamp >=\n pendingDecreaseAt -\n self.parameters.authorizationDecreaseChangePeriod,\n \"Not enough time passed since the original request\"\n );\n }\n\n decreaseRequest.decreasingBy = decreasingBy;\n decreaseRequest.decreasingAt = decreasingAt;\n\n emit AuthorizationDecreaseRequested(\n stakingProvider,\n operator,\n fromAmount,\n toAmount,\n decreasingAt\n );\n }\n\n /// @notice Approves the previously registered authorization decrease\n /// request. Reverts if authorization decrease delay have not passed\n /// yet or if the authorization decrease was not requested for the\n /// given staking provider.\n function approveAuthorizationDecrease(\n Data storage self,\n IStaking tokenStaking,\n address stakingProvider\n ) internal {\n AuthorizationDecrease storage decrease = self.pendingDecreases[\n stakingProvider\n ];\n require(\n decrease.decreasingAt > 0,\n \"Authorization decrease not requested\"\n );\n require(\n decrease.decreasingAt != type(uint64).max,\n \"Authorization decrease request not activated\"\n );\n require(\n // solhint-disable-next-line not-rely-on-time\n block.timestamp >= decrease.decreasingAt,\n \"Authorization decrease delay not passed\"\n );\n\n emit AuthorizationDecreaseApproved(stakingProvider);\n\n // slither-disable-next-line unused-return\n tokenStaking.approveAuthorizationDecrease(stakingProvider);\n delete self.pendingDecreases[stakingProvider];\n }\n\n /// @notice Used by T staking contract to inform the application the\n /// authorization has been decreased for the given staking provider\n /// involuntarily, as a result of slashing.\n ///\n /// If the operator is not known (`registerOperator` was not called)\n /// the function does nothing. The operator was never in a sortition\n /// pool so there is nothing to update.\n ///\n /// If the operator is known, sortition pool is unlocked, and the\n /// operator is in the sortition pool, the sortition pool state is\n /// updated. If the sortition pool is locked, update needs to be\n /// postponed. Every other staker is incentivized to call\n /// `updateOperatorStatus` for the problematic operator to increase\n /// their own rewards in the pool.\n ///\n /// @dev Should only be callable by T staking contract.\n function involuntaryAuthorizationDecrease(\n Data storage self,\n IStaking tokenStaking,\n SortitionPool sortitionPool,\n address stakingProvider,\n uint96 fromAmount,\n uint96 toAmount\n ) internal {\n address operator = self.stakingProviderToOperator[stakingProvider];\n\n if (operator == address(0)) {\n // Operator is not known. It means `registerOperator` was not\n // called yet, and there is no chance the operator could\n // call `joinSortitionPool`. We can just ignore this update because\n // operator was never in the sortition pool.\n return;\n } else {\n // Operator is known. It means that this operator is or was in the\n // sortition pool and the sortition pool may need to be updated.\n //\n // If the sortition pool is not locked and the operator is in the\n // sortition pool, we are updating it.\n //\n // To keep stakes synchronized between applications when staking\n // providers are slashed, without the risk of running out of gas,\n // the staking contract queues up slashings and let users process\n // the transactions. When an application slashes one or more staking\n // providers, it adds them to the slashing queue on the staking\n // contract. A queue entry contains the staking provider’s address\n // and the amount they are due to be slashed.\n //\n // When there is at least one staking provider in the slashing\n // queue, any account can submit a transaction processing one or\n // more staking providers' slashings, and collecting a reward for\n // doing so. A queued slashing is processed by updating the staking\n // provider’s stake to the post-slashing amount, updating authorized\n // amount for each affected application, and notifying all affected\n // applications that the staking provider’s authorized stake has\n // been reduced due to slashing.\n //\n // The entire idea is that the process transaction is expensive\n // because each application needs to be updated, so the reward for\n // the processor is hefty and comes from the slashed tokens.\n // Practically, it means that if the sortition pool is unlocked, and\n // can be updated, it should be updated because we already paid\n // someone for updating it.\n //\n // If the sortition pool is locked, update needs to wait. Other\n // sortition pool members are incentivized to call\n // `updateOperatorStatus` for the problematic operator because they\n // will increase their rewards this way.\n if (sortitionPool.isOperatorInPool(operator)) {\n if (sortitionPool.isLocked()) {\n emit InvoluntaryAuthorizationDecreaseFailed(\n stakingProvider,\n operator,\n fromAmount,\n toAmount\n );\n } else {\n updateOperatorStatus(\n self,\n tokenStaking,\n sortitionPool,\n operator\n );\n }\n }\n }\n }\n\n /// @notice Lets the operator join the sortition pool. The operator address\n /// must be known - before calling this function, it has to be\n /// appointed by the staking provider by calling `registerOperator`.\n /// Also, the operator must have the minimum authorization required\n /// by ECDSA. Function reverts if there is no minimum stake\n /// authorized or if the operator is not known. If there was an\n /// authorization decrease requested, it is activated by starting\n /// the authorization decrease delay.\n function joinSortitionPool(\n Data storage self,\n IStaking tokenStaking,\n SortitionPool sortitionPool\n ) internal {\n address operator = msg.sender;\n\n address stakingProvider = self.operatorToStakingProvider[operator];\n require(stakingProvider != address(0), \"Unknown operator\");\n\n AuthorizationDecrease storage decrease = self.pendingDecreases[\n stakingProvider\n ];\n\n uint96 _eligibleStake = eligibleStake(\n self,\n tokenStaking,\n stakingProvider,\n decrease.decreasingBy\n );\n\n require(_eligibleStake != 0, \"Authorization below the minimum\");\n\n emit OperatorJoinedSortitionPool(stakingProvider, operator);\n\n sortitionPool.insertOperator(operator, _eligibleStake);\n\n // If there is a pending authorization decrease request, activate it.\n // At this point, the sortition pool state is up to date so the\n // authorization decrease delay can start counting.\n if (decrease.decreasingAt == type(uint64).max) {\n decrease.decreasingAt =\n // solhint-disable-next-line not-rely-on-time\n uint64(block.timestamp) +\n self.parameters.authorizationDecreaseDelay;\n }\n }\n\n /// @notice Updates status of the operator in the sortition pool. If there\n /// was an authorization decrease requested, it is activated by\n /// starting the authorization decrease delay.\n /// Function reverts if the operator is not known.\n function updateOperatorStatus(\n Data storage self,\n IStaking tokenStaking,\n SortitionPool sortitionPool,\n address operator\n ) internal {\n address stakingProvider = self.operatorToStakingProvider[operator];\n require(stakingProvider != address(0), \"Unknown operator\");\n\n AuthorizationDecrease storage decrease = self.pendingDecreases[\n stakingProvider\n ];\n\n emit OperatorStatusUpdated(stakingProvider, operator);\n\n if (sortitionPool.isOperatorInPool(operator)) {\n uint96 _eligibleStake = eligibleStake(\n self,\n tokenStaking,\n stakingProvider,\n decrease.decreasingBy\n );\n\n sortitionPool.updateOperatorStatus(operator, _eligibleStake);\n }\n\n // If there is a pending authorization decrease request, activate it.\n // At this point, the sortition pool state is up to date so the\n // authorization decrease delay can start counting.\n if (decrease.decreasingAt == type(uint64).max) {\n decrease.decreasingAt =\n // solhint-disable-next-line not-rely-on-time\n uint64(block.timestamp) +\n self.parameters.authorizationDecreaseDelay;\n }\n }\n\n /// @notice Checks if the operator's authorized stake is in sync with\n /// operator's weight in the sortition pool.\n /// If the operator is not in the sortition pool and their\n /// authorized stake is non-zero, function returns false.\n function isOperatorUpToDate(\n Data storage self,\n IStaking tokenStaking,\n SortitionPool sortitionPool,\n address operator\n ) internal view returns (bool) {\n address stakingProvider = self.operatorToStakingProvider[operator];\n require(stakingProvider != address(0), \"Unknown operator\");\n\n AuthorizationDecrease storage decrease = self.pendingDecreases[\n stakingProvider\n ];\n\n uint96 _eligibleStake = eligibleStake(\n self,\n tokenStaking,\n stakingProvider,\n decrease.decreasingBy\n );\n\n if (!sortitionPool.isOperatorInPool(operator)) {\n return _eligibleStake == 0;\n } else {\n return sortitionPool.isOperatorUpToDate(operator, _eligibleStake);\n }\n }\n\n /// @notice Returns the current value of the staking provider's eligible\n /// stake. Eligible stake is defined as the currently authorized\n /// stake minus the pending authorization decrease. Eligible stake\n /// is what is used for operator's weight in the pool. If the\n /// authorized stake minus the pending authorization decrease is\n /// below the minimum authorization, eligible stake is 0.\n /// @dev This function can be exposed to the public in contrast to the\n /// second variant accepting `decreasingBy` as a parameter.\n function eligibleStake(\n Data storage self,\n IStaking tokenStaking,\n address stakingProvider\n ) internal view returns (uint96) {\n return\n eligibleStake(\n self,\n tokenStaking,\n stakingProvider,\n pendingAuthorizationDecrease(self, stakingProvider)\n );\n }\n\n /// @notice Returns the current value of the staking provider's eligible\n /// stake. Eligible stake is defined as the currently authorized\n /// stake minus the pending authorization decrease. Eligible stake\n /// is what is used for operator's weight in the pool. If the\n /// authorized stake minus the pending authorization decrease is\n /// below the minimum authorization, eligible stake is 0.\n /// @dev This function is not intended to be exposes to the public.\n /// `decreasingBy` must be fetched from `pendingDecreases` mapping and\n /// it is passed as a parameter to optimize gas usage of functions that\n /// call `eligibleStake` and need to use `AuthorizationDecrease`\n /// fetched from `pendingDecreases` for some additional logic.\n function eligibleStake(\n Data storage self,\n IStaking tokenStaking,\n address stakingProvider,\n uint96 decreasingBy\n ) internal view returns (uint96) {\n uint96 authorizedStake = tokenStaking.authorizedStake(\n stakingProvider,\n address(this)\n );\n\n uint96 _eligibleStake = authorizedStake > decreasingBy\n ? authorizedStake - decreasingBy\n : 0;\n\n if (_eligibleStake < self.parameters.minimumAuthorization) {\n return 0;\n } else {\n return _eligibleStake;\n }\n }\n\n /// @notice Returns the amount of stake that is pending authorization\n /// decrease for the given staking provider. If no authorization\n /// decrease has been requested, returns zero.\n function pendingAuthorizationDecrease(\n Data storage self,\n address stakingProvider\n ) internal view returns (uint96) {\n AuthorizationDecrease storage decrease = self.pendingDecreases[\n stakingProvider\n ];\n\n return decrease.decreasingBy;\n }\n\n /// @notice Returns the remaining time in seconds that needs to pass before\n /// the requested authorization decrease can be approved.\n /// If the sortition pool state was not updated yet by the operator\n /// after requesting the authorization decrease, returns\n /// `type(uint64).max`.\n function remainingAuthorizationDecreaseDelay(\n Data storage self,\n address stakingProvider\n ) internal view returns (uint64) {\n AuthorizationDecrease storage decrease = self.pendingDecreases[\n stakingProvider\n ];\n\n if (decrease.decreasingAt == type(uint64).max) {\n return type(uint64).max;\n }\n\n // solhint-disable-next-line not-rely-on-time\n uint64 _now = uint64(block.timestamp);\n return _now > decrease.decreasingAt ? 0 : decrease.decreasingAt - _now;\n }\n}\n"
|
|
258
258
|
},
|
|
@@ -268,6 +268,12 @@
|
|
|
268
268
|
"contracts/bridge/BridgeGovernanceParameters.sol": {
|
|
269
269
|
"content": "// SPDX-License-Identifier: MIT\n\n// ██████████████ ▐████▌ ██████████████\n// ██████████████ ▐████▌ ██████████████\n// ▐████▌ ▐████▌\n// ▐████▌ ▐████▌\n// ██████████████ ▐████▌ ██████████████\n// ██████████████ ▐████▌ ██████████████\n// ▐████▌ ▐████▌\n// ▐████▌ ▐████▌\n// ▐████▌ ▐████▌\n// ▐████▌ ▐████▌\n// ▐████▌ ▐████▌\n// ▐████▌ ▐████▌\n\npragma solidity ^0.8.9;\n\n/// @title Bridge Governance library for storing updatable parameters.\nlibrary BridgeGovernanceParameters {\n struct DepositData {\n uint64 newDepositDustThreshold;\n uint256 depositDustThresholdChangeInitiated;\n uint64 newDepositTreasuryFeeDivisor;\n uint256 depositTreasuryFeeDivisorChangeInitiated;\n uint64 newDepositTxMaxFee;\n uint256 depositTxMaxFeeChangeInitiated;\n }\n\n struct RedemptionData {\n uint64 newRedemptionDustThreshold;\n uint256 redemptionDustThresholdChangeInitiated;\n uint64 newRedemptionTreasuryFeeDivisor;\n uint256 redemptionTreasuryFeeDivisorChangeInitiated;\n uint64 newRedemptionTxMaxFee;\n uint256 redemptionTxMaxFeeChangeInitiated;\n uint32 newRedemptionTimeout;\n uint256 redemptionTimeoutChangeInitiated;\n uint96 newRedemptionTimeoutSlashingAmount;\n uint256 redemptionTimeoutSlashingAmountChangeInitiated;\n uint32 newRedemptionTimeoutNotifierRewardMultiplier;\n uint256 redemptionTimeoutNotifierRewardMultiplierChangeInitiated;\n }\n\n struct MovingFundsData {\n uint64 newMovingFundsTxMaxTotalFee;\n uint256 movingFundsTxMaxTotalFeeChangeInitiated;\n uint64 newMovingFundsDustThreshold;\n uint256 movingFundsDustThresholdChangeInitiated;\n uint32 newMovingFundsTimeoutResetDelay;\n uint256 movingFundsTimeoutResetDelayChangeInitiated;\n uint32 newMovingFundsTimeout;\n uint256 movingFundsTimeoutChangeInitiated;\n uint96 newMovingFundsTimeoutSlashingAmount;\n uint256 movingFundsTimeoutSlashingAmountChangeInitiated;\n uint32 newMovingFundsTimeoutNotifierRewardMultiplier;\n uint256 movingFundsTimeoutNotifierRewardMultiplierChangeInitiated;\n uint64 newMovedFundsSweepTxMaxTotalFee;\n uint256 movedFundsSweepTxMaxTotalFeeChangeInitiated;\n uint32 newMovedFundsSweepTimeout;\n uint256 movedFundsSweepTimeoutChangeInitiated;\n uint96 newMovedFundsSweepTimeoutSlashingAmount;\n uint256 movedFundsSweepTimeoutSlashingAmountChangeInitiated;\n uint32 newMovedFundsSweepTimeoutNotifierRewardMultiplier;\n uint256 movedFundsSweepTimeoutNotifierRewardMultiplierChangeInitiated;\n }\n\n struct WalletData {\n uint32 newWalletCreationPeriod;\n uint256 walletCreationPeriodChangeInitiated;\n uint64 newWalletCreationMinBtcBalance;\n uint256 walletCreationMinBtcBalanceChangeInitiated;\n uint64 newWalletCreationMaxBtcBalance;\n uint256 walletCreationMaxBtcBalanceChangeInitiated;\n uint64 newWalletClosureMinBtcBalance;\n uint256 walletClosureMinBtcBalanceChangeInitiated;\n uint32 newWalletMaxAge;\n uint256 walletMaxAgeChangeInitiated;\n uint64 newWalletMaxBtcTransfer;\n uint256 walletMaxBtcTransferChangeInitiated;\n uint32 newWalletClosingPeriod;\n uint256 walletClosingPeriodChangeInitiated;\n }\n\n struct FraudData {\n uint96 newFraudChallengeDepositAmount;\n uint256 fraudChallengeDepositAmountChangeInitiated;\n uint32 newFraudChallengeDefeatTimeout;\n uint256 fraudChallengeDefeatTimeoutChangeInitiated;\n uint96 newFraudSlashingAmount;\n uint256 fraudSlashingAmountChangeInitiated;\n uint32 newFraudNotifierRewardMultiplier;\n uint256 fraudNotifierRewardMultiplierChangeInitiated;\n }\n\n event DepositDustThresholdUpdateStarted(\n uint64 newDepositDustThreshold,\n uint256 timestamp\n );\n event DepositDustThresholdUpdated(uint64 depositDustThreshold);\n\n event DepositTreasuryFeeDivisorUpdateStarted(\n uint64 depositTreasuryFeeDivisor,\n uint256 timestamp\n );\n event DepositTreasuryFeeDivisorUpdated(uint64 depositTreasuryFeeDivisor);\n\n event DepositTxMaxFeeUpdateStarted(\n uint64 newDepositTxMaxFee,\n uint256 timestamp\n );\n event DepositTxMaxFeeUpdated(uint64 depositTxMaxFee);\n\n event RedemptionDustThresholdUpdateStarted(\n uint64 newRedemptionDustThreshold,\n uint256 timestamp\n );\n event RedemptionDustThresholdUpdated(uint64 redemptionDustThreshold);\n\n event RedemptionTreasuryFeeDivisorUpdateStarted(\n uint64 newRedemptionTreasuryFeeDivisor,\n uint256 timestamp\n );\n event RedemptionTreasuryFeeDivisorUpdated(\n uint64 redemptionTreasuryFeeDivisor\n );\n\n event RedemptionTxMaxFeeUpdateStarted(\n uint64 newRedemptionTxMaxFee,\n uint256 timestamp\n );\n event RedemptionTxMaxFeeUpdated(uint64 redemptionTxMaxFee);\n\n event RedemptionTimeoutUpdateStarted(\n uint32 newRedemptionTimeout,\n uint256 timestamp\n );\n event RedemptionTimeoutUpdated(uint32 redemptionTimeout);\n\n event RedemptionTimeoutSlashingAmountUpdateStarted(\n uint96 newRedemptionTimeoutSlashingAmount,\n uint256 timestamp\n );\n event RedemptionTimeoutSlashingAmountUpdated(\n uint96 redemptionTimeoutSlashingAmount\n );\n\n event RedemptionTimeoutNotifierRewardMultiplierUpdateStarted(\n uint32 newRedemptionTimeoutNotifierRewardMultiplier,\n uint256 timestamp\n );\n event RedemptionTimeoutNotifierRewardMultiplierUpdated(\n uint32 redemptionTimeoutNotifierRewardMultiplier\n );\n\n event MovingFundsTxMaxTotalFeeUpdateStarted(\n uint64 newMovingFundsTxMaxTotalFee,\n uint256 timestamp\n );\n event MovingFundsTxMaxTotalFeeUpdated(uint64 movingFundsTxMaxTotalFee);\n\n event MovingFundsDustThresholdUpdateStarted(\n uint64 newMovingFundsDustThreshold,\n uint256 timestamp\n );\n event MovingFundsDustThresholdUpdated(uint64 movingFundsDustThreshold);\n\n event MovingFundsTimeoutResetDelayUpdateStarted(\n uint32 newMovingFundsTimeoutResetDelay,\n uint256 timestamp\n );\n event MovingFundsTimeoutResetDelayUpdated(\n uint32 movingFundsTimeoutResetDelay\n );\n\n event MovingFundsTimeoutUpdateStarted(\n uint32 newMovingFundsTimeout,\n uint256 timestamp\n );\n event MovingFundsTimeoutUpdated(uint32 movingFundsTimeout);\n\n event MovingFundsTimeoutSlashingAmountUpdateStarted(\n uint96 newMovingFundsTimeoutSlashingAmount,\n uint256 timestamp\n );\n event MovingFundsTimeoutSlashingAmountUpdated(\n uint96 movingFundsTimeoutSlashingAmount\n );\n\n event MovingFundsTimeoutNotifierRewardMultiplierUpdateStarted(\n uint32 newMovingFundsTimeoutNotifierRewardMultiplier,\n uint256 timestamp\n );\n event MovingFundsTimeoutNotifierRewardMultiplierUpdated(\n uint32 movingFundsTimeoutNotifierRewardMultiplier\n );\n\n event MovedFundsSweepTxMaxTotalFeeUpdateStarted(\n uint64 newMovedFundsSweepTxMaxTotalFee,\n uint256 timestamp\n );\n event MovedFundsSweepTxMaxTotalFeeUpdated(\n uint64 movedFundsSweepTxMaxTotalFee\n );\n\n event MovedFundsSweepTimeoutUpdateStarted(\n uint32 newMovedFundsSweepTimeout,\n uint256 timestamp\n );\n event MovedFundsSweepTimeoutUpdated(uint32 movedFundsSweepTimeout);\n\n event MovedFundsSweepTimeoutSlashingAmountUpdateStarted(\n uint96 newMovedFundsSweepTimeoutSlashingAmount,\n uint256 timestamp\n );\n event MovedFundsSweepTimeoutSlashingAmountUpdated(\n uint96 movedFundsSweepTimeoutSlashingAmount\n );\n\n event MovedFundsSweepTimeoutNotifierRewardMultiplierUpdateStarted(\n uint32 newMovedFundsSweepTimeoutNotifierRewardMultiplier,\n uint256 timestamp\n );\n event MovedFundsSweepTimeoutNotifierRewardMultiplierUpdated(\n uint32 movedFundsSweepTimeoutNotifierRewardMultiplier\n );\n\n event WalletCreationPeriodUpdateStarted(\n uint32 newWalletCreationPeriod,\n uint256 timestamp\n );\n event WalletCreationPeriodUpdated(uint32 walletCreationPeriod);\n\n event WalletCreationMinBtcBalanceUpdateStarted(\n uint64 newWalletCreationMinBtcBalance,\n uint256 timestamp\n );\n event WalletCreationMinBtcBalanceUpdated(\n uint64 walletCreationMinBtcBalance\n );\n\n event WalletCreationMaxBtcBalanceUpdateStarted(\n uint64 newWalletCreationMaxBtcBalance,\n uint256 timestamp\n );\n event WalletCreationMaxBtcBalanceUpdated(\n uint64 walletCreationMaxBtcBalance\n );\n\n event WalletClosureMinBtcBalanceUpdateStarted(\n uint64 newWalletClosureMinBtcBalance,\n uint256 timestamp\n );\n event WalletClosureMinBtcBalanceUpdated(uint64 walletClosureMinBtcBalance);\n\n event WalletMaxAgeUpdateStarted(uint32 newWalletMaxAge, uint256 timestamp);\n event WalletMaxAgeUpdated(uint32 walletMaxAge);\n\n event WalletMaxBtcTransferUpdateStarted(\n uint64 newWalletMaxBtcTransfer,\n uint256 timestamp\n );\n event WalletMaxBtcTransferUpdated(uint64 walletMaxBtcTransfer);\n\n event WalletClosingPeriodUpdateStarted(\n uint32 newWalletClosingPeriod,\n uint256 timestamp\n );\n event WalletClosingPeriodUpdated(uint32 walletClosingPeriod);\n\n event FraudChallengeDepositAmountUpdateStarted(\n uint96 newFraudChallengeDepositAmount,\n uint256 timestamp\n );\n event FraudChallengeDepositAmountUpdated(\n uint96 fraudChallengeDepositAmount\n );\n\n event FraudChallengeDefeatTimeoutUpdateStarted(\n uint32 newFraudChallengeDefeatTimeout,\n uint256 timestamp\n );\n event FraudChallengeDefeatTimeoutUpdated(\n uint32 fraudChallengeDefeatTimeout\n );\n\n event FraudSlashingAmountUpdateStarted(\n uint96 newFraudSlashingAmount,\n uint256 timestamp\n );\n event FraudSlashingAmountUpdated(uint96 fraudSlashingAmount);\n\n event FraudNotifierRewardMultiplierUpdateStarted(\n uint32 newFraudNotifierRewardMultiplier,\n uint256 timestamp\n );\n event FraudNotifierRewardMultiplierUpdated(\n uint32 fraudNotifierRewardMultiplier\n );\n\n /// @notice Reverts if called before the governance delay elapses.\n /// @param changeInitiatedTimestamp Timestamp indicating the beginning\n /// of the change.\n modifier onlyAfterGovernanceDelay(\n uint256 changeInitiatedTimestamp,\n uint256 governanceDelay\n ) {\n /* solhint-disable not-rely-on-time */\n require(changeInitiatedTimestamp > 0, \"Change not initiated\");\n require(\n block.timestamp - changeInitiatedTimestamp >= governanceDelay,\n \"Governance delay has not elapsed\"\n );\n _;\n /* solhint-enable not-rely-on-time */\n }\n\n // --- Deposit\n\n /// @notice Begins the deposit dust threshold amount update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newDepositDustThreshold New deposit dust threshold amount.\n function beginDepositDustThresholdUpdate(\n DepositData storage self,\n uint64 _newDepositDustThreshold\n ) external {\n /* solhint-disable not-rely-on-time */\n self.newDepositDustThreshold = _newDepositDustThreshold;\n self.depositDustThresholdChangeInitiated = block.timestamp;\n emit DepositDustThresholdUpdateStarted(\n _newDepositDustThreshold,\n block.timestamp\n );\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the deposit dust threshold amount update process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeDepositDustThresholdUpdate(\n DepositData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.depositDustThresholdChangeInitiated,\n governanceDelay\n )\n {\n emit DepositDustThresholdUpdated(self.newDepositDustThreshold);\n\n self.newDepositDustThreshold = 0;\n self.depositDustThresholdChangeInitiated = 0;\n }\n\n function getNewDepositDustThreshold(DepositData storage self)\n internal\n view\n returns (uint64)\n {\n return self.newDepositDustThreshold;\n }\n\n /// @notice Begins the deposit treasury fee divisor amount update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newDepositTreasuryFeeDivisor New deposit treasury fee divisor amount.\n function beginDepositTreasuryFeeDivisorUpdate(\n DepositData storage self,\n uint64 _newDepositTreasuryFeeDivisor\n ) external {\n /* solhint-disable not-rely-on-time */\n self.newDepositTreasuryFeeDivisor = _newDepositTreasuryFeeDivisor;\n self.depositTreasuryFeeDivisorChangeInitiated = block.timestamp;\n emit DepositTreasuryFeeDivisorUpdateStarted(\n _newDepositTreasuryFeeDivisor,\n block.timestamp\n );\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the deposit treasury fee divisor amount update process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeDepositTreasuryFeeDivisorUpdate(\n DepositData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.depositTreasuryFeeDivisorChangeInitiated,\n governanceDelay\n )\n {\n emit DepositTreasuryFeeDivisorUpdated(\n self.newDepositTreasuryFeeDivisor\n );\n\n self.newDepositTreasuryFeeDivisor = 0;\n self.depositTreasuryFeeDivisorChangeInitiated = 0;\n }\n\n function getNewDepositTreasuryFeeDivisor(DepositData storage self)\n internal\n view\n returns (uint64)\n {\n return self.newDepositTreasuryFeeDivisor;\n }\n\n /// @notice Begins the deposit tx max fee amount update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newDepositTxMaxFee New deposit tx max fee amount.\n function beginDepositTxMaxFeeUpdate(\n DepositData storage self,\n uint64 _newDepositTxMaxFee\n ) external {\n /* solhint-disable not-rely-on-time */\n self.newDepositTxMaxFee = _newDepositTxMaxFee;\n self.depositTxMaxFeeChangeInitiated = block.timestamp;\n emit DepositTxMaxFeeUpdateStarted(_newDepositTxMaxFee, block.timestamp);\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the deposit tx max fee amount update process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeDepositTxMaxFeeUpdate(\n DepositData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.depositTxMaxFeeChangeInitiated,\n governanceDelay\n )\n {\n emit DepositTxMaxFeeUpdated(self.newDepositTxMaxFee);\n\n self.newDepositTxMaxFee = 0;\n self.depositTxMaxFeeChangeInitiated = 0;\n }\n\n function getNewDepositTxMaxFee(DepositData storage self)\n internal\n view\n returns (uint64)\n {\n return self.newDepositTxMaxFee;\n }\n\n // --- Redemption\n\n /// @notice Begins the redemption dust threshold amount update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newRedemptionDustThreshold New redemption dust threshold amount.\n function beginRedemptionDustThresholdUpdate(\n RedemptionData storage self,\n uint64 _newRedemptionDustThreshold\n ) external {\n /* solhint-disable not-rely-on-time */\n self.newRedemptionDustThreshold = _newRedemptionDustThreshold;\n self.redemptionDustThresholdChangeInitiated = block.timestamp;\n emit RedemptionDustThresholdUpdateStarted(\n _newRedemptionDustThreshold,\n block.timestamp\n );\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the redemption dust threshold amount update process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeRedemptionDustThresholdUpdate(\n RedemptionData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.redemptionDustThresholdChangeInitiated,\n governanceDelay\n )\n {\n emit RedemptionDustThresholdUpdated(self.newRedemptionDustThreshold);\n\n self.newRedemptionDustThreshold = 0;\n self.redemptionDustThresholdChangeInitiated = 0;\n }\n\n function getNewRedemptionDustThreshold(RedemptionData storage self)\n internal\n view\n returns (uint64)\n {\n return self.newRedemptionDustThreshold;\n }\n\n /// @notice Begins the redemption treasury fee divisor amount update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newRedemptionTreasuryFeeDivisor New redemption treasury fee divisor\n /// amount.\n function beginRedemptionTreasuryFeeDivisorUpdate(\n RedemptionData storage self,\n uint64 _newRedemptionTreasuryFeeDivisor\n ) external {\n /* solhint-disable not-rely-on-time */\n self.newRedemptionTreasuryFeeDivisor = _newRedemptionTreasuryFeeDivisor;\n self.redemptionTreasuryFeeDivisorChangeInitiated = block.timestamp;\n emit RedemptionTreasuryFeeDivisorUpdateStarted(\n _newRedemptionTreasuryFeeDivisor,\n block.timestamp\n );\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the redemption treasury fee divisor amount update process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeRedemptionTreasuryFeeDivisorUpdate(\n RedemptionData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.redemptionTreasuryFeeDivisorChangeInitiated,\n governanceDelay\n )\n {\n emit RedemptionTreasuryFeeDivisorUpdated(\n self.newRedemptionTreasuryFeeDivisor\n );\n\n self.newRedemptionTreasuryFeeDivisor = 0;\n self.redemptionTreasuryFeeDivisorChangeInitiated = 0;\n }\n\n function getNewRedemptionTreasuryFeeDivisor(RedemptionData storage self)\n internal\n view\n returns (uint64)\n {\n return self.newRedemptionTreasuryFeeDivisor;\n }\n\n /// @notice Begins the redemption tx max fee amount update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newRedemptionTxMaxFee New redemption tx max fee amount.\n function beginRedemptionTxMaxFeeUpdate(\n RedemptionData storage self,\n uint64 _newRedemptionTxMaxFee\n ) external {\n /* solhint-disable not-rely-on-time */\n self.newRedemptionTxMaxFee = _newRedemptionTxMaxFee;\n self.redemptionTxMaxFeeChangeInitiated = block.timestamp;\n emit RedemptionTxMaxFeeUpdateStarted(\n _newRedemptionTxMaxFee,\n block.timestamp\n );\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the redemption tx max fee amount update process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeRedemptionTxMaxFeeUpdate(\n RedemptionData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.redemptionTxMaxFeeChangeInitiated,\n governanceDelay\n )\n {\n emit RedemptionTxMaxFeeUpdated(self.newRedemptionTxMaxFee);\n\n self.newRedemptionTxMaxFee = 0;\n self.redemptionTxMaxFeeChangeInitiated = 0;\n }\n\n function getNewRedemptionTxMaxFee(RedemptionData storage self)\n internal\n view\n returns (uint64)\n {\n return self.newRedemptionTxMaxFee;\n }\n\n /// @notice Begins the redemption timeout amount update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newRedemptionTimeout New redemption timeout amount.\n function beginRedemptionTimeoutUpdate(\n RedemptionData storage self,\n uint32 _newRedemptionTimeout\n ) external {\n /* solhint-disable not-rely-on-time */\n self.newRedemptionTimeout = _newRedemptionTimeout;\n self.redemptionTimeoutChangeInitiated = block.timestamp;\n emit RedemptionTimeoutUpdateStarted(\n _newRedemptionTimeout,\n block.timestamp\n );\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the redemption timeout amount update\n /// process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeRedemptionTimeoutUpdate(\n RedemptionData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.redemptionTimeoutChangeInitiated,\n governanceDelay\n )\n {\n emit RedemptionTimeoutUpdated(self.newRedemptionTimeout);\n\n self.newRedemptionTimeout = 0;\n self.redemptionTimeoutChangeInitiated = 0;\n }\n\n function getNewRedemptionTimeout(RedemptionData storage self)\n internal\n view\n returns (uint32)\n {\n return self.newRedemptionTimeout;\n }\n\n /// @notice Begins the redemption timeout slashing amount update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newRedemptionTimeoutSlashingAmount New redemption timeout slashing\n /// amount.\n function beginRedemptionTimeoutSlashingAmountUpdate(\n RedemptionData storage self,\n uint96 _newRedemptionTimeoutSlashingAmount\n ) external {\n /* solhint-disable not-rely-on-time */\n self\n .newRedemptionTimeoutSlashingAmount = _newRedemptionTimeoutSlashingAmount;\n self.redemptionTimeoutSlashingAmountChangeInitiated = block.timestamp;\n emit RedemptionTimeoutSlashingAmountUpdateStarted(\n _newRedemptionTimeoutSlashingAmount,\n block.timestamp\n );\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the redemption timeout slashing amount update process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeRedemptionTimeoutSlashingAmountUpdate(\n RedemptionData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.redemptionTimeoutSlashingAmountChangeInitiated,\n governanceDelay\n )\n {\n emit RedemptionTimeoutSlashingAmountUpdated(\n self.newRedemptionTimeoutSlashingAmount\n );\n\n self.newRedemptionTimeoutSlashingAmount = 0;\n self.redemptionTimeoutSlashingAmountChangeInitiated = 0;\n }\n\n function getNewRedemptionTimeoutSlashingAmount(RedemptionData storage self)\n internal\n view\n returns (uint96)\n {\n return self.newRedemptionTimeoutSlashingAmount;\n }\n\n /// @notice Begins the redemption timeout notifier reward multiplier amount\n /// update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newRedemptionTimeoutNotifierRewardMultiplier New redemption\n /// timeout notifier reward multiplier amount.\n function beginRedemptionTimeoutNotifierRewardMultiplierUpdate(\n RedemptionData storage self,\n uint32 _newRedemptionTimeoutNotifierRewardMultiplier\n ) internal {\n /* solhint-disable not-rely-on-time */\n self\n .newRedemptionTimeoutNotifierRewardMultiplier = _newRedemptionTimeoutNotifierRewardMultiplier;\n self.redemptionTimeoutNotifierRewardMultiplierChangeInitiated = block\n .timestamp;\n emit RedemptionTimeoutNotifierRewardMultiplierUpdateStarted(\n _newRedemptionTimeoutNotifierRewardMultiplier,\n block.timestamp\n );\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the redemption timeout notifier reward multiplier amount update process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeRedemptionTimeoutNotifierRewardMultiplierUpdate(\n RedemptionData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.redemptionTimeoutNotifierRewardMultiplierChangeInitiated,\n governanceDelay\n )\n {\n emit RedemptionTimeoutNotifierRewardMultiplierUpdated(\n self.newRedemptionTimeoutNotifierRewardMultiplier\n );\n\n self.newRedemptionTimeoutNotifierRewardMultiplier = 0;\n self.redemptionTimeoutNotifierRewardMultiplierChangeInitiated = 0;\n }\n\n function getNewRedemptionTimeoutNotifierRewardMultiplier(\n RedemptionData storage self\n ) internal view returns (uint32) {\n return self.newRedemptionTimeoutNotifierRewardMultiplier;\n }\n\n // --- Moving funds\n\n /// @notice Begins the moving funds tx max total fee amount update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newMovingFundsTxMaxTotalFee New moving funds tx max total fee amount.\n function beginMovingFundsTxMaxTotalFeeUpdate(\n MovingFundsData storage self,\n uint64 _newMovingFundsTxMaxTotalFee\n ) external {\n /* solhint-disable not-rely-on-time */\n self.newMovingFundsTxMaxTotalFee = _newMovingFundsTxMaxTotalFee;\n self.movingFundsTxMaxTotalFeeChangeInitiated = block.timestamp;\n emit MovingFundsTxMaxTotalFeeUpdateStarted(\n _newMovingFundsTxMaxTotalFee,\n block.timestamp\n );\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the moving funds tx max total fee amount update process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeMovingFundsTxMaxTotalFeeUpdate(\n MovingFundsData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.movingFundsTxMaxTotalFeeChangeInitiated,\n governanceDelay\n )\n {\n emit MovingFundsTxMaxTotalFeeUpdated(self.newMovingFundsTxMaxTotalFee);\n\n self.newMovingFundsTxMaxTotalFee = 0;\n self.movingFundsTxMaxTotalFeeChangeInitiated = 0;\n }\n\n function getNewMovingFundsTxMaxTotalFee(MovingFundsData storage self)\n internal\n view\n returns (uint64)\n {\n return self.newMovingFundsTxMaxTotalFee;\n }\n\n /// @notice Begins the moving funds dust threshold amount update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newMovingFundsDustThreshold New moving funds dust threshold amount.\n function beginMovingFundsDustThresholdUpdate(\n MovingFundsData storage self,\n uint64 _newMovingFundsDustThreshold\n ) external {\n /* solhint-disable not-rely-on-time */\n self.newMovingFundsDustThreshold = _newMovingFundsDustThreshold;\n self.movingFundsDustThresholdChangeInitiated = block.timestamp;\n emit MovingFundsDustThresholdUpdateStarted(\n _newMovingFundsDustThreshold,\n block.timestamp\n );\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the moving funds dust threshold amount update process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeMovingFundsDustThresholdUpdate(\n MovingFundsData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.movingFundsDustThresholdChangeInitiated,\n governanceDelay\n )\n {\n emit MovingFundsDustThresholdUpdated(self.newMovingFundsDustThreshold);\n\n self.newMovingFundsDustThreshold = 0;\n self.movingFundsDustThresholdChangeInitiated = 0;\n }\n\n function getNewMovingFundsDustThreshold(MovingFundsData storage self)\n internal\n view\n returns (uint64)\n {\n return self.newMovingFundsDustThreshold;\n }\n\n /// @notice Begins the moving funds timeout reset delay amount update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newMovingFundsTimeoutResetDelay New moving funds timeout reset\n /// delay amount.\n function beginMovingFundsTimeoutResetDelayUpdate(\n MovingFundsData storage self,\n uint32 _newMovingFundsTimeoutResetDelay\n ) external {\n /* solhint-disable not-rely-on-time */\n self.newMovingFundsTimeoutResetDelay = _newMovingFundsTimeoutResetDelay;\n self.movingFundsTimeoutResetDelayChangeInitiated = block.timestamp;\n emit MovingFundsTimeoutResetDelayUpdateStarted(\n _newMovingFundsTimeoutResetDelay,\n block.timestamp\n );\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the moving funds timeout reset delay amount update process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeMovingFundsTimeoutResetDelayUpdate(\n MovingFundsData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.movingFundsTimeoutResetDelayChangeInitiated,\n governanceDelay\n )\n {\n emit MovingFundsTimeoutResetDelayUpdated(\n self.newMovingFundsTimeoutResetDelay\n );\n\n self.newMovingFundsTimeoutResetDelay = 0;\n self.movingFundsTimeoutResetDelayChangeInitiated = 0;\n }\n\n function getNewMovingFundsTimeoutResetDelay(MovingFundsData storage self)\n internal\n view\n returns (uint32)\n {\n return self.newMovingFundsTimeoutResetDelay;\n }\n\n /// @notice Begins the moving funds timeout amount update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newMovingFundsTimeout New moving funds timeout amount.\n function beginMovingFundsTimeoutUpdate(\n MovingFundsData storage self,\n uint32 _newMovingFundsTimeout\n ) external {\n /* solhint-disable not-rely-on-time */\n self.newMovingFundsTimeout = _newMovingFundsTimeout;\n self.movingFundsTimeoutChangeInitiated = block.timestamp;\n emit MovingFundsTimeoutUpdateStarted(\n _newMovingFundsTimeout,\n block.timestamp\n );\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the moving funds timeout amount update process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeMovingFundsTimeoutUpdate(\n MovingFundsData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.movingFundsTimeoutChangeInitiated,\n governanceDelay\n )\n {\n emit MovingFundsTimeoutUpdated(self.newMovingFundsTimeout);\n\n self.newMovingFundsTimeout = 0;\n self.movingFundsTimeoutChangeInitiated = 0;\n }\n\n function getNewMovingFundsTimeout(MovingFundsData storage self)\n internal\n view\n returns (uint32)\n {\n return self.newMovingFundsTimeout;\n }\n\n /// @notice Begins the moving funds timeout slashing amount update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newMovingFundsTimeoutSlashingAmount New moving funds timeout slashing amount.\n function beginMovingFundsTimeoutSlashingAmountUpdate(\n MovingFundsData storage self,\n uint96 _newMovingFundsTimeoutSlashingAmount\n ) external {\n /* solhint-disable not-rely-on-time */\n self\n .newMovingFundsTimeoutSlashingAmount = _newMovingFundsTimeoutSlashingAmount;\n self.movingFundsTimeoutSlashingAmountChangeInitiated = block.timestamp;\n emit MovingFundsTimeoutSlashingAmountUpdateStarted(\n _newMovingFundsTimeoutSlashingAmount,\n block.timestamp\n );\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the moving funds timeout slashing amount update process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeMovingFundsTimeoutSlashingAmountUpdate(\n MovingFundsData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.movingFundsTimeoutSlashingAmountChangeInitiated,\n governanceDelay\n )\n {\n emit MovingFundsTimeoutSlashingAmountUpdated(\n self.newMovingFundsTimeoutSlashingAmount\n );\n\n self.newMovingFundsTimeoutSlashingAmount = 0;\n self.movingFundsTimeoutSlashingAmountChangeInitiated = 0;\n }\n\n function getNewMovingFundsTimeoutSlashingAmount(\n MovingFundsData storage self\n ) external view returns (uint96) {\n return self.newMovingFundsTimeoutSlashingAmount;\n }\n\n /// @notice Begins the moving funds timeout notifier reward multiplier amount\n /// update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newMovingFundsTimeoutNotifierRewardMultiplier New moving funds\n /// timeout notifier reward multiplier amount.\n function beginMovingFundsTimeoutNotifierRewardMultiplierUpdate(\n MovingFundsData storage self,\n uint32 _newMovingFundsTimeoutNotifierRewardMultiplier\n ) external {\n /* solhint-disable not-rely-on-time */\n self\n .newMovingFundsTimeoutNotifierRewardMultiplier = _newMovingFundsTimeoutNotifierRewardMultiplier;\n self.movingFundsTimeoutNotifierRewardMultiplierChangeInitiated = block\n .timestamp;\n emit MovingFundsTimeoutNotifierRewardMultiplierUpdateStarted(\n _newMovingFundsTimeoutNotifierRewardMultiplier,\n block.timestamp\n );\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the moving funds timeout notifier reward multiplier\n /// amount update process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeMovingFundsTimeoutNotifierRewardMultiplierUpdate(\n MovingFundsData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.movingFundsTimeoutNotifierRewardMultiplierChangeInitiated,\n governanceDelay\n )\n {\n emit MovingFundsTimeoutNotifierRewardMultiplierUpdated(\n self.newMovingFundsTimeoutNotifierRewardMultiplier\n );\n\n self.newMovingFundsTimeoutNotifierRewardMultiplier = 0;\n self.movingFundsTimeoutNotifierRewardMultiplierChangeInitiated = 0;\n }\n\n function getNewMovingFundsTimeoutNotifierRewardMultiplier(\n MovingFundsData storage self\n ) internal view returns (uint32) {\n return self.newMovingFundsTimeoutNotifierRewardMultiplier;\n }\n\n /// @notice Begins the moved funds sweep tx max total fee amount update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newMovedFundsSweepTxMaxTotalFee New moved funds sweep tx max total\n /// fee amount.\n function beginMovedFundsSweepTxMaxTotalFeeUpdate(\n MovingFundsData storage self,\n uint64 _newMovedFundsSweepTxMaxTotalFee\n ) external {\n /* solhint-disable not-rely-on-time */\n self.newMovedFundsSweepTxMaxTotalFee = _newMovedFundsSweepTxMaxTotalFee;\n self.movedFundsSweepTxMaxTotalFeeChangeInitiated = block.timestamp;\n emit MovedFundsSweepTxMaxTotalFeeUpdateStarted(\n _newMovedFundsSweepTxMaxTotalFee,\n block.timestamp\n );\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the moved funds sweep tx max total fee amount update\n /// process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeMovedFundsSweepTxMaxTotalFeeUpdate(\n MovingFundsData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.movedFundsSweepTxMaxTotalFeeChangeInitiated,\n governanceDelay\n )\n {\n emit MovedFundsSweepTxMaxTotalFeeUpdated(\n self.newMovedFundsSweepTxMaxTotalFee\n );\n\n self.newMovedFundsSweepTxMaxTotalFee = 0;\n self.movedFundsSweepTxMaxTotalFeeChangeInitiated = 0;\n }\n\n function getNewMovedFundsSweepTxMaxTotalFee(MovingFundsData storage self)\n internal\n view\n returns (uint64)\n {\n return self.newMovedFundsSweepTxMaxTotalFee;\n }\n\n /// @notice Begins the moved funds sweep timeout amount update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newMovedFundsSweepTimeout New moved funds sweep timeout amount.\n function beginMovedFundsSweepTimeoutUpdate(\n MovingFundsData storage self,\n uint32 _newMovedFundsSweepTimeout\n ) external {\n /* solhint-disable not-rely-on-time */\n self.newMovedFundsSweepTimeout = _newMovedFundsSweepTimeout;\n self.movedFundsSweepTimeoutChangeInitiated = block.timestamp;\n emit MovedFundsSweepTimeoutUpdateStarted(\n _newMovedFundsSweepTimeout,\n block.timestamp\n );\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the moved funds sweep timeout amount update process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeMovedFundsSweepTimeoutUpdate(\n MovingFundsData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.movedFundsSweepTimeoutChangeInitiated,\n governanceDelay\n )\n {\n emit MovedFundsSweepTimeoutUpdated(self.newMovedFundsSweepTimeout);\n\n self.newMovedFundsSweepTimeout = 0;\n self.movedFundsSweepTimeoutChangeInitiated = 0;\n }\n\n function getNewMovedFundsSweepTimeout(MovingFundsData storage self)\n internal\n view\n returns (uint32)\n {\n return self.newMovedFundsSweepTimeout;\n }\n\n /// @notice Begins the moved funds sweep timeout slashing amount update\n /// process.\n /// @dev Can be called only by the contract owner.\n /// @param _newMovedFundsSweepTimeoutSlashingAmount New moved funds sweep\n /// timeout slashing amount.\n function beginMovedFundsSweepTimeoutSlashingAmountUpdate(\n MovingFundsData storage self,\n uint96 _newMovedFundsSweepTimeoutSlashingAmount\n ) external {\n /* solhint-disable not-rely-on-time */\n self\n .newMovedFundsSweepTimeoutSlashingAmount = _newMovedFundsSweepTimeoutSlashingAmount;\n self.movedFundsSweepTimeoutSlashingAmountChangeInitiated = block\n .timestamp;\n emit MovedFundsSweepTimeoutSlashingAmountUpdateStarted(\n _newMovedFundsSweepTimeoutSlashingAmount,\n block.timestamp\n );\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the moved funds sweep timeout slashing amount\n /// update process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeMovedFundsSweepTimeoutSlashingAmountUpdate(\n MovingFundsData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.movedFundsSweepTimeoutSlashingAmountChangeInitiated,\n governanceDelay\n )\n {\n emit MovedFundsSweepTimeoutSlashingAmountUpdated(\n self.newMovedFundsSweepTimeoutSlashingAmount\n );\n\n self.newMovedFundsSweepTimeoutSlashingAmount = 0;\n self.movedFundsSweepTimeoutSlashingAmountChangeInitiated = 0;\n }\n\n function getNewMovedFundsSweepTimeoutSlashingAmount(\n MovingFundsData storage self\n ) internal view returns (uint96) {\n return self.newMovedFundsSweepTimeoutSlashingAmount;\n }\n\n /// @notice Begins the moved funds sweep timeout notifier reward multiplier\n /// amount update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newMovedFundsSweepTimeoutNotifierRewardMultiplier New moved funds\n /// sweep timeout notifier reward multiplier amount.\n function beginMovedFundsSweepTimeoutNotifierRewardMultiplierUpdate(\n MovingFundsData storage self,\n uint32 _newMovedFundsSweepTimeoutNotifierRewardMultiplier\n ) external {\n /* solhint-disable not-rely-on-time */\n self\n .newMovedFundsSweepTimeoutNotifierRewardMultiplier = _newMovedFundsSweepTimeoutNotifierRewardMultiplier;\n self\n .movedFundsSweepTimeoutNotifierRewardMultiplierChangeInitiated = block\n .timestamp;\n emit MovedFundsSweepTimeoutNotifierRewardMultiplierUpdateStarted(\n _newMovedFundsSweepTimeoutNotifierRewardMultiplier,\n block.timestamp\n );\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the moved funds sweep timeout notifier reward multiplier\n /// amount update process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeMovedFundsSweepTimeoutNotifierRewardMultiplierUpdate(\n MovingFundsData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.movedFundsSweepTimeoutNotifierRewardMultiplierChangeInitiated,\n governanceDelay\n )\n {\n emit MovedFundsSweepTimeoutNotifierRewardMultiplierUpdated(\n self.newMovedFundsSweepTimeoutNotifierRewardMultiplier\n );\n\n self.newMovedFundsSweepTimeoutNotifierRewardMultiplier = 0;\n self.movedFundsSweepTimeoutNotifierRewardMultiplierChangeInitiated = 0;\n }\n\n function getNewMovedFundsSweepTimeoutNotifierRewardMultiplier(\n MovingFundsData storage self\n ) internal view returns (uint32) {\n return self.newMovedFundsSweepTimeoutNotifierRewardMultiplier;\n }\n\n // --- Wallet params\n\n /// @notice Begins the wallet creation period amount update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newWalletCreationPeriod New wallet creation period amount.\n function beginWalletCreationPeriodUpdate(\n WalletData storage self,\n uint32 _newWalletCreationPeriod\n ) external {\n /* solhint-disable not-rely-on-time */\n self.newWalletCreationPeriod = _newWalletCreationPeriod;\n self.walletCreationPeriodChangeInitiated = block.timestamp;\n emit WalletCreationPeriodUpdateStarted(\n _newWalletCreationPeriod,\n block.timestamp\n );\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the wallet creation period amount update process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeWalletCreationPeriodUpdate(\n WalletData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.walletCreationPeriodChangeInitiated,\n governanceDelay\n )\n {\n emit WalletCreationPeriodUpdated(self.newWalletCreationPeriod);\n\n self.newWalletCreationPeriod = 0;\n self.walletCreationPeriodChangeInitiated = 0;\n }\n\n function getNewWalletCreationPeriod(WalletData storage self)\n external\n view\n returns (uint32)\n {\n return self.newWalletCreationPeriod;\n }\n\n /// @notice Begins the wallet creation min btc balance amount update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newWalletCreationMinBtcBalance New wallet creation min btc balance\n /// amount.\n function beginWalletCreationMinBtcBalanceUpdate(\n WalletData storage self,\n uint64 _newWalletCreationMinBtcBalance\n ) external {\n /* solhint-disable not-rely-on-time */\n self.newWalletCreationMinBtcBalance = _newWalletCreationMinBtcBalance;\n self.walletCreationMinBtcBalanceChangeInitiated = block.timestamp;\n emit WalletCreationMinBtcBalanceUpdateStarted(\n _newWalletCreationMinBtcBalance,\n block.timestamp\n );\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the wallet creation min btc balance amount update process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeWalletCreationMinBtcBalanceUpdate(\n WalletData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.walletCreationMinBtcBalanceChangeInitiated,\n governanceDelay\n )\n {\n emit WalletCreationMinBtcBalanceUpdated(\n self.newWalletCreationMinBtcBalance\n );\n\n self.newWalletCreationMinBtcBalance = 0;\n self.walletCreationMinBtcBalanceChangeInitiated = 0;\n }\n\n function getNewWalletCreationMinBtcBalance(WalletData storage self)\n internal\n view\n returns (uint64)\n {\n return self.newWalletCreationMinBtcBalance;\n }\n\n /// @notice Begins the wallet creation max btc balance amount update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newWalletCreationMaxBtcBalance New wallet creation max btc balance\n /// amount.\n function beginWalletCreationMaxBtcBalanceUpdate(\n WalletData storage self,\n uint64 _newWalletCreationMaxBtcBalance\n ) external {\n /* solhint-disable not-rely-on-time */\n self.newWalletCreationMaxBtcBalance = _newWalletCreationMaxBtcBalance;\n self.walletCreationMaxBtcBalanceChangeInitiated = block.timestamp;\n emit WalletCreationMaxBtcBalanceUpdateStarted(\n _newWalletCreationMaxBtcBalance,\n block.timestamp\n );\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the wallet creation max btc balance amount update process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeWalletCreationMaxBtcBalanceUpdate(\n WalletData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.walletCreationMaxBtcBalanceChangeInitiated,\n governanceDelay\n )\n {\n emit WalletCreationMaxBtcBalanceUpdated(\n self.newWalletCreationMaxBtcBalance\n );\n\n self.newWalletCreationMaxBtcBalance = 0;\n self.walletCreationMaxBtcBalanceChangeInitiated = 0;\n }\n\n function getNewWalletCreationMaxBtcBalance(WalletData storage self)\n internal\n view\n returns (uint64)\n {\n return self.newWalletCreationMaxBtcBalance;\n }\n\n /// @notice Begins the wallet closure min btc balance amount update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newWalletClosureMinBtcBalance New wallet closure min btc balance amount.\n function beginWalletClosureMinBtcBalanceUpdate(\n WalletData storage self,\n uint64 _newWalletClosureMinBtcBalance\n ) external {\n /* solhint-disable not-rely-on-time */\n self.newWalletClosureMinBtcBalance = _newWalletClosureMinBtcBalance;\n self.walletClosureMinBtcBalanceChangeInitiated = block.timestamp;\n emit WalletClosureMinBtcBalanceUpdateStarted(\n _newWalletClosureMinBtcBalance,\n block.timestamp\n );\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the wallet closure min btc balance amount update process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeWalletClosureMinBtcBalanceUpdate(\n WalletData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.walletClosureMinBtcBalanceChangeInitiated,\n governanceDelay\n )\n {\n emit WalletClosureMinBtcBalanceUpdated(\n self.newWalletClosureMinBtcBalance\n );\n\n self.newWalletClosureMinBtcBalance = 0;\n self.walletClosureMinBtcBalanceChangeInitiated = 0;\n }\n\n function getNewWalletClosureMinBtcBalance(WalletData storage self)\n internal\n view\n returns (uint64)\n {\n return self.newWalletClosureMinBtcBalance;\n }\n\n /// @notice Begins the wallet max age amount update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newWalletMaxAge New wallet max age amount.\n function beginWalletMaxAgeUpdate(\n WalletData storage self,\n uint32 _newWalletMaxAge\n ) external {\n /* solhint-disable not-rely-on-time */\n self.newWalletMaxAge = _newWalletMaxAge;\n self.walletMaxAgeChangeInitiated = block.timestamp;\n emit WalletMaxAgeUpdateStarted(_newWalletMaxAge, block.timestamp);\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the wallet max age amount update process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeWalletMaxAgeUpdate(\n WalletData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.walletMaxAgeChangeInitiated,\n governanceDelay\n )\n {\n emit WalletMaxAgeUpdated(self.newWalletMaxAge);\n\n self.newWalletMaxAge = 0;\n self.walletMaxAgeChangeInitiated = 0;\n }\n\n function getNewWalletMaxAge(WalletData storage self)\n internal\n view\n returns (uint32)\n {\n return self.newWalletMaxAge;\n }\n\n /// @notice Begins the wallet max btc transfer amount update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newWalletMaxBtcTransfer New wallet max btc transfer amount.\n function beginWalletMaxBtcTransferUpdate(\n WalletData storage self,\n uint64 _newWalletMaxBtcTransfer\n ) external {\n /* solhint-disable not-rely-on-time */\n self.newWalletMaxBtcTransfer = _newWalletMaxBtcTransfer;\n self.walletMaxBtcTransferChangeInitiated = block.timestamp;\n emit WalletMaxBtcTransferUpdateStarted(\n _newWalletMaxBtcTransfer,\n block.timestamp\n );\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the wallet max btc transfer amount update process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeWalletMaxBtcTransferUpdate(\n WalletData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.walletMaxBtcTransferChangeInitiated,\n governanceDelay\n )\n {\n emit WalletMaxBtcTransferUpdated(self.newWalletMaxBtcTransfer);\n\n self.newWalletMaxBtcTransfer = 0;\n self.walletMaxBtcTransferChangeInitiated = 0;\n }\n\n function getNewWalletMaxBtcTransfer(WalletData storage self)\n internal\n view\n returns (uint64)\n {\n return self.newWalletMaxBtcTransfer;\n }\n\n /// @notice Begins the wallet closing period amount update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newWalletClosingPeriod New wallet closing period amount.\n function beginWalletClosingPeriodUpdate(\n WalletData storage self,\n uint32 _newWalletClosingPeriod\n ) external {\n /* solhint-disable not-rely-on-time */\n self.newWalletClosingPeriod = _newWalletClosingPeriod;\n self.walletClosingPeriodChangeInitiated = block.timestamp;\n emit WalletClosingPeriodUpdateStarted(\n _newWalletClosingPeriod,\n block.timestamp\n );\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the wallet closing period amount update process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeWalletClosingPeriodUpdate(\n WalletData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.walletClosingPeriodChangeInitiated,\n governanceDelay\n )\n {\n emit WalletClosingPeriodUpdated(self.newWalletClosingPeriod);\n\n self.newWalletClosingPeriod = 0;\n self.walletClosingPeriodChangeInitiated = 0;\n }\n\n function getNewWalletClosingPeriod(WalletData storage self)\n internal\n view\n returns (uint32)\n {\n return self.newWalletClosingPeriod;\n }\n\n // --- Fraud\n\n /// @notice Begins the fraud challenge deposit amount update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newFraudChallengeDepositAmount New fraud challenge deposit amount.\n function beginFraudChallengeDepositAmountUpdate(\n FraudData storage self,\n uint96 _newFraudChallengeDepositAmount\n ) external {\n /* solhint-disable not-rely-on-time */\n self.newFraudChallengeDepositAmount = _newFraudChallengeDepositAmount;\n self.fraudChallengeDepositAmountChangeInitiated = block.timestamp;\n emit FraudChallengeDepositAmountUpdateStarted(\n _newFraudChallengeDepositAmount,\n block.timestamp\n );\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the fraud challenge deposit amount update process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeFraudChallengeDepositAmountUpdate(\n FraudData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.fraudChallengeDepositAmountChangeInitiated,\n governanceDelay\n )\n {\n emit FraudChallengeDepositAmountUpdated(\n self.newFraudChallengeDepositAmount\n );\n\n self.newFraudChallengeDepositAmount = 0;\n self.fraudChallengeDepositAmountChangeInitiated = 0;\n }\n\n function getNewFraudChallengeDepositAmount(FraudData storage self)\n internal\n view\n returns (uint96)\n {\n return self.newFraudChallengeDepositAmount;\n }\n\n /// @notice Begins the fraud challenge defeat timeout amount update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newFraudChallengeDefeatTimeout New fraud challenge defeat timeout\n /// amount.\n function beginFraudChallengeDefeatTimeoutUpdate(\n FraudData storage self,\n uint32 _newFraudChallengeDefeatTimeout\n ) external {\n /* solhint-disable not-rely-on-time */\n self.newFraudChallengeDefeatTimeout = _newFraudChallengeDefeatTimeout;\n self.fraudChallengeDefeatTimeoutChangeInitiated = block.timestamp;\n emit FraudChallengeDefeatTimeoutUpdateStarted(\n _newFraudChallengeDefeatTimeout,\n block.timestamp\n );\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the fraud challenge defeat timeout amount update process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeFraudChallengeDefeatTimeoutUpdate(\n FraudData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.fraudChallengeDefeatTimeoutChangeInitiated,\n governanceDelay\n )\n {\n emit FraudChallengeDefeatTimeoutUpdated(\n self.newFraudChallengeDefeatTimeout\n );\n\n self.newFraudChallengeDefeatTimeout = 0;\n self.fraudChallengeDefeatTimeoutChangeInitiated = 0;\n }\n\n function getNewFraudChallengeDefeatTimeout(FraudData storage self)\n internal\n view\n returns (uint32)\n {\n return self.newFraudChallengeDefeatTimeout;\n }\n\n /// @notice Begins the fraud slashing amount update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newFraudSlashingAmount New fraud slashing amount.\n function beginFraudSlashingAmountUpdate(\n FraudData storage self,\n uint96 _newFraudSlashingAmount\n ) external {\n /* solhint-disable not-rely-on-time */\n self.newFraudSlashingAmount = _newFraudSlashingAmount;\n self.fraudSlashingAmountChangeInitiated = block.timestamp;\n emit FraudSlashingAmountUpdateStarted(\n _newFraudSlashingAmount,\n block.timestamp\n );\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the fraud slashing amount update process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeFraudSlashingAmountUpdate(\n FraudData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.fraudSlashingAmountChangeInitiated,\n governanceDelay\n )\n {\n emit FraudSlashingAmountUpdated(self.newFraudSlashingAmount);\n\n self.newFraudSlashingAmount = 0;\n self.fraudSlashingAmountChangeInitiated = 0;\n }\n\n function getNewFraudSlashingAmount(FraudData storage self)\n internal\n view\n returns (uint96)\n {\n return self.newFraudSlashingAmount;\n }\n\n /// @notice Begins the fraud notifier reward multiplier amount update process.\n /// @dev Can be called only by the contract owner.\n /// @param _newFraudNotifierRewardMultiplier New fraud notifier reward multiplier\n /// amount.\n function beginFraudNotifierRewardMultiplierUpdate(\n FraudData storage self,\n uint32 _newFraudNotifierRewardMultiplier\n ) external {\n /* solhint-disable not-rely-on-time */\n self\n .newFraudNotifierRewardMultiplier = _newFraudNotifierRewardMultiplier;\n self.fraudNotifierRewardMultiplierChangeInitiated = block.timestamp;\n emit FraudNotifierRewardMultiplierUpdateStarted(\n _newFraudNotifierRewardMultiplier,\n block.timestamp\n );\n /* solhint-enable not-rely-on-time */\n }\n\n /// @notice Finalizes the fraud notifier reward multiplier amount update process.\n /// @dev Can be called only by the contract owner, after the governance\n /// delay elapses.\n function finalizeFraudNotifierRewardMultiplierUpdate(\n FraudData storage self,\n uint256 governanceDelay\n )\n external\n onlyAfterGovernanceDelay(\n self.fraudNotifierRewardMultiplierChangeInitiated,\n governanceDelay\n )\n {\n emit FraudNotifierRewardMultiplierUpdated(\n self.newFraudNotifierRewardMultiplier\n );\n\n self.newFraudNotifierRewardMultiplier = 0;\n self.fraudNotifierRewardMultiplierChangeInitiated = 0;\n }\n\n function getNewFraudNotifierRewardMultiplier(FraudData storage self)\n internal\n view\n returns (uint32)\n {\n return self.newFraudNotifierRewardMultiplier;\n }\n}\n"
|
|
270
270
|
},
|
|
271
|
+
"contracts/test/HeartbeatStub.sol": {
|
|
272
|
+
"content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.9;\n\nimport \"../bridge/Heartbeat.sol\";\n\n/// @dev This is a contract implemented to test Heartbeat library directly.\ncontract HeartbeatStub {\n function isValidHeartbeatMessage(bytes calldata message)\n public\n pure\n returns (bool)\n {\n return Heartbeat.isValidHeartbeatMessage(message);\n }\n}\n"
|
|
273
|
+
},
|
|
274
|
+
"contracts/test/TestEcdsaLib.sol": {
|
|
275
|
+
"content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.9;\n\nimport \"../bridge/EcdsaLib.sol\";\n\n// TODO: Rename to EcdsLibStub\n/// @dev This is a contract implemented to test EcdsaLib library directly.\ncontract TestEcdsaLib {\n function compressPublicKey(bytes32 x, bytes32 y)\n public\n pure\n returns (bytes memory)\n {\n return EcdsaLib.compressPublicKey(x, y);\n }\n}\n"
|
|
276
|
+
},
|
|
271
277
|
"contracts/vault/DonationVault.sol": {
|
|
272
278
|
"content": "// SPDX-License-Identifier: MIT\n\n// ██████████████ ▐████▌ ██████████████\n// ██████████████ ▐████▌ ██████████████\n// ▐████▌ ▐████▌\n// ▐████▌ ▐████▌\n// ██████████████ ▐████▌ ██████████████\n// ██████████████ ▐████▌ ██████████████\n// ▐████▌ ▐████▌\n// ▐████▌ ▐████▌\n// ▐████▌ ▐████▌\n// ▐████▌ ▐████▌\n// ▐████▌ ▐████▌\n// ▐████▌ ▐████▌\n\npragma solidity ^0.8.9;\n\nimport \"./IVault.sol\";\nimport \"../bank/Bank.sol\";\n\n/// @title BTC donation vault\n/// @notice Vault that allows making BTC donations to the system. Upon deposit,\n/// this vault does not increase depositors' balances and always\n/// decreases its own balance in the same transaction. The vault also\n/// allows making donations using existing Bank balances.\n///\n/// BEWARE: ALL BTC DEPOSITS TARGETING THIS VAULT ARE NOT REDEEMABLE\n/// AND THERE IS NO WAY TO RESTORE THE DONATED BALANCE.\n/// USE THIS VAULT ONLY WHEN YOU REALLY KNOW WHAT YOU ARE DOING!\ncontract DonationVault is IVault {\n Bank public bank;\n\n event DonationReceived(address donor, uint256 donatedAmount);\n\n modifier onlyBank() {\n require(msg.sender == address(bank), \"Caller is not the Bank\");\n _;\n }\n\n constructor(Bank _bank) {\n require(\n address(_bank) != address(0),\n \"Bank can not be the zero address\"\n );\n\n bank = _bank;\n }\n\n /// @notice Transfers the given `amount` of the Bank balance from the\n /// caller to the Donation Vault and immediately decreases the\n /// vault's balance in the Bank by the transferred `amount`.\n /// @param amount Amount of the Bank balance to donate.\n /// @dev Requirements:\n /// - The caller's balance in the Bank must be greater than or equal\n /// to the `amount`,\n /// - Donation Vault must have an allowance for caller's balance in\n /// the Bank for at least `amount`.\n function donate(uint256 amount) external {\n address donor = msg.sender;\n\n require(\n bank.balanceOf(donor) >= amount,\n \"Amount exceeds balance in the bank\"\n );\n\n emit DonationReceived(donor, amount);\n\n bank.transferBalanceFrom(donor, address(this), amount);\n bank.decreaseBalance(amount);\n }\n\n /// @notice Transfers the given `amount` of the Bank balance from the\n /// `owner` to the Donation Vault and immediately decreases the\n /// vault's balance in the Bank by the transferred `amount`.\n /// @param owner Address of the Bank balance owner who approved their\n /// balance to be used by the vault.\n /// @param amount The amount of the Bank balance approved by the owner\n /// to be used by the vault.\n /// @dev Requirements:\n /// - Can only be called by the Bank via `approveBalanceAndCall`,\n /// - The `owner` balance in the Bank must be greater than or equal\n /// to the `amount`.\n function receiveBalanceApproval(\n address owner,\n uint256 amount,\n bytes memory\n ) external override onlyBank {\n require(\n bank.balanceOf(owner) >= amount,\n \"Amount exceeds balance in the bank\"\n );\n\n emit DonationReceived(owner, amount);\n\n bank.transferBalanceFrom(owner, address(this), amount);\n bank.decreaseBalance(amount);\n }\n\n /// @notice Ignores the deposited amounts and does not increase depositors'\n /// individual balances. The vault decreases its own tBTC balance\n /// in the Bank by the total deposited amount.\n /// @param depositors Addresses of depositors whose deposits have been swept.\n /// @param depositedAmounts Amounts deposited by individual depositors and\n /// swept.\n /// @dev Requirements:\n /// - Can only be called by the Bank after the Bridge swept deposits\n /// and Bank increased balance for the vault,\n /// - The `depositors` array must not be empty,\n /// - The `depositors` array length must be equal to the\n /// `depositedAmounts` array length.\n function receiveBalanceIncrease(\n address[] calldata depositors,\n uint256[] calldata depositedAmounts\n ) external override onlyBank {\n require(depositors.length != 0, \"No depositors specified\");\n\n uint256 totalAmount = 0;\n for (uint256 i = 0; i < depositors.length; i++) {\n totalAmount += depositedAmounts[i];\n emit DonationReceived(depositors[i], depositedAmounts[i]);\n }\n\n bank.decreaseBalance(totalAmount);\n }\n}\n"
|
|
273
279
|
},
|