// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity ^0.8.3;

import '@openzeppelin/contracts/utils/structs/EnumerableSet.sol';

import '@mimic-fi/v2-helpers/contracts/math/FixedPoint.sol';

import './BaseAction.sol';
import './interfaces/ITokenThresholdAction.sol';

/**
 * @dev Token threshold action. It mainly works with token threshold configs that can be used to tell if
 * a specific token amount is compliant with certain minimum or maximum values. Token threshold actions
 * make use of a default threshold config as a fallback in case there is no custom threshold defined for the token
 * being evaluated.
 */
abstract contract TokenThresholdAction is ITokenThresholdAction, BaseAction {
    using FixedPoint for uint256;
    using EnumerableSet for EnumerableSet.AddressSet;

    // Default threshold
    Threshold private _defaultThreshold;

    // Custom thresholds per token
    TokenToThresholdMap private _customThresholds;

    /**
     * @dev Enumerable map of tokens to threshold configs
     */
    struct TokenToThresholdMap {
        EnumerableSet.AddressSet tokens;
        mapping (address => Threshold) thresholds;
    }

    /**
     * @dev Custom token threshold config
     */
    struct CustomThreshold {
        address token;
        Threshold threshold;
    }

    /**
     * @dev Token threshold config. Only used in the constructor.
     * @param defaultThreshold Default threshold to be set
     * @param tokens List of tokens to define a custom threshold for
     * @param thresholds List of custom thresholds to define for each token
     */
    struct TokenThresholdConfig {
        Threshold defaultThreshold;
        CustomThreshold[] customThresholds;
    }

    /**
     * @dev Creates a new token threshold action
     */
    constructor(TokenThresholdConfig memory config) {
        if (config.defaultThreshold.token != address(0)) {
            _setDefaultTokenThreshold(config.defaultThreshold);
        }

        for (uint256 i = 0; i < config.customThresholds.length; i++) {
            _setCustomTokenThreshold(config.customThresholds[i].token, config.customThresholds[i].threshold);
        }
    }

    /**
     * @dev Tells the default token threshold
     */
    function getDefaultTokenThreshold() public view override returns (Threshold memory) {
        return _defaultThreshold;
    }

    /**
     * @dev Tells the token threshold defined for a specific token
     * @param token Address of the token being queried
     */
    function getCustomTokenThreshold(address token)
        public
        view
        override
        returns (bool exists, Threshold memory threshold)
    {
        threshold = _customThresholds.thresholds[token];
        return (_customThresholds.tokens.contains(token), threshold);
    }

    /**
     * @dev Tells the list of custom token thresholds set
     */
    function getCustomTokenThresholds()
        public
        view
        override
        returns (address[] memory tokens, Threshold[] memory thresholds)
    {
        tokens = new address[](_customThresholds.tokens.length());
        thresholds = new Threshold[](tokens.length);
        for (uint256 i = 0; i < tokens.length; i++) {
            (address token, Threshold memory threshold) = _getTokenThresholdAt(i);
            tokens[i] = token;
            thresholds[i] = threshold;
        }
    }

    /**
     * @dev Sets a new default threshold config
     * @param threshold Threshold config to be set as the default one. Threshold token cannot be zero and max amount
     * must be greater than or equal to the min amount, with the exception of max being set to zero in which case it
     * will be ignored.
     */
    function setDefaultTokenThreshold(Threshold memory threshold) external override auth {
        _setDefaultTokenThreshold(threshold);
    }

    /**
     * @dev Unsets the default threshold, it ignores the request if it was not set
     */
    function unsetDefaultTokenThreshold() external override auth {
        _unsetDefaultTokenThreshold();
    }

    /**
     * @dev Sets a list of tokens thresholds
     * @param tokens List of token addresses to set its custom thresholds
     * @param thresholds Lists of thresholds be set for each token. Threshold token cannot be zero and max amount
     * must be greater than or equal to the min amount, with the exception of max being set to zero in which case it
     * will be ignored.
     */
    function setCustomTokenThresholds(address[] memory tokens, Threshold[] memory thresholds) external override auth {
        _setCustomTokenThresholds(tokens, thresholds);
    }

    /**
     * @dev Unsets a list of custom threshold tokens, it ignores nonexistent custom thresholds
     * @param tokens List of token addresses to unset its custom thresholds
     */
    function unsetCustomTokenThresholds(address[] memory tokens) external override auth {
        _unsetCustomTokenThresholds(tokens);
    }

    /**
     * @dev Returns the token-threshold that should be applied for a token. If there is a custom threshold set it will
     * prioritized over the default threshold. If non of them are defined a null threshold is returned.
     * @param token Address of the token querying the threshold of
     */
    function _getApplicableTokenThreshold(address token) internal view returns (Threshold memory) {
        (bool exists, Threshold memory threshold) = getCustomTokenThreshold(token);
        return exists ? threshold : getDefaultTokenThreshold();
    }

    /**
     * @dev Tells if a token and amount are compliant with a threshold, returns true if the threshold is not set
     * @param threshold Threshold to be evaluated
     * @param token Address of the token to be validated
     * @param amount Token amount to be validated
     */
    function _isTokenThresholdValid(Threshold memory threshold, address token, uint256 amount)
        internal
        view
        returns (bool)
    {
        if (threshold.token == address(0)) return true;
        uint256 price = _getPrice(token, threshold.token);
        uint256 convertedAmount = amount.mulDown(price);
        return convertedAmount >= threshold.min && (threshold.max == 0 || convertedAmount <= threshold.max);
    }

    /**
     * @dev Reverts if the requested token and amount does not comply with the given threshold config
     */
    function _beforeAction(address token, uint256 amount) internal virtual override {
        Threshold memory threshold = _getApplicableTokenThreshold(token);
        require(_isTokenThresholdValid(threshold, token, amount), 'ACTION_TOKEN_THRESHOLD_NOT_MET');
    }

    /**
     * @dev Sets a new default threshold config
     * @param threshold Threshold config to be set as the default one. Threshold token cannot be zero and max amount
     * must be greater than or equal to the min amount, with the exception of max being set to zero in which case it
     * will be ignored.
     */
    function _setDefaultTokenThreshold(Threshold memory threshold) internal {
        _validateThreshold(threshold);
        _defaultThreshold = threshold;
        emit DefaultTokenThresholdSet(threshold);
    }

    /**
     * @dev Unsets a the default threshold config
     */
    function _unsetDefaultTokenThreshold() internal {
        delete _defaultThreshold;
        emit DefaultTokenThresholdUnset();
    }

    /**
     * @dev Sets a list of custom tokens thresholds
     * @param tokens List of token addresses to set its custom thresholds
     * @param thresholds Lists of thresholds be set for each token
     */
    function _setCustomTokenThresholds(address[] memory tokens, Threshold[] memory thresholds) internal {
        require(tokens.length == thresholds.length, 'TOKEN_THRESHOLDS_INPUT_INV_LEN');
        for (uint256 i = 0; i < tokens.length; i++) {
            _setCustomTokenThreshold(tokens[i], thresholds[i]);
        }
    }

    /**
     * @dev Sets a custom of tokens thresholds
     * @param token Address of the token to set a custom threshold for
     * @param threshold Thresholds be set. Threshold token cannot be zero and max amount must be greater than or
     * equal to the min amount, with the exception of max being set to zero in which case it will be ignored.
     */
    function _setCustomTokenThreshold(address token, Threshold memory threshold) internal {
        require(token != address(0), 'THRESHOLD_TOKEN_ADDRESS_ZERO');
        _validateThreshold(threshold);

        _customThresholds.thresholds[token] = threshold;
        _customThresholds.tokens.add(token);
        emit CustomTokenThresholdSet(token, threshold);
    }

    /**
     * @dev Unsets a list of custom threshold tokens, it ignores nonexistent custom thresholds
     * @param tokens List of token addresses to unset its custom thresholds
     */
    function _unsetCustomTokenThresholds(address[] memory tokens) internal {
        for (uint256 i = 0; i < tokens.length; i++) {
            address token = tokens[i];
            delete _customThresholds.thresholds[token];
            if (_customThresholds.tokens.remove(token)) emit CustomTokenThresholdUnset(token);
        }
    }

    /**
     * @dev Returns the token-threshold pair stored at position `i` in the map. Note that there are no guarantees on
     * the ordering of entries inside the array, and it may change when more entries are added or removed. O(1).
     * @param i Index to be accessed in the enumerable map, must be strictly less than its length
     */
    function _getTokenThresholdAt(uint256 i) private view returns (address, Threshold memory) {
        address token = _customThresholds.tokens.at(i);
        return (token, _customThresholds.thresholds[token]);
    }

    /**
     * @dev Reverts if a threshold is not considered valid, that is if the token is zero or if the max amount is greater
     * than zero but lower than the min amount.
     */
    function _validateThreshold(Threshold memory threshold) private pure {
        require(threshold.token != address(0), 'INVALID_THRESHOLD_TOKEN_ZERO');
        require(threshold.max == 0 || threshold.max >= threshold.min, 'INVALID_THRESHOLD_MAX_LT_MIN');
    }
}
[{"inputs":[{"components":[{"internalType":"address","name":"recipient","type":"address"},{"components":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"smartVault","type":"address"},{"internalType":"uint8","name":"groupId","type":"uint8"}],"internalType":"struct BaseAction.BaseConfig","name":"baseConfig","type":"tuple"},{"components":[{"internalType":"uint256","name":"gasPriceLimit","type":"uint256"},{"internalType":"uint256","name":"priorityFeeLimit","type":"uint256"},{"internalType":"uint256","name":"txCostLimit","type":"uint256"},{"internalType":"address","name":"gasToken","type":"address"},{"internalType":"bool","name":"permissiveMode","type":"bool"},{"internalType":"address[]","name":"relayers","type":"address[]"}],"internalType":"struct RelayedAction.RelayConfig","name":"relayConfig","type":"tuple"},{"components":[{"internalType":"address[]","name":"signers","type":"address[]"}],"internalType":"struct OracledAction.OracleConfig","name":"oracleConfig","type":"tuple"},{"components":[{"internalType":"uint256","name":"delay","type":"uint256"},{"internalType":"uint256","name":"nextExecutionTimestamp","type":"uint256"}],"internalType":"struct TimeLockedAction.TimeLockConfig","name":"timeLockConfig","type":"tuple"},{"components":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"address[]","name":"sources","type":"address[]"},{"internalType":"enum ITokenIndexedAction.TokensAcceptanceType","name":"acceptanceType","type":"uint8"}],"internalType":"struct TokenIndexedAction.TokenIndexConfig","name":"tokenIndexConfig","type":"tuple"},{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"internalType":"struct ITokenThresholdAction.Threshold","name":"defaultThreshold","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"internalType":"struct ITokenThresholdAction.Threshold","name":"threshold","type":"tuple"}],"internalType":"struct TokenThresholdAction.CustomThreshold[]","name":"customThresholds","type":"tuple[]"}],"internalType":"struct TokenThresholdAction.TokenThresholdConfig","name":"tokenThresholdConfig","type":"tuple"}],"internalType":"struct Action.ActionConfig","name":"actionConfig","type":"tuple"}],"internalType":"struct Withdrawer.WithdrawerConfig","name":"config","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"who","type":"address"},{"indexed":false,"internalType":"bytes4","name":"what","type":"bytes4"}],"name":"Authorized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"indexed":false,"internalType":"struct ITokenThresholdAction.Threshold","name":"threshold","type":"tuple"}],"name":"CustomTokenThresholdSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"}],"name":"CustomTokenThresholdUnset","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"indexed":false,"internalType":"struct ITokenThresholdAction.Threshold","name":"threshold","type":"tuple"}],"name":"DefaultTokenThresholdSet","type":"event"},{"anonymous":false,"inputs":[],"name":"DefaultTokenThresholdUnset","type":"event"},{"anonymous":false,"inputs":[],"name":"Executed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"groupId","type":"uint8"}],"name":"GroupIdSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"signer","type":"address"}],"name":"OracleSignerAllowed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"signer","type":"address"}],"name":"OracleSignerDisallowed","type":"event"},{"anonymous":false,"inputs":[],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"}],"name":"RecipientSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"gasPriceLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"priorityFeeLimit","type":"uint256"}],"name":"RelayGasLimitsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"}],"name":"RelayGasTokenSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"active","type":"bool"}],"name":"RelayPermissiveModeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"txCostLimit","type":"uint256"}],"name":"RelayTxCostLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"RelayerAllowed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"RelayerDisallowed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"delay","type":"uint256"}],"name":"TimeLockDelaySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"expiration","type":"uint256"}],"name":"TimeLockExpirationSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"source","type":"address"}],"name":"TokenIndexSourceAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"source","type":"address"}],"name":"TokenIndexSourceRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"}],"name":"TokensAcceptanceAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"}],"name":"TokensAcceptanceRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum ITokenIndexedAction.TokensAcceptanceType","name":"acceptanceType","type":"uint8"}],"name":"TokensAcceptanceTypeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"who","type":"address"},{"indexed":false,"internalType":"bytes4","name":"what","type":"bytes4"}],"name":"Unauthorized","type":"event"},{"anonymous":false,"inputs":[],"name":"Unpaused","type":"event"},{"inputs":[],"name":"ANY_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BASE_GAS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"},{"internalType":"bytes4","name":"what","type":"bytes4"}],"name":"authorize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"call","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getActionBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getCustomTokenThreshold","outputs":[{"internalType":"bool","name":"exists","type":"bool"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"internalType":"struct ITokenThresholdAction.Threshold","name":"threshold","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCustomTokenThresholds","outputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"internalType":"struct ITokenThresholdAction.Threshold[]","name":"thresholds","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDefaultTokenThreshold","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"internalType":"struct ITokenThresholdAction.Threshold","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"base","type":"address"},{"internalType":"address","name":"quote","type":"address"},{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IOracledAction.FeedData[]","name":"feeds","type":"tuple[]"}],"name":"getFeedsDigest","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getGroupId","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOracleSigners","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRelayGasLimits","outputs":[{"internalType":"uint256","name":"gasPriceLimit","type":"uint256"},{"internalType":"uint256","name":"priorityFeeLimit","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRelayGasToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRelayTxCostLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRelayers","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getSmartVaultBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTimeLock","outputs":[{"internalType":"uint256","name":"delay","type":"uint256"},{"internalType":"uint256","name":"expiresAt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTokensAcceptanceList","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTokensAcceptanceType","outputs":[{"internalType":"enum ITokenIndexedAction.TokensAcceptanceType","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTokensIndexSources","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getTotalBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"},{"internalType":"bytes4","name":"what","type":"bytes4"}],"name":"isAuthorized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"signer","type":"address"}],"name":"isOracleSigner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isRelayPermissiveModeActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"relayer","type":"address"}],"name":"isRelayer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isTimeLockExpired","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"isTokenAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"internalType":"struct ITokenThresholdAction.Threshold[]","name":"thresholds","type":"tuple[]"}],"name":"setCustomTokenThresholds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"internalType":"struct ITokenThresholdAction.Threshold","name":"threshold","type":"tuple"}],"name":"setDefaultTokenThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"groupId","type":"uint8"}],"name":"setGroupId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"toAdd","type":"address[]"},{"internalType":"address[]","name":"toRemove","type":"address[]"}],"name":"setOracleSigners","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"setRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"gasPriceLimit","type":"uint256"},{"internalType":"uint256","name":"priorityFeeLimit","type":"uint256"}],"name":"setRelayGasLimits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"setRelayGasToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"active","type":"bool"}],"name":"setRelayPermissiveMode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"txCostLimit","type":"uint256"}],"name":"setRelayTxCostLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"relayersToAdd","type":"address[]"},{"internalType":"address[]","name":"relayersToRemove","type":"address[]"}],"name":"setRelayers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"delay","type":"uint256"}],"name":"setTimeLockDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"setTimeLockExpiration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"toAdd","type":"address[]"},{"internalType":"address[]","name":"toRemove","type":"address[]"}],"name":"setTokensAcceptanceList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum ITokenIndexedAction.TokensAcceptanceType","name":"acceptanceType","type":"uint8"}],"name":"setTokensAcceptanceType","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"toAdd","type":"address[]"},{"internalType":"address[]","name":"toRemove","type":"address[]"}],"name":"setTokensIndexSources","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"smartVault","outputs":[{"internalType":"contract ISmartVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferToSmartVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"},{"internalType":"bytes4","name":"what","type":"bytes4"}],"name":"unauthorize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"}],"name":"unsetCustomTokenThresholds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unsetDefaultTokenThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]