{"file_path":"src/PSM.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/interfaces/IERC4626.sol\";\nimport {PSMFed} from \"src/PSMFed.sol\";\n\ninterface IController {\n    function onBuy(address user, address to, uint256 amount) external returns (bool);\n    function onSell(address user, address to, uint256 amount) external returns (bool);\n}\n\ncontract PSM {\n    using SafeERC20 for IERC20;\n\n    IERC20 public immutable collateral;\n    IERC20 public immutable DOLA;\n    address public immutable fed; // PSMFed contract address\n\n    address public gov;\n    address public pendingGov;\n    IController public controller; // Controller contract address\n    uint256 public buyFeeBps; // e.g., 50 = 0.5%\n    uint256 public sellFeeBps; // e.g., 50 = 0.5%\n    uint256 public constant BPS_DENOMINATOR = 10_000;\n    uint256 public supply; // Collateral supplied in the PSM (excluding fees and profit)\n    IERC4626 public vault;\n    uint256 public minTotalSupply;\n\n    event GovChanged(address indexed oldGov, address indexed newGov);\n    event PendingGovUpdated(address indexed pendingGov);\n    event ControllerChanged(address indexed oldController, address indexed newController);\n    event VaultMigrated(address indexed oldVault, address indexed newVault);\n    event BuyFeeUpdated(uint256 oldFee, uint256 newFee);\n    event SellFeeUpdated(uint256 oldFee, uint256 newFee);\n    event SupplyCapUpdated(uint256 newSupplyCap);\n    event Buy(address indexed user, uint256 purchased, uint256 spent);\n    event Sell(address indexed user, uint256 sold, uint256 received);\n    event ProfitTaken(uint256 profit);\n    event MinTotalSupplyUpdated(uint256 oldMinTotalSupply, uint256 newMinTotalSupply);\n\n    constructor(address _collateral, address _vault, address _DOLA, address _gov, address _controller, address _chair) {\n        collateral = IERC20(_collateral);\n        vault = IERC4626(_vault);\n        DOLA = IERC20(_DOLA);\n        gov = _gov;\n        controller = IController(_controller);\n        fed = address(new PSMFed(address(this), _gov, _chair, _DOLA));\n        DOLA.approve(fed, type(uint256).max);\n    }\n\n    modifier onlyGov() {\n        require(msg.sender == gov, \"Not gov\");\n        _;\n    }\n\n    /**\n     * @notice Allows to buy DOLA minus fee using collateral.\n     * @param collateralAmountIn Amount of collateral to sell for DOLA.\n     */\n    function buy(uint256 collateralAmountIn) external {\n        buy(msg.sender, collateralAmountIn);\n    }\n\n    /**\n     * @notice Allows to buy DOLA minus fee using collateral.\n     * @param to DOLA receiver.\n     * @param collateralAmountIn Amount of collateral to sell for DOLA.\n     */\n    function buy(address to, uint256 collateralAmountIn) public {\n        require(collateralAmountIn > 0, \"Amount must be > 0\");\n        require(vault.totalSupply() >= minTotalSupply, \"Min total supply not met\");\n        require(controller.onBuy(msg.sender, to, collateralAmountIn), \"Denied by controller\");\n        uint256 amountOut = collateralAmountIn;\n\n        if (buyFeeBps > 0) {\n            uint256 fee = (collateralAmountIn * buyFeeBps) / BPS_DENOMINATOR;\n            amountOut -= fee;\n        }\n        supply += amountOut;\n\n        collateral.safeTransferFrom(msg.sender, address(this), collateralAmountIn);\n        collateral.approve(address(vault), collateralAmountIn);\n        uint256 shares = vault.deposit(collateralAmountIn, address(this));\n        require(shares > 0, \"Deposit failed\");\n        DOLA.safeTransfer(to, amountOut);\n        emit Buy(msg.sender, amountOut, collateralAmountIn);\n    }\n\n    /**\n     * @notice Allows to sell DOLA for collateral minus fee.\n     * @param dolaAmountIn Amount of DOLA to sell.\n     */\n    function sell(uint256 dolaAmountIn) external {\n        sell(msg.sender, dolaAmountIn);\n    }\n\n    /**\n     * @notice Allows to sell DOLA for collateral minus fee.\n     * @param to Address to receive the collateral.\n     * @param dolaAmountIn Amount of DOLA to sell.\n     */\n    function sell(address to, uint256 dolaAmountIn) public {\n        require(dolaAmountIn > 0, \"Amount must be > 0\");\n        require(controller.onSell(msg.sender, to, dolaAmountIn), \"Denied by controller\");\n        supply -= dolaAmountIn;\n        DOLA.safeTransferFrom(msg.sender, address(this), dolaAmountIn);\n\n        uint256 amountOut = dolaAmountIn;\n\n        if (sellFeeBps > 0) {\n            uint256 fee = (dolaAmountIn * sellFeeBps) / BPS_DENOMINATOR;\n            amountOut -= fee;\n        }\n\n        vault.withdraw(amountOut, to, address(this));\n        emit Sell(msg.sender, dolaAmountIn, amountOut);\n    }\n\n    /**\n     * @notice Takes profit from the vault and transfers it to the governance address.\n     * @dev Can be called by anyone to transfer profits and fees to governance.\n     */\n    function takeProfit() public {\n        uint256 profit = getProfit();\n        if (profit > 0) {\n            vault.withdraw(profit, gov, address(this));\n        }\n        emit ProfitTaken(profit);\n    }\n\n    /**\n     * @notice Returns the total collateral reserves in the vault, including profit and fees.\n     * @return Total reserves in the vault.\n     */\n    function getTotalReserves() public view returns (uint256) {\n        return vault.previewRedeem(vault.balanceOf(address(this)));\n    }\n\n    /**\n     * @notice Returns the total profit made by the PSM.\n     * @return Total profit in the PSM.\n     */\n    function getProfit() public view returns (uint256) {\n        uint256 totalReserves = getTotalReserves();\n        return totalReserves > supply ? totalReserves - supply : 0;\n    }\n\n    /**\n     * @notice Returns the amount of DOLA that can be obtained for a given amount of collateral.\n     * @param collateralIn Amount of collateral to convert to DOLA.\n     * @return Amount of DOLA that will be received after fees.\n     */\n    function getDolaOut(uint256 collateralIn) external view returns (uint256) {\n        uint256 fee = (collateralIn * buyFeeBps) / BPS_DENOMINATOR;\n        return collateralIn - fee;\n    }\n\n    /**\n     * @notice Returns the amount of collateral that can be obtained for a given amount of DOLA.\n     * @param dolaIn Amount of DOLA to convert to collateral.\n     * @return Amount of collateral that will be received after fees.\n     */\n    function getCollateralOut(uint256 dolaIn) external view returns (uint256) {\n        uint256 fee = (dolaIn * sellFeeBps) / BPS_DENOMINATOR;\n        return dolaIn - fee;\n    }\n\n    /**\n     * @notice Migrate the vault to a new IERC4626 vault.\n     * @dev Can only be called by governance and will take profit before migration.\n     * @param newVault Address of the new vault to migrate to.\n     * @param minCollateralAmount Minimum amount of collateral to be deposited in the new vault.\n     * @param minSharesOut Minimum amount of shares to receive from the new vault.\n     */\n    function migrate(address newVault, uint256 minCollateralAmount, uint256 minSharesOut) external onlyGov {\n        require(newVault != address(0), \"Zero address\");\n        require(IERC4626(newVault).asset() == address(collateral), \"New vault must accept collateral\");\n\n        takeProfit();\n\n        if (vault.balanceOf(address(this)) != 0) {\n            vault.redeem(vault.balanceOf(address(this)), address(this), address(this));\n        }\n\n        address oldVault = address(vault);\n        vault = IERC4626(newVault);\n        require(vault.totalSupply() >= minTotalSupply, \"New vault does not meet min total supply\");\n\n        uint256 collateralBalance = collateral.balanceOf(address(this));\n        require(collateralBalance >= minCollateralAmount, \"Insufficient collateral balance for migration\");\n        if (collateralBalance > 0) {\n            collateral.approve(address(vault), collateralBalance);\n            uint256 sharesOut = vault.deposit(collateralBalance, address(this));\n            require(sharesOut >= minSharesOut, \"Insufficient shares received from new vault\");\n        }\n        emit VaultMigrated(oldVault, newVault);\n    }\n\n    /**\n     * @notice Allows governance to sweep any ERC20 tokens from the contract.\n     * @dev Can only be called by governance.\n     * @param token The ERC20 token to sweep.\n     */\n    function sweep(IERC20 token) external onlyGov {\n        token.safeTransfer(gov, token.balanceOf(address(this)));\n    }\n\n    /**\n     * @notice Allows governance to set the buy fee.\n     * @dev The fee is specified in basis points (bps), where 100 bps = 1%.\n     */\n    function setBuyFeeBps(uint256 newFee) external onlyGov {\n        require(newFee <= BPS_DENOMINATOR, \"Fee too high\");\n        emit BuyFeeUpdated(buyFeeBps, newFee);\n        buyFeeBps = newFee;\n    }\n\n    /**\n     * @notice Allows governance to set the sell fee.\n     * @dev The fee is specified in basis points (bps), where 100 bps = 1%.\n     */\n    function setSellFeeBps(uint256 newFee) external onlyGov {\n        require(newFee <= BPS_DENOMINATOR, \"Fee too high\");\n        emit SellFeeUpdated(sellFeeBps, newFee);\n        sellFeeBps = newFee;\n    }\n\n    /**\n     * @notice Allows governance to set the minimum vault total supply.\n     * @dev This is used to ensure that the vault has enough shares before allowing buy operations.\n     * @param _minTotalSupply Minimum total supply that must have been already minted in the vault.\n     */\n    function setMinTotalSupply(uint256 _minTotalSupply) external onlyGov {\n        require(_minTotalSupply > 0, \"Min total supply must be > 0\");\n        emit MinTotalSupplyUpdated(minTotalSupply, _minTotalSupply);\n        minTotalSupply = _minTotalSupply;\n    }\n\n    /**\n     * @notice Allows governance to set a new pending governance.\n     * @dev The pending governance must accept the role.\n     * @param _pendingGov Address of the new pending governance.\n     */\n    function setPendingGov(address _pendingGov) external onlyGov {\n        pendingGov = _pendingGov;\n        emit PendingGovUpdated(_pendingGov);\n    }\n\n    /**\n     * @notice Allows the pending governance to claim the governance role.\n     * @dev Can only be called by the pending governance.\n     */\n    function claimPendingGov() external {\n        require(msg.sender == pendingGov, \"Not pending gov\");\n        emit GovChanged(gov, pendingGov);\n        gov = pendingGov;\n        pendingGov = address(0);\n    }\n\n    /**\n     * @notice Allows governance to set a new controller.\n     * @dev The new controller must not be the zero address.\n     * @param newController Address of the new controller.\n     */\n    function setController(address newController) external onlyGov {\n        require(newController != address(0), \"Zero address\");\n        emit ControllerChanged(address(controller), newController);\n        controller = IController(newController);\n    }\n}\n","deployed_bytecode":"0x608060405234801561000f575f80fd5b50600436106101c6575f3560e01c806392c592d0116100fe578063e1a452181161009e578063f5d121e61161006e578063f5d121e6146103af578063f77c4791146103c2578063fbfa77cf146103d5578063fc22d0e5146103e8575f80fd5b8063e1a4521814610378578063e4849b3214610381578063efdf0bb014610394578063f0c9e465146103a7575f80fd5b8063c71a7eff116100d9578063c71a7eff14610318578063cce7ec131461032b578063d8dfeb451461033e578063d96a094a14610365575f80fd5b806392c592d0146102cb57806392eefe9b146102f2578063a0422edf14610305575f80fd5b806353d06f941161016957806370c105781161014457806370c105781461029e57806377d2300e146102a657806379db6346146102af5780639058c8a4146102b8575f80fd5b806353d06f941461025c578063679dffb4146102835780636c197ff51461028b575f80fd5b806323cbe1f3116101a457806323cbe1f314610225578063242693d31461022e578063252408101461023657806334119d1514610249575f80fd5b806301681a62146101ca578063047fc9aa146101df57806312d43a51146101fb575b5f80fd5b6101dd6101d8366004611c76565b6103fb565b005b6101e860055481565b6040519081526020015b60405180910390f35b5f5461020d906001600160a01b031681565b6040516001600160a01b0390911681526020016101f2565b6101e860045481565b6101e86104f7565b60015461020d906001600160a01b031681565b6101dd610257366004611c91565b6105e4565b61020d7f00000000000000000000000067fc21332d24fc5250a3b7fc988191ad7f38f9cc81565b6101e86106d0565b6101dd610299366004611ca8565b6106fe565b6101dd610982565b6101e860035481565b6101e860075481565b6101dd6102c6366004611c91565b610a5f565b61020d7f000000000000000000000000865377367054516e17014ccded1e7d814edc9ce481565b6101dd610300366004611c76565b610b4b565b6101e8610313366004611c91565b610c6d565b6101e8610326366004611c91565b610c9d565b6101dd610339366004611ca8565b610cb0565b61020d7f000000000000000000000000dc035d45d973e3ec169d2276ddab16f1e407384f81565b6101dd610373366004611c91565b611125565b6101e861271081565b6101dd61038f366004611c91565b61112f565b6101dd6103a2366004611c76565b611139565b6101dd6111f3565b6101dd6103bd366004611c91565b6112c7565b60025461020d906001600160a01b031681565b60065461020d906001600160a01b031681565b6101dd6103f6366004611cd2565b6113b0565b5f546001600160a01b031633146104595760405162461bcd60e51b815260206004820152600760248201527f4e6f7420676f760000000000000000000000000000000000000000000000000060448201526064015b60405180910390fd5b5f546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526104f4916001600160a01b0390811691908416906370a0823190602401602060405180830381865afa1580156104bf573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104e39190611d04565b6001600160a01b0384169190611b25565b50565b6006546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f916001600160a01b031690634cdad5069082906370a0823190602401602060405180830381865afa15801561055e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105829190611d04565b6040518263ffffffff1660e01b81526004016105a091815260200190565b602060405180830381865afa1580156105bb573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105df9190611d04565b905090565b5f546001600160a01b0316331461063d5760405162461bcd60e51b815260206004820152600760248201527f4e6f7420676f76000000000000000000000000000000000000000000000000006044820152606401610450565b61271081111561068f5760405162461bcd60e51b815260206004820152600c60248201527f46656520746f6f206869676800000000000000000000000000000000000000006044820152606401610450565b60045460408051918252602082018390527f5bafec153d96f8ef37761b64348732b41a6b477401d244a5070f9f82d689adce910160405180910390a1600455565b5f806106da6104f7565b905060055481116106eb575f6106f8565b6005546106f89082611d48565b91505090565b5f811161074d5760405162461bcd60e51b815260206004820152601260248201527f416d6f756e74206d757374206265203e203000000000000000000000000000006044820152606401610450565b6002546040517fb29431fb0000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b038481166024830152604482018490529091169063b29431fb906064016020604051808303815f875af11580156107bc573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107e09190611d61565b61082c5760405162461bcd60e51b815260206004820152601460248201527f44656e69656420627920636f6e74726f6c6c65720000000000000000000000006044820152606401610450565b8060055f82825461083d9190611d48565b9091555061087890506001600160a01b037f000000000000000000000000865377367054516e17014ccded1e7d814edc9ce416333084611b9e565b6004548190156108ae575f612710600454846108949190611d80565b61089e9190611d97565b90506108aa8183611d48565b9150505b6006546040517fb460af94000000000000000000000000000000000000000000000000000000008152600481018390526001600160a01b0385811660248301523060448301529091169063b460af94906064016020604051808303815f875af115801561091d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109419190611d04565b50604080518381526020810183905233917fed7a144fad14804d5c249145e3e0e2b63a9eb455b76aee5bc92d711e9bba3e4a910160405180910390a2505050565b5f61098b6106d0565b90508015610a29576006545f546040517fb460af94000000000000000000000000000000000000000000000000000000008152600481018490526001600160a01b03918216602482015230604482015291169063b460af94906064016020604051808303815f875af1158015610a03573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a279190611d04565b505b6040518181527f949da057e0c10ac8c590fc56cf17f0a7f8a424d6f373268e7fc205c8dcbc7bb49060200160405180910390a150565b5f546001600160a01b03163314610ab85760405162461bcd60e51b815260206004820152600760248201527f4e6f7420676f76000000000000000000000000000000000000000000000000006044820152606401610450565b612710811115610b0a5760405162461bcd60e51b815260206004820152600c60248201527f46656520746f6f206869676800000000000000000000000000000000000000006044820152606401610450565b60035460408051918252602082018390527f28e297c7c282931a994191b735b01eaf17558295f761512a7047f4e1b8dc3b0b910160405180910390a1600355565b5f546001600160a01b03163314610ba45760405162461bcd60e51b815260206004820152600760248201527f4e6f7420676f76000000000000000000000000000000000000000000000000006044820152606401610450565b6001600160a01b038116610bfa5760405162461bcd60e51b815260206004820152600c60248201527f5a65726f206164647265737300000000000000000000000000000000000000006044820152606401610450565b6002546040516001600160a01b038084169216907f6aef1fb5b23d0e109fc7f2b0601019e1edbacd177e31a441ec8548e8dd14f0f7905f90a3600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b5f8061271060035484610c809190611d80565b610c8a9190611d97565b9050610c968184611d48565b9392505050565b5f8061271060045484610c809190611d80565b5f8111610cff5760405162461bcd60e51b815260206004820152601260248201527f416d6f756e74206d757374206265203e203000000000000000000000000000006044820152606401610450565b60075460065f9054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d52573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d769190611d04565b1015610dc45760405162461bcd60e51b815260206004820152601860248201527f4d696e20746f74616c20737570706c79206e6f74206d657400000000000000006044820152606401610450565b6002546040517f1f437f9d0000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b0384811660248301526044820184905290911690631f437f9d906064016020604051808303815f875af1158015610e33573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e579190611d61565b610ea35760405162461bcd60e51b815260206004820152601460248201527f44656e69656420627920636f6e74726f6c6c65720000000000000000000000006044820152606401610450565b600354819015610ed9575f61271060035484610ebf9190611d80565b610ec99190611d97565b9050610ed58183611d48565b9150505b8060055f828254610eea9190611dcf565b90915550610f2590506001600160a01b037f000000000000000000000000dc035d45d973e3ec169d2276ddab16f1e407384f16333085611b9e565b6006546040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152602481018490527f000000000000000000000000dc035d45d973e3ec169d2276ddab16f1e407384f9091169063095ea7b3906044016020604051808303815f875af1158015610faf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fd39190611d61565b506006546040517f6e553f65000000000000000000000000000000000000000000000000000000008152600481018490523060248201525f916001600160a01b031690636e553f65906044016020604051808303815f875af115801561103b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061105f9190611d04565b90505f81116110b05760405162461bcd60e51b815260206004820152600e60248201527f4465706f736974206661696c65640000000000000000000000000000000000006044820152606401610450565b6110e46001600160a01b037f000000000000000000000000865377367054516e17014ccded1e7d814edc9ce4168584611b25565b604080518381526020810185905233917f1cbc5ab135991bd2b6a4b034a04aa2aa086dac1371cb9b16b8b5e2ed6b036bed910160405180910390a250505050565b6104f43382610cb0565b6104f433826106fe565b5f546001600160a01b031633146111925760405162461bcd60e51b815260206004820152600760248201527f4e6f7420676f76000000000000000000000000000000000000000000000000006044820152606401610450565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f0b1b3d8e19656af9f8acea883020be347ec617cada0060e56959226bb0109c49905f90a250565b6001546001600160a01b0316331461124d5760405162461bcd60e51b815260206004820152600f60248201527f4e6f742070656e64696e6720676f7600000000000000000000000000000000006044820152606401610450565b6001545f80546040516001600160a01b0393841693909116917f3d1e4c3a68fed9f4f8315582b7297cf8fa264bc8e6704287603ba8c72bf05ac291a3600180545f80547fffffffffffffffffffffffff00000000000000000000000000000000000000009081166001600160a01b03841617909155169055565b5f546001600160a01b031633146113205760405162461bcd60e51b815260206004820152600760248201527f4e6f7420676f76000000000000000000000000000000000000000000000000006044820152606401610450565b5f811161136f5760405162461bcd60e51b815260206004820152601c60248201527f4d696e20746f74616c20737570706c79206d757374206265203e2030000000006044820152606401610450565b60075460408051918252602082018390527fe9b2d6ed3a1e53a2cbc74ea1516580639c8c1a43411ca794eaa9e101c3c3dea4910160405180910390a1600755565b5f546001600160a01b031633146114095760405162461bcd60e51b815260206004820152600760248201527f4e6f7420676f76000000000000000000000000000000000000000000000000006044820152606401610450565b6001600160a01b03831661145f5760405162461bcd60e51b815260206004820152600c60248201527f5a65726f206164647265737300000000000000000000000000000000000000006044820152606401610450565b7f000000000000000000000000dc035d45d973e3ec169d2276ddab16f1e407384f6001600160a01b0316836001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114c5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114e99190611de2565b6001600160a01b03161461153f5760405162461bcd60e51b815260206004820181905260248201527f4e6577207661756c74206d7573742061636365707420636f6c6c61746572616c6044820152606401610450565b611547610982565b6006546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156115a6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115ca9190611d04565b156116e0576006546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b039091169063ba0876529082906370a0823190602401602060405180830381865afa158015611636573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061165a9190611d04565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526004810191909152306024820181905260448201526064016020604051808303815f875af11580156116ba573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116de9190611d04565b505b600680547fffffffffffffffffffffffff000000000000000000000000000000000000000081166001600160a01b03868116918217909355600754604080517f18160ddd0000000000000000000000000000000000000000000000000000000081529051949093169390926318160ddd9160048083019260209291908290030181865afa158015611773573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117979190611d04565b101561180b5760405162461bcd60e51b815260206004820152602860248201527f4e6577207661756c7420646f6573206e6f74206d656574206d696e20746f746160448201527f6c20737570706c790000000000000000000000000000000000000000000000006064820152608401610450565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f907f000000000000000000000000dc035d45d973e3ec169d2276ddab16f1e407384f6001600160a01b0316906370a0823190602401602060405180830381865afa158015611888573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118ac9190611d04565b9050838110156119245760405162461bcd60e51b815260206004820152602d60248201527f496e73756666696369656e7420636f6c6c61746572616c2062616c616e63652060448201527f666f72206d6967726174696f6e000000000000000000000000000000000000006064820152608401610450565b8015611ade576006546040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152602481018390527f000000000000000000000000dc035d45d973e3ec169d2276ddab16f1e407384f9091169063095ea7b3906044016020604051808303815f875af11580156119b4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119d89190611d61565b506006546040517f6e553f65000000000000000000000000000000000000000000000000000000008152600481018390523060248201525f916001600160a01b031690636e553f65906044016020604051808303815f875af1158015611a40573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a649190611d04565b905083811015611adc5760405162461bcd60e51b815260206004820152602b60248201527f496e73756666696369656e74207368617265732072656365697665642066726f60448201527f6d206e6577207661756c740000000000000000000000000000000000000000006064820152608401610450565b505b846001600160a01b0316826001600160a01b03167faa10add0ff0f23b874d2d1fa353ab28a639aa51906dec303238cdb1f1e54ea4260405160405180910390a35050505050565b6040516001600160a01b03838116602483015260448201839052611b9991859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050611bdd565b505050565b6040516001600160a01b038481166024830152838116604483015260648201839052611bd79186918216906323b872dd90608401611b52565b50505050565b5f8060205f8451602086015f885af180611bfc576040513d5f823e3d81fd5b50505f513d91508115611c13578060011415611c20565b6001600160a01b0384163b155b15611bd7576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401610450565b6001600160a01b03811681146104f4575f80fd5b5f60208284031215611c86575f80fd5b8135610c9681611c62565b5f60208284031215611ca1575f80fd5b5035919050565b5f8060408385031215611cb9575f80fd5b8235611cc481611c62565b946020939093013593505050565b5f805f60608486031215611ce4575f80fd5b8335611cef81611c62565b95602085013595506040909401359392505050565b5f60208284031215611d14575f80fd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b81810381811115611d5b57611d5b611d1b565b92915050565b5f60208284031215611d71575f80fd5b81518015158114610c96575f80fd5b8082028115828204841417611d5b57611d5b611d1b565b5f82611dca577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b80820180821115611d5b57611d5b611d1b565b5f60208284031215611df2575f80fd5b8151610c9681611c6256fea2646970667358221220fb094be55e618a2b326be9cb9c850683abaf8c7ae48d41e110708f81340d4efe64736f6c63430008140033","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"shanghai","libraries":{},"metadata":{"bytecodeHash":"ipfs"},"optimizer":{"enabled":true,"runs":10000},"remappings":[":@openzeppelin/contracts/=lib/openzeppelin/contracts/",":forge-std/=lib/forge-std/src/",":openzeppelin/=lib/openzeppelin/",":solmate/=lib/solmate/src/"]},"optimization_runs":10000,"sourcify_repo_url":"https://repo.sourcify.dev/contracts/full_match/1/0x1d02f2841afA3Cc20435a8c804C24dEaC5F30DFa/","decoded_constructor_args":[["0xdC035D45d973E3EC169d2276DDab16f1e407384F",{"internalType":"address","name":"_collateral","type":"address"}],["0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD",{"internalType":"address","name":"_vault","type":"address"}],["0x865377367054516e17014CcdED1e7d814EDC9ce4",{"internalType":"address","name":"_DOLA","type":"address"}],["0x926dF14a23BE491164dCF93f4c468A50ef659D5B",{"internalType":"address","name":"_gov","type":"address"}],["0xE3475728673eAbaeC90A37AA3ae2cEd9f0DB5Ff2",{"internalType":"address","name":"_controller","type":"address"}],["0x8F97cCA30Dbe80e7a8B462F1dD1a51C32accDfC8",{"internalType":"address","name":"_chair","type":"address"}]],"compiler_version":"0.8.20+commit.a1b79de6","is_verified_via_verifier_alliance":false,"verified_at":"2026-01-20T19:39:40.182870Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x60e060405234801562000010575f80fd5b5060405162002efe38038062002efe833981016040819052620000339162000188565b6001600160a01b03868116608052600680546001600160a01b03199081168884161790915585821660a0525f805482168684161790556002805490911691841691909117905560405130908490839087906200008f906200015e565b6001600160a01b039485168152928416602084015290831660408301529091166060820152608001604051809103905ff080158015620000d1573d5f803e3d5ffd5b506001600160a01b0390811660c081905260a05160405163095ea7b360e01b815260048101929092525f1960248301529091169063095ea7b3906044016020604051808303815f875af11580156200012b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062000151919062000205565b505050505050506200022d565b610e4280620020bc83390190565b80516001600160a01b038116811462000183575f80fd5b919050565b5f805f805f8060c087890312156200019e575f80fd5b620001a9876200016c565b9550620001b9602088016200016c565b9450620001c9604088016200016c565b9350620001d9606088016200016c565b9250620001e9608088016200016c565b9150620001f960a088016200016c565b90509295509295509295565b5f6020828403121562000216575f80fd5b8151801515811462000226575f80fd5b9392505050565b60805160a05160c051611e33620002895f395f61026101525f81816102d00152818161085001526110bd01525f818161034301528181610efd01528181610f67015281816114610152818161183b015261196c0152611e335ff3fe608060405234801561000f575f80fd5b50600436106101c6575f3560e01c806392c592d0116100fe578063e1a452181161009e578063f5d121e61161006e578063f5d121e6146103af578063f77c4791146103c2578063fbfa77cf146103d5578063fc22d0e5146103e8575f80fd5b8063e1a4521814610378578063e4849b3214610381578063efdf0bb014610394578063f0c9e465146103a7575f80fd5b8063c71a7eff116100d9578063c71a7eff14610318578063cce7ec131461032b578063d8dfeb451461033e578063d96a094a14610365575f80fd5b806392c592d0146102cb57806392eefe9b146102f2578063a0422edf14610305575f80fd5b806353d06f941161016957806370c105781161014457806370c105781461029e57806377d2300e146102a657806379db6346146102af5780639058c8a4146102b8575f80fd5b806353d06f941461025c578063679dffb4146102835780636c197ff51461028b575f80fd5b806323cbe1f3116101a457806323cbe1f314610225578063242693d31461022e578063252408101461023657806334119d1514610249575f80fd5b806301681a62146101ca578063047fc9aa146101df57806312d43a51146101fb575b5f80fd5b6101dd6101d8366004611c76565b6103fb565b005b6101e860055481565b6040519081526020015b60405180910390f35b5f5461020d906001600160a01b031681565b6040516001600160a01b0390911681526020016101f2565b6101e860045481565b6101e86104f7565b60015461020d906001600160a01b031681565b6101dd610257366004611c91565b6105e4565b61020d7f000000000000000000000000000000000000000000000000000000000000000081565b6101e86106d0565b6101dd610299366004611ca8565b6106fe565b6101dd610982565b6101e860035481565b6101e860075481565b6101dd6102c6366004611c91565b610a5f565b61020d7f000000000000000000000000000000000000000000000000000000000000000081565b6101dd610300366004611c76565b610b4b565b6101e8610313366004611c91565b610c6d565b6101e8610326366004611c91565b610c9d565b6101dd610339366004611ca8565b610cb0565b61020d7f000000000000000000000000000000000000000000000000000000000000000081565b6101dd610373366004611c91565b611125565b6101e861271081565b6101dd61038f366004611c91565b61112f565b6101dd6103a2366004611c76565b611139565b6101dd6111f3565b6101dd6103bd366004611c91565b6112c7565b60025461020d906001600160a01b031681565b60065461020d906001600160a01b031681565b6101dd6103f6366004611cd2565b6113b0565b5f546001600160a01b031633146104595760405162461bcd60e51b815260206004820152600760248201527f4e6f7420676f760000000000000000000000000000000000000000000000000060448201526064015b60405180910390fd5b5f546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526104f4916001600160a01b0390811691908416906370a0823190602401602060405180830381865afa1580156104bf573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104e39190611d04565b6001600160a01b0384169190611b25565b50565b6006546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f916001600160a01b031690634cdad5069082906370a0823190602401602060405180830381865afa15801561055e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105829190611d04565b6040518263ffffffff1660e01b81526004016105a091815260200190565b602060405180830381865afa1580156105bb573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105df9190611d04565b905090565b5f546001600160a01b0316331461063d5760405162461bcd60e51b815260206004820152600760248201527f4e6f7420676f76000000000000000000000000000000000000000000000000006044820152606401610450565b61271081111561068f5760405162461bcd60e51b815260206004820152600c60248201527f46656520746f6f206869676800000000000000000000000000000000000000006044820152606401610450565b60045460408051918252602082018390527f5bafec153d96f8ef37761b64348732b41a6b477401d244a5070f9f82d689adce910160405180910390a1600455565b5f806106da6104f7565b905060055481116106eb575f6106f8565b6005546106f89082611d48565b91505090565b5f811161074d5760405162461bcd60e51b815260206004820152601260248201527f416d6f756e74206d757374206265203e203000000000000000000000000000006044820152606401610450565b6002546040517fb29431fb0000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b038481166024830152604482018490529091169063b29431fb906064016020604051808303815f875af11580156107bc573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107e09190611d61565b61082c5760405162461bcd60e51b815260206004820152601460248201527f44656e69656420627920636f6e74726f6c6c65720000000000000000000000006044820152606401610450565b8060055f82825461083d9190611d48565b9091555061087890506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016333084611b9e565b6004548190156108ae575f612710600454846108949190611d80565b61089e9190611d97565b90506108aa8183611d48565b9150505b6006546040517fb460af94000000000000000000000000000000000000000000000000000000008152600481018390526001600160a01b0385811660248301523060448301529091169063b460af94906064016020604051808303815f875af115801561091d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109419190611d04565b50604080518381526020810183905233917fed7a144fad14804d5c249145e3e0e2b63a9eb455b76aee5bc92d711e9bba3e4a910160405180910390a2505050565b5f61098b6106d0565b90508015610a29576006545f546040517fb460af94000000000000000000000000000000000000000000000000000000008152600481018490526001600160a01b03918216602482015230604482015291169063b460af94906064016020604051808303815f875af1158015610a03573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a279190611d04565b505b6040518181527f949da057e0c10ac8c590fc56cf17f0a7f8a424d6f373268e7fc205c8dcbc7bb49060200160405180910390a150565b5f546001600160a01b03163314610ab85760405162461bcd60e51b815260206004820152600760248201527f4e6f7420676f76000000000000000000000000000000000000000000000000006044820152606401610450565b612710811115610b0a5760405162461bcd60e51b815260206004820152600c60248201527f46656520746f6f206869676800000000000000000000000000000000000000006044820152606401610450565b60035460408051918252602082018390527f28e297c7c282931a994191b735b01eaf17558295f761512a7047f4e1b8dc3b0b910160405180910390a1600355565b5f546001600160a01b03163314610ba45760405162461bcd60e51b815260206004820152600760248201527f4e6f7420676f76000000000000000000000000000000000000000000000000006044820152606401610450565b6001600160a01b038116610bfa5760405162461bcd60e51b815260206004820152600c60248201527f5a65726f206164647265737300000000000000000000000000000000000000006044820152606401610450565b6002546040516001600160a01b038084169216907f6aef1fb5b23d0e109fc7f2b0601019e1edbacd177e31a441ec8548e8dd14f0f7905f90a3600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b5f8061271060035484610c809190611d80565b610c8a9190611d97565b9050610c968184611d48565b9392505050565b5f8061271060045484610c809190611d80565b5f8111610cff5760405162461bcd60e51b815260206004820152601260248201527f416d6f756e74206d757374206265203e203000000000000000000000000000006044820152606401610450565b60075460065f9054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d52573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d769190611d04565b1015610dc45760405162461bcd60e51b815260206004820152601860248201527f4d696e20746f74616c20737570706c79206e6f74206d657400000000000000006044820152606401610450565b6002546040517f1f437f9d0000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b0384811660248301526044820184905290911690631f437f9d906064016020604051808303815f875af1158015610e33573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e579190611d61565b610ea35760405162461bcd60e51b815260206004820152601460248201527f44656e69656420627920636f6e74726f6c6c65720000000000000000000000006044820152606401610450565b600354819015610ed9575f61271060035484610ebf9190611d80565b610ec99190611d97565b9050610ed58183611d48565b9150505b8060055f828254610eea9190611dcf565b90915550610f2590506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016333085611b9e565b6006546040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152602481018490527f00000000000000000000000000000000000000000000000000000000000000009091169063095ea7b3906044016020604051808303815f875af1158015610faf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fd39190611d61565b506006546040517f6e553f65000000000000000000000000000000000000000000000000000000008152600481018490523060248201525f916001600160a01b031690636e553f65906044016020604051808303815f875af115801561103b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061105f9190611d04565b90505f81116110b05760405162461bcd60e51b815260206004820152600e60248201527f4465706f736974206661696c65640000000000000000000000000000000000006044820152606401610450565b6110e46001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168584611b25565b604080518381526020810185905233917f1cbc5ab135991bd2b6a4b034a04aa2aa086dac1371cb9b16b8b5e2ed6b036bed910160405180910390a250505050565b6104f43382610cb0565b6104f433826106fe565b5f546001600160a01b031633146111925760405162461bcd60e51b815260206004820152600760248201527f4e6f7420676f76000000000000000000000000000000000000000000000000006044820152606401610450565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f0b1b3d8e19656af9f8acea883020be347ec617cada0060e56959226bb0109c49905f90a250565b6001546001600160a01b0316331461124d5760405162461bcd60e51b815260206004820152600f60248201527f4e6f742070656e64696e6720676f7600000000000000000000000000000000006044820152606401610450565b6001545f80546040516001600160a01b0393841693909116917f3d1e4c3a68fed9f4f8315582b7297cf8fa264bc8e6704287603ba8c72bf05ac291a3600180545f80547fffffffffffffffffffffffff00000000000000000000000000000000000000009081166001600160a01b03841617909155169055565b5f546001600160a01b031633146113205760405162461bcd60e51b815260206004820152600760248201527f4e6f7420676f76000000000000000000000000000000000000000000000000006044820152606401610450565b5f811161136f5760405162461bcd60e51b815260206004820152601c60248201527f4d696e20746f74616c20737570706c79206d757374206265203e2030000000006044820152606401610450565b60075460408051918252602082018390527fe9b2d6ed3a1e53a2cbc74ea1516580639c8c1a43411ca794eaa9e101c3c3dea4910160405180910390a1600755565b5f546001600160a01b031633146114095760405162461bcd60e51b815260206004820152600760248201527f4e6f7420676f76000000000000000000000000000000000000000000000000006044820152606401610450565b6001600160a01b03831661145f5760405162461bcd60e51b815260206004820152600c60248201527f5a65726f206164647265737300000000000000000000000000000000000000006044820152606401610450565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114c5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114e99190611de2565b6001600160a01b03161461153f5760405162461bcd60e51b815260206004820181905260248201527f4e6577207661756c74206d7573742061636365707420636f6c6c61746572616c6044820152606401610450565b611547610982565b6006546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156115a6573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115ca9190611d04565b156116e0576006546040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b039091169063ba0876529082906370a0823190602401602060405180830381865afa158015611636573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061165a9190611d04565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526004810191909152306024820181905260448201526064016020604051808303815f875af11580156116ba573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116de9190611d04565b505b600680547fffffffffffffffffffffffff000000000000000000000000000000000000000081166001600160a01b03868116918217909355600754604080517f18160ddd0000000000000000000000000000000000000000000000000000000081529051949093169390926318160ddd9160048083019260209291908290030181865afa158015611773573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117979190611d04565b101561180b5760405162461bcd60e51b815260206004820152602860248201527f4e6577207661756c7420646f6573206e6f74206d656574206d696e20746f746160448201527f6c20737570706c790000000000000000000000000000000000000000000000006064820152608401610450565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015611888573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118ac9190611d04565b9050838110156119245760405162461bcd60e51b815260206004820152602d60248201527f496e73756666696369656e7420636f6c6c61746572616c2062616c616e63652060448201527f666f72206d6967726174696f6e000000000000000000000000000000000000006064820152608401610450565b8015611ade576006546040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b039182166004820152602481018390527f00000000000000000000000000000000000000000000000000000000000000009091169063095ea7b3906044016020604051808303815f875af11580156119b4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119d89190611d61565b506006546040517f6e553f65000000000000000000000000000000000000000000000000000000008152600481018390523060248201525f916001600160a01b031690636e553f65906044016020604051808303815f875af1158015611a40573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a649190611d04565b905083811015611adc5760405162461bcd60e51b815260206004820152602b60248201527f496e73756666696369656e74207368617265732072656365697665642066726f60448201527f6d206e6577207661756c740000000000000000000000000000000000000000006064820152608401610450565b505b846001600160a01b0316826001600160a01b03167faa10add0ff0f23b874d2d1fa353ab28a639aa51906dec303238cdb1f1e54ea4260405160405180910390a35050505050565b6040516001600160a01b03838116602483015260448201839052611b9991859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050611bdd565b505050565b6040516001600160a01b038481166024830152838116604483015260648201839052611bd79186918216906323b872dd90608401611b52565b50505050565b5f8060205f8451602086015f885af180611bfc576040513d5f823e3d81fd5b50505f513d91508115611c13578060011415611c20565b6001600160a01b0384163b155b15611bd7576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401610450565b6001600160a01b03811681146104f4575f80fd5b5f60208284031215611c86575f80fd5b8135610c9681611c62565b5f60208284031215611ca1575f80fd5b5035919050565b5f8060408385031215611cb9575f80fd5b8235611cc481611c62565b946020939093013593505050565b5f805f60608486031215611ce4575f80fd5b8335611cef81611c62565b95602085013595506040909401359392505050565b5f60208284031215611d14575f80fd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b81810381811115611d5b57611d5b611d1b565b92915050565b5f60208284031215611d71575f80fd5b81518015158114610c96575f80fd5b8082028115828204841417611d5b57611d5b611d1b565b5f82611dca577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b80820180821115611d5b57611d5b611d1b565b5f60208284031215611df2575f80fd5b8151610c9681611c6256fea2646970667358221220fb094be55e618a2b326be9cb9c850683abaf8c7ae48d41e110708f81340d4efe64736f6c6343000814003360c060405234801561000f575f80fd5b50604051610e42380380610e4283398101604081905261002e91610087565b6001600160a01b039384166080525f80549385166001600160a01b03199485161790556002805492851692909316919091179091551660a0526100d8565b80516001600160a01b0381168114610082575f80fd5b919050565b5f805f806080858703121561009a575f80fd5b6100a38561006c565b93506100b16020860161006c565b92506100bf6040860161006c565b91506100cd6060860161006c565b905092959194509250565b60805160a051610d2661011c5f395f81816101bb0152818161043a015281816107f7015261089101525f818161010a0152818161040b01526107c20152610d265ff3fe608060405234801561000f575f80fd5b50600436106100e5575f3560e01c806392c592d011610088578063ee1ef57511610063578063ee1ef57514610203578063efdf0bb014610216578063f0c9e46514610229578063fdf893f514610231575f80fd5b806392c592d0146101b6578063b6a3f59a146101dd578063e1a611b7146101f0575f80fd5b806325240810116100c357806325240810146101705780632720b22e1461019057806369652fcf146101a55780638f770ad0146101ad575f80fd5b8063047fc9aa146100e957806304bda2621461010557806312d43a5114610151575b5f80fd5b6100f260035481565b6040519081526020015b60405180910390f35b61012c7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100fc565b5f5461012c9073ffffffffffffffffffffffffffffffffffffffff1681565b60015461012c9073ffffffffffffffffffffffffffffffffffffffff1681565b6101a361019e366004610c27565b610251565b005b6101a36104cd565b6100f260045481565b61012c7f000000000000000000000000000000000000000000000000000000000000000081565b6101a36101eb366004610c27565b6105c0565b6101a36101fe366004610c27565b610685565b6101a3610211366004610c3e565b61092e565b6101a3610224366004610c3e565b610a24565b6101a3610b12565b60025461012c9073ffffffffffffffffffffffffffffffffffffffff1681565b60025473ffffffffffffffffffffffffffffffffffffffff1633146102d7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4e6f74206368616972000000000000000000000000000000000000000000000060448201526064015b60405180910390fd5b5f8111610340576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f416d6f756e74206d757374206265203e2030000000000000000000000000000060448201526064016102ce565b6004546003546103509083610ca5565b11156103b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f537570706c79206361702065786365656465640000000000000000000000000060448201526064016102ce565b8060035f8282546103c99190610ca5565b90915550506040517f40c10f1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018390527f000000000000000000000000000000000000000000000000000000000000000016906340c10f19906044015f604051808303815f87803b15801561047b575f80fd5b505af115801561048d573d5f803e3d5ffd5b505050507fdcc16fd18a808d877bcd9a09b544844b36ae8f0a4b222e317d7b777b2c18b032816040516104c291815260200190565b60405180910390a150565b60025473ffffffffffffffffffffffffffffffffffffffff16331461054e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4e6f74206368616972000000000000000000000000000000000000000000000060448201526064016102ce565b600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000811690915560405173ffffffffffffffffffffffffffffffffffffffff909116905f9082907f0a47357b37b43edfce3b49e26d073c29be56d40a540f4766153a6169d031e86e908390a350565b5f5473ffffffffffffffffffffffffffffffffffffffff163314610640576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e6f7420676f7665726e616e636500000000000000000000000000000000000060448201526064016102ce565b600480549082905560408051828152602081018490527fb4d96b3a6638191d0f6aefa0fdc4d99af3592f4c97480e31feeb977723c63b53910160405180910390a15050565b60025473ffffffffffffffffffffffffffffffffffffffff163314610706576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4e6f74206368616972000000000000000000000000000000000000000000000060448201526064016102ce565b5f811161076f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f416d6f756e74206d757374206265203e2030000000000000000000000000000060448201526064016102ce565b8060035f8282546107809190610cbe565b90915550506040517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000081166004830152306024830152604482018390527f000000000000000000000000000000000000000000000000000000000000000016906323b872dd906064016020604051808303815f875af115801561083d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108619190610cd1565b506040517f42966c68000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906342966c68906024015f604051808303815f87803b1580156108e7575f80fd5b505af11580156108f9573d5f803e3d5ffd5b505050507f32d275175c36fa468b3e61c6763f9488ff3c9be127e35e011cf4e04d602224ba816040516104c291815260200190565b5f5473ffffffffffffffffffffffffffffffffffffffff1633146109ae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e6f7420676f7665726e616e636500000000000000000000000000000000000060448201526064016102ce565b6002805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f0a47357b37b43edfce3b49e26d073c29be56d40a540f4766153a6169d031e86e905f90a35050565b5f5473ffffffffffffffffffffffffffffffffffffffff163314610aa4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f4e6f7420676f7665726e616e636500000000000000000000000000000000000060448201526064016102ce565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f0b1b3d8e19656af9f8acea883020be347ec617cada0060e56959226bb0109c49905f90a250565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b93576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f4e6f742070656e64696e6720676f76000000000000000000000000000000000060448201526064016102ce565b6001545f805460405173ffffffffffffffffffffffffffffffffffffffff93841693909116917f3d1e4c3a68fed9f4f8315582b7297cf8fa264bc8e6704287603ba8c72bf05ac291a3600180545f80547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff841617909155169055565b5f60208284031215610c37575f80fd5b5035919050565b5f60208284031215610c4e575f80fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610c71575f80fd5b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610cb857610cb8610c78565b92915050565b81810381811115610cb857610cb8610c78565b5f60208284031215610ce1575f80fd5b81518015158114610c71575f80fdfea264697066735822122036b7c9aa871b3c4aeaafcd7a910dc3a6d174e44d38a46c9060d0681b6bac34a064736f6c63430008140033000000000000000000000000dc035d45d973e3ec169d2276ddab16f1e407384f000000000000000000000000a3931d71877c0e7a3148cb7eb4463524fec27fbd000000000000000000000000865377367054516e17014ccded1e7d814edc9ce4000000000000000000000000926df14a23be491164dcf93f4c468a50ef659d5b000000000000000000000000e3475728673eabaec90a37aa3ae2ced9f0db5ff20000000000000000000000008f97cca30dbe80e7a8b462f1dd1a51c32accdfc8","name":"PSM","is_blueprint":false,"license_type":"none","is_fully_verified":true,"is_verified_via_eth_bytecode_db":true,"language":"solidity","evm_version":"shanghai","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":true,"additional_sources":[{"file_path":"lib/openzeppelin/contracts/utils/introspection/IERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC-165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[ERC].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"},{"file_path":"lib/openzeppelin/contracts/interfaces/IERC1363.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"./IERC20.sol\";\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @title IERC1363\n * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].\n *\n * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract\n * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.\n */\ninterface IERC1363 is IERC20, IERC165 {\n    /*\n     * Note: the ERC-165 identifier for this interface is 0xb0202a11.\n     * 0xb0202a11 ===\n     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^\n     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^\n     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^\n     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^\n     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^\n     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))\n     */\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferAndCall(address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @param data Additional data with no specified format, sent in call to `to`.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param from The address which you want to send tokens from.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param from The address which you want to send tokens from.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @param data Additional data with no specified format, sent in call to `to`.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n     * @param spender The address which will spend the funds.\n     * @param value The amount of tokens to be spent.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function approveAndCall(address spender, uint256 value) external returns (bool);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n     * @param spender The address which will spend the funds.\n     * @param value The amount of tokens to be spent.\n     * @param data Additional data with no specified format, sent in call to `spender`.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);\n}\n"},{"file_path":"lib/openzeppelin/contracts/interfaces/IERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"../utils/introspection/IERC165.sol\";\n"},{"file_path":"lib/openzeppelin/contracts/interfaces/IERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\n"},{"file_path":"lib/openzeppelin/contracts/interfaces/IERC4626.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (interfaces/IERC4626.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\nimport {IERC20Metadata} from \"../token/ERC20/extensions/IERC20Metadata.sol\";\n\n/**\n * @dev Interface of the ERC-4626 \"Tokenized Vault Standard\", as defined in\n * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].\n */\ninterface IERC4626 is IERC20, IERC20Metadata {\n    event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);\n\n    event Withdraw(\n        address indexed sender,\n        address indexed receiver,\n        address indexed owner,\n        uint256 assets,\n        uint256 shares\n    );\n\n    /**\n     * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.\n     *\n     * - MUST be an ERC-20 token contract.\n     * - MUST NOT revert.\n     */\n    function asset() external view returns (address assetTokenAddress);\n\n    /**\n     * @dev Returns the total amount of the underlying asset that is “managed” by Vault.\n     *\n     * - SHOULD include any compounding that occurs from yield.\n     * - MUST be inclusive of any fees that are charged against assets in the Vault.\n     * - MUST NOT revert.\n     */\n    function totalAssets() external view returns (uint256 totalManagedAssets);\n\n    /**\n     * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal\n     * scenario where all the conditions are met.\n     *\n     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n     * - MUST NOT show any variations depending on the caller.\n     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n     * - MUST NOT revert.\n     *\n     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n     * from.\n     */\n    function convertToShares(uint256 assets) external view returns (uint256 shares);\n\n    /**\n     * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal\n     * scenario where all the conditions are met.\n     *\n     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.\n     * - MUST NOT show any variations depending on the caller.\n     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.\n     * - MUST NOT revert.\n     *\n     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the\n     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and\n     * from.\n     */\n    function convertToAssets(uint256 shares) external view returns (uint256 assets);\n\n    /**\n     * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,\n     * through a deposit call.\n     *\n     * - MUST return a limited value if receiver is subject to some deposit limit.\n     * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.\n     * - MUST NOT revert.\n     */\n    function maxDeposit(address receiver) external view returns (uint256 maxAssets);\n\n    /**\n     * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given\n     * current on-chain conditions.\n     *\n     * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit\n     *   call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called\n     *   in the same transaction.\n     * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the\n     *   deposit would be accepted, regardless if the user has enough tokens approved, etc.\n     * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n     * - MUST NOT revert.\n     *\n     * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in\n     * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n     */\n    function previewDeposit(uint256 assets) external view returns (uint256 shares);\n\n    /**\n     * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.\n     *\n     * - MUST emit the Deposit event.\n     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n     *   deposit execution, and are accounted for during deposit.\n     * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not\n     *   approving enough underlying tokens to the Vault contract, etc).\n     *\n     * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n     */\n    function deposit(uint256 assets, address receiver) external returns (uint256 shares);\n\n    /**\n     * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.\n     * - MUST return a limited value if receiver is subject to some mint limit.\n     * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.\n     * - MUST NOT revert.\n     */\n    function maxMint(address receiver) external view returns (uint256 maxShares);\n\n    /**\n     * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given\n     * current on-chain conditions.\n     *\n     * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call\n     *   in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the\n     *   same transaction.\n     * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint\n     *   would be accepted, regardless if the user has enough tokens approved, etc.\n     * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.\n     * - MUST NOT revert.\n     *\n     * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in\n     * share price or some other type of condition, meaning the depositor will lose assets by minting.\n     */\n    function previewMint(uint256 shares) external view returns (uint256 assets);\n\n    /**\n     * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.\n     *\n     * - MUST emit the Deposit event.\n     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint\n     *   execution, and are accounted for during mint.\n     * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not\n     *   approving enough underlying tokens to the Vault contract, etc).\n     *\n     * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.\n     */\n    function mint(uint256 shares, address receiver) external returns (uint256 assets);\n\n    /**\n     * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the\n     * Vault, through a withdraw call.\n     *\n     * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n     * - MUST NOT revert.\n     */\n    function maxWithdraw(address owner) external view returns (uint256 maxAssets);\n\n    /**\n     * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,\n     * given current on-chain conditions.\n     *\n     * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw\n     *   call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if\n     *   called\n     *   in the same transaction.\n     * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though\n     *   the withdrawal would be accepted, regardless if the user has enough shares, etc.\n     * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n     * - MUST NOT revert.\n     *\n     * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in\n     * share price or some other type of condition, meaning the depositor will lose assets by depositing.\n     */\n    function previewWithdraw(uint256 assets) external view returns (uint256 shares);\n\n    /**\n     * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.\n     *\n     * - MUST emit the Withdraw event.\n     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n     *   withdraw execution, and are accounted for during withdraw.\n     * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner\n     *   not having enough shares, etc).\n     *\n     * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n     * Those methods should be performed separately.\n     */\n    function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);\n\n    /**\n     * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,\n     * through a redeem call.\n     *\n     * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.\n     * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.\n     * - MUST NOT revert.\n     */\n    function maxRedeem(address owner) external view returns (uint256 maxShares);\n\n    /**\n     * @dev Allows an on-chain or off-chain user to simulate the effects of their redemption at the current block,\n     * given current on-chain conditions.\n     *\n     * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call\n     *   in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the\n     *   same transaction.\n     * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the\n     *   redemption would be accepted, regardless if the user has enough shares, etc.\n     * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.\n     * - MUST NOT revert.\n     *\n     * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in\n     * share price or some other type of condition, meaning the depositor will lose assets by redeeming.\n     */\n    function previewRedeem(uint256 shares) external view returns (uint256 assets);\n\n    /**\n     * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.\n     *\n     * - MUST emit the Withdraw event.\n     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the\n     *   redeem execution, and are accounted for during redeem.\n     * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner\n     *   not having enough shares, etc).\n     *\n     * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.\n     * Those methods should be performed separately.\n     */\n    function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);\n}\n"},{"file_path":"lib/openzeppelin/contracts/token/ERC20/IERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC-20 standard as defined in the ERC.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the value of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the value of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the\n     * allowance mechanism. `value` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"},{"file_path":"lib/openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC-20 standard.\n */\ninterface IERC20Metadata is IERC20 {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"},{"file_path":"lib/openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\nimport {IERC1363} from \"../../../interfaces/IERC1363.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC-20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    /**\n     * @dev An operation with an ERC-20 token failed.\n     */\n    error SafeERC20FailedOperation(address token);\n\n    /**\n     * @dev Indicates a failed `decreaseAllowance` request.\n     */\n    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n    /**\n     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeTransfer(IERC20 token, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n    }\n\n    /**\n     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n     */\n    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n    }\n\n    /**\n     * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.\n     */\n    function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {\n        return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));\n    }\n\n    /**\n     * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.\n     */\n    function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {\n        return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n    }\n\n    /**\n     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     *\n     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n     * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n     */\n    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        uint256 oldAllowance = token.allowance(address(this), spender);\n        forceApprove(token, spender, oldAllowance + value);\n    }\n\n    /**\n     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n     * value, non-reverting calls are assumed to be successful.\n     *\n     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n     * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n     */\n    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n        unchecked {\n            uint256 currentAllowance = token.allowance(address(this), spender);\n            if (currentAllowance < requestedDecrease) {\n                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n            }\n            forceApprove(token, spender, currentAllowance - requestedDecrease);\n        }\n    }\n\n    /**\n     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n     * to be set to zero before setting it to a non-zero value, such as USDT.\n     *\n     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function\n     * only sets the \"standard\" allowance. Any temporary allowance will remain active, in addition to the value being\n     * set here.\n     */\n    function forceApprove(IERC20 token, address spender, uint256 value) internal {\n        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n        if (!_callOptionalReturnBool(token, approvalCall)) {\n            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n            _callOptionalReturn(token, approvalCall);\n        }\n    }\n\n    /**\n     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no\n     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n     * targeting contracts.\n     *\n     * Reverts if the returned value is other than `true`.\n     */\n    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n        if (to.code.length == 0) {\n            safeTransfer(token, to, value);\n        } else if (!token.transferAndCall(to, value, data)) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target\n     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n     * targeting contracts.\n     *\n     * Reverts if the returned value is other than `true`.\n     */\n    function transferFromAndCallRelaxed(\n        IERC1363 token,\n        address from,\n        address to,\n        uint256 value,\n        bytes memory data\n    ) internal {\n        if (to.code.length == 0) {\n            safeTransferFrom(token, from, to, value);\n        } else if (!token.transferFromAndCall(from, to, value, data)) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no\n     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n     * targeting contracts.\n     *\n     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.\n     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}\n     * once without retrying, and relies on the returned value to be true.\n     *\n     * Reverts if the returned value is other than `true`.\n     */\n    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n        if (to.code.length == 0) {\n            forceApprove(token, to, value);\n        } else if (!token.approveAndCall(to, value, data)) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.\n     */\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        uint256 returnSize;\n        uint256 returnValue;\n        assembly (\"memory-safe\") {\n            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n            // bubble errors\n            if iszero(success) {\n                let ptr := mload(0x40)\n                returndatacopy(ptr, 0, returndatasize())\n                revert(ptr, returndatasize())\n            }\n            returnSize := returndatasize()\n            returnValue := mload(0)\n        }\n\n        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.\n     */\n    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n        bool success;\n        uint256 returnSize;\n        uint256 returnValue;\n        assembly (\"memory-safe\") {\n            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n            returnSize := returndatasize()\n            returnValue := mload(0)\n        }\n        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);\n    }\n}\n"},{"file_path":"src/PSMFed.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface IDOLA is IERC20 {\n    function mint(address to, uint256 amount) external;\n    function burn(uint256 amount) external;\n}\n\ncontract PSMFed {\n    address public immutable psm;\n    IDOLA public immutable DOLA;\n\n    address public gov;\n    address public pendingGov;\n    address public chair;\n    uint256 public supply; // Current DOLA amount supplied to the PSM\n    uint256 public supplyCap; // Maximum DOLA supply allowed in the PSM\n\n    event GovChanged(address indexed oldGov, address indexed newGov);\n    event PendingGovUpdated(address indexed pendingGov);\n    event ChairChanged(address indexed oldChair, address indexed newChair);\n    event SupplyCapUpdated(uint256 oldSupplyCap, uint256 newSupplyCap);\n    event Expansion(uint256 amount);\n    event Contraction(uint256 amount);\n\n    constructor(address _psm, address _gov, address _chair, address _dola) {\n        psm = _psm;\n        gov = _gov;\n        chair = _chair;\n        DOLA = IDOLA(_dola);\n    }\n\n    modifier onlyGov() {\n        require(msg.sender == gov, \"Not governance\");\n        _;\n    }\n\n    modifier onlyChair() {\n        require(msg.sender == chair, \"Not chair\");\n        _;\n    }\n\n    /**\n     * @notice Allows the chair to expand the supply of DOLA in the PSM.\n     * @dev This function increases the supply of DOLA in the PSM and mints\n     * the specified amount of DOLA.\n     * @dev The amount must be greater than zero and cannot exceed the supply cap.\n     * @param amount The amount of DOLA to expand.\n     */\n    function expansion(uint256 amount) external onlyChair {\n        require(amount > 0, \"Amount must be > 0\");\n        require(amount + supply <= supplyCap, \"Supply cap exceeded\");\n        supply += amount;\n        DOLA.mint(psm, amount);\n        emit Expansion(amount);\n    }\n\n    /**\n     * @notice Allows the chair to contract the supply of DOLA in the PSM.\n     * @dev This function reduces the supply of DOLA in the PSM and burns the\n     * specified amount of DOLA.\n     * @dev The amount must be greater than zero and cannot exceed the current supply.\n     * @param amount The amount of DOLA to contract.\n     */\n    function contraction(uint256 amount) external onlyChair {\n        require(amount > 0, \"Amount must be > 0\");\n        supply -= amount;\n        DOLA.transferFrom(psm, address(this), amount);\n        DOLA.burn(amount);\n        emit Contraction(amount);\n    }\n\n    /**\n     * @notice Allows governance to set a new supply cap.\n     * @param newSupplyCap The new supply cap for DOLA in the PSM.\n     */\n    function setSupplyCap(uint256 newSupplyCap) external onlyGov {\n        uint256 oldSupplyCap = supplyCap;\n        supplyCap = newSupplyCap;\n        emit SupplyCapUpdated(oldSupplyCap, newSupplyCap);\n    }\n\n    /**\n     * @notice Allows governance to set a new chair.\n     * @dev The new chair must not be the zero address.\n     * @param newChair Address of the new chair.\n     */\n    function setChair(address newChair) external onlyGov {\n        address oldChair = chair;\n        chair = newChair;\n        emit ChairChanged(oldChair, newChair);\n    }\n\n    /**\n     * @notice Allows the current chair to resign.\n     * @dev The chair can resign, leaving the chair address as zero.\n     */\n    function resign() external onlyChair {\n        address oldChair = chair;\n        chair = address(0);\n        emit ChairChanged(oldChair, address(0));\n    }\n\n    /**\n     * @notice Allows governance to set a new pending governance.\n     * @dev The pending governance must accept the role.\n     * @param _pendingGov Address of the new pending governance.\n     */\n    function setPendingGov(address _pendingGov) external onlyGov {\n        pendingGov = _pendingGov;\n        emit PendingGovUpdated(_pendingGov);\n    }\n\n    /**\n     * @notice Allows the pending governance to claim the governance role.\n     * @dev Can only be called by the pending governance.\n     */\n    function claimPendingGov() external {\n        require(msg.sender == pendingGov, \"Not pending gov\");\n        emit GovChanged(gov, pendingGov);\n        gov = pendingGov;\n        pendingGov = address(0);\n    }\n}\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[{"internalType":"address","name":"_collateral","type":"address"},{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_DOLA","type":"address"},{"internalType":"address","name":"_gov","type":"address"},{"internalType":"address","name":"_controller","type":"address"},{"internalType":"address","name":"_chair","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"purchased","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"spent","type":"uint256"}],"name":"Buy","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"BuyFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldController","type":"address"},{"indexed":true,"internalType":"address","name":"newController","type":"address"}],"name":"ControllerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldGov","type":"address"},{"indexed":true,"internalType":"address","name":"newGov","type":"address"}],"name":"GovChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldMinTotalSupply","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMinTotalSupply","type":"uint256"}],"name":"MinTotalSupplyUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingGov","type":"address"}],"name":"PendingGovUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"profit","type":"uint256"}],"name":"ProfitTaken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"sold","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"received","type":"uint256"}],"name":"Sell","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"SellFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newSupplyCap","type":"uint256"}],"name":"SupplyCapUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldVault","type":"address"},{"indexed":true,"internalType":"address","name":"newVault","type":"address"}],"name":"VaultMigrated","type":"event"},{"inputs":[],"name":"BPS_DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOLA","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"collateralAmountIn","type":"uint256"}],"name":"buy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"collateralAmountIn","type":"uint256"}],"name":"buy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"buyFeeBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimPendingGov","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"collateral","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"controller","outputs":[{"internalType":"contract IController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fed","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"dolaIn","type":"uint256"}],"name":"getCollateralOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"collateralIn","type":"uint256"}],"name":"getDolaOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getProfit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gov","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newVault","type":"address"},{"internalType":"uint256","name":"minCollateralAmount","type":"uint256"},{"internalType":"uint256","name":"minSharesOut","type":"uint256"}],"name":"migrate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"minTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingGov","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"dolaAmountIn","type":"uint256"}],"name":"sell","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"dolaAmountIn","type":"uint256"}],"name":"sell","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sellFeeBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"setBuyFeeBps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newController","type":"address"}],"name":"setController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minTotalSupply","type":"uint256"}],"name":"setMinTotalSupply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_pendingGov","type":"address"}],"name":"setPendingGov","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"setSellFeeBps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"supply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"sweep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"takeProfit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"contract IERC4626","name":"","type":"address"}],"stateMutability":"view","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":false,"constructor_args":"0x000000000000000000000000dc035d45d973e3ec169d2276ddab16f1e407384f000000000000000000000000a3931d71877c0e7a3148cb7eb4463524fec27fbd000000000000000000000000865377367054516e17014ccded1e7d814edc9ce4000000000000000000000000926df14a23be491164dcf93f4c468a50ef659d5b000000000000000000000000e3475728673eabaec90a37aa3ae2ced9f0db5ff20000000000000000000000008f97cca30dbe80e7a8b462f1dd1a51c32accdfc8"}