diff --git a/Makefile b/Makefile index 3a1d7cc..a97938b 100644 --- a/Makefile +++ b/Makefile @@ -6,4 +6,6 @@ fmt :; @forge fmt dry-run:; @forge script script/Deploy.s.sol:DeployScript deploy :; @forge script script/Deploy.s.sol:DeployScript --broadcast --verify +migrate:; @forge script script/Migrate.s.sol:MigrateScript --sender 0x08837De0Ae21C270383D9F2de4DB03c7b1314632 -vvvv + .PHONY: all flat clean test salt deploy diff --git a/foundry.toml b/foundry.toml index 73c6580..b8b0092 100644 --- a/foundry.toml +++ b/foundry.toml @@ -15,7 +15,7 @@ bytecode_hash = "ipfs" extra_output = ["storageLayout"] extra_output_files = ["metadata"] fs_permissions = [{ access = "read", path = "out" }] -eth_rpc_url = "https://rpc.darwinia.network" +eth_rpc_url = "https://crab-rpc.darwinia.network" etherscan_api_key = "xxx" [rpc_endpoints] diff --git a/script/Migrate.s.sol b/script/Migrate.s.sol new file mode 100644 index 0000000..dfa8ab2 --- /dev/null +++ b/script/Migrate.s.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {Script} from "forge-std/Script.sol"; +import {safeconsole} from "forge-std/safeconsole.sol"; +import {Upgrades} from "openzeppelin-foundry-upgrades/Upgrades.sol"; +import {Core} from "openzeppelin-foundry-upgrades/internal/Core.sol"; + +import {KtonDAOVaultV2} from "../src/staking/KtonDAOVaultV2.sol"; + +contract MigrateScript is Script { + address vault = 0x652182C6aBc0bBE41b5702b05a26d109A405EAcA; + address v2 = 0xC4784B3593fF0ace8773ec79EF4F8D8901a8DCfC; + + function run() public { + vm.startBroadcast(); + + Core.upgradeProxyTo(vault, v2, abi.encodeCall(KtonDAOVaultV2.initializeV2, ())); + + vm.stopBroadcast(); + } +} diff --git a/src/staking/KtonDAOVaultV2.sol b/src/staking/KtonDAOVaultV2.sol new file mode 100644 index 0000000..0b41979 --- /dev/null +++ b/src/staking/KtonDAOVaultV2.sol @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.20; + +import "./interfaces/IRewardsDistributionRecipient.sol"; +import "./interfaces/IOldRewardsDistributionRecipient.sol"; +import "./interfaces/IStakingRewards.sol"; +import "./interfaces/IOldStakingRewards.sol"; +import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; + +/// @custom:oz-upgrades-from KtonDAOVault +contract KtonDAOVaultV2 is Initializable, Ownable2StepUpgradeable { + // "modlda/trsry" in bytes. + address public constant SYSTEM_PALLET = 0x6D6f646c64612f74727372790000000000000000; + + address public constant OLD_KTON_STAKING_REWARDS = 0x000000000419683a1a03AbC21FC9da25fd2B4dD7; + address public constant OLD_KTON_REWARDS_DISTRIBUTION = 0x000000000Ae5DB7BDAf8D071e680452e33d91Dd5; + + address public stakingRewards; + + modifier onlySystem() { + require(msg.sender == SYSTEM_PALLET, "Caller is not RewardsDistribution contract"); + _; + } + + function initializeV2() public reinitializer(2) { + uint256 rewards = OLD_KTON_REWARDS_DISTRIBUTION.balance; + IOldRewardsDistributionRecipient(OLD_KTON_REWARDS_DISTRIBUTION).distributeRewards( + OLD_KTON_STAKING_REWARDS, rewards + ); + emit RewardsDistributed(OLD_KTON_REWARDS_DISTRIBUTION, rewards); + } + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + receive() external payable {} + + /// Runtime migration Step: + /// 1. Migrate OLD_KTON_REWARDS_DISTRIBUTION's owner to this contracts address. + /// 2. distributeRewards to this contract address. + /// Note: The amount of the reward must be passed in via msg.value. + function distributeRewards() external payable onlySystem returns (bool) { + uint256 reward = msg.value; + require(reward > 0, "Nothing to distribute"); + require( + address(this).balance >= reward, "RewardsDistribution contract does not have enough tokens to distribute" + ); + + uint256 oldTotalSupply = IOldStakingRewards(OLD_KTON_STAKING_REWARDS).totalSupply(); + uint256 newTotalSupply = IStakingRewards(stakingRewards).underlyingTotalSupply(); + uint256 totalSupply = oldTotalSupply + newTotalSupply; + + if (totalSupply == 0) { + return true; + } + + uint256 oldReward = reward * oldTotalSupply / totalSupply; + uint256 newReward = reward - oldReward; + + if (oldReward > 0) { + IOldRewardsDistributionRecipient(OLD_KTON_REWARDS_DISTRIBUTION).distributeRewards{value: oldReward}( + OLD_KTON_STAKING_REWARDS, oldReward + ); + emit RewardsDistributed(OLD_KTON_REWARDS_DISTRIBUTION, oldReward); + } + + if (newReward > 0) { + IRewardsDistributionRecipient(stakingRewards).notifyRewardAmount{value: newReward}(); + emit RewardsDistributed(stakingRewards, newReward); + } + + return true; + } + + event RewardsDistributed(address stakingRewards, uint256 amount); +} diff --git a/src/staking/interfaces/IOldRewardsDistributionRecipient.sol b/src/staking/interfaces/IOldRewardsDistributionRecipient.sol new file mode 100644 index 0000000..6a06833 --- /dev/null +++ b/src/staking/interfaces/IOldRewardsDistributionRecipient.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.4.24; + +interface IOldRewardsDistributionRecipient { + function distributeRewards(address ktonStakingRewards, uint256 reward) external payable returns (bool); +} diff --git a/verify/KtonDAOVaultV2.json b/verify/KtonDAOVaultV2.json new file mode 100644 index 0000000..b5e4f0f --- /dev/null +++ b/verify/KtonDAOVaultV2.json @@ -0,0 +1 @@ +{"language":"Solidity","sources":{"src/staking/KtonDAOVaultV2.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.20;\n\nimport \"./interfaces/IRewardsDistributionRecipient.sol\";\nimport \"./interfaces/IOldRewardsDistributionRecipient.sol\";\nimport \"./interfaces/IStakingRewards.sol\";\nimport \"./interfaces/IOldStakingRewards.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\n\n/// @custom:oz-upgrades-from KtonDAOVault\ncontract KtonDAOVaultV2 is Initializable, Ownable2StepUpgradeable {\n // \"modlda/trsry\" in bytes.\n address public constant SYSTEM_PALLET = 0x6D6f646c64612f74727372790000000000000000;\n\n address public constant OLD_KTON_STAKING_REWARDS = 0x000000000419683a1a03AbC21FC9da25fd2B4dD7;\n address public constant OLD_KTON_REWARDS_DISTRIBUTION = 0x000000000Ae5DB7BDAf8D071e680452e33d91Dd5;\n\n address public stakingRewards;\n\n modifier onlySystem() {\n require(msg.sender == SYSTEM_PALLET, \"Caller is not RewardsDistribution contract\");\n _;\n }\n\n function initializeV2() public reinitializer(2) {\n uint256 rewards = OLD_KTON_REWARDS_DISTRIBUTION.balance;\n IOldRewardsDistributionRecipient(OLD_KTON_REWARDS_DISTRIBUTION).distributeRewards(\n OLD_KTON_STAKING_REWARDS, rewards\n );\n emit RewardsDistributed(OLD_KTON_REWARDS_DISTRIBUTION, rewards);\n }\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor() {\n _disableInitializers();\n }\n\n receive() external payable {}\n\n /// Runtime migration Step:\n /// 1. Migrate OLD_KTON_REWARDS_DISTRIBUTION's owner to this contracts address.\n /// 2. distributeRewards to this contract address.\n /// Note: The amount of the reward must be passed in via msg.value.\n function distributeRewards() external payable onlySystem returns (bool) {\n uint256 reward = msg.value;\n require(reward > 0, \"Nothing to distribute\");\n require(\n address(this).balance >= reward, \"RewardsDistribution contract does not have enough tokens to distribute\"\n );\n\n uint256 oldTotalSupply = IOldStakingRewards(OLD_KTON_STAKING_REWARDS).totalSupply();\n uint256 newTotalSupply = IStakingRewards(stakingRewards).underlyingTotalSupply();\n uint256 totalSupply = oldTotalSupply + newTotalSupply;\n\n if (totalSupply == 0) {\n return true;\n }\n\n uint256 oldReward = reward * oldTotalSupply / totalSupply;\n uint256 newReward = reward - oldReward;\n\n if (oldReward > 0) {\n IOldRewardsDistributionRecipient(OLD_KTON_REWARDS_DISTRIBUTION).distributeRewards{value: oldReward}(\n OLD_KTON_STAKING_REWARDS, oldReward\n );\n emit RewardsDistributed(OLD_KTON_REWARDS_DISTRIBUTION, oldReward);\n }\n\n if (newReward > 0) {\n IRewardsDistributionRecipient(stakingRewards).notifyRewardAmount{value: newReward}();\n emit RewardsDistributed(stakingRewards, newReward);\n }\n\n return true;\n }\n\n event RewardsDistributed(address stakingRewards, uint256 amount);\n}\n"},"src/staking/interfaces/IRewardsDistributionRecipient.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity >=0.4.24;\n\ninterface IRewardsDistributionRecipient {\n function notifyRewardAmount() external payable;\n}\n"},"src/staking/interfaces/IOldRewardsDistributionRecipient.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity >=0.4.24;\n\ninterface IOldRewardsDistributionRecipient {\n function distributeRewards(address ktonStakingRewards, uint256 reward) external payable returns (bool);\n}\n"},"src/staking/interfaces/IStakingRewards.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity >=0.4.24;\n\ninterface IStakingRewards {\n // Views\n function lastTimeRewardApplicable() external view returns (uint256);\n\n function rewardPerToken() external view returns (uint256);\n\n function earned(address account) external view returns (uint256);\n\n function getRewardForDuration() external view returns (uint256);\n\n function underlying() external pure returns (address);\n\n function underlyingTotalSupply() external view returns (uint256);\n\n function underlyingBalanceOf(address account) external view returns (uint256);\n\n // Mutative\n\n function lockAndStake(uint256 amount) external;\n\n function unlockAndWithdraw(uint256 amount) external;\n\n function getReward() external;\n}\n"},"src/staking/interfaces/IOldStakingRewards.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity >=0.4.24;\n\ninterface IOldStakingRewards {\n // Views\n function lastTimeRewardApplicable() external view returns (uint256);\n\n function rewardPerToken() external view returns (uint256);\n\n function earned(address account) external view returns (uint256);\n\n function getRewardForDuration() external view returns (uint256);\n\n function totalSupply() external view returns (uint256);\n\n function balanceOf(address account) external view returns (uint256);\n\n // Mutative\n\n function stake(uint256 amount) external;\n\n function withdraw(uint256 amount) external;\n\n function getReward() external;\n\n function exit() external;\n\n function acceptOwnership() external;\n}\n"},"lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```solidity\n * contract MyToken is ERC20Upgradeable {\n * function initialize() initializer public {\n * __ERC20_init(\"MyToken\", \"MTK\");\n * }\n * }\n *\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n * function initializeV2() reinitializer(2) public {\n * __ERC20Permit_init(\"MyToken\");\n * }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n * _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n /**\n * @dev Storage of the initializable contract.\n *\n * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions\n * when using with upgradeable contracts.\n *\n * @custom:storage-location erc7201:openzeppelin.storage.Initializable\n */\n struct InitializableStorage {\n /**\n * @dev Indicates that the contract has been initialized.\n */\n uint64 _initialized;\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool _initializing;\n }\n\n // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Initializable\")) - 1)) & ~bytes32(uint256(0xff))\n bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;\n\n /**\n * @dev The contract is already initialized.\n */\n error InvalidInitialization();\n\n /**\n * @dev The contract is not initializing.\n */\n error NotInitializing();\n\n /**\n * @dev Triggered when the contract has been initialized or reinitialized.\n */\n event Initialized(uint64 version);\n\n /**\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n * `onlyInitializing` functions can be used to initialize parent contracts.\n *\n * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any\n * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in\n * production.\n *\n * Emits an {Initialized} event.\n */\n modifier initializer() {\n // solhint-disable-next-line var-name-mixedcase\n InitializableStorage storage $ = _getInitializableStorage();\n\n // Cache values to avoid duplicated sloads\n bool isTopLevelCall = !$._initializing;\n uint64 initialized = $._initialized;\n\n // Allowed calls:\n // - initialSetup: the contract is not in the initializing state and no previous version was\n // initialized\n // - construction: the contract is initialized at version 1 (no reininitialization) and the\n // current contract is just being deployed\n bool initialSetup = initialized == 0 && isTopLevelCall;\n bool construction = initialized == 1 && address(this).code.length == 0;\n\n if (!initialSetup && !construction) {\n revert InvalidInitialization();\n }\n $._initialized = 1;\n if (isTopLevelCall) {\n $._initializing = true;\n }\n _;\n if (isTopLevelCall) {\n $._initializing = false;\n emit Initialized(1);\n }\n }\n\n /**\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n * used to initialize parent contracts.\n *\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n * are added through upgrades and that require initialization.\n *\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n * cannot be nested. If one is invoked in the context of another, execution will revert.\n *\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n * a contract, executing them in the right order is up to the developer or operator.\n *\n * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.\n *\n * Emits an {Initialized} event.\n */\n modifier reinitializer(uint64 version) {\n // solhint-disable-next-line var-name-mixedcase\n InitializableStorage storage $ = _getInitializableStorage();\n\n if ($._initializing || $._initialized >= version) {\n revert InvalidInitialization();\n }\n $._initialized = version;\n $._initializing = true;\n _;\n $._initializing = false;\n emit Initialized(version);\n }\n\n /**\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\n */\n modifier onlyInitializing() {\n _checkInitializing();\n _;\n }\n\n /**\n * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.\n */\n function _checkInitializing() internal view virtual {\n if (!_isInitializing()) {\n revert NotInitializing();\n }\n }\n\n /**\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n * through proxies.\n *\n * Emits an {Initialized} event the first time it is successfully executed.\n */\n function _disableInitializers() internal virtual {\n // solhint-disable-next-line var-name-mixedcase\n InitializableStorage storage $ = _getInitializableStorage();\n\n if ($._initializing) {\n revert InvalidInitialization();\n }\n if ($._initialized != type(uint64).max) {\n $._initialized = type(uint64).max;\n emit Initialized(type(uint64).max);\n }\n }\n\n /**\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\n */\n function _getInitializedVersion() internal view returns (uint64) {\n return _getInitializableStorage()._initialized;\n }\n\n /**\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n */\n function _isInitializing() internal view returns (bool) {\n return _getInitializableStorage()._initializing;\n }\n\n /**\n * @dev Returns a pointer to the storage namespace.\n */\n // solhint-disable-next-line var-name-mixedcase\n function _getInitializableStorage() private pure returns (InitializableStorage storage $) {\n assembly {\n $.slot := INITIALIZABLE_STORAGE\n }\n }\n}\n"},"lib/openzeppelin-contracts-upgradeable/contracts/access/Ownable2StepUpgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol)\n\npragma solidity ^0.8.20;\n\nimport {OwnableUpgradeable} from \"./OwnableUpgradeable.sol\";\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which provides access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * The initial owner is specified at deployment time in the constructor for `Ownable`. This\n * can later be changed with {transferOwnership} and {acceptOwnership}.\n *\n * This module is used through inheritance. It will make available all functions\n * from parent (Ownable).\n */\nabstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {\n /// @custom:storage-location erc7201:openzeppelin.storage.Ownable2Step\n struct Ownable2StepStorage {\n address _pendingOwner;\n }\n\n // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Ownable2Step\")) - 1)) & ~bytes32(uint256(0xff))\n bytes32 private constant Ownable2StepStorageLocation = 0x237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c00;\n\n function _getOwnable2StepStorage() private pure returns (Ownable2StepStorage storage $) {\n assembly {\n $.slot := Ownable2StepStorageLocation\n }\n }\n\n event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\n\n function __Ownable2Step_init() internal onlyInitializing {\n }\n\n function __Ownable2Step_init_unchained() internal onlyInitializing {\n }\n /**\n * @dev Returns the address of the pending owner.\n */\n function pendingOwner() public view virtual returns (address) {\n Ownable2StepStorage storage $ = _getOwnable2StepStorage();\n return $._pendingOwner;\n }\n\n /**\n * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual override onlyOwner {\n Ownable2StepStorage storage $ = _getOwnable2StepStorage();\n $._pendingOwner = newOwner;\n emit OwnershipTransferStarted(owner(), newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual override {\n Ownable2StepStorage storage $ = _getOwnable2StepStorage();\n delete $._pendingOwner;\n super._transferOwnership(newOwner);\n }\n\n /**\n * @dev The new owner accepts the ownership transfer.\n */\n function acceptOwnership() public virtual {\n address sender = _msgSender();\n if (pendingOwner() != sender) {\n revert OwnableUnauthorizedAccount(sender);\n }\n _transferOwnership(sender);\n }\n}\n"},"lib/openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\n\npragma solidity ^0.8.20;\n\nimport {ContextUpgradeable} from \"../utils/ContextUpgradeable.sol\";\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * The initial owner is set to the address provided by the deployer. This can\n * later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n /// @custom:storage-location erc7201:openzeppelin.storage.Ownable\n struct OwnableStorage {\n address _owner;\n }\n\n // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Ownable\")) - 1)) & ~bytes32(uint256(0xff))\n bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;\n\n function _getOwnableStorage() private pure returns (OwnableStorage storage $) {\n assembly {\n $.slot := OwnableStorageLocation\n }\n }\n\n /**\n * @dev The caller account is not authorized to perform an operation.\n */\n error OwnableUnauthorizedAccount(address account);\n\n /**\n * @dev The owner is not a valid owner account. (eg. `address(0)`)\n */\n error OwnableInvalidOwner(address owner);\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\n */\n function __Ownable_init(address initialOwner) internal onlyInitializing {\n __Ownable_init_unchained(initialOwner);\n }\n\n function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {\n if (initialOwner == address(0)) {\n revert OwnableInvalidOwner(address(0));\n }\n _transferOwnership(initialOwner);\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n OwnableStorage storage $ = _getOwnableStorage();\n return $._owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n if (owner() != _msgSender()) {\n revert OwnableUnauthorizedAccount(_msgSender());\n }\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby disabling any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n if (newOwner == address(0)) {\n revert OwnableInvalidOwner(address(0));\n }\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n OwnableStorage storage $ = _getOwnableStorage();\n address oldOwner = $._owner;\n $._owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n"},"lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol":{"content":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract ContextUpgradeable is Initializable {\n function __Context_init() internal onlyInitializing {\n }\n\n function __Context_init_unchained() internal onlyInitializing {\n }\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n"}},"settings":{"remappings":["forge-std/=lib/forge-std/src/","@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/","@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/","solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/"],"optimizer":{"enabled":true,"runs":999999},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"":["ast"],"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata","storageLayout"]}},"evmVersion":"london","viaIR":false,"libraries":{}}}