diff --git a/contracts/MigrateMaha.sol b/contracts/MigrateMaha.sol new file mode 100644 index 0000000..ea917ae --- /dev/null +++ b/contracts/MigrateMaha.sol @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: GPL-3.0 + +// ███╗ ███╗ █████╗ ██╗ ██╗ █████╗ +// ████╗ ████║██╔══██╗██║ ██║██╔══██╗ +// ██╔████╔██║███████║███████║███████║ +// ██║╚██╔╝██║██╔══██║██╔══██║██╔══██║ +// ██║ ╚═╝ ██║██║ ██║██║ ██║██║ ██║ +// ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ + +// Website: https://maha.xyz +// Discord: https://discord.gg/mahadao +// Twitter: https://twitter.com/mahaxyz_ + +pragma solidity 0.8.21; + +import {ILocker} from "./interfaces/governance/ILocker.sol"; +import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; +import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; +import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; +import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {MerkleProof} from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; + +/** + * @title MigratorMaha + * @notice This contract facilitates the migration of locked assets and distributes bonus MAHA tokens to eligible users. + * @dev Implements migration functionality using a Merkle tree for verification and interacts with an ILocker contract. + * Includes features such as pausing, owner control, and token refunds. + */ +contract MigratorMaha is Ownable2StepUpgradeable, PausableUpgradeable, ReentrancyGuardUpgradeable { + using SafeERC20 for IERC20; + + /// @notice Merkle root used to verify the migration eligibility of users. + bytes32 public merkleRoot; + + /// @notice Address of the MAHA token contract used for bonus distribution. + IERC20 public maha; + + /// @notice Address of the ILocker contract for lock creation. + ILocker public locker; + + /// @notice Tracks whether an NFT ID has already been migrated. + mapping(uint256 => bool) public isTokenIdMigrated; + + // -------------------- Errors -------------------- + + /// @notice Thrown when attempting to migrate an already migrated NFT ID. + /// @param nftId The ID of the NFT that was already migrated. + error AlreadyMigrated(uint256 nftId); + + /// @notice Thrown when the migration process fails. + /// @param nftId The ID of the NFT for which migration failed. + error MigrationFailed(uint256 nftId); + + /// @notice Thrown when an invalid or zero NFT ID is provided. + /// @param nftId The invalid NFT ID. + error InvalidTokenId(uint256 nftId); + + /// @notice Thrown when an invalid Merkle proof is submitted. + /// @param proof The invalid Merkle proof. + error InvalidMerkleProof(bytes32[] proof); + + /// @notice Thrown when a zero address is provided where an address is required. + error InvalidZeroAddress(); + + /// @notice Thrown when the lock's end time is already expired or invalid. + /// @param endTime The invalid end time provided. + error EndTimeExpired(uint256 endTime); + + // -------------------- Events -------------------- + + /** + * @notice Event emitted when a migration is successfully completed. + * @param user The address of the user who migrated. + * @param nftId The ID of the NFT issued to the user. + * @param bonus The amount of bonus MAHA tokens distributed. + */ + event Migrated(address indexed user, uint256 indexed nftId, uint256 bonus); + + /** + * @notice Event emitted when the Merkle root is updated. + * @param oldMerkleRoot The previous Merkle root. + * @param newMerkleRoot The new Merkle root. + */ + event MerkleRootUpdated(bytes32 oldMerkleRoot, bytes32 newMerkleRoot); + + // -------------------- Functions -------------------- + + /** + * @notice Initializes the contract with initial values. + * @param _merkleRoot The Merkle root for verifying eligibility. + * @param _maha The MAHA token contract address. + * @param _locker The ILocker contract address. + */ + function initialize(bytes32 _merkleRoot, IERC20 _maha, ILocker _locker) external initializer { + __Ownable_init(msg.sender); + __Pausable_init(); + merkleRoot = _merkleRoot; + maha = _maha; + locker = _locker; + } + + /** + * @notice Facilitates the migration of locked assets. + * @param _user The address of the user initiating the migration. + * @param _nftId The ID of the NFT to be migrated. + * @param _mahaLocked The amount of MAHA tokens to be locked. + * @param _startTime The start time of the lock. + * @param _endTime The end time of the lock. + * @param _mahaBonus The amount of bonus MAHA tokens to be distributed. + * @param _stakeNFT Whether to stake the NFT or not. + * @param proof The Merkle proof verifying the user's eligibility. + * @dev Emits a `Migrated` event upon success. + * Reverts with appropriate errors for invalid data or migration conditions. + */ + function migrateLock( + address _user, + uint256 _nftId, + uint256 _mahaLocked, + uint256 _startTime, + uint256 _endTime, + uint256 _mahaBonus, + bool _stakeNFT, + bytes32[] calldata proof + ) external nonReentrant whenNotPaused { + _migrateLock(_user, _nftId, _mahaLocked, _startTime, _endTime, _mahaBonus, _stakeNFT, proof); + } + + /** + * @notice Verifies the validity of a migration lock using the Merkle tree. + * @param _user The user's address. + * @param _nftId The NFT ID. + * @param _mahaLocked The amount of locked MAHA tokens. + * @param _startTime The lock's start time. + * @param _endTime The lock's end time. + * @param _mahaBonus The bonus MAHA tokens. + * @param _proof The Merkle proof. + * @return bool Returns `true` if the lock is valid, otherwise reverts. + */ + function isValidLock( + address _user, + uint256 _nftId, + uint256 _mahaLocked, + uint256 _startTime, + uint256 _endTime, + uint256 _mahaBonus, + bytes32[] calldata _proof + ) public view returns (bool) { + bytes32 leaf = keccak256(abi.encodePacked(_user, _nftId, _mahaLocked, _startTime, _endTime, _mahaBonus)); + if (!MerkleProof.verify(_proof, merkleRoot, leaf)) { + revert InvalidMerkleProof(_proof); + } + return true; + } + + /** + * @notice Updates the Merkle root used for migration verification. + * @param _newMerkleRoot The new Merkle root. + * @dev Only callable by the owner. Emits a `MerkleRootUpdated` event. + */ + function updateMerkleRoot( + bytes32 _newMerkleRoot + ) external onlyOwner { + bytes32 oldMerkleRoot = merkleRoot; + merkleRoot = _newMerkleRoot; + emit MerkleRootUpdated(oldMerkleRoot, _newMerkleRoot); + } + + /** + * @notice Toggles the paused state of the contract. + * @dev Only callable by the owner. Pauses or unpauses the contract. + */ + function togglePause() external onlyOwner { + if (paused()) _unpause(); + else _pause(); + } + + /** + * @notice Refunds the contract's token balance to the owner. + * @param token The ERC20 token to refund. + * @dev Transfers the entire token balance of the contract to the owner. + */ + function refund( + IERC20 token + ) external onlyOwner { + token.safeTransfer(msg.sender, token.balanceOf(address(this))); + } + + /** + * @dev Internal function to handle migration logic. + * @param _user The address of the user initiating the migration. + * @param _nftId The ID of the NFT to be migrated. + * @param _mahaLocked The amount of MAHA tokens to be locked. + * @param _startTime The start time of the lock. + * @param _endTime The end time of the lock. + * @param _mahaBonus The amount of bonus MAHA tokens to be distributed. + * @param _stakeNFT Whether to stake the NFT or not. + * @param proof The Merkle proof verifying the user's eligibility. + */ + function _migrateLock( + address _user, + uint256 _nftId, + uint256 _mahaLocked, + uint256 _startTime, + uint256 _endTime, + uint256 _mahaBonus, + bool _stakeNFT, + bytes32[] calldata proof + ) internal { + if (_user == address(0)) { + revert InvalidZeroAddress(); + } + if (isTokenIdMigrated[_nftId]) { + revert AlreadyMigrated(_nftId); + } + if (_nftId == 0) { + revert InvalidTokenId(_nftId); + } + if (_endTime < (block.timestamp + 2 weeks)) { + revert EndTimeExpired(_endTime); + } + + isValidLock(_user, _nftId, _mahaLocked, _startTime, _endTime, _mahaBonus, proof); + uint256 _lockDuration = _endTime - block.timestamp; + + uint256 tokenId = locker.createLockFor(_mahaLocked, _lockDuration, _user, _stakeNFT); + + if (tokenId == 0) { + revert MigrationFailed(tokenId); + } + + isTokenIdMigrated[_nftId] = true; + + if (_mahaBonus > 0) maha.safeTransfer(msg.sender, _mahaBonus); + + emit Migrated(_user, _nftId, _mahaBonus); + } +} diff --git a/contracts/interfaces/core/IPegStabilityModuleYield.sol b/contracts/interfaces/core/IPegStabilityModuleYield.sol new file mode 100644 index 0000000..6c4eca0 --- /dev/null +++ b/contracts/interfaces/core/IPegStabilityModuleYield.sol @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity 0.8.21; + +import {IStablecoin} from "../IStablecoin.sol"; +import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; + +/** + * @title Peg Stability Module Yield Interface + * @dev Interface for the Peg Stability Module that allows minting USDz using ERC4626-compatible collateral, supporting yield generation. + * Enables minting and redeeming of USDz, adjusting caps, rates, and fees, and collecting yield. + * @notice This interface defines the functions to mint and redeem USDz at a pre-defined rate using yield-bearing collateral. + * @custom:author maha.xyz + */ +interface IPegStabilityModuleYield { + /** + * @notice Returns the USDz stablecoin. + * @return usdz The address of the USDz stablecoin contract. + */ + function usdz() external returns (IStablecoin); + + /** + * @notice Returns the ERC4626-compatible collateral token. + * @return collateral The address of the collateral token contract. + */ + function collateral() external returns (IERC4626); + + /** + * @notice Returns the maximum allowable supply of USDz. + * @return supplyCap The maximum supply of USDz. + */ + function supplyCap() external returns (uint256); + + /** + * @notice Returns the maximum allowable debt in USDz. + * @return debtCap The maximum debt limit for USDz. + */ + function debtCap() external returns (uint256); + + /** + * @notice Returns the current debt held by the module in USDz. + * @return debt The current amount of debt in USDz. + */ + function debt() external returns (uint256); + + /** + * @notice Returns the current exchange rate of USDz to collateral. + * @return rate The current rate of USDz/Collateral. + */ + function rate() external returns (uint256); + + /** + * @notice Returns the minting fee in basis points (BPS). + * @return mintFeeBps The mint fee in BPS. + */ + function mintFeeBps() external returns (uint256); + + /** + * @notice Returns the address where collected fees are sent. + * @return feeCollector The address designated to collect fees. + */ + function feeDistributor() external returns (address); + + /** + * @notice Returns the redeem fee in basis points (BPS). + * @return redeemFeeBps The redeem fee in BPS. + */ + function redeemFeeBps() external returns (uint256); + + // /** + // * @notice Returns the maximum fee limit in BPS that can be charged. + // * @return MAX_FEE_BPS The maximum allowable fee in BPS. + // */ + // function MAX_FEE_BPS() external returns (uint256); + + /** + * @notice Mints USDz using collateral. + * @dev Calculates the amount of collateral required for minting the specified USDz. + * @param destination The address receiving the minted USDz. + * @param shares The amount of USDz to mint. + */ + function mint(address destination, uint256 shares) external; + + /** + * @notice Redeems USDz in exchange for collateral. + * @dev Calculates the amount of collateral to be provided for the redeemed USDz. + * @param destination The address receiving the collateral. + * @param shares The amount of USDz to redeem. + */ + function redeem(address destination, uint256 shares) external; + + /** + * @notice Updates the supply and debt caps. + * @dev Restricted to the contract's administrator. + * @param _supplyCap The new supply cap for USDz. + * @param _debtCap The new debt cap for USDz. + */ + function updateCaps(uint256 _supplyCap, uint256 _debtCap) external; + + /** + * @notice Updates the exchange rate between USDz and collateral. + * @dev Restricted to the contract's administrator. + * @param _newRate The new rate of USDz/Collateral. + */ + function updateRate(uint256 _newRate) external; + + /** + * @notice Converts an amount of USDz to its equivalent collateral value. + * @param _amount The amount of USDz. + * @return collateralAmount The equivalent collateral amount. + */ + function toCollateralAmount( + uint256 _amount + ) external view returns (uint256 collateralAmount); + + /** + * @notice Converts an amount of USDz to collateral with fees included. + * @dev Fee is calculated as (amount * (MAX_FEE_BPS + fee)) / MAX_FEE_BPS. + * @param _amount The amount of USDz. + * @param _fee The fee in BPS to be added. + * @return The collateral amount with fees included. + */ + function toCollateralAmountWithFee( + uint256 _amount, + uint256 _fee + ) external view returns (uint256); + + /** + * @notice Converts an amount of USDz to collateral with fees excluded. + * @dev Fee is calculated as (amount * (MAX_FEE_BPS - fee)) / MAX_FEE_BPS. + * @param _amount The amount of USDz. + * @param _fee The fee in BPS to be subtracted. + * @return The collateral amount with fees excluded. + */ + function toCollateralAmountWithFeeInverse( + uint256 _amount, + uint256 _fee + ) external view returns (uint256); + + /** + * @notice Calculates the USDz amount to mint for a given collateral input. + * @param amountAssetsIn The collateral amount. + * @return shares The corresponding USDz amount to mint. + */ + function mintAmountIn( + uint256 amountAssetsIn + ) external view returns (uint256 shares); + + /** + * @notice Calculates the USDz amount to redeem for a given collateral output. + * @param amountAssetsOut The collateral amount. + * @return shares The corresponding USDz amount to redeem. + */ + function redeemAmountOut( + uint256 amountAssetsOut + ) external view returns (uint256 shares); + + /** + * @notice Returns the total fees collected by the protocol in USDz. + * @return fees The amount of fees collected. + */ + function feesCollected() external view returns (uint256 fees); + + /** + * @notice Updates the minting and redeeming fees. + * @param _mintFeeBps The new mint fee in BPS. + * @param _redeemFeeBps The new redeem fee in BPS. + */ + function updateFees(uint256 _mintFeeBps, uint256 _redeemFeeBps) external; + + /** + * @notice Updates the address for fee collection. + * @dev Restricted to the contract's administrator. + * @param _feeCollector The new fee collector address. + */ + function updateFeeDistributor(address _feeCollector) external; + + /** + * @notice Initializes the Peg Stability Module with necessary parameters. + * @param usdz_ The USDz stablecoin address. + * @param collateral_ The collateral token address. + * @param governance_ The governance address. + * @param newRate_ The initial USDz/Collateral rate. + * @param supplyCap_ The initial supply cap. + * @param debtCap_ The initial debt cap. + * @param mintFeeBps_ The mint fee in BPS. + * @param redeemFeeBps_ The redeem fee in BPS. + * @param feeCollector_ The initial fee collection address. + */ + function initialize( + address usdz_, + address collateral_, + address governance_, + uint256 newRate_, + uint256 supplyCap_, + uint256 debtCap_, + uint256 mintFeeBps_, + uint256 redeemFeeBps_, + address feeCollector_ + ) external; + + /** + * @notice Transfers accumulated yield to the designated fee distributor. + * + */ + function transferYieldToFeeDistributor() external; +} diff --git a/contracts/periphery/BuyBackBurnMaha.sol b/contracts/periphery/BuyBackBurnMaha.sol index df10c00..6f3f97f 100644 --- a/contracts/periphery/BuyBackBurnMaha.sol +++ b/contracts/periphery/BuyBackBurnMaha.sol @@ -17,8 +17,7 @@ contract BuyBackBurnMaha is AccessControlUpgradeable { bytes32 public constant DISTRIBUTOR_ROLE = keccak256("DISTRIBUTOR_ROLE"); /// @notice Address representing the burn address (tokens sent here are considered burned). - address public constant DEAD_ADDRESS = - 0x0000000000000000000000000000000000000000; + address public constant DEAD_ADDRESS = 0x0000000000000000000000000000000000000000; /// @notice Address of the ODOS router used for swapping USDC to MAHA. address public odos; @@ -36,19 +35,13 @@ contract BuyBackBurnMaha is AccessControlUpgradeable { * @param _odos Address of the ODOS router used for swaps. * @param _distributor Address to be assigned the DISTRIBUTOR_ROLE. */ - function initialize( - address _maha, - address _usdc, - address _odos, - address _distributor - ) external initializer { + function initialize(address _maha, address _usdc, address _odos, address _distributor) external initializer { __AccessControl_init(); maha = IERC20(_maha); usdc = IERC20(_usdc); - - setOdos(_odos); _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); _grantRole(DISTRIBUTOR_ROLE, _distributor); + setOdos(_odos); } /** @@ -56,7 +49,9 @@ contract BuyBackBurnMaha is AccessControlUpgradeable { * @dev Only callable by an account with the DEFAULT_ADMIN_ROLE. * @param _newOdos New address of the ODOS router. */ - function setOdos(address _newOdos) public onlyRole(DEFAULT_ADMIN_ROLE) { + function setOdos( + address _newOdos + ) public onlyRole(DEFAULT_ADMIN_ROLE) { odos = _newOdos; } @@ -67,13 +62,10 @@ contract BuyBackBurnMaha is AccessControlUpgradeable { * @param odosData Encoded data for the ODOS router call to perform the swap. * @param amount How much USDC you want ODOS router to swap */ - function buyMahaBurn( - bytes calldata odosData, - uint256 amount - ) external payable onlyRole(DISTRIBUTOR_ROLE) { + function buyMahaBurn(bytes calldata odosData, uint256 amount) external payable onlyRole(DISTRIBUTOR_ROLE) { IERC20(usdc).approve(odos, amount); - (bool ok, ) = odos.call{value: msg.value}(odosData); + (bool ok,) = odos.call{value: msg.value}(odosData); require(ok, "odos call failed"); uint256 mahaBalanceAfterSwap = IERC20(maha).balanceOf(address(this)); @@ -88,7 +80,9 @@ contract BuyBackBurnMaha is AccessControlUpgradeable { * @dev Only callable by an account with the DEFAULT_ADMIN_ROLE. * @param token The ERC20 token to be refunded. */ - function refund(IERC20 token) external onlyRole(DEFAULT_ADMIN_ROLE) { + function refund( + IERC20 token + ) external onlyRole(DEFAULT_ADMIN_ROLE) { token.safeTransfer(msg.sender, token.balanceOf(address(this))); } } diff --git a/deploy/base/deploy-buyback-burn.ts b/deploy/base/deploy-buyback-burn.ts new file mode 100644 index 0000000..e8612d4 --- /dev/null +++ b/deploy/base/deploy-buyback-burn.ts @@ -0,0 +1,27 @@ +import { HardhatRuntimeEnvironment } from "hardhat/types"; +import assert = require("assert"); +import { deployProxy } from "../../scripts/utils"; + +async function main(hre: HardhatRuntimeEnvironment) { + assert(hre.network.name === "base", "Wrong network"); + const { deployments, getNamedAccounts } = hre; + const { deployer } = await getNamedAccounts(); + const ODOS_ROUTER_BASE = "0x19cEeAd7105607Cd444F5ad10dd51356436095a1"; + const MAHA = await deployments.get("MAHA"); + const USDC = await deployments.get("USDC"); + const ProxyAdmin = await deployments.get("ProxyAdmin"); + const DISTRIBUTOR = deployer; + + const BuyBackBurnProxy = await deployProxy( + hre, + "BuyBackBurnMaha", + [MAHA.address, USDC.address, ODOS_ROUTER_BASE, DISTRIBUTOR], + ProxyAdmin.address, + "BuyBackBurnMaha" + ); + + console.log(`BuyBack Burn contract deployed to ${BuyBackBurnProxy.address}`); +} + +main.tags = ["BuyBackBurn"]; +export default main; diff --git a/deployments/base/BuyBackBurnMaha-Impl.json b/deployments/base/BuyBackBurnMaha-Impl.json new file mode 100644 index 0000000..3ceff9b --- /dev/null +++ b/deployments/base/BuyBackBurnMaha-Impl.json @@ -0,0 +1,632 @@ +{ + "address": "0xf18B779F5b8Fe17A97df07F0c32915E68D1AE145", + "abi": [ + { + "inputs": [], + "name": "AccessControlBadConfirmation", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "neededRole", + "type": "bytes32" + } + ], + "name": "AccessControlUnauthorizedAccount", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "AddressEmptyCode", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "AddressInsufficientBalance", + "type": "error" + }, + { + "inputs": [], + "name": "FailedInnerCall", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidInitialization", + "type": "error" + }, + { + "inputs": [], + "name": "NotInitializing", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "SafeERC20FailedOperation", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "version", + "type": "uint64" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" + } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleRevoked", + "type": "event" + }, + { + "inputs": [], + "name": "DEAD_ADDRESS", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DISTRIBUTOR_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "odosData", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "buyMahaBurn", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleAdmin", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_maha", + "type": "address" + }, + { + "internalType": "address", + "name": "_usdc", + "type": "address" + }, + { + "internalType": "address", + "name": "_odos", + "type": "address" + }, + { + "internalType": "address", + "name": "_distributor", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "maha", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "odos", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + } + ], + "name": "refund", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "callerConfirmation", + "type": "address" + } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newOdos", + "type": "address" + } + ], + "name": "setOdos", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "usdc", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0x31c65c8d518950810dd0babf2ab8ef59ac85b6ea265453c32323852e9c14cf12", + "receipt": { + "to": null, + "from": "0x5A61eD1eC946068E261694E85fe017F3BF3FF76e", + "contractAddress": "0xf18B779F5b8Fe17A97df07F0c32915E68D1AE145", + "transactionIndex": 73, + "gasUsed": "844410", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xb2e96743d7b88c68b0bfc02bc4af1141e2d5d0fc03b9e2e5984fb6cbb809ecf2", + "transactionHash": "0x31c65c8d518950810dd0babf2ab8ef59ac85b6ea265453c32323852e9c14cf12", + "logs": [], + "blockNumber": 23000465, + "cumulativeGasUsed": "17266743", + "status": 1, + "byzantium": true + }, + "args": [], + "numDeployments": 1, + "solcInputHash": "872ab92c9be5f3ce4c8080b4611e0262", + "metadata": "{\"compiler\":{\"version\":\"0.8.21+commit.d9974bed\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"AccessControlBadConfirmation\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"neededRole\",\"type\":\"bytes32\"}],\"name\":\"AccessControlUnauthorizedAccount\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"AddressInsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidInitialization\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotInitializing\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SafeERC20FailedOperation\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"version\",\"type\":\"uint64\"}],\"name\":\"Initialized\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"previousAdminRole\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"newAdminRole\",\"type\":\"bytes32\"}],\"name\":\"RoleAdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleGranted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"}],\"name\":\"RoleRevoked\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEAD_ADDRESS\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEFAULT_ADMIN_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DISTRIBUTOR_ROLE\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"odosData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"buyMahaBurn\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"}],\"name\":\"getRoleAdmin\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"grantRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"hasRole\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_maha\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_usdc\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_odos\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_distributor\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maha\",\"outputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"odos\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"refund\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"callerConfirmation\",\"type\":\"address\"}],\"name\":\"renounceRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"role\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"revokeRole\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_newOdos\",\"type\":\"address\"}],\"name\":\"setOdos\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"usdc\",\"outputs\":[{\"internalType\":\"contract IERC20\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"This contract facilitates the buy-back and burning of MAHA tokens using USDC. It leverages a specified ODOS router for token swaps and allows only authorized distributors to perform buy-back and burn operations.\",\"errors\":{\"AccessControlBadConfirmation()\":[{\"details\":\"The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\"}],\"AccessControlUnauthorizedAccount(address,bytes32)\":[{\"details\":\"The `account` is missing a role.\"}],\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"AddressInsufficientBalance(address)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"InvalidInitialization()\":[{\"details\":\"The contract is already initialized.\"}],\"NotInitializing()\":[{\"details\":\"The contract is not initializing.\"}],\"SafeERC20FailedOperation(address)\":[{\"details\":\"An operation with an ERC20 token failed.\"}]},\"events\":{\"Initialized(uint64)\":{\"details\":\"Triggered when the contract has been initialized or reinitialized.\"},\"RoleAdminChanged(bytes32,bytes32,bytes32)\":{\"details\":\"Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this.\"},\"RoleGranted(bytes32,address,address)\":{\"details\":\"Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}.\"},\"RoleRevoked(bytes32,address,address)\":{\"details\":\"Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)\"}},\"kind\":\"dev\",\"methods\":{\"buyMahaBurn(bytes,uint256)\":{\"details\":\"Only callable by an account with the DISTRIBUTOR_ROLE. Swaps USDC for MAHA through the ODOS router and sends the MAHA to the burn address.\",\"params\":{\"amount\":\"How much USDC you want ODOS router to swap\",\"odosData\":\"Encoded data for the ODOS router call to perform the swap.\"}},\"getRoleAdmin(bytes32)\":{\"details\":\"Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}.\"},\"grantRole(bytes32,address)\":{\"details\":\"Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event.\"},\"hasRole(bytes32,address)\":{\"details\":\"Returns `true` if `account` has been granted `role`.\"},\"initialize(address,address,address,address)\":{\"params\":{\"_distributor\":\"Address to be assigned the DISTRIBUTOR_ROLE.\",\"_maha\":\"Address of the MAHA token contract.\",\"_odos\":\"Address of the ODOS router used for swaps.\",\"_usdc\":\"Address of the USDC token contract.\"}},\"refund(address)\":{\"details\":\"Only callable by an account with the DEFAULT_ADMIN_ROLE.\",\"params\":{\"token\":\"The ERC20 token to be refunded.\"}},\"renounceRole(bytes32,address)\":{\"details\":\"Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event.\"},\"revokeRole(bytes32,address)\":{\"details\":\"Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event.\"},\"setOdos(address)\":{\"details\":\"Only callable by an account with the DEFAULT_ADMIN_ROLE.\",\"params\":{\"_newOdos\":\"New address of the ODOS router.\"}},\"supportsInterface(bytes4)\":{\"details\":\"See {IERC165-supportsInterface}.\"}},\"title\":\"BuyBackBurnMaha\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"DEAD_ADDRESS()\":{\"notice\":\"Address representing the burn address (tokens sent here are considered burned).\"},\"DISTRIBUTOR_ROLE()\":{\"notice\":\"Role identifier for accounts authorized to initiate buy-back and burn operations.\"},\"buyMahaBurn(bytes,uint256)\":{\"notice\":\"Executes the buy-back and burn operation.\"},\"initialize(address,address,address,address)\":{\"notice\":\"Initializes the contract with MAHA and USDC token addresses, ODOS router address, and distributor role.\"},\"maha()\":{\"notice\":\"The MAHA token contract.\"},\"odos()\":{\"notice\":\"Address of the ODOS router used for swapping USDC to MAHA.\"},\"refund(address)\":{\"notice\":\"Refunds the specified token balance held by the contract to the caller.\"},\"setOdos(address)\":{\"notice\":\"Updates the address of the ODOS router.\"},\"usdc()\":{\"notice\":\"The USDC token contract.\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/periphery/BuyBackBurnMaha.sol\":\"BuyBackBurnMaha\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":100},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\\n\\npragma solidity ^0.8.20;\\n\\nimport {IAccessControl} from \\\"@openzeppelin/contracts/access/IAccessControl.sol\\\";\\nimport {ContextUpgradeable} from \\\"../utils/ContextUpgradeable.sol\\\";\\nimport {ERC165Upgradeable} from \\\"../utils/introspection/ERC165Upgradeable.sol\\\";\\nimport {Initializable} from \\\"../proxy/utils/Initializable.sol\\\";\\n\\n/**\\n * @dev Contract module that allows children to implement role-based access\\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\\n * members except through off-chain means by accessing the contract event logs. Some\\n * applications may benefit from on-chain enumerability, for those cases see\\n * {AccessControlEnumerable}.\\n *\\n * Roles are referred to by their `bytes32` identifier. These should be exposed\\n * in the external API and be unique. The best way to achieve this is by\\n * using `public constant` hash digests:\\n *\\n * ```solidity\\n * bytes32 public constant MY_ROLE = keccak256(\\\"MY_ROLE\\\");\\n * ```\\n *\\n * Roles can be used to represent a set of permissions. To restrict access to a\\n * function call, use {hasRole}:\\n *\\n * ```solidity\\n * function foo() public {\\n * require(hasRole(MY_ROLE, msg.sender));\\n * ...\\n * }\\n * ```\\n *\\n * Roles can be granted and revoked dynamically via the {grantRole} and\\n * {revokeRole} functions. Each role has an associated admin role, and only\\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\\n *\\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\\n * that only accounts with this role will be able to grant or revoke other\\n * roles. More complex role relationships can be created by using\\n * {_setRoleAdmin}.\\n *\\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\\n * grant and revoke this role. Extra precautions should be taken to secure\\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\\n * to enforce additional security measures for this role.\\n */\\nabstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControl, ERC165Upgradeable {\\n struct RoleData {\\n mapping(address account => bool) hasRole;\\n bytes32 adminRole;\\n }\\n\\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\\n\\n\\n /// @custom:storage-location erc7201:openzeppelin.storage.AccessControl\\n struct AccessControlStorage {\\n mapping(bytes32 role => RoleData) _roles;\\n }\\n\\n // keccak256(abi.encode(uint256(keccak256(\\\"openzeppelin.storage.AccessControl\\\")) - 1)) & ~bytes32(uint256(0xff))\\n bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800;\\n\\n function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) {\\n assembly {\\n $.slot := AccessControlStorageLocation\\n }\\n }\\n\\n /**\\n * @dev Modifier that checks that an account has a specific role. Reverts\\n * with an {AccessControlUnauthorizedAccount} error including the required role.\\n */\\n modifier onlyRole(bytes32 role) {\\n _checkRole(role);\\n _;\\n }\\n\\n function __AccessControl_init() internal onlyInitializing {\\n }\\n\\n function __AccessControl_init_unchained() internal onlyInitializing {\\n }\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\\n }\\n\\n /**\\n * @dev Returns `true` if `account` has been granted `role`.\\n */\\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\\n AccessControlStorage storage $ = _getAccessControlStorage();\\n return $._roles[role].hasRole[account];\\n }\\n\\n /**\\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\\n */\\n function _checkRole(bytes32 role) internal view virtual {\\n _checkRole(role, _msgSender());\\n }\\n\\n /**\\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\\n * is missing `role`.\\n */\\n function _checkRole(bytes32 role, address account) internal view virtual {\\n if (!hasRole(role, account)) {\\n revert AccessControlUnauthorizedAccount(account, role);\\n }\\n }\\n\\n /**\\n * @dev Returns the admin role that controls `role`. See {grantRole} and\\n * {revokeRole}.\\n *\\n * To change a role's admin, use {_setRoleAdmin}.\\n */\\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\\n AccessControlStorage storage $ = _getAccessControlStorage();\\n return $._roles[role].adminRole;\\n }\\n\\n /**\\n * @dev Grants `role` to `account`.\\n *\\n * If `account` had not been already granted `role`, emits a {RoleGranted}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n *\\n * May emit a {RoleGranted} event.\\n */\\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\\n _grantRole(role, account);\\n }\\n\\n /**\\n * @dev Revokes `role` from `account`.\\n *\\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n *\\n * May emit a {RoleRevoked} event.\\n */\\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\\n _revokeRole(role, account);\\n }\\n\\n /**\\n * @dev Revokes `role` from the calling account.\\n *\\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\\n * purpose is to provide a mechanism for accounts to lose their privileges\\n * if they are compromised (such as when a trusted device is misplaced).\\n *\\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must be `callerConfirmation`.\\n *\\n * May emit a {RoleRevoked} event.\\n */\\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\\n if (callerConfirmation != _msgSender()) {\\n revert AccessControlBadConfirmation();\\n }\\n\\n _revokeRole(role, callerConfirmation);\\n }\\n\\n /**\\n * @dev Sets `adminRole` as ``role``'s admin role.\\n *\\n * Emits a {RoleAdminChanged} event.\\n */\\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\\n AccessControlStorage storage $ = _getAccessControlStorage();\\n bytes32 previousAdminRole = getRoleAdmin(role);\\n $._roles[role].adminRole = adminRole;\\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\\n }\\n\\n /**\\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\\n *\\n * Internal function without access restriction.\\n *\\n * May emit a {RoleGranted} event.\\n */\\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\\n AccessControlStorage storage $ = _getAccessControlStorage();\\n if (!hasRole(role, account)) {\\n $._roles[role].hasRole[account] = true;\\n emit RoleGranted(role, account, _msgSender());\\n return true;\\n } else {\\n return false;\\n }\\n }\\n\\n /**\\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\\n *\\n * Internal function without access restriction.\\n *\\n * May emit a {RoleRevoked} event.\\n */\\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\\n AccessControlStorage storage $ = _getAccessControlStorage();\\n if (hasRole(role, account)) {\\n $._roles[role].hasRole[account] = false;\\n emit RoleRevoked(role, account, _msgSender());\\n return true;\\n } else {\\n return false;\\n }\\n }\\n}\\n\",\"keccak256\":\"0x6662ec4e5cefca03eeadd073e9469df8d2944bb2ee8ec8f7622c2c46aab5f225\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)\\n\\npragma solidity ^0.8.20;\\n\\n/**\\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\\n *\\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\\n * reused. This mechanism prevents re-execution of each \\\"step\\\" but allows the creation of new initialization steps in\\n * case an upgrade adds a module that needs to be initialized.\\n *\\n * For example:\\n *\\n * [.hljs-theme-light.nopadding]\\n * ```solidity\\n * contract MyToken is ERC20Upgradeable {\\n * function initialize() initializer public {\\n * __ERC20_init(\\\"MyToken\\\", \\\"MTK\\\");\\n * }\\n * }\\n *\\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\\n * function initializeV2() reinitializer(2) public {\\n * __ERC20Permit_init(\\\"MyToken\\\");\\n * }\\n * }\\n * ```\\n *\\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\\n *\\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\\n *\\n * [CAUTION]\\n * ====\\n * Avoid leaving a contract uninitialized.\\n *\\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\\n *\\n * [.hljs-theme-light.nopadding]\\n * ```\\n * /// @custom:oz-upgrades-unsafe-allow constructor\\n * constructor() {\\n * _disableInitializers();\\n * }\\n * ```\\n * ====\\n */\\nabstract contract Initializable {\\n /**\\n * @dev Storage of the initializable contract.\\n *\\n * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions\\n * when using with upgradeable contracts.\\n *\\n * @custom:storage-location erc7201:openzeppelin.storage.Initializable\\n */\\n struct InitializableStorage {\\n /**\\n * @dev Indicates that the contract has been initialized.\\n */\\n uint64 _initialized;\\n /**\\n * @dev Indicates that the contract is in the process of being initialized.\\n */\\n bool _initializing;\\n }\\n\\n // keccak256(abi.encode(uint256(keccak256(\\\"openzeppelin.storage.Initializable\\\")) - 1)) & ~bytes32(uint256(0xff))\\n bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;\\n\\n /**\\n * @dev The contract is already initialized.\\n */\\n error InvalidInitialization();\\n\\n /**\\n * @dev The contract is not initializing.\\n */\\n error NotInitializing();\\n\\n /**\\n * @dev Triggered when the contract has been initialized or reinitialized.\\n */\\n event Initialized(uint64 version);\\n\\n /**\\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\\n * `onlyInitializing` functions can be used to initialize parent contracts.\\n *\\n * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any\\n * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in\\n * production.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier initializer() {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n // Cache values to avoid duplicated sloads\\n bool isTopLevelCall = !$._initializing;\\n uint64 initialized = $._initialized;\\n\\n // Allowed calls:\\n // - initialSetup: the contract is not in the initializing state and no previous version was\\n // initialized\\n // - construction: the contract is initialized at version 1 (no reininitialization) and the\\n // current contract is just being deployed\\n bool initialSetup = initialized == 0 && isTopLevelCall;\\n bool construction = initialized == 1 && address(this).code.length == 0;\\n\\n if (!initialSetup && !construction) {\\n revert InvalidInitialization();\\n }\\n $._initialized = 1;\\n if (isTopLevelCall) {\\n $._initializing = true;\\n }\\n _;\\n if (isTopLevelCall) {\\n $._initializing = false;\\n emit Initialized(1);\\n }\\n }\\n\\n /**\\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\\n * used to initialize parent contracts.\\n *\\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\\n * are added through upgrades and that require initialization.\\n *\\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\\n * cannot be nested. If one is invoked in the context of another, execution will revert.\\n *\\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\\n * a contract, executing them in the right order is up to the developer or operator.\\n *\\n * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.\\n *\\n * Emits an {Initialized} event.\\n */\\n modifier reinitializer(uint64 version) {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n if ($._initializing || $._initialized >= version) {\\n revert InvalidInitialization();\\n }\\n $._initialized = version;\\n $._initializing = true;\\n _;\\n $._initializing = false;\\n emit Initialized(version);\\n }\\n\\n /**\\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\\n */\\n modifier onlyInitializing() {\\n _checkInitializing();\\n _;\\n }\\n\\n /**\\n * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.\\n */\\n function _checkInitializing() internal view virtual {\\n if (!_isInitializing()) {\\n revert NotInitializing();\\n }\\n }\\n\\n /**\\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\\n * through proxies.\\n *\\n * Emits an {Initialized} event the first time it is successfully executed.\\n */\\n function _disableInitializers() internal virtual {\\n // solhint-disable-next-line var-name-mixedcase\\n InitializableStorage storage $ = _getInitializableStorage();\\n\\n if ($._initializing) {\\n revert InvalidInitialization();\\n }\\n if ($._initialized != type(uint64).max) {\\n $._initialized = type(uint64).max;\\n emit Initialized(type(uint64).max);\\n }\\n }\\n\\n /**\\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\\n */\\n function _getInitializedVersion() internal view returns (uint64) {\\n return _getInitializableStorage()._initialized;\\n }\\n\\n /**\\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\\n */\\n function _isInitializing() internal view returns (bool) {\\n return _getInitializableStorage()._initializing;\\n }\\n\\n /**\\n * @dev Returns a pointer to the storage namespace.\\n */\\n // solhint-disable-next-line var-name-mixedcase\\n function _getInitializableStorage() private pure returns (InitializableStorage storage $) {\\n assembly {\\n $.slot := INITIALIZABLE_STORAGE\\n }\\n }\\n}\\n\",\"keccak256\":\"0x631188737069917d2f909d29ce62c4d48611d326686ba6683e26b72a23bfac0b\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\\n\\npragma solidity ^0.8.20;\\nimport {Initializable} from \\\"../proxy/utils/Initializable.sol\\\";\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract ContextUpgradeable is Initializable {\\n function __Context_init() internal onlyInitializing {\\n }\\n\\n function __Context_init_unchained() internal onlyInitializing {\\n }\\n function _msgSender() internal view virtual returns (address) {\\n return msg.sender;\\n }\\n\\n function _msgData() internal view virtual returns (bytes calldata) {\\n return msg.data;\\n }\\n\\n function _contextSuffixLength() internal view virtual returns (uint256) {\\n return 0;\\n }\\n}\\n\",\"keccak256\":\"0xdbef5f0c787055227243a7318ef74c8a5a1108ca3a07f2b3a00ef67769e1e397\",\"license\":\"MIT\"},\"@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\\n\\npragma solidity ^0.8.20;\\n\\nimport {IERC165} from \\\"@openzeppelin/contracts/utils/introspection/IERC165.sol\\\";\\nimport {Initializable} from \\\"../../proxy/utils/Initializable.sol\\\";\\n\\n/**\\n * @dev Implementation of the {IERC165} interface.\\n *\\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\\n * for the additional interface id that will be supported. For example:\\n *\\n * ```solidity\\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\\n * }\\n * ```\\n */\\nabstract contract ERC165Upgradeable is Initializable, IERC165 {\\n function __ERC165_init() internal onlyInitializing {\\n }\\n\\n function __ERC165_init_unchained() internal onlyInitializing {\\n }\\n /**\\n * @dev See {IERC165-supportsInterface}.\\n */\\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\\n return interfaceId == type(IERC165).interfaceId;\\n }\\n}\\n\",\"keccak256\":\"0xdaba3f7c42c55b2896353f32bd27d4d5f8bae741b3b05d4c53f67abc4dc47ce8\",\"license\":\"MIT\"},\"@openzeppelin/contracts/access/IAccessControl.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\\n\\npragma solidity ^0.8.20;\\n\\n/**\\n * @dev External interface of AccessControl declared to support ERC165 detection.\\n */\\ninterface IAccessControl {\\n /**\\n * @dev The `account` is missing a role.\\n */\\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\\n\\n /**\\n * @dev The caller of a function is not the expected one.\\n *\\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\\n */\\n error AccessControlBadConfirmation();\\n\\n /**\\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\\n *\\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\\n * {RoleAdminChanged} not being emitted signaling this.\\n */\\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\\n\\n /**\\n * @dev Emitted when `account` is granted `role`.\\n *\\n * `sender` is the account that originated the contract call, an admin role\\n * bearer except when using {AccessControl-_setupRole}.\\n */\\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\\n\\n /**\\n * @dev Emitted when `account` is revoked `role`.\\n *\\n * `sender` is the account that originated the contract call:\\n * - if using `revokeRole`, it is the admin role bearer\\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\\n */\\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\\n\\n /**\\n * @dev Returns `true` if `account` has been granted `role`.\\n */\\n function hasRole(bytes32 role, address account) external view returns (bool);\\n\\n /**\\n * @dev Returns the admin role that controls `role`. See {grantRole} and\\n * {revokeRole}.\\n *\\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\\n */\\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\\n\\n /**\\n * @dev Grants `role` to `account`.\\n *\\n * If `account` had not been already granted `role`, emits a {RoleGranted}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n */\\n function grantRole(bytes32 role, address account) external;\\n\\n /**\\n * @dev Revokes `role` from `account`.\\n *\\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n */\\n function revokeRole(bytes32 role, address account) external;\\n\\n /**\\n * @dev Revokes `role` from the calling account.\\n *\\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\\n * purpose is to provide a mechanism for accounts to lose their privileges\\n * if they are compromised (such as when a trusted device is misplaced).\\n *\\n * If the calling account had been granted `role`, emits a {RoleRevoked}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must be `callerConfirmation`.\\n */\\n function renounceRole(bytes32 role, address callerConfirmation) external;\\n}\\n\",\"keccak256\":\"0xb6b36edd6a2999fd243ff226d6cbf84bd71af2432bbd0dfe19392996a1d9cb41\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.20;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\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\",\"keccak256\":\"0xc6a8ff0ea489379b61faa647490411b80102578440ab9d84e9a957cc12164e70\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)\\n\\npragma solidity ^0.8.20;\\n\\n/**\\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\\n *\\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\\n * need to send a transaction, and thus is not required to hold Ether at all.\\n *\\n * ==== Security Considerations\\n *\\n * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature\\n * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be\\n * considered as an intention to spend the allowance in any specific way. The second is that because permits have\\n * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should\\n * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be\\n * generally recommended is:\\n *\\n * ```solidity\\n * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {\\n * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}\\n * doThing(..., value);\\n * }\\n *\\n * function doThing(..., uint256 value) public {\\n * token.safeTransferFrom(msg.sender, address(this), value);\\n * ...\\n * }\\n * ```\\n *\\n * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of\\n * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also\\n * {SafeERC20-safeTransferFrom}).\\n *\\n * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so\\n * contracts should have entry points that don't rely on permit.\\n */\\ninterface IERC20Permit {\\n /**\\n * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\\n * given ``owner``'s signed approval.\\n *\\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\\n * ordering also apply here.\\n *\\n * Emits an {Approval} event.\\n *\\n * Requirements:\\n *\\n * - `spender` cannot be the zero address.\\n * - `deadline` must be a timestamp in the future.\\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\\n * over the EIP712-formatted function arguments.\\n * - the signature must use ``owner``'s current nonce (see {nonces}).\\n *\\n * For more information on the signature format, see the\\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\\n * section].\\n *\\n * CAUTION: See Security Considerations above.\\n */\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) external;\\n\\n /**\\n * @dev Returns the current nonce for `owner`. This value must be\\n * included whenever a signature is generated for {permit}.\\n *\\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\\n * prevents a signature from being used multiple times.\\n */\\n function nonces(address owner) external view returns (uint256);\\n\\n /**\\n * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\\n */\\n // solhint-disable-next-line func-name-mixedcase\\n function DOMAIN_SEPARATOR() external view returns (bytes32);\\n}\\n\",\"keccak256\":\"0x6008dabfe393240d73d7dd7688033f72740d570aa422254d29a7dce8568f3aff\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.20;\\n\\nimport {IERC20} from \\\"../IERC20.sol\\\";\\nimport {IERC20Permit} from \\\"../extensions/IERC20Permit.sol\\\";\\nimport {Address} from \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 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 using Address for address;\\n\\n /**\\n * @dev An operation with an ERC20 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 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 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 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 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 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 function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\\n // the target address contains contract code and also asserts for success in the low-level call.\\n\\n bytes memory returndata = address(token).functionCall(data);\\n if (returndata.length != 0 && !abi.decode(returndata, (bool))) {\\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 silents catches all reverts and returns a bool instead.\\n */\\n function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\\n // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false\\n // and not revert is the subcall reverts.\\n\\n (bool success, bytes memory returndata) = address(token).call(data);\\n return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;\\n }\\n}\\n\",\"keccak256\":\"0x37bb49513c49c87c4642a891b13b63571bc87013dde806617aa1efb54605f386\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.20;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev The ETH balance of the account is not enough to perform the operation.\\n */\\n error AddressInsufficientBalance(address account);\\n\\n /**\\n * @dev There's no code at `target` (it is not a contract).\\n */\\n error AddressEmptyCode(address target);\\n\\n /**\\n * @dev A call to an address target failed. The target may have reverted.\\n */\\n error FailedInnerCall();\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n if (address(this).balance < amount) {\\n revert AddressInsufficientBalance(address(this));\\n }\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n if (!success) {\\n revert FailedInnerCall();\\n }\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason or custom error, it is bubbled\\n * up by this function (like regular Solidity function calls). However, if\\n * the call reverted with no returned reason, this function reverts with a\\n * {FailedInnerCall} error.\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n */\\n function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\\n if (address(this).balance < value) {\\n revert AddressInsufficientBalance(address(this));\\n }\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\\n * unsuccessful call.\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata\\n ) internal view returns (bytes memory) {\\n if (!success) {\\n _revert(returndata);\\n } else {\\n // only check if target is a contract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n if (returndata.length == 0 && target.code.length == 0) {\\n revert AddressEmptyCode(target);\\n }\\n return returndata;\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\\n * revert reason or with a default {FailedInnerCall} error.\\n */\\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\\n if (!success) {\\n _revert(returndata);\\n } else {\\n return returndata;\\n }\\n }\\n\\n /**\\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\\n */\\n function _revert(bytes memory returndata) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert FailedInnerCall();\\n }\\n }\\n}\\n\",\"keccak256\":\"0xaf28a975a78550e45f65e559a3ad6a5ad43b9b8a37366999abd1b7084eb70721\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/introspection/IERC165.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\\n\\npragma solidity ^0.8.20;\\n\\n/**\\n * @dev Interface of the ERC165 standard, as defined in the\\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\\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[EIP 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\",\"keccak256\":\"0x4296879f55019b23e135000eb36896057e7101fb7fb859c5ef690cf14643757b\",\"license\":\"MIT\"},\"contracts/periphery/BuyBackBurnMaha.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0\\npragma solidity 0.8.21;\\n\\nimport {AccessControlUpgradeable} from \\\"@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol\\\";\\nimport {IERC20, SafeERC20} from \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\n\\n/**\\n * @title BuyBackBurnMaha\\n * @dev This contract facilitates the buy-back and burning of MAHA tokens using USDC.\\n * It leverages a specified ODOS router for token swaps and allows only authorized\\n * distributors to perform buy-back and burn operations.\\n */\\ncontract BuyBackBurnMaha is AccessControlUpgradeable {\\n using SafeERC20 for IERC20;\\n\\n /// @notice Role identifier for accounts authorized to initiate buy-back and burn operations.\\n bytes32 public constant DISTRIBUTOR_ROLE = keccak256(\\\"DISTRIBUTOR_ROLE\\\");\\n\\n /// @notice Address representing the burn address (tokens sent here are considered burned).\\n address public constant DEAD_ADDRESS = 0x0000000000000000000000000000000000000000;\\n\\n /// @notice Address of the ODOS router used for swapping USDC to MAHA.\\n address public odos;\\n\\n /// @notice The MAHA token contract.\\n IERC20 public maha;\\n\\n /// @notice The USDC token contract.\\n IERC20 public usdc;\\n\\n /**\\n * @notice Initializes the contract with MAHA and USDC token addresses, ODOS router address, and distributor role.\\n * @param _maha Address of the MAHA token contract.\\n * @param _usdc Address of the USDC token contract.\\n * @param _odos Address of the ODOS router used for swaps.\\n * @param _distributor Address to be assigned the DISTRIBUTOR_ROLE.\\n */\\n function initialize(address _maha, address _usdc, address _odos, address _distributor) external initializer {\\n __AccessControl_init();\\n maha = IERC20(_maha);\\n usdc = IERC20(_usdc);\\n _grantRole(DEFAULT_ADMIN_ROLE, msg.sender);\\n _grantRole(DISTRIBUTOR_ROLE, _distributor);\\n setOdos(_odos);\\n }\\n\\n /**\\n * @notice Updates the address of the ODOS router.\\n * @dev Only callable by an account with the DEFAULT_ADMIN_ROLE.\\n * @param _newOdos New address of the ODOS router.\\n */\\n function setOdos(\\n address _newOdos\\n ) public onlyRole(DEFAULT_ADMIN_ROLE) {\\n odos = _newOdos;\\n }\\n\\n /**\\n * @notice Executes the buy-back and burn operation.\\n * @dev Only callable by an account with the DISTRIBUTOR_ROLE.\\n * Swaps USDC for MAHA through the ODOS router and sends the MAHA to the burn address.\\n * @param odosData Encoded data for the ODOS router call to perform the swap.\\n * @param amount How much USDC you want ODOS router to swap\\n */\\n function buyMahaBurn(bytes calldata odosData, uint256 amount) external payable onlyRole(DISTRIBUTOR_ROLE) {\\n IERC20(usdc).approve(odos, amount);\\n\\n (bool ok,) = odos.call{value: msg.value}(odosData);\\n require(ok, \\\"odos call failed\\\");\\n\\n uint256 mahaBalanceAfterSwap = IERC20(maha).balanceOf(address(this));\\n require(mahaBalanceAfterSwap > 0, \\\"No Maha to burn!\\\");\\n\\n // Transfer MAHA tokens to the dead address to effectively \\\"burn\\\" them.\\n IERC20(maha).safeTransfer(DEAD_ADDRESS, mahaBalanceAfterSwap);\\n }\\n\\n /**\\n * @notice Refunds the specified token balance held by the contract to the caller.\\n * @dev Only callable by an account with the DEFAULT_ADMIN_ROLE.\\n * @param token The ERC20 token to be refunded.\\n */\\n function refund(\\n IERC20 token\\n ) external onlyRole(DEFAULT_ADMIN_ROLE) {\\n token.safeTransfer(msg.sender, token.balanceOf(address(this)));\\n }\\n}\\n\",\"keccak256\":\"0x2fc1bdbaf8825ce1a3614353d3e5e0cbb8a9acd5d80a72d31099aa2218f0bfd7\",\"license\":\"GPL-3.0\"}},\"version\":1}", + "bytecode": "0x608060405234801561001057600080fd5b50610e4f806100206000396000f3fe6080604052600436106100d35760003560e01c80638ba7023b1161007a5780638ba7023b146101ff57806391d148541461021f5780639af524c11461023f578063a217fddf14610252578063d547741f14610267578063f0bd87cc14610287578063f8c8765e146102a9578063fa89401a146102c957600080fd5b806301ffc9a7146100d85780631eba02ec1461010d578063248a9ca31461013a5780632f2ff15d1461016857806336568abe1461018a5780633de00c36146101aa5780633e413bee146101ca5780634e6fd6c4146101ea575b600080fd5b3480156100e457600080fd5b506100f86100f3366004610bd9565b6102e9565b60405190151581526020015b60405180910390f35b34801561011957600080fd5b5060005461012d906001600160a01b031681565b6040516101049190610c03565b34801561014657600080fd5b5061015a610155366004610c17565b610320565b604051908152602001610104565b34801561017457600080fd5b50610188610183366004610c45565b610340565b005b34801561019657600080fd5b506101886101a5366004610c45565b610362565b3480156101b657600080fd5b5060015461012d906001600160a01b031681565b3480156101d657600080fd5b5060025461012d906001600160a01b031681565b3480156101f657600080fd5b5061012d600081565b34801561020b57600080fd5b5061018861021a366004610c75565b61039a565b34801561022b57600080fd5b506100f861023a366004610c45565b6103c8565b61018861024d366004610c92565b6103fe565b34801561025e57600080fd5b5061015a600081565b34801561027357600080fd5b50610188610282366004610c45565b610614565b34801561029357600080fd5b5061015a600080516020610dfa83398151915281565b3480156102b557600080fd5b506101886102c4366004610d0a565b610630565b3480156102d557600080fd5b506101886102e4366004610c75565b6107a0565b60006001600160e01b03198216637965db0b60e01b148061031a57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60008061032b610831565b60009384526020525050604090206001015490565b61034982610320565b61035281610855565b61035c8383610862565b50505050565b6001600160a01b038116331461038b5760405163334bd91960e11b815260040160405180910390fd5b6103958282610903565b505050565b60006103a581610855565b50600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000806103d3610831565b6000948552602090815260408086206001600160a01b03959095168652939052505090205460ff1690565b600080516020610dfa83398151915261041681610855565b60025460005460405163095ea7b360e01b81526001600160a01b039283169263095ea7b39261044c929116908690600401610d66565b6020604051808303816000875af115801561046b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061048f9190610d7f565b50600080546040516001600160a01b039091169034906104b29088908890610da1565b60006040518083038185875af1925050503d80600081146104ef576040519150601f19603f3d011682016040523d82523d6000602084013e6104f4565b606091505b505090508061053d5760405162461bcd60e51b815260206004820152601060248201526f1bd91bdcc818d85b1b0819985a5b195960821b60448201526064015b60405180910390fd5b6001546040516370a0823160e01b81526000916001600160a01b0316906370a082319061056e903090600401610c03565b602060405180830381865afa15801561058b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105af9190610db1565b9050600081116105f45760405162461bcd60e51b815260206004820152601060248201526f4e6f204d61686120746f206275726e2160801b6044820152606401610534565b60015461060c906001600160a01b031660008361097b565b505050505050565b61061d82610320565b61062681610855565b61035c8383610903565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff166000811580156106765750825b905060008267ffffffffffffffff1660011480156106935750303b155b9050811580156106a1575080155b156106bf5760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156106e957845460ff60401b1916600160401b1785555b6106f16109d3565b600180546001600160a01b03808c166001600160a01b03199283161790925560028054928b169290911691909117905561072c600033610862565b50610745600080516020610dfa83398151915287610862565b5061074f8761039a565b831561079557845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050505050565b60006107ab81610855565b61082d33836001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016107db9190610c03565b602060405180830381865afa1580156107f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061081c9190610db1565b6001600160a01b038516919061097b565b5050565b7f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680090565b61085f81336109dd565b50565b60008061086d610831565b905061087984846103c8565b6108f9576000848152602082815260408083206001600160a01b03871684529091529020805460ff191660011790556108af3390565b6001600160a01b0316836001600160a01b0316857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4600191505061031a565b600091505061031a565b60008061090e610831565b905061091a84846103c8565b156108f9576000848152602082815260408083206001600160a01b0387168085529252808320805460ff1916905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4600191505061031a565b61039583846001600160a01b031663a9059cbb85856040516024016109a1929190610d66565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050610a08565b6109db610a62565b565b6109e782826103c8565b61082d57808260405163e2517d3f60e01b8152600401610534929190610d66565b6000610a1d6001600160a01b03841683610aab565b90508051600014158015610a42575080806020019051810190610a409190610d7f565b155b156103955782604051635274afe760e01b81526004016105349190610c03565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff166109db57604051631afcd79f60e31b815260040160405180910390fd5b6060610ab983836000610ac0565b9392505050565b606081471015610ae5573060405163cd78605960e01b81526004016105349190610c03565b600080856001600160a01b03168486604051610b019190610dca565b60006040518083038185875af1925050503d8060008114610b3e576040519150601f19603f3d011682016040523d82523d6000602084013e610b43565b606091505b5091509150610b53868383610b5d565b9695505050505050565b606082610b7257610b6d82610bb0565b610ab9565b8151158015610b8957506001600160a01b0384163b155b15610ba95783604051639996b31560e01b81526004016105349190610c03565b5080610ab9565b805115610bc05780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b600060208284031215610beb57600080fd5b81356001600160e01b031981168114610ab957600080fd5b6001600160a01b0391909116815260200190565b600060208284031215610c2957600080fd5b5035919050565b6001600160a01b038116811461085f57600080fd5b60008060408385031215610c5857600080fd5b823591506020830135610c6a81610c30565b809150509250929050565b600060208284031215610c8757600080fd5b8135610ab981610c30565b600080600060408486031215610ca757600080fd5b833567ffffffffffffffff80821115610cbf57600080fd5b818601915086601f830112610cd357600080fd5b813581811115610ce257600080fd5b876020828501011115610cf457600080fd5b6020928301989097509590910135949350505050565b60008060008060808587031215610d2057600080fd5b8435610d2b81610c30565b93506020850135610d3b81610c30565b92506040850135610d4b81610c30565b91506060850135610d5b81610c30565b939692955090935050565b6001600160a01b03929092168252602082015260400190565b600060208284031215610d9157600080fd5b81518015158114610ab957600080fd5b8183823760009101908152919050565b600060208284031215610dc357600080fd5b5051919050565b6000825160005b81811015610deb5760208186018101518583015201610dd1565b50600092019182525091905056fefbd454f36a7e1a388bd6fc3ab10d434aa4578f811acbbcf33afb1c697486313ca2646970667358221220ad202a802e8bae8ab837113bbe109e935c1b5aecfe9848e5282fda76e12cd1b364736f6c63430008150033", + "deployedBytecode": "0x6080604052600436106100d35760003560e01c80638ba7023b1161007a5780638ba7023b146101ff57806391d148541461021f5780639af524c11461023f578063a217fddf14610252578063d547741f14610267578063f0bd87cc14610287578063f8c8765e146102a9578063fa89401a146102c957600080fd5b806301ffc9a7146100d85780631eba02ec1461010d578063248a9ca31461013a5780632f2ff15d1461016857806336568abe1461018a5780633de00c36146101aa5780633e413bee146101ca5780634e6fd6c4146101ea575b600080fd5b3480156100e457600080fd5b506100f86100f3366004610bd9565b6102e9565b60405190151581526020015b60405180910390f35b34801561011957600080fd5b5060005461012d906001600160a01b031681565b6040516101049190610c03565b34801561014657600080fd5b5061015a610155366004610c17565b610320565b604051908152602001610104565b34801561017457600080fd5b50610188610183366004610c45565b610340565b005b34801561019657600080fd5b506101886101a5366004610c45565b610362565b3480156101b657600080fd5b5060015461012d906001600160a01b031681565b3480156101d657600080fd5b5060025461012d906001600160a01b031681565b3480156101f657600080fd5b5061012d600081565b34801561020b57600080fd5b5061018861021a366004610c75565b61039a565b34801561022b57600080fd5b506100f861023a366004610c45565b6103c8565b61018861024d366004610c92565b6103fe565b34801561025e57600080fd5b5061015a600081565b34801561027357600080fd5b50610188610282366004610c45565b610614565b34801561029357600080fd5b5061015a600080516020610dfa83398151915281565b3480156102b557600080fd5b506101886102c4366004610d0a565b610630565b3480156102d557600080fd5b506101886102e4366004610c75565b6107a0565b60006001600160e01b03198216637965db0b60e01b148061031a57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60008061032b610831565b60009384526020525050604090206001015490565b61034982610320565b61035281610855565b61035c8383610862565b50505050565b6001600160a01b038116331461038b5760405163334bd91960e11b815260040160405180910390fd5b6103958282610903565b505050565b60006103a581610855565b50600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000806103d3610831565b6000948552602090815260408086206001600160a01b03959095168652939052505090205460ff1690565b600080516020610dfa83398151915261041681610855565b60025460005460405163095ea7b360e01b81526001600160a01b039283169263095ea7b39261044c929116908690600401610d66565b6020604051808303816000875af115801561046b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061048f9190610d7f565b50600080546040516001600160a01b039091169034906104b29088908890610da1565b60006040518083038185875af1925050503d80600081146104ef576040519150601f19603f3d011682016040523d82523d6000602084013e6104f4565b606091505b505090508061053d5760405162461bcd60e51b815260206004820152601060248201526f1bd91bdcc818d85b1b0819985a5b195960821b60448201526064015b60405180910390fd5b6001546040516370a0823160e01b81526000916001600160a01b0316906370a082319061056e903090600401610c03565b602060405180830381865afa15801561058b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105af9190610db1565b9050600081116105f45760405162461bcd60e51b815260206004820152601060248201526f4e6f204d61686120746f206275726e2160801b6044820152606401610534565b60015461060c906001600160a01b031660008361097b565b505050505050565b61061d82610320565b61062681610855565b61035c8383610903565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff166000811580156106765750825b905060008267ffffffffffffffff1660011480156106935750303b155b9050811580156106a1575080155b156106bf5760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156106e957845460ff60401b1916600160401b1785555b6106f16109d3565b600180546001600160a01b03808c166001600160a01b03199283161790925560028054928b169290911691909117905561072c600033610862565b50610745600080516020610dfa83398151915287610862565b5061074f8761039a565b831561079557845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050505050565b60006107ab81610855565b61082d33836001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016107db9190610c03565b602060405180830381865afa1580156107f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061081c9190610db1565b6001600160a01b038516919061097b565b5050565b7f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680090565b61085f81336109dd565b50565b60008061086d610831565b905061087984846103c8565b6108f9576000848152602082815260408083206001600160a01b03871684529091529020805460ff191660011790556108af3390565b6001600160a01b0316836001600160a01b0316857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4600191505061031a565b600091505061031a565b60008061090e610831565b905061091a84846103c8565b156108f9576000848152602082815260408083206001600160a01b0387168085529252808320805460ff1916905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4600191505061031a565b61039583846001600160a01b031663a9059cbb85856040516024016109a1929190610d66565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050610a08565b6109db610a62565b565b6109e782826103c8565b61082d57808260405163e2517d3f60e01b8152600401610534929190610d66565b6000610a1d6001600160a01b03841683610aab565b90508051600014158015610a42575080806020019051810190610a409190610d7f565b155b156103955782604051635274afe760e01b81526004016105349190610c03565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff166109db57604051631afcd79f60e31b815260040160405180910390fd5b6060610ab983836000610ac0565b9392505050565b606081471015610ae5573060405163cd78605960e01b81526004016105349190610c03565b600080856001600160a01b03168486604051610b019190610dca565b60006040518083038185875af1925050503d8060008114610b3e576040519150601f19603f3d011682016040523d82523d6000602084013e610b43565b606091505b5091509150610b53868383610b5d565b9695505050505050565b606082610b7257610b6d82610bb0565b610ab9565b8151158015610b8957506001600160a01b0384163b155b15610ba95783604051639996b31560e01b81526004016105349190610c03565b5080610ab9565b805115610bc05780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b600060208284031215610beb57600080fd5b81356001600160e01b031981168114610ab957600080fd5b6001600160a01b0391909116815260200190565b600060208284031215610c2957600080fd5b5035919050565b6001600160a01b038116811461085f57600080fd5b60008060408385031215610c5857600080fd5b823591506020830135610c6a81610c30565b809150509250929050565b600060208284031215610c8757600080fd5b8135610ab981610c30565b600080600060408486031215610ca757600080fd5b833567ffffffffffffffff80821115610cbf57600080fd5b818601915086601f830112610cd357600080fd5b813581811115610ce257600080fd5b876020828501011115610cf457600080fd5b6020928301989097509590910135949350505050565b60008060008060808587031215610d2057600080fd5b8435610d2b81610c30565b93506020850135610d3b81610c30565b92506040850135610d4b81610c30565b91506060850135610d5b81610c30565b939692955090935050565b6001600160a01b03929092168252602082015260400190565b600060208284031215610d9157600080fd5b81518015158114610ab957600080fd5b8183823760009101908152919050565b600060208284031215610dc357600080fd5b5051919050565b6000825160005b81811015610deb5760208186018101518583015201610dd1565b50600092019182525091905056fefbd454f36a7e1a388bd6fc3ab10d434aa4578f811acbbcf33afb1c697486313ca2646970667358221220ad202a802e8bae8ab837113bbe109e935c1b5aecfe9848e5282fda76e12cd1b364736f6c63430008150033", + "devdoc": { + "details": "This contract facilitates the buy-back and burning of MAHA tokens using USDC. It leverages a specified ODOS router for token swaps and allows only authorized distributors to perform buy-back and burn operations.", + "errors": { + "AccessControlBadConfirmation()": [ + { + "details": "The caller of a function is not the expected one. NOTE: Don't confuse with {AccessControlUnauthorizedAccount}." + } + ], + "AccessControlUnauthorizedAccount(address,bytes32)": [ + { + "details": "The `account` is missing a role." + } + ], + "AddressEmptyCode(address)": [ + { + "details": "There's no code at `target` (it is not a contract)." + } + ], + "AddressInsufficientBalance(address)": [ + { + "details": "The ETH balance of the account is not enough to perform the operation." + } + ], + "FailedInnerCall()": [ + { + "details": "A call to an address target failed. The target may have reverted." + } + ], + "InvalidInitialization()": [ + { + "details": "The contract is already initialized." + } + ], + "NotInitializing()": [ + { + "details": "The contract is not initializing." + } + ], + "SafeERC20FailedOperation(address)": [ + { + "details": "An operation with an ERC20 token failed." + } + ] + }, + "events": { + "Initialized(uint64)": { + "details": "Triggered when the contract has been initialized or reinitialized." + }, + "RoleAdminChanged(bytes32,bytes32,bytes32)": { + "details": "Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite {RoleAdminChanged} not being emitted signaling this." + }, + "RoleGranted(bytes32,address,address)": { + "details": "Emitted when `account` is granted `role`. `sender` is the account that originated the contract call, an admin role bearer except when using {AccessControl-_setupRole}." + }, + "RoleRevoked(bytes32,address,address)": { + "details": "Emitted when `account` is revoked `role`. `sender` is the account that originated the contract call: - if using `revokeRole`, it is the admin role bearer - if using `renounceRole`, it is the role bearer (i.e. `account`)" + } + }, + "kind": "dev", + "methods": { + "buyMahaBurn(bytes,uint256)": { + "details": "Only callable by an account with the DISTRIBUTOR_ROLE. Swaps USDC for MAHA through the ODOS router and sends the MAHA to the burn address.", + "params": { + "amount": "How much USDC you want ODOS router to swap", + "odosData": "Encoded data for the ODOS router call to perform the swap." + } + }, + "getRoleAdmin(bytes32)": { + "details": "Returns the admin role that controls `role`. See {grantRole} and {revokeRole}. To change a role's admin, use {_setRoleAdmin}." + }, + "grantRole(bytes32,address)": { + "details": "Grants `role` to `account`. If `account` had not been already granted `role`, emits a {RoleGranted} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleGranted} event." + }, + "hasRole(bytes32,address)": { + "details": "Returns `true` if `account` has been granted `role`." + }, + "initialize(address,address,address,address)": { + "params": { + "_distributor": "Address to be assigned the DISTRIBUTOR_ROLE.", + "_maha": "Address of the MAHA token contract.", + "_odos": "Address of the ODOS router used for swaps.", + "_usdc": "Address of the USDC token contract." + } + }, + "refund(address)": { + "details": "Only callable by an account with the DEFAULT_ADMIN_ROLE.", + "params": { + "token": "The ERC20 token to be refunded." + } + }, + "renounceRole(bytes32,address)": { + "details": "Revokes `role` from the calling account. Roles are often managed via {grantRole} and {revokeRole}: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). If the calling account had been revoked `role`, emits a {RoleRevoked} event. Requirements: - the caller must be `callerConfirmation`. May emit a {RoleRevoked} event." + }, + "revokeRole(bytes32,address)": { + "details": "Revokes `role` from `account`. If `account` had been granted `role`, emits a {RoleRevoked} event. Requirements: - the caller must have ``role``'s admin role. May emit a {RoleRevoked} event." + }, + "setOdos(address)": { + "details": "Only callable by an account with the DEFAULT_ADMIN_ROLE.", + "params": { + "_newOdos": "New address of the ODOS router." + } + }, + "supportsInterface(bytes4)": { + "details": "See {IERC165-supportsInterface}." + } + }, + "title": "BuyBackBurnMaha", + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "DEAD_ADDRESS()": { + "notice": "Address representing the burn address (tokens sent here are considered burned)." + }, + "DISTRIBUTOR_ROLE()": { + "notice": "Role identifier for accounts authorized to initiate buy-back and burn operations." + }, + "buyMahaBurn(bytes,uint256)": { + "notice": "Executes the buy-back and burn operation." + }, + "initialize(address,address,address,address)": { + "notice": "Initializes the contract with MAHA and USDC token addresses, ODOS router address, and distributor role." + }, + "maha()": { + "notice": "The MAHA token contract." + }, + "odos()": { + "notice": "Address of the ODOS router used for swapping USDC to MAHA." + }, + "refund(address)": { + "notice": "Refunds the specified token balance held by the contract to the caller." + }, + "setOdos(address)": { + "notice": "Updates the address of the ODOS router." + }, + "usdc()": { + "notice": "The USDC token contract." + } + }, + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 40255, + "contract": "contracts/periphery/BuyBackBurnMaha.sol:BuyBackBurnMaha", + "label": "odos", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 40259, + "contract": "contracts/periphery/BuyBackBurnMaha.sol:BuyBackBurnMaha", + "label": "maha", + "offset": 0, + "slot": "1", + "type": "t_contract(IERC20)15836" + }, + { + "astId": 40263, + "contract": "contracts/periphery/BuyBackBurnMaha.sol:BuyBackBurnMaha", + "label": "usdc", + "offset": 0, + "slot": "2", + "type": "t_contract(IERC20)15836" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_contract(IERC20)15836": { + "encoding": "inplace", + "label": "contract IERC20", + "numberOfBytes": "20" + } + } + } +} \ No newline at end of file diff --git a/deployments/base/BuyBackBurnMaha-Proxy.json b/deployments/base/BuyBackBurnMaha-Proxy.json new file mode 100644 index 0000000..f1ef604 --- /dev/null +++ b/deployments/base/BuyBackBurnMaha-Proxy.json @@ -0,0 +1,291 @@ +{ + "address": "0x8Dbe7A9bec93AD3AC3B4d29AFD87c7209f3560Ba", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "logic_", + "type": "address" + }, + { + "internalType": "address", + "name": "admin_", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data_", + "type": "bytes" + } + ], + "stateMutability": "payable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "AddressEmptyCode", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "admin", + "type": "address" + } + ], + "name": "ERC1967InvalidAdmin", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "ERC1967InvalidImplementation", + "type": "error" + }, + { + "inputs": [], + "name": "ERC1967NonPayable", + "type": "error" + }, + { + "inputs": [], + "name": "FailedInnerCall", + "type": "error" + }, + { + "inputs": [], + "name": "ProxyDeniedAdminAccess", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "previousAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "implementation", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "proxyAdmin", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0xa82444d7a268895a6bf164b8fd2cd5c2193132b42ea868bf34698dcad08972c8", + "receipt": { + "to": null, + "from": "0x5A61eD1eC946068E261694E85fe017F3BF3FF76e", + "contractAddress": "0x8Dbe7A9bec93AD3AC3B4d29AFD87c7209f3560Ba", + "transactionIndex": 59, + "gasUsed": "547504", + "logsBloom": "0x00000004000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018000000002000000000000000000000000000000000000000000020000000000000000000800000000800000000000000000000000000000000000000000000800000000000080000000000084000000010000800000000000000000000000000000000000000000000000108000001000000000000000000020000000000000000000000014000000000404000100000002000020000000000000010000000100000000000000000000000000000000000000000000", + "blockHash": "0xec7899c58b5ff0b80adbd07feb6cc49709b33ed32b7f39dd05a1b9ab7f66bc40", + "transactionHash": "0xa82444d7a268895a6bf164b8fd2cd5c2193132b42ea868bf34698dcad08972c8", + "logs": [ + { + "transactionIndex": 59, + "blockNumber": 23000470, + "transactionHash": "0xa82444d7a268895a6bf164b8fd2cd5c2193132b42ea868bf34698dcad08972c8", + "address": "0x8Dbe7A9bec93AD3AC3B4d29AFD87c7209f3560Ba", + "topics": [ + "0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b", + "0x000000000000000000000000f18b779f5b8fe17a97df07f0c32915e68d1ae145" + ], + "data": "0x", + "logIndex": 112, + "blockHash": "0xec7899c58b5ff0b80adbd07feb6cc49709b33ed32b7f39dd05a1b9ab7f66bc40" + }, + { + "transactionIndex": 59, + "blockNumber": 23000470, + "transactionHash": "0xa82444d7a268895a6bf164b8fd2cd5c2193132b42ea868bf34698dcad08972c8", + "address": "0x8Dbe7A9bec93AD3AC3B4d29AFD87c7209f3560Ba", + "topics": [ + "0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000005a61ed1ec946068e261694e85fe017f3bf3ff76e", + "0x0000000000000000000000005a61ed1ec946068e261694e85fe017f3bf3ff76e" + ], + "data": "0x", + "logIndex": 113, + "blockHash": "0xec7899c58b5ff0b80adbd07feb6cc49709b33ed32b7f39dd05a1b9ab7f66bc40" + }, + { + "transactionIndex": 59, + "blockNumber": 23000470, + "transactionHash": "0xa82444d7a268895a6bf164b8fd2cd5c2193132b42ea868bf34698dcad08972c8", + "address": "0x8Dbe7A9bec93AD3AC3B4d29AFD87c7209f3560Ba", + "topics": [ + "0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d", + "0xfbd454f36a7e1a388bd6fc3ab10d434aa4578f811acbbcf33afb1c697486313c", + "0x0000000000000000000000005a61ed1ec946068e261694e85fe017f3bf3ff76e", + "0x0000000000000000000000005a61ed1ec946068e261694e85fe017f3bf3ff76e" + ], + "data": "0x", + "logIndex": 114, + "blockHash": "0xec7899c58b5ff0b80adbd07feb6cc49709b33ed32b7f39dd05a1b9ab7f66bc40" + }, + { + "transactionIndex": 59, + "blockNumber": 23000470, + "transactionHash": "0xa82444d7a268895a6bf164b8fd2cd5c2193132b42ea868bf34698dcad08972c8", + "address": "0x8Dbe7A9bec93AD3AC3B4d29AFD87c7209f3560Ba", + "topics": [ + "0xc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000001", + "logIndex": 115, + "blockHash": "0xec7899c58b5ff0b80adbd07feb6cc49709b33ed32b7f39dd05a1b9ab7f66bc40" + }, + { + "transactionIndex": 59, + "blockNumber": 23000470, + "transactionHash": "0xa82444d7a268895a6bf164b8fd2cd5c2193132b42ea868bf34698dcad08972c8", + "address": "0x8Dbe7A9bec93AD3AC3B4d29AFD87c7209f3560Ba", + "topics": [ + "0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000069000c978701fc4427d4baf749f10a5cec582863", + "logIndex": 116, + "blockHash": "0xec7899c58b5ff0b80adbd07feb6cc49709b33ed32b7f39dd05a1b9ab7f66bc40" + } + ], + "blockNumber": 23000470, + "cumulativeGasUsed": "11701201", + "status": 1, + "byzantium": true + }, + "args": [ + "0xf18B779F5b8Fe17A97df07F0c32915E68D1AE145", + "0x69000c978701fc4427d4baf749f10a5cec582863", + "0xf8c8765e000000000000000000000000554bba833518793056cf105e66abea330672c0de000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda0291300000000000000000000000019ceead7105607cd444f5ad10dd51356436095a10000000000000000000000005a61ed1ec946068e261694e85fe017f3bf3ff76e" + ], + "numDeployments": 1, + "solcInputHash": "872ab92c9be5f3ce4c8080b4611e0262", + "metadata": "{\"compiler\":{\"version\":\"0.8.21+commit.d9974bed\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"logic_\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"admin_\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data_\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"admin\",\"type\":\"address\"}],\"name\":\"ERC1967InvalidAdmin\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"ERC1967InvalidImplementation\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ERC1967NonPayable\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedInnerCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ProxyDeniedAdminAccess\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"previousAdmin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"AdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"implementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"proxyAdmin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"errors\":{\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}],\"ERC1967InvalidAdmin(address)\":[{\"details\":\"The `admin` of the proxy is invalid.\"}],\"ERC1967InvalidImplementation(address)\":[{\"details\":\"The `implementation` of the proxy is invalid.\"}],\"ERC1967NonPayable()\":[{\"details\":\"An upgrade function sees `msg.value > 0` that may be lost.\"}],\"FailedInnerCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"ProxyDeniedAdminAccess()\":[{\"details\":\"The proxy caller is the current admin, and can't fallback to the proxy target.\"}]},\"events\":{\"AdminChanged(address,address)\":{\"details\":\"Emitted when the admin account has changed.\"},\"Upgraded(address)\":{\"details\":\"Emitted when the implementation is upgraded.\"}},\"kind\":\"dev\",\"methods\":{\"implementation()\":{\"details\":\"Returns the implementation address of the proxy.\"},\"proxyAdmin()\":{\"details\":\"Returns the admin of this proxy.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/governance/MAHAProxy.sol\":\"MAHAProxy\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":100},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/interfaces/IERC1967.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1967.sol)\\n\\npragma solidity ^0.8.20;\\n\\n/**\\n * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.\\n */\\ninterface IERC1967 {\\n /**\\n * @dev Emitted when the implementation is upgraded.\\n */\\n event Upgraded(address indexed implementation);\\n\\n /**\\n * @dev Emitted when the admin account has changed.\\n */\\n event AdminChanged(address previousAdmin, address newAdmin);\\n\\n /**\\n * @dev Emitted when the beacon is changed.\\n */\\n event BeaconUpgraded(address indexed beacon);\\n}\\n\",\"keccak256\":\"0xb25a4f11fa80c702bf5cd85adec90e6f6f507f32f4a8e6f5dbc31e8c10029486\",\"license\":\"MIT\"},\"@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Proxy.sol)\\n\\npragma solidity ^0.8.20;\\n\\nimport {Proxy} from \\\"../Proxy.sol\\\";\\nimport {ERC1967Utils} from \\\"./ERC1967Utils.sol\\\";\\n\\n/**\\n * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an\\n * implementation address that can be changed. This address is stored in storage in the location specified by\\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the\\n * implementation behind the proxy.\\n */\\ncontract ERC1967Proxy is Proxy {\\n /**\\n * @dev Initializes the upgradeable proxy with an initial implementation specified by `implementation`.\\n *\\n * If `_data` is nonempty, it's used as data in a delegate call to `implementation`. This will typically be an\\n * encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.\\n *\\n * Requirements:\\n *\\n * - If `data` is empty, `msg.value` must be zero.\\n */\\n constructor(address implementation, bytes memory _data) payable {\\n ERC1967Utils.upgradeToAndCall(implementation, _data);\\n }\\n\\n /**\\n * @dev Returns the current implementation address.\\n *\\n * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using\\n * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.\\n * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`\\n */\\n function _implementation() internal view virtual override returns (address) {\\n return ERC1967Utils.getImplementation();\\n }\\n}\\n\",\"keccak256\":\"0xbfb6695731de677140fbf76c772ab08c4233a122fb51ac28ac120fc49bbbc4ec\",\"license\":\"MIT\"},\"@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol)\\n\\npragma solidity ^0.8.20;\\n\\nimport {IBeacon} from \\\"../beacon/IBeacon.sol\\\";\\nimport {Address} from \\\"../../utils/Address.sol\\\";\\nimport {StorageSlot} from \\\"../../utils/StorageSlot.sol\\\";\\n\\n/**\\n * @dev This abstract contract provides getters and event emitting update functions for\\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.\\n */\\nlibrary ERC1967Utils {\\n // We re-declare ERC-1967 events here because they can't be used directly from IERC1967.\\n // This will be fixed in Solidity 0.8.21. At that point we should remove these events.\\n /**\\n * @dev Emitted when the implementation is upgraded.\\n */\\n event Upgraded(address indexed implementation);\\n\\n /**\\n * @dev Emitted when the admin account has changed.\\n */\\n event AdminChanged(address previousAdmin, address newAdmin);\\n\\n /**\\n * @dev Emitted when the beacon is changed.\\n */\\n event BeaconUpgraded(address indexed beacon);\\n\\n /**\\n * @dev Storage slot with the address of the current implementation.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.implementation\\\" subtracted by 1.\\n */\\n // solhint-disable-next-line private-vars-leading-underscore\\n bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n /**\\n * @dev The `implementation` of the proxy is invalid.\\n */\\n error ERC1967InvalidImplementation(address implementation);\\n\\n /**\\n * @dev The `admin` of the proxy is invalid.\\n */\\n error ERC1967InvalidAdmin(address admin);\\n\\n /**\\n * @dev The `beacon` of the proxy is invalid.\\n */\\n error ERC1967InvalidBeacon(address beacon);\\n\\n /**\\n * @dev An upgrade function sees `msg.value > 0` that may be lost.\\n */\\n error ERC1967NonPayable();\\n\\n /**\\n * @dev Returns the current implementation address.\\n */\\n function getImplementation() internal view returns (address) {\\n return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new address in the EIP1967 implementation slot.\\n */\\n function _setImplementation(address newImplementation) private {\\n if (newImplementation.code.length == 0) {\\n revert ERC1967InvalidImplementation(newImplementation);\\n }\\n StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;\\n }\\n\\n /**\\n * @dev Performs implementation upgrade with additional setup call if data is nonempty.\\n * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected\\n * to avoid stuck value in the contract.\\n *\\n * Emits an {IERC1967-Upgraded} event.\\n */\\n function upgradeToAndCall(address newImplementation, bytes memory data) internal {\\n _setImplementation(newImplementation);\\n emit Upgraded(newImplementation);\\n\\n if (data.length > 0) {\\n Address.functionDelegateCall(newImplementation, data);\\n } else {\\n _checkNonPayable();\\n }\\n }\\n\\n /**\\n * @dev Storage slot with the admin of the contract.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.admin\\\" subtracted by 1.\\n */\\n // solhint-disable-next-line private-vars-leading-underscore\\n bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\\n\\n /**\\n * @dev Returns the current admin.\\n *\\n * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using\\n * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.\\n * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`\\n */\\n function getAdmin() internal view returns (address) {\\n return StorageSlot.getAddressSlot(ADMIN_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new address in the EIP1967 admin slot.\\n */\\n function _setAdmin(address newAdmin) private {\\n if (newAdmin == address(0)) {\\n revert ERC1967InvalidAdmin(address(0));\\n }\\n StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;\\n }\\n\\n /**\\n * @dev Changes the admin of the proxy.\\n *\\n * Emits an {IERC1967-AdminChanged} event.\\n */\\n function changeAdmin(address newAdmin) internal {\\n emit AdminChanged(getAdmin(), newAdmin);\\n _setAdmin(newAdmin);\\n }\\n\\n /**\\n * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.\\n * This is the keccak-256 hash of \\\"eip1967.proxy.beacon\\\" subtracted by 1.\\n */\\n // solhint-disable-next-line private-vars-leading-underscore\\n bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;\\n\\n /**\\n * @dev Returns the current beacon.\\n */\\n function getBeacon() internal view returns (address) {\\n return StorageSlot.getAddressSlot(BEACON_SLOT).value;\\n }\\n\\n /**\\n * @dev Stores a new beacon in the EIP1967 beacon slot.\\n */\\n function _setBeacon(address newBeacon) private {\\n if (newBeacon.code.length == 0) {\\n revert ERC1967InvalidBeacon(newBeacon);\\n }\\n\\n StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;\\n\\n address beaconImplementation = IBeacon(newBeacon).implementation();\\n if (beaconImplementation.code.length == 0) {\\n revert ERC1967InvalidImplementation(beaconImplementation);\\n }\\n }\\n\\n /**\\n * @dev Change the beacon and trigger a setup call if data is nonempty.\\n * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected\\n * to avoid stuck value in the contract.\\n *\\n * Emits an {IERC1967-BeaconUpgraded} event.\\n *\\n * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since\\n * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for\\n * efficiency.\\n */\\n function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {\\n _setBeacon(newBeacon);\\n emit BeaconUpgraded(newBeacon);\\n\\n if (data.length > 0) {\\n Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);\\n } else {\\n _checkNonPayable();\\n }\\n }\\n\\n /**\\n * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract\\n * if an upgrade doesn't perform an initialization call.\\n */\\n function _checkNonPayable() private {\\n if (msg.value > 0) {\\n revert ERC1967NonPayable();\\n }\\n }\\n}\\n\",\"keccak256\":\"0x06a78f9b3ee3e6d0eb4e4cd635ba49960bea34cac1db8c0a27c75f2319f1fd65\",\"license\":\"MIT\"},\"@openzeppelin/contracts/proxy/Proxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.0) (proxy/Proxy.sol)\\n\\npragma solidity ^0.8.20;\\n\\n/**\\n * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM\\n * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to\\n * be specified by overriding the virtual {_implementation} function.\\n *\\n * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a\\n * different contract through the {_delegate} function.\\n *\\n * The success and return data of the delegated call will be returned back to the caller of the proxy.\\n */\\nabstract contract Proxy {\\n /**\\n * @dev Delegates the current call to `implementation`.\\n *\\n * This function does not return to its internal call site, it will return directly to the external caller.\\n */\\n function _delegate(address implementation) internal virtual {\\n assembly {\\n // Copy msg.data. We take full control of memory in this inline assembly\\n // block because it will not return to Solidity code. We overwrite the\\n // Solidity scratch pad at memory position 0.\\n calldatacopy(0, 0, calldatasize())\\n\\n // Call the implementation.\\n // out and outsize are 0 because we don't know the size yet.\\n let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\\n\\n // Copy the returned data.\\n returndatacopy(0, 0, returndatasize())\\n\\n switch result\\n // delegatecall returns 0 on error.\\n case 0 {\\n revert(0, returndatasize())\\n }\\n default {\\n return(0, returndatasize())\\n }\\n }\\n }\\n\\n /**\\n * @dev This is a virtual function that should be overridden so it returns the address to which the fallback\\n * function and {_fallback} should delegate.\\n */\\n function _implementation() internal view virtual returns (address);\\n\\n /**\\n * @dev Delegates the current call to the address returned by `_implementation()`.\\n *\\n * This function does not return to its internal call site, it will return directly to the external caller.\\n */\\n function _fallback() internal virtual {\\n _delegate(_implementation());\\n }\\n\\n /**\\n * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other\\n * function in the contract matches the call data.\\n */\\n fallback() external payable virtual {\\n _fallback();\\n }\\n}\\n\",\"keccak256\":\"0xc3f2ec76a3de8ed7a7007c46166f5550c72c7709e3fc7e8bb3111a7191cdedbd\",\"license\":\"MIT\"},\"@openzeppelin/contracts/proxy/beacon/IBeacon.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)\\n\\npragma solidity ^0.8.20;\\n\\n/**\\n * @dev This is the interface that {BeaconProxy} expects of its beacon.\\n */\\ninterface IBeacon {\\n /**\\n * @dev Must return an address that can be used as a delegate call target.\\n *\\n * {UpgradeableBeacon} will check that this address is a contract.\\n */\\n function implementation() external view returns (address);\\n}\\n\",\"keccak256\":\"0xc59a78b07b44b2cf2e8ab4175fca91e8eca1eee2df7357b8d2a8833e5ea1f64c\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.20;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n /**\\n * @dev The ETH balance of the account is not enough to perform the operation.\\n */\\n error AddressInsufficientBalance(address account);\\n\\n /**\\n * @dev There's no code at `target` (it is not a contract).\\n */\\n error AddressEmptyCode(address target);\\n\\n /**\\n * @dev A call to an address target failed. The target may have reverted.\\n */\\n error FailedInnerCall();\\n\\n /**\\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n * `recipient`, forwarding all available gas and reverting on errors.\\n *\\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n * imposed by `transfer`, making them unable to receive funds via\\n * `transfer`. {sendValue} removes this limitation.\\n *\\n * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n *\\n * IMPORTANT: because control is transferred to `recipient`, care must be\\n * taken to not create reentrancy vulnerabilities. Consider using\\n * {ReentrancyGuard} or the\\n * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n */\\n function sendValue(address payable recipient, uint256 amount) internal {\\n if (address(this).balance < amount) {\\n revert AddressInsufficientBalance(address(this));\\n }\\n\\n (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n if (!success) {\\n revert FailedInnerCall();\\n }\\n }\\n\\n /**\\n * @dev Performs a Solidity function call using a low level `call`. A\\n * plain `call` is an unsafe replacement for a function call: use this\\n * function instead.\\n *\\n * If `target` reverts with a revert reason or custom error, it is bubbled\\n * up by this function (like regular Solidity function calls). However, if\\n * the call reverted with no returned reason, this function reverts with a\\n * {FailedInnerCall} error.\\n *\\n * Returns the raw returned data. To convert to the expected return value,\\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n *\\n * Requirements:\\n *\\n * - `target` must be a contract.\\n * - calling `target` with `data` must not revert.\\n */\\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n return functionCallWithValue(target, data, 0);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but also transferring `value` wei to `target`.\\n *\\n * Requirements:\\n *\\n * - the calling contract must have an ETH balance of at least `value`.\\n * - the called Solidity function must be `payable`.\\n */\\n function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\\n if (address(this).balance < value) {\\n revert AddressInsufficientBalance(address(this));\\n }\\n (bool success, bytes memory returndata) = target.call{value: value}(data);\\n return verifyCallResultFromTarget(target, success, returndata);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a static call.\\n */\\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.staticcall(data);\\n return verifyCallResultFromTarget(target, success, returndata);\\n }\\n\\n /**\\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n * but performing a delegate call.\\n */\\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n (bool success, bytes memory returndata) = target.delegatecall(data);\\n return verifyCallResultFromTarget(target, success, returndata);\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\\n * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an\\n * unsuccessful call.\\n */\\n function verifyCallResultFromTarget(\\n address target,\\n bool success,\\n bytes memory returndata\\n ) internal view returns (bytes memory) {\\n if (!success) {\\n _revert(returndata);\\n } else {\\n // only check if target is a contract if the call was successful and the return data is empty\\n // otherwise we already know that it was a contract\\n if (returndata.length == 0 && target.code.length == 0) {\\n revert AddressEmptyCode(target);\\n }\\n return returndata;\\n }\\n }\\n\\n /**\\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\\n * revert reason or with a default {FailedInnerCall} error.\\n */\\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\\n if (!success) {\\n _revert(returndata);\\n } else {\\n return returndata;\\n }\\n }\\n\\n /**\\n * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.\\n */\\n function _revert(bytes memory returndata) private pure {\\n // Look for revert reason and bubble it up if present\\n if (returndata.length > 0) {\\n // The easiest way to bubble the revert reason is using memory via assembly\\n /// @solidity memory-safe-assembly\\n assembly {\\n let returndata_size := mload(returndata)\\n revert(add(32, returndata), returndata_size)\\n }\\n } else {\\n revert FailedInnerCall();\\n }\\n }\\n}\\n\",\"keccak256\":\"0xaf28a975a78550e45f65e559a3ad6a5ad43b9b8a37366999abd1b7084eb70721\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/StorageSlot.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)\\n// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.\\n\\npragma solidity ^0.8.20;\\n\\n/**\\n * @dev Library for reading and writing primitive types to specific storage slots.\\n *\\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\\n * This library helps with reading and writing to such slots without the need for inline assembly.\\n *\\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\\n *\\n * Example usage to set ERC1967 implementation slot:\\n * ```solidity\\n * contract ERC1967 {\\n * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n *\\n * function _getImplementation() internal view returns (address) {\\n * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\\n * }\\n *\\n * function _setImplementation(address newImplementation) internal {\\n * require(newImplementation.code.length > 0);\\n * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\\n * }\\n * }\\n * ```\\n */\\nlibrary StorageSlot {\\n struct AddressSlot {\\n address value;\\n }\\n\\n struct BooleanSlot {\\n bool value;\\n }\\n\\n struct Bytes32Slot {\\n bytes32 value;\\n }\\n\\n struct Uint256Slot {\\n uint256 value;\\n }\\n\\n struct StringSlot {\\n string value;\\n }\\n\\n struct BytesSlot {\\n bytes value;\\n }\\n\\n /**\\n * @dev Returns an `AddressSlot` with member `value` located at `slot`.\\n */\\n function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `BooleanSlot` with member `value` located at `slot`.\\n */\\n function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.\\n */\\n function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `Uint256Slot` with member `value` located at `slot`.\\n */\\n function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `StringSlot` with member `value` located at `slot`.\\n */\\n function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `StringSlot` representation of the string storage pointer `store`.\\n */\\n function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := store.slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `BytesSlot` with member `value` located at `slot`.\\n */\\n function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := slot\\n }\\n }\\n\\n /**\\n * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.\\n */\\n function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {\\n /// @solidity memory-safe-assembly\\n assembly {\\n r.slot := store.slot\\n }\\n }\\n}\\n\",\"keccak256\":\"0x32ba59b4b7299237c8ba56319110989d7978a039faf754793064e967e5894418\",\"license\":\"MIT\"},\"contracts/governance/MAHAProxy.sol\":{\"content\":\"// SPDX-License-Identifier: GPL-3.0\\n\\n// \\u2588\\u2588\\u2588\\u2557 \\u2588\\u2588\\u2588\\u2557 \\u2588\\u2588\\u2588\\u2588\\u2588\\u2557 \\u2588\\u2588\\u2557 \\u2588\\u2588\\u2557 \\u2588\\u2588\\u2588\\u2588\\u2588\\u2557\\n// \\u2588\\u2588\\u2588\\u2588\\u2557 \\u2588\\u2588\\u2588\\u2588\\u2551\\u2588\\u2588\\u2554\\u2550\\u2550\\u2588\\u2588\\u2557\\u2588\\u2588\\u2551 \\u2588\\u2588\\u2551\\u2588\\u2588\\u2554\\u2550\\u2550\\u2588\\u2588\\u2557\\n// \\u2588\\u2588\\u2554\\u2588\\u2588\\u2588\\u2588\\u2554\\u2588\\u2588\\u2551\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2551\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2551\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2551\\n// \\u2588\\u2588\\u2551\\u255a\\u2588\\u2588\\u2554\\u255d\\u2588\\u2588\\u2551\\u2588\\u2588\\u2554\\u2550\\u2550\\u2588\\u2588\\u2551\\u2588\\u2588\\u2554\\u2550\\u2550\\u2588\\u2588\\u2551\\u2588\\u2588\\u2554\\u2550\\u2550\\u2588\\u2588\\u2551\\n// \\u2588\\u2588\\u2551 \\u255a\\u2550\\u255d \\u2588\\u2588\\u2551\\u2588\\u2588\\u2551 \\u2588\\u2588\\u2551\\u2588\\u2588\\u2551 \\u2588\\u2588\\u2551\\u2588\\u2588\\u2551 \\u2588\\u2588\\u2551\\n// \\u255a\\u2550\\u255d \\u255a\\u2550\\u255d\\u255a\\u2550\\u255d \\u255a\\u2550\\u255d\\u255a\\u2550\\u255d \\u255a\\u2550\\u255d\\u255a\\u2550\\u255d \\u255a\\u2550\\u255d\\n\\n// Website: https://maha.xyz\\n// Discord: https://discord.gg/mahadao\\n// Twitter: https://twitter.com/mahaxyz_\\n\\npragma solidity 0.8.21;\\n\\nimport {IERC1967} from \\\"@openzeppelin/contracts/interfaces/IERC1967.sol\\\";\\nimport {ERC1967Proxy} from \\\"@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol\\\";\\nimport {ERC1967Utils} from \\\"@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol\\\";\\n\\n/**\\n * @dev Interface for {MAHAProxy}. In order to implement transparency, {MAHAProxy}\\n * does not implement this interface directly, and its upgradeability mechanism is implemented by an internal dispatch\\n * mechanism. The compiler is unaware that these functions are implemented by {MAHAProxy} and will not\\n * include them in the ABI so this interface must be used to interact with it.\\n */\\ninterface IMAHAProxy is IERC1967 {\\n function upgradeToAndCall(address, bytes calldata) external payable;\\n}\\n\\ncontract MAHAProxy is ERC1967Proxy {\\n // An immutable address for the admin to avoid unnecessary SLOADs before each call\\n // at the expense of removing the ability to change the admin once it's set.\\n // This is acceptable if the admin is always a ProxyAdmin instance or similar contract\\n // with its own ability to transfer the permissions to another account.\\n address private immutable _admin;\\n\\n /**\\n * @dev The proxy caller is the current admin, and can't fallback to the proxy target.\\n */\\n error ProxyDeniedAdminAccess();\\n\\n constructor(address logic_, address admin_, bytes memory data_) payable ERC1967Proxy(logic_, data_) {\\n _admin = admin_;\\n ERC1967Utils.changeAdmin(proxyAdmin());\\n }\\n\\n /**\\n * @dev Returns the admin of this proxy.\\n */\\n function proxyAdmin() public view virtual returns (address) {\\n return _admin;\\n }\\n\\n /**\\n * @dev Returns the implementation address of the proxy.\\n */\\n function implementation() public view virtual returns (address) {\\n return _implementation();\\n }\\n\\n /**\\n * @dev If caller is the admin process the call internally, otherwise transparently fallback to the proxy behavior.\\n */\\n function _fallback() internal virtual override {\\n if (msg.sender == proxyAdmin()) {\\n if (msg.sig != IMAHAProxy.upgradeToAndCall.selector) {\\n revert ProxyDeniedAdminAccess();\\n } else {\\n _dispatchUpgradeToAndCall();\\n }\\n } else {\\n super._fallback();\\n }\\n }\\n\\n /**\\n * @dev Upgrade the implementation of the proxy. See {ERC1967Utils-upgradeToAndCall}.\\n *\\n * Requirements:\\n *\\n * - If `data` is empty, `msg.value` must be zero.\\n */\\n function _dispatchUpgradeToAndCall() private {\\n (address newImplementation, bytes memory data) = abi.decode(msg.data[4:], (address, bytes));\\n ERC1967Utils.upgradeToAndCall(newImplementation, data);\\n }\\n}\\n\",\"keccak256\":\"0x0e11427b4b8373cbf082c1a4de2b36e85daf166f9a5819e86ba7eed721fdb524\",\"license\":\"GPL-3.0\"}},\"version\":1}", + "bytecode": "0x60a0604052604051620009d8380380620009d8833981016040819052620000269162000383565b828162000034828262000060565b50506001600160a01b038216608052620000576200005160805190565b620000c6565b50505062000481565b6200006b8262000138565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2805115620000b857620000b38282620001b8565b505050565b620000c262000235565b5050565b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f62000108600080516020620009b8833981519152546001600160a01b031690565b604080516001600160a01b03928316815291841660208301520160405180910390a1620001358162000257565b50565b806001600160a01b03163b6000036200017457604051634c9c8ce360e01b81526001600160a01b03821660048201526024015b60405180910390fd5b807f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5b80546001600160a01b0319166001600160a01b039290921691909117905550565b6060600080846001600160a01b031684604051620001d7919062000463565b600060405180830381855af49150503d806000811462000214576040519150601f19603f3d011682016040523d82523d6000602084013e62000219565b606091505b5090925090506200022c8583836200029a565b95945050505050565b3415620002555760405163b398979f60e01b815260040160405180910390fd5b565b6001600160a01b0381166200028357604051633173bdd160e11b8152600060048201526024016200016b565b80600080516020620009b883398151915262000197565b606082620002b357620002ad8262000300565b620002f9565b8151158015620002cb57506001600160a01b0384163b155b15620002f657604051639996b31560e01b81526001600160a01b03851660048201526024016200016b565b50805b9392505050565b805115620003115780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b80516001600160a01b03811681146200034257600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b838110156200037a57818101518382015260200162000360565b50506000910152565b6000806000606084860312156200039957600080fd5b620003a4846200032a565b9250620003b4602085016200032a565b60408501519092506001600160401b0380821115620003d257600080fd5b818601915086601f830112620003e757600080fd5b815181811115620003fc57620003fc62000347565b604051601f8201601f19908116603f0116810190838211818310171562000427576200042762000347565b816040528281528960208487010111156200044157600080fd5b620004548360208301602088016200035d565b80955050505050509250925092565b60008251620004778184602087016200035d565b9190910192915050565b608051610516620004a26000396000818160420152608f01526105166000f3fe6080604052600436106100295760003560e01c80633e47158c146100335780635c60da1b14610078575b61003161008d565b005b34801561003f57600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405161006f919061038d565b60405180910390f35b34801561008457600080fd5b50610062610102565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633036100fa576000356001600160e01b03191663278f794360e11b146100f0576040516334ad5dbb60e21b815260040160405180910390fd5b6100f8610111565b565b6100f8610140565b600061010c610150565b905090565b60008061012136600481846103a1565b81019061012e91906103e1565b9150915061013c8282610183565b5050565b6100f861014b610150565b6101de565b600061010c7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b61018c82610202565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a28051156101d6576101d18282610279565b505050565b61013c6102ef565b3660008037600080366000845af43d6000803e8080156101fd573d6000f35b3d6000fd5b806001600160a01b03163b6000036102385780604051634c9c8ce360e01b815260040161022f919061038d565b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b03168460405161029691906104b1565b600060405180830381855af49150503d80600081146102d1576040519150601f19603f3d011682016040523d82523d6000602084013e6102d6565b606091505b50915091506102e685838361030e565b95945050505050565b34156100f85760405163b398979f60e01b815260040160405180910390fd5b6060826103235761031e82610364565b61035d565b815115801561033a57506001600160a01b0384163b155b1561035a5783604051639996b31560e01b815260040161022f919061038d565b50805b9392505050565b8051156103745780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6001600160a01b0391909116815260200190565b600080858511156103b157600080fd5b838611156103be57600080fd5b5050820193919092039150565b634e487b7160e01b600052604160045260246000fd5b600080604083850312156103f457600080fd5b82356001600160a01b038116811461040b57600080fd5b9150602083013567ffffffffffffffff8082111561042857600080fd5b818501915085601f83011261043c57600080fd5b81358181111561044e5761044e6103cb565b604051601f8201601f19908116603f01168101908382118183101715610476576104766103cb565b8160405282815288602084870101111561048f57600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b6000825160005b818110156104d257602081860181015185830152016104b8565b50600092019182525091905056fea2646970667358221220660bd151a9462bc0dfda57427e70a67401a61e3ea04462dab0d2758cf0854d8964736f6c63430008150033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103", + "deployedBytecode": "0x6080604052600436106100295760003560e01c80633e47158c146100335780635c60da1b14610078575b61003161008d565b005b34801561003f57600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405161006f919061038d565b60405180910390f35b34801561008457600080fd5b50610062610102565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633036100fa576000356001600160e01b03191663278f794360e11b146100f0576040516334ad5dbb60e21b815260040160405180910390fd5b6100f8610111565b565b6100f8610140565b600061010c610150565b905090565b60008061012136600481846103a1565b81019061012e91906103e1565b9150915061013c8282610183565b5050565b6100f861014b610150565b6101de565b600061010c7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b61018c82610202565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a28051156101d6576101d18282610279565b505050565b61013c6102ef565b3660008037600080366000845af43d6000803e8080156101fd573d6000f35b3d6000fd5b806001600160a01b03163b6000036102385780604051634c9c8ce360e01b815260040161022f919061038d565b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080846001600160a01b03168460405161029691906104b1565b600060405180830381855af49150503d80600081146102d1576040519150601f19603f3d011682016040523d82523d6000602084013e6102d6565b606091505b50915091506102e685838361030e565b95945050505050565b34156100f85760405163b398979f60e01b815260040160405180910390fd5b6060826103235761031e82610364565b61035d565b815115801561033a57506001600160a01b0384163b155b1561035a5783604051639996b31560e01b815260040161022f919061038d565b50805b9392505050565b8051156103745780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6001600160a01b0391909116815260200190565b600080858511156103b157600080fd5b838611156103be57600080fd5b5050820193919092039150565b634e487b7160e01b600052604160045260246000fd5b600080604083850312156103f457600080fd5b82356001600160a01b038116811461040b57600080fd5b9150602083013567ffffffffffffffff8082111561042857600080fd5b818501915085601f83011261043c57600080fd5b81358181111561044e5761044e6103cb565b604051601f8201601f19908116603f01168101908382118183101715610476576104766103cb565b8160405282815288602084870101111561048f57600080fd5b8260208601602083013760006020848301015280955050505050509250929050565b6000825160005b818110156104d257602081860181015185830152016104b8565b50600092019182525091905056fea2646970667358221220660bd151a9462bc0dfda57427e70a67401a61e3ea04462dab0d2758cf0854d8964736f6c63430008150033", + "devdoc": { + "errors": { + "AddressEmptyCode(address)": [ + { + "details": "There's no code at `target` (it is not a contract)." + } + ], + "ERC1967InvalidAdmin(address)": [ + { + "details": "The `admin` of the proxy is invalid." + } + ], + "ERC1967InvalidImplementation(address)": [ + { + "details": "The `implementation` of the proxy is invalid." + } + ], + "ERC1967NonPayable()": [ + { + "details": "An upgrade function sees `msg.value > 0` that may be lost." + } + ], + "FailedInnerCall()": [ + { + "details": "A call to an address target failed. The target may have reverted." + } + ], + "ProxyDeniedAdminAccess()": [ + { + "details": "The proxy caller is the current admin, and can't fallback to the proxy target." + } + ] + }, + "events": { + "AdminChanged(address,address)": { + "details": "Emitted when the admin account has changed." + }, + "Upgraded(address)": { + "details": "Emitted when the implementation is upgraded." + } + }, + "kind": "dev", + "methods": { + "implementation()": { + "details": "Returns the implementation address of the proxy." + }, + "proxyAdmin()": { + "details": "Returns the admin of this proxy." + } + }, + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": {}, + "version": 1 + }, + "storageLayout": { + "storage": [], + "types": null + } +} \ No newline at end of file diff --git a/deployments/base/BuyBackBurnMaha.json b/deployments/base/BuyBackBurnMaha.json new file mode 100644 index 0000000..2f488fc --- /dev/null +++ b/deployments/base/BuyBackBurnMaha.json @@ -0,0 +1,435 @@ +{ + "address": "0x8Dbe7A9bec93AD3AC3B4d29AFD87c7209f3560Ba", + "abi": [ + { + "inputs": [], + "name": "AccessControlBadConfirmation", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "neededRole", + "type": "bytes32" + } + ], + "name": "AccessControlUnauthorizedAccount", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "target", + "type": "address" + } + ], + "name": "AddressEmptyCode", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "AddressInsufficientBalance", + "type": "error" + }, + { + "inputs": [], + "name": "FailedInnerCall", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidInitialization", + "type": "error" + }, + { + "inputs": [], + "name": "NotInitializing", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "SafeERC20FailedOperation", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "version", + "type": "uint64" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "previousAdminRole", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "bytes32", + "name": "newAdminRole", + "type": "bytes32" + } + ], + "name": "RoleAdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleGranted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "RoleRevoked", + "type": "event" + }, + { + "inputs": [], + "name": "DEAD_ADDRESS", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DEFAULT_ADMIN_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DISTRIBUTOR_ROLE", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "odosData", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "buyMahaBurn", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + } + ], + "name": "getRoleAdmin", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "grantRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "hasRole", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_maha", + "type": "address" + }, + { + "internalType": "address", + "name": "_usdc", + "type": "address" + }, + { + "internalType": "address", + "name": "_odos", + "type": "address" + }, + { + "internalType": "address", + "name": "_distributor", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "maha", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "odos", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + } + ], + "name": "refund", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "callerConfirmation", + "type": "address" + } + ], + "name": "renounceRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "role", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "revokeRole", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_newOdos", + "type": "address" + } + ], + "name": "setOdos", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "usdc", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "args": [ + "0x554bba833518793056CF105E66aBEA330672c0dE", + "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + "0x19cEeAd7105607Cd444F5ad10dd51356436095a1", + "0x5A61eD1eC946068E261694E85fe017F3BF3FF76e" + ], + "numDeployments": 2 +} \ No newline at end of file diff --git a/package.json b/package.json index 0bbb3dd..306f6fb 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "@types/underscore": "^1.11.15", "bluebird": "^3.7.2", "chai": "^4.2.0", + "csv-parser": "^3.0.0", "dotenv": "^16.4.5", "eth-sig-util": "2.5.3", "ethereumjs-util": "7.0.2", @@ -81,6 +82,7 @@ "hardhat-typechain": "^0.3.5", "husky": "8.0.3", "lint-staged": "13.1.0", + "merkletreejs": "^0.4.0", "prettier": "2.8.4", "prettier-plugin-solidity": "1.1.3", "rimraf": "^6.0.1", diff --git a/scripts/merkle/.gitignore b/scripts/merkle/.gitignore new file mode 100644 index 0000000..8130cb4 --- /dev/null +++ b/scripts/merkle/.gitignore @@ -0,0 +1,2 @@ +/*.csv +/*.json \ No newline at end of file diff --git a/scripts/merkle/createMerkle.ts b/scripts/merkle/createMerkle.ts new file mode 100644 index 0000000..0ed728b --- /dev/null +++ b/scripts/merkle/createMerkle.ts @@ -0,0 +1,127 @@ +import { ethers } from "hardhat"; +import { MerkleTree } from "merkletreejs"; +import fs from "fs"; +import path from "path"; +import csv from "csv-parser"; +import { keccak256 } from "ethers"; + +type UserDetails = { + user: string; + nftId: number; + mahaLocked: number; + startDate: number; + endDate: number; + bonus: number; +}; + +const parseCSV = async (filePath: string): Promise => { + return new Promise((resolve, reject) => { + const results: UserDetails[] = []; + fs.createReadStream(filePath) + .pipe(csv()) + .on("data", (data) => { + try { + const userAddress = ethers.getAddress(data.user.toLowerCase()); // Normalize and checksum address + + const userDetails: UserDetails = { + user: userAddress, + nftId: parseInt(data.nftId, 10), + mahaLocked: Number(data.mahaLocked), + startDate: parseInt(data.startDate, 10), + endDate: parseInt(data.endDate, 10), + bonus: Number(data.bonus), + }; + + // Validate the data + if ( + !ethers.isAddress(userDetails.user) || + isNaN(userDetails.nftId) || + isNaN(userDetails.mahaLocked) || + isNaN(userDetails.startDate) || + isNaN(userDetails.endDate) || + isNaN(userDetails.bonus) + ) { + throw new Error(`Invalid data format: ${JSON.stringify(data)}`); + } + + if (userDetails.endDate <= userDetails.startDate) { + throw new Error(`End date must be greater than start date: ${JSON.stringify(data)}`); + } + + results.push(userDetails); + } catch (err) { + console.error("Skipping invalid row:", data, err); + } + }) + .on("end", () => resolve(results)) + .on("error", (error) => reject(error)); + }); +}; + +const hashLeafNode = ( + user: string, + nftId: number, + mahaLocked: number, + startDate: number, + endDate: number, + bonus: number +): Buffer => { + return Buffer.from( + keccak256( + ethers.AbiCoder.defaultAbiCoder().encode( + ["address", "uint256", "uint256", "uint256", "uint256", "uint256"], + [user, nftId, mahaLocked, startDate, endDate, bonus] + ) + ).substring(2), // Remove the "0x" prefix + "hex" + ); +}; + +const generateMerkleTree = (userDetails: UserDetails[]) => { + const leafNodes = userDetails.map((detail) => + hashLeafNode( + detail.user, + detail.nftId, + detail.mahaLocked, + detail.startDate, + detail.endDate, + detail.bonus + ) + ); + + const merkleTree = new MerkleTree(leafNodes, keccak256, { sortPairs: true }); + const merkleRoot = merkleTree.getHexRoot(); + + console.log("Merkle Tree Root:", merkleRoot); + + return { + root: merkleRoot, + leaves: userDetails.map((data, index) => ({ + data, + proof: merkleTree.getHexProof(leafNodes[index]), + })), + }; +}; + +async function main() { + const csvFilePath = path.resolve(__dirname, "./userDetails.csv"); + const outputFilePath = path.resolve(__dirname, "./merkleTreeOutput.json"); + + try { + const userDetails = await parseCSV(csvFilePath); + + if (userDetails.length === 0) { + throw new Error("No valid data found in the CSV file."); + } + + const merkleTreeData = generateMerkleTree(userDetails); + + fs.writeFileSync(outputFilePath, JSON.stringify(merkleTreeData, null, 2)); + console.log("Merkle tree written to:", outputFilePath); + } catch (err) { + console.error("An error occurred:", err); + process.exitCode = 1; + } +} + +main(); diff --git a/scripts/utils.ts b/scripts/utils.ts index 925c6df..12d9123 100644 --- a/scripts/utils.ts +++ b/scripts/utils.ts @@ -77,17 +77,17 @@ export async function deployProxy( args: args, }); - // if (hre.network.name !== "hardhat") { - // console.log("verifying contracts"); - // await hre.run("verify:verify", { - // address: implementationD.address, - // constructorArguments: [], - // }); - // await hre.run("verify:verify", { - // address: proxy.address, - // constructorArguments: [implementationD.address, proxyAdmin, argsInit], - // }); - // } + if (hre.network.name !== "hardhat") { + console.log("verifying contracts"); + await hre.run("verify:verify", { + address: implementationD.address, + constructorArguments: [], + }); + await hre.run("verify:verify", { + address: proxy.address, + constructorArguments: [implementationD.address, proxyAdmin, argsInit], + }); + } return proxy; } diff --git a/yarn.lock b/yarn.lock index 11e266b..b38f15e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2676,6 +2676,11 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== +buffer-reverse@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-reverse/-/buffer-reverse-1.0.1.tgz#49283c8efa6f901bc01fa3304d06027971ae2f60" + integrity sha512-M87YIUBsZ6N924W57vDwT/aOu8hw7ZgdByz6ijksLjmHJELBASmYTTlNHRgjE+pTsT9oJXGaDSgqqwfdHotDUg== + buffer-xor@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" @@ -3145,6 +3150,18 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.3: resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow== +crypto-js@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631" + integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q== + +csv-parser@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/csv-parser/-/csv-parser-3.0.0.tgz#b88a6256d79e090a97a1b56451f9327b01d710e7" + integrity sha512-s6OYSXAK3IdKqYO33y09jhypG/bSDHPuyCme/IdEHfWpLf/jKcpitVFyOC6UemgGk8v7Q5u2XE0vvwmanxhGlQ== + dependencies: + minimist "^1.2.0" + data-view-buffer@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" @@ -5452,6 +5469,17 @@ merge2@^1.2.3, merge2@^1.3.0: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== +merkletreejs@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/merkletreejs/-/merkletreejs-0.4.0.tgz#40514dd8b5f511b3f136aeea3ff90d74d5604112" + integrity sha512-a48Ta5kWiVNBgeEbZVMm6FB1hBlp6vEuou/XnZdlkmd2zq6NZR6Sh2j+kR1B0iOZIXrTMcigBYzZ39MLdYhm1g== + dependencies: + bignumber.js "^9.0.1" + buffer-reverse "^1.0.1" + crypto-js "^4.2.0" + treeify "^1.1.0" + web3-utils "^1.3.4" + methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" @@ -6727,7 +6755,7 @@ string-format@^2.0.0: resolved "https://registry.yarnpkg.com/string-format/-/string-format-2.0.0.tgz#f2df2e7097440d3b65de31b6d40d54c96eaffb9b" integrity sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA== -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -6744,6 +6772,15 @@ string-width@^2.1.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" +string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string-width@^5.0.0, string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" @@ -6795,7 +6832,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -6809,6 +6846,13 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^7.0.1: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -7347,7 +7391,7 @@ vary@~1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== -web3-utils@^1.3.6: +web3-utils@^1.3.4, web3-utils@^1.3.6: version "1.10.4" resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.10.4.tgz#0daee7d6841641655d8b3726baf33b08eda1cbec" integrity sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A== @@ -7473,7 +7517,7 @@ workerpool@^6.5.1: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -7491,6 +7535,15 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"