From e524fdce77fc52db07ad5765122a1e4508f762a9 Mon Sep 17 00:00:00 2001 From: Borja Aranda Date: Tue, 11 Mar 2025 18:53:52 +0100 Subject: [PATCH 01/24] Payer contract implementation --- contracts/src/Payer.sol | 471 ++++++++++++++++++++++++++++ contracts/src/interfaces/IPayer.sol | 386 +++++++++++++++++++++++ 2 files changed, 857 insertions(+) create mode 100644 contracts/src/Payer.sol create mode 100644 contracts/src/interfaces/IPayer.sol diff --git a/contracts/src/Payer.sol b/contracts/src/Payer.sol new file mode 100644 index 00000000..07dbeb44 --- /dev/null +++ b/contracts/src/Payer.sol @@ -0,0 +1,471 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import "@openzeppelin-contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import "@openzeppelin-contracts-upgradeable/utils/PausableUpgradeable.sol"; +import "@openzeppelin-contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; +import "@openzeppelin-contracts-upgradeable/proxy/utils/Initializable.sol"; +import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; +import "./interfaces/IPayer.sol"; +import "./interfaces/INodes.sol"; + +interface INodesCaller { + // TODO: Node has to implement ERC721Enumerable or an ad-hoc function (senderIsNodeOperator) + function senderIsActiveNodeOperator(address sender) external view returns (bool isNodeOperator); + function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256); +} + +/** + * @title Payer + * @notice Implementation for managing payer USDC deposits, usage settlements, + * and a secure withdrawal process with optimized storage using + * Merkle trees and EIP-1283 gas optimizations. + */ +contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, PausableUpgradeable, IPayer{ + using SafeERC20 for IERC20; + using EnumerableSet for EnumerableSet.AddressSet; + + /// @dev Roles + bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE"); + + /// @dev USDC token contract + IERC20 public usdcToken; + + /// @dev Distribution contract + address public distributionContract; + + /// @dev Nodes contract + address public nodesContract; + + /// @dev Payer report contract + address public payerReportContract; + + /// @dev Minimum deposit amount in micro-USDC + uint256 public minimumDepositMicroDollars = 10_000_000; + + /// @dev Pending fees + uint256 public pendingFees; + + /// @dev Last fee transfer timestamp + uint256 public lastFeeTransferTimestamp; + + /// @dev Withdrawal lock period + uint256 public withdrawalLockPeriod = 3 days; + + /// @dev Maximum backdated time + uint256 public maxBackdatedTime = 1 days; + + /// @dev Mapping of payer address to their information + mapping(address => Payer) private payers; + + /// @dev Mapping of payer address to withdrawal information + mapping(address => Withdrawal) private withdrawals; + + /// @dev Set of all payer addresses + EnumerableSet.AddressSet private totalPayers; + + /// @dev Set of active payer addresses + EnumerableSet.AddressSet private activePayers; + + /// @dev Total value locked + uint256 public totalValueLocked; + + /// @dev Total debt amount + uint256 public totalDebtAmount; + + //============================================================== + // Modifiers + //============================================================== + + /** + * @dev Modifier to check if caller is an active node operator + */ + modifier onlyNodeOperator() { + if (!getIsActiveNodeOperator(msg.sender)) { + revert UnauthorizedNodeOperator(); + } + _; + } + + /** + * @dev Modifier to check if caller is the payer report contract + */ + modifier onlyPayerReport() { + if (msg.sender != payerReportContract) { + revert NotPayerReportContract(); + } + _; + } + + /** + * @dev Modifier to check if address is an active payer + */ + modifier onlyPayer(address payer) { + require(_payerExists(payer), PayerDoesNotExist(payer)); + _; + } + + //============================================================== + // Initialization + //============================================================== + + /// @notice Initializes the contract with the deployer as admin. + /// @param _initialAdmin The address of the admin. + function initialize( + address _initialAdmin, + address _usdcToken, + address _distributionContract, + address _nodesContract, + uint256 _withdrawalLockPeriod, + uint256 _maxBackdatedTime + ) public initializer { + if (_initialAdmin == address(0) || + _usdcToken == address(0) || + _nodesContract == address(0) || + _withdrawalLockPeriod == 0 || + _maxBackdatedTime == 0) { + revert InvalidAddress(); + } + + __UUPSUpgradeable_init(); + __AccessControl_init(); + __Pausable_init(); + + _grantRole(DEFAULT_ADMIN_ROLE, _initialAdmin); + _grantRole(ADMIN_ROLE, _initialAdmin); + + usdcToken = IERC20(_usdcToken); + distributionContract = _distributionContract; + nodesContract = _nodesContract; + withdrawalLockPeriod = _withdrawalLockPeriod; + maxBackdatedTime = _maxBackdatedTime; + } + + //============================================================== + // Payers Management + //============================================================== + + /** + * @inheritdoc IPayer + */ + function register(uint256 amount) external whenNotPaused { + require(amount >= minimumDepositMicroDollars, InsufficientAmount()); + require(!_payerExists(msg.sender), PayerAlreadyRegistered(msg.sender)); + + // Transfer USDC from the sender to this contract + usdcToken.safeTransferFrom(msg.sender, address(this), amount); + + // New payer registration + payers[msg.sender] = Payer({ + balance: amount, + isActive: true, + creationTimestamp: block.timestamp, + latestDepositTimestamp: block.timestamp, + debtAmount: 0 + }); + + // Add new payer to active and total payers sets + activePayers.add(msg.sender); + totalPayers.add(msg.sender); + + // Update counters + totalValueLocked += amount; + + emit PayerRegistered(msg.sender, amount); + } + + /** + * @inheritdoc IPayer + */ + function deposit(uint256 amount) external whenNotPaused onlyPayer(msg.sender) { + require(amount > 0, InsufficientAmount()); + + if (withdrawals[msg.sender].requestTimestamp != 0) { + revert PayerInWithdrawal(); + } + + // Transfer USDC from sender to this contract + usdcToken.safeTransferFrom(msg.sender, address(this), amount); + + // Update payer record + payers[msg.sender].balance += amount; + payers[msg.sender].latestDepositTimestamp = block.timestamp; + totalValueLocked += amount; + + emit Deposit(msg.sender, amount); + } + + /** + * @inheritdoc IPayer + */ + function donate(address payer, uint256 amount) external whenNotPaused { + require(amount > 0, InsufficientAmount()); + require(_payerExists(payer), PayerDoesNotExist(payer)); + + if (withdrawals[payer].requestTimestamp != 0) { + revert PayerInWithdrawal(); + } + + // Transfer USDC from sender to this contract + usdcToken.safeTransferFrom(msg.sender, address(this), amount); + + // Update payer record + payers[payer].balance += amount; + + // Update TVL + totalValueLocked += amount; + + emit Donation(msg.sender, payer, amount); + } + + /** + * @inheritdoc IPayer + */ + function deactivatePayer(address payer) external whenNotPaused onlyRole(ADMIN_ROLE) { + require(_payerExists(payer), PayerDoesNotExist(payer)); + payers[payer].isActive = false; + activePayers.remove(payer); + emit PayerDeactivated(payer); + } + + /** + * @inheritdoc IPayer + */ + function deletePayer(address payer) external whenNotPaused onlyRole(ADMIN_ROLE) { + require(_payerExists(payer), PayerDoesNotExist(payer)); + + if (payers[payer].balance > 0 || payers[payer].debtAmount > 0) { + revert PayerHasBalanceOrDebt(); + } + + if (withdrawals[payer].requestTimestamp != 0) { + revert PayerInWithdrawal(); + } + + // Delete payer data + delete payers[payer]; + + // Remove from totalPayers set + totalPayers.remove(payer); + activePayers.remove(payer); + + emit PayerDeleted(payer, block.timestamp); + } + + /** + * @inheritdoc IPayer + */ + function getIsActivePayer(address payer) public view returns (bool isActive) { + return activePayers.contains(payer); + } + + //============================================================== + // Payers Balance Management + //============================================================== + + /** + * @inheritdoc IPayer + */ + function getPayerBalance(address payer) external view returns (uint256 balance) { + require(_payerExists(payer), PayerDoesNotExist(payer)); + return payers[payer].balance; + } + + /** + * @inheritdoc IPayer + */ + function requestWithdrawal(uint256 amount) external whenNotPaused() onlyPayer(msg.sender) { + // TODO: Implement withdrawal request logic + } + + /** + * @inheritdoc IPayer + */ + function cancelWithdrawal() external whenNotPaused() onlyPayer(msg.sender) { + // TODO: Implement withdrawal cancellation logic + } + + /** + * @inheritdoc IPayer + */ + function finalizeWithdrawal() external whenNotPaused() onlyPayer(msg.sender) { + // TODO: Implement withdrawal finalization logic + } + + /** + * @inheritdoc IPayer + */ + function getWithdrawalStatus(address payer) external view returns (Withdrawal memory withdrawal) { + // TODO: Implement withdrawal status retrieval logic + } + + //============================================================== + // Usage Settlement + //============================================================== + + /** + * @inheritdoc IPayer + */ + function settleUsage( + address originatorNode, + uint256 reportIndex, + address[] calldata payerList, + uint256[] calldata amounts + ) external whenNotPaused onlyPayerReport + { + // TODO: Implement usage settlement logic + } + + function calculateFees(uint256 amount) external view returns (uint256 fees) { + // TODO: Implement fee calculation logic + } + + /** + * @inheritdoc IPayer + */ + function transferFeesToDistribution() external whenNotPaused onlyRole(ADMIN_ROLE) { + // TODO: Implement fee transfer logic + } + + //============================================================== + // Administrative Functions + //============================================================== + + /** + * @inheritdoc IPayer + */ + function setDistributionContract(address _newDistributionContract) external onlyRole(ADMIN_ROLE) { + require (_newDistributionContract != address(0), InvalidAddress()); + // TODO: Add check to ensure the new distribution contract is valid + distributionContract = _newDistributionContract; + emit DistributionContractUpdated(_newDistributionContract); + } + + /** + * @inheritdoc IPayer + */ + function setNodesContract(address _newNodesContract) external onlyRole(ADMIN_ROLE) { + require (_newNodesContract != address(0), InvalidAddress()); + // TODO: Add check to ensure the new nodes contract is valid + nodesContract = _newNodesContract; + emit NodesContractUpdated(_newNodesContract); + } + + /** + * @inheritdoc IPayer + */ + function setPayerReportContract(address _newPayerReportContract) external onlyRole(ADMIN_ROLE) { + require (_newPayerReportContract != address(0), InvalidAddress()); + // TODO: Add check to ensure the new payer report contract is valid + payerReportContract = _newPayerReportContract; + emit PayerReportContractUpdated(_newPayerReportContract); + } + + /** + * @inheritdoc IPayer + */ + function setMinimumDeposit(uint256 _newMinimumDeposit) external onlyRole(ADMIN_ROLE) { + uint256 oldMinimumDeposit = minimumDepositMicroDollars; + minimumDepositMicroDollars = _newMinimumDeposit; + emit MinimumDepositUpdated(oldMinimumDeposit, _newMinimumDeposit); + } + + /** + * @inheritdoc IPayer + */ + function getPayersInDebt(uint256 offset, uint256 limit) external view returns ( + address[] memory debtors, + uint256[] memory debtAmounts, + uint256 totalCount + ) { + // TODO: Implement payers in debt retrieval logic + } + + /** + * @inheritdoc IPayer + */ + function getContractBalance() external view returns (uint256 balance) { + return usdcToken.balanceOf(address(this)); + } + + /** + * @inheritdoc IPayer + */ + function pause() external onlyRole(ADMIN_ROLE) { + _pause(); + } + + /** + * @inheritdoc IPayer + */ + function unpause() external onlyRole(ADMIN_ROLE) { + _unpause(); + } + + // Upgradeability + /// @dev Authorizes the upgrade of the contract. + /// @param newImplementation The address of the new implementation. + function _authorizeUpgrade(address newImplementation) internal override onlyRole(DEFAULT_ADMIN_ROLE) { + require(newImplementation != address(0), "New implementation cannot be zero address"); + emit UpgradeAuthorized(msg.sender, newImplementation); + } + + /** + * @inheritdoc IPayer + */ + function getIsActiveNodeOperator(address operator) public view returns (bool) { + INodesCaller nodes = INodesCaller(nodesContract); + require(address(nodes) != address(0), Unauthorized()); + + return nodes.senderIsActiveNodeOperator(operator); + } + + //============================================================== + // Getters + //============================================================== + + /** + * @inheritdoc IPayer + */ + function getTotalPayerCount() external view returns (uint256 count) { + return totalPayers.length(); + } + + /** + * @inheritdoc IPayer + */ + function getActivePayerCount() external view returns (uint256 count) { + return activePayers.length(); + } + + /** + * @inheritdoc IPayer + */ + function getLastFeeTransferTimestamp() external view returns (uint256 timestamp) { + return lastFeeTransferTimestamp; + } + + function getTotalValueLocked() external view returns (uint256 tvl) { + // TODO: TVL should subtract the total debt amount + return totalValueLocked; + } + + function getTotalDebtAmount() external view returns (uint256 totalDebt) { + return totalDebtAmount; + } + + //============================================================== + // Internal Functions + //============================================================== + + /** + * @dev Checks if a payer exists. + * @param payer The address of the payer to check. + * @return exists True if the payer exists, false otherwise. + */ + function _payerExists(address payer) internal view returns (bool exists) { + return payers[payer].creationTimestamp != 0; + } +} \ No newline at end of file diff --git a/contracts/src/interfaces/IPayer.sol b/contracts/src/interfaces/IPayer.sol new file mode 100644 index 00000000..f4d1fd12 --- /dev/null +++ b/contracts/src/interfaces/IPayer.sol @@ -0,0 +1,386 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +/** + * @title IPayer + * @notice Interface for managing payer USDC deposits, usage settlements, + * and a secure withdrawal process. + */ +interface IPayer { + //============================================================== + // STRUCTS + //============================================================== + + /** + * @dev Struct to store payer information. + * @param balance The current USDC balance of the payer. + * @param isActive Indicates whether the payer is active. + * @param creationTimestamp The timestamp when the payer was first registered. + * @param latestDepositTimestamp The timestamp of the most recent deposit. + * @param debtAmount The amount of fees owed but not yet settled. + */ + struct Payer { + uint256 balance; + bool isActive; + uint256 creationTimestamp; + uint256 latestDepositTimestamp; + uint256 debtAmount; + } + + /** + * @dev Struct to store withdrawal request information. + * @param requestTimestamp The timestamp when the withdrawal was requested. + * @param withdrawableTimestamp The timestamp when the withdrawal can be finalized. + * @param amount The amount requested for withdrawal. + */ + struct Withdrawal { + uint256 requestTimestamp; + uint256 withdrawableTimestamp; + uint256 amount; + } + + //============================================================== + // EVENTS + //============================================================== + + /// @dev Emitted when a deposit is made to a payer's account. + event Deposit(address indexed payer, uint256 amount); + + /// @dev Emitted when the distribution contract address is updated. + event DistributionContractUpdated(address indexed newDistributionContract); + + /// @dev Emitted when a user donates to a payer's account. + event Donation(address indexed donor, address indexed payer, uint256 amount); + + /// @dev Emitted when fees are transferred to the distribution contract. + event FeesTransferred(uint256 amount); + + /// @dev Emitted when the minimum deposit amount is updated. + event MinimumDepositUpdated(uint256 oldMinimumDeposit, uint256 newMinimumDeposit); + + /// @dev Emitted when the nodes contract address is updated. + event NodesContractUpdated(address indexed newNodesContract); + + /// @dev Emitted when a payer is deactivated by an owner. + event PayerDeactivated(address indexed payer); + + /// @dev Emitted when a payer is permanently deleted from the system. + event PayerDeleted(address indexed payer, uint256 timestamp); + + /// @dev Emitted when a new payer is registered. + event PayerRegistered(address indexed payer, uint256 amount); + + /// @dev Emitted when the payer report contract address is updated. + event PayerReportContractUpdated(address indexed newPayerReportContract); + + /// @dev Emitted when the upgrade is authorized. + event UpgradeAuthorized(address indexed upgrader, address indexed newImplementation); + + /// @dev Emitted when usage is settled and fees are calculated. + event UsageSettled(uint256 fees, address indexed payer, uint256 indexed originatorNode, uint256 timestamp); + + /// @dev Emitted when a payer cancels a withdrawal request. + event WithdrawalCancelled(address indexed payer); + + /// @dev Emitted when a payer's withdrawal is finalized. + event WithdrawalFinalized(address indexed payer, uint256 amountReturned); + + /// @dev Emitted when a payer initiates a withdrawal request. + event WithdrawalRequest(address indexed payer, uint256 requestTimestamp, uint256 withdrawableTimestamp, uint256 amount); + + //============================================================== + // ERRORS + //============================================================== + + /// @dev Error thrown when arrays have mismatched lengths. + error ArrayLengthMismatch(); + + /// @dev Error thrown when the amount is insufficient. + error InsufficientAmount(); + + /// @dev Error thrown when an address is invalid (usually zero address). + error InvalidAddress(); + + /// @dev Error thrown when trying to backdate settlement too far. + error InvalidSettlementTime(); + + /// @dev Error thrown when a lock period has not yet elapsed. + error LockPeriodNotElapsed(); + + /// @dev Error thrown when caller is not the distribution contract. + error NotDistributionContract(); + + /// @dev Error thrown when caller is not the payer report contract. + error NotPayerReportContract(); + + /// @dev Error thrown when a payer is already registered. + error PayerAlreadyRegistered(address); + + /// @dev Error thrown when a payer does not exist. + error PayerDoesNotExist(address); + + /// @dev Error thrown when trying to delete a payer with balance or debt. + error PayerHasBalanceOrDebt(); + + /// @dev Error thrown when trying to delete a payer in withdrawal state. + error PayerInWithdrawal(); + + /// @dev Error thrown in case of an unauthorized access. + error Unauthorized(); + + /// @dev Error thrown when caller is not an authorized node operator. + error UnauthorizedNodeOperator(); + + /// @dev Error thrown when a withdrawal is already in progress. + error WithdrawalAlreadyRequested(); + + /// @dev Error thrown when a withdrawal is not in the requested state. + error WithdrawalNotRequested(); + + //============================================================== + // PAYER REGISTRATION & MANAGEMENT + //============================================================== + + /** + * @notice Registers the caller as a new payer upon depositing the minimum required USDC. + * The caller must approve this contract to spend USDC beforehand. + * @param amount The amount of USDC to deposit (must be at least the minimum required). + * + * Emits `PayerRegistered`. + */ + function register(uint256 amount) external; + + /** + * @notice Allows the caller to deposit USDC into their own payer account. + * The caller must approve this contract to spend USDC beforehand. + * @param amount The amount of USDC to deposit. + * + * Emits `Deposit`. + */ + function deposit(uint256 amount) external; + + /** + * @notice Allows anyone to donate USDC to an existing payer's account. + * The sender must approve this contract to spend USDC beforehand. + * @param payer The address of the payer receiving the donation. + * @param amount The amount of USDC to donate. + * + * Emits `Donation`. + */ + function donate(address payer, uint256 amount) external; + + /** + * @notice Deactivates a payer, preventing them from initiating new transactions. + * Only callable by authorized node operators. + * @param payer The address of the payer to deactivate. + * + * Emits `PayerDeactivated`. + */ + function deactivatePayer(address payer) external; + + /** + * @notice Permanently deletes a payer from the system. + * @dev Can only delete payers with zero balance and zero debt who are not in withdrawal. + * Only callable by authorized node operators. + * @param payer The address of the payer to delete. + * + * Emits `PayerDeleted`. + */ + function deletePayer(address payer) external; + + /** + * @notice Checks if a given address is an active payer. + * @param payer The address to check. + * @return isActive True if the address is an active payer, false otherwise. + */ + function getIsActivePayer(address payer) external view returns (bool isActive); + + /** + * @notice Updates the minimum deposit amount required for registration. + * @param newMinimumDeposit The new minimum deposit amount. + * + * Emits `MinimumDepositUpdated`. + */ + function setMinimumDeposit(uint256 newMinimumDeposit) external; + + //============================================================== + // PAYER BALANCE MANAGEMENT + //============================================================== + + /** + * @notice Retrieves the current total balance of a given payer. + * @param payer The address of the payer. + * @return balance The current balance of the payer. + */ + function getPayerBalance(address payer) external view returns (uint256 balance); + + /** + * @notice Initiates a withdrawal request for the caller. + * - Sets the payer into withdrawal mode (no further usage allowed). + * - Records a timestamp for the withdrawal lock period. + * @param amount The amount to withdraw (can be less than or equal to current balance). + * + * Emits `WithdrawalRequest`. + */ + function requestWithdrawal(uint256 amount) external; + + /** + * @notice Cancels a previously requested withdrawal, removing withdrawal mode. + * @dev Only callable by the payer who initiated the withdrawal. + * + * Emits `WithdrawalCancelled`. + */ + function cancelWithdrawal() external; + + /** + * @notice Finalizes a payer's withdrawal after the lock period has elapsed. + * - Accounts for any pending usage during the lock. + * - Returns the unspent balance to the payer. + * + * Emits `WithdrawalFinalized`. + */ + function finalizeWithdrawal() external; + + /** + * @notice Checks if a payer is currently in withdrawal mode and the timestamp + * when they initiated the withdrawal. + * @param payer The address to check. + * @return withdrawal The withdrawal status of the payer. + */ + function getWithdrawalStatus(address payer) + external + view + returns (Withdrawal memory withdrawal); + + //============================================================== + // USAGE SETTLEMENT + //============================================================== + + /** + * @notice Settles usage for a contiguous batch of (payer, amount) entries. + * Assumes that the PayerReport contract has already verified the aggregated Merkle proof. + * + * @param originatorNode The node that submitted the report. + * @param reportIndex The index of the report. + * @param payers A contiguous array of payer addresses. + * @param amounts A contiguous array of usage amounts corresponding to each payer. + */ + function settleUsage( + address originatorNode, + uint256 reportIndex, + address[] calldata payers, + uint256[] calldata amounts + ) external /* onlyPayerReport */ ; + + /** + * @notice Transfers all pending fees to the designated distribution contract. + * @dev Uses a single storage write for updating accumulated fees. + * + * Emits `FeesTransferred`. + */ + function transferFeesToDistribution() external; + + //============================================================== + // OBSERVABILITY FUNCTIONS + //============================================================== + + /** + * @notice Returns the total value locked in the contract (all payer balances). + * @return tvl The total value locked in USDC. + */ + function getTotalValueLocked() external view returns (uint256 tvl); + + /** + * @notice Returns the total outstanding debt amount across all payers. + * @return totalDebt The total debt amount in USDC. + */ + function getTotalDebtAmount() external view returns (uint256 totalDebt); + + /** + * @notice Returns the total number of registered payers. + * @return count The total number of registered payers. + */ + function getTotalPayerCount() external view returns (uint256 count); + + /** + * @notice Returns the number of active payers. + * @return count The number of active payers. + */ + function getActivePayerCount() external view returns (uint256 count); + + /** + * @notice Returns the timestamp of the last fee transfer to the rewards contract. + * @return timestamp The last fee transfer timestamp. + */ + function getLastFeeTransferTimestamp() external view returns (uint256 timestamp); + + /** + * @notice Returns a paginated list of payers with outstanding debt. + * @param offset Number of payers to skip before starting to return results. + * @param limit Maximum number of payers to return. + * @return debtors Array of payer addresses with debt. + * @return debtAmounts Corresponding debt amounts for each payer. + * @return totalCount Total number of payers with debt (regardless of pagination). + */ + function getPayersInDebt(uint256 offset, uint256 limit) external view returns ( + address[] memory debtors, + uint256[] memory debtAmounts, + uint256 totalCount + ); + + /** + * @notice Returns the actual USDC balance held by the contract. + * @dev This can be used to verify the contract's accounting is accurate. + * @return balance The USDC token balance of the contract. + */ + function getContractBalance() external view returns (uint256 balance); + + //============================================================== + // ADMINISTRATIVE FUNCTIONS + //============================================================== + + /** + * @notice Sets the address of the distribution contract. + * @param _distributionContract The address of the new distribution contract. + * + * Emits `DistributionContractUpdated`. + */ + function setDistributionContract(address _distributionContract) external; + + /** + * @notice Sets the address of the nodes contract for operator verification. + * @param _nodesContract The address of the new nodes contract. + * + * Emits `NodesContractUpdated`. + */ + function setNodesContract(address _nodesContract) external; + + /** + * @notice Sets the address of the payer report contract. + * @param _payerReportContract The address of the new payer report contract. + * + * Emits `PayerReportContractUpdated`. + */ + function setPayerReportContract(address _payerReportContract) external; + + /** + * @notice Pauses the contract functions in case of emergency. + * + * Emits `Paused()`. + */ + function pause() external; + + /** + * @notice Unpauses the contract. + * + * Emits `Unpaused()`. + */ + function unpause() external; + + /** + * @notice Checks if a given address is an active node operator. + * @param operator The address to check. + * @return isActiveNodeOperator True if the address is an active node operator, false otherwise. + */ + function getIsActiveNodeOperator(address operator) external view returns (bool isActiveNodeOperator); +} \ No newline at end of file From ff743f12941fbc307a083fad362f0a6a1b7c35de Mon Sep 17 00:00:00 2001 From: Borja Aranda Date: Tue, 11 Mar 2025 19:03:13 +0100 Subject: [PATCH 02/24] ordering --- contracts/src/Payer.sol | 46 +++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/contracts/src/Payer.sol b/contracts/src/Payer.sol index 07dbeb44..7118be40 100644 --- a/contracts/src/Payer.sol +++ b/contracts/src/Payer.sol @@ -254,13 +254,6 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus emit PayerDeleted(payer, block.timestamp); } - /** - * @inheritdoc IPayer - */ - function getIsActivePayer(address payer) public view returns (bool isActive) { - return activePayers.contains(payer); - } - //============================================================== // Payers Balance Management //============================================================== @@ -372,17 +365,6 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus emit MinimumDepositUpdated(oldMinimumDeposit, _newMinimumDeposit); } - /** - * @inheritdoc IPayer - */ - function getPayersInDebt(uint256 offset, uint256 limit) external view returns ( - address[] memory debtors, - uint256[] memory debtAmounts, - uint256 totalCount - ) { - // TODO: Implement payers in debt retrieval logic - } - /** * @inheritdoc IPayer */ @@ -426,6 +408,34 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus // Getters //============================================================== + /** + * @dev Returns the payer information. + * @param payer The address of the payer. + * @return payerInfo The payer information. + */ + function getPayer(address payer) external view returns (Payer memory payerInfo) { + require(_payerExists(payer), PayerDoesNotExist(payer)); + return payers[payer]; + } + + /** + * @inheritdoc IPayer + */ + function getIsActivePayer(address payer) public view returns (bool isActive) { + return activePayers.contains(payer); + } + + /** + * @inheritdoc IPayer + */ + function getPayersInDebt(uint256 offset, uint256 limit) external view returns ( + address[] memory debtors, + uint256[] memory debtAmounts, + uint256 totalCount + ) { + // TODO: Implement payers in debt retrieval logic + } + /** * @inheritdoc IPayer */ From eecf89623a7136907e2e8768c7928b3d840d69a8 Mon Sep 17 00:00:00 2001 From: Borja Aranda Date: Tue, 11 Mar 2025 20:40:51 +0100 Subject: [PATCH 03/24] delete inodescaller --- contracts/src/Payer.sol | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/contracts/src/Payer.sol b/contracts/src/Payer.sol index 7118be40..06972bc9 100644 --- a/contracts/src/Payer.sol +++ b/contracts/src/Payer.sol @@ -11,12 +11,6 @@ import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import "./interfaces/IPayer.sol"; import "./interfaces/INodes.sol"; -interface INodesCaller { - // TODO: Node has to implement ERC721Enumerable or an ad-hoc function (senderIsNodeOperator) - function senderIsActiveNodeOperator(address sender) external view returns (bool isNodeOperator); - function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256); -} - /** * @title Payer * @notice Implementation for managing payer USDC deposits, usage settlements, @@ -398,10 +392,11 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus * @inheritdoc IPayer */ function getIsActiveNodeOperator(address operator) public view returns (bool) { - INodesCaller nodes = INodesCaller(nodesContract); + INodes nodes = INodes(nodesContract); require(address(nodes) != address(0), Unauthorized()); - return nodes.senderIsActiveNodeOperator(operator); + // TODO: Implement this in Nodes contract + return nodes.isActiveNodeOperator(operator); } //============================================================== From 2e2a7034c9aa0c5ce3150c72956cf15b419b9bd8 Mon Sep 17 00:00:00 2001 From: Borja Aranda Date: Tue, 11 Mar 2025 21:17:09 +0100 Subject: [PATCH 04/24] sol version --- contracts/src/Payer.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/src/Payer.sol b/contracts/src/Payer.sol index 06972bc9..62b592c0 100644 --- a/contracts/src/Payer.sol +++ b/contracts/src/Payer.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.28; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; From 725159cece7c9d9e5fbd7ec5e2ac5464b5f4affc Mon Sep 17 00:00:00 2001 From: Borja Aranda Date: Wed, 12 Mar 2025 19:16:08 +0100 Subject: [PATCH 05/24] adapt to EIP7201 and add script to compute storage slot --- contracts/script/ComputeStorageSlot.sol | 25 ++ contracts/src/Payer.sol | 421 ++++++++++++++---------- contracts/src/interfaces/IPayer.sol | 376 +++++++++++---------- 3 files changed, 474 insertions(+), 348 deletions(-) create mode 100644 contracts/script/ComputeStorageSlot.sol diff --git a/contracts/script/ComputeStorageSlot.sol b/contracts/script/ComputeStorageSlot.sol new file mode 100644 index 00000000..7348e5cd --- /dev/null +++ b/contracts/script/ComputeStorageSlot.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +import {Script, console} from "forge-std/src/Script.sol"; + +/* + * @dev Compute the storage slot for a given namespace. + * forge script script/ComputeStorageSlot.sol --sig "compute(string)" "xmtp.storage.Payer" + */ +contract ComputeStorageSlot is Script { + function compute(string calldata namespace) external view { + bytes32 namespaceHash = keccak256(bytes(namespace)); + uint256 namespaceInt = uint256(namespaceHash); + bytes32 slot = bytes32((namespaceInt - 1) & ~uint256(0xff)); + + console.log("Namespace:", namespace); + console.logBytes32(namespaceHash); + console.log("Storage Slot:"); + console.logBytes32(slot); + } + + function run() external view { + this.compute(""); + } +} \ No newline at end of file diff --git a/contracts/src/Payer.sol b/contracts/src/Payer.sol index 62b592c0..e799fadc 100644 --- a/contracts/src/Payer.sol +++ b/contracts/src/Payer.sol @@ -1,15 +1,15 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.28; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import "@openzeppelin-contracts-upgradeable/access/AccessControlUpgradeable.sol"; -import "@openzeppelin-contracts-upgradeable/utils/PausableUpgradeable.sol"; -import "@openzeppelin-contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; -import "@openzeppelin-contracts-upgradeable/proxy/utils/Initializable.sol"; -import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; -import "./interfaces/IPayer.sol"; -import "./interfaces/INodes.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import { AccessControlUpgradeable } from "@openzeppelin-contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import { PausableUpgradeable } from "@openzeppelin-contracts-upgradeable/utils/PausableUpgradeable.sol"; +import { UUPSUpgradeable } from "@openzeppelin-contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; +import { Initializable } from "@openzeppelin-contracts-upgradeable/proxy/utils/Initializable.sol"; +import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; +import { IPayer } from "./interfaces/IPayer.sol"; +import { INodes } from "./interfaces/INodes.sol"; /** * @title Payer @@ -21,63 +21,53 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus using SafeERC20 for IERC20; using EnumerableSet for EnumerableSet.AddressSet; + /* ============ Constants ============ */ + /// @dev Roles bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE"); - /// @dev USDC token contract - IERC20 public usdcToken; - - /// @dev Distribution contract - address public distributionContract; - - /// @dev Nodes contract - address public nodesContract; - - /// @dev Payer report contract - address public payerReportContract; - - /// @dev Minimum deposit amount in micro-USDC - uint256 public minimumDepositMicroDollars = 10_000_000; - - /// @dev Pending fees - uint256 public pendingFees; - - /// @dev Last fee transfer timestamp - uint256 public lastFeeTransferTimestamp; - - /// @dev Withdrawal lock period - uint256 public withdrawalLockPeriod = 3 days; - - /// @dev Maximum backdated time - uint256 public maxBackdatedTime = 1 days; - - /// @dev Mapping of payer address to their information - mapping(address => Payer) private payers; - - /// @dev Mapping of payer address to withdrawal information - mapping(address => Withdrawal) private withdrawals; - - /// @dev Set of all payer addresses - EnumerableSet.AddressSet private totalPayers; - - /// @dev Set of active payer addresses - EnumerableSet.AddressSet private activePayers; - - /// @dev Total value locked - uint256 public totalValueLocked; - - /// @dev Total debt amount - uint256 public totalDebtAmount; + /* ============ UUPS Storage ============ */ + + /// @custom:storage-location erc7201:xmtp.storage.Payer + struct PayerStorage { + /// @dev Contracts to interact with. + IERC20 usdcToken; + address distributionContract; + address nodesContract; + address payerReportContract; + + /// @dev Parameters + uint256 minimumDepositMicroDollars; + uint256 pendingFees; + uint256 lastFeeTransferTimestamp; + uint256 withdrawalLockPeriod; + uint256 maxBackdatedTime; + uint256 totalValueLocked; + uint256 totalDebtAmount; + + /// @dev Mappings + mapping(address => Payer) payers; + mapping(address => Withdrawal) withdrawals; + EnumerableSet.AddressSet totalPayers; + EnumerableSet.AddressSet activePayers; + } + + // keccak256(abi.encode(uint256(keccak256("xmtp.storage.Payer")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 internal constant PayerStorageLocation = 0xd0335f337c570f3417b0f0d20340c88da711d60e810b5e9b3ecabe9ccfcdce5a; + + function _getPayerStorage() internal pure returns (PayerStorage storage $) { + assembly { + $.slot := PayerStorageLocation + } + } - //============================================================== - // Modifiers - //============================================================== + /* ============ Modifiers ============ */ /** * @dev Modifier to check if caller is an active node operator */ modifier onlyNodeOperator() { - if (!getIsActiveNodeOperator(msg.sender)) { + if (!_getIsActiveNodeOperator(msg.sender)) { revert UnauthorizedNodeOperator(); } _; @@ -87,7 +77,7 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus * @dev Modifier to check if caller is the payer report contract */ modifier onlyPayerReport() { - if (msg.sender != payerReportContract) { + if (msg.sender != _getPayerStorage().payerReportContract) { revert NotPayerReportContract(); } _; @@ -97,62 +87,60 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus * @dev Modifier to check if address is an active payer */ modifier onlyPayer(address payer) { - require(_payerExists(payer), PayerDoesNotExist(payer)); + require(_payerExists(payer), PayerDoesNotExist()); _; } - //============================================================== - // Initialization - //============================================================== + /* ============ Initialization ============ */ - /// @notice Initializes the contract with the deployer as admin. - /// @param _initialAdmin The address of the admin. + /** + * @notice Initializes the contract with the deployer as admin. + * @param _initialAdmin The address of the admin. + */ function initialize( address _initialAdmin, address _usdcToken, address _distributionContract, - address _nodesContract, - uint256 _withdrawalLockPeriod, - uint256 _maxBackdatedTime + address _nodesContract ) public initializer { - if (_initialAdmin == address(0) || - _usdcToken == address(0) || - _nodesContract == address(0) || - _withdrawalLockPeriod == 0 || - _maxBackdatedTime == 0) { + if (_initialAdmin == address(0) || _usdcToken == address(0) || _nodesContract == address(0)) { revert InvalidAddress(); } + PayerStorage storage $ = _getPayerStorage(); + + $.minimumDepositMicroDollars = 10_000_000; + $.withdrawalLockPeriod = 3 days; + $.maxBackdatedTime = 1 days; + + $.usdcToken = IERC20(_usdcToken); + $.distributionContract = _distributionContract; + $.nodesContract = _nodesContract; + __UUPSUpgradeable_init(); __AccessControl_init(); __Pausable_init(); - _grantRole(DEFAULT_ADMIN_ROLE, _initialAdmin); - _grantRole(ADMIN_ROLE, _initialAdmin); - - usdcToken = IERC20(_usdcToken); - distributionContract = _distributionContract; - nodesContract = _nodesContract; - withdrawalLockPeriod = _withdrawalLockPeriod; - maxBackdatedTime = _maxBackdatedTime; + require(_grantRole(DEFAULT_ADMIN_ROLE, _initialAdmin), FailedToGrantRole(DEFAULT_ADMIN_ROLE, _initialAdmin)); + require(_grantRole(ADMIN_ROLE, _initialAdmin), FailedToGrantRole(ADMIN_ROLE, _initialAdmin)); } - //============================================================== - // Payers Management - //============================================================== + /* ============ Payers Management ============ */ /** * @inheritdoc IPayer */ function register(uint256 amount) external whenNotPaused { - require(amount >= minimumDepositMicroDollars, InsufficientAmount()); - require(!_payerExists(msg.sender), PayerAlreadyRegistered(msg.sender)); + PayerStorage storage $ = _getPayerStorage(); + + require(amount >= $.minimumDepositMicroDollars, InsufficientAmount()); + require(!_payerExists(msg.sender), PayerAlreadyRegistered()); // Transfer USDC from the sender to this contract - usdcToken.safeTransferFrom(msg.sender, address(this), amount); + $.usdcToken.safeTransferFrom(msg.sender, address(this), amount); // New payer registration - payers[msg.sender] = Payer({ + $.payers[msg.sender] = Payer({ balance: amount, isActive: true, creationTimestamp: block.timestamp, @@ -161,11 +149,11 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus }); // Add new payer to active and total payers sets - activePayers.add(msg.sender); - totalPayers.add(msg.sender); + $.activePayers.add(msg.sender); + $.totalPayers.add(msg.sender); // Update counters - totalValueLocked += amount; + $.totalValueLocked += amount; emit PayerRegistered(msg.sender, amount); } @@ -174,19 +162,22 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus * @inheritdoc IPayer */ function deposit(uint256 amount) external whenNotPaused onlyPayer(msg.sender) { + PayerStorage storage $ = _getPayerStorage(); + require(amount > 0, InsufficientAmount()); + _revertIfPayerDoesNotExist(msg.sender); - if (withdrawals[msg.sender].requestTimestamp != 0) { + if ($.withdrawals[msg.sender].requestTimestamp != 0) { revert PayerInWithdrawal(); } // Transfer USDC from sender to this contract - usdcToken.safeTransferFrom(msg.sender, address(this), amount); + $.usdcToken.safeTransferFrom(msg.sender, address(this), amount); // Update payer record - payers[msg.sender].balance += amount; - payers[msg.sender].latestDepositTimestamp = block.timestamp; - totalValueLocked += amount; + $.payers[msg.sender].balance += amount; + $.payers[msg.sender].latestDepositTimestamp = block.timestamp; + $.totalValueLocked += amount; emit Deposit(msg.sender, amount); } @@ -195,21 +186,23 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus * @inheritdoc IPayer */ function donate(address payer, uint256 amount) external whenNotPaused { + PayerStorage storage $ = _getPayerStorage(); + require(amount > 0, InsufficientAmount()); - require(_payerExists(payer), PayerDoesNotExist(payer)); + _revertIfPayerDoesNotExist(payer); - if (withdrawals[payer].requestTimestamp != 0) { + if ($.withdrawals[payer].requestTimestamp != 0) { revert PayerInWithdrawal(); } // Transfer USDC from sender to this contract - usdcToken.safeTransferFrom(msg.sender, address(this), amount); + $.usdcToken.safeTransferFrom(msg.sender, address(this), amount); // Update payer record - payers[payer].balance += amount; + $.payers[payer].balance += amount; // Update TVL - totalValueLocked += amount; + $.totalValueLocked += amount; emit Donation(msg.sender, payer, amount); } @@ -218,9 +211,11 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus * @inheritdoc IPayer */ function deactivatePayer(address payer) external whenNotPaused onlyRole(ADMIN_ROLE) { - require(_payerExists(payer), PayerDoesNotExist(payer)); - payers[payer].isActive = false; - activePayers.remove(payer); + PayerStorage storage $ = _getPayerStorage(); + + _revertIfPayerDoesNotExist(payer); + $.payers[payer].isActive = false; + $.activePayers.remove(payer); emit PayerDeactivated(payer); } @@ -228,37 +223,29 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus * @inheritdoc IPayer */ function deletePayer(address payer) external whenNotPaused onlyRole(ADMIN_ROLE) { - require(_payerExists(payer), PayerDoesNotExist(payer)); + PayerStorage storage $ = _getPayerStorage(); - if (payers[payer].balance > 0 || payers[payer].debtAmount > 0) { + _revertIfPayerDoesNotExist(payer); + + if ($.payers[payer].balance > 0 || $.payers[payer].debtAmount > 0) { revert PayerHasBalanceOrDebt(); } - if (withdrawals[payer].requestTimestamp != 0) { + if ($.withdrawals[payer].requestTimestamp != 0) { revert PayerInWithdrawal(); } // Delete payer data - delete payers[payer]; + delete $.payers[payer]; // Remove from totalPayers set - totalPayers.remove(payer); - activePayers.remove(payer); + $.totalPayers.remove(payer); + $.activePayers.remove(payer); emit PayerDeleted(payer, block.timestamp); } - //============================================================== - // Payers Balance Management - //============================================================== - - /** - * @inheritdoc IPayer - */ - function getPayerBalance(address payer) external view returns (uint256 balance) { - require(_payerExists(payer), PayerDoesNotExist(payer)); - return payers[payer].balance; - } + /* ========== Payers Balance Management ========= */ /** * @inheritdoc IPayer @@ -288,9 +275,7 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus // TODO: Implement withdrawal status retrieval logic } - //============================================================== - // Usage Settlement - //============================================================== + /* ============ Usage Settlement ============ */ /** * @inheritdoc IPayer @@ -305,10 +290,6 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus // TODO: Implement usage settlement logic } - function calculateFees(uint256 amount) external view returns (uint256 fees) { - // TODO: Implement fee calculation logic - } - /** * @inheritdoc IPayer */ @@ -316,17 +297,17 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus // TODO: Implement fee transfer logic } - //============================================================== - // Administrative Functions - //============================================================== + /* ========== Administrative Functions ========== */ /** * @inheritdoc IPayer */ function setDistributionContract(address _newDistributionContract) external onlyRole(ADMIN_ROLE) { + PayerStorage storage $ = _getPayerStorage(); + require (_newDistributionContract != address(0), InvalidAddress()); // TODO: Add check to ensure the new distribution contract is valid - distributionContract = _newDistributionContract; + $.distributionContract = _newDistributionContract; emit DistributionContractUpdated(_newDistributionContract); } @@ -334,9 +315,11 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus * @inheritdoc IPayer */ function setNodesContract(address _newNodesContract) external onlyRole(ADMIN_ROLE) { + PayerStorage storage $ = _getPayerStorage(); + require (_newNodesContract != address(0), InvalidAddress()); // TODO: Add check to ensure the new nodes contract is valid - nodesContract = _newNodesContract; + $.nodesContract = _newNodesContract; emit NodesContractUpdated(_newNodesContract); } @@ -344,9 +327,11 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus * @inheritdoc IPayer */ function setPayerReportContract(address _newPayerReportContract) external onlyRole(ADMIN_ROLE) { + PayerStorage storage $ = _getPayerStorage(); + require (_newPayerReportContract != address(0), InvalidAddress()); // TODO: Add check to ensure the new payer report contract is valid - payerReportContract = _newPayerReportContract; + $.payerReportContract = _newPayerReportContract; emit PayerReportContractUpdated(_newPayerReportContract); } @@ -354,16 +339,11 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus * @inheritdoc IPayer */ function setMinimumDeposit(uint256 _newMinimumDeposit) external onlyRole(ADMIN_ROLE) { - uint256 oldMinimumDeposit = minimumDepositMicroDollars; - minimumDepositMicroDollars = _newMinimumDeposit; - emit MinimumDepositUpdated(oldMinimumDeposit, _newMinimumDeposit); - } + PayerStorage storage $ = _getPayerStorage(); - /** - * @inheritdoc IPayer - */ - function getContractBalance() external view returns (uint256 balance) { - return usdcToken.balanceOf(address(this)); + uint256 oldMinimumDeposit = $.minimumDepositMicroDollars; + $.minimumDepositMicroDollars = _newMinimumDeposit; + emit MinimumDepositUpdated(oldMinimumDeposit, _newMinimumDeposit); } /** @@ -380,44 +360,23 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus _unpause(); } - // Upgradeability - /// @dev Authorizes the upgrade of the contract. - /// @param newImplementation The address of the new implementation. - function _authorizeUpgrade(address newImplementation) internal override onlyRole(DEFAULT_ADMIN_ROLE) { - require(newImplementation != address(0), "New implementation cannot be zero address"); - emit UpgradeAuthorized(msg.sender, newImplementation); - } + /* ============ Getters ============ */ /** * @inheritdoc IPayer */ - function getIsActiveNodeOperator(address operator) public view returns (bool) { - INodes nodes = INodes(nodesContract); - require(address(nodes) != address(0), Unauthorized()); - - // TODO: Implement this in Nodes contract - return nodes.isActiveNodeOperator(operator); - } - - //============================================================== - // Getters - //============================================================== - - /** - * @dev Returns the payer information. - * @param payer The address of the payer. - * @return payerInfo The payer information. - */ function getPayer(address payer) external view returns (Payer memory payerInfo) { - require(_payerExists(payer), PayerDoesNotExist(payer)); - return payers[payer]; + PayerStorage storage $ = _getPayerStorage(); + + _revertIfPayerDoesNotExist(payer); + return $.payers[payer]; } /** * @inheritdoc IPayer */ function getIsActivePayer(address payer) public view returns (bool isActive) { - return activePayers.contains(payer); + return _getPayerStorage().activePayers.contains(payer); } /** @@ -435,42 +394,146 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus * @inheritdoc IPayer */ function getTotalPayerCount() external view returns (uint256 count) { - return totalPayers.length(); + PayerStorage storage $ = _getPayerStorage(); + + return $.totalPayers.length(); } /** * @inheritdoc IPayer */ function getActivePayerCount() external view returns (uint256 count) { - return activePayers.length(); + return _getPayerStorage().activePayers.length(); } /** * @inheritdoc IPayer */ function getLastFeeTransferTimestamp() external view returns (uint256 timestamp) { - return lastFeeTransferTimestamp; + return _getPayerStorage().lastFeeTransferTimestamp; } + /** + * @inheritdoc IPayer + */ function getTotalValueLocked() external view returns (uint256 tvl) { // TODO: TVL should subtract the total debt amount - return totalValueLocked; + return _getPayerStorage().totalValueLocked; } + /** + * @inheritdoc IPayer + */ function getTotalDebtAmount() external view returns (uint256 totalDebt) { - return totalDebtAmount; + return _getPayerStorage().totalDebtAmount; } - //============================================================== - // Internal Functions - //============================================================== + /** + * @inheritdoc IPayer + */ + function getContractBalance() external view returns (uint256 balance) { + return _getPayerStorage().usdcToken.balanceOf(address(this)); + } /** - * @dev Checks if a payer exists. + * @inheritdoc IPayer + */ + function getDistributionContract() external view returns (address distributionContractAddress) { + return _getPayerStorage().distributionContract; + } + + /** + * @inheritdoc IPayer + */ + function getNodesContract() external view returns (address nodesContractAddress) { + return _getPayerStorage().nodesContract; + } + + /** + * @inheritdoc IPayer + */ + function getPayerReportContract() external view returns (address payerReportContractAddress) { + return _getPayerStorage().payerReportContract; + } + + /** + * @notice Retrieves the minimum deposit amount required to register as a payer. + * @return minimumDeposit The minimum deposit amount in USDC. + */ + function getMinimumDeposit() external view returns (uint256 minimumDeposit) { + return _getPayerStorage().minimumDepositMicroDollars; + } + + /** + * @inheritdoc IPayer + */ + function getPayerBalance(address payer) external view returns (uint256 balance) { + _revertIfPayerDoesNotExist(payer); + return _getPayerStorage().payers[payer].balance; + } + + /** + * @inheritdoc IPayer + */ + function getWithdrawalLockPeriod() external view returns (uint256 lockPeriod) { + return _getPayerStorage().withdrawalLockPeriod; + } + + /** + * @inheritdoc IPayer + */ + function getPendingFees() external view returns (uint256 fees) { + return _getPayerStorage().pendingFees; + } + + /** + * @inheritdoc IPayer + */ + function getMaxBackdatedTime() external view returns (uint256 maxTime) { + return _getPayerStorage().maxBackdatedTime; + } + + /* ============ Internal ============ */ + + /** + * @dev Reverts if a payer does not exist. * @param payer The address of the payer to check. + */ + function _revertIfPayerDoesNotExist(address payer) internal view { + require(_payerExists(payer), PayerDoesNotExist()); + } + + /** + * @dev Checks if a payer exists. + * @param payer The address of the payer to check. * @return exists True if the payer exists, false otherwise. */ function _payerExists(address payer) internal view returns (bool exists) { - return payers[payer].creationTimestamp != 0; + return _getPayerStorage().payers[payer].creationTimestamp != 0; + } + + /** + * @notice Checks if a given address is an active node operator. + * @param operator The address to check. + * @return isActiveNodeOperator True if the address is an active node operator, false otherwise. + */ + function _getIsActiveNodeOperator(address operator) internal view returns (bool) { + INodes nodes = INodes(_getPayerStorage().nodesContract); + require(address(nodes) != address(0), Unauthorized()); + + // TODO: Implement this in Nodes contract + // return nodes.isActiveNodeOperator(operator); + return true; + } + + /* ============ Upgradeability ============ */ + + /** + * @dev Authorizes the upgrade of the contract. + * @param newImplementation The address of the new implementation. + */ + function _authorizeUpgrade(address newImplementation) internal override onlyRole(DEFAULT_ADMIN_ROLE) { + require(newImplementation != address(0), "New implementation cannot be zero address"); + emit UpgradeAuthorized(msg.sender, newImplementation); } } \ No newline at end of file diff --git a/contracts/src/interfaces/IPayer.sol b/contracts/src/interfaces/IPayer.sol index f4d1fd12..07a304fd 100644 --- a/contracts/src/interfaces/IPayer.sol +++ b/contracts/src/interfaces/IPayer.sol @@ -2,22 +2,20 @@ pragma solidity 0.8.28; /** - * @title IPayer + * @title IPayer * @notice Interface for managing payer USDC deposits, usage settlements, * and a secure withdrawal process. */ interface IPayer { - //============================================================== - // STRUCTS - //============================================================== + /* ============ Structs ============ */ /** - * @dev Struct to store payer information. - * @param balance The current USDC balance of the payer. - * @param isActive Indicates whether the payer is active. - * @param creationTimestamp The timestamp when the payer was first registered. + * @dev Struct to store payer information. + * @param balance The current USDC balance of the payer. + * @param isActive Indicates whether the payer is active. + * @param creationTimestamp The timestamp when the payer was first registered. * @param latestDepositTimestamp The timestamp of the most recent deposit. - * @param debtAmount The amount of fees owed but not yet settled. + * @param debtAmount The amount of fees owed but not yet settled. */ struct Payer { uint256 balance; @@ -28,10 +26,10 @@ interface IPayer { } /** - * @dev Struct to store withdrawal request information. - * @param requestTimestamp The timestamp when the withdrawal was requested. + * @dev Struct to store withdrawal request information. + * @param requestTimestamp The timestamp when the withdrawal was requested. * @param withdrawableTimestamp The timestamp when the withdrawal can be finalized. - * @param amount The amount requested for withdrawal. + * @param amount The amount requested for withdrawal. */ struct Withdrawal { uint256 requestTimestamp; @@ -39,85 +37,98 @@ interface IPayer { uint256 amount; } - //============================================================== - // EVENTS - //============================================================== + /* ============ Events ============ */ + + /// @dev Emitted when a new payer is registered. + event PayerRegistered(address indexed payer, uint256 amount); + + /// @dev Emitted when a payer is deactivated by an owner. + event PayerDeactivated(address indexed payer); + + /// @dev Emitted when a payer is permanently deleted from the system. + event PayerDeleted(address indexed payer, uint256 timestamp); /// @dev Emitted when a deposit is made to a payer's account. event Deposit(address indexed payer, uint256 amount); - /// @dev Emitted when the distribution contract address is updated. - event DistributionContractUpdated(address indexed newDistributionContract); - /// @dev Emitted when a user donates to a payer's account. event Donation(address indexed donor, address indexed payer, uint256 amount); + /// @dev Emitted when a payer initiates a withdrawal request. + event WithdrawalRequest( + address indexed payer, uint256 requestTimestamp, uint256 withdrawableTimestamp, uint256 amount + ); + + /// @dev Emitted when a payer cancels a withdrawal request. + event WithdrawalCancelled(address indexed payer); + + /// @dev Emitted when a payer's withdrawal is finalized. + event WithdrawalFinalized(address indexed payer, uint256 amountReturned); + + /// @dev Emitted when usage is settled and fees are calculated. + event UsageSettled(uint256 fees, address indexed payer, uint256 indexed originatorNode, uint256 timestamp); + /// @dev Emitted when fees are transferred to the distribution contract. event FeesTransferred(uint256 amount); - /// @dev Emitted when the minimum deposit amount is updated. - event MinimumDepositUpdated(uint256 oldMinimumDeposit, uint256 newMinimumDeposit); + /// @dev Emitted when the distribution contract address is updated. + event DistributionContractUpdated(address indexed newDistributionContract); /// @dev Emitted when the nodes contract address is updated. event NodesContractUpdated(address indexed newNodesContract); - /// @dev Emitted when a payer is deactivated by an owner. - event PayerDeactivated(address indexed payer); - - /// @dev Emitted when a payer is permanently deleted from the system. - event PayerDeleted(address indexed payer, uint256 timestamp); - - /// @dev Emitted when a new payer is registered. - event PayerRegistered(address indexed payer, uint256 amount); - /// @dev Emitted when the payer report contract address is updated. event PayerReportContractUpdated(address indexed newPayerReportContract); + /// @dev Emitted when the minimum deposit amount is updated. + event MinimumDepositUpdated(uint256 oldMinimumDeposit, uint256 newMinimumDeposit); + /// @dev Emitted when the upgrade is authorized. event UpgradeAuthorized(address indexed upgrader, address indexed newImplementation); - /// @dev Emitted when usage is settled and fees are calculated. - event UsageSettled(uint256 fees, address indexed payer, uint256 indexed originatorNode, uint256 timestamp); + /* ============ Custom Errors ============ */ - /// @dev Emitted when a payer cancels a withdrawal request. - event WithdrawalCancelled(address indexed payer); + /// @dev Error thrown when a call is unauthorized. + error Unauthorized(); - /// @dev Emitted when a payer's withdrawal is finalized. - event WithdrawalFinalized(address indexed payer, uint256 amountReturned); + /// @dev Error thrown when caller is not an authorized node operator. + error UnauthorizedNodeOperator(); - /// @dev Emitted when a payer initiates a withdrawal request. - event WithdrawalRequest(address indexed payer, uint256 requestTimestamp, uint256 withdrawableTimestamp, uint256 amount); + /// @dev Error thrown when caller is not the distribution contract. + error NotDistributionContract(); - //============================================================== - // ERRORS - //============================================================== + /// @dev Error thrown when caller is not the payer report contract. + error NotPayerReportContract(); - /// @dev Error thrown when arrays have mismatched lengths. - error ArrayLengthMismatch(); + /// @dev Error thrown when caller is not the nodes contract. + error NotNodesContract(); + + /// @dev Error thrown when an address is invalid (usually zero address). + error InvalidAddress(); /// @dev Error thrown when the amount is insufficient. error InsufficientAmount(); - /// @dev Error thrown when an address is invalid (usually zero address). - error InvalidAddress(); + /// @dev Error thrown when a withdrawal is not in the requested state. + error WithdrawalNotRequested(); - /// @dev Error thrown when trying to backdate settlement too far. - error InvalidSettlementTime(); + /// @dev Error thrown when a withdrawal is already in progress. + error WithdrawalAlreadyRequested(); /// @dev Error thrown when a lock period has not yet elapsed. error LockPeriodNotElapsed(); - /// @dev Error thrown when caller is not the distribution contract. - error NotDistributionContract(); + /// @dev Error thrown when arrays have mismatched lengths. + error ArrayLengthMismatch(); - /// @dev Error thrown when caller is not the payer report contract. - error NotPayerReportContract(); + /// @dev Error thrown when trying to backdate settlement too far. + error InvalidSettlementTime(); - /// @dev Error thrown when a payer is already registered. - error PayerAlreadyRegistered(address); + /// @dev Error thrown when payer already exists. + error PayerAlreadyRegistered(); - /// @dev Error thrown when a payer does not exist. - error PayerDoesNotExist(address); + /// @dev Error thrown when payer does not exist. + error PayerDoesNotExist(); /// @dev Error thrown when trying to delete a payer with balance or debt. error PayerHasBalanceOrDebt(); @@ -125,26 +136,18 @@ interface IPayer { /// @dev Error thrown when trying to delete a payer in withdrawal state. error PayerInWithdrawal(); - /// @dev Error thrown in case of an unauthorized access. - error Unauthorized(); - - /// @dev Error thrown when caller is not an authorized node operator. - error UnauthorizedNodeOperator(); - - /// @dev Error thrown when a withdrawal is already in progress. - error WithdrawalAlreadyRequested(); + /// @notice Error thrown when granting a role has failed. + error FailedToGrantRole(bytes32 role, address account); - /// @dev Error thrown when a withdrawal is not in the requested state. - error WithdrawalNotRequested(); + /// @notice Error thrown when registering a payer has failed. + error FailedToRegisterPayer(); - //============================================================== - // PAYER REGISTRATION & MANAGEMENT - //============================================================== + /* ============ Payer Management ============ */ /** * @notice Registers the caller as a new payer upon depositing the minimum required USDC. * The caller must approve this contract to spend USDC beforehand. - * @param amount The amount of USDC to deposit (must be at least the minimum required). + * @param amount The amount of USDC to deposit (must be at least the minimum required). * * Emits `PayerRegistered`. */ @@ -153,7 +156,7 @@ interface IPayer { /** * @notice Allows the caller to deposit USDC into their own payer account. * The caller must approve this contract to spend USDC beforehand. - * @param amount The amount of USDC to deposit. + * @param amount The amount of USDC to deposit. * * Emits `Deposit`. */ @@ -162,8 +165,8 @@ interface IPayer { /** * @notice Allows anyone to donate USDC to an existing payer's account. * The sender must approve this contract to spend USDC beforehand. - * @param payer The address of the payer receiving the donation. - * @param amount The amount of USDC to donate. + * @param payer The address of the payer receiving the donation. + * @param amount The amount of USDC to donate. * * Emits `Donation`. */ @@ -172,7 +175,7 @@ interface IPayer { /** * @notice Deactivates a payer, preventing them from initiating new transactions. * Only callable by authorized node operators. - * @param payer The address of the payer to deactivate. + * @param payer The address of the payer to deactivate. * * Emits `PayerDeactivated`. */ @@ -180,45 +183,21 @@ interface IPayer { /** * @notice Permanently deletes a payer from the system. - * @dev Can only delete payers with zero balance and zero debt who are not in withdrawal. - * Only callable by authorized node operators. - * @param payer The address of the payer to delete. + * @dev Can only delete payers with zero balance and zero debt who are not in withdrawal. + * Only callable by authorized node operators. + * @param payer The address of the payer to delete. * * Emits `PayerDeleted`. */ function deletePayer(address payer) external; - /** - * @notice Checks if a given address is an active payer. - * @param payer The address to check. - * @return isActive True if the address is an active payer, false otherwise. - */ - function getIsActivePayer(address payer) external view returns (bool isActive); - - /** - * @notice Updates the minimum deposit amount required for registration. - * @param newMinimumDeposit The new minimum deposit amount. - * - * Emits `MinimumDepositUpdated`. - */ - function setMinimumDeposit(uint256 newMinimumDeposit) external; - - //============================================================== - // PAYER BALANCE MANAGEMENT - //============================================================== - - /** - * @notice Retrieves the current total balance of a given payer. - * @param payer The address of the payer. - * @return balance The current balance of the payer. - */ - function getPayerBalance(address payer) external view returns (uint256 balance); + /* ============ Payer Balance Management ============ */ /** * @notice Initiates a withdrawal request for the caller. * - Sets the payer into withdrawal mode (no further usage allowed). * - Records a timestamp for the withdrawal lock period. - * @param amount The amount to withdraw (can be less than or equal to current balance). + * @param amount The amount to withdraw (can be less than or equal to current balance). * * Emits `WithdrawalRequest`. */ @@ -226,7 +205,7 @@ interface IPayer { /** * @notice Cancels a previously requested withdrawal, removing withdrawal mode. - * @dev Only callable by the payer who initiated the withdrawal. + * @dev Only callable by the payer who initiated the withdrawal. * * Emits `WithdrawalCancelled`. */ @@ -244,57 +223,116 @@ interface IPayer { /** * @notice Checks if a payer is currently in withdrawal mode and the timestamp * when they initiated the withdrawal. - * @param payer The address to check. - * @return withdrawal The withdrawal status of the payer. + * @param payer The address to check. + * @return withdrawal The withdrawal status. */ function getWithdrawalStatus(address payer) external view returns (Withdrawal memory withdrawal); - //============================================================== - // USAGE SETTLEMENT - //============================================================== + /* ============ Usage Settlement ============ */ /** - * @notice Settles usage for a contiguous batch of (payer, amount) entries. - * Assumes that the PayerReport contract has already verified the aggregated Merkle proof. - * - * @param originatorNode The node that submitted the report. - * @param reportIndex The index of the report. - * @param payers A contiguous array of payer addresses. - * @param amounts A contiguous array of usage amounts corresponding to each payer. - */ + * @notice Settles usage for a contiguous batch of (payer, amount) entries. + * Assumes that the PayerReport contract has already verified the aggregated Merkle proof. + * + * @param originatorNode The node that submitted the report. + * @param reportIndex The index of the report. + * @param payers A contiguous array of payer addresses. + * @param amounts A contiguous array of usage amounts corresponding to each payer. + */ function settleUsage( address originatorNode, uint256 reportIndex, address[] calldata payers, uint256[] calldata amounts - ) external /* onlyPayerReport */ ; + ) external; /* onlyPayerReport */ /** * @notice Transfers all pending fees to the designated distribution contract. - * @dev Uses a single storage write for updating accumulated fees. + * @dev Uses a single storage write for updating accumulated fees. * * Emits `FeesTransferred`. */ function transferFeesToDistribution() external; - //============================================================== - // OBSERVABILITY FUNCTIONS - //============================================================== + /* ============ Administrative Functions ============ */ /** - * @notice Returns the total value locked in the contract (all payer balances). - * @return tvl The total value locked in USDC. + * @notice Sets the address of the distribution contract. + * @param distributionContract The address of the new distribution contract. + * + * Emits `DistributionContractUpdated`. */ - function getTotalValueLocked() external view returns (uint256 tvl); + function setDistributionContract(address distributionContract) external; /** - * @notice Returns the total outstanding debt amount across all payers. - * @return totalDebt The total debt amount in USDC. + * @notice Sets the address of the nodes contract for operator verification. + * @param nodesContract The address of the new nodes contract. + * + * Emits `NodesContractUpdated`. */ - function getTotalDebtAmount() external view returns (uint256 totalDebt); + function setNodesContract(address nodesContract) external; + + /** + * @notice Sets the address of the payer report contract. + * @param payerReportContract The address of the new payer report contract. + * + * Emits `PayerReportContractUpdated`. + */ + function setPayerReportContract(address payerReportContract) external; + + /** + * @notice Sets the minimum deposit amount required for registration. + * @param newMinimumDeposit The new minimum deposit amount. + * + * Emits `MinimumDepositUpdated`. + */ + function setMinimumDeposit(uint256 newMinimumDeposit) external; + + /** + * @notice Pauses the contract functions in case of emergency. + * + * Emits `Paused()`. + */ + function pause() external; + + /** + * @notice Unpauses the contract. + * + * Emits `Unpaused()`. + */ + function unpause() external; + + /* ============ Getters ============ */ + + /** + * @notice Returns the payer information. + * @param payer The address of the payer. + * @return payerInfo The payer information. + */ + function getPayer(address payer) external view returns (Payer memory payerInfo); + + /** + * @notice Checks if a given address is an active payer. + * @param payer The address to check. + * @return isActive True if the address is an active payer, false otherwise. + */ + function getIsActivePayer(address payer) external view returns (bool isActive); + + /** + * @notice Returns a paginated list of payers with outstanding debt. + * @param offset Number of payers to skip before starting to return results. + * @param limit Maximum number of payers to return. + * @return debtors Array of payer addresses with debt. + * @return debtAmounts Corresponding debt amounts for each payer. + * @return totalCount Total number of payers with debt (regardless of pagination). + */ + function getPayersInDebt(uint256 offset, uint256 limit) + external + view + returns (address[] memory debtors, uint256[] memory debtAmounts, uint256 totalCount); /** * @notice Returns the total number of registered payers. @@ -308,79 +346,79 @@ interface IPayer { */ function getActivePayerCount() external view returns (uint256 count); - /** + /** * @notice Returns the timestamp of the last fee transfer to the rewards contract. * @return timestamp The last fee transfer timestamp. */ function getLastFeeTransferTimestamp() external view returns (uint256 timestamp); /** - * @notice Returns a paginated list of payers with outstanding debt. - * @param offset Number of payers to skip before starting to return results. - * @param limit Maximum number of payers to return. - * @return debtors Array of payer addresses with debt. - * @return debtAmounts Corresponding debt amounts for each payer. - * @return totalCount Total number of payers with debt (regardless of pagination). + * @notice Returns the total value locked in the contract (all payer balances). + * @return tvl The total value locked in USDC. */ - function getPayersInDebt(uint256 offset, uint256 limit) external view returns ( - address[] memory debtors, - uint256[] memory debtAmounts, - uint256 totalCount - ); + function getTotalValueLocked() external view returns (uint256 tvl); + + /** + * @notice Returns the total outstanding debt amount across all payers. + * @return totalDebt The total debt amount in USDC. + */ + function getTotalDebtAmount() external view returns (uint256 totalDebt); /** * @notice Returns the actual USDC balance held by the contract. - * @dev This can be used to verify the contract's accounting is accurate. + * @dev This can be used to verify the contract's accounting is accurate. * @return balance The USDC token balance of the contract. */ function getContractBalance() external view returns (uint256 balance); - //============================================================== - // ADMINISTRATIVE FUNCTIONS - //============================================================== + /** + * @notice Retrieves the address of the current distribution contract. + * @return distributionContract The address of the distribution contract. + */ + function getDistributionContract() external view returns (address distributionContract); /** - * @notice Sets the address of the distribution contract. - * @param _distributionContract The address of the new distribution contract. - * - * Emits `DistributionContractUpdated`. + * @notice Retrieves the address of the current nodes contract. + * @return nodesContract The address of the nodes contract. */ - function setDistributionContract(address _distributionContract) external; + function getNodesContract() external view returns (address nodesContract); /** - * @notice Sets the address of the nodes contract for operator verification. - * @param _nodesContract The address of the new nodes contract. - * - * Emits `NodesContractUpdated`. + * @notice Retrieves the address of the current payer report contract. + * @return payerReportContract The address of the payer report contract. */ - function setNodesContract(address _nodesContract) external; + function getPayerReportContract() external view returns (address payerReportContract); /** - * @notice Sets the address of the payer report contract. - * @param _payerReportContract The address of the new payer report contract. - * - * Emits `PayerReportContractUpdated`. + * @notice Retrieves the minimum deposit amount required to register as a payer. + * @return minimumDeposit The minimum deposit amount in USDC. */ - function setPayerReportContract(address _payerReportContract) external; + function getMinimumDeposit() external view returns (uint256 minimumDeposit); /** - * @notice Pauses the contract functions in case of emergency. - * - * Emits `Paused()`. + * @notice Retrieves the current total balance of a given payer. + * @param payer The address of the payer. + * @return balance The current balance of the payer. */ - function pause() external; + function getPayerBalance(address payer) external view returns (uint256 balance); /** - * @notice Unpauses the contract. - * - * Emits `Unpaused()`. + * @notice Returns the duration of the lock period required before a withdrawal + * can be finalized. + * @return lockPeriod The lock period in seconds. */ - function unpause() external; + function getWithdrawalLockPeriod() external view returns (uint256 lockPeriod); + + /** + * @notice Retrieves the total pending fees that have not yet been transferred + * to the distribution contract. + * @return fees The total pending fees in USDC. + */ + function getPendingFees() external view returns (uint256 fees); /** - * @notice Checks if a given address is an active node operator. - * @param operator The address to check. - * @return isActiveNodeOperator True if the address is an active node operator, false otherwise. + * @notice Returns the maximum allowed time difference for backdated settlements. + * @return maxTime The maximum allowed time difference in seconds. */ - function getIsActiveNodeOperator(address operator) external view returns (bool isActiveNodeOperator); + function getMaxBackdatedTime() external view returns (uint256 maxTime); } \ No newline at end of file From 1eb6187da718a937b90093cf8bc242afd8a2ba35 Mon Sep 17 00:00:00 2001 From: Borja Aranda Date: Thu, 13 Mar 2025 13:13:04 +0100 Subject: [PATCH 06/24] add all setters --- contracts/src/Payer.sol | 227 +++++++++++++++------- contracts/src/interfaces/IPayer.sol | 77 ++++++-- contracts/src/interfaces/IPayerReport.sol | 5 +- 3 files changed, 228 insertions(+), 81 deletions(-) diff --git a/contracts/src/Payer.sol b/contracts/src/Payer.sol index e799fadc..2cc31cb2 100644 --- a/contracts/src/Payer.sol +++ b/contracts/src/Payer.sol @@ -2,6 +2,7 @@ pragma solidity 0.8.28; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { AccessControlUpgradeable } from "@openzeppelin-contracts-upgradeable/access/AccessControlUpgradeable.sol"; import { PausableUpgradeable } from "@openzeppelin-contracts-upgradeable/utils/PausableUpgradeable.sol"; @@ -9,13 +10,13 @@ import { UUPSUpgradeable } from "@openzeppelin-contracts-upgradeable/proxy/utils import { Initializable } from "@openzeppelin-contracts-upgradeable/proxy/utils/Initializable.sol"; import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import { IPayer } from "./interfaces/IPayer.sol"; +import { IPayerReport } from "./interfaces/IPayerReport.sol"; import { INodes } from "./interfaces/INodes.sol"; /** - * @title Payer + * @title Payer * @notice Implementation for managing payer USDC deposits, usage settlements, - * and a secure withdrawal process with optimized storage using - * Merkle trees and EIP-1283 gas optimizations. + * and a secure withdrawal process. */ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, PausableUpgradeable, IPayer{ using SafeERC20 for IERC20; @@ -23,8 +24,13 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus /* ============ Constants ============ */ - /// @dev Roles bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE"); + uint256 public constant DEFAULT_MINIMUM_DEPOSIT_MICRO_DOLLARS = 10_000_000; + uint256 public constant DEFAULT_WITHDRAWAL_LOCK_PERIOD = 3 days; + uint256 public constant ABSOLUTE_MINIMUM_WITHDRAWAL_LOCK_PERIOD = 1 days; + uint256 public constant DEFAULT_MAX_BACKDATED_TIME = 1 days; + uint256 public constant ABSOLUTE_MINIMUM_MAX_BACKDATED_TIME = 6 hours; + string internal constant USDC_SYMBOL = "USDC"; /* ============ UUPS Storage ============ */ @@ -36,12 +42,14 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus address nodesContract; address payerReportContract; - /// @dev Parameters + /// @dev Configuration parameters uint256 minimumDepositMicroDollars; - uint256 pendingFees; - uint256 lastFeeTransferTimestamp; uint256 withdrawalLockPeriod; uint256 maxBackdatedTime; + + /// @dev State variables + uint256 lastFeeTransferTimestamp; + uint256 pendingFees; uint256 totalValueLocked; uint256 totalDebtAmount; @@ -78,7 +86,7 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus */ modifier onlyPayerReport() { if (msg.sender != _getPayerStorage().payerReportContract) { - revert NotPayerReportContract(); + revert Unauthorized(); } _; } @@ -88,6 +96,7 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus */ modifier onlyPayer(address payer) { require(_payerExists(payer), PayerDoesNotExist()); + require(msg.sender == payer, Unauthorized()); _; } @@ -96,31 +105,32 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus /** * @notice Initializes the contract with the deployer as admin. * @param _initialAdmin The address of the admin. + * @dev There's a chicken-egg problem here with PayerReport and Distribution contracts. + * We need to deploy these contracts first, then set their addresses + * in the Payer contract. */ function initialize( address _initialAdmin, address _usdcToken, - address _distributionContract, address _nodesContract ) public initializer { if (_initialAdmin == address(0) || _usdcToken == address(0) || _nodesContract == address(0)) { revert InvalidAddress(); } - PayerStorage storage $ = _getPayerStorage(); - - $.minimumDepositMicroDollars = 10_000_000; - $.withdrawalLockPeriod = 3 days; - $.maxBackdatedTime = 1 days; - - $.usdcToken = IERC20(_usdcToken); - $.distributionContract = _distributionContract; - $.nodesContract = _nodesContract; - __UUPSUpgradeable_init(); __AccessControl_init(); __Pausable_init(); + PayerStorage storage $ = _getPayerStorage(); + + $.minimumDepositMicroDollars = DEFAULT_MINIMUM_DEPOSIT_MICRO_DOLLARS; + $.withdrawalLockPeriod = DEFAULT_WITHDRAWAL_LOCK_PERIOD; + $.maxBackdatedTime = DEFAULT_MAX_BACKDATED_TIME; + + _setUsdcTokenContract(_usdcToken); + _setNodesContract(_nodesContract); + require(_grantRole(DEFAULT_ADMIN_ROLE, _initialAdmin), FailedToGrantRole(DEFAULT_ADMIN_ROLE, _initialAdmin)); require(_grantRole(ADMIN_ROLE, _initialAdmin), FailedToGrantRole(ADMIN_ROLE, _initialAdmin)); } @@ -212,10 +222,11 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus */ function deactivatePayer(address payer) external whenNotPaused onlyRole(ADMIN_ROLE) { PayerStorage storage $ = _getPayerStorage(); - _revertIfPayerDoesNotExist(payer); + $.payers[payer].isActive = false; $.activePayers.remove(payer); + emit PayerDeactivated(payer); } @@ -295,6 +306,10 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus */ function transferFeesToDistribution() external whenNotPaused onlyRole(ADMIN_ROLE) { // TODO: Implement fee transfer logic + // Update lastFeeTransferTimestamp + // Update pendingFees + // Transfer fees to distribution contract + // Emit FeesTransferred event } /* ========== Administrative Functions ========== */ @@ -303,47 +318,70 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus * @inheritdoc IPayer */ function setDistributionContract(address _newDistributionContract) external onlyRole(ADMIN_ROLE) { - PayerStorage storage $ = _getPayerStorage(); + _setDistributionContract(_newDistributionContract); + } - require (_newDistributionContract != address(0), InvalidAddress()); - // TODO: Add check to ensure the new distribution contract is valid - $.distributionContract = _newDistributionContract; - emit DistributionContractUpdated(_newDistributionContract); + /** + * @inheritdoc IPayer + */ + function setPayerReportContract(address _newPayerReportContract) external onlyRole(ADMIN_ROLE) { + _setPayerReportContract(_newPayerReportContract); } /** * @inheritdoc IPayer */ function setNodesContract(address _newNodesContract) external onlyRole(ADMIN_ROLE) { + _setNodesContract(_newNodesContract); + } + + /** + * @inheritdoc IPayer + */ + function setUsdcToken(address _newUsdcToken) external onlyRole(ADMIN_ROLE) { + _setUsdcTokenContract(_newUsdcToken); + } + + /** + * @inheritdoc IPayer + */ + function setMinimumDeposit(uint256 _newMinimumDeposit) external onlyRole(ADMIN_ROLE) { + require(_newMinimumDeposit > DEFAULT_MINIMUM_DEPOSIT_MICRO_DOLLARS, InvalidMinimumDeposit()); + PayerStorage storage $ = _getPayerStorage(); - require (_newNodesContract != address(0), InvalidAddress()); - // TODO: Add check to ensure the new nodes contract is valid - $.nodesContract = _newNodesContract; - emit NodesContractUpdated(_newNodesContract); + uint256 oldMinimumDeposit = $.minimumDepositMicroDollars; + $.minimumDepositMicroDollars = _newMinimumDeposit; + + emit MinimumDepositSet(oldMinimumDeposit, _newMinimumDeposit); } /** * @inheritdoc IPayer */ - function setPayerReportContract(address _newPayerReportContract) external onlyRole(ADMIN_ROLE) { + function setWithdrawalLockPeriod(uint256 _newWithdrawalLockPeriod) external onlyRole(ADMIN_ROLE) { + require(_newWithdrawalLockPeriod >= ABSOLUTE_MINIMUM_WITHDRAWAL_LOCK_PERIOD, InvalidWithdrawalLockPeriod()); + PayerStorage storage $ = _getPayerStorage(); - require (_newPayerReportContract != address(0), InvalidAddress()); - // TODO: Add check to ensure the new payer report contract is valid - $.payerReportContract = _newPayerReportContract; - emit PayerReportContractUpdated(_newPayerReportContract); + uint256 oldWithdrawalLockPeriod = $.withdrawalLockPeriod; + $.withdrawalLockPeriod = _newWithdrawalLockPeriod; + + emit WithdrawalLockPeriodSet(oldWithdrawalLockPeriod, _newWithdrawalLockPeriod); } /** * @inheritdoc IPayer */ - function setMinimumDeposit(uint256 _newMinimumDeposit) external onlyRole(ADMIN_ROLE) { + function setMaxBackdatedTime(uint256 _newMaxBackdatedTime) external onlyRole(ADMIN_ROLE) { + require(_newMaxBackdatedTime >= ABSOLUTE_MINIMUM_MAX_BACKDATED_TIME, InvalidMaxBackdatedTime()); + PayerStorage storage $ = _getPayerStorage(); - uint256 oldMinimumDeposit = $.minimumDepositMicroDollars; - $.minimumDepositMicroDollars = _newMinimumDeposit; - emit MinimumDepositUpdated(oldMinimumDeposit, _newMinimumDeposit); + uint256 oldMaxBackdatedTime = $.maxBackdatedTime; + $.maxBackdatedTime = _newMaxBackdatedTime; + + emit MaxBackdatedTimeSet(oldMaxBackdatedTime, _newMaxBackdatedTime); } /** @@ -366,17 +404,27 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus * @inheritdoc IPayer */ function getPayer(address payer) external view returns (Payer memory payerInfo) { - PayerStorage storage $ = _getPayerStorage(); - _revertIfPayerDoesNotExist(payer); - return $.payers[payer]; + + return _getPayerStorage().payers[payer]; } /** * @inheritdoc IPayer */ function getIsActivePayer(address payer) public view returns (bool isActive) { - return _getPayerStorage().activePayers.contains(payer); + _revertIfPayerDoesNotExist(payer); + + return _getPayerStorage().payers[payer].isActive; + } + + /** + * @inheritdoc IPayer + */ + function getPayerBalance(address payer) external view returns (uint256 balance) { + _revertIfPayerDoesNotExist(payer); + + return _getPayerStorage().payers[payer].balance; } /** @@ -394,9 +442,7 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus * @inheritdoc IPayer */ function getTotalPayerCount() external view returns (uint256 count) { - PayerStorage storage $ = _getPayerStorage(); - - return $.totalPayers.length(); + return _getPayerStorage().totalPayers.length(); } /** @@ -457,21 +503,12 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus } /** - * @notice Retrieves the minimum deposit amount required to register as a payer. - * @return minimumDeposit The minimum deposit amount in USDC. + * @inheritdoc IPayer */ function getMinimumDeposit() external view returns (uint256 minimumDeposit) { return _getPayerStorage().minimumDepositMicroDollars; } - /** - * @inheritdoc IPayer - */ - function getPayerBalance(address payer) external view returns (uint256 balance) { - _revertIfPayerDoesNotExist(payer); - return _getPayerStorage().payers[payer].balance; - } - /** * @inheritdoc IPayer */ @@ -495,14 +532,6 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus /* ============ Internal ============ */ - /** - * @dev Reverts if a payer does not exist. - * @param payer The address of the payer to check. - */ - function _revertIfPayerDoesNotExist(address payer) internal view { - require(_payerExists(payer), PayerDoesNotExist()); - } - /** * @dev Checks if a payer exists. * @param payer The address of the payer to check. @@ -512,13 +541,22 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus return _getPayerStorage().payers[payer].creationTimestamp != 0; } + /** + * @dev Reverts if a payer does not exist. + * @param payer The address of the payer to check. + */ + function _revertIfPayerDoesNotExist(address payer) internal view { + require(_payerExists(payer), PayerDoesNotExist()); + } + /** * @notice Checks if a given address is an active node operator. * @param operator The address to check. * @return isActiveNodeOperator True if the address is an active node operator, false otherwise. */ - function _getIsActiveNodeOperator(address operator) internal view returns (bool) { + function _getIsActiveNodeOperator(address operator) internal view returns (bool isActiveNodeOperator) { INodes nodes = INodes(_getPayerStorage().nodesContract); + require(address(nodes) != address(0), Unauthorized()); // TODO: Implement this in Nodes contract @@ -526,6 +564,65 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus return true; } + function _setDistributionContract(address _newDistributionContract) internal { + PayerStorage storage $ = _getPayerStorage(); + + // TODO: Add check to ensure the new distribution contract is valid + // Wait until Distribution contract is implemented + // IDistribution distribution = IDistribution(_newDistributionContract); + // require(distribution.supportsInterface(type(IDistribution).interfaceId), InvalidDistributionContract()); + + require (_newDistributionContract != address(0), InvalidAddress()); + + $.distributionContract = _newDistributionContract; + + emit DistributionContractSet(_newDistributionContract); + } + + function _setPayerReportContract(address _newPayerReportContract) internal { + PayerStorage storage $ = _getPayerStorage(); + + IPayerReport payerReport = IPayerReport(_newPayerReportContract); + + try payerReport.supportsInterface(type(IPayerReport).interfaceId) returns (bool supported) { + require(supported, InvalidPayerReportContract()); + } catch { + revert InvalidPayerReportContract(); + } + + $.payerReportContract = _newPayerReportContract; + + emit PayerReportContractSet(_newPayerReportContract); + } + + function _setNodesContract(address _newNodesContract) internal { + PayerStorage storage $ = _getPayerStorage(); + + try INodes(_newNodesContract).supportsInterface(type(INodes).interfaceId) returns (bool supported) { + require(supported, InvalidNodesContract()); + } catch { + revert InvalidNodesContract(); + } + + $.nodesContract = _newNodesContract; + + emit NodesContractSet(_newNodesContract); + } + + function _setUsdcTokenContract(address _newUsdcToken) internal { + PayerStorage storage $ = _getPayerStorage(); + + try IERC20Metadata(_newUsdcToken).symbol() returns (string memory symbol) { + require(keccak256(bytes(symbol)) == keccak256(bytes(USDC_SYMBOL)), InvalidUsdcTokenContract()); + } catch { + revert InvalidUsdcTokenContract(); + } + + $.usdcToken = IERC20(_newUsdcToken); + + emit UsdcTokenSet(_newUsdcToken); + } + /* ============ Upgradeability ============ */ /** @@ -533,7 +630,7 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus * @param newImplementation The address of the new implementation. */ function _authorizeUpgrade(address newImplementation) internal override onlyRole(DEFAULT_ADMIN_ROLE) { - require(newImplementation != address(0), "New implementation cannot be zero address"); + require(newImplementation != address(0), InvalidAddress()); emit UpgradeAuthorized(msg.sender, newImplementation); } } \ No newline at end of file diff --git a/contracts/src/interfaces/IPayer.sol b/contracts/src/interfaces/IPayer.sol index 07a304fd..9907026e 100644 --- a/contracts/src/interfaces/IPayer.sol +++ b/contracts/src/interfaces/IPayer.sol @@ -1,12 +1,14 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.28; +import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; + /** * @title IPayer * @notice Interface for managing payer USDC deposits, usage settlements, * and a secure withdrawal process. */ -interface IPayer { +interface IPayer is IERC165 { /* ============ Structs ============ */ /** @@ -72,20 +74,29 @@ interface IPayer { event FeesTransferred(uint256 amount); /// @dev Emitted when the distribution contract address is updated. - event DistributionContractUpdated(address indexed newDistributionContract); + event DistributionContractSet(address indexed newDistributionContract); /// @dev Emitted when the nodes contract address is updated. - event NodesContractUpdated(address indexed newNodesContract); + event NodesContractSet(address indexed newNodesContract); /// @dev Emitted when the payer report contract address is updated. - event PayerReportContractUpdated(address indexed newPayerReportContract); + event PayerReportContractSet(address indexed newPayerReportContract); + + /// @dev Emitted when the USDC token address is updated. + event UsdcTokenSet(address indexed newUsdcToken); /// @dev Emitted when the minimum deposit amount is updated. - event MinimumDepositUpdated(uint256 oldMinimumDeposit, uint256 newMinimumDeposit); + event MinimumDepositSet(uint256 oldMinimumDeposit, uint256 newMinimumDeposit); /// @dev Emitted when the upgrade is authorized. event UpgradeAuthorized(address indexed upgrader, address indexed newImplementation); + /// @dev Emitted when the withdrawal lock period is updated. + event WithdrawalLockPeriodSet(uint256 oldWithdrawalLockPeriod, uint256 newWithdrawalLockPeriod); + + /// @dev Emitted when the maximum backdated time is updated. + event MaxBackdatedTimeSet(uint256 oldMaxBackdatedTime, uint256 newMaxBackdatedTime); + /* ============ Custom Errors ============ */ /// @dev Error thrown when a call is unauthorized. @@ -94,14 +105,17 @@ interface IPayer { /// @dev Error thrown when caller is not an authorized node operator. error UnauthorizedNodeOperator(); - /// @dev Error thrown when caller is not the distribution contract. - error NotDistributionContract(); + /// @dev Error thrown when contract is not the distribution contract. + error InvalidDistributionContract(); - /// @dev Error thrown when caller is not the payer report contract. - error NotPayerReportContract(); + /// @dev Error thrown when contract is not the payer report contract. + error InvalidPayerReportContract(); - /// @dev Error thrown when caller is not the nodes contract. - error NotNodesContract(); + /// @dev Error thrown when contract is not the nodes contract. + error InvalidNodesContract(); + + /// @dev Error thrown when contract is not the USDC token contract. + error InvalidUsdcTokenContract(); /// @dev Error thrown when an address is invalid (usually zero address). error InvalidAddress(); @@ -109,6 +123,15 @@ interface IPayer { /// @dev Error thrown when the amount is insufficient. error InsufficientAmount(); + /// @dev Error thrown when the minimum deposit is invalid. + error InvalidMinimumDeposit(); + + /// @dev Error thrown when the withdrawal lock period is invalid. + error InvalidWithdrawalLockPeriod(); + + /// @dev Error thrown when the maximum backdated time is invalid. + error InvalidMaxBackdatedTime(); + /// @dev Error thrown when a withdrawal is not in the requested state. error WithdrawalNotRequested(); @@ -267,6 +290,14 @@ interface IPayer { */ function setDistributionContract(address distributionContract) external; + /** + * @notice Sets the address of the payer report contract. + * @param payerReportContract The address of the new payer report contract. + * + * Emits `PayerReportContractUpdated`. + */ + function setPayerReportContract(address payerReportContract) external; + /** * @notice Sets the address of the nodes contract for operator verification. * @param nodesContract The address of the new nodes contract. @@ -276,12 +307,12 @@ interface IPayer { function setNodesContract(address nodesContract) external; /** - * @notice Sets the address of the payer report contract. - * @param payerReportContract The address of the new payer report contract. + * @notice Sets the address of the USDC token contract. + * @param usdcToken The address of the new USDC token contract. * - * Emits `PayerReportContractUpdated`. + * Emits `UsdcTokenUpdated`. */ - function setPayerReportContract(address payerReportContract) external; + function setUsdcToken(address usdcToken) external; /** * @notice Sets the minimum deposit amount required for registration. @@ -291,6 +322,22 @@ interface IPayer { */ function setMinimumDeposit(uint256 newMinimumDeposit) external; + /** + * @notice Sets the withdrawal lock period. + * @param newWithdrawalLockPeriod The new withdrawal lock period. + * + * Emits `WithdrawalLockPeriodUpdated`. + */ + function setWithdrawalLockPeriod(uint256 newWithdrawalLockPeriod) external; + + /** + * @notice Sets the maximum backdated time for settlements. + * @param newMaxBackdatedTime The new maximum backdated time. + * + * Emits `MaxBackdatedTimeUpdated`. + */ + function setMaxBackdatedTime(uint256 newMaxBackdatedTime) external; + /** * @notice Pauses the contract functions in case of emergency. * diff --git a/contracts/src/interfaces/IPayerReport.sol b/contracts/src/interfaces/IPayerReport.sol index 507a174e..75bc9b9e 100644 --- a/contracts/src/interfaces/IPayerReport.sol +++ b/contracts/src/interfaces/IPayerReport.sol @@ -1,11 +1,14 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.28; +import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; + /** * @title IPayerReport * @notice Interface for the PayerReport contract handling usage reports and batch settlements. */ -interface IPayerReport { +interface IPayerReport is IERC165 { + /* ============ Structs ============ */ /** From 73b6476ed244a7f78b56294c74efdddfb41eaeba Mon Sep 17 00:00:00 2001 From: Borja Aranda Date: Thu, 13 Mar 2025 15:23:27 +0100 Subject: [PATCH 07/24] withdrawal logic --- contracts/src/Payer.sol | 283 +++++++++++++++++++++------- contracts/src/interfaces/IPayer.sol | 56 +++++- 2 files changed, 267 insertions(+), 72 deletions(-) diff --git a/contracts/src/Payer.sol b/contracts/src/Payer.sol index 2cc31cb2..cd928a9c 100644 --- a/contracts/src/Payer.sol +++ b/contracts/src/Payer.sol @@ -25,7 +25,8 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus /* ============ Constants ============ */ bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE"); - uint256 public constant DEFAULT_MINIMUM_DEPOSIT_MICRO_DOLLARS = 10_000_000; + uint256 public constant DEFAULT_MINIMUM_REGISTRATION_AMOUNT_MICRO_DOLLARS = 10_000_000; + uint256 public constant DEFAULT_MINIMUM_DEPOSIT_AMOUNT_MICRO_DOLLARS = 10_000_000; uint256 public constant DEFAULT_WITHDRAWAL_LOCK_PERIOD = 3 days; uint256 public constant ABSOLUTE_MINIMUM_WITHDRAWAL_LOCK_PERIOD = 1 days; uint256 public constant DEFAULT_MAX_BACKDATED_TIME = 1 days; @@ -43,14 +44,15 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus address payerReportContract; /// @dev Configuration parameters - uint256 minimumDepositMicroDollars; + uint256 minimumRegistrationAmountMicroDollars; + uint256 minimumDepositAmountMicroDollars; uint256 withdrawalLockPeriod; uint256 maxBackdatedTime; /// @dev State variables uint256 lastFeeTransferTimestamp; uint256 pendingFees; - uint256 totalValueLocked; + uint256 totalAmountDeposited; uint256 totalDebtAmount; /// @dev Mappings @@ -124,7 +126,8 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus PayerStorage storage $ = _getPayerStorage(); - $.minimumDepositMicroDollars = DEFAULT_MINIMUM_DEPOSIT_MICRO_DOLLARS; + $.minimumRegistrationAmountMicroDollars = DEFAULT_MINIMUM_REGISTRATION_AMOUNT_MICRO_DOLLARS; + $.minimumDepositAmountMicroDollars = DEFAULT_MINIMUM_DEPOSIT_AMOUNT_MICRO_DOLLARS; $.withdrawalLockPeriod = DEFAULT_WITHDRAWAL_LOCK_PERIOD; $.maxBackdatedTime = DEFAULT_MAX_BACKDATED_TIME; @@ -143,28 +146,27 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus function register(uint256 amount) external whenNotPaused { PayerStorage storage $ = _getPayerStorage(); - require(amount >= $.minimumDepositMicroDollars, InsufficientAmount()); + require(amount >= $.minimumRegistrationAmountMicroDollars, InsufficientAmount()); require(!_payerExists(msg.sender), PayerAlreadyRegistered()); - // Transfer USDC from the sender to this contract - $.usdcToken.safeTransferFrom(msg.sender, address(this), amount); + _deposit(msg.sender, amount); // New payer registration $.payers[msg.sender] = Payer({ balance: amount, - isActive: true, + debtAmount: 0, creationTimestamp: block.timestamp, latestDepositTimestamp: block.timestamp, - debtAmount: 0 + latestDonationTimestamp: 0, + isActive: true }); // Add new payer to active and total payers sets - $.activePayers.add(msg.sender); - $.totalPayers.add(msg.sender); + require($.activePayers.add(msg.sender), FailedToRegisterPayer()); + require($.totalPayers.add(msg.sender), FailedToRegisterPayer()); + + _increaseTotalAmountDeposited(amount); - // Update counters - $.totalValueLocked += amount; - emit PayerRegistered(msg.sender, amount); } @@ -174,45 +176,33 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus function deposit(uint256 amount) external whenNotPaused onlyPayer(msg.sender) { PayerStorage storage $ = _getPayerStorage(); - require(amount > 0, InsufficientAmount()); - _revertIfPayerDoesNotExist(msg.sender); + require(amount >= $.minimumDepositAmountMicroDollars, InsufficientAmount()); - if ($.withdrawals[msg.sender].requestTimestamp != 0) { - revert PayerInWithdrawal(); - } + if ($.withdrawals[msg.sender].requestTimestamp != 0) revert PayerInWithdrawal(); - // Transfer USDC from sender to this contract - $.usdcToken.safeTransferFrom(msg.sender, address(this), amount); + _deposit(msg.sender, amount); - // Update payer record - $.payers[msg.sender].balance += amount; - $.payers[msg.sender].latestDepositTimestamp = block.timestamp; - $.totalValueLocked += amount; + _updatePayerBalance(msg.sender, amount); - emit Deposit(msg.sender, amount); + $.payers[msg.sender].latestDepositTimestamp = block.timestamp; } /** * @inheritdoc IPayer */ function donate(address payer, uint256 amount) external whenNotPaused { - PayerStorage storage $ = _getPayerStorage(); - require(amount > 0, InsufficientAmount()); _revertIfPayerDoesNotExist(payer); - if ($.withdrawals[payer].requestTimestamp != 0) { - revert PayerInWithdrawal(); - } + PayerStorage storage $ = _getPayerStorage(); - // Transfer USDC from sender to this contract - $.usdcToken.safeTransferFrom(msg.sender, address(this), amount); + if ($.withdrawals[payer].requestTimestamp != 0) revert PayerInWithdrawal(); - // Update payer record - $.payers[payer].balance += amount; - - // Update TVL - $.totalValueLocked += amount; + _deposit(msg.sender, amount); + + _updatePayerBalance(payer, amount); + + $.payers[payer].latestDonationTimestamp = block.timestamp; emit Donation(msg.sender, payer, amount); } @@ -220,12 +210,15 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus /** * @inheritdoc IPayer */ - function deactivatePayer(address payer) external whenNotPaused onlyRole(ADMIN_ROLE) { - PayerStorage storage $ = _getPayerStorage(); + function deactivatePayer(address payer) external whenNotPaused onlyNodeOperator { _revertIfPayerDoesNotExist(payer); + PayerStorage storage $ = _getPayerStorage(); + $.payers[payer].isActive = false; - $.activePayers.remove(payer); + + // Deactivating a payer only removes them from the active payers set + require($.activePayers.remove(payer), FailedToDeactivatePayer()); emit PayerDeactivated(payer); } @@ -234,24 +227,20 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus * @inheritdoc IPayer */ function deletePayer(address payer) external whenNotPaused onlyRole(ADMIN_ROLE) { - PayerStorage storage $ = _getPayerStorage(); - _revertIfPayerDoesNotExist(payer); + PayerStorage storage $ = _getPayerStorage(); + if ($.payers[payer].balance > 0 || $.payers[payer].debtAmount > 0) { revert PayerHasBalanceOrDebt(); } - if ($.withdrawals[payer].requestTimestamp != 0) { - revert PayerInWithdrawal(); - } + if ($.withdrawals[payer].requestTimestamp != 0) revert PayerInWithdrawal(); - // Delete payer data + // Delete all payer data delete $.payers[payer]; - - // Remove from totalPayers set - $.totalPayers.remove(payer); - $.activePayers.remove(payer); + require($.totalPayers.remove(payer), FailedToDeletePayer()); + require($.activePayers.remove(payer), FailedToDeletePayer()); emit PayerDeleted(payer, block.timestamp); } @@ -262,28 +251,75 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus * @inheritdoc IPayer */ function requestWithdrawal(uint256 amount) external whenNotPaused() onlyPayer(msg.sender) { - // TODO: Implement withdrawal request logic + if (_withdrawalExists(msg.sender)) revert WithdrawalAlreadyRequested(); + + PayerStorage storage $ = _getPayerStorage(); + + require($.payers[msg.sender].debtAmount == 0, PayerHasDebt()); + require($.payers[msg.sender].balance >= amount, InsufficientBalance()); + + // Balance to be withdrawn is deducted from the payer's balance, + // it can't be used to settle payments. + _decreasePayerBalance(msg.sender, amount); + _decreaseTotalAmountDeposited(amount); + + uint256 withdrawableTimestamp = block.timestamp + $.withdrawalLockPeriod; + + $.withdrawals[msg.sender] = Withdrawal({ + requestTimestamp: block.timestamp, + withdrawableTimestamp: withdrawableTimestamp, + amount: amount + }); + + emit WithdrawalRequested( + msg.sender, + block.timestamp, + withdrawableTimestamp, + amount + ); } /** * @inheritdoc IPayer */ function cancelWithdrawal() external whenNotPaused() onlyPayer(msg.sender) { - // TODO: Implement withdrawal cancellation logic + _revertIfWithdrawalNotExists(msg.sender); + + PayerStorage storage $ = _getPayerStorage(); + + Withdrawal memory withdrawal = $.withdrawals[msg.sender]; + + delete $.withdrawals[msg.sender]; + + _updatePayerBalance(msg.sender, withdrawal.amount); + + emit WithdrawalCancelled(msg.sender, withdrawal.requestTimestamp); } /** * @inheritdoc IPayer */ function finalizeWithdrawal() external whenNotPaused() onlyPayer(msg.sender) { - // TODO: Implement withdrawal finalization logic + _revertIfWithdrawalNotExists(msg.sender); + + PayerStorage storage $ = _getPayerStorage(); + + Withdrawal memory withdrawal = $.withdrawals[msg.sender]; + + delete $.withdrawals[msg.sender]; + + $.usdcToken.safeTransfer(msg.sender, withdrawal.amount); + + emit WithdrawalFinalized(msg.sender, withdrawal.requestTimestamp); } /** * @inheritdoc IPayer */ function getWithdrawalStatus(address payer) external view returns (Withdrawal memory withdrawal) { - // TODO: Implement withdrawal status retrieval logic + _revertIfPayerDoesNotExist(payer); + + return _getPayerStorage().withdrawals[payer]; } /* ============ Usage Settlement ============ */ @@ -346,16 +382,30 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus * @inheritdoc IPayer */ function setMinimumDeposit(uint256 _newMinimumDeposit) external onlyRole(ADMIN_ROLE) { - require(_newMinimumDeposit > DEFAULT_MINIMUM_DEPOSIT_MICRO_DOLLARS, InvalidMinimumDeposit()); + require(_newMinimumDeposit > DEFAULT_MINIMUM_DEPOSIT_AMOUNT_MICRO_DOLLARS, InvalidMinimumDeposit()); PayerStorage storage $ = _getPayerStorage(); - uint256 oldMinimumDeposit = $.minimumDepositMicroDollars; - $.minimumDepositMicroDollars = _newMinimumDeposit; + uint256 oldMinimumDeposit = $.minimumDepositAmountMicroDollars; + $.minimumDepositAmountMicroDollars = _newMinimumDeposit; emit MinimumDepositSet(oldMinimumDeposit, _newMinimumDeposit); } + /** + * @inheritdoc IPayer + */ + function setMinimumRegistrationAmount(uint256 _newMinimumRegistrationAmount) external onlyRole(ADMIN_ROLE) { + require(_newMinimumRegistrationAmount > DEFAULT_MINIMUM_REGISTRATION_AMOUNT_MICRO_DOLLARS, InvalidMinimumRegistrationAmount()); + + PayerStorage storage $ = _getPayerStorage(); + + uint256 oldMinimumRegistrationAmount = $.minimumRegistrationAmountMicroDollars; + $.minimumRegistrationAmountMicroDollars = _newMinimumRegistrationAmount; + + emit MinimumRegistrationAmountSet(oldMinimumRegistrationAmount, _newMinimumRegistrationAmount); + } + /** * @inheritdoc IPayer */ @@ -462,9 +512,12 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus /** * @inheritdoc IPayer */ - function getTotalValueLocked() external view returns (uint256 tvl) { - // TODO: TVL should subtract the total debt amount - return _getPayerStorage().totalValueLocked; + function getTotalValueLocked() external view returns (uint256 totalValueLocked) { + PayerStorage storage $ = _getPayerStorage(); + + if ($.totalDebtAmount > $.totalAmountDeposited) return 0; + + return $.totalAmountDeposited - $.totalDebtAmount; } /** @@ -506,7 +559,14 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus * @inheritdoc IPayer */ function getMinimumDeposit() external view returns (uint256 minimumDeposit) { - return _getPayerStorage().minimumDepositMicroDollars; + return _getPayerStorage().minimumDepositAmountMicroDollars; + } + + /** + * @inheritdoc IPayer + */ + function getMinimumRegistrationAmount() external view returns (uint256 minimumRegistrationAmount) { + return _getPayerStorage().minimumRegistrationAmountMicroDollars; } /** @@ -532,8 +592,57 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus /* ============ Internal ============ */ + function _deposit(address payer, uint256 amount) internal { + PayerStorage storage $ = _getPayerStorage(); + + $.usdcToken.safeTransferFrom(payer, address(this), amount); + } + + /** + * @notice Updates a payer's balance by the specified amount. + * If the payer has debt, the debt is subtracted from the amount. + * If the payer has no debt, the amount is added to the balance. + * @param payerAddress The address of the payer. + * @param amount The amount to update by. + */ + function _updatePayerBalance(address payerAddress, uint256 amount) internal { + Payer storage payer = _getPayerStorage().payers[payerAddress]; + + if (payer.debtAmount == 0) { + payer.balance += amount; + _increaseTotalAmountDeposited(amount); + } else { + if (payer.debtAmount < amount) { + uint256 debtToRemove = payer.debtAmount; + amount -= debtToRemove; + payer.debtAmount = 0; + payer.balance += amount; + _increaseTotalAmountDeposited(amount); + _decreaseTotalDebtAmount(debtToRemove); + } else { + payer.debtAmount -= amount; + _decreaseTotalDebtAmount(amount); + } + } + + emit PayerBalanceUpdated(payerAddress, payer.balance, payer.debtAmount); + } + /** - * @dev Checks if a payer exists. + * @notice Decreases a payer's balance by the specified amount. + * @param payerAddress The address of the payer. + * @param amount The amount to decrease by. + */ + function _decreasePayerBalance(address payerAddress, uint256 amount) internal { + Payer storage payer = _getPayerStorage().payers[payerAddress]; + + payer.balance -= amount; + + emit PayerBalanceUpdated(payerAddress, payer.balance, payer.debtAmount); + } + + /** + * @notice Checks if a payer exists. * @param payer The address of the payer to check. * @return exists True if the payer exists, false otherwise. */ @@ -542,13 +651,39 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus } /** - * @dev Reverts if a payer does not exist. - * @param payer The address of the payer to check. + * @notice Checks if a payer is active. + * @param payer The address of the payer to check. + * @return isActive True if the payer is active, false otherwise. + */ + function _payerIsActive(address payer) internal view returns (bool isActive) { + return _getPayerStorage().payers[payer].isActive; + } + + /** + * @notice Reverts if a payer does not exist. + * @param payer The address of the payer to check. */ function _revertIfPayerDoesNotExist(address payer) internal view { require(_payerExists(payer), PayerDoesNotExist()); } + /** + * @notice Checks if a withdrawal exists. + * @param payer The address of the payer to check. + * @return exists True if the withdrawal exists, false otherwise. + */ + function _withdrawalExists(address payer) internal view returns (bool exists) { + return _getPayerStorage().withdrawals[payer].requestTimestamp != 0; + } + + /** + * @notice Reverts if a withdrawal does not exist. + * @param payer The address of the payer to check. + */ + function _revertIfWithdrawalNotExists(address payer) internal view { + require(_withdrawalExists(payer), WithdrawalNotExists()); + } + /** * @notice Checks if a given address is an active node operator. * @param operator The address to check. @@ -623,6 +758,24 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus emit UsdcTokenSet(_newUsdcToken); } + function _increaseTotalAmountDeposited(uint256 amount) internal { + _getPayerStorage().totalAmountDeposited += amount; + } + + // TODO: Check for underflow + function _decreaseTotalAmountDeposited(uint256 amount) internal { + _getPayerStorage().totalAmountDeposited -= amount; + } + + function _increaseTotalDebtAmount(uint256 amount) internal { + _getPayerStorage().totalDebtAmount += amount; + } + + // TODO: Check for underflow + function _decreaseTotalDebtAmount(uint256 amount) internal { + _getPayerStorage().totalDebtAmount -= amount; + } + /* ============ Upgradeability ============ */ /** diff --git a/contracts/src/interfaces/IPayer.sol b/contracts/src/interfaces/IPayer.sol index 9907026e..e85fbc66 100644 --- a/contracts/src/interfaces/IPayer.sol +++ b/contracts/src/interfaces/IPayer.sol @@ -21,10 +21,11 @@ interface IPayer is IERC165 { */ struct Payer { uint256 balance; - bool isActive; + uint256 debtAmount; uint256 creationTimestamp; uint256 latestDepositTimestamp; - uint256 debtAmount; + uint256 latestDonationTimestamp; + bool isActive; } /** @@ -56,16 +57,19 @@ interface IPayer is IERC165 { /// @dev Emitted when a user donates to a payer's account. event Donation(address indexed donor, address indexed payer, uint256 amount); + /// @dev Emitted when a payer balance is updated. + event PayerBalanceUpdated(address indexed payer, uint256 newBalance, uint256 newDebtAmount); + /// @dev Emitted when a payer initiates a withdrawal request. - event WithdrawalRequest( - address indexed payer, uint256 requestTimestamp, uint256 withdrawableTimestamp, uint256 amount + event WithdrawalRequested( + address indexed payer, uint256 indexed requestTimestamp, uint256 withdrawableTimestamp, uint256 amount ); /// @dev Emitted when a payer cancels a withdrawal request. - event WithdrawalCancelled(address indexed payer); + event WithdrawalCancelled(address indexed payer, uint256 indexed requestTimestamp); /// @dev Emitted when a payer's withdrawal is finalized. - event WithdrawalFinalized(address indexed payer, uint256 amountReturned); + event WithdrawalFinalized(address indexed payer, uint256 indexed requestTimestamp); /// @dev Emitted when usage is settled and fees are calculated. event UsageSettled(uint256 fees, address indexed payer, uint256 indexed originatorNode, uint256 timestamp); @@ -88,6 +92,9 @@ interface IPayer is IERC165 { /// @dev Emitted when the minimum deposit amount is updated. event MinimumDepositSet(uint256 oldMinimumDeposit, uint256 newMinimumDeposit); + /// @dev Emitted when the minimum registration amount is updated. + event MinimumRegistrationAmountSet(uint256 oldMinimumRegistrationAmount, uint256 newMinimumRegistrationAmount); + /// @dev Emitted when the upgrade is authorized. event UpgradeAuthorized(address indexed upgrader, address indexed newImplementation); @@ -123,9 +130,15 @@ interface IPayer is IERC165 { /// @dev Error thrown when the amount is insufficient. error InsufficientAmount(); + /// @dev Error thrown when balance is insufficient. + error InsufficientBalance(); + /// @dev Error thrown when the minimum deposit is invalid. error InvalidMinimumDeposit(); + /// @dev Error thrown when the minimum registration amount is invalid. + error InvalidMinimumRegistrationAmount(); + /// @dev Error thrown when the withdrawal lock period is invalid. error InvalidWithdrawalLockPeriod(); @@ -138,6 +151,9 @@ interface IPayer is IERC165 { /// @dev Error thrown when a withdrawal is already in progress. error WithdrawalAlreadyRequested(); + /// @dev Error thrown when a withdrawal is not in the requested state. + error WithdrawalNotExists(); + /// @dev Error thrown when a lock period has not yet elapsed. error LockPeriodNotElapsed(); @@ -156,15 +172,27 @@ interface IPayer is IERC165 { /// @dev Error thrown when trying to delete a payer with balance or debt. error PayerHasBalanceOrDebt(); + /// @dev Error thrown when payer has debt. + error PayerHasDebt(); + /// @dev Error thrown when trying to delete a payer in withdrawal state. error PayerInWithdrawal(); + /// @dev Error thrown when a payer is not active. + error PayerIsNotActive(); + /// @notice Error thrown when granting a role has failed. error FailedToGrantRole(bytes32 role, address account); /// @notice Error thrown when registering a payer has failed. error FailedToRegisterPayer(); + /// @notice Error thrown when deactivating a payer has failed. + error FailedToDeactivatePayer(); + + /// @notice Error thrown when deleting a payer has failed. + error FailedToDeletePayer(); + /* ============ Payer Management ============ */ /** @@ -196,7 +224,7 @@ interface IPayer is IERC165 { function donate(address payer, uint256 amount) external; /** - * @notice Deactivates a payer, preventing them from initiating new transactions. + * @notice Deactivates a payer, signaling XMTP nodes they should not accept messages from them. * Only callable by authorized node operators. * @param payer The address of the payer to deactivate. * @@ -322,6 +350,14 @@ interface IPayer is IERC165 { */ function setMinimumDeposit(uint256 newMinimumDeposit) external; + /** + * @notice Sets the minimum deposit amount required for registration. + * @param newMinimumRegistrationAmount The new minimum deposit amount. + * + * Emits `MinimumRegistrationAmountUpdated`. + */ + function setMinimumRegistrationAmount(uint256 newMinimumRegistrationAmount) external; + /** * @notice Sets the withdrawal lock period. * @param newWithdrawalLockPeriod The new withdrawal lock period. @@ -442,6 +478,12 @@ interface IPayer is IERC165 { */ function getMinimumDeposit() external view returns (uint256 minimumDeposit); + /** + * @notice Retrieves the minimum deposit amount required to register as a payer. + * @return minimumRegistrationAmount The minimum deposit amount in USDC. + */ + function getMinimumRegistrationAmount() external view returns (uint256 minimumRegistrationAmount); + /** * @notice Retrieves the current total balance of a given payer. * @param payer The address of the payer. From a9570f9a3ce73d2abb50b91c46a6df9203e3b4a7 Mon Sep 17 00:00:00 2001 From: Borja Aranda Date: Thu, 13 Mar 2025 15:37:54 +0100 Subject: [PATCH 08/24] divide interfaces for legibility --- contracts/src/interfaces/IPayer.sol | 86 ++++++++++++++++------------- 1 file changed, 47 insertions(+), 39 deletions(-) diff --git a/contracts/src/interfaces/IPayer.sol b/contracts/src/interfaces/IPayer.sol index e85fbc66..475420c0 100644 --- a/contracts/src/interfaces/IPayer.sol +++ b/contracts/src/interfaces/IPayer.sol @@ -4,44 +4,10 @@ pragma solidity 0.8.28; import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; /** - * @title IPayer - * @notice Interface for managing payer USDC deposits, usage settlements, - * and a secure withdrawal process. + * @title IPayerEvents + * @notice Interface for events emitted by the Payer contract. */ -interface IPayer is IERC165 { - /* ============ Structs ============ */ - - /** - * @dev Struct to store payer information. - * @param balance The current USDC balance of the payer. - * @param isActive Indicates whether the payer is active. - * @param creationTimestamp The timestamp when the payer was first registered. - * @param latestDepositTimestamp The timestamp of the most recent deposit. - * @param debtAmount The amount of fees owed but not yet settled. - */ - struct Payer { - uint256 balance; - uint256 debtAmount; - uint256 creationTimestamp; - uint256 latestDepositTimestamp; - uint256 latestDonationTimestamp; - bool isActive; - } - - /** - * @dev Struct to store withdrawal request information. - * @param requestTimestamp The timestamp when the withdrawal was requested. - * @param withdrawableTimestamp The timestamp when the withdrawal can be finalized. - * @param amount The amount requested for withdrawal. - */ - struct Withdrawal { - uint256 requestTimestamp; - uint256 withdrawableTimestamp; - uint256 amount; - } - - /* ============ Events ============ */ - +interface IPayerEvents { /// @dev Emitted when a new payer is registered. event PayerRegistered(address indexed payer, uint256 amount); @@ -103,9 +69,13 @@ interface IPayer is IERC165 { /// @dev Emitted when the maximum backdated time is updated. event MaxBackdatedTimeSet(uint256 oldMaxBackdatedTime, uint256 newMaxBackdatedTime); +} - /* ============ Custom Errors ============ */ - +/** + * @title IPayerErrors + * @notice Interface for errors emitted by the Payer contract. + */ +interface IPayerErrors { /// @dev Error thrown when a call is unauthorized. error Unauthorized(); @@ -192,6 +162,44 @@ interface IPayer is IERC165 { /// @notice Error thrown when deleting a payer has failed. error FailedToDeletePayer(); +} + +/** + * @title IPayer + * @notice Interface for managing payer USDC deposits, usage settlements, + * and a secure withdrawal process. + */ +interface IPayer is IERC165, IPayerEvents, IPayerErrors { + /* ============ Structs ============ */ + + /** + * @dev Struct to store payer information. + * @param balance The current USDC balance of the payer. + * @param isActive Indicates whether the payer is active. + * @param creationTimestamp The timestamp when the payer was first registered. + * @param latestDepositTimestamp The timestamp of the most recent deposit. + * @param debtAmount The amount of fees owed but not yet settled. + */ + struct Payer { + uint256 balance; + uint256 debtAmount; + uint256 creationTimestamp; + uint256 latestDepositTimestamp; + uint256 latestDonationTimestamp; + bool isActive; + } + + /** + * @dev Struct to store withdrawal request information. + * @param requestTimestamp The timestamp when the withdrawal was requested. + * @param withdrawableTimestamp The timestamp when the withdrawal can be finalized. + * @param amount The amount requested for withdrawal. + */ + struct Withdrawal { + uint256 requestTimestamp; + uint256 withdrawableTimestamp; + uint256 amount; + } /* ============ Payer Management ============ */ From 6d5ce5a187a44d57287befcfbe1f9b65d6f96f8f Mon Sep 17 00:00:00 2001 From: Borja Aranda Date: Thu, 13 Mar 2025 16:17:36 +0100 Subject: [PATCH 09/24] add getActivePayers paginated --- contracts/src/Payer.sol | 28 ++++++++++++++++++++++++++++ contracts/src/interfaces/IPayer.sol | 15 +++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/contracts/src/Payer.sol b/contracts/src/Payer.sol index cd928a9c..ee6ff713 100644 --- a/contracts/src/Payer.sol +++ b/contracts/src/Payer.sol @@ -459,6 +459,34 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus return _getPayerStorage().payers[payer]; } + /** + * @inheritdoc IPayer + */ + function getActivePayers(uint256 offset, uint256 limit) external view returns (Payer[] memory payers, bool hasMore) { + PayerStorage storage $ = _getPayerStorage(); + + uint256 totalCount = $.activePayers.length(); + + if (offset >= totalCount) revert OutOfBounds(); + + uint256 count = totalCount - offset; + if (count > limit) { + count = limit; + hasMore = true; + } else { + hasMore = false; + } + + payers = new Payer[](count); + + for (uint256 i = 0; i < count; i++) { + address payerAddress = $.activePayers.at(offset + i); + payers[i] = $.payers[payerAddress]; + } + + return (payers, hasMore); + } + /** * @inheritdoc IPayer */ diff --git a/contracts/src/interfaces/IPayer.sol b/contracts/src/interfaces/IPayer.sol index 475420c0..53e14baf 100644 --- a/contracts/src/interfaces/IPayer.sol +++ b/contracts/src/interfaces/IPayer.sol @@ -162,6 +162,9 @@ interface IPayerErrors { /// @notice Error thrown when deleting a payer has failed. error FailedToDeletePayer(); + + /// @notice Error thrown when the offset is out of bounds. + error OutOfBounds(); } /** @@ -405,6 +408,18 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { */ function getPayer(address payer) external view returns (Payer memory payerInfo); + /** + * @notice Returns all active payers in a paginated response. + * @param offset Number of payers to skip before starting to return results. + * @param limit Maximum number of payers to return. + * @return payers The payer information. + * @return hasMore True if there are more payers to retrieve. + */ + function getActivePayers(uint256 offset, uint256 limit) + external + view + returns (Payer[] memory payers, bool hasMore); + /** * @notice Checks if a given address is an active payer. * @param payer The address to check. From d9ae9db789ae309672c7e9b7976ffc1e86ea88b9 Mon Sep 17 00:00:00 2001 From: Borja Aranda Date: Thu, 13 Mar 2025 16:51:30 +0100 Subject: [PATCH 10/24] abstract pagination over enumerableSets --- contracts/script/ComputeStorageSlot.sol | 6 +- contracts/src/Payer.sol | 152 +++++++++++++--------- contracts/src/interfaces/IPayer.sol | 16 +-- contracts/src/interfaces/IPayerReport.sol | 2 +- 4 files changed, 99 insertions(+), 77 deletions(-) diff --git a/contracts/script/ComputeStorageSlot.sol b/contracts/script/ComputeStorageSlot.sol index 7348e5cd..c10e0c7f 100644 --- a/contracts/script/ComputeStorageSlot.sol +++ b/contracts/script/ComputeStorageSlot.sol @@ -12,14 +12,14 @@ contract ComputeStorageSlot is Script { bytes32 namespaceHash = keccak256(bytes(namespace)); uint256 namespaceInt = uint256(namespaceHash); bytes32 slot = bytes32((namespaceInt - 1) & ~uint256(0xff)); - + console.log("Namespace:", namespace); console.logBytes32(namespaceHash); console.log("Storage Slot:"); console.logBytes32(slot); } - + function run() external view { this.compute(""); } -} \ No newline at end of file +} diff --git a/contracts/src/Payer.sol b/contracts/src/Payer.sol index ee6ff713..b011e3f2 100644 --- a/contracts/src/Payer.sol +++ b/contracts/src/Payer.sol @@ -1,24 +1,24 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.28; -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; -import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import { AccessControlUpgradeable } from "@openzeppelin-contracts-upgradeable/access/AccessControlUpgradeable.sol"; -import { PausableUpgradeable } from "@openzeppelin-contracts-upgradeable/utils/PausableUpgradeable.sol"; -import { UUPSUpgradeable } from "@openzeppelin-contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; -import { Initializable } from "@openzeppelin-contracts-upgradeable/proxy/utils/Initializable.sol"; -import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; -import { IPayer } from "./interfaces/IPayer.sol"; -import { IPayerReport } from "./interfaces/IPayerReport.sol"; -import { INodes } from "./interfaces/INodes.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {AccessControlUpgradeable} from "@openzeppelin-contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import {PausableUpgradeable} from "@openzeppelin-contracts-upgradeable/utils/PausableUpgradeable.sol"; +import {UUPSUpgradeable} from "@openzeppelin-contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; +import {Initializable} from "@openzeppelin-contracts-upgradeable/proxy/utils/Initializable.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; +import {IPayer} from "./interfaces/IPayer.sol"; +import {IPayerReport} from "./interfaces/IPayerReport.sol"; +import {INodes} from "./interfaces/INodes.sol"; /** * @title Payer * @notice Implementation for managing payer USDC deposits, usage settlements, * and a secure withdrawal process. */ -contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, PausableUpgradeable, IPayer{ +contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, PausableUpgradeable, IPayer { using SafeERC20 for IERC20; using EnumerableSet for EnumerableSet.AddressSet; @@ -42,24 +42,22 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus address distributionContract; address nodesContract; address payerReportContract; - /// @dev Configuration parameters uint256 minimumRegistrationAmountMicroDollars; uint256 minimumDepositAmountMicroDollars; uint256 withdrawalLockPeriod; uint256 maxBackdatedTime; - /// @dev State variables uint256 lastFeeTransferTimestamp; uint256 pendingFees; uint256 totalAmountDeposited; uint256 totalDebtAmount; - /// @dev Mappings mapping(address => Payer) payers; mapping(address => Withdrawal) withdrawals; EnumerableSet.AddressSet totalPayers; EnumerableSet.AddressSet activePayers; + EnumerableSet.AddressSet debtPayers; } // keccak256(abi.encode(uint256(keccak256("xmtp.storage.Payer")) - 1)) & ~bytes32(uint256(0xff)) @@ -111,11 +109,7 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus * We need to deploy these contracts first, then set their addresses * in the Payer contract. */ - function initialize( - address _initialAdmin, - address _usdcToken, - address _nodesContract - ) public initializer { + function initialize(address _initialAdmin, address _usdcToken, address _nodesContract) public initializer { if (_initialAdmin == address(0) || _usdcToken == address(0) || _nodesContract == address(0)) { revert InvalidAddress(); } @@ -241,7 +235,7 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus delete $.payers[payer]; require($.totalPayers.remove(payer), FailedToDeletePayer()); require($.activePayers.remove(payer), FailedToDeletePayer()); - + emit PayerDeleted(payer, block.timestamp); } @@ -250,7 +244,7 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus /** * @inheritdoc IPayer */ - function requestWithdrawal(uint256 amount) external whenNotPaused() onlyPayer(msg.sender) { + function requestWithdrawal(uint256 amount) external whenNotPaused onlyPayer(msg.sender) { if (_withdrawalExists(msg.sender)) revert WithdrawalAlreadyRequested(); PayerStorage storage $ = _getPayerStorage(); @@ -271,18 +265,13 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus amount: amount }); - emit WithdrawalRequested( - msg.sender, - block.timestamp, - withdrawableTimestamp, - amount - ); + emit WithdrawalRequested(msg.sender, block.timestamp, withdrawableTimestamp, amount); } /** * @inheritdoc IPayer */ - function cancelWithdrawal() external whenNotPaused() onlyPayer(msg.sender) { + function cancelWithdrawal() external whenNotPaused onlyPayer(msg.sender) { _revertIfWithdrawalNotExists(msg.sender); PayerStorage storage $ = _getPayerStorage(); @@ -299,7 +288,7 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus /** * @inheritdoc IPayer */ - function finalizeWithdrawal() external whenNotPaused() onlyPayer(msg.sender) { + function finalizeWithdrawal() external whenNotPaused onlyPayer(msg.sender) { _revertIfWithdrawalNotExists(msg.sender); PayerStorage storage $ = _getPayerStorage(); @@ -332,8 +321,7 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus uint256 reportIndex, address[] calldata payerList, uint256[] calldata amounts - ) external whenNotPaused onlyPayerReport - { + ) external whenNotPaused onlyPayerReport { // TODO: Implement usage settlement logic } @@ -396,7 +384,10 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus * @inheritdoc IPayer */ function setMinimumRegistrationAmount(uint256 _newMinimumRegistrationAmount) external onlyRole(ADMIN_ROLE) { - require(_newMinimumRegistrationAmount > DEFAULT_MINIMUM_REGISTRATION_AMOUNT_MICRO_DOLLARS, InvalidMinimumRegistrationAmount()); + require( + _newMinimumRegistrationAmount > DEFAULT_MINIMUM_REGISTRATION_AMOUNT_MICRO_DOLLARS, + InvalidMinimumRegistrationAmount() + ); PayerStorage storage $ = _getPayerStorage(); @@ -462,29 +453,21 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus /** * @inheritdoc IPayer */ - function getActivePayers(uint256 offset, uint256 limit) external view returns (Payer[] memory payers, bool hasMore) { + function getActivePayers(uint256 offset, uint256 limit) + external + view + returns (Payer[] memory payers, bool hasMore) + { PayerStorage storage $ = _getPayerStorage(); - - uint256 totalCount = $.activePayers.length(); - if (offset >= totalCount) revert OutOfBounds(); + (address[] memory payerAddresses, bool _hasMore) = _getPaginatedAddresses($.activePayers, offset, limit); - uint256 count = totalCount - offset; - if (count > limit) { - count = limit; - hasMore = true; - } else { - hasMore = false; + payers = new Payer[](payerAddresses.length); + for (uint256 i = 0; i < payerAddresses.length; i++) { + payers[i] = $.payers[payerAddresses[i]]; } - payers = new Payer[](count); - - for (uint256 i = 0; i < count; i++) { - address payerAddress = $.activePayers.at(offset + i); - payers[i] = $.payers[payerAddress]; - } - - return (payers, hasMore); + return (payers, _hasMore); } /** @@ -508,12 +491,21 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus /** * @inheritdoc IPayer */ - function getPayersInDebt(uint256 offset, uint256 limit) external view returns ( - address[] memory debtors, - uint256[] memory debtAmounts, - uint256 totalCount - ) { - // TODO: Implement payers in debt retrieval logic + function getPayersInDebt(uint256 offset, uint256 limit) + external + view + returns (Payer[] memory payers, bool hasMore) + { + PayerStorage storage $ = _getPayerStorage(); + + (address[] memory payerAddresses, bool _hasMore) = _getPaginatedAddresses($.debtPayers, offset, limit); + + payers = new Payer[](payerAddresses.length); + for (uint256 i = 0; i < payerAddresses.length; i++) { + payers[i] = $.payers[payerAddresses[i]]; + } + + return (payers, _hasMore); } /** @@ -657,10 +649,10 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus } /** - * @notice Decreases a payer's balance by the specified amount. - * @param payerAddress The address of the payer. - * @param amount The amount to decrease by. - */ + * @notice Decreases a payer's balance by the specified amount. + * @param payerAddress The address of the payer. + * @param amount The amount to decrease by. + */ function _decreasePayerBalance(address payerAddress, uint256 amount) internal { Payer storage payer = _getPayerStorage().payers[payerAddress]; @@ -735,7 +727,7 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus // IDistribution distribution = IDistribution(_newDistributionContract); // require(distribution.supportsInterface(type(IDistribution).interfaceId), InvalidDistributionContract()); - require (_newDistributionContract != address(0), InvalidAddress()); + require(_newDistributionContract != address(0), InvalidAddress()); $.distributionContract = _newDistributionContract; @@ -804,6 +796,40 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus _getPayerStorage().totalDebtAmount -= amount; } + /** + * @notice Internal helper for paginated access to EnumerableSet.AddressSet + * @param addressSet The EnumerableSet to paginate + * @param offset The starting index + * @param limit Maximum number of items to return + * @return addresses Array of addresses from the set + * @return hasMore Whether there are more items after this page + */ + function _getPaginatedAddresses(EnumerableSet.AddressSet storage addressSet, uint256 offset, uint256 limit) + internal + view + returns (address[] memory addresses, bool hasMore) + { + uint256 totalCount = addressSet.length(); + + if (offset >= totalCount) revert OutOfBounds(); + + uint256 count = totalCount - offset; + if (count > limit) { + count = limit; + hasMore = true; + } else { + hasMore = false; + } + + addresses = new address[](count); + + for (uint256 i = 0; i < count; i++) { + addresses[i] = addressSet.at(offset + i); + } + + return (addresses, hasMore); + } + /* ============ Upgradeability ============ */ /** @@ -814,4 +840,4 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus require(newImplementation != address(0), InvalidAddress()); emit UpgradeAuthorized(msg.sender, newImplementation); } -} \ No newline at end of file +} diff --git a/contracts/src/interfaces/IPayer.sol b/contracts/src/interfaces/IPayer.sol index 53e14baf..632a70c5 100644 --- a/contracts/src/interfaces/IPayer.sol +++ b/contracts/src/interfaces/IPayer.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.28; -import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; /** * @title IPayerEvents @@ -288,10 +288,7 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { * @param payer The address to check. * @return withdrawal The withdrawal status. */ - function getWithdrawalStatus(address payer) - external - view - returns (Withdrawal memory withdrawal); + function getWithdrawalStatus(address payer) external view returns (Withdrawal memory withdrawal); /* ============ Usage Settlement ============ */ @@ -431,14 +428,13 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { * @notice Returns a paginated list of payers with outstanding debt. * @param offset Number of payers to skip before starting to return results. * @param limit Maximum number of payers to return. - * @return debtors Array of payer addresses with debt. - * @return debtAmounts Corresponding debt amounts for each payer. - * @return totalCount Total number of payers with debt (regardless of pagination). + * @return payers Array of payer addresses with debt. + * @return hasMore True if there are more payers to retrieve. */ function getPayersInDebt(uint256 offset, uint256 limit) external view - returns (address[] memory debtors, uint256[] memory debtAmounts, uint256 totalCount); + returns (Payer[] memory payers, bool hasMore); /** * @notice Returns the total number of registered payers. @@ -533,4 +529,4 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { * @return maxTime The maximum allowed time difference in seconds. */ function getMaxBackdatedTime() external view returns (uint256 maxTime); -} \ No newline at end of file +} diff --git a/contracts/src/interfaces/IPayerReport.sol b/contracts/src/interfaces/IPayerReport.sol index 75bc9b9e..c61b18bb 100644 --- a/contracts/src/interfaces/IPayerReport.sol +++ b/contracts/src/interfaces/IPayerReport.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.28; -import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; /** * @title IPayerReport From 0354e71efa523b2d01767d1c5bb9773cbb9bb46e Mon Sep 17 00:00:00 2001 From: Borja Aranda Date: Thu, 13 Mar 2025 18:02:37 +0100 Subject: [PATCH 11/24] add first settleUsage draft --- contracts/src/Payer.sol | 117 ++++++++++++++++++++++++---- contracts/src/interfaces/IPayer.sol | 15 ++-- 2 files changed, 110 insertions(+), 22 deletions(-) diff --git a/contracts/src/Payer.sol b/contracts/src/Payer.sol index b011e3f2..4bb7d67a 100644 --- a/contracts/src/Payer.sol +++ b/contracts/src/Payer.sol @@ -27,6 +27,7 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE"); uint256 public constant DEFAULT_MINIMUM_REGISTRATION_AMOUNT_MICRO_DOLLARS = 10_000_000; uint256 public constant DEFAULT_MINIMUM_DEPOSIT_AMOUNT_MICRO_DOLLARS = 10_000_000; + uint256 public constant MAX_TOLERABLE_DEBT_AMOUNT_MICRO_DOLLARS = 100_000_000; uint256 public constant DEFAULT_WITHDRAWAL_LOCK_PERIOD = 3 days; uint256 public constant ABSOLUTE_MINIMUM_WITHDRAWAL_LOCK_PERIOD = 1 days; uint256 public constant DEFAULT_MAX_BACKDATED_TIME = 1 days; @@ -42,17 +43,22 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus address distributionContract; address nodesContract; address payerReportContract; + /// @dev Configuration parameters uint256 minimumRegistrationAmountMicroDollars; uint256 minimumDepositAmountMicroDollars; + uint256 maxTolerableDebtAmountMicroDollars; uint256 withdrawalLockPeriod; uint256 maxBackdatedTime; + /// @dev State variables uint256 lastFeeTransferTimestamp; uint256 pendingFees; uint256 totalAmountDeposited; uint256 totalDebtAmount; + /// @dev Mappings + uint256 collectedFees; mapping(address => Payer) payers; mapping(address => Withdrawal) withdrawals; EnumerableSet.AddressSet totalPayers; @@ -207,14 +213,7 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus function deactivatePayer(address payer) external whenNotPaused onlyNodeOperator { _revertIfPayerDoesNotExist(payer); - PayerStorage storage $ = _getPayerStorage(); - - $.payers[payer].isActive = false; - - // Deactivating a payer only removes them from the active payers set - require($.activePayers.remove(payer), FailedToDeactivatePayer()); - - emit PayerDeactivated(payer); + _deactivatePayer(payer); } /** @@ -295,10 +294,14 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus Withdrawal memory withdrawal = $.withdrawals[msg.sender]; - delete $.withdrawals[msg.sender]; + // TODO: A payer withdrawing funds can still incur debt. + // We need to handle this case. + // if ($.payers[msg.sender].debtAmount > 0) {} $.usdcToken.safeTransfer(msg.sender, withdrawal.amount); + delete $.withdrawals[msg.sender]; + emit WithdrawalFinalized(msg.sender, withdrawal.requestTimestamp); } @@ -317,12 +320,53 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus * @inheritdoc IPayer */ function settleUsage( - address originatorNode, - uint256 reportIndex, address[] calldata payerList, - uint256[] calldata amounts + uint256[] calldata amountsList ) external whenNotPaused onlyPayerReport { - // TODO: Implement usage settlement logic + require(payerList.length == amountsList.length, InvalidPayerListLength()); + + PayerStorage storage $ = _getPayerStorage(); + + for (uint256 i = 0; i < payerList.length; i++) { + address payer = payerList[i]; + uint256 amount = amountsList[i]; + + // This should never happen, as PayerReport has already verified the payers and amounts. + // Payers in payerList should always exist and be active. + if (!_payerExists(payer)) { + _decreaseTotalAmountDeposited(amount); + + continue; + } + + if (!_payerIsActive(payer)) continue; + + Payer memory storedPayer = $.payers[payer]; + + if (storedPayer.balance < amount) { + uint256 debt = amount - storedPayer.balance; + + $.collectedFees += storedPayer.balance; + + storedPayer.balance = 0; + storedPayer.debtAmount = debt; + + _addDebtor(payer); + _increaseTotalDebtAmount(debt); + + if (debt > MAX_TOLERABLE_DEBT_AMOUNT_MICRO_DOLLARS) _deactivatePayer(payer); + + emit PayerBalanceUpdated(payer, storedPayer.balance, storedPayer.debtAmount); + + continue; + } + + $.collectedFees += amount; + + storedPayer.balance -= amount; + + emit PayerBalanceUpdated(payer, storedPayer.balance, storedPayer.debtAmount); + } } /** @@ -626,6 +670,7 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus * @param amount The amount to update by. */ function _updatePayerBalance(address payerAddress, uint256 amount) internal { + // TODO: Remove this logic, in favor of settleDebts() or similar. Payer storage payer = _getPayerStorage().payers[payerAddress]; if (payer.debtAmount == 0) { @@ -637,6 +682,7 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus amount -= debtToRemove; payer.debtAmount = 0; payer.balance += amount; + _removeDebtor(payerAddress); _increaseTotalAmountDeposited(amount); _decreaseTotalDebtAmount(debtToRemove); } else { @@ -679,6 +725,17 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus return _getPayerStorage().payers[payer].isActive; } + function _deactivatePayer(address payer) internal { + PayerStorage storage $ = _getPayerStorage(); + + $.payers[payer].isActive = false; + + // Deactivating a payer only removes them from the active payers set + require($.activePayers.remove(payer), FailedToDeactivatePayer()); + + emit PayerDeactivated(payer); + } + /** * @notice Reverts if a payer does not exist. * @param payer The address of the payer to check. @@ -704,6 +761,30 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus require(_withdrawalExists(payer), WithdrawalNotExists()); } + /** + * @notice Removes a payer from the debt payers set. + * @param payer The address of the payer to remove. + */ + function _removeDebtor(address payer) internal { + PayerStorage storage $ = _getPayerStorage(); + + if ($.debtPayers.contains(payer)) { + require($.debtPayers.remove(payer), FailedToRemoveDebtor()); + } + } + + /** + * @notice Adds a payer to the debt payers set. + * @param payer The address of the payer to add. + */ + function _addDebtor(address payer) internal { + PayerStorage storage $ = _getPayerStorage(); + + if (!$.debtPayers.contains(payer)) { + require($.debtPayers.add(payer), FailedToAddDebtor()); + } + } + /** * @notice Checks if a given address is an active node operator. * @param operator The address to check. @@ -782,18 +863,20 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus _getPayerStorage().totalAmountDeposited += amount; } - // TODO: Check for underflow function _decreaseTotalAmountDeposited(uint256 amount) internal { - _getPayerStorage().totalAmountDeposited -= amount; + PayerStorage storage $ = _getPayerStorage(); + + $.totalAmountDeposited = amount > $.totalAmountDeposited ? 0 : $.totalAmountDeposited - amount; } function _increaseTotalDebtAmount(uint256 amount) internal { _getPayerStorage().totalDebtAmount += amount; } - // TODO: Check for underflow function _decreaseTotalDebtAmount(uint256 amount) internal { - _getPayerStorage().totalDebtAmount -= amount; + PayerStorage storage $ = _getPayerStorage(); + + $.totalDebtAmount = amount > $.totalDebtAmount ? 0 : $.totalDebtAmount - amount; } /** diff --git a/contracts/src/interfaces/IPayer.sol b/contracts/src/interfaces/IPayer.sol index 632a70c5..21168f71 100644 --- a/contracts/src/interfaces/IPayer.sol +++ b/contracts/src/interfaces/IPayer.sol @@ -163,8 +163,17 @@ interface IPayerErrors { /// @notice Error thrown when deleting a payer has failed. error FailedToDeletePayer(); + /// @notice Error thrown when removing a debtor has failed. + error FailedToRemoveDebtor(); + + /// @notice Error thrown when adding a debtor has failed. + error FailedToAddDebtor(); + /// @notice Error thrown when the offset is out of bounds. error OutOfBounds(); + + /// @notice Error thrown when the payer list length is invalid. + error InvalidPayerListLength(); } /** @@ -294,16 +303,12 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { /** * @notice Settles usage for a contiguous batch of (payer, amount) entries. - * Assumes that the PayerReport contract has already verified the aggregated Merkle proof. + * Assumes that the PayerReport contract has already verified the validity of the payers and amounts. * - * @param originatorNode The node that submitted the report. - * @param reportIndex The index of the report. * @param payers A contiguous array of payer addresses. * @param amounts A contiguous array of usage amounts corresponding to each payer. */ function settleUsage( - address originatorNode, - uint256 reportIndex, address[] calldata payers, uint256[] calldata amounts ) external; /* onlyPayerReport */ From 952b09cb26099df463ebefbcbfda25c0ddb3b18e Mon Sep 17 00:00:00 2001 From: Borja Aranda Date: Thu, 13 Mar 2025 21:47:05 +0100 Subject: [PATCH 12/24] cleaner logic --- contracts/src/Payer.sol | 154 ++++++++++------------ contracts/src/interfaces/IPayer.sol | 193 ++++++++++++---------------- 2 files changed, 150 insertions(+), 197 deletions(-) diff --git a/contracts/src/Payer.sol b/contracts/src/Payer.sol index 4bb7d67a..84cd60fe 100644 --- a/contracts/src/Payer.sol +++ b/contracts/src/Payer.sol @@ -30,8 +30,6 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus uint256 public constant MAX_TOLERABLE_DEBT_AMOUNT_MICRO_DOLLARS = 100_000_000; uint256 public constant DEFAULT_WITHDRAWAL_LOCK_PERIOD = 3 days; uint256 public constant ABSOLUTE_MINIMUM_WITHDRAWAL_LOCK_PERIOD = 1 days; - uint256 public constant DEFAULT_MAX_BACKDATED_TIME = 1 days; - uint256 public constant ABSOLUTE_MINIMUM_MAX_BACKDATED_TIME = 6 hours; string internal constant USDC_SYMBOL = "USDC"; /* ============ UUPS Storage ============ */ @@ -43,20 +41,16 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus address distributionContract; address nodesContract; address payerReportContract; - /// @dev Configuration parameters uint256 minimumRegistrationAmountMicroDollars; uint256 minimumDepositAmountMicroDollars; uint256 maxTolerableDebtAmountMicroDollars; uint256 withdrawalLockPeriod; - uint256 maxBackdatedTime; - /// @dev State variables uint256 lastFeeTransferTimestamp; uint256 pendingFees; uint256 totalAmountDeposited; uint256 totalDebtAmount; - /// @dev Mappings uint256 collectedFees; mapping(address => Payer) payers; @@ -129,7 +123,6 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus $.minimumRegistrationAmountMicroDollars = DEFAULT_MINIMUM_REGISTRATION_AMOUNT_MICRO_DOLLARS; $.minimumDepositAmountMicroDollars = DEFAULT_MINIMUM_DEPOSIT_AMOUNT_MICRO_DOLLARS; $.withdrawalLockPeriod = DEFAULT_WITHDRAWAL_LOCK_PERIOD; - $.maxBackdatedTime = DEFAULT_MAX_BACKDATED_TIME; _setUsdcTokenContract(_usdcToken); _setNodesContract(_nodesContract); @@ -177,14 +170,19 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus PayerStorage storage $ = _getPayerStorage(); require(amount >= $.minimumDepositAmountMicroDollars, InsufficientAmount()); - - if ($.withdrawals[msg.sender].requestTimestamp != 0) revert PayerInWithdrawal(); + require($.withdrawals[msg.sender].requestTimestamp == 0, PayerInWithdrawal()); _deposit(msg.sender, amount); - _updatePayerBalance(msg.sender, amount); + // TODO: Extract this logic to a helper function. + if ($.payers[msg.sender].debtAmount > 0) { + _settleDebts(msg.sender, amount); + } else { + $.payers[msg.sender].balance += amount; + _increaseTotalAmountDeposited(amount); + } - $.payers[msg.sender].latestDepositTimestamp = block.timestamp; + emit PayerBalanceUpdated(msg.sender, $.payers[msg.sender].balance, $.payers[msg.sender].debtAmount); } /** @@ -196,14 +194,21 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus PayerStorage storage $ = _getPayerStorage(); - if ($.withdrawals[payer].requestTimestamp != 0) revert PayerInWithdrawal(); + require($.withdrawals[payer].requestTimestamp == 0, PayerInWithdrawal()); _deposit(msg.sender, amount); - _updatePayerBalance(payer, amount); + // TODO: Extract this logic to a helper function. + if ($.payers[payer].debtAmount > 0) { + _settleDebts(payer, amount); + } else { + $.payers[payer].balance += amount; + _increaseTotalAmountDeposited(amount); + } $.payers[payer].latestDonationTimestamp = block.timestamp; + emit PayerBalanceUpdated(payer, $.payers[payer].balance, $.payers[payer].debtAmount); emit Donation(msg.sender, payer, amount); } @@ -224,12 +229,12 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus PayerStorage storage $ = _getPayerStorage(); + require($.withdrawals[payer].requestTimestamp == 0, PayerInWithdrawal()); + if ($.payers[payer].balance > 0 || $.payers[payer].debtAmount > 0) { revert PayerHasBalanceOrDebt(); } - if ($.withdrawals[payer].requestTimestamp != 0) revert PayerInWithdrawal(); - // Delete all payer data delete $.payers[payer]; require($.totalPayers.remove(payer), FailedToDeletePayer()); @@ -253,7 +258,7 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus // Balance to be withdrawn is deducted from the payer's balance, // it can't be used to settle payments. - _decreasePayerBalance(msg.sender, amount); + $.payers[msg.sender].balance -= amount; _decreaseTotalAmountDeposited(amount); uint256 withdrawableTimestamp = block.timestamp + $.withdrawalLockPeriod; @@ -279,7 +284,8 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus delete $.withdrawals[msg.sender]; - _updatePayerBalance(msg.sender, withdrawal.amount); + $.payers[msg.sender].balance += withdrawal.amount; + _increaseTotalAmountDeposited(withdrawal.amount); emit WithdrawalCancelled(msg.sender, withdrawal.requestTimestamp); } @@ -294,11 +300,13 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus Withdrawal memory withdrawal = $.withdrawals[msg.sender]; - // TODO: A payer withdrawing funds can still incur debt. - // We need to handle this case. - // if ($.payers[msg.sender].debtAmount > 0) {} + uint256 finalWithdrawalAmount = withdrawal.amount; - $.usdcToken.safeTransfer(msg.sender, withdrawal.amount); + if ($.payers[msg.sender].debtAmount > 0) { + finalWithdrawalAmount = _settleDebts(msg.sender, withdrawal.amount); + } + + $.usdcToken.safeTransfer(msg.sender, finalWithdrawalAmount); delete $.withdrawals[msg.sender]; @@ -319,37 +327,38 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus /** * @inheritdoc IPayer */ - function settleUsage( - address[] calldata payerList, - uint256[] calldata amountsList - ) external whenNotPaused onlyPayerReport { + function settleUsage(uint256 originatorNode, address[] calldata payerList, uint256[] calldata amountsList) + external + whenNotPaused + onlyPayerReport + { require(payerList.length == amountsList.length, InvalidPayerListLength()); PayerStorage storage $ = _getPayerStorage(); + uint256 fees = 0; + for (uint256 i = 0; i < payerList.length; i++) { address payer = payerList[i]; uint256 amount = amountsList[i]; // This should never happen, as PayerReport has already verified the payers and amounts. // Payers in payerList should always exist and be active. - if (!_payerExists(payer)) { - _decreaseTotalAmountDeposited(amount); - + if (!_payerExists(payer) || !_payerIsActive(payer)) { continue; } - if (!_payerIsActive(payer)) continue; - Payer memory storedPayer = $.payers[payer]; if (storedPayer.balance < amount) { uint256 debt = amount - storedPayer.balance; $.collectedFees += storedPayer.balance; + fees += storedPayer.balance; storedPayer.balance = 0; storedPayer.debtAmount = debt; + $.payers[payer] = storedPayer; _addDebtor(payer); _increaseTotalDebtAmount(debt); @@ -362,17 +371,22 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus } $.collectedFees += amount; + fees += amount; storedPayer.balance -= amount; + $.payers[payer] = storedPayer; + emit PayerBalanceUpdated(payer, storedPayer.balance, storedPayer.debtAmount); } + + emit UsageSettled(originatorNode, block.timestamp, fees); } /** * @inheritdoc IPayer */ - function transferFeesToDistribution() external whenNotPaused onlyRole(ADMIN_ROLE) { + function transferFeesToDistribution() external whenNotPaused onlyNodeOperator { // TODO: Implement fee transfer logic // Update lastFeeTransferTimestamp // Update pendingFees @@ -455,20 +469,6 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus emit WithdrawalLockPeriodSet(oldWithdrawalLockPeriod, _newWithdrawalLockPeriod); } - /** - * @inheritdoc IPayer - */ - function setMaxBackdatedTime(uint256 _newMaxBackdatedTime) external onlyRole(ADMIN_ROLE) { - require(_newMaxBackdatedTime >= ABSOLUTE_MINIMUM_MAX_BACKDATED_TIME, InvalidMaxBackdatedTime()); - - PayerStorage storage $ = _getPayerStorage(); - - uint256 oldMaxBackdatedTime = $.maxBackdatedTime; - $.maxBackdatedTime = _newMaxBackdatedTime; - - emit MaxBackdatedTimeSet(oldMaxBackdatedTime, _newMaxBackdatedTime); - } - /** * @inheritdoc IPayer */ @@ -647,13 +647,6 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus return _getPayerStorage().pendingFees; } - /** - * @inheritdoc IPayer - */ - function getMaxBackdatedTime() external view returns (uint256 maxTime) { - return _getPayerStorage().maxBackdatedTime; - } - /* ============ Internal ============ */ function _deposit(address payer, uint256 amount) internal { @@ -662,49 +655,34 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus $.usdcToken.safeTransferFrom(payer, address(this), amount); } - /** - * @notice Updates a payer's balance by the specified amount. - * If the payer has debt, the debt is subtracted from the amount. - * If the payer has no debt, the amount is added to the balance. - * @param payerAddress The address of the payer. - * @param amount The amount to update by. - */ - function _updatePayerBalance(address payerAddress, uint256 amount) internal { - // TODO: Remove this logic, in favor of settleDebts() or similar. - Payer storage payer = _getPayerStorage().payers[payerAddress]; + function _settleDebts(address payer, uint256 amount) internal returns (uint256 amountAfterSettlement) { + PayerStorage storage $ = _getPayerStorage(); + + Payer memory storedPayer = $.payers[payer]; - if (payer.debtAmount == 0) { - payer.balance += amount; + if (storedPayer.debtAmount < amount) { + uint256 debtToRemove = storedPayer.debtAmount; + amount -= debtToRemove; + + storedPayer.debtAmount = 0; + storedPayer.balance += amount; + + _removeDebtor(payer); _increaseTotalAmountDeposited(amount); + _decreaseTotalDebtAmount(debtToRemove); + + amountAfterSettlement = amount; } else { - if (payer.debtAmount < amount) { - uint256 debtToRemove = payer.debtAmount; - amount -= debtToRemove; - payer.debtAmount = 0; - payer.balance += amount; - _removeDebtor(payerAddress); - _increaseTotalAmountDeposited(amount); - _decreaseTotalDebtAmount(debtToRemove); - } else { - payer.debtAmount -= amount; - _decreaseTotalDebtAmount(amount); - } - } + storedPayer.debtAmount -= amount; - emit PayerBalanceUpdated(payerAddress, payer.balance, payer.debtAmount); - } + _decreaseTotalDebtAmount(amount); - /** - * @notice Decreases a payer's balance by the specified amount. - * @param payerAddress The address of the payer. - * @param amount The amount to decrease by. - */ - function _decreasePayerBalance(address payerAddress, uint256 amount) internal { - Payer storage payer = _getPayerStorage().payers[payerAddress]; + amountAfterSettlement = 0; + } - payer.balance -= amount; + $.payers[payer] = storedPayer; - emit PayerBalanceUpdated(payerAddress, payer.balance, payer.debtAmount); + return amountAfterSettlement; } /** diff --git a/contracts/src/interfaces/IPayer.sol b/contracts/src/interfaces/IPayer.sol index 21168f71..0676ef91 100644 --- a/contracts/src/interfaces/IPayer.sol +++ b/contracts/src/interfaces/IPayer.sol @@ -8,67 +8,61 @@ import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; * @notice Interface for events emitted by the Payer contract. */ interface IPayerEvents { - /// @dev Emitted when a new payer is registered. - event PayerRegistered(address indexed payer, uint256 amount); - - /// @dev Emitted when a payer is deactivated by an owner. - event PayerDeactivated(address indexed payer); - - /// @dev Emitted when a payer is permanently deleted from the system. - event PayerDeleted(address indexed payer, uint256 timestamp); - - /// @dev Emitted when a deposit is made to a payer's account. - event Deposit(address indexed payer, uint256 amount); + /// @dev Emitted when the distribution contract address is updated. + event DistributionContractSet(address indexed newDistributionContract); /// @dev Emitted when a user donates to a payer's account. event Donation(address indexed donor, address indexed payer, uint256 amount); - /// @dev Emitted when a payer balance is updated. - event PayerBalanceUpdated(address indexed payer, uint256 newBalance, uint256 newDebtAmount); + /// @dev Emitted when fees are transferred to the distribution contract. + event FeesTransferred(uint256 amount); - /// @dev Emitted when a payer initiates a withdrawal request. - event WithdrawalRequested( - address indexed payer, uint256 indexed requestTimestamp, uint256 withdrawableTimestamp, uint256 amount - ); + /// @dev Emitted when the minimum deposit amount is updated. + event MinimumDepositSet(uint256 oldMinimumDeposit, uint256 newMinimumDeposit); - /// @dev Emitted when a payer cancels a withdrawal request. - event WithdrawalCancelled(address indexed payer, uint256 indexed requestTimestamp); + /// @dev Emitted when the minimum registration amount is updated. + event MinimumRegistrationAmountSet(uint256 oldMinimumRegistrationAmount, uint256 newMinimumRegistrationAmount); - /// @dev Emitted when a payer's withdrawal is finalized. - event WithdrawalFinalized(address indexed payer, uint256 indexed requestTimestamp); + /// @dev Emitted when the nodes contract address is updated. + event NodesContractSet(address indexed newNodesContract); - /// @dev Emitted when usage is settled and fees are calculated. - event UsageSettled(uint256 fees, address indexed payer, uint256 indexed originatorNode, uint256 timestamp); + /// @dev Emitted when a payer balance is updated. + event PayerBalanceUpdated(address indexed payer, uint256 newBalance, uint256 newDebtAmount); - /// @dev Emitted when fees are transferred to the distribution contract. - event FeesTransferred(uint256 amount); + /// @dev Emitted when a payer is deactivated by an owner. + event PayerDeactivated(address indexed payer); - /// @dev Emitted when the distribution contract address is updated. - event DistributionContractSet(address indexed newDistributionContract); + /// @dev Emitted when a payer is permanently deleted from the system. + event PayerDeleted(address indexed payer, uint256 timestamp); - /// @dev Emitted when the nodes contract address is updated. - event NodesContractSet(address indexed newNodesContract); + /// @dev Emitted when a new payer is registered. + event PayerRegistered(address indexed payer, uint256 amount); /// @dev Emitted when the payer report contract address is updated. event PayerReportContractSet(address indexed newPayerReportContract); + /// @dev Emitted when the upgrade is authorized. + event UpgradeAuthorized(address indexed upgrader, address indexed newImplementation); + + /// @dev Emitted when usage is settled and fees are calculated. + event UsageSettled(uint256 indexed originatorNode, uint256 timestamp, uint256 feesCollected); + /// @dev Emitted when the USDC token address is updated. event UsdcTokenSet(address indexed newUsdcToken); - /// @dev Emitted when the minimum deposit amount is updated. - event MinimumDepositSet(uint256 oldMinimumDeposit, uint256 newMinimumDeposit); - - /// @dev Emitted when the minimum registration amount is updated. - event MinimumRegistrationAmountSet(uint256 oldMinimumRegistrationAmount, uint256 newMinimumRegistrationAmount); + /// @dev Emitted when a payer cancels a withdrawal request. + event WithdrawalCancelled(address indexed payer, uint256 indexed requestTimestamp); - /// @dev Emitted when the upgrade is authorized. - event UpgradeAuthorized(address indexed upgrader, address indexed newImplementation); + /// @dev Emitted when a payer's withdrawal is finalized. + event WithdrawalFinalized(address indexed payer, uint256 indexed requestTimestamp); /// @dev Emitted when the withdrawal lock period is updated. event WithdrawalLockPeriodSet(uint256 oldWithdrawalLockPeriod, uint256 newWithdrawalLockPeriod); - /// @dev Emitted when the maximum backdated time is updated. - event MaxBackdatedTimeSet(uint256 oldMaxBackdatedTime, uint256 newMaxBackdatedTime); + /// @dev Emitted when a payer initiates a withdrawal request. + event WithdrawalRequested( + address indexed payer, uint256 indexed requestTimestamp, uint256 withdrawableTimestamp, uint256 amount + ); } /** @@ -76,32 +70,38 @@ interface IPayerEvents { * @notice Interface for errors emitted by the Payer contract. */ interface IPayerErrors { - /// @dev Error thrown when a call is unauthorized. - error Unauthorized(); + /// @dev Error thrown when arrays have mismatched lengths. + error ArrayLengthMismatch(); - /// @dev Error thrown when caller is not an authorized node operator. - error UnauthorizedNodeOperator(); + /// @notice Error thrown when adding a debtor has failed. + error FailedToAddDebtor(); - /// @dev Error thrown when contract is not the distribution contract. - error InvalidDistributionContract(); + /// @notice Error thrown when deactivating a payer has failed. + error FailedToDeactivatePayer(); - /// @dev Error thrown when contract is not the payer report contract. - error InvalidPayerReportContract(); + /// @notice Error thrown when deleting a payer has failed. + error FailedToDeletePayer(); - /// @dev Error thrown when contract is not the nodes contract. - error InvalidNodesContract(); + /// @notice Error thrown when granting a role has failed. + error FailedToGrantRole(bytes32 role, address account); - /// @dev Error thrown when contract is not the USDC token contract. - error InvalidUsdcTokenContract(); + /// @notice Error thrown when registering a payer has failed. + error FailedToRegisterPayer(); - /// @dev Error thrown when an address is invalid (usually zero address). - error InvalidAddress(); + /// @notice Error thrown when removing a debtor has failed. + error FailedToRemoveDebtor(); + + /// @dev Error thrown when balance is insufficient. + error InsufficientBalance(); /// @dev Error thrown when the amount is insufficient. error InsufficientAmount(); - /// @dev Error thrown when balance is insufficient. - error InsufficientBalance(); + /// @dev Error thrown when an address is invalid (usually zero address). + error InvalidAddress(); + + /// @dev Error thrown when contract is not the distribution contract. + error InvalidDistributionContract(); /// @dev Error thrown when the minimum deposit is invalid. error InvalidMinimumDeposit(); @@ -109,36 +109,33 @@ interface IPayerErrors { /// @dev Error thrown when the minimum registration amount is invalid. error InvalidMinimumRegistrationAmount(); - /// @dev Error thrown when the withdrawal lock period is invalid. - error InvalidWithdrawalLockPeriod(); + /// @dev Error thrown when contract is not the nodes contract. + error InvalidNodesContract(); - /// @dev Error thrown when the maximum backdated time is invalid. - error InvalidMaxBackdatedTime(); + /// @notice Error thrown when the payer list length is invalid. + error InvalidPayerListLength(); - /// @dev Error thrown when a withdrawal is not in the requested state. - error WithdrawalNotRequested(); + /// @dev Error thrown when contract is not the payer report contract. + error InvalidPayerReportContract(); - /// @dev Error thrown when a withdrawal is already in progress. - error WithdrawalAlreadyRequested(); + /// @dev Error thrown when trying to backdate settlement too far. + error InvalidSettlementTime(); - /// @dev Error thrown when a withdrawal is not in the requested state. - error WithdrawalNotExists(); + /// @dev Error thrown when contract is not the USDC token contract. + error InvalidUsdcTokenContract(); + + /// @dev Error thrown when the withdrawal lock period is invalid. + error InvalidWithdrawalLockPeriod(); /// @dev Error thrown when a lock period has not yet elapsed. error LockPeriodNotElapsed(); - /// @dev Error thrown when arrays have mismatched lengths. - error ArrayLengthMismatch(); - - /// @dev Error thrown when trying to backdate settlement too far. - error InvalidSettlementTime(); + /// @notice Error thrown when the offset is out of bounds. + error OutOfBounds(); /// @dev Error thrown when payer already exists. error PayerAlreadyRegistered(); - /// @dev Error thrown when payer does not exist. - error PayerDoesNotExist(); - /// @dev Error thrown when trying to delete a payer with balance or debt. error PayerHasBalanceOrDebt(); @@ -148,32 +145,26 @@ interface IPayerErrors { /// @dev Error thrown when trying to delete a payer in withdrawal state. error PayerInWithdrawal(); + /// @dev Error thrown when payer does not exist. + error PayerDoesNotExist(); + /// @dev Error thrown when a payer is not active. error PayerIsNotActive(); - /// @notice Error thrown when granting a role has failed. - error FailedToGrantRole(bytes32 role, address account); - - /// @notice Error thrown when registering a payer has failed. - error FailedToRegisterPayer(); - - /// @notice Error thrown when deactivating a payer has failed. - error FailedToDeactivatePayer(); - - /// @notice Error thrown when deleting a payer has failed. - error FailedToDeletePayer(); + /// @dev Error thrown when a call is unauthorized. + error Unauthorized(); - /// @notice Error thrown when removing a debtor has failed. - error FailedToRemoveDebtor(); + /// @dev Error thrown when caller is not an authorized node operator. + error UnauthorizedNodeOperator(); - /// @notice Error thrown when adding a debtor has failed. - error FailedToAddDebtor(); + /// @dev Error thrown when a withdrawal is already in progress. + error WithdrawalAlreadyRequested(); - /// @notice Error thrown when the offset is out of bounds. - error OutOfBounds(); + /// @dev Error thrown when a withdrawal is not in the requested state. + error WithdrawalNotExists(); - /// @notice Error thrown when the payer list length is invalid. - error InvalidPayerListLength(); + /// @dev Error thrown when a withdrawal is not in the requested state. + error WithdrawalNotRequested(); } /** @@ -305,13 +296,11 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { * @notice Settles usage for a contiguous batch of (payer, amount) entries. * Assumes that the PayerReport contract has already verified the validity of the payers and amounts. * + * @param originatorNode The originator node of the usage. * @param payers A contiguous array of payer addresses. * @param amounts A contiguous array of usage amounts corresponding to each payer. */ - function settleUsage( - address[] calldata payers, - uint256[] calldata amounts - ) external; /* onlyPayerReport */ + function settleUsage(uint256 originatorNode, address[] calldata payers, uint256[] calldata amounts) external; /* onlyPayerReport */ /** * @notice Transfers all pending fees to the designated distribution contract. @@ -379,14 +368,6 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { */ function setWithdrawalLockPeriod(uint256 newWithdrawalLockPeriod) external; - /** - * @notice Sets the maximum backdated time for settlements. - * @param newMaxBackdatedTime The new maximum backdated time. - * - * Emits `MaxBackdatedTimeUpdated`. - */ - function setMaxBackdatedTime(uint256 newMaxBackdatedTime) external; - /** * @notice Pauses the contract functions in case of emergency. * @@ -528,10 +509,4 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { * @return fees The total pending fees in USDC. */ function getPendingFees() external view returns (uint256 fees); - - /** - * @notice Returns the maximum allowed time difference for backdated settlements. - * @return maxTime The maximum allowed time difference in seconds. - */ - function getMaxBackdatedTime() external view returns (uint256 maxTime); } From fce81d6085a56796f51df965a32563be40228fdc Mon Sep 17 00:00:00 2001 From: Borja Aranda Date: Fri, 14 Mar 2025 11:47:44 +0100 Subject: [PATCH 13/24] use generic func to update balance --- contracts/src/Payer.sol | 68 ++++++++++++++++------------- contracts/src/interfaces/IPayer.sol | 22 +++++++--- 2 files changed, 52 insertions(+), 38 deletions(-) diff --git a/contracts/src/Payer.sol b/contracts/src/Payer.sol index 84cd60fe..950f10e7 100644 --- a/contracts/src/Payer.sol +++ b/contracts/src/Payer.sol @@ -12,25 +12,25 @@ import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet import {IPayer} from "./interfaces/IPayer.sol"; import {IPayerReport} from "./interfaces/IPayerReport.sol"; import {INodes} from "./interfaces/INodes.sol"; - +import {ReentrancyGuardUpgradeable} from "@openzeppelin-contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; /** * @title Payer * @notice Implementation for managing payer USDC deposits, usage settlements, * and a secure withdrawal process. */ -contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, PausableUpgradeable, IPayer { +contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, PausableUpgradeable, ReentrancyGuardUpgradeable, IPayer { using SafeERC20 for IERC20; using EnumerableSet for EnumerableSet.AddressSet; /* ============ Constants ============ */ bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE"); - uint256 public constant DEFAULT_MINIMUM_REGISTRATION_AMOUNT_MICRO_DOLLARS = 10_000_000; - uint256 public constant DEFAULT_MINIMUM_DEPOSIT_AMOUNT_MICRO_DOLLARS = 10_000_000; - uint256 public constant MAX_TOLERABLE_DEBT_AMOUNT_MICRO_DOLLARS = 100_000_000; - uint256 public constant DEFAULT_WITHDRAWAL_LOCK_PERIOD = 3 days; - uint256 public constant ABSOLUTE_MINIMUM_WITHDRAWAL_LOCK_PERIOD = 1 days; string internal constant USDC_SYMBOL = "USDC"; + uint64 public constant DEFAULT_MINIMUM_REGISTRATION_AMOUNT_MICRO_DOLLARS = 10_000_000; + uint64 public constant DEFAULT_MINIMUM_DEPOSIT_AMOUNT_MICRO_DOLLARS = 10_000_000; + uint64 public constant MAX_TOLERABLE_DEBT_AMOUNT_MICRO_DOLLARS = 100_000_000; + uint32 public constant DEFAULT_WITHDRAWAL_LOCK_PERIOD = 3 days; + uint32 public constant ABSOLUTE_MINIMUM_WITHDRAWAL_LOCK_PERIOD = 1 days; /* ============ UUPS Storage ============ */ @@ -42,17 +42,17 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus address nodesContract; address payerReportContract; /// @dev Configuration parameters - uint256 minimumRegistrationAmountMicroDollars; - uint256 minimumDepositAmountMicroDollars; - uint256 maxTolerableDebtAmountMicroDollars; - uint256 withdrawalLockPeriod; + uint64 minimumRegistrationAmountMicroDollars; + uint64 minimumDepositAmountMicroDollars; + uint64 maxTolerableDebtAmountMicroDollars; + uint32 withdrawalLockPeriod; /// @dev State variables uint256 lastFeeTransferTimestamp; uint256 pendingFees; uint256 totalAmountDeposited; uint256 totalDebtAmount; - /// @dev Mappings uint256 collectedFees; + /// @dev Mappings mapping(address => Payer) payers; mapping(address => Withdrawal) withdrawals; EnumerableSet.AddressSet totalPayers; @@ -166,7 +166,7 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus /** * @inheritdoc IPayer */ - function deposit(uint256 amount) external whenNotPaused onlyPayer(msg.sender) { + function deposit(uint256 amount) external whenNotPaused nonReentrant onlyPayer(msg.sender) { PayerStorage storage $ = _getPayerStorage(); require(amount >= $.minimumDepositAmountMicroDollars, InsufficientAmount()); @@ -174,13 +174,7 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus _deposit(msg.sender, amount); - // TODO: Extract this logic to a helper function. - if ($.payers[msg.sender].debtAmount > 0) { - _settleDebts(msg.sender, amount); - } else { - $.payers[msg.sender].balance += amount; - _increaseTotalAmountDeposited(amount); - } + _updatePayerBalance(msg.sender, amount); emit PayerBalanceUpdated(msg.sender, $.payers[msg.sender].balance, $.payers[msg.sender].debtAmount); } @@ -198,13 +192,7 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus _deposit(msg.sender, amount); - // TODO: Extract this logic to a helper function. - if ($.payers[payer].debtAmount > 0) { - _settleDebts(payer, amount); - } else { - $.payers[payer].balance += amount; - _increaseTotalAmountDeposited(amount); - } + _updatePayerBalance(payer, amount); $.payers[payer].latestDonationTimestamp = block.timestamp; @@ -293,7 +281,7 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus /** * @inheritdoc IPayer */ - function finalizeWithdrawal() external whenNotPaused onlyPayer(msg.sender) { + function finalizeWithdrawal() external whenNotPaused nonReentrant onlyPayer(msg.sender) { _revertIfWithdrawalNotExists(msg.sender); PayerStorage storage $ = _getPayerStorage(); @@ -427,7 +415,7 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus /** * @inheritdoc IPayer */ - function setMinimumDeposit(uint256 _newMinimumDeposit) external onlyRole(ADMIN_ROLE) { + function setMinimumDeposit(uint64 _newMinimumDeposit) external onlyRole(ADMIN_ROLE) { require(_newMinimumDeposit > DEFAULT_MINIMUM_DEPOSIT_AMOUNT_MICRO_DOLLARS, InvalidMinimumDeposit()); PayerStorage storage $ = _getPayerStorage(); @@ -441,7 +429,7 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus /** * @inheritdoc IPayer */ - function setMinimumRegistrationAmount(uint256 _newMinimumRegistrationAmount) external onlyRole(ADMIN_ROLE) { + function setMinimumRegistrationAmount(uint64 _newMinimumRegistrationAmount) external onlyRole(ADMIN_ROLE) { require( _newMinimumRegistrationAmount > DEFAULT_MINIMUM_REGISTRATION_AMOUNT_MICRO_DOLLARS, InvalidMinimumRegistrationAmount() @@ -458,7 +446,7 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus /** * @inheritdoc IPayer */ - function setWithdrawalLockPeriod(uint256 _newWithdrawalLockPeriod) external onlyRole(ADMIN_ROLE) { + function setWithdrawalLockPeriod(uint32 _newWithdrawalLockPeriod) external onlyRole(ADMIN_ROLE) { require(_newWithdrawalLockPeriod >= ABSOLUTE_MINIMUM_WITHDRAWAL_LOCK_PERIOD, InvalidWithdrawalLockPeriod()); PayerStorage storage $ = _getPayerStorage(); @@ -655,6 +643,24 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus $.usdcToken.safeTransferFrom(payer, address(this), amount); } + /** + * @notice Updates a payer's balance, handling debt settlement if applicable + * @param payerAddress The address of the payer + * @param amount The amount to add to the payer's balance + * @return leftoverAmount Amount remaining after debt settlement (if any) + */ + function _updatePayerBalance(address payerAddress, uint256 amount) internal returns (uint256 leftoverAmount) { + PayerStorage storage $ = _getPayerStorage(); + + if ($.payers[payerAddress].debtAmount > 0) { + return _settleDebts(payerAddress, amount); + } else { + $.payers[payerAddress].balance += amount; + _increaseTotalAmountDeposited(amount); + return amount; + } + } + function _settleDebts(address payer, uint256 amount) internal returns (uint256 amountAfterSettlement) { PayerStorage storage $ = _getPayerStorage(); diff --git a/contracts/src/interfaces/IPayer.sol b/contracts/src/interfaces/IPayer.sol index 0676ef91..cff76ed8 100644 --- a/contracts/src/interfaces/IPayer.sol +++ b/contracts/src/interfaces/IPayer.sol @@ -65,6 +65,10 @@ interface IPayerEvents { ); } +/** + * @title IPayerErrors + * @notice Interface for errors emitted by the Payer contract. + */ /** * @title IPayerErrors * @notice Interface for errors emitted by the Payer contract. @@ -136,6 +140,9 @@ interface IPayerErrors { /// @dev Error thrown when payer already exists. error PayerAlreadyRegistered(); + /// @dev Error thrown when payer does not exist. + error PayerDoesNotExist(); + /// @dev Error thrown when trying to delete a payer with balance or debt. error PayerHasBalanceOrDebt(); @@ -145,9 +152,6 @@ interface IPayerErrors { /// @dev Error thrown when trying to delete a payer in withdrawal state. error PayerInWithdrawal(); - /// @dev Error thrown when payer does not exist. - error PayerDoesNotExist(); - /// @dev Error thrown when a payer is not active. error PayerIsNotActive(); @@ -300,7 +304,11 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { * @param payers A contiguous array of payer addresses. * @param amounts A contiguous array of usage amounts corresponding to each payer. */ - function settleUsage(uint256 originatorNode, address[] calldata payers, uint256[] calldata amounts) external; /* onlyPayerReport */ + function settleUsage( + uint256 originatorNode, + address[] calldata payers, + uint256[] calldata amounts + ) external; /* onlyPayerReport */ /** * @notice Transfers all pending fees to the designated distribution contract. @@ -350,7 +358,7 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { * * Emits `MinimumDepositUpdated`. */ - function setMinimumDeposit(uint256 newMinimumDeposit) external; + function setMinimumDeposit(uint64 newMinimumDeposit) external; /** * @notice Sets the minimum deposit amount required for registration. @@ -358,7 +366,7 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { * * Emits `MinimumRegistrationAmountUpdated`. */ - function setMinimumRegistrationAmount(uint256 newMinimumRegistrationAmount) external; + function setMinimumRegistrationAmount(uint64 newMinimumRegistrationAmount) external; /** * @notice Sets the withdrawal lock period. @@ -366,7 +374,7 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { * * Emits `WithdrawalLockPeriodUpdated`. */ - function setWithdrawalLockPeriod(uint256 newWithdrawalLockPeriod) external; + function setWithdrawalLockPeriod(uint32 newWithdrawalLockPeriod) external; /** * @notice Pauses the contract functions in case of emergency. From 94ed76952ed19a226ae940014c0d2c0ff789d349 Mon Sep 17 00:00:00 2001 From: Borja Aranda Date: Fri, 14 Mar 2025 11:49:41 +0100 Subject: [PATCH 14/24] withdraw only when there are funds --- contracts/src/Payer.sol | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contracts/src/Payer.sol b/contracts/src/Payer.sol index 950f10e7..7187289e 100644 --- a/contracts/src/Payer.sol +++ b/contracts/src/Payer.sol @@ -294,7 +294,9 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus finalWithdrawalAmount = _settleDebts(msg.sender, withdrawal.amount); } - $.usdcToken.safeTransfer(msg.sender, finalWithdrawalAmount); + if (finalWithdrawalAmount > 0) { + $.usdcToken.safeTransfer(msg.sender, finalWithdrawalAmount); + } delete $.withdrawals[msg.sender]; From 7d0efcb4685f24506b4bd94a831fa44c327de4df Mon Sep 17 00:00:00 2001 From: Borja Aranda Date: Fri, 14 Mar 2025 11:50:25 +0100 Subject: [PATCH 15/24] check-effect-interactions --- contracts/src/Payer.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/src/Payer.sol b/contracts/src/Payer.sol index 7187289e..1f08425b 100644 --- a/contracts/src/Payer.sol +++ b/contracts/src/Payer.sol @@ -288,6 +288,8 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus Withdrawal memory withdrawal = $.withdrawals[msg.sender]; + delete $.withdrawals[msg.sender]; + uint256 finalWithdrawalAmount = withdrawal.amount; if ($.payers[msg.sender].debtAmount > 0) { @@ -298,8 +300,6 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus $.usdcToken.safeTransfer(msg.sender, finalWithdrawalAmount); } - delete $.withdrawals[msg.sender]; - emit WithdrawalFinalized(msg.sender, withdrawal.requestTimestamp); } From a5e5a9d14fb89b68b9890685d68bb36972b4d73d Mon Sep 17 00:00:00 2001 From: Borja Aranda Date: Fri, 14 Mar 2025 13:58:05 +0100 Subject: [PATCH 16/24] final touches --- contracts/src/Payer.sol | 186 +++++++++++++++++++++------- contracts/src/interfaces/IPayer.sol | 43 ++++++- 2 files changed, 180 insertions(+), 49 deletions(-) diff --git a/contracts/src/Payer.sol b/contracts/src/Payer.sol index 1f08425b..bf4b17a9 100644 --- a/contracts/src/Payer.sol +++ b/contracts/src/Payer.sol @@ -1,24 +1,33 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.28; +import {AccessControlUpgradeable} from "@openzeppelin-contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; -import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import {AccessControlUpgradeable} from "@openzeppelin-contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import {Initializable} from "@openzeppelin-contracts-upgradeable/proxy/utils/Initializable.sol"; import {PausableUpgradeable} from "@openzeppelin-contracts-upgradeable/utils/PausableUpgradeable.sol"; +import {ReentrancyGuardUpgradeable} from "@openzeppelin-contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {UUPSUpgradeable} from "@openzeppelin-contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; -import {Initializable} from "@openzeppelin-contracts-upgradeable/proxy/utils/Initializable.sol"; -import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; + +import {INodes} from "./interfaces/INodes.sol"; import {IPayer} from "./interfaces/IPayer.sol"; import {IPayerReport} from "./interfaces/IPayerReport.sol"; -import {INodes} from "./interfaces/INodes.sol"; -import {ReentrancyGuardUpgradeable} from "@openzeppelin-contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; + /** * @title Payer * @notice Implementation for managing payer USDC deposits, usage settlements, * and a secure withdrawal process. */ -contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, PausableUpgradeable, ReentrancyGuardUpgradeable, IPayer { +contract Payer is + Initializable, + AccessControlUpgradeable, + UUPSUpgradeable, + PausableUpgradeable, + ReentrancyGuardUpgradeable, + IPayer +{ using SafeERC20 for IERC20; using EnumerableSet for EnumerableSet.AddressSet; @@ -26,11 +35,13 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE"); string internal constant USDC_SYMBOL = "USDC"; - uint64 public constant DEFAULT_MINIMUM_REGISTRATION_AMOUNT_MICRO_DOLLARS = 10_000_000; - uint64 public constant DEFAULT_MINIMUM_DEPOSIT_AMOUNT_MICRO_DOLLARS = 10_000_000; - uint64 public constant MAX_TOLERABLE_DEBT_AMOUNT_MICRO_DOLLARS = 100_000_000; - uint32 public constant DEFAULT_WITHDRAWAL_LOCK_PERIOD = 3 days; - uint32 public constant ABSOLUTE_MINIMUM_WITHDRAWAL_LOCK_PERIOD = 1 days; + uint64 private constant DEFAULT_MINIMUM_REGISTRATION_AMOUNT_MICRO_DOLLARS = 10_000_000; // 10 USD + uint64 private constant DEFAULT_MINIMUM_DEPOSIT_AMOUNT_MICRO_DOLLARS = 10_000_000; // 10 USD + uint64 private constant DEFAULT_MAX_TOLERABLE_DEBT_AMOUNT_MICRO_DOLLARS = 50_000_000; // 50 USD + uint32 private constant DEFAULT_MINIMUM_TRANSFER_FEES_PERIOD = 6 hours; + uint32 private constant ABSOLUTE_MINIMUM_TRANSFER_FEES_PERIOD = 1 hours; + uint32 private constant DEFAULT_WITHDRAWAL_LOCK_PERIOD = 3 days; + uint32 private constant ABSOLUTE_MINIMUM_WITHDRAWAL_LOCK_PERIOD = 1 days; /* ============ UUPS Storage ============ */ @@ -46,11 +57,12 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus uint64 minimumDepositAmountMicroDollars; uint64 maxTolerableDebtAmountMicroDollars; uint32 withdrawalLockPeriod; + uint32 transferFeesPeriod; /// @dev State variables uint256 lastFeeTransferTimestamp; - uint256 pendingFees; uint256 totalAmountDeposited; uint256 totalDebtAmount; + uint256 pendingFees; uint256 collectedFees; /// @dev Mappings mapping(address => Payer) payers; @@ -72,7 +84,7 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus /* ============ Modifiers ============ */ /** - * @dev Modifier to check if caller is an active node operator + * @dev Modifier to check if caller is an active node operator. */ modifier onlyNodeOperator() { if (!_getIsActiveNodeOperator(msg.sender)) { @@ -82,7 +94,7 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus } /** - * @dev Modifier to check if caller is the payer report contract + * @dev Modifier to check if caller is the payer report contract. */ modifier onlyPayerReport() { if (msg.sender != _getPayerStorage().payerReportContract) { @@ -92,7 +104,7 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus } /** - * @dev Modifier to check if address is an active payer + * @dev Modifier to check if address is an active payer. */ modifier onlyPayer(address payer) { require(_payerExists(payer), PayerDoesNotExist()); @@ -123,6 +135,8 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus $.minimumRegistrationAmountMicroDollars = DEFAULT_MINIMUM_REGISTRATION_AMOUNT_MICRO_DOLLARS; $.minimumDepositAmountMicroDollars = DEFAULT_MINIMUM_DEPOSIT_AMOUNT_MICRO_DOLLARS; $.withdrawalLockPeriod = DEFAULT_WITHDRAWAL_LOCK_PERIOD; + $.maxTolerableDebtAmountMicroDollars = DEFAULT_MAX_TOLERABLE_DEBT_AMOUNT_MICRO_DOLLARS; + $.transferFeesPeriod = DEFAULT_MINIMUM_TRANSFER_FEES_PERIOD; _setUsdcTokenContract(_usdcToken); _setNodesContract(_nodesContract); @@ -317,12 +331,13 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus /** * @inheritdoc IPayer */ - function settleUsage(uint256 originatorNode, address[] calldata payerList, uint256[] calldata amountsList) + function settleUsage(uint256 originatorNode, address[] calldata payerList, uint256[] calldata usageAmountsList) external whenNotPaused + nonReentrant onlyPayerReport { - require(payerList.length == amountsList.length, InvalidPayerListLength()); + require(payerList.length == usageAmountsList.length, InvalidPayerListLength()); PayerStorage storage $ = _getPayerStorage(); @@ -330,7 +345,7 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus for (uint256 i = 0; i < payerList.length; i++) { address payer = payerList[i]; - uint256 amount = amountsList[i]; + uint256 usage = usageAmountsList[i]; // This should never happen, as PayerReport has already verified the payers and amounts. // Payers in payerList should always exist and be active. @@ -340,10 +355,10 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus Payer memory storedPayer = $.payers[payer]; - if (storedPayer.balance < amount) { - uint256 debt = amount - storedPayer.balance; + if (storedPayer.balance < usage) { + uint256 debt = usage - storedPayer.balance; - $.collectedFees += storedPayer.balance; + $.pendingFees += storedPayer.balance; fees += storedPayer.balance; storedPayer.balance = 0; @@ -353,17 +368,17 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus _addDebtor(payer); _increaseTotalDebtAmount(debt); - if (debt > MAX_TOLERABLE_DEBT_AMOUNT_MICRO_DOLLARS) _deactivatePayer(payer); + if (debt > $.maxTolerableDebtAmountMicroDollars) _deactivatePayer(payer); emit PayerBalanceUpdated(payer, storedPayer.balance, storedPayer.debtAmount); continue; } - $.collectedFees += amount; - fees += amount; + $.pendingFees += usage; + fees += usage; - storedPayer.balance -= amount; + storedPayer.balance -= usage; $.payers[payer] = storedPayer; @@ -376,12 +391,21 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus /** * @inheritdoc IPayer */ - function transferFeesToDistribution() external whenNotPaused onlyNodeOperator { - // TODO: Implement fee transfer logic - // Update lastFeeTransferTimestamp - // Update pendingFees - // Transfer fees to distribution contract - // Emit FeesTransferred event + function transferFeesToDistribution() external whenNotPaused nonReentrant { + PayerStorage storage $ = _getPayerStorage(); + + require(block.timestamp - $.lastFeeTransferTimestamp >= $.transferFeesPeriod, InsufficientTimePassed()); + require($.pendingFees > 0, InsufficientAmount()); + + uint256 feesToTransfer = $.pendingFees; + + $.usdcToken.safeTransfer($.distributionContract, feesToTransfer); + + $.lastFeeTransferTimestamp = block.timestamp; + $.collectedFees += $.pendingFees; + $.pendingFees = 0; + + emit FeesTransferred(block.timestamp, feesToTransfer); } /* ========== Administrative Functions ========== */ @@ -459,6 +483,35 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus emit WithdrawalLockPeriodSet(oldWithdrawalLockPeriod, _newWithdrawalLockPeriod); } + /** + * @inheritdoc IPayer + */ + function setMaxTolerableDebtAmount(uint64 _newMaxTolerableDebtAmountMicroDollars) external onlyRole(ADMIN_ROLE) { + require(_newMaxTolerableDebtAmountMicroDollars > 0, InvalidMaxTolerableDebtAmount()); + + PayerStorage storage $ = _getPayerStorage(); + + uint64 oldMaxTolerableDebtAmount = $.maxTolerableDebtAmountMicroDollars; + $.maxTolerableDebtAmountMicroDollars = _newMaxTolerableDebtAmountMicroDollars; + + emit MaxTolerableDebtAmountSet(oldMaxTolerableDebtAmount, _newMaxTolerableDebtAmountMicroDollars); + } + + /** + * @inheritdoc IPayer + */ + function setTransferFeesPeriod(uint32 _newTransferFeesPeriod) external onlyRole(ADMIN_ROLE) { + require(_newTransferFeesPeriod >= ABSOLUTE_MINIMUM_TRANSFER_FEES_PERIOD, InvalidTransferFeesPeriod()); + + PayerStorage storage $ = _getPayerStorage(); + + uint32 oldTransferFeesPeriod = $.transferFeesPeriod; + $.transferFeesPeriod = _newTransferFeesPeriod; + + emit TransferFeesPeriodSet(oldTransferFeesPeriod, _newTransferFeesPeriod); + } + + /** * @inheritdoc IPayer */ @@ -639,6 +692,11 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus /* ============ Internal ============ */ + /** + * @notice Deposits USDC from a payer to the contract. + * @param payer The address of the payer. + * @param amount The amount to deposit. + */ function _deposit(address payer, uint256 amount) internal { PayerStorage storage $ = _getPayerStorage(); @@ -646,11 +704,11 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus } /** - * @notice Updates a payer's balance, handling debt settlement if applicable - * @param payerAddress The address of the payer - * @param amount The amount to add to the payer's balance - * @return leftoverAmount Amount remaining after debt settlement (if any) - */ + * @notice Updates a payer's balance, handling debt settlement if applicable. + * @param payerAddress The address of the payer. + * @param amount The amount to add to the payer's balance. + * @return leftoverAmount Amount remaining after debt settlement (if any). + */ function _updatePayerBalance(address payerAddress, uint256 amount) internal returns (uint256 leftoverAmount) { PayerStorage storage $ = _getPayerStorage(); @@ -663,6 +721,12 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus } } + /** + * @notice Settles debts for a payer, updating their balance and total amounts. + * @param payer The address of the payer. + * @param amount The amount to settle debts for. + * @return amountAfterSettlement The amount remaining after debt settlement. + */ function _settleDebts(address payer, uint256 amount) internal returns (uint256 amountAfterSettlement) { PayerStorage storage $ = _getPayerStorage(); @@ -711,6 +775,10 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus return _getPayerStorage().payers[payer].isActive; } + /** + * @notice Deactivates a payer. + * @param payer The address of the payer to deactivate. + */ function _deactivatePayer(address payer) internal { PayerStorage storage $ = _getPayerStorage(); @@ -786,6 +854,10 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus return true; } + /** + * @notice Sets the Distribution contract. + * @param _newDistributionContract The address of the new Distribution contract. + */ function _setDistributionContract(address _newDistributionContract) internal { PayerStorage storage $ = _getPayerStorage(); @@ -801,6 +873,10 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus emit DistributionContractSet(_newDistributionContract); } + /** + * @notice Sets the PayerReport contract. + * @param _newPayerReportContract The address of the new PayerReport contract. + */ function _setPayerReportContract(address _newPayerReportContract) internal { PayerStorage storage $ = _getPayerStorage(); @@ -817,6 +893,10 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus emit PayerReportContractSet(_newPayerReportContract); } + /** + * @notice Sets the Nodes contract. + * @param _newNodesContract The address of the new Nodes contract. + */ function _setNodesContract(address _newNodesContract) internal { PayerStorage storage $ = _getPayerStorage(); @@ -831,6 +911,10 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus emit NodesContractSet(_newNodesContract); } + /** + * @notice Sets the USDC token contract. + * @param _newUsdcToken The address of the new USDC token contract. + */ function _setUsdcTokenContract(address _newUsdcToken) internal { PayerStorage storage $ = _getPayerStorage(); @@ -845,20 +929,36 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus emit UsdcTokenSet(_newUsdcToken); } + /** + * @notice Increases the total amount deposited by a given amount. + * @param amount The amount to increase the total amount deposited by. + */ function _increaseTotalAmountDeposited(uint256 amount) internal { _getPayerStorage().totalAmountDeposited += amount; } + /** + * @notice Decreases the total amount deposited by a given amount. + * @param amount The amount to decrease the total amount deposited by. + */ function _decreaseTotalAmountDeposited(uint256 amount) internal { PayerStorage storage $ = _getPayerStorage(); $.totalAmountDeposited = amount > $.totalAmountDeposited ? 0 : $.totalAmountDeposited - amount; } + /** + * @notice Increases the total debt amount by a given amount. + * @param amount The amount to increase the total debt amount by. + */ function _increaseTotalDebtAmount(uint256 amount) internal { _getPayerStorage().totalDebtAmount += amount; } + /** + * @notice Decreases the total debt amount by a given amount. + * @param amount The amount to decrease the total debt amount by. + */ function _decreaseTotalDebtAmount(uint256 amount) internal { PayerStorage storage $ = _getPayerStorage(); @@ -866,12 +966,12 @@ contract Payer is Initializable, AccessControlUpgradeable, UUPSUpgradeable, Paus } /** - * @notice Internal helper for paginated access to EnumerableSet.AddressSet - * @param addressSet The EnumerableSet to paginate - * @param offset The starting index - * @param limit Maximum number of items to return - * @return addresses Array of addresses from the set - * @return hasMore Whether there are more items after this page + * @notice Internal helper for paginated access to EnumerableSet.AddressSet. + * @param addressSet The EnumerableSet to paginate. + * @param offset The starting index. + * @param limit Maximum number of items to return. + * @return addresses Array of addresses from the set. + * @return hasMore Whether there are more items after this page. */ function _getPaginatedAddresses(EnumerableSet.AddressSet storage addressSet, uint256 offset, uint256 limit) internal diff --git a/contracts/src/interfaces/IPayer.sol b/contracts/src/interfaces/IPayer.sol index cff76ed8..f8f0ef0a 100644 --- a/contracts/src/interfaces/IPayer.sol +++ b/contracts/src/interfaces/IPayer.sol @@ -15,7 +15,10 @@ interface IPayerEvents { event Donation(address indexed donor, address indexed payer, uint256 amount); /// @dev Emitted when fees are transferred to the distribution contract. - event FeesTransferred(uint256 amount); + event FeesTransferred(uint256 indexed timestamp, uint256 amount); + + /// @dev Emitted when the maximum tolerable debt amount is updated. + event MaxTolerableDebtAmountSet(uint64 oldMaxTolerableDebtAmount, uint64 newMaxTolerableDebtAmount); /// @dev Emitted when the minimum deposit amount is updated. event MinimumDepositSet(uint256 oldMinimumDeposit, uint256 newMinimumDeposit); @@ -41,11 +44,14 @@ interface IPayerEvents { /// @dev Emitted when the payer report contract address is updated. event PayerReportContractSet(address indexed newPayerReportContract); + /// @dev Emitted when the transfer fees period is updated. + event TransferFeesPeriodSet(uint32 oldTransferFeesPeriod, uint32 newTransferFeesPeriod); + /// @dev Emitted when the upgrade is authorized. event UpgradeAuthorized(address indexed upgrader, address indexed newImplementation); /// @dev Emitted when usage is settled and fees are calculated. - event UsageSettled(uint256 indexed originatorNode, uint256 timestamp, uint256 feesCollected); + event UsageSettled(uint256 indexed originatorNode, uint256 timestamp, uint256 collectedFees); /// @dev Emitted when the USDC token address is updated. event UsdcTokenSet(address indexed newUsdcToken); @@ -95,18 +101,24 @@ interface IPayerErrors { /// @notice Error thrown when removing a debtor has failed. error FailedToRemoveDebtor(); - /// @dev Error thrown when balance is insufficient. - error InsufficientBalance(); + /// @dev Error thrown when an address is invalid (usually zero address). + error InvalidAddress(); /// @dev Error thrown when the amount is insufficient. error InsufficientAmount(); - /// @dev Error thrown when an address is invalid (usually zero address). - error InvalidAddress(); + /// @dev Error thrown when balance is insufficient. + error InsufficientBalance(); + + /// @dev Error thrown when insufficient time has passed since the last fee transfer. + error InsufficientTimePassed(); /// @dev Error thrown when contract is not the distribution contract. error InvalidDistributionContract(); + /// @dev Error thrown when the maximum tolerable debt amount is invalid. + error InvalidMaxTolerableDebtAmount(); + /// @dev Error thrown when the minimum deposit is invalid. error InvalidMinimumDeposit(); @@ -125,6 +137,9 @@ interface IPayerErrors { /// @dev Error thrown when trying to backdate settlement too far. error InvalidSettlementTime(); + /// @dev Error thrown when the transfer fees period is invalid. + error InvalidTransferFeesPeriod(); + /// @dev Error thrown when contract is not the USDC token contract. error InvalidUsdcTokenContract(); @@ -376,6 +391,22 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { */ function setWithdrawalLockPeriod(uint32 newWithdrawalLockPeriod) external; + /** + * @notice Sets the maximum tolerable debt amount. + * @param newMaxTolerableDebtAmount The new maximum tolerable debt amount. + * + * Emits `MaxTolerableDebtAmountUpdated`. + */ + function setMaxTolerableDebtAmount(uint64 newMaxTolerableDebtAmount) external; + + /** + * @notice Sets the transfer fees period. + * @param newTransferFeesPeriod The new transfer fees period. + * + * Emits `TransferFeesPeriodUpdated`. + */ + function setTransferFeesPeriod(uint32 newTransferFeesPeriod) external; + /** * @notice Pauses the contract functions in case of emergency. * From 950b501deeea16aad1ec1f76d4e75f1977e78ed8 Mon Sep 17 00:00:00 2001 From: Borja Aranda Date: Fri, 14 Mar 2025 14:13:02 +0100 Subject: [PATCH 17/24] update ABIs --- contracts/pkg/groupmessages/GroupMessages.go | 78 +++++++++++++++++-- .../pkg/identityupdates/IdentityUpdates.go | 78 +++++++++++++++++-- contracts/pkg/nodes/Nodes.go | 51 +++++++++--- contracts/pkg/ratesmanager/RatesManager.go | 41 ++++++++-- 4 files changed, 217 insertions(+), 31 deletions(-) diff --git a/contracts/pkg/groupmessages/GroupMessages.go b/contracts/pkg/groupmessages/GroupMessages.go index cb5506ee..e911e762 100644 --- a/contracts/pkg/groupmessages/GroupMessages.go +++ b/contracts/pkg/groupmessages/GroupMessages.go @@ -31,8 +31,8 @@ var ( // GroupMessagesMetaData contains all meta data concerning the GroupMessages contract. var GroupMessagesMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"function\",\"name\":\"DEFAULT_ADMIN_ROLE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"UPGRADE_INTERFACE_VERSION\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"addMessage\",\"inputs\":[{\"name\":\"groupId\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"message\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"getRoleAdmin\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"grantRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"hasRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"admin\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"maxPayloadSize\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"minPayloadSize\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proxiableUUID\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"renounceRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"callerConfirmation\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"revokeRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setMaxPayloadSize\",\"inputs\":[{\"name\":\"maxPayloadSizeRequest\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setMinPayloadSize\",\"inputs\":[{\"name\":\"minPayloadSizeRequest\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"supportsInterface\",\"inputs\":[{\"name\":\"interfaceId\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"upgradeToAndCall\",\"inputs\":[{\"name\":\"newImplementation\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"MaxPayloadSizeUpdated\",\"inputs\":[{\"name\":\"oldSize\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newSize\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"MessageSent\",\"inputs\":[{\"name\":\"groupId\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"},{\"name\":\"message\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"},{\"name\":\"sequenceId\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"MinPayloadSizeUpdated\",\"inputs\":[{\"name\":\"oldSize\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newSize\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleAdminChanged\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"previousAdminRole\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"newAdminRole\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleGranted\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleRevoked\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UpgradeAuthorized\",\"inputs\":[{\"name\":\"upgrader\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"newImplementation\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Upgraded\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AccessControlBadConfirmation\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"AccessControlUnauthorizedAccount\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"neededRole\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"AddressEmptyCode\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC1967InvalidImplementation\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC1967NonPayable\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"EnforcedPause\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ExpectedPause\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FailedCall\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidInitialization\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidMaxPayloadSize\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidMinPayloadSize\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidPayloadSize\",\"inputs\":[{\"name\":\"actualSize\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"minSize\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"maxSize\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"NotInitializing\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UUPSUnauthorizedCallContext\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UUPSUnsupportedProxiableUUID\",\"inputs\":[{\"name\":\"slot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"ZeroAdminAddress\",\"inputs\":[]}]", - Bin: "0x60a0604052306080523480156012575f5ffd5b506080516119af6100395f395f8181610d9501528181610dbe01526110d101526119af5ff3fe60806040526004361061013d575f3560e01c806358e3e94c116100bb578063ad3cb1cc11610071578063d547741f11610057578063d547741f146103df578063f96927ac146103fe578063fe8e37a314610412575f5ffd5b8063ad3cb1cc1461036b578063c4d66de8146103c0575f5ffd5b80638456cb59116100a15780638456cb59146102d457806391d14854146102e8578063a217fddf14610358575f5ffd5b806358e3e94c146102895780635c975abb1461029e575f5ffd5b806336568abe116101105780634dff26b5116100f65780634dff26b5146102435780634f1ef2861461026257806352d1902d14610275575f5ffd5b806336568abe146102105780633f4ba83a1461022f575f5ffd5b806301ffc9a714610141578063248a9ca3146101755780632f2ff15d146101d0578063314a100e146101f1575b5f5ffd5b34801561014c575f5ffd5b5061016061015b36600461162d565b610431565b60405190151581526020015b60405180910390f35b348015610180575f5ffd5b506101c261018f36600461166c565b5f9081527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052604090206001015490565b60405190815260200161016c565b3480156101db575f5ffd5b506101ef6101ea3660046116ab565b6104c9565b005b3480156101fc575f5ffd5b506101ef61020b36600461166c565b610512565b34801561021b575f5ffd5b506101ef61022a3660046116ab565b6105d6565b34801561023a575f5ffd5b506101ef610634565b34801561024e575f5ffd5b506101ef61025d3660046116d5565b610649565b6101ef610270366004611779565b61072b565b348015610280575f5ffd5b506101c261074a565b348015610294575f5ffd5b506101c260015481565b3480156102a9575f5ffd5b507fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff16610160565b3480156102df575f5ffd5b506101ef610778565b3480156102f3575f5ffd5b506101606103023660046116ab565b5f9182527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020908152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b348015610363575f5ffd5b506101c25f81565b348015610376575f5ffd5b506103b36040518060400160405280600581526020017f352e302e3000000000000000000000000000000000000000000000000000000081525081565b60405161016c919061187a565b3480156103cb575f5ffd5b506101ef6103da3660046118cd565b61078a565b3480156103ea575f5ffd5b506101ef6103f93660046116ab565b61097c565b348015610409575f5ffd5b506101c25f5481565b34801561041d575f5ffd5b506101ef61042c36600461166c565b6109bf565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806104c357507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052604090206001015461050281610a7e565b61050c8383610a88565b50505050565b5f61051c81610a7e565b6001548210610557576040517fe219e4f000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8211610590576040517fe219e4f000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80549083905560408051828152602081018590527f1ee836faee0e7c61d20a079d0b5b4e1ee9c536e18268ef6f7c620dcec82f72cd91015b60405180910390a1505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610625576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61062f8282610ba6565b505050565b5f61063e81610a7e565b610646610c82565b50565b610651610d1f565b5f54811080159061066457506001548111155b5f5460015483926106b7576040517f93b7abe60000000000000000000000000000000000000000000000000000000081526004810193909352602483019190915260448201526064015b60405180910390fd5b50506002805467ffffffffffffffff808216600101167fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000090911681179091556040517f91f47151424884a46811ed593aa8a02ee5012e9332a4dcf1e9236a8ed4443c3e92506105c9918691869186916118e6565b610733610d7d565b61073c82610e81565b6107468282610f80565b5050565b5f6107536110b9565b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b5f61078281610a7e565b610646611128565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff165f811580156107d45750825b90505f8267ffffffffffffffff1660011480156107f05750303b155b9050811580156107fe575080155b15610835576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000016600117855583156108965784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b73ffffffffffffffffffffffffffffffffffffffff86166108e3576040517f3ef39b8100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108eb6111a1565b6108f36111a1565b6108fb6111a9565b604e5f908155624000006001556109129087610a88565b5083156109745784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260409020600101546109b581610a7e565b61050c8383610ba6565b5f6109c981610a7e565b5f548211610a03576040517f1d8e7a4a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b62400000821115610a40576040517f1d8e7a4a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180549083905560408051828152602081018590527ff59e99f8f54d2696b7cf184949ab2b4bbd6336ec1816b36f58ae9948d868fe9091016105c9565b61064681336111b9565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020818152604080842073ffffffffffffffffffffffffffffffffffffffff8616855290915282205460ff16610b9d575f8481526020828152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b393390565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a460019150506104c3565b5f9150506104c3565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020818152604080842073ffffffffffffffffffffffffffffffffffffffff8616855290915282205460ff1615610b9d575f8481526020828152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a460019150506104c3565b610c8a61125f565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a150565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff1615610d7b576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b3073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161480610e4a57507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16610e317f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614155b15610d7b576040517fe07c8dba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f610e8b81610a7e565b73ffffffffffffffffffffffffffffffffffffffff8216610f2e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f4e657720696d706c656d656e746174696f6e2063616e6e6f74206265207a657260448201527f6f2061646472657373000000000000000000000000000000000000000000000060648201526084016106ae565b6040805133815273ffffffffffffffffffffffffffffffffffffffff841660208201527fd30e1d298bf814ea43d22b4ce8298062b08609cd67496483769d836157dd52fa910160405180910390a15050565b8173ffffffffffffffffffffffffffffffffffffffff166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611005575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682019092526110029181019061194c565b60015b611053576040517f4c9c8ce300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff831660048201526024016106ae565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc81146110af576040517faa1d49a4000000000000000000000000000000000000000000000000000000008152600481018290526024016106ae565b61062f83836112ba565b3073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610d7b576040517fe07c8dba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611130610d1f565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833610cf4565b610d7b61131c565b6111b161131c565b610d7b611383565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610746576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602481018390526044016106ae565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff16610d7b576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112c3826113d4565b60405173ffffffffffffffffffffffffffffffffffffffff8316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a28051156113145761062f82826114a2565b610746611521565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff16610d7b576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61138b61131c565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b8073ffffffffffffffffffffffffffffffffffffffff163b5f0361143c576040517f4c9c8ce300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024016106ae565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60605f5f8473ffffffffffffffffffffffffffffffffffffffff16846040516114cb9190611963565b5f60405180830381855af49150503d805f8114611503576040519150601f19603f3d011682016040523d82523d5f602084013e611508565b606091505b5091509150611518858383611559565b95945050505050565b3415610d7b576040517fb398979f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608261156e57611569826115eb565b6115e4565b8151158015611592575073ffffffffffffffffffffffffffffffffffffffff84163b155b156115e1576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851660048201526024016106ae565b50805b9392505050565b8051156115fb5780518082602001fd5b6040517fd6bda27500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6020828403121561163d575f5ffd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146115e4575f5ffd5b5f6020828403121561167c575f5ffd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff811681146116a6575f5ffd5b919050565b5f5f604083850312156116bc575f5ffd5b823591506116cc60208401611683565b90509250929050565b5f5f5f604084860312156116e7575f5ffd5b83359250602084013567ffffffffffffffff811115611704575f5ffd5b8401601f81018613611714575f5ffd5b803567ffffffffffffffff81111561172a575f5ffd5b86602082840101111561173b575f5ffd5b939660209190910195509293505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f5f6040838503121561178a575f5ffd5b61179383611683565b9150602083013567ffffffffffffffff8111156117ae575f5ffd5b8301601f810185136117be575f5ffd5b803567ffffffffffffffff8111156117d8576117d861174c565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff821117156118445761184461174c565b60405281815282820160200187101561185b575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505092915050565b5f602082840312156118dd575f5ffd5b6115e482611683565b84815260606020820152826060820152828460808301375f608084830101525f60807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f860116830101905067ffffffffffffffff8316604083015295945050505050565b5f6020828403121561195c575f5ffd5b5051919050565b5f82518060208501845e5f92019182525091905056fea264697066735822122087b5a0bc224d473621249cc9c736454ff85aac664db9e21e42244bdd7c0d636f64736f6c634300081c0033", + ABI: "[{\"type\":\"function\",\"name\":\"ABSOLUTE_MAX_PAYLOAD_SIZE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"ABSOLUTE_MIN_PAYLOAD_SIZE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"DEFAULT_ADMIN_ROLE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"UPGRADE_INTERFACE_VERSION\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"addMessage\",\"inputs\":[{\"name\":\"groupId\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"message\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"getRoleAdmin\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"grantRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"hasRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"admin\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"maxPayloadSize\",\"inputs\":[],\"outputs\":[{\"name\":\"size\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"minPayloadSize\",\"inputs\":[],\"outputs\":[{\"name\":\"size\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proxiableUUID\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"renounceRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"callerConfirmation\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"revokeRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setMaxPayloadSize\",\"inputs\":[{\"name\":\"maxPayloadSizeRequest\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setMinPayloadSize\",\"inputs\":[{\"name\":\"minPayloadSizeRequest\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"supportsInterface\",\"inputs\":[{\"name\":\"interfaceId\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"upgradeToAndCall\",\"inputs\":[{\"name\":\"newImplementation\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"MaxPayloadSizeUpdated\",\"inputs\":[{\"name\":\"oldSize\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newSize\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"MessageSent\",\"inputs\":[{\"name\":\"groupId\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"},{\"name\":\"message\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"},{\"name\":\"sequenceId\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"MinPayloadSizeUpdated\",\"inputs\":[{\"name\":\"oldSize\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newSize\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleAdminChanged\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"previousAdminRole\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"newAdminRole\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleGranted\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleRevoked\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UpgradeAuthorized\",\"inputs\":[{\"name\":\"upgrader\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"newImplementation\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Upgraded\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AccessControlBadConfirmation\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"AccessControlUnauthorizedAccount\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"neededRole\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"AddressEmptyCode\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC1967InvalidImplementation\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC1967NonPayable\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"EnforcedPause\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ExpectedPause\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FailedCall\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidInitialization\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidMaxPayloadSize\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidMinPayloadSize\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidPayloadSize\",\"inputs\":[{\"name\":\"actualSize\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"minSize\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"maxSize\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"NotInitializing\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UUPSUnauthorizedCallContext\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UUPSUnsupportedProxiableUUID\",\"inputs\":[{\"name\":\"slot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"ZeroAdminAddress\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ZeroImplementationAddress\",\"inputs\":[]}]", + Bin: "0x60a0604052306080523480156012575f5ffd5b50608051611a4b6100395f395f8181610e8701528181610eb0015261116d0152611a4b5ff3fe608060405260043610610161575f3560e01c806352d1902d116100c6578063a217fddf1161007c578063d547741f11610057578063d547741f1461044b578063f96927ac1461046a578063fe8e37a31461049d575f5ffd5b8063a217fddf146103c4578063ad3cb1cc146103d7578063c4d66de81461042c575f5ffd5b80635c975abb116100ac5780635c975abb1461030a5780638456cb591461034057806391d1485414610354575f5ffd5b806352d1902d146102c357806358e3e94c146102d7575f5ffd5b8063314a100e1161011b5780633f4ba83a116101015780633f4ba83a1461027d5780634dff26b5146102915780634f1ef286146102b0575f5ffd5b8063314a100e1461023f57806336568abe1461025e575f5ffd5b80631de015991161014b5780631de01599146101bd578063248a9ca3146101d15780632f2ff15d1461021e575f5ffd5b806209e1271461016557806301ffc9a71461018e575b5f5ffd5b348015610170575f5ffd5b5061017b6240000081565b6040519081526020015b60405180910390f35b348015610199575f5ffd5b506101ad6101a83660046116c9565b6104bc565b6040519015158152602001610185565b3480156101c8575f5ffd5b5061017b604e81565b3480156101dc575f5ffd5b5061017b6101eb366004611708565b5f9081527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052604090206001015490565b348015610229575f5ffd5b5061023d610238366004611747565b610554565b005b34801561024a575f5ffd5b5061023d610259366004611708565b61059d565b348015610269575f5ffd5b5061023d610278366004611747565b610674565b348015610288575f5ffd5b5061023d6106d2565b34801561029c575f5ffd5b5061023d6102ab366004611771565b6106e7565b61023d6102be366004611815565b6107e9565b3480156102ce575f5ffd5b5061017b610808565b3480156102e2575f5ffd5b507f5d34bcd3bd75a3e15b8380222f0e4a5877bc3f258e24e1caa87a1298d2a610015461017b565b348015610315575f5ffd5b507fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff166101ad565b34801561034b575f5ffd5b5061023d610836565b34801561035f575f5ffd5b506101ad61036e366004611747565b5f9182527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020908152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b3480156103cf575f5ffd5b5061017b5f81565b3480156103e2575f5ffd5b5061041f6040518060400160405280600581526020017f352e302e3000000000000000000000000000000000000000000000000000000081525081565b6040516101859190611916565b348015610437575f5ffd5b5061023d610446366004611969565b610848565b348015610456575f5ffd5b5061023d610465366004611747565b610a7a565b348015610475575f5ffd5b507f5d34bcd3bd75a3e15b8380222f0e4a5877bc3f258e24e1caa87a1298d2a610005461017b565b3480156104a8575f5ffd5b5061023d6104b7366004611708565b610abd565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061054e57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052604090206001015461058d81610b70565b6105978383610b7a565b50505050565b5f6105a781610b70565b7f5d34bcd3bd75a3e15b8380222f0e4a5877bc3f258e24e1caa87a1298d2a61001547f5d34bcd3bd75a3e15b8380222f0e4a5877bc3f258e24e1caa87a1298d2a61000908311806105f85750604e83105b1561062f576040517fe219e4f000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805483825560408051828152602081018690527f1ee836faee0e7c61d20a079d0b5b4e1ee9c536e18268ef6f7c620dcec82f72cd91015b60405180910390a150505050565b73ffffffffffffffffffffffffffffffffffffffff811633146106c3576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6106cd8282610c98565b505050565b5f6106dc81610b70565b6106e4610d74565b50565b6106ef610e11565b7f5d34bcd3bd75a3e15b8380222f0e4a5877bc3f258e24e1caa87a1298d2a6100080548210806107225750600181015482115b1561077557805460018201546040517f93b7abe600000000000000000000000000000000000000000000000000000000815260048101859052602481019290925260448201526064015b60405180910390fd5b6002810180547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000008116600167ffffffffffffffff92831601918216179091556040517f91f47151424884a46811ed593aa8a02ee5012e9332a4dcf1e9236a8ed4443c3e916106669187918791879190611982565b6107f1610e6f565b6107fa82610f73565b610804828261101c565b5050565b5f610811611155565b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b5f61084081610b70565b6106e46111c4565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff165f811580156108925750825b90505f8267ffffffffffffffff1660011480156108ae5750303b155b9050811580156108bc575080155b156108f3576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000016600117855583156109545784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b73ffffffffffffffffffffffffffffffffffffffff86166109a1576040517f3ef39b8100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109a961123d565b6109b161123d565b6109b9611245565b604e7f5d34bcd3bd75a3e15b8380222f0e4a5877bc3f258e24e1caa87a1298d2a61000908155624000007f5d34bcd3bd75a3e15b8380222f0e4a5877bc3f258e24e1caa87a1298d2a6100155610a0f5f88610b7a565b50508315610a725784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020526040902060010154610ab381610b70565b6105978383610c98565b5f610ac781610b70565b7f5d34bcd3bd75a3e15b8380222f0e4a5877bc3f258e24e1caa87a1298d2a610008054831080610af957506240000083115b15610b30576040517f1d8e7a4a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001810180549084905560408051828152602081018690527ff59e99f8f54d2696b7cf184949ab2b4bbd6336ec1816b36f58ae9948d868fe909101610666565b6106e48133611255565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020818152604080842073ffffffffffffffffffffffffffffffffffffffff8616855290915282205460ff16610c8f575f8481526020828152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610c2b3390565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4600191505061054e565b5f91505061054e565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020818152604080842073ffffffffffffffffffffffffffffffffffffffff8616855290915282205460ff1615610c8f575f8481526020828152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4600191505061054e565b610d7c6112fb565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a150565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff1615610e6d576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b3073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161480610f3c57507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16610f237f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614155b15610e6d576040517fe07c8dba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f610f7d81610b70565b73ffffffffffffffffffffffffffffffffffffffff8216610fca576040517fd02c623d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805133815273ffffffffffffffffffffffffffffffffffffffff841660208201527fd30e1d298bf814ea43d22b4ce8298062b08609cd67496483769d836157dd52fa910160405180910390a15050565b8173ffffffffffffffffffffffffffffffffffffffff166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156110a1575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261109e918101906119e8565b60015b6110ef576040517f4c9c8ce300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8316600482015260240161076c565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc811461114b576040517faa1d49a40000000000000000000000000000000000000000000000000000000081526004810182905260240161076c565b6106cd8383611356565b3073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610e6d576040517fe07c8dba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111cc610e11565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833610de6565b610e6d6113b8565b61124d6113b8565b610e6d61141f565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610804576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024810183905260440161076c565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff16610e6d576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61135f82611470565b60405173ffffffffffffffffffffffffffffffffffffffff8316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a28051156113b0576106cd828261153e565b6108046115bd565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff16610e6d576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114276113b8565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b8073ffffffffffffffffffffffffffffffffffffffff163b5f036114d8576040517f4c9c8ce300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260240161076c565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60605f5f8473ffffffffffffffffffffffffffffffffffffffff168460405161156791906119ff565b5f60405180830381855af49150503d805f811461159f576040519150601f19603f3d011682016040523d82523d5f602084013e6115a4565b606091505b50915091506115b48583836115f5565b95945050505050565b3415610e6d576040517fb398979f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608261160a5761160582611687565b611680565b815115801561162e575073ffffffffffffffffffffffffffffffffffffffff84163b155b1561167d576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240161076c565b50805b9392505050565b8051156116975780518082602001fd5b6040517fd6bda27500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f602082840312156116d9575f5ffd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114611680575f5ffd5b5f60208284031215611718575f5ffd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611742575f5ffd5b919050565b5f5f60408385031215611758575f5ffd5b823591506117686020840161171f565b90509250929050565b5f5f5f60408486031215611783575f5ffd5b83359250602084013567ffffffffffffffff8111156117a0575f5ffd5b8401601f810186136117b0575f5ffd5b803567ffffffffffffffff8111156117c6575f5ffd5b8660208284010111156117d7575f5ffd5b939660209190910195509293505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f5f60408385031215611826575f5ffd5b61182f8361171f565b9150602083013567ffffffffffffffff81111561184a575f5ffd5b8301601f8101851361185a575f5ffd5b803567ffffffffffffffff811115611874576118746117e8565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff821117156118e0576118e06117e8565b6040528181528282016020018710156118f7575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505092915050565b5f60208284031215611979575f5ffd5b6116808261171f565b84815260606020820152826060820152828460808301375f608084830101525f60807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f860116830101905067ffffffffffffffff8316604083015295945050505050565b5f602082840312156119f8575f5ffd5b5051919050565b5f82518060208501845e5f92019182525091905056fea2646970667358221220a9d8450861b726977a199e2e96685ffa25c46d0cc14014015e81c1518113c59464736f6c634300081c0033", } // GroupMessagesABI is the input ABI used to generate the binding from. @@ -202,6 +202,68 @@ func (_GroupMessages *GroupMessagesTransactorRaw) Transact(opts *bind.TransactOp return _GroupMessages.Contract.contract.Transact(opts, method, params...) } +// ABSOLUTEMAXPAYLOADSIZE is a free data retrieval call binding the contract method 0x0009e127. +// +// Solidity: function ABSOLUTE_MAX_PAYLOAD_SIZE() view returns(uint256) +func (_GroupMessages *GroupMessagesCaller) ABSOLUTEMAXPAYLOADSIZE(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _GroupMessages.contract.Call(opts, &out, "ABSOLUTE_MAX_PAYLOAD_SIZE") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ABSOLUTEMAXPAYLOADSIZE is a free data retrieval call binding the contract method 0x0009e127. +// +// Solidity: function ABSOLUTE_MAX_PAYLOAD_SIZE() view returns(uint256) +func (_GroupMessages *GroupMessagesSession) ABSOLUTEMAXPAYLOADSIZE() (*big.Int, error) { + return _GroupMessages.Contract.ABSOLUTEMAXPAYLOADSIZE(&_GroupMessages.CallOpts) +} + +// ABSOLUTEMAXPAYLOADSIZE is a free data retrieval call binding the contract method 0x0009e127. +// +// Solidity: function ABSOLUTE_MAX_PAYLOAD_SIZE() view returns(uint256) +func (_GroupMessages *GroupMessagesCallerSession) ABSOLUTEMAXPAYLOADSIZE() (*big.Int, error) { + return _GroupMessages.Contract.ABSOLUTEMAXPAYLOADSIZE(&_GroupMessages.CallOpts) +} + +// ABSOLUTEMINPAYLOADSIZE is a free data retrieval call binding the contract method 0x1de01599. +// +// Solidity: function ABSOLUTE_MIN_PAYLOAD_SIZE() view returns(uint256) +func (_GroupMessages *GroupMessagesCaller) ABSOLUTEMINPAYLOADSIZE(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _GroupMessages.contract.Call(opts, &out, "ABSOLUTE_MIN_PAYLOAD_SIZE") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ABSOLUTEMINPAYLOADSIZE is a free data retrieval call binding the contract method 0x1de01599. +// +// Solidity: function ABSOLUTE_MIN_PAYLOAD_SIZE() view returns(uint256) +func (_GroupMessages *GroupMessagesSession) ABSOLUTEMINPAYLOADSIZE() (*big.Int, error) { + return _GroupMessages.Contract.ABSOLUTEMINPAYLOADSIZE(&_GroupMessages.CallOpts) +} + +// ABSOLUTEMINPAYLOADSIZE is a free data retrieval call binding the contract method 0x1de01599. +// +// Solidity: function ABSOLUTE_MIN_PAYLOAD_SIZE() view returns(uint256) +func (_GroupMessages *GroupMessagesCallerSession) ABSOLUTEMINPAYLOADSIZE() (*big.Int, error) { + return _GroupMessages.Contract.ABSOLUTEMINPAYLOADSIZE(&_GroupMessages.CallOpts) +} + // DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. // // Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) @@ -328,7 +390,7 @@ func (_GroupMessages *GroupMessagesCallerSession) HasRole(role [32]byte, account // MaxPayloadSize is a free data retrieval call binding the contract method 0x58e3e94c. // -// Solidity: function maxPayloadSize() view returns(uint256) +// Solidity: function maxPayloadSize() view returns(uint256 size) func (_GroupMessages *GroupMessagesCaller) MaxPayloadSize(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _GroupMessages.contract.Call(opts, &out, "maxPayloadSize") @@ -345,21 +407,21 @@ func (_GroupMessages *GroupMessagesCaller) MaxPayloadSize(opts *bind.CallOpts) ( // MaxPayloadSize is a free data retrieval call binding the contract method 0x58e3e94c. // -// Solidity: function maxPayloadSize() view returns(uint256) +// Solidity: function maxPayloadSize() view returns(uint256 size) func (_GroupMessages *GroupMessagesSession) MaxPayloadSize() (*big.Int, error) { return _GroupMessages.Contract.MaxPayloadSize(&_GroupMessages.CallOpts) } // MaxPayloadSize is a free data retrieval call binding the contract method 0x58e3e94c. // -// Solidity: function maxPayloadSize() view returns(uint256) +// Solidity: function maxPayloadSize() view returns(uint256 size) func (_GroupMessages *GroupMessagesCallerSession) MaxPayloadSize() (*big.Int, error) { return _GroupMessages.Contract.MaxPayloadSize(&_GroupMessages.CallOpts) } // MinPayloadSize is a free data retrieval call binding the contract method 0xf96927ac. // -// Solidity: function minPayloadSize() view returns(uint256) +// Solidity: function minPayloadSize() view returns(uint256 size) func (_GroupMessages *GroupMessagesCaller) MinPayloadSize(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _GroupMessages.contract.Call(opts, &out, "minPayloadSize") @@ -376,14 +438,14 @@ func (_GroupMessages *GroupMessagesCaller) MinPayloadSize(opts *bind.CallOpts) ( // MinPayloadSize is a free data retrieval call binding the contract method 0xf96927ac. // -// Solidity: function minPayloadSize() view returns(uint256) +// Solidity: function minPayloadSize() view returns(uint256 size) func (_GroupMessages *GroupMessagesSession) MinPayloadSize() (*big.Int, error) { return _GroupMessages.Contract.MinPayloadSize(&_GroupMessages.CallOpts) } // MinPayloadSize is a free data retrieval call binding the contract method 0xf96927ac. // -// Solidity: function minPayloadSize() view returns(uint256) +// Solidity: function minPayloadSize() view returns(uint256 size) func (_GroupMessages *GroupMessagesCallerSession) MinPayloadSize() (*big.Int, error) { return _GroupMessages.Contract.MinPayloadSize(&_GroupMessages.CallOpts) } diff --git a/contracts/pkg/identityupdates/IdentityUpdates.go b/contracts/pkg/identityupdates/IdentityUpdates.go index 179dd908..3c94366f 100644 --- a/contracts/pkg/identityupdates/IdentityUpdates.go +++ b/contracts/pkg/identityupdates/IdentityUpdates.go @@ -31,8 +31,8 @@ var ( // IdentityUpdatesMetaData contains all meta data concerning the IdentityUpdates contract. var IdentityUpdatesMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"function\",\"name\":\"DEFAULT_ADMIN_ROLE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"UPGRADE_INTERFACE_VERSION\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"addIdentityUpdate\",\"inputs\":[{\"name\":\"inboxId\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"update\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"getRoleAdmin\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"grantRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"hasRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"admin\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"maxPayloadSize\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"minPayloadSize\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proxiableUUID\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"renounceRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"callerConfirmation\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"revokeRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setMaxPayloadSize\",\"inputs\":[{\"name\":\"maxPayloadSizeRequest\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setMinPayloadSize\",\"inputs\":[{\"name\":\"minPayloadSizeRequest\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"supportsInterface\",\"inputs\":[{\"name\":\"interfaceId\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"upgradeToAndCall\",\"inputs\":[{\"name\":\"newImplementation\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"event\",\"name\":\"IdentityUpdateCreated\",\"inputs\":[{\"name\":\"inboxId\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"},{\"name\":\"update\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"},{\"name\":\"sequenceId\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"MaxPayloadSizeUpdated\",\"inputs\":[{\"name\":\"oldSize\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newSize\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"MinPayloadSizeUpdated\",\"inputs\":[{\"name\":\"oldSize\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newSize\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleAdminChanged\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"previousAdminRole\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"newAdminRole\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleGranted\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleRevoked\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UpgradeAuthorized\",\"inputs\":[{\"name\":\"upgrader\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"newImplementation\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Upgraded\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AccessControlBadConfirmation\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"AccessControlUnauthorizedAccount\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"neededRole\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"AddressEmptyCode\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC1967InvalidImplementation\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC1967NonPayable\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"EnforcedPause\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ExpectedPause\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FailedCall\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidInitialization\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidMaxPayloadSize\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidMinPayloadSize\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidPayloadSize\",\"inputs\":[{\"name\":\"actualSize\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"minSize\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"maxSize\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"NotInitializing\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UUPSUnauthorizedCallContext\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UUPSUnsupportedProxiableUUID\",\"inputs\":[{\"name\":\"slot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"ZeroAdminAddress\",\"inputs\":[]}]", - Bin: "0x60a0604052306080523480156012575f5ffd5b506080516119af6100395f395f8181610d3701528181610d60015261107501526119af5ff3fe60806040526004361061013d575f3560e01c80635c975abb116100bb578063ba74fc7c11610071578063d547741f11610057578063d547741f146103df578063f96927ac146103fe578063fe8e37a314610412575f5ffd5b8063ba74fc7c146103a1578063c4d66de8146103c0575f5ffd5b806391d14854116100a157806391d14854146102c9578063a217fddf14610339578063ad3cb1cc1461034c575f5ffd5b80635c975abb1461027f5780638456cb59146102b5575f5ffd5b806336568abe116101105780634f1ef286116100f65780634f1ef2861461024357806352d1902d1461025657806358e3e94c1461026a575f5ffd5b806336568abe146102105780633f4ba83a1461022f575f5ffd5b806301ffc9a714610141578063248a9ca3146101755780632f2ff15d146101d0578063314a100e146101f1575b5f5ffd5b34801561014c575f5ffd5b5061016061015b36600461162d565b610431565b60405190151581526020015b60405180910390f35b348015610180575f5ffd5b506101c261018f36600461166c565b5f9081527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052604090206001015490565b60405190815260200161016c565b3480156101db575f5ffd5b506101ef6101ea3660046116ab565b6104c9565b005b3480156101fc575f5ffd5b506101ef61020b36600461166c565b610512565b34801561021b575f5ffd5b506101ef61022a3660046116ab565b6105d6565b34801561023a575f5ffd5b506101ef610634565b6101ef610251366004611702565b610649565b348015610261575f5ffd5b506101c2610668565b348015610275575f5ffd5b506101c260015481565b34801561028a575f5ffd5b507fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff16610160565b3480156102c0575f5ffd5b506101ef610696565b3480156102d4575f5ffd5b506101606102e33660046116ab565b5f9182527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020908152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b348015610344575f5ffd5b506101c25f81565b348015610357575f5ffd5b506103946040518060400160405280600581526020017f352e302e3000000000000000000000000000000000000000000000000000000081525081565b60405161016c9190611803565b3480156103ac575f5ffd5b506101ef6103bb366004611856565b6106a8565b3480156103cb575f5ffd5b506101ef6103da3660046118cd565b61078a565b3480156103ea575f5ffd5b506101ef6103f93660046116ab565b61097c565b348015610409575f5ffd5b506101c25f5481565b34801561041d575f5ffd5b506101ef61042c36600461166c565b6109bf565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806104c357507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052604090206001015461050281610a7e565b61050c8383610a88565b50505050565b5f61051c81610a7e565b6001548210610557576040517fe219e4f000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8211610590576040517fe219e4f000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80549083905560408051828152602081018590527f1ee836faee0e7c61d20a079d0b5b4e1ee9c536e18268ef6f7c620dcec82f72cd91015b60405180910390a1505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610625576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61062f8282610ba6565b505050565b5f61063e81610a7e565b610646610c82565b50565b610651610d1f565b61065a82610e25565b6106648282610f24565b5050565b5f61067161105d565b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b5f6106a081610a7e565b6106466110cc565b6106b0611145565b5f5481108015906106c357506001548111155b5f546001548392610716576040517f93b7abe60000000000000000000000000000000000000000000000000000000081526004810193909352602483019190915260448201526064015b60405180910390fd5b50506002805467ffffffffffffffff808216600101167fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000090911681179091556040517fc1a40f292090ec0435e939cdfe248e0322a88566679a90a50c4e9e5ef762dbd592506105c9918691869186916118e6565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff165f811580156107d45750825b90505f8267ffffffffffffffff1660011480156107f05750303b155b9050811580156107fe575080155b15610835576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000016600117855583156108965784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b73ffffffffffffffffffffffffffffffffffffffff86166108e3576040517f3ef39b8100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108eb6111a1565b6108f36111a1565b6108fb6111a9565b60685f908155624000006001556109129087610a88565b5083156109745784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260409020600101546109b581610a7e565b61050c8383610ba6565b5f6109c981610a7e565b5f548211610a03576040517f1d8e7a4a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b62400000821115610a40576040517f1d8e7a4a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180549083905560408051828152602081018590527ff59e99f8f54d2696b7cf184949ab2b4bbd6336ec1816b36f58ae9948d868fe9091016105c9565b61064681336111b9565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020818152604080842073ffffffffffffffffffffffffffffffffffffffff8616855290915282205460ff16610b9d575f8481526020828152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610b393390565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a460019150506104c3565b5f9150506104c3565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020818152604080842073ffffffffffffffffffffffffffffffffffffffff8616855290915282205460ff1615610b9d575f8481526020828152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a460019150506104c3565b610c8a61125f565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a150565b3073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161480610dec57507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16610dd37f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614155b15610e23576040517fe07c8dba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b5f610e2f81610a7e565b73ffffffffffffffffffffffffffffffffffffffff8216610ed2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f4e657720696d706c656d656e746174696f6e2063616e6e6f74206265207a657260448201527f6f20616464726573730000000000000000000000000000000000000000000000606482015260840161070d565b6040805133815273ffffffffffffffffffffffffffffffffffffffff841660208201527fd30e1d298bf814ea43d22b4ce8298062b08609cd67496483769d836157dd52fa910160405180910390a15050565b8173ffffffffffffffffffffffffffffffffffffffff166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610fa9575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252610fa69181019061194c565b60015b610ff7576040517f4c9c8ce300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8316600482015260240161070d565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc8114611053576040517faa1d49a40000000000000000000000000000000000000000000000000000000081526004810182905260240161070d565b61062f83836112ba565b3073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610e23576040517fe07c8dba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110d4611145565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833610cf4565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff1615610e23576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610e2361131c565b6111b161131c565b610e23611383565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610664576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024810183905260440161070d565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff16610e23576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112c3826113d4565b60405173ffffffffffffffffffffffffffffffffffffffff8316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a28051156113145761062f82826114a2565b610664611521565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff16610e23576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61138b61131c565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b8073ffffffffffffffffffffffffffffffffffffffff163b5f0361143c576040517f4c9c8ce300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260240161070d565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60605f5f8473ffffffffffffffffffffffffffffffffffffffff16846040516114cb9190611963565b5f60405180830381855af49150503d805f8114611503576040519150601f19603f3d011682016040523d82523d5f602084013e611508565b606091505b5091509150611518858383611559565b95945050505050565b3415610e23576040517fb398979f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608261156e57611569826115eb565b6115e4565b8151158015611592575073ffffffffffffffffffffffffffffffffffffffff84163b155b156115e1576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240161070d565b50805b9392505050565b8051156115fb5780518082602001fd5b6040517fd6bda27500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6020828403121561163d575f5ffd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146115e4575f5ffd5b5f6020828403121561167c575f5ffd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff811681146116a6575f5ffd5b919050565b5f5f604083850312156116bc575f5ffd5b823591506116cc60208401611683565b90509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f5f60408385031215611713575f5ffd5b61171c83611683565b9150602083013567ffffffffffffffff811115611737575f5ffd5b8301601f81018513611747575f5ffd5b803567ffffffffffffffff811115611761576117616116d5565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff821117156117cd576117cd6116d5565b6040528181528282016020018710156117e4575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505092915050565b5f5f5f60408486031215611868575f5ffd5b83359250602084013567ffffffffffffffff811115611885575f5ffd5b8401601f81018613611895575f5ffd5b803567ffffffffffffffff8111156118ab575f5ffd5b8660208284010111156118bc575f5ffd5b939660209190910195509293505050565b5f602082840312156118dd575f5ffd5b6115e482611683565b84815260606020820152826060820152828460808301375f608084830101525f60807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f860116830101905067ffffffffffffffff8316604083015295945050505050565b5f6020828403121561195c575f5ffd5b5051919050565b5f82518060208501845e5f92019182525091905056fea2646970667358221220af11cb5a0ccc5bfc74bb2f3184ef3ca322cfc7db443c3d2d8f84b77f4a3b5f1e64736f6c634300081c0033", + ABI: "[{\"type\":\"function\",\"name\":\"ABSOLUTE_MAX_PAYLOAD_SIZE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"ABSOLUTE_MIN_PAYLOAD_SIZE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"DEFAULT_ADMIN_ROLE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"UPGRADE_INTERFACE_VERSION\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"addIdentityUpdate\",\"inputs\":[{\"name\":\"inboxId\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"update\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"getRoleAdmin\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"grantRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"hasRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"admin\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"maxPayloadSize\",\"inputs\":[],\"outputs\":[{\"name\":\"size\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"minPayloadSize\",\"inputs\":[],\"outputs\":[{\"name\":\"size\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proxiableUUID\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"renounceRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"callerConfirmation\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"revokeRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setMaxPayloadSize\",\"inputs\":[{\"name\":\"maxPayloadSizeRequest\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setMinPayloadSize\",\"inputs\":[{\"name\":\"minPayloadSizeRequest\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"supportsInterface\",\"inputs\":[{\"name\":\"interfaceId\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"upgradeToAndCall\",\"inputs\":[{\"name\":\"newImplementation\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"event\",\"name\":\"IdentityUpdateCreated\",\"inputs\":[{\"name\":\"inboxId\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"},{\"name\":\"update\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"},{\"name\":\"sequenceId\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"MaxPayloadSizeUpdated\",\"inputs\":[{\"name\":\"oldSize\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newSize\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"MinPayloadSizeUpdated\",\"inputs\":[{\"name\":\"oldSize\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"},{\"name\":\"newSize\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleAdminChanged\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"previousAdminRole\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"newAdminRole\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleGranted\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleRevoked\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UpgradeAuthorized\",\"inputs\":[{\"name\":\"upgrader\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"newImplementation\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Upgraded\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AccessControlBadConfirmation\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"AccessControlUnauthorizedAccount\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"neededRole\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"AddressEmptyCode\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC1967InvalidImplementation\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC1967NonPayable\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"EnforcedPause\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ExpectedPause\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FailedCall\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidInitialization\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidMaxPayloadSize\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidMinPayloadSize\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidPayloadSize\",\"inputs\":[{\"name\":\"actualSize\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"minSize\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"maxSize\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"NotInitializing\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UUPSUnauthorizedCallContext\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UUPSUnsupportedProxiableUUID\",\"inputs\":[{\"name\":\"slot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"ZeroAdminAddress\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ZeroImplementationAddress\",\"inputs\":[]}]", + Bin: "0x60a0604052306080523480156012575f5ffd5b50608051611a4b6100395f395f8181610e2901528181610e5201526111110152611a4b5ff3fe608060405260043610610161575f3560e01c806358e3e94c116100c6578063ad3cb1cc1161007c578063d547741f11610057578063d547741f1461044b578063f96927ac1461046a578063fe8e37a31461049d575f5ffd5b8063ad3cb1cc146103b8578063ba74fc7c1461040d578063c4d66de81461042c575f5ffd5b80638456cb59116100ac5780638456cb591461032157806391d1485414610335578063a217fddf146103a5575f5ffd5b806358e3e94c146102b85780635c975abb146102eb575f5ffd5b8063314a100e1161011b5780633f4ba83a116101015780633f4ba83a1461027d5780634f1ef2861461029157806352d1902d146102a4575f5ffd5b8063314a100e1461023f57806336568abe1461025e575f5ffd5b80631de015991161014b5780631de01599146101bd578063248a9ca3146101d15780632f2ff15d1461021e575f5ffd5b806209e1271461016557806301ffc9a71461018e575b5f5ffd5b348015610170575f5ffd5b5061017b6240000081565b6040519081526020015b60405180910390f35b348015610199575f5ffd5b506101ad6101a83660046116c9565b6104bc565b6040519015158152602001610185565b3480156101c8575f5ffd5b5061017b604e81565b3480156101dc575f5ffd5b5061017b6101eb366004611708565b5f9081527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052604090206001015490565b348015610229575f5ffd5b5061023d610238366004611747565b610554565b005b34801561024a575f5ffd5b5061023d610259366004611708565b61059d565b348015610269575f5ffd5b5061023d610278366004611747565b610674565b348015610288575f5ffd5b5061023d6106d2565b61023d61029f36600461179e565b6106e7565b3480156102af575f5ffd5b5061017b610706565b3480156102c3575f5ffd5b507f92f6d7b379434335724ccaa6ce32661f25de0b6cb746fac5f5edaed4b9685e015461017b565b3480156102f6575f5ffd5b507fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff166101ad565b34801561032c575f5ffd5b5061023d610734565b348015610340575f5ffd5b506101ad61034f366004611747565b5f9182527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020908152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b3480156103b0575f5ffd5b5061017b5f81565b3480156103c3575f5ffd5b506104006040518060400160405280600581526020017f352e302e3000000000000000000000000000000000000000000000000000000081525081565b604051610185919061189f565b348015610418575f5ffd5b5061023d6104273660046118f2565b610746565b348015610437575f5ffd5b5061023d610446366004611969565b610848565b348015610456575f5ffd5b5061023d610465366004611747565b610a7a565b348015610475575f5ffd5b507f92f6d7b379434335724ccaa6ce32661f25de0b6cb746fac5f5edaed4b9685e005461017b565b3480156104a8575f5ffd5b5061023d6104b7366004611708565b610abd565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061054e57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052604090206001015461058d81610b70565b6105978383610b7a565b50505050565b5f6105a781610b70565b7f92f6d7b379434335724ccaa6ce32661f25de0b6cb746fac5f5edaed4b9685e01547f92f6d7b379434335724ccaa6ce32661f25de0b6cb746fac5f5edaed4b9685e00908311806105f85750604e83105b1561062f576040517fe219e4f000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805483825560408051828152602081018690527f1ee836faee0e7c61d20a079d0b5b4e1ee9c536e18268ef6f7c620dcec82f72cd91015b60405180910390a150505050565b73ffffffffffffffffffffffffffffffffffffffff811633146106c3576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6106cd8282610c98565b505050565b5f6106dc81610b70565b6106e4610d74565b50565b6106ef610e11565b6106f882610f17565b6107028282610fc0565b5050565b5f61070f6110f9565b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b5f61073e81610b70565b6106e4611168565b61074e6111e1565b7f92f6d7b379434335724ccaa6ce32661f25de0b6cb746fac5f5edaed4b9685e0080548210806107815750600181015482115b156107d457805460018201546040517f93b7abe600000000000000000000000000000000000000000000000000000000815260048101859052602481019290925260448201526064015b60405180910390fd5b6002810180547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000008116600167ffffffffffffffff92831601918216179091556040517fc1a40f292090ec0435e939cdfe248e0322a88566679a90a50c4e9e5ef762dbd5916106669187918791879190611982565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff165f811580156108925750825b90505f8267ffffffffffffffff1660011480156108ae5750303b155b9050811580156108bc575080155b156108f3576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000016600117855583156109545784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b73ffffffffffffffffffffffffffffffffffffffff86166109a1576040517f3ef39b8100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109a961123d565b6109b161123d565b6109b9611245565b604e7f92f6d7b379434335724ccaa6ce32661f25de0b6cb746fac5f5edaed4b9685e00908155624000007f92f6d7b379434335724ccaa6ce32661f25de0b6cb746fac5f5edaed4b9685e0155610a0f5f88610b7a565b50508315610a725784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020526040902060010154610ab381610b70565b6105978383610c98565b5f610ac781610b70565b7f92f6d7b379434335724ccaa6ce32661f25de0b6cb746fac5f5edaed4b9685e008054831080610af957506240000083115b15610b30576040517f1d8e7a4a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001810180549084905560408051828152602081018690527ff59e99f8f54d2696b7cf184949ab2b4bbd6336ec1816b36f58ae9948d868fe909101610666565b6106e48133611255565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020818152604080842073ffffffffffffffffffffffffffffffffffffffff8616855290915282205460ff16610c8f575f8481526020828152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610c2b3390565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4600191505061054e565b5f91505061054e565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020818152604080842073ffffffffffffffffffffffffffffffffffffffff8616855290915282205460ff1615610c8f575f8481526020828152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4600191505061054e565b610d7c6112fb565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a150565b3073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161480610ede57507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16610ec57f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614155b15610f15576040517fe07c8dba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b5f610f2181610b70565b73ffffffffffffffffffffffffffffffffffffffff8216610f6e576040517fd02c623d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805133815273ffffffffffffffffffffffffffffffffffffffff841660208201527fd30e1d298bf814ea43d22b4ce8298062b08609cd67496483769d836157dd52fa910160405180910390a15050565b8173ffffffffffffffffffffffffffffffffffffffff166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611045575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252611042918101906119e8565b60015b611093576040517f4c9c8ce300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff831660048201526024016107cb565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc81146110ef576040517faa1d49a4000000000000000000000000000000000000000000000000000000008152600481018290526024016107cb565b6106cd8383611356565b3073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610f15576040517fe07c8dba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111706111e1565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833610de6565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff1615610f15576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610f156113b8565b61124d6113b8565b610f1561141f565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610702576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602481018390526044016107cb565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff16610f15576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61135f82611470565b60405173ffffffffffffffffffffffffffffffffffffffff8316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a28051156113b0576106cd828261153e565b6107026115bd565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff16610f15576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114276113b8565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b8073ffffffffffffffffffffffffffffffffffffffff163b5f036114d8576040517f4c9c8ce300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024016107cb565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60605f5f8473ffffffffffffffffffffffffffffffffffffffff168460405161156791906119ff565b5f60405180830381855af49150503d805f811461159f576040519150601f19603f3d011682016040523d82523d5f602084013e6115a4565b606091505b50915091506115b48583836115f5565b95945050505050565b3415610f15576040517fb398979f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608261160a5761160582611687565b611680565b815115801561162e575073ffffffffffffffffffffffffffffffffffffffff84163b155b1561167d576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851660048201526024016107cb565b50805b9392505050565b8051156116975780518082602001fd5b6040517fd6bda27500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f602082840312156116d9575f5ffd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114611680575f5ffd5b5f60208284031215611718575f5ffd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611742575f5ffd5b919050565b5f5f60408385031215611758575f5ffd5b823591506117686020840161171f565b90509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f5f604083850312156117af575f5ffd5b6117b88361171f565b9150602083013567ffffffffffffffff8111156117d3575f5ffd5b8301601f810185136117e3575f5ffd5b803567ffffffffffffffff8111156117fd576117fd611771565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff8211171561186957611869611771565b604052818152828201602001871015611880575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505092915050565b5f5f5f60408486031215611904575f5ffd5b83359250602084013567ffffffffffffffff811115611921575f5ffd5b8401601f81018613611931575f5ffd5b803567ffffffffffffffff811115611947575f5ffd5b866020828401011115611958575f5ffd5b939660209190910195509293505050565b5f60208284031215611979575f5ffd5b6116808261171f565b84815260606020820152826060820152828460808301375f608084830101525f60807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f860116830101905067ffffffffffffffff8316604083015295945050505050565b5f602082840312156119f8575f5ffd5b5051919050565b5f82518060208501845e5f92019182525091905056fea2646970667358221220b5506b42a917135f257e49614278b717d41bf0000fab0c76f537679c7498c8bc64736f6c634300081c0033", } // IdentityUpdatesABI is the input ABI used to generate the binding from. @@ -202,6 +202,68 @@ func (_IdentityUpdates *IdentityUpdatesTransactorRaw) Transact(opts *bind.Transa return _IdentityUpdates.Contract.contract.Transact(opts, method, params...) } +// ABSOLUTEMAXPAYLOADSIZE is a free data retrieval call binding the contract method 0x0009e127. +// +// Solidity: function ABSOLUTE_MAX_PAYLOAD_SIZE() view returns(uint256) +func (_IdentityUpdates *IdentityUpdatesCaller) ABSOLUTEMAXPAYLOADSIZE(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _IdentityUpdates.contract.Call(opts, &out, "ABSOLUTE_MAX_PAYLOAD_SIZE") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ABSOLUTEMAXPAYLOADSIZE is a free data retrieval call binding the contract method 0x0009e127. +// +// Solidity: function ABSOLUTE_MAX_PAYLOAD_SIZE() view returns(uint256) +func (_IdentityUpdates *IdentityUpdatesSession) ABSOLUTEMAXPAYLOADSIZE() (*big.Int, error) { + return _IdentityUpdates.Contract.ABSOLUTEMAXPAYLOADSIZE(&_IdentityUpdates.CallOpts) +} + +// ABSOLUTEMAXPAYLOADSIZE is a free data retrieval call binding the contract method 0x0009e127. +// +// Solidity: function ABSOLUTE_MAX_PAYLOAD_SIZE() view returns(uint256) +func (_IdentityUpdates *IdentityUpdatesCallerSession) ABSOLUTEMAXPAYLOADSIZE() (*big.Int, error) { + return _IdentityUpdates.Contract.ABSOLUTEMAXPAYLOADSIZE(&_IdentityUpdates.CallOpts) +} + +// ABSOLUTEMINPAYLOADSIZE is a free data retrieval call binding the contract method 0x1de01599. +// +// Solidity: function ABSOLUTE_MIN_PAYLOAD_SIZE() view returns(uint256) +func (_IdentityUpdates *IdentityUpdatesCaller) ABSOLUTEMINPAYLOADSIZE(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _IdentityUpdates.contract.Call(opts, &out, "ABSOLUTE_MIN_PAYLOAD_SIZE") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ABSOLUTEMINPAYLOADSIZE is a free data retrieval call binding the contract method 0x1de01599. +// +// Solidity: function ABSOLUTE_MIN_PAYLOAD_SIZE() view returns(uint256) +func (_IdentityUpdates *IdentityUpdatesSession) ABSOLUTEMINPAYLOADSIZE() (*big.Int, error) { + return _IdentityUpdates.Contract.ABSOLUTEMINPAYLOADSIZE(&_IdentityUpdates.CallOpts) +} + +// ABSOLUTEMINPAYLOADSIZE is a free data retrieval call binding the contract method 0x1de01599. +// +// Solidity: function ABSOLUTE_MIN_PAYLOAD_SIZE() view returns(uint256) +func (_IdentityUpdates *IdentityUpdatesCallerSession) ABSOLUTEMINPAYLOADSIZE() (*big.Int, error) { + return _IdentityUpdates.Contract.ABSOLUTEMINPAYLOADSIZE(&_IdentityUpdates.CallOpts) +} + // DEFAULTADMINROLE is a free data retrieval call binding the contract method 0xa217fddf. // // Solidity: function DEFAULT_ADMIN_ROLE() view returns(bytes32) @@ -328,7 +390,7 @@ func (_IdentityUpdates *IdentityUpdatesCallerSession) HasRole(role [32]byte, acc // MaxPayloadSize is a free data retrieval call binding the contract method 0x58e3e94c. // -// Solidity: function maxPayloadSize() view returns(uint256) +// Solidity: function maxPayloadSize() view returns(uint256 size) func (_IdentityUpdates *IdentityUpdatesCaller) MaxPayloadSize(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _IdentityUpdates.contract.Call(opts, &out, "maxPayloadSize") @@ -345,21 +407,21 @@ func (_IdentityUpdates *IdentityUpdatesCaller) MaxPayloadSize(opts *bind.CallOpt // MaxPayloadSize is a free data retrieval call binding the contract method 0x58e3e94c. // -// Solidity: function maxPayloadSize() view returns(uint256) +// Solidity: function maxPayloadSize() view returns(uint256 size) func (_IdentityUpdates *IdentityUpdatesSession) MaxPayloadSize() (*big.Int, error) { return _IdentityUpdates.Contract.MaxPayloadSize(&_IdentityUpdates.CallOpts) } // MaxPayloadSize is a free data retrieval call binding the contract method 0x58e3e94c. // -// Solidity: function maxPayloadSize() view returns(uint256) +// Solidity: function maxPayloadSize() view returns(uint256 size) func (_IdentityUpdates *IdentityUpdatesCallerSession) MaxPayloadSize() (*big.Int, error) { return _IdentityUpdates.Contract.MaxPayloadSize(&_IdentityUpdates.CallOpts) } // MinPayloadSize is a free data retrieval call binding the contract method 0xf96927ac. // -// Solidity: function minPayloadSize() view returns(uint256) +// Solidity: function minPayloadSize() view returns(uint256 size) func (_IdentityUpdates *IdentityUpdatesCaller) MinPayloadSize(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _IdentityUpdates.contract.Call(opts, &out, "minPayloadSize") @@ -376,14 +438,14 @@ func (_IdentityUpdates *IdentityUpdatesCaller) MinPayloadSize(opts *bind.CallOpt // MinPayloadSize is a free data retrieval call binding the contract method 0xf96927ac. // -// Solidity: function minPayloadSize() view returns(uint256) +// Solidity: function minPayloadSize() view returns(uint256 size) func (_IdentityUpdates *IdentityUpdatesSession) MinPayloadSize() (*big.Int, error) { return _IdentityUpdates.Contract.MinPayloadSize(&_IdentityUpdates.CallOpts) } // MinPayloadSize is a free data retrieval call binding the contract method 0xf96927ac. // -// Solidity: function minPayloadSize() view returns(uint256) +// Solidity: function minPayloadSize() view returns(uint256 size) func (_IdentityUpdates *IdentityUpdatesCallerSession) MinPayloadSize() (*big.Int, error) { return _IdentityUpdates.Contract.MinPayloadSize(&_IdentityUpdates.CallOpts) } diff --git a/contracts/pkg/nodes/Nodes.go b/contracts/pkg/nodes/Nodes.go index 38a36dfd..01e6e904 100644 --- a/contracts/pkg/nodes/Nodes.go +++ b/contracts/pkg/nodes/Nodes.go @@ -47,8 +47,8 @@ type INodesNodeWithId struct { // NodesMetaData contains all meta data concerning the Nodes contract. var NodesMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_initialAdmin\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"ADMIN_ROLE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"DEFAULT_ADMIN_ROLE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MAX_BPS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"NODE_MANAGER_ROLE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"acceptDefaultAdminTransfer\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"addNode\",\"inputs\":[{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"signingKeyPub\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"minMonthlyFeeMicroDollars\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"approve\",\"inputs\":[{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"balanceOf\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"beginDefaultAdminTransfer\",\"inputs\":[{\"name\":\"newAdmin\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"cancelDefaultAdminTransfer\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"changeDefaultAdminDelay\",\"inputs\":[{\"name\":\"newDelay\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"defaultAdmin\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"defaultAdminDelay\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"defaultAdminDelayIncreaseWait\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"disableNode\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"enableNode\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"getActiveApiNodes\",\"inputs\":[],\"outputs\":[{\"name\":\"activeNodes\",\"type\":\"tuple[]\",\"internalType\":\"structINodes.NodeWithId[]\",\"components\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"node\",\"type\":\"tuple\",\"internalType\":\"structINodes.Node\",\"components\":[{\"name\":\"signingKeyPub\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"isReplicationEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isApiEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isDisabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"minMonthlyFeeMicroDollars\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getActiveApiNodesCount\",\"inputs\":[],\"outputs\":[{\"name\":\"activeNodesCount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getActiveApiNodesIDs\",\"inputs\":[],\"outputs\":[{\"name\":\"activeNodesIDs\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getActiveReplicationNodes\",\"inputs\":[],\"outputs\":[{\"name\":\"activeNodes\",\"type\":\"tuple[]\",\"internalType\":\"structINodes.NodeWithId[]\",\"components\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"node\",\"type\":\"tuple\",\"internalType\":\"structINodes.Node\",\"components\":[{\"name\":\"signingKeyPub\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"isReplicationEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isApiEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isDisabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"minMonthlyFeeMicroDollars\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getActiveReplicationNodesCount\",\"inputs\":[],\"outputs\":[{\"name\":\"activeNodesCount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getActiveReplicationNodesIDs\",\"inputs\":[],\"outputs\":[{\"name\":\"activeNodesIDs\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getAllNodes\",\"inputs\":[],\"outputs\":[{\"name\":\"allNodes\",\"type\":\"tuple[]\",\"internalType\":\"structINodes.NodeWithId[]\",\"components\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"node\",\"type\":\"tuple\",\"internalType\":\"structINodes.Node\",\"components\":[{\"name\":\"signingKeyPub\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"isReplicationEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isApiEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isDisabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"minMonthlyFeeMicroDollars\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getAllNodesCount\",\"inputs\":[],\"outputs\":[{\"name\":\"nodeCount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getApiNodeIsActive\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"isActive\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getApproved\",\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getNode\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"node\",\"type\":\"tuple\",\"internalType\":\"structINodes.Node\",\"components\":[{\"name\":\"signingKeyPub\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"isReplicationEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isApiEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isDisabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"minMonthlyFeeMicroDollars\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getNodeOperatorCommissionPercent\",\"inputs\":[],\"outputs\":[{\"name\":\"commissionPercent\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getReplicationNodeIsActive\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"isActive\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRoleAdmin\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"grantRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"hasRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isApprovedForAll\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"maxActiveNodes\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"name\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"nodeOperatorCommissionPercent\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"ownerOf\",\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pendingDefaultAdmin\",\"inputs\":[],\"outputs\":[{\"name\":\"newAdmin\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"schedule\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pendingDefaultAdminDelay\",\"inputs\":[],\"outputs\":[{\"name\":\"newDelay\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"schedule\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"removeFromApiNodes\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"removeFromReplicationNodes\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"renounceRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"revokeRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"rollbackDefaultAdminDelay\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"safeTransferFrom\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"safeTransferFrom\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setApprovalForAll\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"approved\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setBaseURI\",\"inputs\":[{\"name\":\"newBaseURI\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setHttpAddress\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setIsApiEnabled\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"isApiEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setIsReplicationEnabled\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"isReplicationEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setMaxActiveNodes\",\"inputs\":[{\"name\":\"newMaxActiveNodes\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setMinMonthlyFee\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"minMonthlyFeeMicroDollars\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setNodeOperatorCommissionPercent\",\"inputs\":[{\"name\":\"newCommissionPercent\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"supportsInterface\",\"inputs\":[{\"name\":\"interfaceId\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"symbol\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"tokenURI\",\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"transferFrom\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"ApiDisabled\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ApiEnabled\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Approval\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"approved\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ApprovalForAll\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"approved\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"BaseURIUpdated\",\"inputs\":[{\"name\":\"newBaseURI\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DefaultAdminDelayChangeCanceled\",\"inputs\":[],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DefaultAdminDelayChangeScheduled\",\"inputs\":[{\"name\":\"newDelay\",\"type\":\"uint48\",\"indexed\":false,\"internalType\":\"uint48\"},{\"name\":\"effectSchedule\",\"type\":\"uint48\",\"indexed\":false,\"internalType\":\"uint48\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DefaultAdminTransferCanceled\",\"inputs\":[],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DefaultAdminTransferScheduled\",\"inputs\":[{\"name\":\"newAdmin\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"acceptSchedule\",\"type\":\"uint48\",\"indexed\":false,\"internalType\":\"uint48\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"HttpAddressUpdated\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"newHttpAddress\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"MaxActiveNodesUpdated\",\"inputs\":[{\"name\":\"newMaxActiveNodes\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"MinMonthlyFeeUpdated\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"minMonthlyFeeMicroDollars\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NodeAdded\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"owner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"signingKeyPub\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"},{\"name\":\"minMonthlyFeeMicroDollars\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NodeDisabled\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NodeEnabled\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NodeOperatorCommissionPercentUpdated\",\"inputs\":[{\"name\":\"newCommissionPercent\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NodeTransferred\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"from\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ReplicationDisabled\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ReplicationEnabled\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleAdminChanged\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"previousAdminRole\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"newAdminRole\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleGranted\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleRevoked\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Transfer\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AccessControlBadConfirmation\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"AccessControlEnforcedDefaultAdminDelay\",\"inputs\":[{\"name\":\"schedule\",\"type\":\"uint48\",\"internalType\":\"uint48\"}]},{\"type\":\"error\",\"name\":\"AccessControlEnforcedDefaultAdminRules\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"AccessControlInvalidDefaultAdmin\",\"inputs\":[{\"name\":\"defaultAdmin\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"AccessControlUnauthorizedAccount\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"neededRole\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"ERC721IncorrectOwner\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721InsufficientApproval\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"ERC721InvalidApprover\",\"inputs\":[{\"name\":\"approver\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721InvalidOperator\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721InvalidOwner\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721InvalidReceiver\",\"inputs\":[{\"name\":\"receiver\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721InvalidSender\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721NonexistentToken\",\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"InvalidAddress\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidCommissionPercent\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidHttpAddress\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidInputLength\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidNodeConfig\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidSigningKey\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidURI\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"MaxActiveNodesBelowCurrentCount\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"MaxActiveNodesReached\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NodeDoesNotExist\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NodeIsDisabled\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SafeCastOverflowedUintDowncast\",\"inputs\":[{\"name\":\"bits\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"value\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"Unauthorized\",\"inputs\":[]}]", - Bin: "0x6080604052600a805464ffffffffff19166014179055348015610020575f5ffd5b50604051614a17380380614a1783398101604081905261003f91610317565b60408051808201825260128152712c26aa28102737b2329027b832b930ba37b960711b602080830191909152825180840190935260048352630584d54560e41b90830152906202a300836001600160a01b0381166100b657604051636116401160e11b81525f600482015260240160405180910390fd5b600180546001600160d01b0316600160d01b65ffffffffffff8516021790556100df5f8261018b565b50600391506100f0905083826103dc565b5060046100fd82826103dc565b5050506001600160a01b0381166101275760405163e6c4247b60e01b815260040160405180910390fd5b61013e5f5160206149f75f395f51905f525f6101fa565b6101555f5160206149d75f395f51905f525f6101fa565b61016c5f5160206149f75f395f51905f528261018b565b506101845f5160206149d75f395f51905f528261018b565b5050610496565b5f826101e7575f6101a46002546001600160a01b031690565b6001600160a01b0316146101cb57604051631fe1e13d60e11b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0384161790555b6101f18383610226565b90505b92915050565b8161021857604051631fe1e13d60e11b815260040160405180910390fd5b61022282826102cd565b5050565b5f828152602081815260408083206001600160a01b038516845290915281205460ff166102c6575f838152602081815260408083206001600160a01b03861684529091529020805460ff1916600117905561027e3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016101f4565b505f6101f4565b5f82815260208190526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b5f60208284031215610327575f5ffd5b81516001600160a01b038116811461033d575f5ffd5b9392505050565b634e487b7160e01b5f52604160045260245ffd5b600181811c9082168061036c57607f821691505b60208210810361038a57634e487b7160e01b5f52602260045260245ffd5b50919050565b601f8211156103d757805f5260205f20601f840160051c810160208510156103b55750805b601f840160051c820191505b818110156103d4575f81556001016103c1565b50505b505050565b81516001600160401b038111156103f5576103f5610344565b610409816104038454610358565b84610390565b6020601f82116001811461043b575f83156104245750848201515b5f19600385901b1c1916600184901b1784556103d4565b5f84815260208120601f198516915b8281101561046a578785015182556020948501946001909201910161044a565b508482101561048757868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b614534806104a35f395ff3fe608060405234801561000f575f5ffd5b5060043610610388575f3560e01c80638da5cb5b116101df578063cc8463c811610109578063d74a2a50116100a9578063f3194a3911610079578063f3194a391461084c578063f579d7e114610855578063fb1120e21461085d578063fd967f4714610865575f5ffd5b8063d74a2a50146107e3578063e18cb254146107f6578063e985e9c514610809578063ebe487bf14610844575f5ffd5b8063cf6eefb7116100e4578063cf6eefb714610762578063d547741f146107a1578063d59f9fe0146107b4578063d602b9fd146107db575f5ffd5b8063cc8463c81461073f578063ce99948914610747578063cefc14291461075a575f5ffd5b8063a1eda53c1161017f578063b88d4fde1161014f578063b88d4fde146106fe578063b9b140d614610711578063c4741f3114610719578063c87b56dd1461072c575f5ffd5b8063a1eda53c146106aa578063a217fddf146106d1578063a22cb465146106d8578063a835f88e146106eb575f5ffd5b806391d14854116101ba57806391d148541461064557806395d89b411461067b5780639d32f9ba14610683578063a1174e7d146106a2575f5ffd5b80638da5cb5b146106155780638ed9ea341461061d5780638fbbf62314610630575f5ffd5b806342842e0e116102c0578063646453ba1161026057806375b238fc1161023057806375b238fc146105b757806379e0d58c146105de57806384ef8ffc146105f1578063895620b714610602575f5ffd5b8063646453ba14610569578063649a5ec71461057e5780636ec97bfc1461059157806370a08231146105a4575f5ffd5b806350d0215f1161029b57806350d0215f1461051d57806355f804b314610530578063634e93da146105435780636352211e14610556575f5ffd5b806342842e0e146104d757806344ff624e146104ea5780634f0f4aa9146104fd575f5ffd5b8063203ede771161032b578063248a9ca311610306578063248a9ca31461047c5780632f2ff15d1461049e57806336568abe146104b15780633d2853fb146104c4575f5ffd5b8063203ede771461044357806321fbd7cb1461045657806323b872dd14610469575f5ffd5b8063081812fc11610366578063081812fc146103e5578063095ea7b3146104105780630aa6220b1461042557806317e3b3a91461042d575f5ffd5b806301ffc9a71461038c578063022d63fb146103b457806306fdde03146103d0575b5f5ffd5b61039f61039a366004613afa565b61086e565b60405190151581526020015b60405180910390f35b620697805b60405165ffffffffffff90911681526020016103ab565b6103d861087e565b6040516103ab9190613b43565b6103f86103f3366004613b55565b61090e565b6040516001600160a01b0390911681526020016103ab565b61042361041e366004613b87565b610935565b005b610423610944565b610435610959565b6040519081526020016103ab565b610423610451366004613b55565b610969565b61039f610464366004613b55565b6109e9565b610423610477366004613baf565b6109f5565b61043561048a366004613b55565b5f9081526020819052604090206001015490565b6104236104ac366004613be9565b610a82565b6104236104bf366004613be9565b610ac3565b6104236104d2366004613b55565b610bb3565b6104236104e5366004613baf565b610c8b565b61039f6104f8366004613b55565b610caa565b61051061050b366004613b55565b610cb6565b6040516103ab9190613c7b565b600a54610100900463ffffffff16610435565b61042361053e366004613cd2565b610ea9565b610423610551366004613d11565b610fda565b6103f8610564366004613b55565b610fed565b610571610ff7565b6040516103ab9190613d2a565b61042361058c366004613d6c565b611003565b61043561059f366004613d91565b611016565b6104356105b2366004613d11565b61133a565b6104357fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177581565b6104236105ec366004613b55565b611398565b6002546001600160a01b03166103f8565b610423610610366004613e28565b611418565b6103f861151f565b61042361062b366004613e49565b611532565b610638611602565b6040516103ab9190613e69565b61039f610653366004613be9565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6103d8611873565b600a546106909060ff1681565b60405160ff90911681526020016103ab565b610638611882565b6106b2611b08565b6040805165ffffffffffff9384168152929091166020830152016103ab565b6104355f81565b6104236106e6366004613f01565b611b82565b6104236106f9366004613b55565b611b8d565b61042361070c366004613f56565b611c7f565b601054610435565b610423610727366004613b55565b611c9d565b6103d861073a366004613b55565b611d38565b6103b9611d9d565b610423610755366004614034565b611e3a565b610423611f05565b600154604080516001600160a01b03831681527401000000000000000000000000000000000000000090920465ffffffffffff166020830152016103ab565b6104236107af366004613be9565b611f54565b6104357fdaf9ac3a6308052428e8806fd908cf472318416ed7d78b3f35dd94bbbafde56a81565b610423611f95565b6104236107f1366004614054565b611fa7565b610423610804366004613e28565b6120b1565b61039f61081736600461409c565b6001600160a01b039182165f90815260086020908152604080832093909416825291909152205460ff1690565b6106386121b8565b61043560105481565b610435612425565b610571612430565b61043561271081565b5f6108788261243c565b92915050565b60606003805461088d906140c4565b80601f01602080910402602001604051908101604052809291908181526020018280546108b9906140c4565b80156109045780601f106108db57610100808354040283529160200191610904565b820191905f5260205f20905b8154815290600101906020018083116108e757829003601f168201915b5050505050905090565b5f610918826124dd565b505f828152600760205260409020546001600160a01b0316610878565b61094082823361252e565b5050565b5f61094e8161253b565b610956612545565b50565b5f610964600e612551565b905090565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217756109938161253b565b5f828152600560205260409020546001600160a01b03166109e0576040517f5e926f7100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109408261255a565b5f610878600c836125bc565b7fdaf9ac3a6308052428e8806fd908cf472318416ed7d78b3f35dd94bbbafde56a610a1f8161253b565b610a28826125d3565b610a318261255a565b610a3c848484612653565b826001600160a01b0316846001600160a01b0316837e80108bb11ee8badd8a48ff0b4585853d721b6e5ac7e3415f99413dac52be7260405160405180910390a450505050565b81610ab9576040517f3fc3c27a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109408282612708565b81158015610ade57506002546001600160a01b038281169116145b15610ba9576001546001600160a01b0381169074010000000000000000000000000000000000000000900465ffffffffffff1681151580610b25575065ffffffffffff8116155b80610b3857504265ffffffffffff821610155b15610b7e576040517f19ca5ebb00000000000000000000000000000000000000000000000000000000815265ffffffffffff821660048201526024015b60405180910390fd5b5050600180547fffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffff1690555b610940828261272c565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775610bdd8161253b565b5f828152600560205260409020546001600160a01b0316610c2a576040517f5e926f7100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f828152600b602052604080822060020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff1690555183917ff044a2d72ef98b7636ca9d9f8c0fc60e24309bbb8d472fdecbbaca55fe166d0a91a25050565b610ca583838360405180602001604052805f815250611c7f565b505050565b5f610878600e836125bc565b6040805160c081018252606080825260208083018290525f8385018190529183018290526080830182905260a083018290528482526005905291909120546001600160a01b0316610d33576040517f5e926f7100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f828152600b602052604090819020815160c08101909252805482908290610d5a906140c4565b80601f0160208091040260200160405190810160405280929190818152602001828054610d86906140c4565b8015610dd15780601f10610da857610100808354040283529160200191610dd1565b820191905f5260205f20905b815481529060010190602001808311610db457829003601f168201915b50505050508152602001600182018054610dea906140c4565b80601f0160208091040260200160405190810160405280929190818152602001828054610e16906140c4565b8015610e615780601f10610e3857610100808354040283529160200191610e61565b820191905f5260205f20905b815481529060010190602001808311610e4457829003601f168201915b5050509183525050600282015460ff80821615156020840152610100820481161515604084015262010000909104161515606082015260039091015460809091015292915050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775610ed38161253b565b81610f0a576040517f3ba0191100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8282610f17600182614142565b818110610f2657610f26614155565b9050013560f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916602f60f81b14610f8e576040517f3ba0191100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6009610f9b8385836141c6565b507f6741b2fc379fad678116fe3d4d4b9a1a184ab53ba36b86ad0fa66340b1ab41ad8383604051610fcd9291906142a9565b60405180910390a1505050565b5f610fe48161253b565b61094082612778565b5f610878826124dd565b6060610964600c6127ea565b5f61100d8161253b565b610940826127f6565b5f7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217756110418161253b565b6001600160a01b038816611081576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b856110b8576040517f8125403000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b836110ef576040517fcbd6898900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a8054610100900463ffffffff1690600161110a836142bc565b91906101000a81548163ffffffff021916908363ffffffff160217905550505f6064600a60019054906101000a900463ffffffff1661114991906142e0565b905061115b898263ffffffff1661285e565b6040518060c0016040528089898080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250505090825250604080516020601f8a01819004810282018101909252888152918101919089908990819084018382808284375f9201829052509385525050506020808301829052604080840183905260608401839052608090930188905263ffffffff85168252600b9052208151819061121290826142ff565b506020820151600182019061122790826142ff565b5060408281015160028301805460608601516080870151151562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff911515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff951515959095167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090931692909217939093179290921691909117905560a090920151600390910155516001600160a01b038a169063ffffffff8316907f663d98c1e2bdf874fcd4fadcdf16242719c434e099664a3eb574322b78bd7c5c90611320908c908c908c908c908c906143ba565b60405180910390a363ffffffff1698975050505050505050565b5f6001600160a01b03821661137d576040517f89c62b640000000000000000000000000000000000000000000000000000000081525f6004820152602401610b75565b506001600160a01b03165f9081526006602052604090205490565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217756113c28161253b565b5f828152600560205260409020546001600160a01b031661140f576040517f5e926f7100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610940826125d3565b5f8281526005602052604090205482906001600160a01b0316611467576040517f5e926f7100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f818152600b602052604090206002015462010000900460ff16156114b8576040517fc40c6f6300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f838152600560205260409020546001600160a01b03163314611507576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b811561151657610ca5836128f1565b610ca5836125d3565b5f6109646002546001600160a01b031690565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561155c8161253b565b611566600c612551565b8260ff161080611581575061157b600e612551565b8260ff16105b156115b8576040517f39beadee00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a805460ff191660ff84169081179091556040519081527f6dd6623df488fb2b38fa153b12758a1b41c8e49e88025f8d9fb1eba1b8f1d821906020015b60405180910390a15050565b606061160e600e612551565b67ffffffffffffffff81111561162657611626613f29565b60405190808252806020026020018201604052801561165f57816020015b61164c613a7c565b8152602001906001900390816116445790505b5090505f5b61166e600e612551565b8163ffffffff16101561186f575f611690600e63ffffffff808516906129bb16565b5f818152600560205260409020549091506001600160a01b03161561185c576040518060400160405280828152602001600b5f8481526020019081526020015f206040518060c00160405290815f820180546116eb906140c4565b80601f0160208091040260200160405190810160405280929190818152602001828054611717906140c4565b80156117625780601f1061173957610100808354040283529160200191611762565b820191905f5260205f20905b81548152906001019060200180831161174557829003601f168201915b5050505050815260200160018201805461177b906140c4565b80601f01602080910402602001604051908101604052809291908181526020018280546117a7906140c4565b80156117f25780601f106117c9576101008083540402835291602001916117f2565b820191905f5260205f20905b8154815290600101906020018083116117d557829003601f168201915b5050509183525050600282015460ff80821615156020840152610100820481161515604084015262010000909104161515606082015260039091015460809091015290528351849063ffffffff851690811061185057611850614155565b60200260200101819052505b5080611867816142bc565b915050611664565b5090565b60606004805461088d906140c4565b600a54606090610100900463ffffffff1667ffffffffffffffff8111156118ab576118ab613f29565b6040519080825280602002602001820160405280156118e457816020015b6118d1613a7c565b8152602001906001900390816118c95790505b5090505f5b600a5463ffffffff6101009091048116908216101561186f575f61190e8260016143f3565b6119199060646142e0565b90506119418163ffffffff165f908152600560205260409020546001600160a01b0316151590565b15611aff5760405180604001604052808263ffffffff168152602001600b5f8463ffffffff1681526020019081526020015f206040518060c00160405290815f8201805461198e906140c4565b80601f01602080910402602001604051908101604052809291908181526020018280546119ba906140c4565b8015611a055780601f106119dc57610100808354040283529160200191611a05565b820191905f5260205f20905b8154815290600101906020018083116119e857829003601f168201915b50505050508152602001600182018054611a1e906140c4565b80601f0160208091040260200160405190810160405280929190818152602001828054611a4a906140c4565b8015611a955780601f10611a6c57610100808354040283529160200191611a95565b820191905f5260205f20905b815481529060010190602001808311611a7857829003601f168201915b5050509183525050600282015460ff80821615156020840152610100820481161515604084015262010000909104161515606082015260039091015460809091015290528351849063ffffffff8516908110611af357611af3614155565b60200260200101819052505b506001016118e9565b6002545f907a010000000000000000000000000000000000000000000000000000900465ffffffffffff168015158015611b4a57504265ffffffffffff821610155b611b55575f5f611b7a565b60025474010000000000000000000000000000000000000000900465ffffffffffff16815b915091509091565b6109403383836129c6565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775611bb78161253b565b5f828152600560205260409020546001600160a01b0316611c04576040517f5e926f7100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f828152600b6020526040902060020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff1662010000179055611c48826125d3565b611c518261255a565b60405182907fa6c942fbe3ded4df132dc2c4adbb95359afebc3c361393a3d7217e3c310923e8905f90a25050565b611c8a8484846109f5565b611c973385858585612a7d565b50505050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775611cc78161253b565b612710821115611d03576040517f47d3b04600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60108290556040518281527f6367530104bc8677601bbb2f410055f5144865bf130b2c7bed1af5ff39185eb0906020016115f6565b6060611d43826124dd565b505f611d4d612c21565b90505f815111611d6b5760405180602001604052805f815250611d96565b80611d7584612c30565b604051602001611d86929190614426565b6040516020818303038152906040525b9392505050565b6002545f907a010000000000000000000000000000000000000000000000000000900465ffffffffffff168015158015611dde57504265ffffffffffff8216105b611e10576001547a010000000000000000000000000000000000000000000000000000900465ffffffffffff16611e34565b60025474010000000000000000000000000000000000000000900465ffffffffffff165b91505090565b7fdaf9ac3a6308052428e8806fd908cf472318416ed7d78b3f35dd94bbbafde56a611e648161253b565b5f838152600560205260409020546001600160a01b0316611eb1576040517f5e926f7100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f838152600b6020526040908190206003018390555183907f27a815a14bf8281048d2768dcd6b695fbd4e98af4e3fb52d92c8c65384320d4a90611ef89085815260200190565b60405180910390a2505050565b6001546001600160a01b0316338114611f4c576040517fc22c8022000000000000000000000000000000000000000000000000000000008152336004820152602401610b75565b610956612ccd565b81611f8b576040517f3fc3c27a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109408282612da4565b5f611f9f8161253b565b610956612dc8565b7fdaf9ac3a6308052428e8806fd908cf472318416ed7d78b3f35dd94bbbafde56a611fd18161253b565b5f848152600560205260409020546001600160a01b031661201e576040517f5e926f7100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81612055576040517fcbd6898900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f848152600b602052604090206001016120708385836141c6565b50837f15c3eac3b34037e402127abd35c3804f49d489c361f5bb8ff237544f0dfff4ed84846040516120a39291906142a9565b60405180910390a250505050565b5f8281526005602052604090205482906001600160a01b0316612100576040517f5e926f7100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f818152600b602052604090206002015462010000900460ff1615612151576040517fc40c6f6300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f838152600560205260409020546001600160a01b031633146121a0576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81156121af57610ca583612dd2565b610ca58361255a565b60606121c4600c612551565b67ffffffffffffffff8111156121dc576121dc613f29565b60405190808252806020026020018201604052801561221557816020015b612202613a7c565b8152602001906001900390816121fa5790505b5090505f5b612224600c612551565b8163ffffffff16101561186f575f612246600c63ffffffff808516906129bb16565b5f818152600560205260409020549091506001600160a01b031615612412576040518060400160405280828152602001600b5f8481526020019081526020015f206040518060c00160405290815f820180546122a1906140c4565b80601f01602080910402602001604051908101604052809291908181526020018280546122cd906140c4565b80156123185780601f106122ef57610100808354040283529160200191612318565b820191905f5260205f20905b8154815290600101906020018083116122fb57829003601f168201915b50505050508152602001600182018054612331906140c4565b80601f016020809104026020016040519081016040528092919081815260200182805461235d906140c4565b80156123a85780601f1061237f576101008083540402835291602001916123a8565b820191905f5260205f20905b81548152906001019060200180831161238b57829003601f168201915b5050509183525050600282015460ff80821615156020840152610100820481161515604084015262010000909104161515606082015260039091015460809091015290528351849063ffffffff851690811061240657612406614155565b60200260200101819052505b508061241d816142bc565b91505061221a565b5f610964600c612551565b6060610964600e6127ea565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f80ac58cd0000000000000000000000000000000000000000000000000000000014806124ce57507fffffffff0000000000000000000000000000000000000000000000000000000082167f5b5e139f00000000000000000000000000000000000000000000000000000000145b80610878575061087882612e7d565b5f818152600560205260408120546001600160a01b031680610878576040517f7e27328900000000000000000000000000000000000000000000000000000000815260048101849052602401610b75565b610ca58383836001612ed2565b6109568133613025565b61254f5f5f613090565b565b5f610878825490565b5f818152600b60205260409020600201805460ff1916905561257d600e826125bc565b1561258f5761258d600e826131dc565b505b60405181907fa9837328431beea294d22d476aeafca23f85f320de41750a9b9c3ce280761808905f90a250565b5f8181526001830160205260408120541515611d96565b5f818152600b6020526040902060020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055612614600c826125bc565b1561262657612624600c826131dc565b505b60405181907f9e61606f143f77c9ef06d68819ce159e3b98756d8eb558b91db82c8ca42357f3905f90a250565b6001600160a01b038216612695576040517f64a0ae920000000000000000000000000000000000000000000000000000000081525f6004820152602401610b75565b5f6126a18383336131e7565b9050836001600160a01b0316816001600160a01b031614611c97576040517f64283d7b0000000000000000000000000000000000000000000000000000000081526001600160a01b0380861660048301526024820184905282166044820152606401610b75565b5f828152602081905260409020600101546127228161253b565b611c9783836132f1565b6001600160a01b038116331461276e576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ca58282613388565b5f612781611d9d565b61278a426133dc565b612794919061443a565b90506127a08282613427565b60405165ffffffffffff821681526001600160a01b038316907f3377dc44241e779dd06afab5b788a35ca5f3b778836e2990bdb26a2a4b2e5ed69060200160405180910390a25050565b60605f611d96836134b5565b5f6128008261350e565b612809426133dc565b612813919061443a565b905061281f8282613090565b6040805165ffffffffffff8085168252831660208201527ff1038c18cf84a56e432fdbfaf746924b7ea511dfe03a6506a0ceba4888788d9b91016115f6565b6001600160a01b0382166128a0576040517f64a0ae920000000000000000000000000000000000000000000000000000000081525f6004820152602401610b75565b5f6128ac83835f6131e7565b90506001600160a01b03811615610ca5576040517f73c6ac6e0000000000000000000000000000000000000000000000000000000081525f6004820152602401610b75565b600a5460ff16612901600c612551565b10612938576040517f950be9a500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f818152600b6020526040902060020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010017905561297d600c826125bc565b61298e5761298c600c82613555565b505b60405181907f3cd0abf09f2e68bb82445a4d250b6a3e30b2b2c711b322e3f3817927a07da173905f90a250565b5f611d968383613560565b6001600160a01b038216612a11576040517f5b08ba180000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610b75565b6001600160a01b038381165f81815260086020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0383163b15612c1a576040517f150b7a020000000000000000000000000000000000000000000000000000000081526001600160a01b0384169063150b7a0290612ad8908890889087908790600401614458565b6020604051808303815f875af1925050508015612b12575060408051601f3d908101601f19168201909252612b0f91810190614498565b60015b612b92573d808015612b3f576040519150601f19603f3d011682016040523d82523d5f602084013e612b44565b606091505b5080515f03612b8a576040517f64a0ae920000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401610b75565b805181602001fd5b7fffffffff0000000000000000000000000000000000000000000000000000000081167f150b7a020000000000000000000000000000000000000000000000000000000014612c18576040517f64a0ae920000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401610b75565b505b5050505050565b60606009805461088d906140c4565b60605f612c3c83613586565b60010190505f8167ffffffffffffffff811115612c5b57612c5b613f29565b6040519080825280601f01601f191660200182016040528015612c85576020820181803683370190505b5090508181016020015b5f19017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8504945084612c8f57509392505050565b6001546001600160a01b0381169074010000000000000000000000000000000000000000900465ffffffffffff16801580612d1057504265ffffffffffff821610155b15612d51576040517f19ca5ebb00000000000000000000000000000000000000000000000000000000815265ffffffffffff82166004820152602401610b75565b612d6c5f612d676002546001600160a01b031690565b613388565b50612d775f836132f1565b5050600180547fffffffffffff000000000000000000000000000000000000000000000000000016905550565b5f82815260208190526040902060010154612dbe8161253b565b611c978383613388565b61254f5f5f613427565b600a5460ff16612de2600e612551565b10612e19576040517f950be9a500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f818152600b60205260409020600201805460ff19166001179055612e3f600e826125bc565b612e5057612e4e600e82613555565b505b60405181907fd9199c75487673396ebe8093e82e5cf7902ccfb90befe22763a8bc4c36b976d0905f90a250565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f31498786000000000000000000000000000000000000000000000000000000001480610878575061087882613667565b8080612ee657506001600160a01b03821615155b15612fde575f612ef5846124dd565b90506001600160a01b03831615801590612f215750826001600160a01b0316816001600160a01b031614155b8015612f5257506001600160a01b038082165f9081526008602090815260408083209387168352929052205460ff16155b15612f94576040517fa9fbf51f0000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401610b75565b8115612fdc5783856001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b50505f90815260076020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b5f828152602081815260408083206001600160a01b038516845290915290205460ff16610940576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401610b75565b6002547a010000000000000000000000000000000000000000000000000000900465ffffffffffff168015613164574265ffffffffffff8216101561313b576002546001805479ffffffffffffffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000090920465ffffffffffff167a01000000000000000000000000000000000000000000000000000002919091179055613164565b6040517f2b1fa2edafe6f7b9e97c1a9e0c3660e645beb2dcaa2d45bdbf9beaf5472e1ec5905f90a15b50600280546001600160a01b03167401000000000000000000000000000000000000000065ffffffffffff9485160279ffffffffffffffffffffffffffffffffffffffffffffffffffff16177a0100000000000000000000000000000000000000000000000000009290931691909102919091179055565b5f611d9683836136fd565b5f828152600560205260408120546001600160a01b0390811690831615613213576132138184866137e7565b6001600160a01b0381161561324d5761322e5f855f5f612ed2565b6001600160a01b0381165f90815260066020526040902080545f190190555b6001600160a01b0385161561327b576001600160a01b0385165f908152600660205260409020805460010190555b5f8481526005602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0389811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b5f8261337e575f61330a6002546001600160a01b031690565b6001600160a01b03161461334a576040517f3fc3c27a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0384161790555b611d96838361387d565b5f821580156133a457506002546001600160a01b038381169116145b156133d257600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555b611d968383613924565b5f65ffffffffffff82111561186f576040517f6dfcc6500000000000000000000000000000000000000000000000000000000081526030600482015260248101839052604401610b75565b600180547401000000000000000000000000000000000000000065ffffffffffff84811682027fffffffffffff000000000000000000000000000000000000000000000000000084166001600160a01b03881617179093559004168015610ca5576040517f8886ebfc4259abdbc16601dd8fb5678e54878f47b3c34836cfc51154a9605109905f90a1505050565b6060815f0180548060200260200160405190810160405280929190818152602001828054801561350257602002820191905f5260205f20905b8154815260200190600101908083116134ee575b50505050509050919050565b5f5f613518611d9d565b90508065ffffffffffff168365ffffffffffff16116135405761353b83826144b3565b611d96565b611d9665ffffffffffff8416620697806139a5565b5f611d9683836139b4565b5f825f01828154811061357557613575614155565b905f5260205f200154905092915050565b5f807a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000083106135ce577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef810000000083106135fa576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061361857662386f26fc10000830492506010015b6305f5e1008310613630576305f5e100830492506008015b612710831061364457612710830492506004015b60648310613656576064830492506002015b600a83106108785760010192915050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061087857507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610878565b5f81815260018301602052604081205480156137d7575f61371f600183614142565b85549091505f9061373290600190614142565b9050808214613791575f865f01828154811061375057613750614155565b905f5260205f200154905080875f01848154811061377057613770614155565b5f918252602080832090910192909255918252600188019052604090208390555b85548690806137a2576137a26144d1565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610878565b5f915050610878565b5092915050565b6137f28383836139f9565b610ca5576001600160a01b038316613839576040517f7e27328900000000000000000000000000000000000000000000000000000000815260048101829052602401610b75565b6040517f177e802f0000000000000000000000000000000000000000000000000000000081526001600160a01b038316600482015260248101829052604401610b75565b5f828152602081815260408083206001600160a01b038516845290915281205460ff1661391d575f838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556138d53390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610878565b505f610878565b5f828152602081815260408083206001600160a01b038516845290915281205460ff161561391d575f838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610878565b5f828218828410028218611d96565b5f81815260018301602052604081205461391d57508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610878565b5f6001600160a01b03831615801590613a745750826001600160a01b0316846001600160a01b03161480613a5157506001600160a01b038085165f9081526008602090815260408083209387168352929052205460ff165b80613a7457505f828152600760205260409020546001600160a01b038481169116145b949350505050565b60405180604001604052805f8152602001613ac86040518060c0016040528060608152602001606081526020015f151581526020015f151581526020015f151581526020015f81525090565b905290565b7fffffffff0000000000000000000000000000000000000000000000000000000081168114610956575f5ffd5b5f60208284031215613b0a575f5ffd5b8135611d9681613acd565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f611d966020830184613b15565b5f60208284031215613b65575f5ffd5b5035919050565b80356001600160a01b0381168114613b82575f5ffd5b919050565b5f5f60408385031215613b98575f5ffd5b613ba183613b6c565b946020939093013593505050565b5f5f5f60608486031215613bc1575f5ffd5b613bca84613b6c565b9250613bd860208501613b6c565b929592945050506040919091013590565b5f5f60408385031215613bfa575f5ffd5b82359150613c0a60208401613b6c565b90509250929050565b5f815160c08452613c2760c0850182613b15565b905060208301518482036020860152613c408282613b15565b91505060408301511515604085015260608301511515606085015260808301511515608085015260a083015160a08501528091505092915050565b602081525f611d966020830184613c13565b5f5f83601f840112613c9d575f5ffd5b50813567ffffffffffffffff811115613cb4575f5ffd5b602083019150836020828501011115613ccb575f5ffd5b9250929050565b5f5f60208385031215613ce3575f5ffd5b823567ffffffffffffffff811115613cf9575f5ffd5b613d0585828601613c8d565b90969095509350505050565b5f60208284031215613d21575f5ffd5b611d9682613b6c565b602080825282518282018190525f918401906040840190835b81811015613d61578351835260209384019390920191600101613d43565b509095945050505050565b5f60208284031215613d7c575f5ffd5b813565ffffffffffff81168114611d96575f5ffd5b5f5f5f5f5f5f60808789031215613da6575f5ffd5b613daf87613b6c565b9550602087013567ffffffffffffffff811115613dca575f5ffd5b613dd689828a01613c8d565b909650945050604087013567ffffffffffffffff811115613df5575f5ffd5b613e0189828a01613c8d565b979a9699509497949695606090950135949350505050565b80358015158114613b82575f5ffd5b5f5f60408385031215613e39575f5ffd5b82359150613c0a60208401613e19565b5f60208284031215613e59575f5ffd5b813560ff81168114611d96575f5ffd5b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b82811015613ef5577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08786030184528151805186526020810151905060406020870152613edf6040870182613c13565b9550506020938401939190910190600101613e8f565b50929695505050505050565b5f5f60408385031215613f12575f5ffd5b613f1b83613b6c565b9150613c0a60208401613e19565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f5f5f5f60808587031215613f69575f5ffd5b613f7285613b6c565b9350613f8060208601613b6c565b925060408501359150606085013567ffffffffffffffff811115613fa2575f5ffd5b8501601f81018713613fb2575f5ffd5b803567ffffffffffffffff811115613fcc57613fcc613f29565b604051601f19603f601f19601f8501160116810181811067ffffffffffffffff82111715613ffc57613ffc613f29565b604052818152828201602001891015614013575f5ffd5b816020840160208301375f6020838301015280935050505092959194509250565b5f5f60408385031215614045575f5ffd5b50508035926020909101359150565b5f5f5f60408486031215614066575f5ffd5b83359250602084013567ffffffffffffffff811115614083575f5ffd5b61408f86828701613c8d565b9497909650939450505050565b5f5f604083850312156140ad575f5ffd5b6140b683613b6c565b9150613c0a60208401613b6c565b600181811c908216806140d857607f821691505b60208210810361410f577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8181038181111561087857610878614115565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b601f821115610ca557805f5260205f20601f840160051c810160208510156141a75750805b601f840160051c820191505b81811015612c1a575f81556001016141b3565b67ffffffffffffffff8311156141de576141de613f29565b6141f2836141ec83546140c4565b83614182565b5f601f841160018114614223575f851561420c5750838201355b5f19600387901b1c1916600186901b178355612c1a565b5f83815260208120601f198716915b828110156142525786850135825560209485019460019092019101614232565b508682101561426e575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b81835281816020850137505f602082840101525f6020601f19601f840116840101905092915050565b602081525f613a74602083018486614280565b5f63ffffffff821663ffffffff81036142d7576142d7614115565b60010192915050565b63ffffffff81811683821602908116908181146137e0576137e0614115565b815167ffffffffffffffff81111561431957614319613f29565b61432d8161432784546140c4565b84614182565b6020601f82116001811461435f575f83156143485750848201515b5f19600385901b1c1916600184901b178455612c1a565b5f84815260208120601f198516915b8281101561438e578785015182556020948501946001909201910161436e565b50848210156143ab57868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b606081525f6143cd606083018789614280565b82810360208401526143e0818688614280565b9150508260408301529695505050505050565b63ffffffff818116838216019081111561087857610878614115565b5f81518060208401855e5f93019283525090919050565b5f613a74614434838661440f565b8461440f565b65ffffffffffff818116838216019081111561087857610878614115565b6001600160a01b03851681526001600160a01b0384166020820152826040820152608060608201525f61448e6080830184613b15565b9695505050505050565b5f602082840312156144a8575f5ffd5b8151611d9681613acd565b65ffffffffffff828116828216039081111561087857610878614115565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea26469706673582212201c8431a6b882e33541dc40f999b4c29d63754f93186ba0c1a2d01639468408ee64736f6c634300081c0033daf9ac3a6308052428e8806fd908cf472318416ed7d78b3f35dd94bbbafde56aa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775", + ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"initialAdmin\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"ADMIN_ROLE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"DEFAULT_ADMIN_ROLE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MAX_BPS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"NODE_INCREMENT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"NODE_MANAGER_ROLE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"acceptDefaultAdminTransfer\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"addNode\",\"inputs\":[{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"signingKeyPub\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"minMonthlyFeeMicroDollars\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"approve\",\"inputs\":[{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"balanceOf\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"beginDefaultAdminTransfer\",\"inputs\":[{\"name\":\"newAdmin\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"cancelDefaultAdminTransfer\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"changeDefaultAdminDelay\",\"inputs\":[{\"name\":\"newDelay\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"defaultAdmin\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"defaultAdminDelay\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"defaultAdminDelayIncreaseWait\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"disableNode\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"enableNode\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"getActiveApiNodes\",\"inputs\":[],\"outputs\":[{\"name\":\"activeNodes\",\"type\":\"tuple[]\",\"internalType\":\"structINodes.NodeWithId[]\",\"components\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"node\",\"type\":\"tuple\",\"internalType\":\"structINodes.Node\",\"components\":[{\"name\":\"signingKeyPub\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"isReplicationEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isApiEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isDisabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"minMonthlyFeeMicroDollars\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getActiveApiNodesCount\",\"inputs\":[],\"outputs\":[{\"name\":\"activeNodesCount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getActiveApiNodesIDs\",\"inputs\":[],\"outputs\":[{\"name\":\"activeNodesIDs\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getActiveReplicationNodes\",\"inputs\":[],\"outputs\":[{\"name\":\"activeNodes\",\"type\":\"tuple[]\",\"internalType\":\"structINodes.NodeWithId[]\",\"components\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"node\",\"type\":\"tuple\",\"internalType\":\"structINodes.Node\",\"components\":[{\"name\":\"signingKeyPub\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"isReplicationEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isApiEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isDisabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"minMonthlyFeeMicroDollars\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getActiveReplicationNodesCount\",\"inputs\":[],\"outputs\":[{\"name\":\"activeNodesCount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getActiveReplicationNodesIDs\",\"inputs\":[],\"outputs\":[{\"name\":\"activeNodesIDs\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getAllNodes\",\"inputs\":[],\"outputs\":[{\"name\":\"allNodes\",\"type\":\"tuple[]\",\"internalType\":\"structINodes.NodeWithId[]\",\"components\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"node\",\"type\":\"tuple\",\"internalType\":\"structINodes.Node\",\"components\":[{\"name\":\"signingKeyPub\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"isReplicationEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isApiEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isDisabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"minMonthlyFeeMicroDollars\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getAllNodesCount\",\"inputs\":[],\"outputs\":[{\"name\":\"nodeCount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getApiNodeIsActive\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"isActive\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getApproved\",\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getNode\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"node\",\"type\":\"tuple\",\"internalType\":\"structINodes.Node\",\"components\":[{\"name\":\"signingKeyPub\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"isReplicationEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isApiEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isDisabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"minMonthlyFeeMicroDollars\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getNodeOperatorCommissionPercent\",\"inputs\":[],\"outputs\":[{\"name\":\"commissionPercent\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getReplicationNodeIsActive\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"isActive\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRoleAdmin\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"grantRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"hasRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isApprovedForAll\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"maxActiveNodes\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"name\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"nodeOperatorCommissionPercent\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"ownerOf\",\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pendingDefaultAdmin\",\"inputs\":[],\"outputs\":[{\"name\":\"newAdmin\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"schedule\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pendingDefaultAdminDelay\",\"inputs\":[],\"outputs\":[{\"name\":\"newDelay\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"schedule\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"removeFromApiNodes\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"removeFromReplicationNodes\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"renounceRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"revokeRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"rollbackDefaultAdminDelay\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"safeTransferFrom\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"safeTransferFrom\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setApprovalForAll\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"approved\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setBaseURI\",\"inputs\":[{\"name\":\"newBaseURI\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setHttpAddress\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setIsApiEnabled\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"isApiEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setIsReplicationEnabled\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"isReplicationEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setMaxActiveNodes\",\"inputs\":[{\"name\":\"newMaxActiveNodes\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setMinMonthlyFee\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"minMonthlyFeeMicroDollars\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setNodeOperatorCommissionPercent\",\"inputs\":[{\"name\":\"newCommissionPercent\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"supportsInterface\",\"inputs\":[{\"name\":\"interfaceId\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"}],\"outputs\":[{\"name\":\"supported\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"symbol\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"tokenURI\",\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"transferFrom\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"ApiDisabled\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ApiEnabled\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Approval\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"approved\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ApprovalForAll\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"approved\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"BaseURIUpdated\",\"inputs\":[{\"name\":\"newBaseURI\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DefaultAdminDelayChangeCanceled\",\"inputs\":[],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DefaultAdminDelayChangeScheduled\",\"inputs\":[{\"name\":\"newDelay\",\"type\":\"uint48\",\"indexed\":false,\"internalType\":\"uint48\"},{\"name\":\"effectSchedule\",\"type\":\"uint48\",\"indexed\":false,\"internalType\":\"uint48\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DefaultAdminTransferCanceled\",\"inputs\":[],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DefaultAdminTransferScheduled\",\"inputs\":[{\"name\":\"newAdmin\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"acceptSchedule\",\"type\":\"uint48\",\"indexed\":false,\"internalType\":\"uint48\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"HttpAddressUpdated\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"newHttpAddress\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"MaxActiveNodesUpdated\",\"inputs\":[{\"name\":\"newMaxActiveNodes\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"MinMonthlyFeeUpdated\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"minMonthlyFeeMicroDollars\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NodeAdded\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"owner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"signingKeyPub\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"},{\"name\":\"minMonthlyFeeMicroDollars\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NodeDisabled\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NodeEnabled\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NodeOperatorCommissionPercentUpdated\",\"inputs\":[{\"name\":\"newCommissionPercent\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NodeTransferred\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"from\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ReplicationDisabled\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ReplicationEnabled\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleAdminChanged\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"previousAdminRole\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"newAdminRole\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleGranted\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleRevoked\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Transfer\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AccessControlBadConfirmation\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"AccessControlEnforcedDefaultAdminDelay\",\"inputs\":[{\"name\":\"schedule\",\"type\":\"uint48\",\"internalType\":\"uint48\"}]},{\"type\":\"error\",\"name\":\"AccessControlEnforcedDefaultAdminRules\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"AccessControlInvalidDefaultAdmin\",\"inputs\":[{\"name\":\"defaultAdmin\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"AccessControlUnauthorizedAccount\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"neededRole\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"ERC721IncorrectOwner\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721InsufficientApproval\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"ERC721InvalidApprover\",\"inputs\":[{\"name\":\"approver\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721InvalidOperator\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721InvalidOwner\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721InvalidReceiver\",\"inputs\":[{\"name\":\"receiver\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721InvalidSender\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721NonexistentToken\",\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"InvalidAddress\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidCommissionPercent\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidHttpAddress\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidInputLength\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidNodeConfig\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidSigningKey\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidURI\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"MaxActiveNodesBelowCurrentCount\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"MaxActiveNodesReached\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NodeDoesNotExist\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NodeIsDisabled\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SafeCastOverflowedUintDowncast\",\"inputs\":[{\"name\":\"bits\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"value\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"Unauthorized\",\"inputs\":[]}]", + Bin: "0x6080604052600a805464ffffffffff19166014179055348015610020575f5ffd5b506040516146eb3803806146eb83398101604081905261003f91610317565b60408051808201825260128152712c26aa28102737b2329027b832b930ba37b960711b602080830191909152825180840190935260048352630584d54560e41b90830152906202a300836001600160a01b0381166100b657604051636116401160e11b81525f600482015260240160405180910390fd5b600180546001600160d01b0316600160d01b65ffffffffffff8516021790556100df5f8261018b565b50600391506100f0905083826103dc565b5060046100fd82826103dc565b5050506001600160a01b0381166101275760405163e6c4247b60e01b815260040160405180910390fd5b61013e5f5160206146cb5f395f51905f525f6101fa565b6101555f5160206146ab5f395f51905f525f6101fa565b61016c5f5160206146cb5f395f51905f528261018b565b506101845f5160206146ab5f395f51905f528261018b565b5050610496565b5f826101e7575f6101a46002546001600160a01b031690565b6001600160a01b0316146101cb57604051631fe1e13d60e11b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0384161790555b6101f18383610226565b90505b92915050565b8161021857604051631fe1e13d60e11b815260040160405180910390fd5b61022282826102cd565b5050565b5f828152602081815260408083206001600160a01b038516845290915281205460ff166102c6575f838152602081815260408083206001600160a01b03861684529091529020805460ff1916600117905561027e3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016101f4565b505f6101f4565b5f82815260208190526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b5f60208284031215610327575f5ffd5b81516001600160a01b038116811461033d575f5ffd5b9392505050565b634e487b7160e01b5f52604160045260245ffd5b600181811c9082168061036c57607f821691505b60208210810361038a57634e487b7160e01b5f52602260045260245ffd5b50919050565b601f8211156103d757805f5260205f20601f840160051c810160208510156103b55750805b601f840160051c820191505b818110156103d4575f81556001016103c1565b50505b505050565b81516001600160401b038111156103f5576103f5610344565b610409816104038454610358565b84610390565b6020601f82116001811461043b575f83156104245750848201515b5f19600385901b1c1916600184901b1784556103d4565b5f84815260208120601f198516915b8281101561046a578785015182556020948501946001909201910161044a565b508482101561048757868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b614208806104a35f395ff3fe608060405234801561000f575f5ffd5b5060043610610393575f3560e01c80638ed9ea34116101df578063ce99948911610109578063e18cb254116100a9578063f579d7e111610079578063f579d7e114610860578063fb1120e214610868578063fd667d1e14610870578063fd967f471461088d575f5ffd5b8063e18cb25414610801578063e985e9c514610814578063ebe487bf1461084f578063f3194a3914610857575f5ffd5b8063d547741f116100e4578063d547741f146107ac578063d59f9fe0146107bf578063d602b9fd146107e6578063d74a2a50146107ee575f5ffd5b8063ce99948914610752578063cefc142914610765578063cf6eefb71461076d575f5ffd5b8063a217fddf1161017f578063b9b140d61161014f578063b9b140d61461071c578063c4741f3114610724578063c87b56dd14610737578063cc8463c81461074a575f5ffd5b8063a217fddf146106dc578063a22cb465146106e3578063a835f88e146106f6578063b88d4fde14610709575f5ffd5b806395d89b41116101ba57806395d89b41146106865780639d32f9ba1461068e578063a1174e7d146106ad578063a1eda53c146106b5575f5ffd5b80638ed9ea34146106285780638fbbf6231461063b57806391d1485414610650575f5ffd5b806344ff624e116102c0578063649a5ec71161026057806379e0d58c1161023057806379e0d58c146105e957806384ef8ffc146105fc578063895620b71461060d5780638da5cb5b14610620575f5ffd5b8063649a5ec7146105895780636ec97bfc1461059c57806370a08231146105af57806375b238fc146105c2575f5ffd5b806355f804b31161029b57806355f804b31461053b578063634e93da1461054e5780636352211e14610561578063646453ba14610574575f5ffd5b806344ff624e146104f55780634f0f4aa91461050857806350d0215f14610528575f5ffd5b8063203ede77116103365780632f2ff15d116103065780632f2ff15d146104a957806336568abe146104bc5780633d2853fb146104cf57806342842e0e146104e2575f5ffd5b8063203ede771461044e57806321fbd7cb1461046157806323b872dd14610474578063248a9ca314610487575f5ffd5b8063081812fc11610371578063081812fc146103f0578063095ea7b31461041b5780630aa6220b1461043057806317e3b3a914610438575f5ffd5b806301ffc9a714610397578063022d63fb146103bf57806306fdde03146103db575b5f5ffd5b6103aa6103a53660046137ce565b610896565b60405190151581526020015b60405180910390f35b620697805b60405165ffffffffffff90911681526020016103b6565b6103e36108a6565b6040516103b69190613817565b6104036103fe366004613829565b610936565b6040516001600160a01b0390911681526020016103b6565b61042e61042936600461385b565b61095d565b005b61042e61096c565b610440610981565b6040519081526020016103b6565b61042e61045c366004613829565b610991565b6103aa61046f366004613829565b6109cd565b61042e610482366004613883565b6109d9565b610440610495366004613829565b5f9081526020819052604090206001015490565b61042e6104b73660046138bd565b610a66565b61042e6104ca3660046138bd565b610aa7565b61042e6104dd366004613829565b610b97565b61042e6104f0366004613883565b610c2b565b6103aa610503366004613829565b610c4a565b61051b610516366004613829565b610c56565b6040516103b6919061394f565b600a54610100900463ffffffff16610440565b61042e6105493660046139a6565b610e06565b61042e61055c3660046139e5565b610f53565b61040361056f366004613829565b610f66565b61057c610f70565b6040516103b691906139fe565b61042e610597366004613a40565b610f7c565b6104406105aa366004613a65565b610f8f565b6104406105bd3660046139e5565b61128b565b6104407fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177581565b61042e6105f7366004613829565b6112e9565b6002546001600160a01b0316610403565b61042e61061b366004613afc565b611325565b61040361134f565b61042e610636366004613b1d565b611362565b610643611432565b6040516103b69190613b3d565b6103aa61065e3660046138bd565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6103e3611684565b600a5461069b9060ff1681565b60405160ff90911681526020016103b6565b610643611693565b6106bd6118ed565b6040805165ffffffffffff9384168152929091166020830152016103b6565b6104405f81565b61042e6106f1366004613bd5565b611967565b61042e610704366004613829565b611972565b61042e610717366004613c2a565b611a20565b601054610440565b61042e610732366004613829565b611a3e565b6103e3610745366004613829565b611ad9565b6103c4611b3e565b61042e610760366004613d08565b611bdb565b61042e611c62565b600154604080516001600160a01b03831681527401000000000000000000000000000000000000000090920465ffffffffffff166020830152016103b6565b61042e6107ba3660046138bd565b611cb1565b6104407fdaf9ac3a6308052428e8806fd908cf472318416ed7d78b3f35dd94bbbafde56a81565b61042e611cf2565b61042e6107fc366004613d28565b611d04565b61042e61080f366004613afc565b611dca565b6103aa610822366004613d70565b6001600160a01b039182165f90815260086020908152604080832093909416825291909152205460ff1690565b610643611df4565b61044060105481565b610440612042565b61057c61204d565b610878606481565b60405163ffffffff90911681526020016103b6565b61044061271081565b5f6108a082612059565b92915050565b6060600380546108b590613d98565b80601f01602080910402602001604051908101604052809291908181526020018280546108e190613d98565b801561092c5780601f106109035761010080835404028352916020019161092c565b820191905f5260205f20905b81548152906001019060200180831161090f57829003601f168201915b5050505050905090565b5f610940826120fa565b505f828152600760205260409020546001600160a01b03166108a0565b61096882823361214b565b5050565b5f61097681612158565b61097e612162565b50565b5f61098c600e61216e565b905090565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217756109bb81612158565b6109c482612177565b610968826121c4565b5f6108a0600c83612218565b7fdaf9ac3a6308052428e8806fd908cf472318416ed7d78b3f35dd94bbbafde56a610a0381612158565b610a0c8261222f565b610a15826121c4565b610a208484846122a1565b826001600160a01b0316846001600160a01b0316837e80108bb11ee8badd8a48ff0b4585853d721b6e5ac7e3415f99413dac52be7260405160405180910390a450505050565b81610a9d576040517f3fc3c27a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109688282612356565b81158015610ac257506002546001600160a01b038281169116145b15610b8d576001546001600160a01b0381169074010000000000000000000000000000000000000000900465ffffffffffff1681151580610b09575065ffffffffffff8116155b80610b1c57504265ffffffffffff821610155b15610b62576040517f19ca5ebb00000000000000000000000000000000000000000000000000000000815265ffffffffffff821660048201526024015b60405180910390fd5b5050600180547fffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffff1690555b610968828261237a565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775610bc181612158565b610bca82612177565b5f828152600b602052604080822060020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff1690555183917ff044a2d72ef98b7636ca9d9f8c0fc60e24309bbb8d472fdecbbaca55fe166d0a91a25050565b610c4583838360405180602001604052805f815250611a20565b505050565b5f6108a0600e83612218565b6040805160c0810182526060808252602082018190525f92820183905281018290526080810182905260a0810191909152610c9082612177565b5f828152600b602052604090819020815160c08101909252805482908290610cb790613d98565b80601f0160208091040260200160405190810160405280929190818152602001828054610ce390613d98565b8015610d2e5780601f10610d0557610100808354040283529160200191610d2e565b820191905f5260205f20905b815481529060010190602001808311610d1157829003601f168201915b50505050508152602001600182018054610d4790613d98565b80601f0160208091040260200160405190810160405280929190818152602001828054610d7390613d98565b8015610dbe5780601f10610d9557610100808354040283529160200191610dbe565b820191905f5260205f20905b815481529060010190602001808311610da157829003601f168201915b5050509183525050600282015460ff80821615156020840152610100820481161515604084015262010000909104161515606082015260039091015460809091015292915050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775610e3081612158565b81610e67576040517f3ba0191100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f2f000000000000000000000000000000000000000000000000000000000000008383610e95600182613e16565b818110610ea457610ea4613e29565b9050013560f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614610f07576040517f3ba0191100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6009610f14838583613e9a565b507f6741b2fc379fad678116fe3d4d4b9a1a184ab53ba36b86ad0fa66340b1ab41ad8383604051610f46929190613f7d565b60405180910390a1505050565b5f610f5d81612158565b610968826123c6565b5f6108a0826120fa565b606061098c600c612438565b5f610f8681612158565b61096882612444565b5f7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775610fba81612158565b6001600160a01b038816610ffa576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b85611031576040517f8125403000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83611068576040517fcbd6898900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6064600a600181819054906101000a900463ffffffff1661108890613f90565b91906101000a81548163ffffffff021916908363ffffffff16021790556110af9190613fb4565b63ffffffff1691506040518060c0016040528088888080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250505090825250604080516020601f8901819004810282018101909252878152918101919088908890819084018382808284375f92018290525093855250505060208083018290526040808401839052606084018390526080909301879052858252600b905220815181906111689082613fd3565b506020820151600182019061117d9082613fd3565b50604082015160028201805460608501516080860151151562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff911515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff951515959095167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090931692909217939093179290921691909117905560a09091015160039091015561123688836124ac565b876001600160a01b0316827f663d98c1e2bdf874fcd4fadcdf16242719c434e099664a3eb574322b78bd7c5c898989898960405161127895949392919061408e565b60405180910390a3509695505050505050565b5f6001600160a01b0382166112ce576040517f89c62b640000000000000000000000000000000000000000000000000000000081525f6004820152602401610b59565b506001600160a01b03165f9081526006602052604090205490565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561131381612158565b61131c82612177565b6109688261222f565b61132e82612177565b6113378261253f565b61134082612590565b801561131c57610968826125df565b5f61098c6002546001600160a01b031690565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561138c81612158565b611396600c61216e565b8260ff1610806113b157506113ab600e61216e565b8260ff16105b156113e8576040517f39beadee00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a805460ff191660ff84169081179091556040519081527f6dd6623df488fb2b38fa153b12758a1b41c8e49e88025f8d9fb1eba1b8f1d821906020015b60405180910390a15050565b606061143e600e61216e565b67ffffffffffffffff81111561145657611456613bfd565b60405190808252806020026020018201604052801561148f57816020015b61147c613750565b8152602001906001900390816114745790505b5090505f5b61149e600e61216e565b8163ffffffff161015611680575f6114c0600e63ffffffff8085169061269c16565b90506040518060400160405280828152602001600b5f8481526020019081526020015f206040518060c00160405290815f820180546114fe90613d98565b80601f016020809104026020016040519081016040528092919081815260200182805461152a90613d98565b80156115755780601f1061154c57610100808354040283529160200191611575565b820191905f5260205f20905b81548152906001019060200180831161155857829003601f168201915b5050505050815260200160018201805461158e90613d98565b80601f01602080910402602001604051908101604052809291908181526020018280546115ba90613d98565b80156116055780601f106115dc57610100808354040283529160200191611605565b820191905f5260205f20905b8154815290600101906020018083116115e857829003601f168201915b5050509183525050600282015460ff80821615156020840152610100820481161515604084015262010000909104161515606082015260039091015460809091015290528351849063ffffffff851690811061166357611663613e29565b6020026020010181905250508061167990613f90565b9050611494565b5090565b6060600480546108b590613d98565b600a54606090610100900463ffffffff1667ffffffffffffffff8111156116bc576116bc613bfd565b6040519080825280602002602001820160405280156116f557816020015b6116e2613750565b8152602001906001900390816116da5790505b5090505f5b600a5463ffffffff61010090910481169082161015611680575f61171f8260016140c7565b61172a906064613fb4565b905060405180604001604052808263ffffffff168152602001600b5f8463ffffffff1681526020019081526020015f206040518060c00160405290815f8201805461177490613d98565b80601f01602080910402602001604051908101604052809291908181526020018280546117a090613d98565b80156117eb5780601f106117c2576101008083540402835291602001916117eb565b820191905f5260205f20905b8154815290600101906020018083116117ce57829003601f168201915b5050505050815260200160018201805461180490613d98565b80601f016020809104026020016040519081016040528092919081815260200182805461183090613d98565b801561187b5780601f106118525761010080835404028352916020019161187b565b820191905f5260205f20905b81548152906001019060200180831161185e57829003601f168201915b5050509183525050600282015460ff80821615156020840152610100820481161515604084015262010000909104161515606082015260039091015460809091015290528351849063ffffffff85169081106118d9576118d9613e29565b6020908102919091010152506001016116fa565b6002545f907a010000000000000000000000000000000000000000000000000000900465ffffffffffff16801515801561192f57504265ffffffffffff821610155b61193a575f5f61195f565b60025474010000000000000000000000000000000000000000900465ffffffffffff16815b915091509091565b6109683383836126a7565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561199c81612158565b6119a582612177565b5f828152600b6020526040902060020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff16620100001790556119e98261222f565b6119f2826121c4565b60405182907fa6c942fbe3ded4df132dc2c4adbb95359afebc3c361393a3d7217e3c310923e8905f90a25050565b611a2b8484846109d9565b611a38338585858561275e565b50505050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775611a6881612158565b612710821115611aa4576040517f47d3b04600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60108290556040518281527f6367530104bc8677601bbb2f410055f5144865bf130b2c7bed1af5ff39185eb090602001611426565b6060611ae4826120fa565b505f611aee612902565b90505f815111611b0c5760405180602001604052805f815250611b37565b80611b1684612911565b604051602001611b279291906140fa565b6040516020818303038152906040525b9392505050565b6002545f907a010000000000000000000000000000000000000000000000000000900465ffffffffffff168015158015611b7f57504265ffffffffffff8216105b611bb1576001547a010000000000000000000000000000000000000000000000000000900465ffffffffffff16611bd5565b60025474010000000000000000000000000000000000000000900465ffffffffffff165b91505090565b7fdaf9ac3a6308052428e8806fd908cf472318416ed7d78b3f35dd94bbbafde56a611c0581612158565b611c0e83612177565b5f838152600b6020526040908190206003018390555183907f27a815a14bf8281048d2768dcd6b695fbd4e98af4e3fb52d92c8c65384320d4a90611c559085815260200190565b60405180910390a2505050565b6001546001600160a01b0316338114611ca9576040517fc22c8022000000000000000000000000000000000000000000000000000000008152336004820152602401610b59565b61097e6129ae565b81611ce8576040517f3fc3c27a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109688282612a85565b5f611cfc81612158565b61097e612aa9565b7fdaf9ac3a6308052428e8806fd908cf472318416ed7d78b3f35dd94bbbafde56a611d2e81612158565b611d3784612177565b81611d6e576040517fcbd6898900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f848152600b60205260409020600101611d89838583613e9a565b50837f15c3eac3b34037e402127abd35c3804f49d489c361f5bb8ff237544f0dfff4ed8484604051611dbc929190613f7d565b60405180910390a250505050565b611dd382612177565b611ddc8261253f565b611de582612590565b80156109c45761096882612ab3565b6060611e00600c61216e565b67ffffffffffffffff811115611e1857611e18613bfd565b604051908082528060200260200182016040528015611e5157816020015b611e3e613750565b815260200190600190039081611e365790505b5090505f5b611e60600c61216e565b8163ffffffff161015611680575f611e82600c63ffffffff8085169061269c16565b90506040518060400160405280828152602001600b5f8481526020019081526020015f206040518060c00160405290815f82018054611ec090613d98565b80601f0160208091040260200160405190810160405280929190818152602001828054611eec90613d98565b8015611f375780601f10611f0e57610100808354040283529160200191611f37565b820191905f5260205f20905b815481529060010190602001808311611f1a57829003601f168201915b50505050508152602001600182018054611f5090613d98565b80601f0160208091040260200160405190810160405280929190818152602001828054611f7c90613d98565b8015611fc75780601f10611f9e57610100808354040283529160200191611fc7565b820191905f5260205f20905b815481529060010190602001808311611faa57829003601f168201915b5050509183525050600282015460ff80821615156020840152610100820481161515604084015262010000909104161515606082015260039091015460809091015290528351849063ffffffff851690811061202557612025613e29565b6020026020010181905250508061203b90613f90565b9050611e56565b5f61098c600c61216e565b606061098c600e612438565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f80ac58cd0000000000000000000000000000000000000000000000000000000014806120eb57507fffffffff0000000000000000000000000000000000000000000000000000000082167f5b5e139f00000000000000000000000000000000000000000000000000000000145b806108a057506108a082612b51565b5f818152600560205260408120546001600160a01b0316806108a0576040517f7e27328900000000000000000000000000000000000000000000000000000000815260048101849052602401610b59565b610c458383836001612ba6565b61097e8133612cf9565b61216c5f5f612d64565b565b5f6108a0825490565b5f818152600560205260409020546001600160a01b031661097e576040517f5e926f7100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6121cf600e82612eb0565b6121d65750565b5f818152600b6020526040808220600201805460ff191690555182917fa9837328431beea294d22d476aeafca23f85f320de41750a9b9c3ce28076180891a250565b5f8181526001830160205260408120541515611b37565b61223a600c82612eb0565b6122415750565b5f818152600b602052604080822060020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555182917f9e61606f143f77c9ef06d68819ce159e3b98756d8eb558b91db82c8ca42357f391a250565b6001600160a01b0382166122e3576040517f64a0ae920000000000000000000000000000000000000000000000000000000081525f6004820152602401610b59565b5f6122ef838333612ebb565b9050836001600160a01b0316816001600160a01b031614611a38576040517f64283d7b0000000000000000000000000000000000000000000000000000000081526001600160a01b0380861660048301526024820184905282166044820152606401610b59565b5f8281526020819052604090206001015461237081612158565b611a388383612fc5565b6001600160a01b03811633146123bc576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c45828261305c565b5f6123cf611b3e565b6123d8426130b0565b6123e2919061410e565b90506123ee82826130fb565b60405165ffffffffffff821681526001600160a01b038316907f3377dc44241e779dd06afab5b788a35ca5f3b778836e2990bdb26a2a4b2e5ed69060200160405180910390a25050565b60605f611b3783613189565b5f61244e826131e2565b612457426130b0565b612461919061410e565b905061246d8282612d64565b6040805165ffffffffffff8085168252831660208201527ff1038c18cf84a56e432fdbfaf746924b7ea511dfe03a6506a0ceba4888788d9b9101611426565b6001600160a01b0382166124ee576040517f64a0ae920000000000000000000000000000000000000000000000000000000081525f6004820152602401610b59565b5f6124fa83835f612ebb565b90506001600160a01b03811615610c45576040517f73c6ac6e0000000000000000000000000000000000000000000000000000000081525f6004820152602401610b59565b5f818152600b602052604090206002015462010000900460ff161561097e576040517fc40c6f6300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f818152600560205260409020546001600160a01b0316331461097e576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a5460ff166125ef600c61216e565b10612626576040517f950be9a500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612631600c82613229565b6126385750565b5f818152600b602052604080822060020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555182917f3cd0abf09f2e68bb82445a4d250b6a3e30b2b2c711b322e3f3817927a07da17391a250565b5f611b378383613234565b6001600160a01b0382166126f2576040517f5b08ba180000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610b59565b6001600160a01b038381165f81815260086020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0383163b156128fb576040517f150b7a020000000000000000000000000000000000000000000000000000000081526001600160a01b0384169063150b7a02906127b990889088908790879060040161412c565b6020604051808303815f875af19250505080156127f3575060408051601f3d908101601f191682019092526127f09181019061416c565b60015b612873573d808015612820576040519150601f19603f3d011682016040523d82523d5f602084013e612825565b606091505b5080515f0361286b576040517f64a0ae920000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401610b59565b805181602001fd5b7fffffffff0000000000000000000000000000000000000000000000000000000081167f150b7a0200000000000000000000000000000000000000000000000000000000146128f9576040517f64a0ae920000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401610b59565b505b5050505050565b6060600980546108b590613d98565b60605f61291d8361325a565b60010190505f8167ffffffffffffffff81111561293c5761293c613bfd565b6040519080825280601f01601f191660200182016040528015612966576020820181803683370190505b5090508181016020015b5f19017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a850494508461297057509392505050565b6001546001600160a01b0381169074010000000000000000000000000000000000000000900465ffffffffffff168015806129f157504265ffffffffffff821610155b15612a32576040517f19ca5ebb00000000000000000000000000000000000000000000000000000000815265ffffffffffff82166004820152602401610b59565b612a4d5f612a486002546001600160a01b031690565b61305c565b50612a585f83612fc5565b5050600180547fffffffffffff000000000000000000000000000000000000000000000000000016905550565b5f82815260208190526040902060010154612a9f81612158565b611a38838361305c565b61216c5f5f6130fb565b600a5460ff16612ac3600e61216e565b10612afa576040517f950be9a500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612b05600e82613229565b612b0c5750565b5f818152600b6020526040808220600201805460ff191660011790555182917fd9199c75487673396ebe8093e82e5cf7902ccfb90befe22763a8bc4c36b976d091a250565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f314987860000000000000000000000000000000000000000000000000000000014806108a057506108a08261333b565b8080612bba57506001600160a01b03821615155b15612cb2575f612bc9846120fa565b90506001600160a01b03831615801590612bf55750826001600160a01b0316816001600160a01b031614155b8015612c2657506001600160a01b038082165f9081526008602090815260408083209387168352929052205460ff16155b15612c68576040517fa9fbf51f0000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401610b59565b8115612cb05783856001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b50505f90815260076020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b5f828152602081815260408083206001600160a01b038516845290915290205460ff16610968576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401610b59565b6002547a010000000000000000000000000000000000000000000000000000900465ffffffffffff168015612e38574265ffffffffffff82161015612e0f576002546001805479ffffffffffffffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000090920465ffffffffffff167a01000000000000000000000000000000000000000000000000000002919091179055612e38565b6040517f2b1fa2edafe6f7b9e97c1a9e0c3660e645beb2dcaa2d45bdbf9beaf5472e1ec5905f90a15b50600280546001600160a01b03167401000000000000000000000000000000000000000065ffffffffffff9485160279ffffffffffffffffffffffffffffffffffffffffffffffffffff16177a0100000000000000000000000000000000000000000000000000009290931691909102919091179055565b5f611b3783836133d1565b5f828152600560205260408120546001600160a01b0390811690831615612ee757612ee78184866134bb565b6001600160a01b03811615612f2157612f025f855f5f612ba6565b6001600160a01b0381165f90815260066020526040902080545f190190555b6001600160a01b03851615612f4f576001600160a01b0385165f908152600660205260409020805460010190555b5f8481526005602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0389811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b5f82613052575f612fde6002546001600160a01b031690565b6001600160a01b03161461301e576040517f3fc3c27a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0384161790555b611b378383613551565b5f8215801561307857506002546001600160a01b038381169116145b156130a657600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555b611b3783836135f8565b5f65ffffffffffff821115611680576040517f6dfcc6500000000000000000000000000000000000000000000000000000000081526030600482015260248101839052604401610b59565b600180547401000000000000000000000000000000000000000065ffffffffffff84811682027fffffffffffff000000000000000000000000000000000000000000000000000084166001600160a01b03881617179093559004168015610c45576040517f8886ebfc4259abdbc16601dd8fb5678e54878f47b3c34836cfc51154a9605109905f90a1505050565b6060815f018054806020026020016040519081016040528092919081815260200182805480156131d657602002820191905f5260205f20905b8154815260200190600101908083116131c2575b50505050509050919050565b5f5f6131ec611b3e565b90508065ffffffffffff168365ffffffffffff16116132145761320f8382614187565b611b37565b611b3765ffffffffffff841662069780613679565b5f611b378383613688565b5f825f01828154811061324957613249613e29565b905f5260205f200154905092915050565b5f807a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000083106132a2577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef810000000083106132ce576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106132ec57662386f26fc10000830492506010015b6305f5e1008310613304576305f5e100830492506008015b612710831061331857612710830492506004015b6064831061332a576064830492506002015b600a83106108a05760010192915050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806108a057507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146108a0565b5f81815260018301602052604081205480156134ab575f6133f3600183613e16565b85549091505f9061340690600190613e16565b9050808214613465575f865f01828154811061342457613424613e29565b905f5260205f200154905080875f01848154811061344457613444613e29565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080613476576134766141a5565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f9055600193505050506108a0565b5f9150506108a0565b5092915050565b6134c68383836136cd565b610c45576001600160a01b03831661350d576040517f7e27328900000000000000000000000000000000000000000000000000000000815260048101829052602401610b59565b6040517f177e802f0000000000000000000000000000000000000000000000000000000081526001600160a01b038316600482015260248101829052604401610b59565b5f828152602081815260408083206001600160a01b038516845290915281205460ff166135f1575f838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556135a93390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016108a0565b505f6108a0565b5f828152602081815260408083206001600160a01b038516845290915281205460ff16156135f1575f838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45060016108a0565b5f828218828410028218611b37565b5f8181526001830160205260408120546135f157508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556108a0565b5f6001600160a01b038316158015906137485750826001600160a01b0316846001600160a01b0316148061372557506001600160a01b038085165f9081526008602090815260408083209387168352929052205460ff165b8061374857505f828152600760205260409020546001600160a01b038481169116145b949350505050565b60405180604001604052805f815260200161379c6040518060c0016040528060608152602001606081526020015f151581526020015f151581526020015f151581526020015f81525090565b905290565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461097e575f5ffd5b5f602082840312156137de575f5ffd5b8135611b37816137a1565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f611b3760208301846137e9565b5f60208284031215613839575f5ffd5b5035919050565b80356001600160a01b0381168114613856575f5ffd5b919050565b5f5f6040838503121561386c575f5ffd5b61387583613840565b946020939093013593505050565b5f5f5f60608486031215613895575f5ffd5b61389e84613840565b92506138ac60208501613840565b929592945050506040919091013590565b5f5f604083850312156138ce575f5ffd5b823591506138de60208401613840565b90509250929050565b5f815160c084526138fb60c08501826137e9565b90506020830151848203602086015261391482826137e9565b91505060408301511515604085015260608301511515606085015260808301511515608085015260a083015160a08501528091505092915050565b602081525f611b3760208301846138e7565b5f5f83601f840112613971575f5ffd5b50813567ffffffffffffffff811115613988575f5ffd5b60208301915083602082850101111561399f575f5ffd5b9250929050565b5f5f602083850312156139b7575f5ffd5b823567ffffffffffffffff8111156139cd575f5ffd5b6139d985828601613961565b90969095509350505050565b5f602082840312156139f5575f5ffd5b611b3782613840565b602080825282518282018190525f918401906040840190835b81811015613a35578351835260209384019390920191600101613a17565b509095945050505050565b5f60208284031215613a50575f5ffd5b813565ffffffffffff81168114611b37575f5ffd5b5f5f5f5f5f5f60808789031215613a7a575f5ffd5b613a8387613840565b9550602087013567ffffffffffffffff811115613a9e575f5ffd5b613aaa89828a01613961565b909650945050604087013567ffffffffffffffff811115613ac9575f5ffd5b613ad589828a01613961565b979a9699509497949695606090950135949350505050565b80358015158114613856575f5ffd5b5f5f60408385031215613b0d575f5ffd5b823591506138de60208401613aed565b5f60208284031215613b2d575f5ffd5b813560ff81168114611b37575f5ffd5b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b82811015613bc9577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08786030184528151805186526020810151905060406020870152613bb360408701826138e7565b9550506020938401939190910190600101613b63565b50929695505050505050565b5f5f60408385031215613be6575f5ffd5b613bef83613840565b91506138de60208401613aed565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f5f5f5f60808587031215613c3d575f5ffd5b613c4685613840565b9350613c5460208601613840565b925060408501359150606085013567ffffffffffffffff811115613c76575f5ffd5b8501601f81018713613c86575f5ffd5b803567ffffffffffffffff811115613ca057613ca0613bfd565b604051601f19603f601f19601f8501160116810181811067ffffffffffffffff82111715613cd057613cd0613bfd565b604052818152828201602001891015613ce7575f5ffd5b816020840160208301375f6020838301015280935050505092959194509250565b5f5f60408385031215613d19575f5ffd5b50508035926020909101359150565b5f5f5f60408486031215613d3a575f5ffd5b83359250602084013567ffffffffffffffff811115613d57575f5ffd5b613d6386828701613961565b9497909650939450505050565b5f5f60408385031215613d81575f5ffd5b613d8a83613840565b91506138de60208401613840565b600181811c90821680613dac57607f821691505b602082108103613de3577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b818103818111156108a0576108a0613de9565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b601f821115610c4557805f5260205f20601f840160051c81016020851015613e7b5750805b601f840160051c820191505b818110156128fb575f8155600101613e87565b67ffffffffffffffff831115613eb257613eb2613bfd565b613ec683613ec08354613d98565b83613e56565b5f601f841160018114613ef7575f8515613ee05750838201355b5f19600387901b1c1916600186901b1783556128fb565b5f83815260208120601f198716915b82811015613f265786850135825560209485019460019092019101613f06565b5086821015613f42575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b81835281816020850137505f602082840101525f6020601f19601f840116840101905092915050565b602081525f613748602083018486613f54565b5f63ffffffff821663ffffffff8103613fab57613fab613de9565b60010192915050565b63ffffffff81811683821602908116908181146134b4576134b4613de9565b815167ffffffffffffffff811115613fed57613fed613bfd565b61400181613ffb8454613d98565b84613e56565b6020601f821160018114614033575f831561401c5750848201515b5f19600385901b1c1916600184901b1784556128fb565b5f84815260208120601f198516915b828110156140625787850151825560209485019460019092019101614042565b508482101561407f57868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b606081525f6140a1606083018789613f54565b82810360208401526140b4818688613f54565b9150508260408301529695505050505050565b63ffffffff81811683821601908111156108a0576108a0613de9565b5f81518060208401855e5f93019283525090919050565b5f61374861410883866140e3565b846140e3565b65ffffffffffff81811683821601908111156108a0576108a0613de9565b6001600160a01b03851681526001600160a01b0384166020820152826040820152608060608201525f61416260808301846137e9565b9695505050505050565b5f6020828403121561417c575f5ffd5b8151611b37816137a1565b65ffffffffffff82811682821603908111156108a0576108a0613de9565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea26469706673582212204806a675f1da3494a4dd4c0222d2e621e9c6968738ff149341166520231b328364736f6c634300081c0033daf9ac3a6308052428e8806fd908cf472318416ed7d78b3f35dd94bbbafde56aa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775", } // NodesABI is the input ABI used to generate the binding from. @@ -60,7 +60,7 @@ var NodesABI = NodesMetaData.ABI var NodesBin = NodesMetaData.Bin // DeployNodes deploys a new Ethereum contract, binding an instance of Nodes to it. -func DeployNodes(auth *bind.TransactOpts, backend bind.ContractBackend, _initialAdmin common.Address) (common.Address, *types.Transaction, *Nodes, error) { +func DeployNodes(auth *bind.TransactOpts, backend bind.ContractBackend, initialAdmin common.Address) (common.Address, *types.Transaction, *Nodes, error) { parsed, err := NodesMetaData.GetAbi() if err != nil { return common.Address{}, nil, nil, err @@ -69,7 +69,7 @@ func DeployNodes(auth *bind.TransactOpts, backend bind.ContractBackend, _initial return common.Address{}, nil, nil, errors.New("GetABI returned nil") } - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(NodesBin), backend, _initialAdmin) + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(NodesBin), backend, initialAdmin) if err != nil { return common.Address{}, nil, nil, err } @@ -311,6 +311,37 @@ func (_Nodes *NodesCallerSession) MAXBPS() (*big.Int, error) { return _Nodes.Contract.MAXBPS(&_Nodes.CallOpts) } +// NODEINCREMENT is a free data retrieval call binding the contract method 0xfd667d1e. +// +// Solidity: function NODE_INCREMENT() view returns(uint32) +func (_Nodes *NodesCaller) NODEINCREMENT(opts *bind.CallOpts) (uint32, error) { + var out []interface{} + err := _Nodes.contract.Call(opts, &out, "NODE_INCREMENT") + + if err != nil { + return *new(uint32), err + } + + out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32) + + return out0, err + +} + +// NODEINCREMENT is a free data retrieval call binding the contract method 0xfd667d1e. +// +// Solidity: function NODE_INCREMENT() view returns(uint32) +func (_Nodes *NodesSession) NODEINCREMENT() (uint32, error) { + return _Nodes.Contract.NODEINCREMENT(&_Nodes.CallOpts) +} + +// NODEINCREMENT is a free data retrieval call binding the contract method 0xfd667d1e. +// +// Solidity: function NODE_INCREMENT() view returns(uint32) +func (_Nodes *NodesCallerSession) NODEINCREMENT() (uint32, error) { + return _Nodes.Contract.NODEINCREMENT(&_Nodes.CallOpts) +} + // NODEMANAGERROLE is a free data retrieval call binding the contract method 0xd59f9fe0. // // Solidity: function NODE_MANAGER_ROLE() view returns(bytes32) @@ -1209,7 +1240,7 @@ func (_Nodes *NodesCallerSession) PendingDefaultAdminDelay() (struct { // SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. // -// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool supported) func (_Nodes *NodesCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { var out []interface{} err := _Nodes.contract.Call(opts, &out, "supportsInterface", interfaceId) @@ -1226,14 +1257,14 @@ func (_Nodes *NodesCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4 // SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. // -// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool supported) func (_Nodes *NodesSession) SupportsInterface(interfaceId [4]byte) (bool, error) { return _Nodes.Contract.SupportsInterface(&_Nodes.CallOpts, interfaceId) } // SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. // -// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool supported) func (_Nodes *NodesCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { return _Nodes.Contract.SupportsInterface(&_Nodes.CallOpts, interfaceId) } @@ -1323,21 +1354,21 @@ func (_Nodes *NodesTransactorSession) AcceptDefaultAdminTransfer() (*types.Trans // AddNode is a paid mutator transaction binding the contract method 0x6ec97bfc. // -// Solidity: function addNode(address to, bytes signingKeyPub, string httpAddress, uint256 minMonthlyFeeMicroDollars) returns(uint256) +// Solidity: function addNode(address to, bytes signingKeyPub, string httpAddress, uint256 minMonthlyFeeMicroDollars) returns(uint256 nodeId) func (_Nodes *NodesTransactor) AddNode(opts *bind.TransactOpts, to common.Address, signingKeyPub []byte, httpAddress string, minMonthlyFeeMicroDollars *big.Int) (*types.Transaction, error) { return _Nodes.contract.Transact(opts, "addNode", to, signingKeyPub, httpAddress, minMonthlyFeeMicroDollars) } // AddNode is a paid mutator transaction binding the contract method 0x6ec97bfc. // -// Solidity: function addNode(address to, bytes signingKeyPub, string httpAddress, uint256 minMonthlyFeeMicroDollars) returns(uint256) +// Solidity: function addNode(address to, bytes signingKeyPub, string httpAddress, uint256 minMonthlyFeeMicroDollars) returns(uint256 nodeId) func (_Nodes *NodesSession) AddNode(to common.Address, signingKeyPub []byte, httpAddress string, minMonthlyFeeMicroDollars *big.Int) (*types.Transaction, error) { return _Nodes.Contract.AddNode(&_Nodes.TransactOpts, to, signingKeyPub, httpAddress, minMonthlyFeeMicroDollars) } // AddNode is a paid mutator transaction binding the contract method 0x6ec97bfc. // -// Solidity: function addNode(address to, bytes signingKeyPub, string httpAddress, uint256 minMonthlyFeeMicroDollars) returns(uint256) +// Solidity: function addNode(address to, bytes signingKeyPub, string httpAddress, uint256 minMonthlyFeeMicroDollars) returns(uint256 nodeId) func (_Nodes *NodesTransactorSession) AddNode(to common.Address, signingKeyPub []byte, httpAddress string, minMonthlyFeeMicroDollars *big.Int) (*types.Transaction, error) { return _Nodes.Contract.AddNode(&_Nodes.TransactOpts, to, signingKeyPub, httpAddress, minMonthlyFeeMicroDollars) } diff --git a/contracts/pkg/ratesmanager/RatesManager.go b/contracts/pkg/ratesmanager/RatesManager.go index e7b9e3e3..56f4aed8 100644 --- a/contracts/pkg/ratesmanager/RatesManager.go +++ b/contracts/pkg/ratesmanager/RatesManager.go @@ -39,8 +39,8 @@ type RatesManagerRates struct { // RatesManagerMetaData contains all meta data concerning the RatesManager contract. var RatesManagerMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"function\",\"name\":\"DEFAULT_ADMIN_ROLE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"RATES_MANAGER_ROLE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"UPGRADE_INTERFACE_VERSION\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"addRates\",\"inputs\":[{\"name\":\"messageFee\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"storageFee\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"congestionFee\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"startTime\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"getRates\",\"inputs\":[{\"name\":\"fromIndex\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"rates\",\"type\":\"tuple[]\",\"internalType\":\"structRatesManager.Rates[]\",\"components\":[{\"name\":\"messageFee\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"storageFee\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"congestionFee\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"startTime\",\"type\":\"uint64\",\"internalType\":\"uint64\"}]},{\"name\":\"hasMore\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRatesCount\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRoleAdmin\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"grantRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"hasRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"admin\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proxiableUUID\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"renounceRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"callerConfirmation\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"revokeRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"supportsInterface\",\"inputs\":[{\"name\":\"interfaceId\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"upgradeToAndCall\",\"inputs\":[{\"name\":\"newImplementation\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RatesAdded\",\"inputs\":[{\"name\":\"messageFee\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"storageFee\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"congestionFee\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"startTime\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleAdminChanged\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"previousAdminRole\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"newAdminRole\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleGranted\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleRevoked\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UpgradeAuthorized\",\"inputs\":[{\"name\":\"upgrader\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"newImplementation\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Upgraded\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AccessControlBadConfirmation\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"AccessControlUnauthorizedAccount\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"neededRole\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"AddressEmptyCode\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC1967InvalidImplementation\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC1967NonPayable\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"EnforcedPause\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ExpectedPause\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FailedCall\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FromIndexOutOfRange\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidInitialization\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidStartTime\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotInitializing\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UUPSUnauthorizedCallContext\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UUPSUnsupportedProxiableUUID\",\"inputs\":[{\"name\":\"slot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"ZeroAdminAddress\",\"inputs\":[]}]", - Bin: "0x60a0604052306080523480156012575f5ffd5b50608051611d626100395f395f8181610f9f01528181610fc801526112e20152611d625ff3fe608060405260043610610123575f3560e01c806352d1902d116100a1578063a217fddf11610071578063c4d66de811610057578063c4d66de8146103b2578063d547741f146103d1578063e3396735146103f0575f5ffd5b8063a217fddf1461034a578063ad3cb1cc1461035d575f5ffd5b806352d1902d1461027c5780635c975abb146102905780638456cb59146102c657806391d14854146102da575f5ffd5b80632f2ff15d116100f65780633f4ba83a116100dc5780633f4ba83a14610236578063444121071461024a5780634f1ef28614610269575f5ffd5b80632f2ff15d146101f657806336568abe14610217575f5ffd5b806301ffc9a714610127578063081802b11461015b578063248a9ca3146101885780632da72291146101e3575b5f5ffd5b348015610132575f5ffd5b5061014661014136600461193b565b610423565b60405190151581526020015b60405180910390f35b348015610166575f5ffd5b5061017a61017536600461197a565b6104bb565b604051610152929190611991565b348015610193575f5ffd5b506101d56101a236600461197a565b5f9081527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052604090206001015490565b604051908152602001610152565b3480156101ee575f5ffd5b505f546101d5565b348015610201575f5ffd5b50610215610210366004611a53565b61070a565b005b348015610222575f5ffd5b50610215610231366004611a53565b610753565b348015610241575f5ffd5b506102156107b1565b348015610255575f5ffd5b50610215610264366004611a94565b6107c6565b610215610277366004611b12565b610a0a565b348015610287575f5ffd5b506101d5610a29565b34801561029b575f5ffd5b507fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff16610146565b3480156102d1575f5ffd5b50610215610a57565b3480156102e5575f5ffd5b506101466102f4366004611a53565b5f9182527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020908152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b348015610355575f5ffd5b506101d55f81565b348015610368575f5ffd5b506103a56040518060400160405280600581526020017f352e302e3000000000000000000000000000000000000000000000000000000081525081565b6040516101529190611c13565b3480156103bd575f5ffd5b506102156103cc366004611c66565b610a69565b3480156103dc575f5ffd5b506102156103eb366004611a53565b610ca3565b3480156103fb575f5ffd5b506101d57f64b4740f54156feb06b7a9f424e5bce966a52344cf27635887cf63c0ebf2a61e81565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806104b557507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b5f8054606091901580156104cd575082155b1561054257604080515f8082526020820190925290610538565b604080516080810182525f8082526020808301829052928201819052606082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816104e75790505b50935f9350915050565b5f54831061057c576040517fea61fe7000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f610588603285611cac565b5f5490915081111561059857505f545b5f6105a38583611cbf565b90505f8167ffffffffffffffff8111156105bf576105bf611ae5565b60405190808252806020026020018201604052801561062e57816020015b604080516080810182525f8082526020808301829052928201819052606082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816105dd5790505b5090505f5b828110156106fa575f6106468289611cac565b8154811061065657610656611cd2565b5f91825260209182902060408051608081018252929091015467ffffffffffffffff8082168452680100000000000000008204811694840194909452700100000000000000000000000000000000810484169183019190915278010000000000000000000000000000000000000000000000009004909116606082015282518390839081106106e7576106e7611cd2565b6020908102919091010152600101610633565b505f549096921094509092505050565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052604090206001015461074381610ce6565b61074d8383610cf0565b50505050565b73ffffffffffffffffffffffffffffffffffffffff811633146107a2576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107ac8282610e0e565b505050565b5f6107bb81610ce6565b6107c3610eea565b50565b7f64b4740f54156feb06b7a9f424e5bce966a52344cf27635887cf63c0ebf2a61e6107f081610ce6565b5f541580159061085357505f805461080a90600190611cbf565b8154811061081a5761081a611cd2565b5f9182526020909120015467ffffffffffffffff7801000000000000000000000000000000000000000000000000909104811690831611155b1561088a576040517fb290253c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160808101825267ffffffffffffffff808816825286811660208301908152868216838501908152868316606085019081525f805460018101825590805294517f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5639095018054935192519151851678010000000000000000000000000000000000000000000000000277ffffffffffffffffffffffffffffffffffffffffffffffff92861670010000000000000000000000000000000002929092166fffffffffffffffffffffffffffffffff93861668010000000000000000027fffffffffffffffffffffffffffffffff000000000000000000000000000000009095169690951695909517929092171691909117179055517f3bff7b1e021b47f5dfd21d1d3fe2daaf3b9cbaca733c6e15b3a0da546657f19a906109fb90879087908790879067ffffffffffffffff948516815292841660208401529083166040830152909116606082015260800190565b60405180910390a15050505050565b610a12610f87565b610a1b8261108d565b610a258282611191565b5050565b5f610a326112ca565b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b5f610a6181610ce6565b6107c3611339565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff165f81158015610ab35750825b90505f8267ffffffffffffffff166001148015610acf5750303b155b905081158015610add575080155b15610b14576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001660011785558315610b755784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b73ffffffffffffffffffffffffffffffffffffffff8616610bc2576040517f3ef39b8100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610bca6113b2565b610bd26113b2565b610bda6113ba565b610c047f64b4740f54156feb06b7a9f424e5bce966a52344cf27635887cf63c0ebf2a61e5f6113ca565b610c0e5f87610cf0565b50610c397f64b4740f54156feb06b7a9f424e5bce966a52344cf27635887cf63c0ebf2a61e87610cf0565b508315610c9b5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020526040902060010154610cdc81610ce6565b61074d8383610e0e565b6107c3813361146b565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020818152604080842073ffffffffffffffffffffffffffffffffffffffff8616855290915282205460ff16610e05575f8481526020828152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610da13390565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a460019150506104b5565b5f9150506104b5565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020818152604080842073ffffffffffffffffffffffffffffffffffffffff8616855290915282205460ff1615610e05575f8481526020828152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a460019150506104b5565b610ef2611511565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a150565b3073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016148061105457507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1661103b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614155b1561108b576040517fe07c8dba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b5f61109781610ce6565b73ffffffffffffffffffffffffffffffffffffffff821661113f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f4e657720696d706c656d656e746174696f6e2063616e6e6f74206265207a657260448201527f6f2061646472657373000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6040805133815273ffffffffffffffffffffffffffffffffffffffff841660208201527fd30e1d298bf814ea43d22b4ce8298062b08609cd67496483769d836157dd52fa910160405180910390a15050565b8173ffffffffffffffffffffffffffffffffffffffff166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611216575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261121391810190611cff565b60015b611264576040517f4c9c8ce300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602401611136565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc81146112c0576040517faa1d49a400000000000000000000000000000000000000000000000000000000815260048101829052602401611136565b6107ac838361156c565b3073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461108b576040517fe07c8dba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6113416115ce565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833610f5c565b61108b61162a565b6113c261162a565b61108b611691565b7f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268005f611423845f9081527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052604090206001015490565b5f85815260208490526040808220600101869055519192508491839187917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a450505050565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a25576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260248101839052604401611136565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff1661108b576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611575826116e2565b60405173ffffffffffffffffffffffffffffffffffffffff8316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a28051156115c6576107ac82826117b0565b610a2561182f565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff161561108b576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff1661108b576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61169961162a565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b8073ffffffffffffffffffffffffffffffffffffffff163b5f0361174a576040517f4c9c8ce300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401611136565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60605f5f8473ffffffffffffffffffffffffffffffffffffffff16846040516117d99190611d16565b5f60405180830381855af49150503d805f8114611811576040519150601f19603f3d011682016040523d82523d5f602084013e611816565b606091505b5091509150611826858383611867565b95945050505050565b341561108b576040517fb398979f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608261187c57611877826118f9565b6118f2565b81511580156118a0575073ffffffffffffffffffffffffffffffffffffffff84163b155b156118ef576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602401611136565b50805b9392505050565b8051156119095780518082602001fd5b6040517fd6bda27500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6020828403121561194b575f5ffd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146118f2575f5ffd5b5f6020828403121561198a575f5ffd5b5035919050565b604080825283519082018190525f9060208501906060840190835b81811015611a1857835167ffffffffffffffff815116845267ffffffffffffffff602082015116602085015267ffffffffffffffff604082015116604085015267ffffffffffffffff6060820151166060850152506080830192506020840193506001810190506119ac565b5050841515602085015291506118f29050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611a4e575f5ffd5b919050565b5f5f60408385031215611a64575f5ffd5b82359150611a7460208401611a2b565b90509250929050565b803567ffffffffffffffff81168114611a4e575f5ffd5b5f5f5f5f60808587031215611aa7575f5ffd5b611ab085611a7d565b9350611abe60208601611a7d565b9250611acc60408601611a7d565b9150611ada60608601611a7d565b905092959194509250565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f5f60408385031215611b23575f5ffd5b611b2c83611a2b565b9150602083013567ffffffffffffffff811115611b47575f5ffd5b8301601f81018513611b57575f5ffd5b803567ffffffffffffffff811115611b7157611b71611ae5565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff82111715611bdd57611bdd611ae5565b604052818152828201602001871015611bf4575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505092915050565b5f60208284031215611c76575f5ffd5b6118f282611a2b565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b808201808211156104b5576104b5611c7f565b818103818111156104b5576104b5611c7f565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f60208284031215611d0f575f5ffd5b5051919050565b5f82518060208501845e5f92019182525091905056fea26469706673582212208e14859721448338dfe1243a0d63121c43052e5410dd52ea8155ab1b83386cb464736f6c634300081c0033", + ABI: "[{\"type\":\"function\",\"name\":\"DEFAULT_ADMIN_ROLE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"PAGE_SIZE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"RATES_MANAGER_ROLE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"UPGRADE_INTERFACE_VERSION\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"addRates\",\"inputs\":[{\"name\":\"messageFee\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"storageFee\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"congestionFee\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"startTime\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"getRates\",\"inputs\":[{\"name\":\"fromIndex\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"rates\",\"type\":\"tuple[]\",\"internalType\":\"structRatesManager.Rates[]\",\"components\":[{\"name\":\"messageFee\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"storageFee\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"congestionFee\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"startTime\",\"type\":\"uint64\",\"internalType\":\"uint64\"}]},{\"name\":\"hasMore\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRatesCount\",\"inputs\":[],\"outputs\":[{\"name\":\"count\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRoleAdmin\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"grantRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"hasRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"admin\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"pause\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"proxiableUUID\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"renounceRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"callerConfirmation\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"revokeRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"supportsInterface\",\"inputs\":[{\"name\":\"interfaceId\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"unpause\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"upgradeToAndCall\",\"inputs\":[{\"name\":\"newImplementation\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RatesAdded\",\"inputs\":[{\"name\":\"messageFee\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"storageFee\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"congestionFee\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"startTime\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleAdminChanged\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"previousAdminRole\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"newAdminRole\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleGranted\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleRevoked\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UpgradeAuthorized\",\"inputs\":[{\"name\":\"upgrader\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"newImplementation\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Upgraded\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AccessControlBadConfirmation\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"AccessControlUnauthorizedAccount\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"neededRole\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"AddressEmptyCode\",\"inputs\":[{\"name\":\"target\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC1967InvalidImplementation\",\"inputs\":[{\"name\":\"implementation\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC1967NonPayable\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"EnforcedPause\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ExpectedPause\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FailedCall\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FromIndexOutOfRange\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidInitialization\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidStartTime\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotInitializing\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UUPSUnauthorizedCallContext\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UUPSUnsupportedProxiableUUID\",\"inputs\":[{\"name\":\"slot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"ZeroAdminAddress\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ZeroImplementationAddress\",\"inputs\":[]}]", + Bin: "0x60a0604052306080523480156012575f5ffd5b50608051611d726100395f395f81816110080152818161103101526112f50152611d725ff3fe60806040526004361061013d575f3560e01c80634f1ef286116100bb578063a217fddf11610071578063c4d66de811610057578063c4d66de814610400578063d547741f1461041f578063e33967351461043e575f5ffd5b8063a217fddf14610398578063ad3cb1cc146103ab575f5ffd5b80635c975abb116100a15780635c975abb146102de5780638456cb591461031457806391d1485414610328575f5ffd5b80634f1ef286146102b757806352d1902d146102ca575f5ffd5b80632f2ff15d1161011057806336568abe116100f657806336568abe146102655780633f4ba83a146102845780634441210714610298575f5ffd5b80632f2ff15d1461023057806331b2866414610251575f5ffd5b806301ffc9a714610141578063081802b114610175578063248a9ca3146101a25780632da72291146101fd575b5f5ffd5b34801561014c575f5ffd5b5061016061015b36600461194b565b610471565b60405190151581526020015b60405180910390f35b348015610180575f5ffd5b5061019461018f36600461198a565b610509565b60405161016c9291906119a1565b3480156101ad575f5ffd5b506101ef6101bc36600461198a565b5f9081527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052604090206001015490565b60405190815260200161016c565b348015610208575f5ffd5b507f6ad1a01bf62225c91223b2956030efc848b0def7d19ed478ca6dd31490e2d000546101ef565b34801561023b575f5ffd5b5061024f61024a366004611a63565b61076e565b005b34801561025c575f5ffd5b506101ef603281565b348015610270575f5ffd5b5061024f61027f366004611a63565b6107b7565b34801561028f575f5ffd5b5061024f610815565b3480156102a3575f5ffd5b5061024f6102b2366004611aa4565b61082a565b61024f6102c5366004611b22565b610a60565b3480156102d5575f5ffd5b506101ef610a7f565b3480156102e9575f5ffd5b507fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff16610160565b34801561031f575f5ffd5b5061024f610aad565b348015610333575f5ffd5b50610160610342366004611a63565b5f9182527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020908152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b3480156103a3575f5ffd5b506101ef5f81565b3480156103b6575f5ffd5b506103f36040518060400160405280600581526020017f352e302e3000000000000000000000000000000000000000000000000000000081525081565b60405161016c9190611c23565b34801561040b575f5ffd5b5061024f61041a366004611c76565b610abf565b34801561042a575f5ffd5b5061024f610439366004611a63565b610cf5565b348015610449575f5ffd5b506101ef7f64b4740f54156feb06b7a9f424e5bce966a52344cf27635887cf63c0ebf2a61e81565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b00000000000000000000000000000000000000000000000000000000148061050357507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b7f6ad1a01bf62225c91223b2956030efc848b0def7d19ed478ca6dd31490e2d00080546060915f9115801561053c575083155b156105b257604080515f80825260208201909252906105a7565b604080516080810182525f8082526020808301829052928201819052606082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816105565790505b50945f945092505050565b805484106105ec576040517fea61fe7000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6106026105fb603287611cbc565b8354610d38565b905061060e8582611ccf565b67ffffffffffffffff81111561062657610626611af5565b60405190808252806020026020018201604052801561069557816020015b604080516080810182525f8082526020808301829052928201819052606082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816106445790505b5093505f5b845181101561076257826106ae8288611cbc565b815481106106be576106be611ce2565b5f91825260209182902060408051608081018252929091015467ffffffffffffffff80821684526801000000000000000082048116948401949094527001000000000000000000000000000000008104841691830191909152780100000000000000000000000000000000000000000000000090049091166060820152855186908390811061074f5761074f611ce2565b602090810291909101015260010161069a565b50905492949211925050565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b62680060205260409020600101546107a781610d4f565b6107b18383610d59565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610806576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108108282610e77565b505050565b5f61081f81610d4f565b610827610f53565b50565b7f64b4740f54156feb06b7a9f424e5bce966a52344cf27635887cf63c0ebf2a61e61085481610d4f565b7f6ad1a01bf62225c91223b2956030efc848b0def7d19ed478ca6dd31490e2d0008054158015906108d957508054819061089090600190611ccf565b815481106108a0576108a0611ce2565b5f9182526020909120015467ffffffffffffffff7801000000000000000000000000000000000000000000000000909104811690841611155b15610910576040517fb290253c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516080808201835267ffffffffffffffff89811680845289821660208086018281528b85168789018181528c87166060808b018281528d54600181018f555f8f81528890209c519c0180549651945191518b1678010000000000000000000000000000000000000000000000000277ffffffffffffffffffffffffffffffffffffffffffffffff928c1670010000000000000000000000000000000002929092166fffffffffffffffffffffffffffffffff958c1668010000000000000000027fffffffffffffffffffffffffffffffff000000000000000000000000000000009098169d909b169c909c179590951792909216979097179290921790975587519384529083019190915294810193909352928201929092527f3bff7b1e021b47f5dfd21d1d3fe2daaf3b9cbaca733c6e15b3a0da546657f19a91015b60405180910390a1505050505050565b610a68610ff0565b610a71826110f6565b610a7b828261119f565b5050565b5f610a886112dd565b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b5f610ab781610d4f565b61082761134c565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff165f81158015610b095750825b90505f8267ffffffffffffffff166001148015610b255750303b155b905081158015610b33575080155b15610b6a576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001660011785558315610bcb5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b73ffffffffffffffffffffffffffffffffffffffff8616610c18576040517f3ef39b8100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c206113c5565b610c286113c5565b610c306113cd565b610c5a7f64b4740f54156feb06b7a9f424e5bce966a52344cf27635887cf63c0ebf2a61e5f6113dd565b610c645f87610d59565b50610c8f7f64b4740f54156feb06b7a9f424e5bce966a52344cf27635887cf63c0ebf2a61e87610d59565b508315610ced5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602001610a50565b505050505050565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020526040902060010154610d2e81610d4f565b6107b18383610e77565b5f818310610d465781610d48565b825b9392505050565b610827813361147e565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020818152604080842073ffffffffffffffffffffffffffffffffffffffff8616855290915282205460ff16610e6e575f8481526020828152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055610e0a3390565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a46001915050610503565b5f915050610503565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020818152604080842073ffffffffffffffffffffffffffffffffffffffff8616855290915282205460ff1615610e6e575f8481526020828152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a46001915050610503565b610f5b611524565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a150565b3073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614806110bd57507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166110a47f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1614155b156110f4576040517fe07c8dba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b5f61110081610d4f565b73ffffffffffffffffffffffffffffffffffffffff821661114d576040517fd02c623d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805133815273ffffffffffffffffffffffffffffffffffffffff841660208201527fd30e1d298bf814ea43d22b4ce8298062b08609cd67496483769d836157dd52fa910160405180910390a15050565b8173ffffffffffffffffffffffffffffffffffffffff166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611224575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261122191810190611d0f565b60015b611277576040517f4c9c8ce300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff831660048201526024015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc81146112d3576040517faa1d49a40000000000000000000000000000000000000000000000000000000081526004810182905260240161126e565b610810838361157f565b3073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146110f4576040517fe07c8dba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6113546115e1565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833610fc5565b6110f461163d565b6113d561163d565b6110f46116a4565b7f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268005f611436845f9081527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052604090206001015490565b5f85815260208490526040808220600101869055519192508491839187917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a450505050565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268006020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610a7b576040517fe2517d3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024810183905260440161126e565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff166110f4576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611588826116f5565b60405173ffffffffffffffffffffffffffffffffffffffff8316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a28051156115d95761081082826117c3565b610a7b611842565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff16156110f4576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff166110f4576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6116ac61163d565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f0330080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b8073ffffffffffffffffffffffffffffffffffffffff163b5f0361175d576040517f4c9c8ce300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260240161126e565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60605f5f8473ffffffffffffffffffffffffffffffffffffffff16846040516117ec9190611d26565b5f60405180830381855af49150503d805f8114611824576040519150601f19603f3d011682016040523d82523d5f602084013e611829565b606091505b509150915061183985838361187a565b95945050505050565b34156110f4576040517fb398979f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608261188f5761188a82611909565b610d48565b81511580156118b3575073ffffffffffffffffffffffffffffffffffffffff84163b155b15611902576040517f9996b31500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015260240161126e565b5092915050565b8051156119195780518082602001fd5b6040517fd6bda27500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6020828403121561195b575f5ffd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610d48575f5ffd5b5f6020828403121561199a575f5ffd5b5035919050565b604080825283519082018190525f9060208501906060840190835b81811015611a2857835167ffffffffffffffff815116845267ffffffffffffffff602082015116602085015267ffffffffffffffff604082015116604085015267ffffffffffffffff6060820151166060850152506080830192506020840193506001810190506119bc565b505084151560208501529150610d489050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611a5e575f5ffd5b919050565b5f5f60408385031215611a74575f5ffd5b82359150611a8460208401611a3b565b90509250929050565b803567ffffffffffffffff81168114611a5e575f5ffd5b5f5f5f5f60808587031215611ab7575f5ffd5b611ac085611a8d565b9350611ace60208601611a8d565b9250611adc60408601611a8d565b9150611aea60608601611a8d565b905092959194509250565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f5f60408385031215611b33575f5ffd5b611b3c83611a3b565b9150602083013567ffffffffffffffff811115611b57575f5ffd5b8301601f81018513611b67575f5ffd5b803567ffffffffffffffff811115611b8157611b81611af5565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff82111715611bed57611bed611af5565b604052818152828201602001871015611c04575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505092915050565b5f60208284031215611c86575f5ffd5b610d4882611a3b565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8082018082111561050357610503611c8f565b8181038181111561050357610503611c8f565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f60208284031215611d1f575f5ffd5b5051919050565b5f82518060208501845e5f92019182525091905056fea2646970667358221220d3aa48445f0d099a9bca4f5102cc9670e7586b2ad3a3367766854a893fcf5f6164736f6c634300081c0033", } // RatesManagerABI is the input ABI used to generate the binding from. @@ -241,6 +241,37 @@ func (_RatesManager *RatesManagerCallerSession) DEFAULTADMINROLE() ([32]byte, er return _RatesManager.Contract.DEFAULTADMINROLE(&_RatesManager.CallOpts) } +// PAGESIZE is a free data retrieval call binding the contract method 0x31b28664. +// +// Solidity: function PAGE_SIZE() view returns(uint256) +func (_RatesManager *RatesManagerCaller) PAGESIZE(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _RatesManager.contract.Call(opts, &out, "PAGE_SIZE") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// PAGESIZE is a free data retrieval call binding the contract method 0x31b28664. +// +// Solidity: function PAGE_SIZE() view returns(uint256) +func (_RatesManager *RatesManagerSession) PAGESIZE() (*big.Int, error) { + return _RatesManager.Contract.PAGESIZE(&_RatesManager.CallOpts) +} + +// PAGESIZE is a free data retrieval call binding the contract method 0x31b28664. +// +// Solidity: function PAGE_SIZE() view returns(uint256) +func (_RatesManager *RatesManagerCallerSession) PAGESIZE() (*big.Int, error) { + return _RatesManager.Contract.PAGESIZE(&_RatesManager.CallOpts) +} + // RATESMANAGERROLE is a free data retrieval call binding the contract method 0xe3396735. // // Solidity: function RATES_MANAGER_ROLE() view returns(bytes32) @@ -350,7 +381,7 @@ func (_RatesManager *RatesManagerCallerSession) GetRates(fromIndex *big.Int) (st // GetRatesCount is a free data retrieval call binding the contract method 0x2da72291. // -// Solidity: function getRatesCount() view returns(uint256) +// Solidity: function getRatesCount() view returns(uint256 count) func (_RatesManager *RatesManagerCaller) GetRatesCount(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} err := _RatesManager.contract.Call(opts, &out, "getRatesCount") @@ -367,14 +398,14 @@ func (_RatesManager *RatesManagerCaller) GetRatesCount(opts *bind.CallOpts) (*bi // GetRatesCount is a free data retrieval call binding the contract method 0x2da72291. // -// Solidity: function getRatesCount() view returns(uint256) +// Solidity: function getRatesCount() view returns(uint256 count) func (_RatesManager *RatesManagerSession) GetRatesCount() (*big.Int, error) { return _RatesManager.Contract.GetRatesCount(&_RatesManager.CallOpts) } // GetRatesCount is a free data retrieval call binding the contract method 0x2da72291. // -// Solidity: function getRatesCount() view returns(uint256) +// Solidity: function getRatesCount() view returns(uint256 count) func (_RatesManager *RatesManagerCallerSession) GetRatesCount() (*big.Int, error) { return _RatesManager.Contract.GetRatesCount(&_RatesManager.CallOpts) } From b679ec65058b81b8845b2f285e478adc968470c3 Mon Sep 17 00:00:00 2001 From: Borja Aranda Date: Fri, 14 Mar 2025 14:21:09 +0100 Subject: [PATCH 18/24] make slither happy --- contracts/src/Payer.sol | 81 ++++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 38 deletions(-) diff --git a/contracts/src/Payer.sol b/contracts/src/Payer.sol index bf4b17a9..c711787c 100644 --- a/contracts/src/Payer.sol +++ b/contracts/src/Payer.sol @@ -73,11 +73,12 @@ contract Payer is } // keccak256(abi.encode(uint256(keccak256("xmtp.storage.Payer")) - 1)) & ~bytes32(uint256(0xff)) - bytes32 internal constant PayerStorageLocation = 0xd0335f337c570f3417b0f0d20340c88da711d60e810b5e9b3ecabe9ccfcdce5a; + bytes32 internal constant PAYER_STORAGE_LOCATION = 0xd0335f337c570f3417b0f0d20340c88da711d60e810b5e9b3ecabe9ccfcdce5a; function _getPayerStorage() internal pure returns (PayerStorage storage $) { + // slither-disable-next-line assembly assembly { - $.slot := PayerStorageLocation + $.slot := PAYER_STORAGE_LOCATION } } @@ -116,13 +117,13 @@ contract Payer is /** * @notice Initializes the contract with the deployer as admin. - * @param _initialAdmin The address of the admin. + * @param initialAdmin The address of the admin. * @dev There's a chicken-egg problem here with PayerReport and Distribution contracts. * We need to deploy these contracts first, then set their addresses * in the Payer contract. */ - function initialize(address _initialAdmin, address _usdcToken, address _nodesContract) public initializer { - if (_initialAdmin == address(0) || _usdcToken == address(0) || _nodesContract == address(0)) { + function initialize(address initialAdmin, address usdcToken, address nodesContract) public initializer { + if (initialAdmin == address(0) || usdcToken == address(0) || nodesContract == address(0)) { revert InvalidAddress(); } @@ -138,11 +139,11 @@ contract Payer is $.maxTolerableDebtAmountMicroDollars = DEFAULT_MAX_TOLERABLE_DEBT_AMOUNT_MICRO_DOLLARS; $.transferFeesPeriod = DEFAULT_MINIMUM_TRANSFER_FEES_PERIOD; - _setUsdcTokenContract(_usdcToken); - _setNodesContract(_nodesContract); + _setUsdcTokenContract(usdcToken); + _setNodesContract(nodesContract); - require(_grantRole(DEFAULT_ADMIN_ROLE, _initialAdmin), FailedToGrantRole(DEFAULT_ADMIN_ROLE, _initialAdmin)); - require(_grantRole(ADMIN_ROLE, _initialAdmin), FailedToGrantRole(ADMIN_ROLE, _initialAdmin)); + require(_grantRole(DEFAULT_ADMIN_ROLE, initialAdmin), FailedToGrantRole(DEFAULT_ADMIN_ROLE, initialAdmin)); + require(_grantRole(ADMIN_ROLE, initialAdmin), FailedToGrantRole(ADMIN_ROLE, initialAdmin)); } /* ============ Payers Management ============ */ @@ -394,7 +395,12 @@ contract Payer is function transferFeesToDistribution() external whenNotPaused nonReentrant { PayerStorage storage $ = _getPayerStorage(); + /// @dev slither marks this as a security issue because validators can modify block.timestamp. + /// However, in this scenario it's fine, as we'd just send fees a earlier than expected. + /// It would be a bigger issue if we'd rely on timestamp for randomness or calculations. + // slither-disable-next-line timestamp require(block.timestamp - $.lastFeeTransferTimestamp >= $.transferFeesPeriod, InsufficientTimePassed()); + require($.pendingFees > 0, InsufficientAmount()); uint256 feesToTransfer = $.pendingFees; @@ -413,105 +419,104 @@ contract Payer is /** * @inheritdoc IPayer */ - function setDistributionContract(address _newDistributionContract) external onlyRole(ADMIN_ROLE) { - _setDistributionContract(_newDistributionContract); + function setDistributionContract(address newDistributionContract) external onlyRole(ADMIN_ROLE) { + _setDistributionContract(newDistributionContract); } /** * @inheritdoc IPayer */ - function setPayerReportContract(address _newPayerReportContract) external onlyRole(ADMIN_ROLE) { - _setPayerReportContract(_newPayerReportContract); + function setPayerReportContract(address newPayerReportContract) external onlyRole(ADMIN_ROLE) { + _setPayerReportContract(newPayerReportContract); } /** * @inheritdoc IPayer */ - function setNodesContract(address _newNodesContract) external onlyRole(ADMIN_ROLE) { - _setNodesContract(_newNodesContract); + function setNodesContract(address newNodesContract) external onlyRole(ADMIN_ROLE) { + _setNodesContract(newNodesContract); } /** * @inheritdoc IPayer */ - function setUsdcToken(address _newUsdcToken) external onlyRole(ADMIN_ROLE) { - _setUsdcTokenContract(_newUsdcToken); + function setUsdcToken(address newUsdcToken) external onlyRole(ADMIN_ROLE) { + _setUsdcTokenContract(newUsdcToken); } /** * @inheritdoc IPayer */ - function setMinimumDeposit(uint64 _newMinimumDeposit) external onlyRole(ADMIN_ROLE) { - require(_newMinimumDeposit > DEFAULT_MINIMUM_DEPOSIT_AMOUNT_MICRO_DOLLARS, InvalidMinimumDeposit()); + function setMinimumDeposit(uint64 newMinimumDeposit) external onlyRole(ADMIN_ROLE) { + require(newMinimumDeposit > DEFAULT_MINIMUM_DEPOSIT_AMOUNT_MICRO_DOLLARS, InvalidMinimumDeposit()); PayerStorage storage $ = _getPayerStorage(); uint256 oldMinimumDeposit = $.minimumDepositAmountMicroDollars; - $.minimumDepositAmountMicroDollars = _newMinimumDeposit; + $.minimumDepositAmountMicroDollars = newMinimumDeposit; - emit MinimumDepositSet(oldMinimumDeposit, _newMinimumDeposit); + emit MinimumDepositSet(oldMinimumDeposit, newMinimumDeposit); } /** * @inheritdoc IPayer */ - function setMinimumRegistrationAmount(uint64 _newMinimumRegistrationAmount) external onlyRole(ADMIN_ROLE) { + function setMinimumRegistrationAmount(uint64 newMinimumRegistrationAmount) external onlyRole(ADMIN_ROLE) { require( - _newMinimumRegistrationAmount > DEFAULT_MINIMUM_REGISTRATION_AMOUNT_MICRO_DOLLARS, + newMinimumRegistrationAmount > DEFAULT_MINIMUM_REGISTRATION_AMOUNT_MICRO_DOLLARS, InvalidMinimumRegistrationAmount() ); PayerStorage storage $ = _getPayerStorage(); uint256 oldMinimumRegistrationAmount = $.minimumRegistrationAmountMicroDollars; - $.minimumRegistrationAmountMicroDollars = _newMinimumRegistrationAmount; + $.minimumRegistrationAmountMicroDollars = newMinimumRegistrationAmount; - emit MinimumRegistrationAmountSet(oldMinimumRegistrationAmount, _newMinimumRegistrationAmount); + emit MinimumRegistrationAmountSet(oldMinimumRegistrationAmount, newMinimumRegistrationAmount); } /** * @inheritdoc IPayer */ - function setWithdrawalLockPeriod(uint32 _newWithdrawalLockPeriod) external onlyRole(ADMIN_ROLE) { - require(_newWithdrawalLockPeriod >= ABSOLUTE_MINIMUM_WITHDRAWAL_LOCK_PERIOD, InvalidWithdrawalLockPeriod()); + function setWithdrawalLockPeriod(uint32 newWithdrawalLockPeriod) external onlyRole(ADMIN_ROLE) { + require(newWithdrawalLockPeriod >= ABSOLUTE_MINIMUM_WITHDRAWAL_LOCK_PERIOD, InvalidWithdrawalLockPeriod()); PayerStorage storage $ = _getPayerStorage(); uint256 oldWithdrawalLockPeriod = $.withdrawalLockPeriod; - $.withdrawalLockPeriod = _newWithdrawalLockPeriod; + $.withdrawalLockPeriod = newWithdrawalLockPeriod; - emit WithdrawalLockPeriodSet(oldWithdrawalLockPeriod, _newWithdrawalLockPeriod); + emit WithdrawalLockPeriodSet(oldWithdrawalLockPeriod, newWithdrawalLockPeriod); } /** * @inheritdoc IPayer */ - function setMaxTolerableDebtAmount(uint64 _newMaxTolerableDebtAmountMicroDollars) external onlyRole(ADMIN_ROLE) { - require(_newMaxTolerableDebtAmountMicroDollars > 0, InvalidMaxTolerableDebtAmount()); + function setMaxTolerableDebtAmount(uint64 newMaxTolerableDebtAmountMicroDollars) external onlyRole(ADMIN_ROLE) { + require(newMaxTolerableDebtAmountMicroDollars > 0, InvalidMaxTolerableDebtAmount()); PayerStorage storage $ = _getPayerStorage(); uint64 oldMaxTolerableDebtAmount = $.maxTolerableDebtAmountMicroDollars; - $.maxTolerableDebtAmountMicroDollars = _newMaxTolerableDebtAmountMicroDollars; + $.maxTolerableDebtAmountMicroDollars = newMaxTolerableDebtAmountMicroDollars; - emit MaxTolerableDebtAmountSet(oldMaxTolerableDebtAmount, _newMaxTolerableDebtAmountMicroDollars); + emit MaxTolerableDebtAmountSet(oldMaxTolerableDebtAmount, newMaxTolerableDebtAmountMicroDollars); } /** * @inheritdoc IPayer */ - function setTransferFeesPeriod(uint32 _newTransferFeesPeriod) external onlyRole(ADMIN_ROLE) { - require(_newTransferFeesPeriod >= ABSOLUTE_MINIMUM_TRANSFER_FEES_PERIOD, InvalidTransferFeesPeriod()); + function setTransferFeesPeriod(uint32 newTransferFeesPeriod) external onlyRole(ADMIN_ROLE) { + require(newTransferFeesPeriod >= ABSOLUTE_MINIMUM_TRANSFER_FEES_PERIOD, InvalidTransferFeesPeriod()); PayerStorage storage $ = _getPayerStorage(); uint32 oldTransferFeesPeriod = $.transferFeesPeriod; - $.transferFeesPeriod = _newTransferFeesPeriod; + $.transferFeesPeriod = newTransferFeesPeriod; - emit TransferFeesPeriodSet(oldTransferFeesPeriod, _newTransferFeesPeriod); + emit TransferFeesPeriodSet(oldTransferFeesPeriod, newTransferFeesPeriod); } - /** * @inheritdoc IPayer */ From adeb468bc0589b1e12e87b6047f24d9ae49feaae Mon Sep 17 00:00:00 2001 From: Francisco de Borja Aranda Castillejo Date: Mon, 17 Mar 2025 10:14:43 +0100 Subject: [PATCH 19/24] Add IL2Distribution interface (#636) Summary -- - Add a first naive IDistribution interface to pass to Payer. This interface is close to what we want but might change during implementation. - Fix supportsInterface function in Nodes and Payer. - Minor restyling: temporary or memory vars are prefixed by _, storage vars prefixed by $, function params doesn't have prefixes. ## Summary by CodeRabbit - **New Features** - Introduced a new mechanism to retrieve a maximum value and emit notifications when active node limits change. - Enhanced interface support to ensure smoother interactions and compliance with evolving standards. - Added a dedicated interface for reward distribution and administrative management, facilitating parameter updates and state inquiries. - **Refactor** - Improved code clarity with consistent import organization and refined naming conventions for better maintainability. --- contracts/pkg/nodes/Nodes.go | 2 +- contracts/src/Nodes.sol | 4 +- contracts/src/Payer.sol | 224 ++++++++++--------- contracts/src/interfaces/IL2Distribution.sol | 103 +++++++++ 4 files changed, 227 insertions(+), 106 deletions(-) create mode 100644 contracts/src/interfaces/IL2Distribution.sol diff --git a/contracts/pkg/nodes/Nodes.go b/contracts/pkg/nodes/Nodes.go index 01e6e904..86c26b03 100644 --- a/contracts/pkg/nodes/Nodes.go +++ b/contracts/pkg/nodes/Nodes.go @@ -48,7 +48,7 @@ type INodesNodeWithId struct { // NodesMetaData contains all meta data concerning the Nodes contract. var NodesMetaData = &bind.MetaData{ ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"initialAdmin\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"ADMIN_ROLE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"DEFAULT_ADMIN_ROLE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MAX_BPS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"NODE_INCREMENT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"NODE_MANAGER_ROLE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"acceptDefaultAdminTransfer\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"addNode\",\"inputs\":[{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"signingKeyPub\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"minMonthlyFeeMicroDollars\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"approve\",\"inputs\":[{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"balanceOf\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"beginDefaultAdminTransfer\",\"inputs\":[{\"name\":\"newAdmin\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"cancelDefaultAdminTransfer\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"changeDefaultAdminDelay\",\"inputs\":[{\"name\":\"newDelay\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"defaultAdmin\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"defaultAdminDelay\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"defaultAdminDelayIncreaseWait\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"disableNode\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"enableNode\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"getActiveApiNodes\",\"inputs\":[],\"outputs\":[{\"name\":\"activeNodes\",\"type\":\"tuple[]\",\"internalType\":\"structINodes.NodeWithId[]\",\"components\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"node\",\"type\":\"tuple\",\"internalType\":\"structINodes.Node\",\"components\":[{\"name\":\"signingKeyPub\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"isReplicationEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isApiEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isDisabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"minMonthlyFeeMicroDollars\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getActiveApiNodesCount\",\"inputs\":[],\"outputs\":[{\"name\":\"activeNodesCount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getActiveApiNodesIDs\",\"inputs\":[],\"outputs\":[{\"name\":\"activeNodesIDs\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getActiveReplicationNodes\",\"inputs\":[],\"outputs\":[{\"name\":\"activeNodes\",\"type\":\"tuple[]\",\"internalType\":\"structINodes.NodeWithId[]\",\"components\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"node\",\"type\":\"tuple\",\"internalType\":\"structINodes.Node\",\"components\":[{\"name\":\"signingKeyPub\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"isReplicationEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isApiEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isDisabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"minMonthlyFeeMicroDollars\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getActiveReplicationNodesCount\",\"inputs\":[],\"outputs\":[{\"name\":\"activeNodesCount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getActiveReplicationNodesIDs\",\"inputs\":[],\"outputs\":[{\"name\":\"activeNodesIDs\",\"type\":\"uint256[]\",\"internalType\":\"uint256[]\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getAllNodes\",\"inputs\":[],\"outputs\":[{\"name\":\"allNodes\",\"type\":\"tuple[]\",\"internalType\":\"structINodes.NodeWithId[]\",\"components\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"node\",\"type\":\"tuple\",\"internalType\":\"structINodes.Node\",\"components\":[{\"name\":\"signingKeyPub\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"isReplicationEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isApiEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isDisabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"minMonthlyFeeMicroDollars\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getAllNodesCount\",\"inputs\":[],\"outputs\":[{\"name\":\"nodeCount\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getApiNodeIsActive\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"isActive\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getApproved\",\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getNode\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"node\",\"type\":\"tuple\",\"internalType\":\"structINodes.Node\",\"components\":[{\"name\":\"signingKeyPub\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"isReplicationEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isApiEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"isDisabled\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"minMonthlyFeeMicroDollars\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getNodeOperatorCommissionPercent\",\"inputs\":[],\"outputs\":[{\"name\":\"commissionPercent\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getReplicationNodeIsActive\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"isActive\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRoleAdmin\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"grantRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"hasRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"isApprovedForAll\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"maxActiveNodes\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"name\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"nodeOperatorCommissionPercent\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"ownerOf\",\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pendingDefaultAdmin\",\"inputs\":[],\"outputs\":[{\"name\":\"newAdmin\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"schedule\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"pendingDefaultAdminDelay\",\"inputs\":[],\"outputs\":[{\"name\":\"newDelay\",\"type\":\"uint48\",\"internalType\":\"uint48\"},{\"name\":\"schedule\",\"type\":\"uint48\",\"internalType\":\"uint48\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"removeFromApiNodes\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"removeFromReplicationNodes\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"renounceRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"revokeRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"rollbackDefaultAdminDelay\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"safeTransferFrom\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"safeTransferFrom\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"data\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setApprovalForAll\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"approved\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setBaseURI\",\"inputs\":[{\"name\":\"newBaseURI\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setHttpAddress\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"internalType\":\"string\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setIsApiEnabled\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"isApiEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setIsReplicationEnabled\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"isReplicationEnabled\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setMaxActiveNodes\",\"inputs\":[{\"name\":\"newMaxActiveNodes\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setMinMonthlyFee\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"minMonthlyFeeMicroDollars\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setNodeOperatorCommissionPercent\",\"inputs\":[{\"name\":\"newCommissionPercent\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"supportsInterface\",\"inputs\":[{\"name\":\"interfaceId\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"}],\"outputs\":[{\"name\":\"supported\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"symbol\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"tokenURI\",\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"transferFrom\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"nodeId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"ApiDisabled\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ApiEnabled\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Approval\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"approved\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ApprovalForAll\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"operator\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"approved\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"BaseURIUpdated\",\"inputs\":[{\"name\":\"newBaseURI\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DefaultAdminDelayChangeCanceled\",\"inputs\":[],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DefaultAdminDelayChangeScheduled\",\"inputs\":[{\"name\":\"newDelay\",\"type\":\"uint48\",\"indexed\":false,\"internalType\":\"uint48\"},{\"name\":\"effectSchedule\",\"type\":\"uint48\",\"indexed\":false,\"internalType\":\"uint48\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DefaultAdminTransferCanceled\",\"inputs\":[],\"anonymous\":false},{\"type\":\"event\",\"name\":\"DefaultAdminTransferScheduled\",\"inputs\":[{\"name\":\"newAdmin\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"acceptSchedule\",\"type\":\"uint48\",\"indexed\":false,\"internalType\":\"uint48\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"HttpAddressUpdated\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"newHttpAddress\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"MaxActiveNodesUpdated\",\"inputs\":[{\"name\":\"newMaxActiveNodes\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"MinMonthlyFeeUpdated\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"minMonthlyFeeMicroDollars\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NodeAdded\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"owner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"signingKeyPub\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"},{\"name\":\"httpAddress\",\"type\":\"string\",\"indexed\":false,\"internalType\":\"string\"},{\"name\":\"minMonthlyFeeMicroDollars\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NodeDisabled\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NodeEnabled\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NodeOperatorCommissionPercentUpdated\",\"inputs\":[{\"name\":\"newCommissionPercent\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"NodeTransferred\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"from\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ReplicationDisabled\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"ReplicationEnabled\",\"inputs\":[{\"name\":\"nodeId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleAdminChanged\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"previousAdminRole\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"newAdminRole\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleGranted\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleRevoked\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Transfer\",\"inputs\":[{\"name\":\"from\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"to\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AccessControlBadConfirmation\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"AccessControlEnforcedDefaultAdminDelay\",\"inputs\":[{\"name\":\"schedule\",\"type\":\"uint48\",\"internalType\":\"uint48\"}]},{\"type\":\"error\",\"name\":\"AccessControlEnforcedDefaultAdminRules\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"AccessControlInvalidDefaultAdmin\",\"inputs\":[{\"name\":\"defaultAdmin\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"AccessControlUnauthorizedAccount\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"neededRole\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"ERC721IncorrectOwner\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721InsufficientApproval\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"ERC721InvalidApprover\",\"inputs\":[{\"name\":\"approver\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721InvalidOperator\",\"inputs\":[{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721InvalidOwner\",\"inputs\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721InvalidReceiver\",\"inputs\":[{\"name\":\"receiver\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721InvalidSender\",\"inputs\":[{\"name\":\"sender\",\"type\":\"address\",\"internalType\":\"address\"}]},{\"type\":\"error\",\"name\":\"ERC721NonexistentToken\",\"inputs\":[{\"name\":\"tokenId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"InvalidAddress\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidCommissionPercent\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidHttpAddress\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidInputLength\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidNodeConfig\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidSigningKey\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidURI\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"MaxActiveNodesBelowCurrentCount\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"MaxActiveNodesReached\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NodeDoesNotExist\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NodeIsDisabled\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"SafeCastOverflowedUintDowncast\",\"inputs\":[{\"name\":\"bits\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"value\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"Unauthorized\",\"inputs\":[]}]", - Bin: "0x6080604052600a805464ffffffffff19166014179055348015610020575f5ffd5b506040516146eb3803806146eb83398101604081905261003f91610317565b60408051808201825260128152712c26aa28102737b2329027b832b930ba37b960711b602080830191909152825180840190935260048352630584d54560e41b90830152906202a300836001600160a01b0381166100b657604051636116401160e11b81525f600482015260240160405180910390fd5b600180546001600160d01b0316600160d01b65ffffffffffff8516021790556100df5f8261018b565b50600391506100f0905083826103dc565b5060046100fd82826103dc565b5050506001600160a01b0381166101275760405163e6c4247b60e01b815260040160405180910390fd5b61013e5f5160206146cb5f395f51905f525f6101fa565b6101555f5160206146ab5f395f51905f525f6101fa565b61016c5f5160206146cb5f395f51905f528261018b565b506101845f5160206146ab5f395f51905f528261018b565b5050610496565b5f826101e7575f6101a46002546001600160a01b031690565b6001600160a01b0316146101cb57604051631fe1e13d60e11b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0384161790555b6101f18383610226565b90505b92915050565b8161021857604051631fe1e13d60e11b815260040160405180910390fd5b61022282826102cd565b5050565b5f828152602081815260408083206001600160a01b038516845290915281205460ff166102c6575f838152602081815260408083206001600160a01b03861684529091529020805460ff1916600117905561027e3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016101f4565b505f6101f4565b5f82815260208190526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b5f60208284031215610327575f5ffd5b81516001600160a01b038116811461033d575f5ffd5b9392505050565b634e487b7160e01b5f52604160045260245ffd5b600181811c9082168061036c57607f821691505b60208210810361038a57634e487b7160e01b5f52602260045260245ffd5b50919050565b601f8211156103d757805f5260205f20601f840160051c810160208510156103b55750805b601f840160051c820191505b818110156103d4575f81556001016103c1565b50505b505050565b81516001600160401b038111156103f5576103f5610344565b610409816104038454610358565b84610390565b6020601f82116001811461043b575f83156104245750848201515b5f19600385901b1c1916600184901b1784556103d4565b5f84815260208120601f198516915b8281101561046a578785015182556020948501946001909201910161044a565b508482101561048757868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b614208806104a35f395ff3fe608060405234801561000f575f5ffd5b5060043610610393575f3560e01c80638ed9ea34116101df578063ce99948911610109578063e18cb254116100a9578063f579d7e111610079578063f579d7e114610860578063fb1120e214610868578063fd667d1e14610870578063fd967f471461088d575f5ffd5b8063e18cb25414610801578063e985e9c514610814578063ebe487bf1461084f578063f3194a3914610857575f5ffd5b8063d547741f116100e4578063d547741f146107ac578063d59f9fe0146107bf578063d602b9fd146107e6578063d74a2a50146107ee575f5ffd5b8063ce99948914610752578063cefc142914610765578063cf6eefb71461076d575f5ffd5b8063a217fddf1161017f578063b9b140d61161014f578063b9b140d61461071c578063c4741f3114610724578063c87b56dd14610737578063cc8463c81461074a575f5ffd5b8063a217fddf146106dc578063a22cb465146106e3578063a835f88e146106f6578063b88d4fde14610709575f5ffd5b806395d89b41116101ba57806395d89b41146106865780639d32f9ba1461068e578063a1174e7d146106ad578063a1eda53c146106b5575f5ffd5b80638ed9ea34146106285780638fbbf6231461063b57806391d1485414610650575f5ffd5b806344ff624e116102c0578063649a5ec71161026057806379e0d58c1161023057806379e0d58c146105e957806384ef8ffc146105fc578063895620b71461060d5780638da5cb5b14610620575f5ffd5b8063649a5ec7146105895780636ec97bfc1461059c57806370a08231146105af57806375b238fc146105c2575f5ffd5b806355f804b31161029b57806355f804b31461053b578063634e93da1461054e5780636352211e14610561578063646453ba14610574575f5ffd5b806344ff624e146104f55780634f0f4aa91461050857806350d0215f14610528575f5ffd5b8063203ede77116103365780632f2ff15d116103065780632f2ff15d146104a957806336568abe146104bc5780633d2853fb146104cf57806342842e0e146104e2575f5ffd5b8063203ede771461044e57806321fbd7cb1461046157806323b872dd14610474578063248a9ca314610487575f5ffd5b8063081812fc11610371578063081812fc146103f0578063095ea7b31461041b5780630aa6220b1461043057806317e3b3a914610438575f5ffd5b806301ffc9a714610397578063022d63fb146103bf57806306fdde03146103db575b5f5ffd5b6103aa6103a53660046137ce565b610896565b60405190151581526020015b60405180910390f35b620697805b60405165ffffffffffff90911681526020016103b6565b6103e36108a6565b6040516103b69190613817565b6104036103fe366004613829565b610936565b6040516001600160a01b0390911681526020016103b6565b61042e61042936600461385b565b61095d565b005b61042e61096c565b610440610981565b6040519081526020016103b6565b61042e61045c366004613829565b610991565b6103aa61046f366004613829565b6109cd565b61042e610482366004613883565b6109d9565b610440610495366004613829565b5f9081526020819052604090206001015490565b61042e6104b73660046138bd565b610a66565b61042e6104ca3660046138bd565b610aa7565b61042e6104dd366004613829565b610b97565b61042e6104f0366004613883565b610c2b565b6103aa610503366004613829565b610c4a565b61051b610516366004613829565b610c56565b6040516103b6919061394f565b600a54610100900463ffffffff16610440565b61042e6105493660046139a6565b610e06565b61042e61055c3660046139e5565b610f53565b61040361056f366004613829565b610f66565b61057c610f70565b6040516103b691906139fe565b61042e610597366004613a40565b610f7c565b6104406105aa366004613a65565b610f8f565b6104406105bd3660046139e5565b61128b565b6104407fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177581565b61042e6105f7366004613829565b6112e9565b6002546001600160a01b0316610403565b61042e61061b366004613afc565b611325565b61040361134f565b61042e610636366004613b1d565b611362565b610643611432565b6040516103b69190613b3d565b6103aa61065e3660046138bd565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6103e3611684565b600a5461069b9060ff1681565b60405160ff90911681526020016103b6565b610643611693565b6106bd6118ed565b6040805165ffffffffffff9384168152929091166020830152016103b6565b6104405f81565b61042e6106f1366004613bd5565b611967565b61042e610704366004613829565b611972565b61042e610717366004613c2a565b611a20565b601054610440565b61042e610732366004613829565b611a3e565b6103e3610745366004613829565b611ad9565b6103c4611b3e565b61042e610760366004613d08565b611bdb565b61042e611c62565b600154604080516001600160a01b03831681527401000000000000000000000000000000000000000090920465ffffffffffff166020830152016103b6565b61042e6107ba3660046138bd565b611cb1565b6104407fdaf9ac3a6308052428e8806fd908cf472318416ed7d78b3f35dd94bbbafde56a81565b61042e611cf2565b61042e6107fc366004613d28565b611d04565b61042e61080f366004613afc565b611dca565b6103aa610822366004613d70565b6001600160a01b039182165f90815260086020908152604080832093909416825291909152205460ff1690565b610643611df4565b61044060105481565b610440612042565b61057c61204d565b610878606481565b60405163ffffffff90911681526020016103b6565b61044061271081565b5f6108a082612059565b92915050565b6060600380546108b590613d98565b80601f01602080910402602001604051908101604052809291908181526020018280546108e190613d98565b801561092c5780601f106109035761010080835404028352916020019161092c565b820191905f5260205f20905b81548152906001019060200180831161090f57829003601f168201915b5050505050905090565b5f610940826120fa565b505f828152600760205260409020546001600160a01b03166108a0565b61096882823361214b565b5050565b5f61097681612158565b61097e612162565b50565b5f61098c600e61216e565b905090565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217756109bb81612158565b6109c482612177565b610968826121c4565b5f6108a0600c83612218565b7fdaf9ac3a6308052428e8806fd908cf472318416ed7d78b3f35dd94bbbafde56a610a0381612158565b610a0c8261222f565b610a15826121c4565b610a208484846122a1565b826001600160a01b0316846001600160a01b0316837e80108bb11ee8badd8a48ff0b4585853d721b6e5ac7e3415f99413dac52be7260405160405180910390a450505050565b81610a9d576040517f3fc3c27a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109688282612356565b81158015610ac257506002546001600160a01b038281169116145b15610b8d576001546001600160a01b0381169074010000000000000000000000000000000000000000900465ffffffffffff1681151580610b09575065ffffffffffff8116155b80610b1c57504265ffffffffffff821610155b15610b62576040517f19ca5ebb00000000000000000000000000000000000000000000000000000000815265ffffffffffff821660048201526024015b60405180910390fd5b5050600180547fffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffff1690555b610968828261237a565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775610bc181612158565b610bca82612177565b5f828152600b602052604080822060020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff1690555183917ff044a2d72ef98b7636ca9d9f8c0fc60e24309bbb8d472fdecbbaca55fe166d0a91a25050565b610c4583838360405180602001604052805f815250611a20565b505050565b5f6108a0600e83612218565b6040805160c0810182526060808252602082018190525f92820183905281018290526080810182905260a0810191909152610c9082612177565b5f828152600b602052604090819020815160c08101909252805482908290610cb790613d98565b80601f0160208091040260200160405190810160405280929190818152602001828054610ce390613d98565b8015610d2e5780601f10610d0557610100808354040283529160200191610d2e565b820191905f5260205f20905b815481529060010190602001808311610d1157829003601f168201915b50505050508152602001600182018054610d4790613d98565b80601f0160208091040260200160405190810160405280929190818152602001828054610d7390613d98565b8015610dbe5780601f10610d9557610100808354040283529160200191610dbe565b820191905f5260205f20905b815481529060010190602001808311610da157829003601f168201915b5050509183525050600282015460ff80821615156020840152610100820481161515604084015262010000909104161515606082015260039091015460809091015292915050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775610e3081612158565b81610e67576040517f3ba0191100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f2f000000000000000000000000000000000000000000000000000000000000008383610e95600182613e16565b818110610ea457610ea4613e29565b9050013560f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614610f07576040517f3ba0191100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6009610f14838583613e9a565b507f6741b2fc379fad678116fe3d4d4b9a1a184ab53ba36b86ad0fa66340b1ab41ad8383604051610f46929190613f7d565b60405180910390a1505050565b5f610f5d81612158565b610968826123c6565b5f6108a0826120fa565b606061098c600c612438565b5f610f8681612158565b61096882612444565b5f7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775610fba81612158565b6001600160a01b038816610ffa576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b85611031576040517f8125403000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83611068576040517fcbd6898900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6064600a600181819054906101000a900463ffffffff1661108890613f90565b91906101000a81548163ffffffff021916908363ffffffff16021790556110af9190613fb4565b63ffffffff1691506040518060c0016040528088888080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250505090825250604080516020601f8901819004810282018101909252878152918101919088908890819084018382808284375f92018290525093855250505060208083018290526040808401839052606084018390526080909301879052858252600b905220815181906111689082613fd3565b506020820151600182019061117d9082613fd3565b50604082015160028201805460608501516080860151151562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff911515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff951515959095167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090931692909217939093179290921691909117905560a09091015160039091015561123688836124ac565b876001600160a01b0316827f663d98c1e2bdf874fcd4fadcdf16242719c434e099664a3eb574322b78bd7c5c898989898960405161127895949392919061408e565b60405180910390a3509695505050505050565b5f6001600160a01b0382166112ce576040517f89c62b640000000000000000000000000000000000000000000000000000000081525f6004820152602401610b59565b506001600160a01b03165f9081526006602052604090205490565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561131381612158565b61131c82612177565b6109688261222f565b61132e82612177565b6113378261253f565b61134082612590565b801561131c57610968826125df565b5f61098c6002546001600160a01b031690565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561138c81612158565b611396600c61216e565b8260ff1610806113b157506113ab600e61216e565b8260ff16105b156113e8576040517f39beadee00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a805460ff191660ff84169081179091556040519081527f6dd6623df488fb2b38fa153b12758a1b41c8e49e88025f8d9fb1eba1b8f1d821906020015b60405180910390a15050565b606061143e600e61216e565b67ffffffffffffffff81111561145657611456613bfd565b60405190808252806020026020018201604052801561148f57816020015b61147c613750565b8152602001906001900390816114745790505b5090505f5b61149e600e61216e565b8163ffffffff161015611680575f6114c0600e63ffffffff8085169061269c16565b90506040518060400160405280828152602001600b5f8481526020019081526020015f206040518060c00160405290815f820180546114fe90613d98565b80601f016020809104026020016040519081016040528092919081815260200182805461152a90613d98565b80156115755780601f1061154c57610100808354040283529160200191611575565b820191905f5260205f20905b81548152906001019060200180831161155857829003601f168201915b5050505050815260200160018201805461158e90613d98565b80601f01602080910402602001604051908101604052809291908181526020018280546115ba90613d98565b80156116055780601f106115dc57610100808354040283529160200191611605565b820191905f5260205f20905b8154815290600101906020018083116115e857829003601f168201915b5050509183525050600282015460ff80821615156020840152610100820481161515604084015262010000909104161515606082015260039091015460809091015290528351849063ffffffff851690811061166357611663613e29565b6020026020010181905250508061167990613f90565b9050611494565b5090565b6060600480546108b590613d98565b600a54606090610100900463ffffffff1667ffffffffffffffff8111156116bc576116bc613bfd565b6040519080825280602002602001820160405280156116f557816020015b6116e2613750565b8152602001906001900390816116da5790505b5090505f5b600a5463ffffffff61010090910481169082161015611680575f61171f8260016140c7565b61172a906064613fb4565b905060405180604001604052808263ffffffff168152602001600b5f8463ffffffff1681526020019081526020015f206040518060c00160405290815f8201805461177490613d98565b80601f01602080910402602001604051908101604052809291908181526020018280546117a090613d98565b80156117eb5780601f106117c2576101008083540402835291602001916117eb565b820191905f5260205f20905b8154815290600101906020018083116117ce57829003601f168201915b5050505050815260200160018201805461180490613d98565b80601f016020809104026020016040519081016040528092919081815260200182805461183090613d98565b801561187b5780601f106118525761010080835404028352916020019161187b565b820191905f5260205f20905b81548152906001019060200180831161185e57829003601f168201915b5050509183525050600282015460ff80821615156020840152610100820481161515604084015262010000909104161515606082015260039091015460809091015290528351849063ffffffff85169081106118d9576118d9613e29565b6020908102919091010152506001016116fa565b6002545f907a010000000000000000000000000000000000000000000000000000900465ffffffffffff16801515801561192f57504265ffffffffffff821610155b61193a575f5f61195f565b60025474010000000000000000000000000000000000000000900465ffffffffffff16815b915091509091565b6109683383836126a7565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561199c81612158565b6119a582612177565b5f828152600b6020526040902060020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff16620100001790556119e98261222f565b6119f2826121c4565b60405182907fa6c942fbe3ded4df132dc2c4adbb95359afebc3c361393a3d7217e3c310923e8905f90a25050565b611a2b8484846109d9565b611a38338585858561275e565b50505050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775611a6881612158565b612710821115611aa4576040517f47d3b04600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60108290556040518281527f6367530104bc8677601bbb2f410055f5144865bf130b2c7bed1af5ff39185eb090602001611426565b6060611ae4826120fa565b505f611aee612902565b90505f815111611b0c5760405180602001604052805f815250611b37565b80611b1684612911565b604051602001611b279291906140fa565b6040516020818303038152906040525b9392505050565b6002545f907a010000000000000000000000000000000000000000000000000000900465ffffffffffff168015158015611b7f57504265ffffffffffff8216105b611bb1576001547a010000000000000000000000000000000000000000000000000000900465ffffffffffff16611bd5565b60025474010000000000000000000000000000000000000000900465ffffffffffff165b91505090565b7fdaf9ac3a6308052428e8806fd908cf472318416ed7d78b3f35dd94bbbafde56a611c0581612158565b611c0e83612177565b5f838152600b6020526040908190206003018390555183907f27a815a14bf8281048d2768dcd6b695fbd4e98af4e3fb52d92c8c65384320d4a90611c559085815260200190565b60405180910390a2505050565b6001546001600160a01b0316338114611ca9576040517fc22c8022000000000000000000000000000000000000000000000000000000008152336004820152602401610b59565b61097e6129ae565b81611ce8576040517f3fc3c27a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109688282612a85565b5f611cfc81612158565b61097e612aa9565b7fdaf9ac3a6308052428e8806fd908cf472318416ed7d78b3f35dd94bbbafde56a611d2e81612158565b611d3784612177565b81611d6e576040517fcbd6898900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f848152600b60205260409020600101611d89838583613e9a565b50837f15c3eac3b34037e402127abd35c3804f49d489c361f5bb8ff237544f0dfff4ed8484604051611dbc929190613f7d565b60405180910390a250505050565b611dd382612177565b611ddc8261253f565b611de582612590565b80156109c45761096882612ab3565b6060611e00600c61216e565b67ffffffffffffffff811115611e1857611e18613bfd565b604051908082528060200260200182016040528015611e5157816020015b611e3e613750565b815260200190600190039081611e365790505b5090505f5b611e60600c61216e565b8163ffffffff161015611680575f611e82600c63ffffffff8085169061269c16565b90506040518060400160405280828152602001600b5f8481526020019081526020015f206040518060c00160405290815f82018054611ec090613d98565b80601f0160208091040260200160405190810160405280929190818152602001828054611eec90613d98565b8015611f375780601f10611f0e57610100808354040283529160200191611f37565b820191905f5260205f20905b815481529060010190602001808311611f1a57829003601f168201915b50505050508152602001600182018054611f5090613d98565b80601f0160208091040260200160405190810160405280929190818152602001828054611f7c90613d98565b8015611fc75780601f10611f9e57610100808354040283529160200191611fc7565b820191905f5260205f20905b815481529060010190602001808311611faa57829003601f168201915b5050509183525050600282015460ff80821615156020840152610100820481161515604084015262010000909104161515606082015260039091015460809091015290528351849063ffffffff851690811061202557612025613e29565b6020026020010181905250508061203b90613f90565b9050611e56565b5f61098c600c61216e565b606061098c600e612438565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f80ac58cd0000000000000000000000000000000000000000000000000000000014806120eb57507fffffffff0000000000000000000000000000000000000000000000000000000082167f5b5e139f00000000000000000000000000000000000000000000000000000000145b806108a057506108a082612b51565b5f818152600560205260408120546001600160a01b0316806108a0576040517f7e27328900000000000000000000000000000000000000000000000000000000815260048101849052602401610b59565b610c458383836001612ba6565b61097e8133612cf9565b61216c5f5f612d64565b565b5f6108a0825490565b5f818152600560205260409020546001600160a01b031661097e576040517f5e926f7100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6121cf600e82612eb0565b6121d65750565b5f818152600b6020526040808220600201805460ff191690555182917fa9837328431beea294d22d476aeafca23f85f320de41750a9b9c3ce28076180891a250565b5f8181526001830160205260408120541515611b37565b61223a600c82612eb0565b6122415750565b5f818152600b602052604080822060020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555182917f9e61606f143f77c9ef06d68819ce159e3b98756d8eb558b91db82c8ca42357f391a250565b6001600160a01b0382166122e3576040517f64a0ae920000000000000000000000000000000000000000000000000000000081525f6004820152602401610b59565b5f6122ef838333612ebb565b9050836001600160a01b0316816001600160a01b031614611a38576040517f64283d7b0000000000000000000000000000000000000000000000000000000081526001600160a01b0380861660048301526024820184905282166044820152606401610b59565b5f8281526020819052604090206001015461237081612158565b611a388383612fc5565b6001600160a01b03811633146123bc576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c45828261305c565b5f6123cf611b3e565b6123d8426130b0565b6123e2919061410e565b90506123ee82826130fb565b60405165ffffffffffff821681526001600160a01b038316907f3377dc44241e779dd06afab5b788a35ca5f3b778836e2990bdb26a2a4b2e5ed69060200160405180910390a25050565b60605f611b3783613189565b5f61244e826131e2565b612457426130b0565b612461919061410e565b905061246d8282612d64565b6040805165ffffffffffff8085168252831660208201527ff1038c18cf84a56e432fdbfaf746924b7ea511dfe03a6506a0ceba4888788d9b9101611426565b6001600160a01b0382166124ee576040517f64a0ae920000000000000000000000000000000000000000000000000000000081525f6004820152602401610b59565b5f6124fa83835f612ebb565b90506001600160a01b03811615610c45576040517f73c6ac6e0000000000000000000000000000000000000000000000000000000081525f6004820152602401610b59565b5f818152600b602052604090206002015462010000900460ff161561097e576040517fc40c6f6300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f818152600560205260409020546001600160a01b0316331461097e576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a5460ff166125ef600c61216e565b10612626576040517f950be9a500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612631600c82613229565b6126385750565b5f818152600b602052604080822060020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555182917f3cd0abf09f2e68bb82445a4d250b6a3e30b2b2c711b322e3f3817927a07da17391a250565b5f611b378383613234565b6001600160a01b0382166126f2576040517f5b08ba180000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610b59565b6001600160a01b038381165f81815260086020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0383163b156128fb576040517f150b7a020000000000000000000000000000000000000000000000000000000081526001600160a01b0384169063150b7a02906127b990889088908790879060040161412c565b6020604051808303815f875af19250505080156127f3575060408051601f3d908101601f191682019092526127f09181019061416c565b60015b612873573d808015612820576040519150601f19603f3d011682016040523d82523d5f602084013e612825565b606091505b5080515f0361286b576040517f64a0ae920000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401610b59565b805181602001fd5b7fffffffff0000000000000000000000000000000000000000000000000000000081167f150b7a0200000000000000000000000000000000000000000000000000000000146128f9576040517f64a0ae920000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401610b59565b505b5050505050565b6060600980546108b590613d98565b60605f61291d8361325a565b60010190505f8167ffffffffffffffff81111561293c5761293c613bfd565b6040519080825280601f01601f191660200182016040528015612966576020820181803683370190505b5090508181016020015b5f19017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a850494508461297057509392505050565b6001546001600160a01b0381169074010000000000000000000000000000000000000000900465ffffffffffff168015806129f157504265ffffffffffff821610155b15612a32576040517f19ca5ebb00000000000000000000000000000000000000000000000000000000815265ffffffffffff82166004820152602401610b59565b612a4d5f612a486002546001600160a01b031690565b61305c565b50612a585f83612fc5565b5050600180547fffffffffffff000000000000000000000000000000000000000000000000000016905550565b5f82815260208190526040902060010154612a9f81612158565b611a38838361305c565b61216c5f5f6130fb565b600a5460ff16612ac3600e61216e565b10612afa576040517f950be9a500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612b05600e82613229565b612b0c5750565b5f818152600b6020526040808220600201805460ff191660011790555182917fd9199c75487673396ebe8093e82e5cf7902ccfb90befe22763a8bc4c36b976d091a250565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f314987860000000000000000000000000000000000000000000000000000000014806108a057506108a08261333b565b8080612bba57506001600160a01b03821615155b15612cb2575f612bc9846120fa565b90506001600160a01b03831615801590612bf55750826001600160a01b0316816001600160a01b031614155b8015612c2657506001600160a01b038082165f9081526008602090815260408083209387168352929052205460ff16155b15612c68576040517fa9fbf51f0000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401610b59565b8115612cb05783856001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b50505f90815260076020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b5f828152602081815260408083206001600160a01b038516845290915290205460ff16610968576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401610b59565b6002547a010000000000000000000000000000000000000000000000000000900465ffffffffffff168015612e38574265ffffffffffff82161015612e0f576002546001805479ffffffffffffffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000090920465ffffffffffff167a01000000000000000000000000000000000000000000000000000002919091179055612e38565b6040517f2b1fa2edafe6f7b9e97c1a9e0c3660e645beb2dcaa2d45bdbf9beaf5472e1ec5905f90a15b50600280546001600160a01b03167401000000000000000000000000000000000000000065ffffffffffff9485160279ffffffffffffffffffffffffffffffffffffffffffffffffffff16177a0100000000000000000000000000000000000000000000000000009290931691909102919091179055565b5f611b3783836133d1565b5f828152600560205260408120546001600160a01b0390811690831615612ee757612ee78184866134bb565b6001600160a01b03811615612f2157612f025f855f5f612ba6565b6001600160a01b0381165f90815260066020526040902080545f190190555b6001600160a01b03851615612f4f576001600160a01b0385165f908152600660205260409020805460010190555b5f8481526005602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0389811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b5f82613052575f612fde6002546001600160a01b031690565b6001600160a01b03161461301e576040517f3fc3c27a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0384161790555b611b378383613551565b5f8215801561307857506002546001600160a01b038381169116145b156130a657600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555b611b3783836135f8565b5f65ffffffffffff821115611680576040517f6dfcc6500000000000000000000000000000000000000000000000000000000081526030600482015260248101839052604401610b59565b600180547401000000000000000000000000000000000000000065ffffffffffff84811682027fffffffffffff000000000000000000000000000000000000000000000000000084166001600160a01b03881617179093559004168015610c45576040517f8886ebfc4259abdbc16601dd8fb5678e54878f47b3c34836cfc51154a9605109905f90a1505050565b6060815f018054806020026020016040519081016040528092919081815260200182805480156131d657602002820191905f5260205f20905b8154815260200190600101908083116131c2575b50505050509050919050565b5f5f6131ec611b3e565b90508065ffffffffffff168365ffffffffffff16116132145761320f8382614187565b611b37565b611b3765ffffffffffff841662069780613679565b5f611b378383613688565b5f825f01828154811061324957613249613e29565b905f5260205f200154905092915050565b5f807a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000083106132a2577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef810000000083106132ce576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106132ec57662386f26fc10000830492506010015b6305f5e1008310613304576305f5e100830492506008015b612710831061331857612710830492506004015b6064831061332a576064830492506002015b600a83106108a05760010192915050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806108a057507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146108a0565b5f81815260018301602052604081205480156134ab575f6133f3600183613e16565b85549091505f9061340690600190613e16565b9050808214613465575f865f01828154811061342457613424613e29565b905f5260205f200154905080875f01848154811061344457613444613e29565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080613476576134766141a5565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f9055600193505050506108a0565b5f9150506108a0565b5092915050565b6134c68383836136cd565b610c45576001600160a01b03831661350d576040517f7e27328900000000000000000000000000000000000000000000000000000000815260048101829052602401610b59565b6040517f177e802f0000000000000000000000000000000000000000000000000000000081526001600160a01b038316600482015260248101829052604401610b59565b5f828152602081815260408083206001600160a01b038516845290915281205460ff166135f1575f838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556135a93390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016108a0565b505f6108a0565b5f828152602081815260408083206001600160a01b038516845290915281205460ff16156135f1575f838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45060016108a0565b5f828218828410028218611b37565b5f8181526001830160205260408120546135f157508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556108a0565b5f6001600160a01b038316158015906137485750826001600160a01b0316846001600160a01b0316148061372557506001600160a01b038085165f9081526008602090815260408083209387168352929052205460ff165b8061374857505f828152600760205260409020546001600160a01b038481169116145b949350505050565b60405180604001604052805f815260200161379c6040518060c0016040528060608152602001606081526020015f151581526020015f151581526020015f151581526020015f81525090565b905290565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461097e575f5ffd5b5f602082840312156137de575f5ffd5b8135611b37816137a1565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f611b3760208301846137e9565b5f60208284031215613839575f5ffd5b5035919050565b80356001600160a01b0381168114613856575f5ffd5b919050565b5f5f6040838503121561386c575f5ffd5b61387583613840565b946020939093013593505050565b5f5f5f60608486031215613895575f5ffd5b61389e84613840565b92506138ac60208501613840565b929592945050506040919091013590565b5f5f604083850312156138ce575f5ffd5b823591506138de60208401613840565b90509250929050565b5f815160c084526138fb60c08501826137e9565b90506020830151848203602086015261391482826137e9565b91505060408301511515604085015260608301511515606085015260808301511515608085015260a083015160a08501528091505092915050565b602081525f611b3760208301846138e7565b5f5f83601f840112613971575f5ffd5b50813567ffffffffffffffff811115613988575f5ffd5b60208301915083602082850101111561399f575f5ffd5b9250929050565b5f5f602083850312156139b7575f5ffd5b823567ffffffffffffffff8111156139cd575f5ffd5b6139d985828601613961565b90969095509350505050565b5f602082840312156139f5575f5ffd5b611b3782613840565b602080825282518282018190525f918401906040840190835b81811015613a35578351835260209384019390920191600101613a17565b509095945050505050565b5f60208284031215613a50575f5ffd5b813565ffffffffffff81168114611b37575f5ffd5b5f5f5f5f5f5f60808789031215613a7a575f5ffd5b613a8387613840565b9550602087013567ffffffffffffffff811115613a9e575f5ffd5b613aaa89828a01613961565b909650945050604087013567ffffffffffffffff811115613ac9575f5ffd5b613ad589828a01613961565b979a9699509497949695606090950135949350505050565b80358015158114613856575f5ffd5b5f5f60408385031215613b0d575f5ffd5b823591506138de60208401613aed565b5f60208284031215613b2d575f5ffd5b813560ff81168114611b37575f5ffd5b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b82811015613bc9577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08786030184528151805186526020810151905060406020870152613bb360408701826138e7565b9550506020938401939190910190600101613b63565b50929695505050505050565b5f5f60408385031215613be6575f5ffd5b613bef83613840565b91506138de60208401613aed565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f5f5f5f60808587031215613c3d575f5ffd5b613c4685613840565b9350613c5460208601613840565b925060408501359150606085013567ffffffffffffffff811115613c76575f5ffd5b8501601f81018713613c86575f5ffd5b803567ffffffffffffffff811115613ca057613ca0613bfd565b604051601f19603f601f19601f8501160116810181811067ffffffffffffffff82111715613cd057613cd0613bfd565b604052818152828201602001891015613ce7575f5ffd5b816020840160208301375f6020838301015280935050505092959194509250565b5f5f60408385031215613d19575f5ffd5b50508035926020909101359150565b5f5f5f60408486031215613d3a575f5ffd5b83359250602084013567ffffffffffffffff811115613d57575f5ffd5b613d6386828701613961565b9497909650939450505050565b5f5f60408385031215613d81575f5ffd5b613d8a83613840565b91506138de60208401613840565b600181811c90821680613dac57607f821691505b602082108103613de3577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b818103818111156108a0576108a0613de9565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b601f821115610c4557805f5260205f20601f840160051c81016020851015613e7b5750805b601f840160051c820191505b818110156128fb575f8155600101613e87565b67ffffffffffffffff831115613eb257613eb2613bfd565b613ec683613ec08354613d98565b83613e56565b5f601f841160018114613ef7575f8515613ee05750838201355b5f19600387901b1c1916600186901b1783556128fb565b5f83815260208120601f198716915b82811015613f265786850135825560209485019460019092019101613f06565b5086821015613f42575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b81835281816020850137505f602082840101525f6020601f19601f840116840101905092915050565b602081525f613748602083018486613f54565b5f63ffffffff821663ffffffff8103613fab57613fab613de9565b60010192915050565b63ffffffff81811683821602908116908181146134b4576134b4613de9565b815167ffffffffffffffff811115613fed57613fed613bfd565b61400181613ffb8454613d98565b84613e56565b6020601f821160018114614033575f831561401c5750848201515b5f19600385901b1c1916600184901b1784556128fb565b5f84815260208120601f198516915b828110156140625787850151825560209485019460019092019101614042565b508482101561407f57868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b606081525f6140a1606083018789613f54565b82810360208401526140b4818688613f54565b9150508260408301529695505050505050565b63ffffffff81811683821601908111156108a0576108a0613de9565b5f81518060208401855e5f93019283525090919050565b5f61374861410883866140e3565b846140e3565b65ffffffffffff81811683821601908111156108a0576108a0613de9565b6001600160a01b03851681526001600160a01b0384166020820152826040820152608060608201525f61416260808301846137e9565b9695505050505050565b5f6020828403121561417c575f5ffd5b8151611b37816137a1565b65ffffffffffff82811682821603908111156108a0576108a0613de9565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea26469706673582212204806a675f1da3494a4dd4c0222d2e621e9c6968738ff149341166520231b328364736f6c634300081c0033daf9ac3a6308052428e8806fd908cf472318416ed7d78b3f35dd94bbbafde56aa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775", + Bin: "0x6080604052600a805464ffffffffff19166014179055348015610020575f5ffd5b5060405161473638038061473683398101604081905261003f91610317565b60408051808201825260128152712c26aa28102737b2329027b832b930ba37b960711b602080830191909152825180840190935260048352630584d54560e41b90830152906202a300836001600160a01b0381166100b657604051636116401160e11b81525f600482015260240160405180910390fd5b600180546001600160d01b0316600160d01b65ffffffffffff8516021790556100df5f8261018b565b50600391506100f0905083826103dc565b5060046100fd82826103dc565b5050506001600160a01b0381166101275760405163e6c4247b60e01b815260040160405180910390fd5b61013e5f5160206147165f395f51905f525f6101fa565b6101555f5160206146f65f395f51905f525f6101fa565b61016c5f5160206147165f395f51905f528261018b565b506101845f5160206146f65f395f51905f528261018b565b5050610496565b5f826101e7575f6101a46002546001600160a01b031690565b6001600160a01b0316146101cb57604051631fe1e13d60e11b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b0384161790555b6101f18383610226565b90505b92915050565b8161021857604051631fe1e13d60e11b815260040160405180910390fd5b61022282826102cd565b5050565b5f828152602081815260408083206001600160a01b038516845290915281205460ff166102c6575f838152602081815260408083206001600160a01b03861684529091529020805460ff1916600117905561027e3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016101f4565b505f6101f4565b5f82815260208190526040808220600101805490849055905190918391839186917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a4505050565b5f60208284031215610327575f5ffd5b81516001600160a01b038116811461033d575f5ffd5b9392505050565b634e487b7160e01b5f52604160045260245ffd5b600181811c9082168061036c57607f821691505b60208210810361038a57634e487b7160e01b5f52602260045260245ffd5b50919050565b601f8211156103d757805f5260205f20601f840160051c810160208510156103b55750805b601f840160051c820191505b818110156103d4575f81556001016103c1565b50505b505050565b81516001600160401b038111156103f5576103f5610344565b610409816104038454610358565b84610390565b6020601f82116001811461043b575f83156104245750848201515b5f19600385901b1c1916600184901b1784556103d4565b5f84815260208120601f198516915b8281101561046a578785015182556020948501946001909201910161044a565b508482101561048757868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b614253806104a35f395ff3fe608060405234801561000f575f5ffd5b5060043610610393575f3560e01c80638ed9ea34116101df578063ce99948911610109578063e18cb254116100a9578063f579d7e111610079578063f579d7e114610860578063fb1120e214610868578063fd667d1e14610870578063fd967f471461088d575f5ffd5b8063e18cb25414610801578063e985e9c514610814578063ebe487bf1461084f578063f3194a3914610857575f5ffd5b8063d547741f116100e4578063d547741f146107ac578063d59f9fe0146107bf578063d602b9fd146107e6578063d74a2a50146107ee575f5ffd5b8063ce99948914610752578063cefc142914610765578063cf6eefb71461076d575f5ffd5b8063a217fddf1161017f578063b9b140d61161014f578063b9b140d61461071c578063c4741f3114610724578063c87b56dd14610737578063cc8463c81461074a575f5ffd5b8063a217fddf146106dc578063a22cb465146106e3578063a835f88e146106f6578063b88d4fde14610709575f5ffd5b806395d89b41116101ba57806395d89b41146106865780639d32f9ba1461068e578063a1174e7d146106ad578063a1eda53c146106b5575f5ffd5b80638ed9ea34146106285780638fbbf6231461063b57806391d1485414610650575f5ffd5b806344ff624e116102c0578063649a5ec71161026057806379e0d58c1161023057806379e0d58c146105e957806384ef8ffc146105fc578063895620b71461060d5780638da5cb5b14610620575f5ffd5b8063649a5ec7146105895780636ec97bfc1461059c57806370a08231146105af57806375b238fc146105c2575f5ffd5b806355f804b31161029b57806355f804b31461053b578063634e93da1461054e5780636352211e14610561578063646453ba14610574575f5ffd5b806344ff624e146104f55780634f0f4aa91461050857806350d0215f14610528575f5ffd5b8063203ede77116103365780632f2ff15d116103065780632f2ff15d146104a957806336568abe146104bc5780633d2853fb146104cf57806342842e0e146104e2575f5ffd5b8063203ede771461044e57806321fbd7cb1461046157806323b872dd14610474578063248a9ca314610487575f5ffd5b8063081812fc11610371578063081812fc146103f0578063095ea7b31461041b5780630aa6220b1461043057806317e3b3a914610438575f5ffd5b806301ffc9a714610397578063022d63fb146103bf57806306fdde03146103db575b5f5ffd5b6103aa6103a5366004613819565b610896565b60405190151581526020015b60405180910390f35b620697805b60405165ffffffffffff90911681526020016103b6565b6103e36108f1565b6040516103b69190613862565b6104036103fe366004613874565b610981565b6040516001600160a01b0390911681526020016103b6565b61042e6104293660046138a6565b6109a8565b005b61042e6109b7565b6104406109cc565b6040519081526020016103b6565b61042e61045c366004613874565b6109dc565b6103aa61046f366004613874565b610a18565b61042e6104823660046138ce565b610a24565b610440610495366004613874565b5f9081526020819052604090206001015490565b61042e6104b7366004613908565b610ab1565b61042e6104ca366004613908565b610af2565b61042e6104dd366004613874565b610be2565b61042e6104f03660046138ce565b610c76565b6103aa610503366004613874565b610c95565b61051b610516366004613874565b610ca1565b6040516103b6919061399a565b600a54610100900463ffffffff16610440565b61042e6105493660046139f1565b610e51565b61042e61055c366004613a30565b610f9e565b61040361056f366004613874565b610fb1565b61057c610fbb565b6040516103b69190613a49565b61042e610597366004613a8b565b610fc7565b6104406105aa366004613ab0565b610fda565b6104406105bd366004613a30565b6112d6565b6104407fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177581565b61042e6105f7366004613874565b611334565b6002546001600160a01b0316610403565b61042e61061b366004613b47565b611370565b61040361139a565b61042e610636366004613b68565b6113ad565b61064361147d565b6040516103b69190613b88565b6103aa61065e366004613908565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6103e36116cf565b600a5461069b9060ff1681565b60405160ff90911681526020016103b6565b6106436116de565b6106bd611938565b6040805165ffffffffffff9384168152929091166020830152016103b6565b6104405f81565b61042e6106f1366004613c20565b6119b2565b61042e610704366004613874565b6119bd565b61042e610717366004613c75565b611a6b565b601054610440565b61042e610732366004613874565b611a89565b6103e3610745366004613874565b611b24565b6103c4611b89565b61042e610760366004613d53565b611c26565b61042e611cad565b600154604080516001600160a01b03831681527401000000000000000000000000000000000000000090920465ffffffffffff166020830152016103b6565b61042e6107ba366004613908565b611cfc565b6104407fdaf9ac3a6308052428e8806fd908cf472318416ed7d78b3f35dd94bbbafde56a81565b61042e611d3d565b61042e6107fc366004613d73565b611d4f565b61042e61080f366004613b47565b611e15565b6103aa610822366004613dbb565b6001600160a01b039182165f90815260086020908152604080832093909416825291909152205460ff1690565b610643611e3f565b61044060105481565b61044061208d565b61057c612098565b610878606481565b60405163ffffffff90911681526020016103b6565b61044061271081565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f5ad5d4b10000000000000000000000000000000000000000000000000000000014806108eb57506108eb826120a4565b92915050565b60606003805461090090613de3565b80601f016020809104026020016040519081016040528092919081815260200182805461092c90613de3565b80156109775780601f1061094e57610100808354040283529160200191610977565b820191905f5260205f20905b81548152906001019060200180831161095a57829003601f168201915b5050505050905090565b5f61098b82612145565b505f828152600760205260409020546001600160a01b03166108eb565b6109b3828233612196565b5050565b5f6109c1816121a3565b6109c96121ad565b50565b5f6109d7600e6121b9565b905090565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775610a06816121a3565b610a0f826121c2565b6109b38261220f565b5f6108eb600c83612263565b7fdaf9ac3a6308052428e8806fd908cf472318416ed7d78b3f35dd94bbbafde56a610a4e816121a3565b610a578261227a565b610a608261220f565b610a6b8484846122ec565b826001600160a01b0316846001600160a01b0316837e80108bb11ee8badd8a48ff0b4585853d721b6e5ac7e3415f99413dac52be7260405160405180910390a450505050565b81610ae8576040517f3fc3c27a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109b382826123a1565b81158015610b0d57506002546001600160a01b038281169116145b15610bd8576001546001600160a01b0381169074010000000000000000000000000000000000000000900465ffffffffffff1681151580610b54575065ffffffffffff8116155b80610b6757504265ffffffffffff821610155b15610bad576040517f19ca5ebb00000000000000000000000000000000000000000000000000000000815265ffffffffffff821660048201526024015b60405180910390fd5b5050600180547fffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffff1690555b6109b382826123c5565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775610c0c816121a3565b610c15826121c2565b5f828152600b602052604080822060020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff1690555183917ff044a2d72ef98b7636ca9d9f8c0fc60e24309bbb8d472fdecbbaca55fe166d0a91a25050565b610c9083838360405180602001604052805f815250611a6b565b505050565b5f6108eb600e83612263565b6040805160c0810182526060808252602082018190525f92820183905281018290526080810182905260a0810191909152610cdb826121c2565b5f828152600b602052604090819020815160c08101909252805482908290610d0290613de3565b80601f0160208091040260200160405190810160405280929190818152602001828054610d2e90613de3565b8015610d795780601f10610d5057610100808354040283529160200191610d79565b820191905f5260205f20905b815481529060010190602001808311610d5c57829003601f168201915b50505050508152602001600182018054610d9290613de3565b80601f0160208091040260200160405190810160405280929190818152602001828054610dbe90613de3565b8015610e095780601f10610de057610100808354040283529160200191610e09565b820191905f5260205f20905b815481529060010190602001808311610dec57829003601f168201915b5050509183525050600282015460ff80821615156020840152610100820481161515604084015262010000909104161515606082015260039091015460809091015292915050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775610e7b816121a3565b81610eb2576040517f3ba0191100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f2f000000000000000000000000000000000000000000000000000000000000008383610ee0600182613e61565b818110610eef57610eef613e74565b9050013560f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614610f52576040517f3ba0191100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6009610f5f838583613ee5565b507f6741b2fc379fad678116fe3d4d4b9a1a184ab53ba36b86ad0fa66340b1ab41ad8383604051610f91929190613fc8565b60405180910390a1505050565b5f610fa8816121a3565b6109b382612411565b5f6108eb82612145565b60606109d7600c612483565b5f610fd1816121a3565b6109b38261248f565b5f7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775611005816121a3565b6001600160a01b038816611045576040517fe6c4247b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8561107c576040517f8125403000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b836110b3576040517fcbd6898900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6064600a600181819054906101000a900463ffffffff166110d390613fdb565b91906101000a81548163ffffffff021916908363ffffffff16021790556110fa9190613fff565b63ffffffff1691506040518060c0016040528088888080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250505090825250604080516020601f8901819004810282018101909252878152918101919088908890819084018382808284375f92018290525093855250505060208083018290526040808401839052606084018390526080909301879052858252600b905220815181906111b3908261401e565b50602082015160018201906111c8908261401e565b50604082015160028201805460608501516080860151151562010000027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff911515610100027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff951515959095167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090931692909217939093179290921691909117905560a09091015160039091015561128188836124f7565b876001600160a01b0316827f663d98c1e2bdf874fcd4fadcdf16242719c434e099664a3eb574322b78bd7c5c89898989896040516112c39594939291906140d9565b60405180910390a3509695505050505050565b5f6001600160a01b038216611319576040517f89c62b640000000000000000000000000000000000000000000000000000000081525f6004820152602401610ba4565b506001600160a01b03165f9081526006602052604090205490565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177561135e816121a3565b611367826121c2565b6109b38261227a565b611379826121c2565b6113828261258a565b61138b826125db565b8015611367576109b38261262a565b5f6109d76002546001600160a01b031690565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217756113d7816121a3565b6113e1600c6121b9565b8260ff1610806113fc57506113f6600e6121b9565b8260ff16105b15611433576040517f39beadee00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a805460ff191660ff84169081179091556040519081527f6dd6623df488fb2b38fa153b12758a1b41c8e49e88025f8d9fb1eba1b8f1d821906020015b60405180910390a15050565b6060611489600e6121b9565b67ffffffffffffffff8111156114a1576114a1613c48565b6040519080825280602002602001820160405280156114da57816020015b6114c761379b565b8152602001906001900390816114bf5790505b5090505f5b6114e9600e6121b9565b8163ffffffff1610156116cb575f61150b600e63ffffffff808516906126e716565b90506040518060400160405280828152602001600b5f8481526020019081526020015f206040518060c00160405290815f8201805461154990613de3565b80601f016020809104026020016040519081016040528092919081815260200182805461157590613de3565b80156115c05780601f10611597576101008083540402835291602001916115c0565b820191905f5260205f20905b8154815290600101906020018083116115a357829003601f168201915b505050505081526020016001820180546115d990613de3565b80601f016020809104026020016040519081016040528092919081815260200182805461160590613de3565b80156116505780601f1061162757610100808354040283529160200191611650565b820191905f5260205f20905b81548152906001019060200180831161163357829003601f168201915b5050509183525050600282015460ff80821615156020840152610100820481161515604084015262010000909104161515606082015260039091015460809091015290528351849063ffffffff85169081106116ae576116ae613e74565b602002602001018190525050806116c490613fdb565b90506114df565b5090565b60606004805461090090613de3565b600a54606090610100900463ffffffff1667ffffffffffffffff81111561170757611707613c48565b60405190808252806020026020018201604052801561174057816020015b61172d61379b565b8152602001906001900390816117255790505b5090505f5b600a5463ffffffff610100909104811690821610156116cb575f61176a826001614112565b611775906064613fff565b905060405180604001604052808263ffffffff168152602001600b5f8463ffffffff1681526020019081526020015f206040518060c00160405290815f820180546117bf90613de3565b80601f01602080910402602001604051908101604052809291908181526020018280546117eb90613de3565b80156118365780601f1061180d57610100808354040283529160200191611836565b820191905f5260205f20905b81548152906001019060200180831161181957829003601f168201915b5050505050815260200160018201805461184f90613de3565b80601f016020809104026020016040519081016040528092919081815260200182805461187b90613de3565b80156118c65780601f1061189d576101008083540402835291602001916118c6565b820191905f5260205f20905b8154815290600101906020018083116118a957829003601f168201915b5050509183525050600282015460ff80821615156020840152610100820481161515604084015262010000909104161515606082015260039091015460809091015290528351849063ffffffff851690811061192457611924613e74565b602090810291909101015250600101611745565b6002545f907a010000000000000000000000000000000000000000000000000000900465ffffffffffff16801515801561197a57504265ffffffffffff821610155b611985575f5f6119aa565b60025474010000000000000000000000000000000000000000900465ffffffffffff16815b915091509091565b6109b33383836126f2565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c217756119e7816121a3565b6119f0826121c2565b5f828152600b6020526040902060020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff1662010000179055611a348261227a565b611a3d8261220f565b60405182907fa6c942fbe3ded4df132dc2c4adbb95359afebc3c361393a3d7217e3c310923e8905f90a25050565b611a76848484610a24565b611a8333858585856127a9565b50505050565b7fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775611ab3816121a3565b612710821115611aef576040517f47d3b04600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60108290556040518281527f6367530104bc8677601bbb2f410055f5144865bf130b2c7bed1af5ff39185eb090602001611471565b6060611b2f82612145565b505f611b3961294d565b90505f815111611b575760405180602001604052805f815250611b82565b80611b618461295c565b604051602001611b72929190614145565b6040516020818303038152906040525b9392505050565b6002545f907a010000000000000000000000000000000000000000000000000000900465ffffffffffff168015158015611bca57504265ffffffffffff8216105b611bfc576001547a010000000000000000000000000000000000000000000000000000900465ffffffffffff16611c20565b60025474010000000000000000000000000000000000000000900465ffffffffffff165b91505090565b7fdaf9ac3a6308052428e8806fd908cf472318416ed7d78b3f35dd94bbbafde56a611c50816121a3565b611c59836121c2565b5f838152600b6020526040908190206003018390555183907f27a815a14bf8281048d2768dcd6b695fbd4e98af4e3fb52d92c8c65384320d4a90611ca09085815260200190565b60405180910390a2505050565b6001546001600160a01b0316338114611cf4576040517fc22c8022000000000000000000000000000000000000000000000000000000008152336004820152602401610ba4565b6109c96129f9565b81611d33576040517f3fc3c27a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109b38282612ad0565b5f611d47816121a3565b6109c9612af4565b7fdaf9ac3a6308052428e8806fd908cf472318416ed7d78b3f35dd94bbbafde56a611d79816121a3565b611d82846121c2565b81611db9576040517fcbd6898900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f848152600b60205260409020600101611dd4838583613ee5565b50837f15c3eac3b34037e402127abd35c3804f49d489c361f5bb8ff237544f0dfff4ed8484604051611e07929190613fc8565b60405180910390a250505050565b611e1e826121c2565b611e278261258a565b611e30826125db565b8015610a0f576109b382612afe565b6060611e4b600c6121b9565b67ffffffffffffffff811115611e6357611e63613c48565b604051908082528060200260200182016040528015611e9c57816020015b611e8961379b565b815260200190600190039081611e815790505b5090505f5b611eab600c6121b9565b8163ffffffff1610156116cb575f611ecd600c63ffffffff808516906126e716565b90506040518060400160405280828152602001600b5f8481526020019081526020015f206040518060c00160405290815f82018054611f0b90613de3565b80601f0160208091040260200160405190810160405280929190818152602001828054611f3790613de3565b8015611f825780601f10611f5957610100808354040283529160200191611f82565b820191905f5260205f20905b815481529060010190602001808311611f6557829003601f168201915b50505050508152602001600182018054611f9b90613de3565b80601f0160208091040260200160405190810160405280929190818152602001828054611fc790613de3565b80156120125780601f10611fe957610100808354040283529160200191612012565b820191905f5260205f20905b815481529060010190602001808311611ff557829003601f168201915b5050509183525050600282015460ff80821615156020840152610100820481161515604084015262010000909104161515606082015260039091015460809091015290528351849063ffffffff851690811061207057612070613e74565b6020026020010181905250508061208690613fdb565b9050611ea1565b5f6109d7600c6121b9565b60606109d7600e612483565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f80ac58cd00000000000000000000000000000000000000000000000000000000148061213657507fffffffff0000000000000000000000000000000000000000000000000000000082167f5b5e139f00000000000000000000000000000000000000000000000000000000145b806108eb57506108eb82612b9c565b5f818152600560205260408120546001600160a01b0316806108eb576040517f7e27328900000000000000000000000000000000000000000000000000000000815260048101849052602401610ba4565b610c908383836001612bf1565b6109c98133612d44565b6121b75f5f612daf565b565b5f6108eb825490565b5f818152600560205260409020546001600160a01b03166109c9576040517f5e926f7100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61221a600e82612efb565b6122215750565b5f818152600b6020526040808220600201805460ff191690555182917fa9837328431beea294d22d476aeafca23f85f320de41750a9b9c3ce28076180891a250565b5f8181526001830160205260408120541515611b82565b612285600c82612efb565b61228c5750565b5f818152600b602052604080822060020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555182917f9e61606f143f77c9ef06d68819ce159e3b98756d8eb558b91db82c8ca42357f391a250565b6001600160a01b03821661232e576040517f64a0ae920000000000000000000000000000000000000000000000000000000081525f6004820152602401610ba4565b5f61233a838333612f06565b9050836001600160a01b0316816001600160a01b031614611a83576040517f64283d7b0000000000000000000000000000000000000000000000000000000081526001600160a01b0380861660048301526024820184905282166044820152606401610ba4565b5f828152602081905260409020600101546123bb816121a3565b611a838383613010565b6001600160a01b0381163314612407576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c9082826130a7565b5f61241a611b89565b612423426130fb565b61242d9190614159565b90506124398282613146565b60405165ffffffffffff821681526001600160a01b038316907f3377dc44241e779dd06afab5b788a35ca5f3b778836e2990bdb26a2a4b2e5ed69060200160405180910390a25050565b60605f611b82836131d4565b5f6124998261322d565b6124a2426130fb565b6124ac9190614159565b90506124b88282612daf565b6040805165ffffffffffff8085168252831660208201527ff1038c18cf84a56e432fdbfaf746924b7ea511dfe03a6506a0ceba4888788d9b9101611471565b6001600160a01b038216612539576040517f64a0ae920000000000000000000000000000000000000000000000000000000081525f6004820152602401610ba4565b5f61254583835f612f06565b90506001600160a01b03811615610c90576040517f73c6ac6e0000000000000000000000000000000000000000000000000000000081525f6004820152602401610ba4565b5f818152600b602052604090206002015462010000900460ff16156109c9576040517fc40c6f6300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f818152600560205260409020546001600160a01b031633146109c9576040517f82b4290000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a5460ff1661263a600c6121b9565b10612671576040517f950be9a500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61267c600c82613274565b6126835750565b5f818152600b602052604080822060020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555182917f3cd0abf09f2e68bb82445a4d250b6a3e30b2b2c711b322e3f3817927a07da17391a250565b5f611b82838361327f565b6001600160a01b03821661273d576040517f5b08ba180000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610ba4565b6001600160a01b038381165f81815260086020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0383163b15612946576040517f150b7a020000000000000000000000000000000000000000000000000000000081526001600160a01b0384169063150b7a0290612804908890889087908790600401614177565b6020604051808303815f875af192505050801561283e575060408051601f3d908101601f1916820190925261283b918101906141b7565b60015b6128be573d80801561286b576040519150601f19603f3d011682016040523d82523d5f602084013e612870565b606091505b5080515f036128b6576040517f64a0ae920000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401610ba4565b805181602001fd5b7fffffffff0000000000000000000000000000000000000000000000000000000081167f150b7a020000000000000000000000000000000000000000000000000000000014612944576040517f64a0ae920000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401610ba4565b505b5050505050565b60606009805461090090613de3565b60605f612968836132a5565b60010190505f8167ffffffffffffffff81111561298757612987613c48565b6040519080825280601f01601f1916602001820160405280156129b1576020820181803683370190505b5090508181016020015b5f19017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a85049450846129bb57509392505050565b6001546001600160a01b0381169074010000000000000000000000000000000000000000900465ffffffffffff16801580612a3c57504265ffffffffffff821610155b15612a7d576040517f19ca5ebb00000000000000000000000000000000000000000000000000000000815265ffffffffffff82166004820152602401610ba4565b612a985f612a936002546001600160a01b031690565b6130a7565b50612aa35f83613010565b5050600180547fffffffffffff000000000000000000000000000000000000000000000000000016905550565b5f82815260208190526040902060010154612aea816121a3565b611a8383836130a7565b6121b75f5f613146565b600a5460ff16612b0e600e6121b9565b10612b45576040517f950be9a500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612b50600e82613274565b612b575750565b5f818152600b6020526040808220600201805460ff191660011790555182917fd9199c75487673396ebe8093e82e5cf7902ccfb90befe22763a8bc4c36b976d091a250565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f314987860000000000000000000000000000000000000000000000000000000014806108eb57506108eb82613386565b8080612c0557506001600160a01b03821615155b15612cfd575f612c1484612145565b90506001600160a01b03831615801590612c405750826001600160a01b0316816001600160a01b031614155b8015612c7157506001600160a01b038082165f9081526008602090815260408083209387168352929052205460ff16155b15612cb3576040517fa9fbf51f0000000000000000000000000000000000000000000000000000000081526001600160a01b0384166004820152602401610ba4565b8115612cfb5783856001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b50505f90815260076020526040902080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b5f828152602081815260408083206001600160a01b038516845290915290205460ff166109b3576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401610ba4565b6002547a010000000000000000000000000000000000000000000000000000900465ffffffffffff168015612e83574265ffffffffffff82161015612e5a576002546001805479ffffffffffffffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000090920465ffffffffffff167a01000000000000000000000000000000000000000000000000000002919091179055612e83565b6040517f2b1fa2edafe6f7b9e97c1a9e0c3660e645beb2dcaa2d45bdbf9beaf5472e1ec5905f90a15b50600280546001600160a01b03167401000000000000000000000000000000000000000065ffffffffffff9485160279ffffffffffffffffffffffffffffffffffffffffffffffffffff16177a0100000000000000000000000000000000000000000000000000009290931691909102919091179055565b5f611b82838361341c565b5f828152600560205260408120546001600160a01b0390811690831615612f3257612f32818486613506565b6001600160a01b03811615612f6c57612f4d5f855f5f612bf1565b6001600160a01b0381165f90815260066020526040902080545f190190555b6001600160a01b03851615612f9a576001600160a01b0385165f908152600660205260409020805460010190555b5f8481526005602052604080822080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0389811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b5f8261309d575f6130296002546001600160a01b031690565b6001600160a01b031614613069576040517f3fc3c27a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0384161790555b611b82838361359c565b5f821580156130c357506002546001600160a01b038381169116145b156130f157600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001690555b611b828383613643565b5f65ffffffffffff8211156116cb576040517f6dfcc6500000000000000000000000000000000000000000000000000000000081526030600482015260248101839052604401610ba4565b600180547401000000000000000000000000000000000000000065ffffffffffff84811682027fffffffffffff000000000000000000000000000000000000000000000000000084166001600160a01b03881617179093559004168015610c90576040517f8886ebfc4259abdbc16601dd8fb5678e54878f47b3c34836cfc51154a9605109905f90a1505050565b6060815f0180548060200260200160405190810160405280929190818152602001828054801561322157602002820191905f5260205f20905b81548152602001906001019080831161320d575b50505050509050919050565b5f5f613237611b89565b90508065ffffffffffff168365ffffffffffff161161325f5761325a83826141d2565b611b82565b611b8265ffffffffffff8416620697806136c4565b5f611b8283836136d3565b5f825f01828154811061329457613294613e74565b905f5260205f200154905092915050565b5f807a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000083106132ed577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef81000000008310613319576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061333757662386f26fc10000830492506010015b6305f5e100831061334f576305f5e100830492506008015b612710831061336357612710830492506004015b60648310613375576064830492506002015b600a83106108eb5760010192915050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806108eb57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146108eb565b5f81815260018301602052604081205480156134f6575f61343e600183613e61565b85549091505f9061345190600190613e61565b90508082146134b0575f865f01828154811061346f5761346f613e74565b905f5260205f200154905080875f01848154811061348f5761348f613e74565b5f918252602080832090910192909255918252600188019052604090208390555b85548690806134c1576134c16141f0565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f9055600193505050506108eb565b5f9150506108eb565b5092915050565b613511838383613718565b610c90576001600160a01b038316613558576040517f7e27328900000000000000000000000000000000000000000000000000000000815260048101829052602401610ba4565b6040517f177e802f0000000000000000000000000000000000000000000000000000000081526001600160a01b038316600482015260248101829052604401610ba4565b5f828152602081815260408083206001600160a01b038516845290915281205460ff1661363c575f838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556135f43390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016108eb565b505f6108eb565b5f828152602081815260408083206001600160a01b038516845290915281205460ff161561363c575f838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45060016108eb565b5f828218828410028218611b82565b5f81815260018301602052604081205461363c57508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556108eb565b5f6001600160a01b038316158015906137935750826001600160a01b0316846001600160a01b0316148061377057506001600160a01b038085165f9081526008602090815260408083209387168352929052205460ff165b8061379357505f828152600760205260409020546001600160a01b038481169116145b949350505050565b60405180604001604052805f81526020016137e76040518060c0016040528060608152602001606081526020015f151581526020015f151581526020015f151581526020015f81525090565b905290565b7fffffffff00000000000000000000000000000000000000000000000000000000811681146109c9575f5ffd5b5f60208284031215613829575f5ffd5b8135611b82816137ec565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f611b826020830184613834565b5f60208284031215613884575f5ffd5b5035919050565b80356001600160a01b03811681146138a1575f5ffd5b919050565b5f5f604083850312156138b7575f5ffd5b6138c08361388b565b946020939093013593505050565b5f5f5f606084860312156138e0575f5ffd5b6138e98461388b565b92506138f76020850161388b565b929592945050506040919091013590565b5f5f60408385031215613919575f5ffd5b823591506139296020840161388b565b90509250929050565b5f815160c0845261394660c0850182613834565b90506020830151848203602086015261395f8282613834565b91505060408301511515604085015260608301511515606085015260808301511515608085015260a083015160a08501528091505092915050565b602081525f611b826020830184613932565b5f5f83601f8401126139bc575f5ffd5b50813567ffffffffffffffff8111156139d3575f5ffd5b6020830191508360208285010111156139ea575f5ffd5b9250929050565b5f5f60208385031215613a02575f5ffd5b823567ffffffffffffffff811115613a18575f5ffd5b613a24858286016139ac565b90969095509350505050565b5f60208284031215613a40575f5ffd5b611b828261388b565b602080825282518282018190525f918401906040840190835b81811015613a80578351835260209384019390920191600101613a62565b509095945050505050565b5f60208284031215613a9b575f5ffd5b813565ffffffffffff81168114611b82575f5ffd5b5f5f5f5f5f5f60808789031215613ac5575f5ffd5b613ace8761388b565b9550602087013567ffffffffffffffff811115613ae9575f5ffd5b613af589828a016139ac565b909650945050604087013567ffffffffffffffff811115613b14575f5ffd5b613b2089828a016139ac565b979a9699509497949695606090950135949350505050565b803580151581146138a1575f5ffd5b5f5f60408385031215613b58575f5ffd5b8235915061392960208401613b38565b5f60208284031215613b78575f5ffd5b813560ff81168114611b82575f5ffd5b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b82811015613c14577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08786030184528151805186526020810151905060406020870152613bfe6040870182613932565b9550506020938401939190910190600101613bae565b50929695505050505050565b5f5f60408385031215613c31575f5ffd5b613c3a8361388b565b915061392960208401613b38565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f5f5f5f60808587031215613c88575f5ffd5b613c918561388b565b9350613c9f6020860161388b565b925060408501359150606085013567ffffffffffffffff811115613cc1575f5ffd5b8501601f81018713613cd1575f5ffd5b803567ffffffffffffffff811115613ceb57613ceb613c48565b604051601f19603f601f19601f8501160116810181811067ffffffffffffffff82111715613d1b57613d1b613c48565b604052818152828201602001891015613d32575f5ffd5b816020840160208301375f6020838301015280935050505092959194509250565b5f5f60408385031215613d64575f5ffd5b50508035926020909101359150565b5f5f5f60408486031215613d85575f5ffd5b83359250602084013567ffffffffffffffff811115613da2575f5ffd5b613dae868287016139ac565b9497909650939450505050565b5f5f60408385031215613dcc575f5ffd5b613dd58361388b565b91506139296020840161388b565b600181811c90821680613df757607f821691505b602082108103613e2e577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b818103818111156108eb576108eb613e34565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b601f821115610c9057805f5260205f20601f840160051c81016020851015613ec65750805b601f840160051c820191505b81811015612946575f8155600101613ed2565b67ffffffffffffffff831115613efd57613efd613c48565b613f1183613f0b8354613de3565b83613ea1565b5f601f841160018114613f42575f8515613f2b5750838201355b5f19600387901b1c1916600186901b178355612946565b5f83815260208120601f198716915b82811015613f715786850135825560209485019460019092019101613f51565b5086821015613f8d575f1960f88860031b161c19848701351681555b505060018560011b0183555050505050565b81835281816020850137505f602082840101525f6020601f19601f840116840101905092915050565b602081525f613793602083018486613f9f565b5f63ffffffff821663ffffffff8103613ff657613ff6613e34565b60010192915050565b63ffffffff81811683821602908116908181146134ff576134ff613e34565b815167ffffffffffffffff81111561403857614038613c48565b61404c816140468454613de3565b84613ea1565b6020601f82116001811461407e575f83156140675750848201515b5f19600385901b1c1916600184901b178455612946565b5f84815260208120601f198516915b828110156140ad578785015182556020948501946001909201910161408d565b50848210156140ca57868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b606081525f6140ec606083018789613f9f565b82810360208401526140ff818688613f9f565b9150508260408301529695505050505050565b63ffffffff81811683821601908111156108eb576108eb613e34565b5f81518060208401855e5f93019283525090919050565b5f613793614153838661412e565b8461412e565b65ffffffffffff81811683821601908111156108eb576108eb613e34565b6001600160a01b03851681526001600160a01b0384166020820152826040820152608060608201525f6141ad6080830184613834565b9695505050505050565b5f602082840312156141c7575f5ffd5b8151611b82816137ec565b65ffffffffffff82811682821603908111156108eb576108eb613e34565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea2646970667358221220b6d571dd1526ffac8e29836c0c3ebcdb95ef57f1d5955f90f437e97b78dd9afe64736f6c634300081c0033daf9ac3a6308052428e8806fd908cf472318416ed7d78b3f35dd94bbbafde56aa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775", } // NodesABI is the input ABI used to generate the binding from. diff --git a/contracts/src/Nodes.sol b/contracts/src/Nodes.sol index 328c2306..118caf6e 100644 --- a/contracts/src/Nodes.sol +++ b/contracts/src/Nodes.sol @@ -364,14 +364,14 @@ contract Nodes is INodes, AccessControlDefaultAdminRules, ERC721 { emit ReplicationDisabled(nodeId); } - /// @dev Override to support ERC721, IERC165, and AccessControlEnumerable. + /// @dev Override to support INodes, ERC721, IERC165, and AccessControlEnumerable. function supportsInterface(bytes4 interfaceId) public view override(ERC721, IERC165, AccessControlDefaultAdminRules) returns (bool supported) { - return super.supportsInterface(interfaceId); + return interfaceId == type(INodes).interfaceId || super.supportsInterface(interfaceId); } /// @dev Reverts if the node does not exist. diff --git a/contracts/src/Payer.sol b/contracts/src/Payer.sol index c711787c..43fee834 100644 --- a/contracts/src/Payer.sol +++ b/contracts/src/Payer.sol @@ -1,19 +1,21 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.28; -import {AccessControlUpgradeable} from "@openzeppelin-contracts-upgradeable/access/AccessControlUpgradeable.sol"; -import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; -import {Initializable} from "@openzeppelin-contracts-upgradeable/proxy/utils/Initializable.sol"; -import {PausableUpgradeable} from "@openzeppelin-contracts-upgradeable/utils/PausableUpgradeable.sol"; -import {ReentrancyGuardUpgradeable} from "@openzeppelin-contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; -import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import {UUPSUpgradeable} from "@openzeppelin-contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; - -import {INodes} from "./interfaces/INodes.sol"; -import {IPayer} from "./interfaces/IPayer.sol"; -import {IPayerReport} from "./interfaces/IPayerReport.sol"; +import { AccessControlUpgradeable } from "@openzeppelin-contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; +import { Initializable } from "@openzeppelin-contracts-upgradeable/proxy/utils/Initializable.sol"; +import { PausableUpgradeable } from "@openzeppelin-contracts-upgradeable/utils/PausableUpgradeable.sol"; +import { ReentrancyGuardUpgradeable } from "@openzeppelin-contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import { UUPSUpgradeable } from "@openzeppelin-contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +import { IL2Distribution } from "./interfaces/IL2Distribution.sol"; +import { INodes } from "./interfaces/INodes.sol"; +import { IPayer } from "./interfaces/IPayer.sol"; +import { IPayerReport } from "./interfaces/IPayerReport.sol"; /** * @title Payer @@ -73,7 +75,8 @@ contract Payer is } // keccak256(abi.encode(uint256(keccak256("xmtp.storage.Payer")) - 1)) & ~bytes32(uint256(0xff)) - bytes32 internal constant PAYER_STORAGE_LOCATION = 0xd0335f337c570f3417b0f0d20340c88da711d60e810b5e9b3ecabe9ccfcdce5a; + bytes32 internal constant PAYER_STORAGE_LOCATION = + 0xd0335f337c570f3417b0f0d20340c88da711d60e810b5e9b3ecabe9ccfcdce5a; function _getPayerStorage() internal pure returns (PayerStorage storage $) { // slither-disable-next-line assembly @@ -283,14 +286,14 @@ contract Payer is PayerStorage storage $ = _getPayerStorage(); - Withdrawal memory withdrawal = $.withdrawals[msg.sender]; + Withdrawal memory _withdrawal = $.withdrawals[msg.sender]; delete $.withdrawals[msg.sender]; - $.payers[msg.sender].balance += withdrawal.amount; - _increaseTotalAmountDeposited(withdrawal.amount); + $.payers[msg.sender].balance += _withdrawal.amount; + _increaseTotalAmountDeposited(_withdrawal.amount); - emit WithdrawalCancelled(msg.sender, withdrawal.requestTimestamp); + emit WithdrawalCancelled(msg.sender, _withdrawal.requestTimestamp); } /** @@ -301,21 +304,21 @@ contract Payer is PayerStorage storage $ = _getPayerStorage(); - Withdrawal memory withdrawal = $.withdrawals[msg.sender]; + Withdrawal memory _withdrawal = $.withdrawals[msg.sender]; delete $.withdrawals[msg.sender]; - uint256 finalWithdrawalAmount = withdrawal.amount; + uint256 _finalWithdrawalAmount = _withdrawal.amount; if ($.payers[msg.sender].debtAmount > 0) { - finalWithdrawalAmount = _settleDebts(msg.sender, withdrawal.amount); + _finalWithdrawalAmount = _settleDebts(msg.sender, _withdrawal.amount); } - if (finalWithdrawalAmount > 0) { - $.usdcToken.safeTransfer(msg.sender, finalWithdrawalAmount); + if (_finalWithdrawalAmount > 0) { + $.usdcToken.safeTransfer(msg.sender, _finalWithdrawalAmount); } - emit WithdrawalFinalized(msg.sender, withdrawal.requestTimestamp); + emit WithdrawalFinalized(msg.sender, _withdrawal.requestTimestamp); } /** @@ -342,7 +345,7 @@ contract Payer is PayerStorage storage $ = _getPayerStorage(); - uint256 fees = 0; + uint256 _fees = 0; for (uint256 i = 0; i < payerList.length; i++) { address payer = payerList[i]; @@ -354,39 +357,39 @@ contract Payer is continue; } - Payer memory storedPayer = $.payers[payer]; + Payer memory _storedPayer = $.payers[payer]; - if (storedPayer.balance < usage) { - uint256 debt = usage - storedPayer.balance; + if (_storedPayer.balance < usage) { + uint256 _debt = usage - _storedPayer.balance; - $.pendingFees += storedPayer.balance; - fees += storedPayer.balance; + $.pendingFees += _storedPayer.balance; + _fees += _storedPayer.balance; - storedPayer.balance = 0; - storedPayer.debtAmount = debt; - $.payers[payer] = storedPayer; + _storedPayer.balance = 0; + _storedPayer.debtAmount = _debt; + $.payers[payer] = _storedPayer; _addDebtor(payer); - _increaseTotalDebtAmount(debt); + _increaseTotalDebtAmount(_debt); - if (debt > $.maxTolerableDebtAmountMicroDollars) _deactivatePayer(payer); + if (_debt > $.maxTolerableDebtAmountMicroDollars) _deactivatePayer(payer); - emit PayerBalanceUpdated(payer, storedPayer.balance, storedPayer.debtAmount); + emit PayerBalanceUpdated(payer, _storedPayer.balance, _storedPayer.debtAmount); continue; } $.pendingFees += usage; - fees += usage; + _fees += usage; - storedPayer.balance -= usage; + _storedPayer.balance -= usage; - $.payers[payer] = storedPayer; + $.payers[payer] = _storedPayer; - emit PayerBalanceUpdated(payer, storedPayer.balance, storedPayer.debtAmount); + emit PayerBalanceUpdated(payer, _storedPayer.balance, _storedPayer.debtAmount); } - emit UsageSettled(originatorNode, block.timestamp, fees); + emit UsageSettled(originatorNode, block.timestamp, _fees); } /** @@ -403,15 +406,15 @@ contract Payer is require($.pendingFees > 0, InsufficientAmount()); - uint256 feesToTransfer = $.pendingFees; + uint256 _feesToTransfer = $.pendingFees; - $.usdcToken.safeTransfer($.distributionContract, feesToTransfer); + $.usdcToken.safeTransfer($.distributionContract, _feesToTransfer); $.lastFeeTransferTimestamp = block.timestamp; $.collectedFees += $.pendingFees; $.pendingFees = 0; - emit FeesTransferred(block.timestamp, feesToTransfer); + emit FeesTransferred(block.timestamp, _feesToTransfer); } /* ========== Administrative Functions ========== */ @@ -469,10 +472,10 @@ contract Payer is PayerStorage storage $ = _getPayerStorage(); - uint256 oldMinimumRegistrationAmount = $.minimumRegistrationAmountMicroDollars; + uint256 _oldMinimumRegistrationAmount = $.minimumRegistrationAmountMicroDollars; $.minimumRegistrationAmountMicroDollars = newMinimumRegistrationAmount; - emit MinimumRegistrationAmountSet(oldMinimumRegistrationAmount, newMinimumRegistrationAmount); + emit MinimumRegistrationAmountSet(_oldMinimumRegistrationAmount, newMinimumRegistrationAmount); } /** @@ -483,10 +486,10 @@ contract Payer is PayerStorage storage $ = _getPayerStorage(); - uint256 oldWithdrawalLockPeriod = $.withdrawalLockPeriod; + uint256 _oldWithdrawalLockPeriod = $.withdrawalLockPeriod; $.withdrawalLockPeriod = newWithdrawalLockPeriod; - emit WithdrawalLockPeriodSet(oldWithdrawalLockPeriod, newWithdrawalLockPeriod); + emit WithdrawalLockPeriodSet(_oldWithdrawalLockPeriod, newWithdrawalLockPeriod); } /** @@ -497,10 +500,10 @@ contract Payer is PayerStorage storage $ = _getPayerStorage(); - uint64 oldMaxTolerableDebtAmount = $.maxTolerableDebtAmountMicroDollars; + uint64 _oldMaxTolerableDebtAmount = $.maxTolerableDebtAmountMicroDollars; $.maxTolerableDebtAmountMicroDollars = newMaxTolerableDebtAmountMicroDollars; - emit MaxTolerableDebtAmountSet(oldMaxTolerableDebtAmount, newMaxTolerableDebtAmountMicroDollars); + emit MaxTolerableDebtAmountSet(_oldMaxTolerableDebtAmount, newMaxTolerableDebtAmountMicroDollars); } /** @@ -511,10 +514,10 @@ contract Payer is PayerStorage storage $ = _getPayerStorage(); - uint32 oldTransferFeesPeriod = $.transferFeesPeriod; + uint32 _oldTransferFeesPeriod = $.transferFeesPeriod; $.transferFeesPeriod = newTransferFeesPeriod; - emit TransferFeesPeriodSet(oldTransferFeesPeriod, newTransferFeesPeriod); + emit TransferFeesPeriodSet(_oldTransferFeesPeriod, newTransferFeesPeriod); } /** @@ -552,11 +555,11 @@ contract Payer is { PayerStorage storage $ = _getPayerStorage(); - (address[] memory payerAddresses, bool _hasMore) = _getPaginatedAddresses($.activePayers, offset, limit); + (address[] memory _payerAddresses, bool _hasMore) = _getPaginatedAddresses($.activePayers, offset, limit); - payers = new Payer[](payerAddresses.length); - for (uint256 i = 0; i < payerAddresses.length; i++) { - payers[i] = $.payers[payerAddresses[i]]; + payers = new Payer[](_payerAddresses.length); + for (uint256 i = 0; i < _payerAddresses.length; i++) { + payers[i] = $.payers[_payerAddresses[i]]; } return (payers, _hasMore); @@ -590,11 +593,11 @@ contract Payer is { PayerStorage storage $ = _getPayerStorage(); - (address[] memory payerAddresses, bool _hasMore) = _getPaginatedAddresses($.debtPayers, offset, limit); + (address[] memory _payerAddresses, bool _hasMore) = _getPaginatedAddresses($.debtPayers, offset, limit); - payers = new Payer[](payerAddresses.length); - for (uint256 i = 0; i < payerAddresses.length; i++) { - payers[i] = $.payers[payerAddresses[i]]; + payers = new Payer[](_payerAddresses.length); + for (uint256 i = 0; i < _payerAddresses.length; i++) { + payers[i] = $.payers[_payerAddresses[i]]; } return (payers, _hasMore); @@ -735,29 +738,29 @@ contract Payer is function _settleDebts(address payer, uint256 amount) internal returns (uint256 amountAfterSettlement) { PayerStorage storage $ = _getPayerStorage(); - Payer memory storedPayer = $.payers[payer]; + Payer memory _storedPayer = $.payers[payer]; - if (storedPayer.debtAmount < amount) { - uint256 debtToRemove = storedPayer.debtAmount; - amount -= debtToRemove; + if (_storedPayer.debtAmount < amount) { + uint256 _debtToRemove = _storedPayer.debtAmount; + amount -= _debtToRemove; - storedPayer.debtAmount = 0; - storedPayer.balance += amount; + _storedPayer.debtAmount = 0; + _storedPayer.balance += amount; _removeDebtor(payer); _increaseTotalAmountDeposited(amount); - _decreaseTotalDebtAmount(debtToRemove); + _decreaseTotalDebtAmount(_debtToRemove); amountAfterSettlement = amount; } else { - storedPayer.debtAmount -= amount; + _storedPayer.debtAmount -= amount; _decreaseTotalDebtAmount(amount); amountAfterSettlement = 0; } - $.payers[payer] = storedPayer; + $.payers[payer] = _storedPayer; return amountAfterSettlement; } @@ -861,77 +864,78 @@ contract Payer is /** * @notice Sets the Distribution contract. - * @param _newDistributionContract The address of the new Distribution contract. + * @param newDistributionContract The address of the new Distribution contract. */ - function _setDistributionContract(address _newDistributionContract) internal { + function _setDistributionContract(address newDistributionContract) internal { PayerStorage storage $ = _getPayerStorage(); - // TODO: Add check to ensure the new distribution contract is valid - // Wait until Distribution contract is implemented - // IDistribution distribution = IDistribution(_newDistributionContract); - // require(distribution.supportsInterface(type(IDistribution).interfaceId), InvalidDistributionContract()); - - require(_newDistributionContract != address(0), InvalidAddress()); + try IL2Distribution(newDistributionContract).supportsInterface(type(IL2Distribution).interfaceId) returns ( + bool supported + ) { + require(supported, InvalidDistributionContract()); + } catch { + revert InvalidDistributionContract(); + } - $.distributionContract = _newDistributionContract; + $.distributionContract = newDistributionContract; - emit DistributionContractSet(_newDistributionContract); + emit DistributionContractSet(newDistributionContract); } /** * @notice Sets the PayerReport contract. - * @param _newPayerReportContract The address of the new PayerReport contract. + * @param newPayerReportContract The address of the new PayerReport contract. */ - function _setPayerReportContract(address _newPayerReportContract) internal { + function _setPayerReportContract(address newPayerReportContract) internal { PayerStorage storage $ = _getPayerStorage(); - IPayerReport payerReport = IPayerReport(_newPayerReportContract); - - try payerReport.supportsInterface(type(IPayerReport).interfaceId) returns (bool supported) { + try IPayerReport(newPayerReportContract).supportsInterface(type(IPayerReport).interfaceId) returns ( + bool supported + ) { require(supported, InvalidPayerReportContract()); } catch { revert InvalidPayerReportContract(); } - $.payerReportContract = _newPayerReportContract; + $.payerReportContract = newPayerReportContract; - emit PayerReportContractSet(_newPayerReportContract); + emit PayerReportContractSet(newPayerReportContract); } /** * @notice Sets the Nodes contract. - * @param _newNodesContract The address of the new Nodes contract. + * @param newNodesContract The address of the new Nodes contract. */ - function _setNodesContract(address _newNodesContract) internal { + function _setNodesContract(address newNodesContract) internal { PayerStorage storage $ = _getPayerStorage(); - try INodes(_newNodesContract).supportsInterface(type(INodes).interfaceId) returns (bool supported) { + try INodes(newNodesContract).supportsInterface(type(INodes).interfaceId) returns (bool supported) { require(supported, InvalidNodesContract()); } catch { revert InvalidNodesContract(); } - $.nodesContract = _newNodesContract; + $.nodesContract = newNodesContract; - emit NodesContractSet(_newNodesContract); + emit NodesContractSet(newNodesContract); } /** * @notice Sets the USDC token contract. - * @param _newUsdcToken The address of the new USDC token contract. + * @param newUsdcToken The address of the new USDC token contract. */ - function _setUsdcTokenContract(address _newUsdcToken) internal { + function _setUsdcTokenContract(address newUsdcToken) internal { PayerStorage storage $ = _getPayerStorage(); - try IERC20Metadata(_newUsdcToken).symbol() returns (string memory symbol) { + try IERC20Metadata(newUsdcToken).symbol() returns (string memory symbol) { require(keccak256(bytes(symbol)) == keccak256(bytes(USDC_SYMBOL)), InvalidUsdcTokenContract()); } catch { revert InvalidUsdcTokenContract(); } - $.usdcToken = IERC20(_newUsdcToken); + $.usdcToken = IERC20(newUsdcToken); - emit UsdcTokenSet(_newUsdcToken); + emit UsdcTokenSet(newUsdcToken); } /** @@ -983,21 +987,21 @@ contract Payer is view returns (address[] memory addresses, bool hasMore) { - uint256 totalCount = addressSet.length(); + uint256 _totalCount = addressSet.length(); - if (offset >= totalCount) revert OutOfBounds(); + if (offset >= _totalCount) revert OutOfBounds(); - uint256 count = totalCount - offset; - if (count > limit) { - count = limit; + uint256 _count = _totalCount - offset; + if (_count > limit) { + _count = limit; hasMore = true; } else { hasMore = false; } - addresses = new address[](count); + addresses = new address[](_count); - for (uint256 i = 0; i < count; i++) { + for (uint256 i = 0; i < _count; i++) { addresses[i] = addressSet.at(offset + i); } @@ -1014,4 +1018,18 @@ contract Payer is require(newImplementation != address(0), InvalidAddress()); emit UpgradeAuthorized(msg.sender, newImplementation); } + + /* ============ ERC165 ============ */ + + /** + * @dev Override to support IPayer, IERC165 and AccessControlUpgradeable. + */ + function supportsInterface(bytes4 interfaceId) + public + view + override(IERC165, AccessControlUpgradeable) + returns (bool supported) + { + return interfaceId == type(IPayer).interfaceId || super.supportsInterface(interfaceId); + } } diff --git a/contracts/src/interfaces/IL2Distribution.sol b/contracts/src/interfaces/IL2Distribution.sol new file mode 100644 index 00000000..9439aa0b --- /dev/null +++ b/contracts/src/interfaces/IL2Distribution.sol @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; + +/** + * @title IDistribution + * @notice Interface for distributing rewards. + */ +interface IL2Distribution is IERC165 { + /* ============ Distribution ============ */ + + /** + * @notice Distributes the rewards. + * @dev Only callable by the Payer contract. When called: + * - The protocol fee is deducted and kept in the treasury. + * - The Node Operators are paid for their operational costs. + * - Any excess is split between: + * - The possibility of minting XMTP rebates to incentivize Payers. + * - Used to buy back and burn XMTP tokens. + */ + function distributeRewards() external; /* onlyPayerContract */ + + /* ============ Administrative Functions ============ */ + + /** + * @notice Refreshes the node operator list. + * @dev Only callable by the admin or active nodes. + * This function is used to refresh the node operator list. + * It is called when a new node is added, disabled or removed. + */ + function refreshNodeOperatorList() external; + + /** + * @notice Sets the address of the nodes contract for operator verification. + * @param nodesContract The address of the new nodes contract. + * + * Emits `NodesContractUpdated`. + */ + function setNodesContract(address nodesContract) external; + + /** + * @notice Sets the address of the payer contract. + * @param payerContract The address of the new payer contract. + * + * Emits `PayerContractUpdated`. + */ + function setPayerContract(address payerContract) external; + + /** + * @notice Sets the protocol fee. + * @param newProtocolFee New protocol fee (in basis points, e.g., 100 = 1%). + */ + function setProtocolFee(uint256 newProtocolFee) external; + + /** + * @notice Sets the rebates percentage which will be minted as XMTP rebates. + * @param newRebatesPercentage New rebates percentage. + * + * Emits `RebatesPercentageUpdated`. + */ + function setRebatesPercentage(uint256 newRebatesPercentage) external; + + /** + * @notice Sets the address of the USDC token contract. + * @param usdcToken The address of the new USDC token contract. + * + * Emits `UsdcTokenUpdated`. + */ + function setUsdcToken(address usdcToken) external; + + /* ============ Getters ============ */ + + /** + * @notice Returns the current address of the nodes contract. + * @return nodesContract The current address of the nodes contract. + */ + function getNodesContract() external view returns (address nodesContract); + + /** + * @notice Returns the current address of the payer contract. + * @return payerContract The current address of the payer contract. + */ + function getPayerContract() external view returns (address payerContract); + + /** + * @notice Returns the current protocol fee (in basis points). + * @return protocolFee The current protocol fee. + */ + function getProtocolFee() external view returns (uint256 protocolFee); + + /** + * @notice Returns the current rebates percentage (in basis points). + * @return rebatesPercentage The current rebates percentage. + */ + function getRebatesPercentage() external view returns (uint256 rebatesPercentage); + + /** + * @notice Returns the current address of the USDC token contract. + * @return usdcToken The current address of the USDC token contract. + */ + function getUsdcToken() external view returns (address usdcToken); +} From 4cb9e8139de8eddddf6c569a639bb12e0fd09a00 Mon Sep 17 00:00:00 2001 From: Borja Aranda Date: Mon, 17 Mar 2025 11:27:38 +0100 Subject: [PATCH 20/24] improve gas efficiency in some places --- contracts/src/Payer.sol | 124 +++++++++++++++------------- contracts/src/interfaces/IPayer.sol | 9 +- 2 files changed, 72 insertions(+), 61 deletions(-) diff --git a/contracts/src/Payer.sol b/contracts/src/Payer.sol index 43fee834..0beb2029 100644 --- a/contracts/src/Payer.sol +++ b/contracts/src/Payer.sol @@ -37,6 +37,7 @@ contract Payer is bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE"); string internal constant USDC_SYMBOL = "USDC"; + uint8 private constant PAYER_OPERATOR_ID = 1; uint64 private constant DEFAULT_MINIMUM_REGISTRATION_AMOUNT_MICRO_DOLLARS = 10_000_000; // 10 USD uint64 private constant DEFAULT_MINIMUM_DEPOSIT_AMOUNT_MICRO_DOLLARS = 10_000_000; // 10 USD uint64 private constant DEFAULT_MAX_TOLERABLE_DEBT_AMOUNT_MICRO_DOLLARS = 50_000_000; // 50 USD @@ -73,6 +74,7 @@ contract Payer is EnumerableSet.AddressSet activePayers; EnumerableSet.AddressSet debtPayers; } + // TODO: pack struct // keccak256(abi.encode(uint256(keccak256("xmtp.storage.Payer")) - 1)) & ~bytes32(uint256(0xff)) bytes32 internal constant PAYER_STORAGE_LOCATION = @@ -90,10 +92,8 @@ contract Payer is /** * @dev Modifier to check if caller is an active node operator. */ - modifier onlyNodeOperator() { - if (!_getIsActiveNodeOperator(msg.sender)) { - revert UnauthorizedNodeOperator(); - } + modifier onlyNodeOperator(uint256 nodeId) { + require(_getIsActiveNodeOperator(nodeId), UnauthorizedNodeOperator()); _; } @@ -101,9 +101,7 @@ contract Payer is * @dev Modifier to check if caller is the payer report contract. */ modifier onlyPayerReport() { - if (msg.sender != _getPayerStorage().payerReportContract) { - revert Unauthorized(); - } + require(msg.sender == _getPayerStorage().payerReportContract, Unauthorized()); _; } @@ -158,7 +156,8 @@ contract Payer is PayerStorage storage $ = _getPayerStorage(); require(amount >= $.minimumRegistrationAmountMicroDollars, InsufficientAmount()); - require(!_payerExists(msg.sender), PayerAlreadyRegistered()); + + if (_payerExists(msg.sender)) revert PayerAlreadyRegistered(); _deposit(msg.sender, amount); @@ -185,46 +184,30 @@ contract Payer is * @inheritdoc IPayer */ function deposit(uint256 amount) external whenNotPaused nonReentrant onlyPayer(msg.sender) { - PayerStorage storage $ = _getPayerStorage(); - - require(amount >= $.minimumDepositAmountMicroDollars, InsufficientAmount()); - require($.withdrawals[msg.sender].requestTimestamp == 0, PayerInWithdrawal()); - - _deposit(msg.sender, amount); - - _updatePayerBalance(msg.sender, amount); - - emit PayerBalanceUpdated(msg.sender, $.payers[msg.sender].balance, $.payers[msg.sender].debtAmount); + _validateAndProcessDeposit(msg.sender, msg.sender, amount); } /** * @inheritdoc IPayer */ function donate(address payer, uint256 amount) external whenNotPaused { - require(amount > 0, InsufficientAmount()); _revertIfPayerDoesNotExist(payer); + _validateAndProcessDeposit(msg.sender, payer, amount); PayerStorage storage $ = _getPayerStorage(); - require($.withdrawals[payer].requestTimestamp == 0, PayerInWithdrawal()); - - _deposit(msg.sender, amount); - - _updatePayerBalance(payer, amount); - $.payers[payer].latestDonationTimestamp = block.timestamp; - emit PayerBalanceUpdated(payer, $.payers[payer].balance, $.payers[payer].debtAmount); emit Donation(msg.sender, payer, amount); } /** * @inheritdoc IPayer */ - function deactivatePayer(address payer) external whenNotPaused onlyNodeOperator { + function deactivatePayer(uint256 nodeId, address payer) external whenNotPaused onlyNodeOperator(nodeId) { _revertIfPayerDoesNotExist(payer); - _deactivatePayer(payer); + _deactivatePayer(nodeId, payer); } /** @@ -237,7 +220,9 @@ contract Payer is require($.withdrawals[payer].requestTimestamp == 0, PayerInWithdrawal()); - if ($.payers[payer].balance > 0 || $.payers[payer].debtAmount > 0) { + Payer memory _storedPayer = $.payers[payer]; + + if (_storedPayer.balance > 0 || _storedPayer.debtAmount > 0) { revert PayerHasBalanceOrDebt(); } @@ -259,8 +244,10 @@ contract Payer is PayerStorage storage $ = _getPayerStorage(); - require($.payers[msg.sender].debtAmount == 0, PayerHasDebt()); - require($.payers[msg.sender].balance >= amount, InsufficientBalance()); + Payer memory _storedPayer = $.payers[msg.sender]; + + require(_storedPayer.debtAmount == 0, PayerHasDebt()); + require(_storedPayer.balance >= amount, InsufficientBalance()); // Balance to be withdrawn is deducted from the payer's balance, // it can't be used to settle payments. @@ -318,7 +305,7 @@ contract Payer is $.usdcToken.safeTransfer(msg.sender, _finalWithdrawalAmount); } - emit WithdrawalFinalized(msg.sender, _withdrawal.requestTimestamp); + emit WithdrawalFinalized(msg.sender, _withdrawal.requestTimestamp, _finalWithdrawalAmount); } /** @@ -345,7 +332,8 @@ contract Payer is PayerStorage storage $ = _getPayerStorage(); - uint256 _fees = 0; + uint256 _settledFees = 0; + uint256 _pendingFees = $.pendingFees; for (uint256 i = 0; i < payerList.length; i++) { address payer = payerList[i]; @@ -353,17 +341,15 @@ contract Payer is // This should never happen, as PayerReport has already verified the payers and amounts. // Payers in payerList should always exist and be active. - if (!_payerExists(payer) || !_payerIsActive(payer)) { - continue; - } + if (!_payerExists(payer) || !_payerIsActive(payer)) continue; Payer memory _storedPayer = $.payers[payer]; if (_storedPayer.balance < usage) { uint256 _debt = usage - _storedPayer.balance; - $.pendingFees += _storedPayer.balance; - _fees += _storedPayer.balance; + _settledFees += _storedPayer.balance; + _pendingFees += _storedPayer.balance; _storedPayer.balance = 0; _storedPayer.debtAmount = _debt; @@ -372,15 +358,15 @@ contract Payer is _addDebtor(payer); _increaseTotalDebtAmount(_debt); - if (_debt > $.maxTolerableDebtAmountMicroDollars) _deactivatePayer(payer); + if (_debt > $.maxTolerableDebtAmountMicroDollars) _deactivatePayer(PAYER_OPERATOR_ID, payer); emit PayerBalanceUpdated(payer, _storedPayer.balance, _storedPayer.debtAmount); continue; } - $.pendingFees += usage; - _fees += usage; + _settledFees += usage; + _pendingFees += usage; _storedPayer.balance -= usage; @@ -389,7 +375,9 @@ contract Payer is emit PayerBalanceUpdated(payer, _storedPayer.balance, _storedPayer.debtAmount); } - emit UsageSettled(originatorNode, block.timestamp, _fees); + $.pendingFees = _pendingFees; + + emit UsageSettled(originatorNode, block.timestamp, _settledFees); } /** @@ -404,17 +392,17 @@ contract Payer is // slither-disable-next-line timestamp require(block.timestamp - $.lastFeeTransferTimestamp >= $.transferFeesPeriod, InsufficientTimePassed()); - require($.pendingFees > 0, InsufficientAmount()); + uint256 _pendingFeesAmount = $.pendingFees; - uint256 _feesToTransfer = $.pendingFees; + require(_pendingFeesAmount > 0, InsufficientAmount()); - $.usdcToken.safeTransfer($.distributionContract, _feesToTransfer); + $.usdcToken.safeTransfer($.distributionContract, _pendingFeesAmount); $.lastFeeTransferTimestamp = block.timestamp; - $.collectedFees += $.pendingFees; + $.collectedFees += _pendingFeesAmount; $.pendingFees = 0; - emit FeesTransferred(block.timestamp, _feesToTransfer); + emit FeesTransferred(block.timestamp, _pendingFeesAmount); } /* ========== Administrative Functions ========== */ @@ -700,6 +688,24 @@ contract Payer is /* ============ Internal ============ */ + /** + * @notice Validates and processes a deposit or donation + * @param from The address funds are coming from + * @param to The payer account receiving the deposit + * @param amount The amount to deposit + */ + function _validateAndProcessDeposit(address from, address to, uint256 amount) internal { + PayerStorage storage $ = _getPayerStorage(); + + require(amount >= $.minimumDepositAmountMicroDollars, InsufficientAmount()); + require($.withdrawals[to].requestTimestamp == 0, PayerInWithdrawal()); + + _deposit(from, amount); + _updatePayerBalance(to, amount); + + emit PayerBalanceUpdated(to, $.payers[to].balance, $.payers[to].debtAmount); + } + /** * @notice Deposits USDC from a payer to the contract. * @param payer The address of the payer. @@ -720,11 +726,16 @@ contract Payer is function _updatePayerBalance(address payerAddress, uint256 amount) internal returns (uint256 leftoverAmount) { PayerStorage storage $ = _getPayerStorage(); - if ($.payers[payerAddress].debtAmount > 0) { + Payer memory _payer = $.payers[payerAddress]; + + if (_payer.debtAmount > 0) { return _settleDebts(payerAddress, amount); } else { - $.payers[payerAddress].balance += amount; + _payer.balance += amount; _increaseTotalAmountDeposited(amount); + + $.payers[payerAddress] = _payer; + return amount; } } @@ -787,7 +798,7 @@ contract Payer is * @notice Deactivates a payer. * @param payer The address of the payer to deactivate. */ - function _deactivatePayer(address payer) internal { + function _deactivatePayer(uint256 operatorId, address payer) internal { PayerStorage storage $ = _getPayerStorage(); $.payers[payer].isActive = false; @@ -795,7 +806,7 @@ contract Payer is // Deactivating a payer only removes them from the active payers set require($.activePayers.remove(payer), FailedToDeactivatePayer()); - emit PayerDeactivated(payer); + emit PayerDeactivated(operatorId, payer); } /** @@ -849,17 +860,16 @@ contract Payer is /** * @notice Checks if a given address is an active node operator. - * @param operator The address to check. + * @param nodeId The nodeID of the operator to check. * @return isActiveNodeOperator True if the address is an active node operator, false otherwise. */ - function _getIsActiveNodeOperator(address operator) internal view returns (bool isActiveNodeOperator) { + function _getIsActiveNodeOperator(uint256 nodeId) internal view returns (bool isActiveNodeOperator) { INodes nodes = INodes(_getPayerStorage().nodesContract); - require(address(nodes) != address(0), Unauthorized()); + require(msg.sender == nodes.ownerOf(nodeId), Unauthorized()); - // TODO: Implement this in Nodes contract - // return nodes.isActiveNodeOperator(operator); - return true; + // TODO: Change for a better filter. + return nodes.getReplicationNodeIsActive(nodeId); } /** diff --git a/contracts/src/interfaces/IPayer.sol b/contracts/src/interfaces/IPayer.sol index f8f0ef0a..96a08b51 100644 --- a/contracts/src/interfaces/IPayer.sol +++ b/contracts/src/interfaces/IPayer.sol @@ -33,7 +33,7 @@ interface IPayerEvents { event PayerBalanceUpdated(address indexed payer, uint256 newBalance, uint256 newDebtAmount); /// @dev Emitted when a payer is deactivated by an owner. - event PayerDeactivated(address indexed payer); + event PayerDeactivated(uint256 indexed operatorId, address indexed payer); /// @dev Emitted when a payer is permanently deleted from the system. event PayerDeleted(address indexed payer, uint256 timestamp); @@ -60,7 +60,7 @@ interface IPayerEvents { event WithdrawalCancelled(address indexed payer, uint256 indexed requestTimestamp); /// @dev Emitted when a payer's withdrawal is finalized. - event WithdrawalFinalized(address indexed payer, uint256 indexed requestTimestamp); + event WithdrawalFinalized(address indexed payer, uint256 indexed requestTimestamp, uint256 amount); /// @dev Emitted when the withdrawal lock period is updated. event WithdrawalLockPeriodSet(uint256 oldWithdrawalLockPeriod, uint256 newWithdrawalLockPeriod); @@ -256,11 +256,12 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { /** * @notice Deactivates a payer, signaling XMTP nodes they should not accept messages from them. * Only callable by authorized node operators. - * @param payer The address of the payer to deactivate. + * @param operatorId The ID of the operator calling the function. + * @param payer The address of the payer to deactivate. * * Emits `PayerDeactivated`. */ - function deactivatePayer(address payer) external; + function deactivatePayer(uint256 operatorId, address payer) external; /** * @notice Permanently deletes a payer from the system. From d41bdcf638a11b2801f970ef6bd4c98087292f50 Mon Sep 17 00:00:00 2001 From: Borja Aranda Date: Mon, 17 Mar 2025 11:30:50 +0100 Subject: [PATCH 21/24] remove _deposit --- contracts/src/Payer.sol | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/contracts/src/Payer.sol b/contracts/src/Payer.sol index 0beb2029..1e478c5c 100644 --- a/contracts/src/Payer.sol +++ b/contracts/src/Payer.sol @@ -159,7 +159,7 @@ contract Payer is if (_payerExists(msg.sender)) revert PayerAlreadyRegistered(); - _deposit(msg.sender, amount); + $.usdcToken.safeTransferFrom(msg.sender, address(this), amount); // New payer registration $.payers[msg.sender] = Payer({ @@ -699,22 +699,12 @@ contract Payer is require(amount >= $.minimumDepositAmountMicroDollars, InsufficientAmount()); require($.withdrawals[to].requestTimestamp == 0, PayerInWithdrawal()); - - _deposit(from, amount); - _updatePayerBalance(to, amount); - emit PayerBalanceUpdated(to, $.payers[to].balance, $.payers[to].debtAmount); - } + $.usdcToken.safeTransferFrom(from, address(this), amount); - /** - * @notice Deposits USDC from a payer to the contract. - * @param payer The address of the payer. - * @param amount The amount to deposit. - */ - function _deposit(address payer, uint256 amount) internal { - PayerStorage storage $ = _getPayerStorage(); + _updatePayerBalance(to, amount); - $.usdcToken.safeTransferFrom(payer, address(this), amount); + emit PayerBalanceUpdated(to, $.payers[to].balance, $.payers[to].debtAmount); } /** From e89de671a3508ea11929b213ecf392018569a324 Mon Sep 17 00:00:00 2001 From: Borja Aranda Date: Mon, 17 Mar 2025 12:29:29 +0100 Subject: [PATCH 22/24] pack structs for gas efficiency --- contracts/src/Payer.sol | 101 ++++++++++++++-------------- contracts/src/interfaces/IPayer.sol | 27 ++++---- 2 files changed, 65 insertions(+), 63 deletions(-) diff --git a/contracts/src/Payer.sol b/contracts/src/Payer.sol index 1e478c5c..d9c4e9dc 100644 --- a/contracts/src/Payer.sol +++ b/contracts/src/Payer.sol @@ -50,31 +50,37 @@ contract Payer is /// @custom:storage-location erc7201:xmtp.storage.Payer struct PayerStorage { - /// @dev Contracts to interact with. - IERC20 usdcToken; - address distributionContract; - address nodesContract; - address payerReportContract; - /// @dev Configuration parameters - uint64 minimumRegistrationAmountMicroDollars; - uint64 minimumDepositAmountMicroDollars; - uint64 maxTolerableDebtAmountMicroDollars; - uint32 withdrawalLockPeriod; - uint32 transferFeesPeriod; - /// @dev State variables - uint256 lastFeeTransferTimestamp; - uint256 totalAmountDeposited; - uint256 totalDebtAmount; - uint256 pendingFees; - uint256 collectedFees; - /// @dev Mappings + // 1. Configuration and state parameters packed in 2 slots. + uint64 minimumRegistrationAmountMicroDollars; // 8 bytes + uint64 minimumDepositAmountMicroDollars; // 8 bytes + uint64 maxTolerableDebtAmountMicroDollars; // 8 bytes + uint64 lastFeeTransferTimestamp; // 8 bytes + + uint64 totalAmountDeposited; // 8 bytes + uint64 totalDebtAmount; // 8 bytes + uint64 pendingFees; // 8 bytes + uint64 collectedFees; // 8 bytes + + uint32 withdrawalLockPeriod; // 4 bytes + uint32 transferFeesPeriod; // 4 bytes + uint32 reserved1; // 4 bytes (reserved for future use) + uint32 reserved2; // 4 bytes (reserved for future use) + + // 2. Contract addresses (each 20 bytes, fits in 3 slots) + IERC20 usdcToken; // 20 bytes + address distributionContract; // 20 bytes + address nodesContract; // 20 bytes + address payerReportContract; // 20 bytes + + // 3. Mappings and dynamic sets (each starts at its own storage slot) mapping(address => Payer) payers; mapping(address => Withdrawal) withdrawals; EnumerableSet.AddressSet totalPayers; EnumerableSet.AddressSet activePayers; EnumerableSet.AddressSet debtPayers; } - // TODO: pack struct + + // keccak256(abi.encode(uint256(keccak256("xmtp.storage.Payer")) - 1)) & ~bytes32(uint256(0xff)) bytes32 internal constant PAYER_STORAGE_LOCATION = @@ -152,7 +158,7 @@ contract Payer is /** * @inheritdoc IPayer */ - function register(uint256 amount) external whenNotPaused { + function register(uint64 amount) external whenNotPaused { PayerStorage storage $ = _getPayerStorage(); require(amount >= $.minimumRegistrationAmountMicroDollars, InsufficientAmount()); @@ -165,8 +171,8 @@ contract Payer is $.payers[msg.sender] = Payer({ balance: amount, debtAmount: 0, - creationTimestamp: block.timestamp, - latestDepositTimestamp: block.timestamp, + creationTimestamp: uint64(block.timestamp), + latestDepositTimestamp: uint64(block.timestamp), latestDonationTimestamp: 0, isActive: true }); @@ -183,20 +189,20 @@ contract Payer is /** * @inheritdoc IPayer */ - function deposit(uint256 amount) external whenNotPaused nonReentrant onlyPayer(msg.sender) { + function deposit(uint64 amount) external whenNotPaused nonReentrant onlyPayer(msg.sender) { _validateAndProcessDeposit(msg.sender, msg.sender, amount); } /** * @inheritdoc IPayer */ - function donate(address payer, uint256 amount) external whenNotPaused { + function donate(address payer, uint64 amount) external whenNotPaused { _revertIfPayerDoesNotExist(payer); _validateAndProcessDeposit(msg.sender, payer, amount); PayerStorage storage $ = _getPayerStorage(); - $.payers[payer].latestDonationTimestamp = block.timestamp; + $.payers[payer].latestDonationTimestamp = uint64(block.timestamp); emit Donation(msg.sender, payer, amount); } @@ -239,7 +245,7 @@ contract Payer is /** * @inheritdoc IPayer */ - function requestWithdrawal(uint256 amount) external whenNotPaused onlyPayer(msg.sender) { + function requestWithdrawal(uint64 amount) external whenNotPaused onlyPayer(msg.sender) { if (_withdrawalExists(msg.sender)) revert WithdrawalAlreadyRequested(); PayerStorage storage $ = _getPayerStorage(); @@ -257,8 +263,8 @@ contract Payer is uint256 withdrawableTimestamp = block.timestamp + $.withdrawalLockPeriod; $.withdrawals[msg.sender] = Withdrawal({ - requestTimestamp: block.timestamp, - withdrawableTimestamp: withdrawableTimestamp, + requestTimestamp: uint64(block.timestamp), + withdrawableTimestamp: uint64(withdrawableTimestamp), amount: amount }); @@ -322,7 +328,7 @@ contract Payer is /** * @inheritdoc IPayer */ - function settleUsage(uint256 originatorNode, address[] calldata payerList, uint256[] calldata usageAmountsList) + function settleUsage(uint256 originatorNode, address[] calldata payerList, uint64[] calldata usageAmountsList) external whenNotPaused nonReentrant @@ -332,12 +338,12 @@ contract Payer is PayerStorage storage $ = _getPayerStorage(); - uint256 _settledFees = 0; - uint256 _pendingFees = $.pendingFees; + uint64 _settledFees = 0; + uint64 _pendingFees = $.pendingFees; for (uint256 i = 0; i < payerList.length; i++) { address payer = payerList[i]; - uint256 usage = usageAmountsList[i]; + uint64 usage = usageAmountsList[i]; // This should never happen, as PayerReport has already verified the payers and amounts. // Payers in payerList should always exist and be active. @@ -346,7 +352,7 @@ contract Payer is Payer memory _storedPayer = $.payers[payer]; if (_storedPayer.balance < usage) { - uint256 _debt = usage - _storedPayer.balance; + uint64 _debt = usage - _storedPayer.balance; _settledFees += _storedPayer.balance; _pendingFees += _storedPayer.balance; @@ -392,13 +398,13 @@ contract Payer is // slither-disable-next-line timestamp require(block.timestamp - $.lastFeeTransferTimestamp >= $.transferFeesPeriod, InsufficientTimePassed()); - uint256 _pendingFeesAmount = $.pendingFees; + uint64 _pendingFeesAmount = $.pendingFees; require(_pendingFeesAmount > 0, InsufficientAmount()); $.usdcToken.safeTransfer($.distributionContract, _pendingFeesAmount); - $.lastFeeTransferTimestamp = block.timestamp; + $.lastFeeTransferTimestamp = uint64(block.timestamp); $.collectedFees += _pendingFeesAmount; $.pendingFees = 0; @@ -694,7 +700,7 @@ contract Payer is * @param to The payer account receiving the deposit * @param amount The amount to deposit */ - function _validateAndProcessDeposit(address from, address to, uint256 amount) internal { + function _validateAndProcessDeposit(address from, address to, uint64 amount) internal { PayerStorage storage $ = _getPayerStorage(); require(amount >= $.minimumDepositAmountMicroDollars, InsufficientAmount()); @@ -713,19 +719,14 @@ contract Payer is * @param amount The amount to add to the payer's balance. * @return leftoverAmount Amount remaining after debt settlement (if any). */ - function _updatePayerBalance(address payerAddress, uint256 amount) internal returns (uint256 leftoverAmount) { - PayerStorage storage $ = _getPayerStorage(); - - Payer memory _payer = $.payers[payerAddress]; + function _updatePayerBalance(address payerAddress, uint64 amount) internal returns (uint256 leftoverAmount) { + Payer storage _payer = _getPayerStorage().payers[payerAddress]; if (_payer.debtAmount > 0) { return _settleDebts(payerAddress, amount); } else { _payer.balance += amount; _increaseTotalAmountDeposited(amount); - - $.payers[payerAddress] = _payer; - return amount; } } @@ -736,13 +737,13 @@ contract Payer is * @param amount The amount to settle debts for. * @return amountAfterSettlement The amount remaining after debt settlement. */ - function _settleDebts(address payer, uint256 amount) internal returns (uint256 amountAfterSettlement) { + function _settleDebts(address payer, uint64 amount) internal returns (uint256 amountAfterSettlement) { PayerStorage storage $ = _getPayerStorage(); Payer memory _storedPayer = $.payers[payer]; if (_storedPayer.debtAmount < amount) { - uint256 _debtToRemove = _storedPayer.debtAmount; + uint64 _debtToRemove = _storedPayer.debtAmount; amount -= _debtToRemove; _storedPayer.debtAmount = 0; @@ -942,15 +943,15 @@ contract Payer is * @notice Increases the total amount deposited by a given amount. * @param amount The amount to increase the total amount deposited by. */ - function _increaseTotalAmountDeposited(uint256 amount) internal { - _getPayerStorage().totalAmountDeposited += amount; + function _increaseTotalAmountDeposited(uint64 amount) internal { + if (amount > 0) _getPayerStorage().totalAmountDeposited += amount; } /** * @notice Decreases the total amount deposited by a given amount. * @param amount The amount to decrease the total amount deposited by. */ - function _decreaseTotalAmountDeposited(uint256 amount) internal { + function _decreaseTotalAmountDeposited(uint64 amount) internal { PayerStorage storage $ = _getPayerStorage(); $.totalAmountDeposited = amount > $.totalAmountDeposited ? 0 : $.totalAmountDeposited - amount; @@ -960,7 +961,7 @@ contract Payer is * @notice Increases the total debt amount by a given amount. * @param amount The amount to increase the total debt amount by. */ - function _increaseTotalDebtAmount(uint256 amount) internal { + function _increaseTotalDebtAmount(uint64 amount) internal { _getPayerStorage().totalDebtAmount += amount; } @@ -968,7 +969,7 @@ contract Payer is * @notice Decreases the total debt amount by a given amount. * @param amount The amount to decrease the total debt amount by. */ - function _decreaseTotalDebtAmount(uint256 amount) internal { + function _decreaseTotalDebtAmount(uint64 amount) internal { PayerStorage storage $ = _getPayerStorage(); $.totalDebtAmount = amount > $.totalDebtAmount ? 0 : $.totalDebtAmount - amount; diff --git a/contracts/src/interfaces/IPayer.sol b/contracts/src/interfaces/IPayer.sol index 96a08b51..cd04ab80 100644 --- a/contracts/src/interfaces/IPayer.sol +++ b/contracts/src/interfaces/IPayer.sol @@ -200,14 +200,15 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { * @param isActive Indicates whether the payer is active. * @param creationTimestamp The timestamp when the payer was first registered. * @param latestDepositTimestamp The timestamp of the most recent deposit. + * @param latestDonationTimestamp The timestamp of the most recent donation. * @param debtAmount The amount of fees owed but not yet settled. */ struct Payer { - uint256 balance; - uint256 debtAmount; - uint256 creationTimestamp; - uint256 latestDepositTimestamp; - uint256 latestDonationTimestamp; + uint64 balance; + uint64 debtAmount; + uint64 creationTimestamp; + uint64 latestDepositTimestamp; + uint64 latestDonationTimestamp; bool isActive; } @@ -218,9 +219,9 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { * @param amount The amount requested for withdrawal. */ struct Withdrawal { - uint256 requestTimestamp; - uint256 withdrawableTimestamp; - uint256 amount; + uint64 requestTimestamp; + uint64 withdrawableTimestamp; + uint64 amount; } /* ============ Payer Management ============ */ @@ -232,7 +233,7 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { * * Emits `PayerRegistered`. */ - function register(uint256 amount) external; + function register(uint64 amount) external; /** * @notice Allows the caller to deposit USDC into their own payer account. @@ -241,7 +242,7 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { * * Emits `Deposit`. */ - function deposit(uint256 amount) external; + function deposit(uint64 amount) external; /** * @notice Allows anyone to donate USDC to an existing payer's account. @@ -251,7 +252,7 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { * * Emits `Donation`. */ - function donate(address payer, uint256 amount) external; + function donate(address payer, uint64 amount) external; /** * @notice Deactivates a payer, signaling XMTP nodes they should not accept messages from them. @@ -283,7 +284,7 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { * * Emits `WithdrawalRequest`. */ - function requestWithdrawal(uint256 amount) external; + function requestWithdrawal(uint64 amount) external; /** * @notice Cancels a previously requested withdrawal, removing withdrawal mode. @@ -323,7 +324,7 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { function settleUsage( uint256 originatorNode, address[] calldata payers, - uint256[] calldata amounts + uint64[] calldata amounts ) external; /* onlyPayerReport */ /** From 0118fb24e3e43ddcc21b98ca03f17f3e6e130e4c Mon Sep 17 00:00:00 2001 From: Borja Aranda Date: Mon, 17 Mar 2025 13:14:59 +0100 Subject: [PATCH 23/24] update withdrawal logic --- contracts/src/Payer.sol | 75 ++++++++++++++++------------- contracts/src/interfaces/IPayer.sol | 47 +++++++++--------- 2 files changed, 67 insertions(+), 55 deletions(-) diff --git a/contracts/src/Payer.sol b/contracts/src/Payer.sol index d9c4e9dc..be963959 100644 --- a/contracts/src/Payer.sol +++ b/contracts/src/Payer.sol @@ -50,29 +50,25 @@ contract Payer is /// @custom:storage-location erc7201:xmtp.storage.Payer struct PayerStorage { - // 1. Configuration and state parameters packed in 2 slots. + // Configuration and state parameters (fits in 2 slots) uint64 minimumRegistrationAmountMicroDollars; // 8 bytes uint64 minimumDepositAmountMicroDollars; // 8 bytes uint64 maxTolerableDebtAmountMicroDollars; // 8 bytes uint64 lastFeeTransferTimestamp; // 8 bytes - uint64 totalAmountDeposited; // 8 bytes uint64 totalDebtAmount; // 8 bytes uint64 pendingFees; // 8 bytes uint64 collectedFees; // 8 bytes - uint32 withdrawalLockPeriod; // 4 bytes uint32 transferFeesPeriod; // 4 bytes - uint32 reserved1; // 4 bytes (reserved for future use) - uint32 reserved2; // 4 bytes (reserved for future use) - // 2. Contract addresses (each 20 bytes, fits in 3 slots) + // Contract addresses (fits in 3 slots) IERC20 usdcToken; // 20 bytes address distributionContract; // 20 bytes address nodesContract; // 20 bytes address payerReportContract; // 20 bytes - // 3. Mappings and dynamic sets (each starts at its own storage slot) + // Mappings and dynamic sets (each starts at its own storage slot) mapping(address => Payer) payers; mapping(address => Withdrawal) withdrawals; EnumerableSet.AddressSet totalPayers; @@ -237,7 +233,7 @@ contract Payer is require($.totalPayers.remove(payer), FailedToDeletePayer()); require($.activePayers.remove(payer), FailedToDeletePayer()); - emit PayerDeleted(payer, block.timestamp); + emit PayerDeleted(payer, uint64(block.timestamp)); } /* ========== Payers Balance Management ========= */ @@ -260,15 +256,17 @@ contract Payer is $.payers[msg.sender].balance -= amount; _decreaseTotalAmountDeposited(amount); - uint256 withdrawableTimestamp = block.timestamp + $.withdrawalLockPeriod; + uint64 withdrawableTimestamp = uint64(block.timestamp) + $.withdrawalLockPeriod; $.withdrawals[msg.sender] = Withdrawal({ requestTimestamp: uint64(block.timestamp), - withdrawableTimestamp: uint64(withdrawableTimestamp), + withdrawableTimestamp: withdrawableTimestamp, amount: amount }); - emit WithdrawalRequested(msg.sender, block.timestamp, withdrawableTimestamp, amount); + emit PayerBalanceUpdated(msg.sender, $.payers[msg.sender].balance, $.payers[msg.sender].debtAmount); + + emit WithdrawalRequested(msg.sender, uint64(block.timestamp), withdrawableTimestamp, amount); } /** @@ -286,6 +284,8 @@ contract Payer is $.payers[msg.sender].balance += _withdrawal.amount; _increaseTotalAmountDeposited(_withdrawal.amount); + emit PayerBalanceUpdated(msg.sender, $.payers[msg.sender].balance, $.payers[msg.sender].debtAmount); + emit WithdrawalCancelled(msg.sender, _withdrawal.requestTimestamp); } @@ -299,18 +299,22 @@ contract Payer is Withdrawal memory _withdrawal = $.withdrawals[msg.sender]; + require(block.timestamp >= _withdrawal.withdrawableTimestamp, WithdrawalPeriodNotElapsed()); + delete $.withdrawals[msg.sender]; - uint256 _finalWithdrawalAmount = _withdrawal.amount; + uint64 _finalWithdrawalAmount = _withdrawal.amount; if ($.payers[msg.sender].debtAmount > 0) { - _finalWithdrawalAmount = _settleDebts(msg.sender, _withdrawal.amount); + _finalWithdrawalAmount = _settleDebts(msg.sender, _withdrawal.amount, true); } if (_finalWithdrawalAmount > 0) { $.usdcToken.safeTransfer(msg.sender, _finalWithdrawalAmount); } + emit PayerBalanceUpdated(msg.sender, $.payers[msg.sender].balance, $.payers[msg.sender].debtAmount); + emit WithdrawalFinalized(msg.sender, _withdrawal.requestTimestamp, _finalWithdrawalAmount); } @@ -383,7 +387,7 @@ contract Payer is $.pendingFees = _pendingFees; - emit UsageSettled(originatorNode, block.timestamp, _settledFees); + emit UsageSettled(originatorNode, uint64(block.timestamp), _settledFees); } /** @@ -408,7 +412,7 @@ contract Payer is $.collectedFees += _pendingFeesAmount; $.pendingFees = 0; - emit FeesTransferred(block.timestamp, _pendingFeesAmount); + emit FeesTransferred(uint64(block.timestamp), _pendingFeesAmount); } /* ========== Administrative Functions ========== */ @@ -449,7 +453,7 @@ contract Payer is PayerStorage storage $ = _getPayerStorage(); - uint256 oldMinimumDeposit = $.minimumDepositAmountMicroDollars; + uint64 oldMinimumDeposit = $.minimumDepositAmountMicroDollars; $.minimumDepositAmountMicroDollars = newMinimumDeposit; emit MinimumDepositSet(oldMinimumDeposit, newMinimumDeposit); @@ -466,7 +470,7 @@ contract Payer is PayerStorage storage $ = _getPayerStorage(); - uint256 _oldMinimumRegistrationAmount = $.minimumRegistrationAmountMicroDollars; + uint64 _oldMinimumRegistrationAmount = $.minimumRegistrationAmountMicroDollars; $.minimumRegistrationAmountMicroDollars = newMinimumRegistrationAmount; emit MinimumRegistrationAmountSet(_oldMinimumRegistrationAmount, newMinimumRegistrationAmount); @@ -480,7 +484,7 @@ contract Payer is PayerStorage storage $ = _getPayerStorage(); - uint256 _oldWithdrawalLockPeriod = $.withdrawalLockPeriod; + uint32 _oldWithdrawalLockPeriod = $.withdrawalLockPeriod; $.withdrawalLockPeriod = newWithdrawalLockPeriod; emit WithdrawalLockPeriodSet(_oldWithdrawalLockPeriod, newWithdrawalLockPeriod); @@ -542,7 +546,7 @@ contract Payer is /** * @inheritdoc IPayer */ - function getActivePayers(uint256 offset, uint256 limit) + function getActivePayers(uint32 offset, uint32 limit) external view returns (Payer[] memory payers, bool hasMore) @@ -571,7 +575,7 @@ contract Payer is /** * @inheritdoc IPayer */ - function getPayerBalance(address payer) external view returns (uint256 balance) { + function getPayerBalance(address payer) external view returns (uint64 balance) { _revertIfPayerDoesNotExist(payer); return _getPayerStorage().payers[payer].balance; @@ -580,7 +584,7 @@ contract Payer is /** * @inheritdoc IPayer */ - function getPayersInDebt(uint256 offset, uint256 limit) + function getPayersInDebt(uint32 offset, uint32 limit) external view returns (Payer[] memory payers, bool hasMore) @@ -614,14 +618,14 @@ contract Payer is /** * @inheritdoc IPayer */ - function getLastFeeTransferTimestamp() external view returns (uint256 timestamp) { + function getLastFeeTransferTimestamp() external view returns (uint64 timestamp) { return _getPayerStorage().lastFeeTransferTimestamp; } /** * @inheritdoc IPayer */ - function getTotalValueLocked() external view returns (uint256 totalValueLocked) { + function getTotalValueLocked() external view returns (uint64 totalValueLocked) { PayerStorage storage $ = _getPayerStorage(); if ($.totalDebtAmount > $.totalAmountDeposited) return 0; @@ -632,7 +636,7 @@ contract Payer is /** * @inheritdoc IPayer */ - function getTotalDebtAmount() external view returns (uint256 totalDebt) { + function getTotalDebtAmount() external view returns (uint64 totalDebt) { return _getPayerStorage().totalDebtAmount; } @@ -667,28 +671,28 @@ contract Payer is /** * @inheritdoc IPayer */ - function getMinimumDeposit() external view returns (uint256 minimumDeposit) { + function getMinimumDeposit() external view returns (uint64 minimumDeposit) { return _getPayerStorage().minimumDepositAmountMicroDollars; } /** * @inheritdoc IPayer */ - function getMinimumRegistrationAmount() external view returns (uint256 minimumRegistrationAmount) { + function getMinimumRegistrationAmount() external view returns (uint64 minimumRegistrationAmount) { return _getPayerStorage().minimumRegistrationAmountMicroDollars; } /** * @inheritdoc IPayer */ - function getWithdrawalLockPeriod() external view returns (uint256 lockPeriod) { + function getWithdrawalLockPeriod() external view returns (uint32 lockPeriod) { return _getPayerStorage().withdrawalLockPeriod; } /** * @inheritdoc IPayer */ - function getPendingFees() external view returns (uint256 fees) { + function getPendingFees() external view returns (uint64 fees) { return _getPayerStorage().pendingFees; } @@ -719,11 +723,11 @@ contract Payer is * @param amount The amount to add to the payer's balance. * @return leftoverAmount Amount remaining after debt settlement (if any). */ - function _updatePayerBalance(address payerAddress, uint64 amount) internal returns (uint256 leftoverAmount) { + function _updatePayerBalance(address payerAddress, uint64 amount) internal returns (uint64 leftoverAmount) { Payer storage _payer = _getPayerStorage().payers[payerAddress]; if (_payer.debtAmount > 0) { - return _settleDebts(payerAddress, amount); + return _settleDebts(payerAddress, amount, false); } else { _payer.balance += amount; _increaseTotalAmountDeposited(amount); @@ -735,9 +739,10 @@ contract Payer is * @notice Settles debts for a payer, updating their balance and total amounts. * @param payer The address of the payer. * @param amount The amount to settle debts for. + * @param isWithdrawal Whether the debt settlement happens during a withdrawal. * @return amountAfterSettlement The amount remaining after debt settlement. */ - function _settleDebts(address payer, uint64 amount) internal returns (uint256 amountAfterSettlement) { + function _settleDebts(address payer, uint64 amount, bool isWithdrawal) internal returns (uint64 amountAfterSettlement) { PayerStorage storage $ = _getPayerStorage(); Payer memory _storedPayer = $.payers[payer]; @@ -746,8 +751,12 @@ contract Payer is uint64 _debtToRemove = _storedPayer.debtAmount; amount -= _debtToRemove; - _storedPayer.debtAmount = 0; - _storedPayer.balance += amount; + // For regular deposits, add remaining amount to balance. + // In withdrawals, that amount was moved to the withdrawal balance. + if (!isWithdrawal) { + _storedPayer.balance += amount; + _increaseTotalAmountDeposited(amount); + } _removeDebtor(payer); _increaseTotalAmountDeposited(amount); diff --git a/contracts/src/interfaces/IPayer.sol b/contracts/src/interfaces/IPayer.sol index cd04ab80..ee3b83f9 100644 --- a/contracts/src/interfaces/IPayer.sol +++ b/contracts/src/interfaces/IPayer.sol @@ -12,34 +12,34 @@ interface IPayerEvents { event DistributionContractSet(address indexed newDistributionContract); /// @dev Emitted when a user donates to a payer's account. - event Donation(address indexed donor, address indexed payer, uint256 amount); + event Donation(address indexed donor, address indexed payer, uint64 amount); /// @dev Emitted when fees are transferred to the distribution contract. - event FeesTransferred(uint256 indexed timestamp, uint256 amount); + event FeesTransferred(uint64 indexed timestamp, uint64 amount); /// @dev Emitted when the maximum tolerable debt amount is updated. event MaxTolerableDebtAmountSet(uint64 oldMaxTolerableDebtAmount, uint64 newMaxTolerableDebtAmount); /// @dev Emitted when the minimum deposit amount is updated. - event MinimumDepositSet(uint256 oldMinimumDeposit, uint256 newMinimumDeposit); + event MinimumDepositSet(uint64 oldMinimumDeposit, uint64 newMinimumDeposit); /// @dev Emitted when the minimum registration amount is updated. - event MinimumRegistrationAmountSet(uint256 oldMinimumRegistrationAmount, uint256 newMinimumRegistrationAmount); + event MinimumRegistrationAmountSet(uint64 oldMinimumRegistrationAmount, uint64 newMinimumRegistrationAmount); /// @dev Emitted when the nodes contract address is updated. event NodesContractSet(address indexed newNodesContract); /// @dev Emitted when a payer balance is updated. - event PayerBalanceUpdated(address indexed payer, uint256 newBalance, uint256 newDebtAmount); + event PayerBalanceUpdated(address indexed payer, uint64 newBalance, uint64 newDebtAmount); /// @dev Emitted when a payer is deactivated by an owner. event PayerDeactivated(uint256 indexed operatorId, address indexed payer); /// @dev Emitted when a payer is permanently deleted from the system. - event PayerDeleted(address indexed payer, uint256 timestamp); + event PayerDeleted(address indexed payer, uint64 timestamp); /// @dev Emitted when a new payer is registered. - event PayerRegistered(address indexed payer, uint256 amount); + event PayerRegistered(address indexed payer, uint64 amount); /// @dev Emitted when the payer report contract address is updated. event PayerReportContractSet(address indexed newPayerReportContract); @@ -51,23 +51,23 @@ interface IPayerEvents { event UpgradeAuthorized(address indexed upgrader, address indexed newImplementation); /// @dev Emitted when usage is settled and fees are calculated. - event UsageSettled(uint256 indexed originatorNode, uint256 timestamp, uint256 collectedFees); + event UsageSettled(uint256 indexed originatorNode, uint64 timestamp, uint64 collectedFees); /// @dev Emitted when the USDC token address is updated. event UsdcTokenSet(address indexed newUsdcToken); /// @dev Emitted when a payer cancels a withdrawal request. - event WithdrawalCancelled(address indexed payer, uint256 indexed requestTimestamp); + event WithdrawalCancelled(address indexed payer, uint64 indexed requestTimestamp); /// @dev Emitted when a payer's withdrawal is finalized. - event WithdrawalFinalized(address indexed payer, uint256 indexed requestTimestamp, uint256 amount); + event WithdrawalFinalized(address indexed payer, uint64 indexed requestTimestamp, uint64 amount); /// @dev Emitted when the withdrawal lock period is updated. - event WithdrawalLockPeriodSet(uint256 oldWithdrawalLockPeriod, uint256 newWithdrawalLockPeriod); + event WithdrawalLockPeriodSet(uint32 oldWithdrawalLockPeriod, uint32 newWithdrawalLockPeriod); /// @dev Emitted when a payer initiates a withdrawal request. event WithdrawalRequested( - address indexed payer, uint256 indexed requestTimestamp, uint256 withdrawableTimestamp, uint256 amount + address indexed payer, uint64 indexed requestTimestamp, uint64 withdrawableTimestamp, uint64 amount ); } @@ -184,6 +184,9 @@ interface IPayerErrors { /// @dev Error thrown when a withdrawal is not in the requested state. error WithdrawalNotRequested(); + + /// @dev Error thrown when a withdrawal lock period has not yet elapsed. + error WithdrawalPeriodNotElapsed(); } /** @@ -439,7 +442,7 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { * @return payers The payer information. * @return hasMore True if there are more payers to retrieve. */ - function getActivePayers(uint256 offset, uint256 limit) + function getActivePayers(uint32 offset, uint32 limit) external view returns (Payer[] memory payers, bool hasMore); @@ -458,7 +461,7 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { * @return payers Array of payer addresses with debt. * @return hasMore True if there are more payers to retrieve. */ - function getPayersInDebt(uint256 offset, uint256 limit) + function getPayersInDebt(uint32 offset, uint32 limit) external view returns (Payer[] memory payers, bool hasMore); @@ -479,19 +482,19 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { * @notice Returns the timestamp of the last fee transfer to the rewards contract. * @return timestamp The last fee transfer timestamp. */ - function getLastFeeTransferTimestamp() external view returns (uint256 timestamp); + function getLastFeeTransferTimestamp() external view returns (uint64 timestamp); /** * @notice Returns the total value locked in the contract (all payer balances). * @return tvl The total value locked in USDC. */ - function getTotalValueLocked() external view returns (uint256 tvl); + function getTotalValueLocked() external view returns (uint64 tvl); /** * @notice Returns the total outstanding debt amount across all payers. * @return totalDebt The total debt amount in USDC. */ - function getTotalDebtAmount() external view returns (uint256 totalDebt); + function getTotalDebtAmount() external view returns (uint64 totalDebt); /** * @notice Returns the actual USDC balance held by the contract. @@ -522,32 +525,32 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { * @notice Retrieves the minimum deposit amount required to register as a payer. * @return minimumDeposit The minimum deposit amount in USDC. */ - function getMinimumDeposit() external view returns (uint256 minimumDeposit); + function getMinimumDeposit() external view returns (uint64 minimumDeposit); /** * @notice Retrieves the minimum deposit amount required to register as a payer. * @return minimumRegistrationAmount The minimum deposit amount in USDC. */ - function getMinimumRegistrationAmount() external view returns (uint256 minimumRegistrationAmount); + function getMinimumRegistrationAmount() external view returns (uint64 minimumRegistrationAmount); /** * @notice Retrieves the current total balance of a given payer. * @param payer The address of the payer. * @return balance The current balance of the payer. */ - function getPayerBalance(address payer) external view returns (uint256 balance); + function getPayerBalance(address payer) external view returns (uint64 balance); /** * @notice Returns the duration of the lock period required before a withdrawal * can be finalized. * @return lockPeriod The lock period in seconds. */ - function getWithdrawalLockPeriod() external view returns (uint256 lockPeriod); + function getWithdrawalLockPeriod() external view returns (uint32 lockPeriod); /** * @notice Retrieves the total pending fees that have not yet been transferred * to the distribution contract. * @return fees The total pending fees in USDC. */ - function getPendingFees() external view returns (uint256 fees); + function getPendingFees() external view returns (uint64 fees); } From c06a4c2a44608c9072fcbff7cc872e24b9ecb517 Mon Sep 17 00:00:00 2001 From: Borja Aranda Date: Mon, 17 Mar 2025 13:55:30 +0100 Subject: [PATCH 24/24] update intergaface --- contracts/src/interfaces/IPayer.sol | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/contracts/src/interfaces/IPayer.sol b/contracts/src/interfaces/IPayer.sol index ee3b83f9..1531fd54 100644 --- a/contracts/src/interfaces/IPayer.sol +++ b/contracts/src/interfaces/IPayer.sol @@ -243,7 +243,7 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { * The caller must approve this contract to spend USDC beforehand. * @param amount The amount of USDC to deposit. * - * Emits `Deposit`. + * Emits `PayerBalanceUpdated`. */ function deposit(uint64 amount) external; @@ -253,6 +253,7 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { * @param payer The address of the payer receiving the donation. * @param amount The amount of USDC to donate. * + * Emits `PayerBalanceUpdated`. * Emits `Donation`. */ function donate(address payer, uint64 amount) external; @@ -286,6 +287,7 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { * @param amount The amount to withdraw (can be less than or equal to current balance). * * Emits `WithdrawalRequest`. + * Emits `PayerBalanceUpdated`. */ function requestWithdrawal(uint64 amount) external; @@ -294,6 +296,7 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { * @dev Only callable by the payer who initiated the withdrawal. * * Emits `WithdrawalCancelled`. + * Emits `PayerBalanceUpdated`. */ function cancelWithdrawal() external; @@ -303,6 +306,7 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { * - Returns the unspent balance to the payer. * * Emits `WithdrawalFinalized`. + * Emits `PayerBalanceUpdated`. */ function finalizeWithdrawal() external; @@ -323,6 +327,9 @@ interface IPayer is IERC165, IPayerEvents, IPayerErrors { * @param originatorNode The originator node of the usage. * @param payers A contiguous array of payer addresses. * @param amounts A contiguous array of usage amounts corresponding to each payer. + * + * Emits `UsageSettled`. + * Emits `PayerBalanceUpdated` for each payer. */ function settleUsage( uint256 originatorNode,