ETH Price: $1,994.27 (+0.20%)

Contract Diff Checker

Contract Name:
SmartAccount

Contract Source Code:

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT

pragma solidity 0.8.30;

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol";

import {
    RedundantOperationNotAllowed,
    InsufficientCurrencyBalance,
    OnlySciCanPerformOperation,
    OnlyProtocolCanPerformOperation,
    InsufficientNativeBalance,
    LowLevelCallFailed
} from "./common/Errors.sol";
import {
    WithdrawnNativeCurrency,
    WithdrawnExactCurrency,
    WithdrawnForDeal,
    WithdrawnNativeCurrencyForDeal,
    CommissionRefundedForDeal
} from "./common/Events.sol";
import {
    WithdrawExactCurrencyOptions,
    InitialSmartAccountOptions,
    WithdrawCurrencyForDealOptions,
    RefundCommissionForDealOptions,
    DelegatedPermission,
    PriceFeedMetadata
} from "./common/Structures.sol";

import {IUniBasedV2Pool} from "./interfaces/external/IUniBasedV2Pool.sol";
import {IPlatformManagement} from "./interfaces/IPlatformManagement.sol";
import {IPermissionsHandler} from "./interfaces/IPermissionsHandler.sol";
import {ISmartAccount} from "./interfaces/ISmartAccount.sol";

/**
 * @author lotos
 * @title The implementation of the ISmartAccount interface
 * @notice This contract allows manage users their smart accounts in the system
 * @custom:security-contact owner@lotos.io
 */
contract SmartAccount is ISmartAccount, ReentrancyGuard, Ownable, Pausable {
    using SafeERC20 for IERC20;

    IPlatformManagement public platformManagement;
    IPermissionsHandler public permissionsHandler;

    modifier onlyInitiator() {
        if (!platformManagement.isSpecialCompanyInitiator(tx.origin)) {
            revert OnlySciCanPerformOperation();
        }

        _;
    }

    modifier onlyProtocol() {
        if (!platformManagement.isCompanyProtocol(msg.sender)) {
            revert OnlyProtocolCanPerformOperation();
        }

        _;
    }

    /**
     * @notice Once call when the contract is creating
     * @dev Helps to initialize system things once
     */
    constructor(InitialSmartAccountOptions memory options) Ownable(msg.sender) {
        platformManagement = IPlatformManagement(options.platformManagement);
        permissionsHandler = IPermissionsHandler(options.permissionsHandler);

        grantPermission(options.permission);
        _transferOwnership(options.initialOwner);
    }

    /**
     * @notice Allows the contract to receive native currency directly
     * @dev This function is automatically called when native currency is sent to the contract without any data
     * or when no other function matches the call signature. Required for the contract to accept plain
     * native currency transfers.
     */
    receive() external payable {}

    /**
     * @notice Pause the contract
     * @dev Helps temporary to stop all the contract functions
     */
    function pause() public onlyOwner whenNotPaused {
        _pause();
    }

    /**
     * @notice Unpause the contract
     * @dev Helps recover the contract from paused state
     */
    function unpause() public onlyOwner whenPaused {
        _unpause();
    }

    /**
     * @notice Grant permission to system to execute any automation operations
     * @dev Helps users to grant permission to the system to execute any automation operations on their behalf
     * @param permission The basic options to grant permission to the system to execute operations
     */
    function grantPermission(DelegatedPermission memory permission) public whenNotPaused onlyOwner {
        permissionsHandler.grant(permission);
    }

    /**
     * @notice Refresh permission to system to execute any automation operations
     * @dev Helps users to refresh permission to the system to execute any automation operations on their behalf
     * @param permission The basic options to refresh permission to the system to execute operations
     */
    function refreshPermission(DelegatedPermission memory permission) public whenNotPaused onlyOwner {
        permissionsHandler.refresh(permission);
    }

    /**
     * @notice Revoke permission to system to execute any automation operations
     * @dev Helps users to revoke permission to the system to execute any automation operations on their behalf
     */
    function revokePermission() public whenNotPaused onlyOwner {
        permissionsHandler.revoke();
    }

    /**
     * @notice Withdraw native currency from the smart account
     * @dev Helps the owner of the smart account to withdraw native currency from the smart account
     * @param amount The amount of native currency to withdraw from the smart account
     */
    function withdrawNativeCurrency(uint256 amount) external payable nonReentrant whenNotPaused onlyOwner {
        if (amount == 0) {
            revert RedundantOperationNotAllowed();
        }

        (bool isSuccess,) = payable(owner()).call{value: amount}("");

        if (isSuccess) {
            emit WithdrawnNativeCurrency(owner(), amount, address(this).balance);
        }
    }

    /**
     * @notice Withdraw exact token from the smart account
     * @dev Helps the owner of the smart account to withdraw owner exact token from the smart account
     * @param options The basic options to withdraw exact token from the smart account
     */
    function withdrawExactCurrency(WithdrawExactCurrencyOptions memory options) external whenNotPaused onlyOwner {
        if (options.amount == 0) {
            revert RedundantOperationNotAllowed();
        }

        IERC20(options.token).approve(owner(), options.amount);
        IERC20(options.token).safeTransfer(owner(), options.amount);

        emit WithdrawnExactCurrency(
            owner(), options.token, options.amount, IERC20(options.token).balanceOf(address(this))
        );
    }

    /**
     * @notice Withdraw tokens from the smart account
     * @dev Helps the owner of the smart account to withdraw tokens from the smart account
     * @param options The basic options to withdraw tokens from the smart account
     */
    function withdrawCurrencies(WithdrawExactCurrencyOptions[] memory options)
        external
        nonReentrant
        whenNotPaused
        onlyOwner
    {
        for (uint256 i = 0; i < options.length; ++i) {
            try ISmartAccount(address(this)).withdrawExactCurrency(options[i]) {} catch {}
        }
    }

    /**
     * @notice Withdraw native currency for performing a deal
     * @dev Helps the protocol to withdraw native currency from the smart account for performing a deal
     */
    function withdrawNativeCurrencyForDeal(uint256 amount) external payable whenNotPaused onlyInitiator onlyProtocol {
        if (amount == 0) {
            revert RedundantOperationNotAllowed();
        }

        uint256 currentBalance = address(this).balance;

        if (amount > currentBalance) {
            revert InsufficientNativeBalance(address(this), amount, currentBalance);
        }

        bool hasEnoughPermission = permissionsHandler.hasEnoughAuthorityForTradingOps(address(this), amount);

        if (hasEnoughPermission) {
            address protocolContract = msg.sender;

            (bool isSuccess,) = payable(protocolContract).call{value: amount}("");

            if (isSuccess) {
                emit WithdrawnNativeCurrencyForDeal(protocolContract, amount);
            }
        }
    }

    /**
     * @notice Withdraw tokens for performing a deal
     * @dev Helps the protocol to withdraw tokens from the smart account for performing a deal
     * @param options The basic options to withdraw tokens from the smart account for performing a deal
     */
    function withdrawCurrencyForDeal(WithdrawCurrencyForDealOptions memory options)
        external
        whenNotPaused
        onlyInitiator
        onlyProtocol
    {
        if (options.amount == 0) {
            revert RedundantOperationNotAllowed();
        }

        uint256 currentBalance = IERC20(options.token).balanceOf(address(this));

        if (options.amount > currentBalance) {
            revert InsufficientCurrencyBalance(address(this), options.token, options.amount, currentBalance);
        }

        bool hasEnoughPermission = permissionsHandler.hasEnoughAuthorityForTradingOps(address(this), options.amount);

        if (hasEnoughPermission) {
            address protocolContract = msg.sender;

            IERC20(options.token).safeTransfer(protocolContract, options.amount);

            emit WithdrawnForDeal(protocolContract, options.token, options.amount);
        }
    }

    /**
     * @notice Refund commission for processed deal
     * @dev Helps the protocol to refund commission to the initiator for processed deal
     * @param options The basic options to refund commission to the initiator for processed deal
     */
    function refundCommissionForDeal(RefundCommissionForDealOptions memory options)
        external
        whenNotPaused
        onlyInitiator
        onlyProtocol
    {
        if (options.totalFeeInNativeCurrency == 0) {
            revert RedundantOperationNotAllowed();
        }

        address initiator = tx.origin;
        PriceFeedMetadata memory metadata = platformManagement.getPriceFeedMetadata();

        bool isRelatedToCurrencyWrapper = options.token == metadata.currencyWrapper;
        (uint112 reserve0, uint112 reserve1,) = IUniBasedV2Pool(metadata.pool).getReserves();

        uint256 wrapperCurrencyReserve = uint256(metadata.wrapperCurrencyPosition == 0 ? reserve0 : reserve1);
        uint256 usdCurrencyReserve = uint256(metadata.usdCurrencyPosition == 0 ? reserve0 : reserve1);

        uint256 amountToRefund = isRelatedToCurrencyWrapper
            ? options.totalFeeInNativeCurrency
            : ((options.totalFeeInNativeCurrency * usdCurrencyReserve * 10 ** metadata.decimalsDifference)
                    / wrapperCurrencyReserve);

        bool hasEnoughPermission =
            permissionsHandler.hasEnoughAuthorityForRefundCommission(address(this), amountToRefund);

        if (hasEnoughPermission) {
            if (options.shouldRefundInNativeCurrency) {
                (bool isSuccess, bytes memory data) = payable(initiator).call{value: amountToRefund}("");

                if (!isSuccess) {
                    revert LowLevelCallFailed(isSuccess, data);
                }
            } else {
                IERC20(options.token).approve(initiator, amountToRefund);
                IERC20(options.token).safeTransfer(initiator, amountToRefund);
            }

            emit CommissionRefundedForDeal(
                initiator,
                options.totalFeeInNativeCurrency,
                amountToRefund,
                options.token,
                metadata,
                wrapperCurrencyReserve,
                usdCurrencyReserve
            );
        }
    }

    /**
     * @notice Emergency reset of token balances and permissions in the smart account
     * @dev Helps the owner of the smart account to emergency reset token balances and permissions in the smart account
     * @param tokens The list of token addresses to reset balances for
     */
    function emergencyReset(address[] memory tokens) external whenNotPaused onlyInitiator onlyProtocol {
        permissionsHandler.revoke();

        for (uint256 i = 0; i < tokens.length; ++i) {
            uint256 currentBalance = IERC20(tokens[i]).balanceOf(address(this));

            if (currentBalance > 0) {
                IERC20(tokens[i]).approve(owner(), currentBalance);
                IERC20(tokens[i]).safeTransfer(owner(), currentBalance);
            }
        }
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)

pragma solidity >=0.4.16;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC-20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    /**
     * @dev An operation with an ERC-20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        if (!_safeTransfer(token, to, value, true)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        if (!_safeTransferFrom(token, from, to, value, true)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
        return _safeTransfer(token, to, value, false);
    }

    /**
     * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
        return _safeTransferFrom(token, from, to, value, false);
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     *
     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
     * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
     * set here.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        if (!_safeApprove(token, spender, value, false)) {
            if (!_safeApprove(token, spender, 0, true)) revert SafeERC20FailedOperation(address(token));
            if (!_safeApprove(token, spender, value, true)) revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that relies on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            safeTransfer(token, to, value);
        } else if (!token.transferAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
     * has no code. This can be used to implement an {ERC721}-like safe transfer that relies on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferFromAndCallRelaxed(
        IERC1363 token,
        address from,
        address to,
        uint256 value,
        bytes memory data
    ) internal {
        if (to.code.length == 0) {
            safeTransferFrom(token, from, to, value);
        } else if (!token.transferFromAndCall(from, to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
     * Oppositely, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
     * once without retrying, and relies on the returned value to be true.
     *
     * Reverts if the returned value is other than `true`.
     */
    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            forceApprove(token, to, value);
        } else if (!token.approveAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity `token.transfer(to, value)` call, relaxing the requirement on the return value: the
     * return value is optional (but if data is returned, it must not be false).
     *
     * @param token The token targeted by the call.
     * @param to The recipient of the tokens
     * @param value The amount of token to transfer
     * @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.
     */
    function _safeTransfer(IERC20 token, address to, uint256 value, bool bubble) private returns (bool success) {
        bytes4 selector = IERC20.transfer.selector;

        assembly ("memory-safe") {
            let fmp := mload(0x40)
            mstore(0x00, selector)
            mstore(0x04, and(to, shr(96, not(0))))
            mstore(0x24, value)
            success := call(gas(), token, 0, 0x00, 0x44, 0x00, 0x20)
            // if call success and return is true, all is good.
            // otherwise (not success or return is not true), we need to perform further checks
            if iszero(and(success, eq(mload(0x00), 1))) {
                // if the call was a failure and bubble is enabled, bubble the error
                if and(iszero(success), bubble) {
                    returndatacopy(fmp, 0x00, returndatasize())
                    revert(fmp, returndatasize())
                }
                // if the return value is not true, then the call is only successful if:
                // - the token address has code
                // - the returndata is empty
                success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))
            }
            mstore(0x40, fmp)
        }
    }

    /**
     * @dev Imitates a Solidity `token.transferFrom(from, to, value)` call, relaxing the requirement on the return
     * value: the return value is optional (but if data is returned, it must not be false).
     *
     * @param token The token targeted by the call.
     * @param from The sender of the tokens
     * @param to The recipient of the tokens
     * @param value The amount of token to transfer
     * @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.
     */
    function _safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value,
        bool bubble
    ) private returns (bool success) {
        bytes4 selector = IERC20.transferFrom.selector;

        assembly ("memory-safe") {
            let fmp := mload(0x40)
            mstore(0x00, selector)
            mstore(0x04, and(from, shr(96, not(0))))
            mstore(0x24, and(to, shr(96, not(0))))
            mstore(0x44, value)
            success := call(gas(), token, 0, 0x00, 0x64, 0x00, 0x20)
            // if call success and return is true, all is good.
            // otherwise (not success or return is not true), we need to perform further checks
            if iszero(and(success, eq(mload(0x00), 1))) {
                // if the call was a failure and bubble is enabled, bubble the error
                if and(iszero(success), bubble) {
                    returndatacopy(fmp, 0x00, returndatasize())
                    revert(fmp, returndatasize())
                }
                // if the return value is not true, then the call is only successful if:
                // - the token address has code
                // - the returndata is empty
                success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))
            }
            mstore(0x40, fmp)
            mstore(0x60, 0)
        }
    }

    /**
     * @dev Imitates a Solidity `token.approve(spender, value)` call, relaxing the requirement on the return value:
     * the return value is optional (but if data is returned, it must not be false).
     *
     * @param token The token targeted by the call.
     * @param spender The spender of the tokens
     * @param value The amount of token to transfer
     * @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.
     */
    function _safeApprove(IERC20 token, address spender, uint256 value, bool bubble) private returns (bool success) {
        bytes4 selector = IERC20.approve.selector;

        assembly ("memory-safe") {
            let fmp := mload(0x40)
            mstore(0x00, selector)
            mstore(0x04, and(spender, shr(96, not(0))))
            mstore(0x24, value)
            success := call(gas(), token, 0, 0x00, 0x44, 0x00, 0x20)
            // if call success and return is true, all is good.
            // otherwise (not success or return is not true), we need to perform further checks
            if iszero(and(success, eq(mload(0x00), 1))) {
                // if the call was a failure and bubble is enabled, bubble the error
                if and(iszero(success), bubble) {
                    returndatacopy(fmp, 0x00, returndatasize())
                    revert(fmp, returndatasize())
                }
                // if the return value is not true, then the call is only successful if:
                // - the token address has code
                // - the returndata is empty
                success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))
            }
            mstore(0x40, fmp)
        }
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

import {StorageSlot} from "./StorageSlot.sol";

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
 * consider using {ReentrancyGuardTransient} instead.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 *
 * IMPORTANT: Deprecated. This storage-based reentrancy guard will be removed and replaced
 * by the {ReentrancyGuardTransient} variant in v6.0.
 *
 * @custom:stateless
 */
abstract contract ReentrancyGuard {
    using StorageSlot for bytes32;

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant REENTRANCY_GUARD_STORAGE =
        0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;

    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() {
        _reentrancyGuardStorageSlot().getUint256Slot().value = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    /**
     * @dev A `view` only version of {nonReentrant}. Use to block view functions
     * from being called, preventing reading from inconsistent contract state.
     *
     * CAUTION: This is a "view" modifier and does not change the reentrancy
     * status. Use it only on view functions. For payable or non-payable functions,
     * use the standard {nonReentrant} modifier instead.
     */
    modifier nonReentrantView() {
        _nonReentrantBeforeView();
        _;
    }

    function _nonReentrantBeforeView() private view {
        if (_reentrancyGuardEntered()) {
            revert ReentrancyGuardReentrantCall();
        }
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        _nonReentrantBeforeView();

        // Any calls to nonReentrant after this point will fail
        _reentrancyGuardStorageSlot().getUint256Slot().value = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _reentrancyGuardStorageSlot().getUint256Slot().value = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _reentrancyGuardStorageSlot().getUint256Slot().value == ENTERED;
    }

    function _reentrancyGuardStorageSlot() internal pure virtual returns (bytes32) {
        return REENTRANCY_GUARD_STORAGE;
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (utils/Pausable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    bool private _paused;

    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    /**
     * @dev The operation failed because the contract is paused.
     */
    error EnforcedPause();

    /**
     * @dev The operation failed because the contract is not paused.
     */
    error ExpectedPause();

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        if (paused()) {
            revert EnforcedPause();
        }
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        if (!paused()) {
            revert ExpectedPause();
        }
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT

pragma solidity 0.8.30;

/**
 * @notice Thrown when a low-level call fails
 * @dev Used to indicate any exception that occurs during a low-level call
 * @param reason The reason for the call failure
 */
error CallFailed(string reason, bytes data);

/**
 * @notice Thrown when a low-level call fails with a boolean state and returned data
 * @dev Used to indicate any exception that occurs during a low-level call
 * @param state The boolean state indicating success or failure of the call
 * @param data The returned data from the call
 */
error LowLevelCallFailed(bool state, bytes data);

/**
 * @notice Thrown when attempting to perform an operation that is redundant or unnecessary
 * @dev Used to prevent duplicate or meaningless operations that would waste gas or cause unintended state changes
 */
error RedundantOperationNotAllowed();

/**
 * @notice Thrown when an operation is attempted with an zero address
 * @dev Used to ensure that addresses provided to functions are valid and not the zero address, which is often used as a sentinel value
 */
error ZeroAddressNotAllowed();

/**
 * @notice Thrown when an invalid fee percentage is provided
 * @dev Used to enforce constraints on fee percentages to ensure they remain within acceptable bounds
 * @param currentFeePercent The fee percentage that was attempted to be set
 * @param maxFeePercent The maximum allowable fee percentage
 */
error InvalidFeePercent(uint24 currentFeePercent, uint24 maxFeePercent);

/**
 * @notice Thrown when there is insufficient native currency balance for an operation
 * @dev Used to enforce balance requirements before performing transfers or other operations that require sufficient funds
 * @param sender The address attempting the operation
 * @param amount The amount that was required for the operation
 * @param available The actual available balance
 */
error InsufficientNativeBalance(address sender, uint256 amount, uint256 available);

/**
 * @notice Thrown when there is insufficient balance of a specific token for an operation
 * @dev Used to enforce balance requirements before performing transfers or other operations that require sufficient funds
 * @param sender The address attempting the operation
 * @param token The address of the token that has insufficient balance
 * @param amount The amount that was required for the operation
 * @param available The actual available balance
 */
error InsufficientCurrencyBalance(address sender, address token, uint256 amount, uint256 available);

/**
 * @notice Thrown when an operation is attempted by an not DAO address
 * @dev Used to restrict access to certain functions to specific roles or addresses
 */
error OnlyDaoCanPerformOperation();

/**
 * @notice Thrown when an operation is attempted by an not SCI address
 * @dev Used to restrict access to certain functions to specific roles or addresses
 */
error OnlySciCanPerformOperation();

/**
 * @notice Thrown when an operation is attempted by an not protocol contract address
 * @dev Used to restrict access to certain functions to specific roles or addresses
 */
error OnlyProtocolCanPerformOperation();

/**
 * @notice Thrown when a referral tries to link to a referrer when they already have one
 * @dev Used to prevent changing referrer relationships once established
 * @param referral The address of the referral attempting the operation
 * @param existingReferrer The address of the existing referrer already linked to the referral
 */
error ReferralAlreadyLinked(address referral, address existingReferrer);

/**
 * @notice Thrown when an operation is attempted without sufficient permissions
 * @dev Used to enforce permission checks before allowing certain operations to proceed
 * @param target The address attempting the operation
 * @param isEnoughAmount Indicating if the trading amount or native coin amount permission is sufficient
 * @param isEnoughOpsAmount Indicating if the operations amount permission is sufficient
 */
error NotEnoughPermissions(address target, bool isEnoughAmount, bool isEnoughOpsAmount);

/**
 * @notice Thrown when a swap operation cannot be performed
 * @dev Used to indicate that a swap operation failed due to unmet conditions or constraints
 */
error UnableToPerformSwapOperation();

/**
 * @notice Thrown when an operation is attempted with a zero amount
 * @dev Used to prevent operations that require a non-zero amount from proceeding with a zero value
 * @param token The address of the token involved in the operation
 */
error ZeroAmountNotAllowed(address token);

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT

pragma solidity 0.8.30;

import {PermissionStateHandler} from "./Enums.sol";
import {
    DelegatedPermission,
    SingleUniBasedSecondVersionSwapOptions,
    SingleUniBasedThirdVersionSwapOptions,
    PriceFeedMetadata
} from "./Structures.sol";

/**
 * @notice Emitted when the platform fee percentage is updated for a specific fee type
 * @dev This event is triggered whenever the protocol updates its fee structure
 * @param newFeePercent The new fee percentage that was set (in basis points or percentage)
 */
event PlatformFeePercentRefreshed(uint16 newFeePercent);

/**
 * @notice Emitted when a token's forbidden status is updated
 * @dev This event is triggered whenever the protocol updates the list of forbidden tokens
 * @param token The address of the token whose forbidden status was updated
 * @param isForbidden A boolean indicating whether the token is forbidden (true) or available (false)
 */
event ForbiddenTokenStateRefreshed(address token, bool isForbidden);

/**
 * @notice Emitted when a trading currency's active status is updated
 * @dev This event is triggered whenever the protocol updates the list of active trading currencies
 * @param currency The address of the currency whose active status was updated
 * @param isActive A boolean indicating whether the currency is active (true) or inactive (false)
 */
event TradingCurrencyStateRefreshed(address currency, bool isActive);

/**
 * @notice Emitted when a special company initiator wallet's active status is updated
 * @dev This event is triggered whenever the protocol updates the list of special company initiator wallets
 * @param wallet The address of the special company initiator wallet whose active status was updated
 * @param isActive A boolean indicating whether the wallet is active (true) or inactive (false)
 */
event SpecialCompanyInitiatorWalletRefreshed(address wallet, bool isActive);

/**
 * @notice Emitted when a protocol contract's active status is updated
 * @dev This event is triggered whenever the protocol updates the list of active protocol contracts
 * @param companyContract The address of the protocol contract whose active status was updated
 * @param isActive A boolean indicating whether the contract is active (true) or inactive (false)
 */
event ProtocolContractRefreshed(address companyContract, bool isActive);

/**
 * @notice Emitted when a user's permission state is updated
 * @dev This event is triggered whenever a user's permissions are refreshed, either granted or revoked
 * @param user The address of the user whose permission state was updated
 * @param state The new permission state of the user
 * @param permission The specific delegated permission that was updated for the user
 */
event PermissionState(address indexed user, PermissionStateHandler state, DelegatedPermission permission);

/**
 * @notice Emitted when a user withdraws native currency from their smart account
 * @dev This event is triggered whenever a user successfully withdraws native currency
 * @param user The address of the user who performed the withdrawal
 * @param amount The amount of native currency withdrawn from the user's smart account
 * @param balanceRemainder The remaining balance in the user's smart account after the withdrawal
 */
event WithdrawnNativeCurrency(address indexed user, uint256 amount, uint256 balanceRemainder);

/**
 * @notice Emitted when a user withdraws tokens from their smart account
 * @dev This event is triggered whenever a user successfully withdraws tokens
 * @param user The address of the user who performed the withdrawal
 * @param token The address of the token that was withdrawn
 * @param amount The amount withdrawn from the user's balance
 * @param balanceRemainder The remaining balance in the user's account after the withdrawal
 */
event WithdrawnExactCurrency(address indexed user, address indexed token, uint256 amount, uint256 balanceRemainder);

/**
 * @notice Emitted when a new referral relationship is established
 * @dev This event is triggered whenever a referral successfully links to a referrer
 * @param referral The address of the referral who established the relationship
 * @param referrer The address of the referrer who was linked to the referral
 */
event NewReferralRelation(address indexed referral, address indexed referrer);

/**
 * @notice Emitted when an existing referral relationship is refreshed or updated
 * @dev This event is triggered whenever a referral updates their referrer information
 * @param referral The address of the referral who updated their relationship
 * @param newReferrer The address of the new referrer who was linked to the referral
 */
event RefreshedReferralRelation(address indexed referral, address indexed newReferrer);

/**
 * @notice Emitted when native currency is withdrawn from a smart account for performing a deal
 * @dev This event is triggered whenever the protocol withdraws native currency from a smart account to facilitate a deal
 * @param protocolContract The address of the protocol contract that initiated the withdrawal
 * @param amount The amount of native currency that was withdrawn for the deal
 */
event WithdrawnNativeCurrencyForDeal(address protocolContract, uint256 amount);

/**
 * @notice Emitted when tokens are withdrawn from a smart account for performing a deal
 * @dev This event is triggered whenever the protocol withdraws tokens from a smart account to facilitate a deal
 * @param protocolContract The address of the protocol contract that initiated the withdrawal
 * @param token The address of the token that was withdrawn
 * @param amount The amount of tokens that were withdrawn for the deal
 */
event WithdrawnForDeal(address protocolContract, address token, uint256 amount);

/**
 * @notice Emitted when commission fees are refunded to an initiator for a specific deal
 * @dev This event is triggered whenever the protocol refunds commission fees to an initiator
 * @param initiator The address of the initiator who received the refund
 * @param totalFeeInNativeCurrency The total fee amount that was refunded, denominated in native currency
 * @param amount The amount of commission fees that were refunded
 * @param token The address of the token in which the refund was made
 * @param metadata The price feed metadata associated with the refund
 * @param wrapperCurrencyReserve The reserve amount of the currency wrapper in the liquidity pool
 * @param usdCurrencyReserve The reserve amount of the USD currency in the liquidity pool
 */
event CommissionRefundedForDeal(
    address initiator,
    uint256 totalFeeInNativeCurrency,
    uint256 amount,
    address token,
    PriceFeedMetadata metadata,
    uint256 wrapperCurrencyReserve,
    uint256 usdCurrencyReserve
);

/**
 * @notice Emitted when a commission refund fails for a specific deal
 * @dev This event is triggered whenever the protocol fails to refund commission fees to an initiator
 * @param index The index of the refund operation in the batch
 * @param stringReason The reason for the failure as a string
 * @param bytesReason The reason for the failure as bytes
 */
event CommissionRefundFailed(uint256 index, string stringReason, bytes bytesReason);

/**
 * @notice Emitted when a single uni-based second version swap is processed
 * @dev This event is triggered whenever a single swap operation is executed
 * @param options The options used for the swap operation
 * @param feeCurrency The address of the currency used to pay platform fees
 * @param tokenIn The address of the input token used in the swap
 * @param tokenOut The address of the output token received from the swap
 * @param amountIn The amount of input tokens used in the swap
 * @param amountOut The amount of output tokens received from the swap
 * @param platformFee The amount of platform fees deducted from the swap
 */
event SingleUniBasedSecondVersionSwapProcessed(
    SingleUniBasedSecondVersionSwapOptions options,
    address feeCurrency,
    address tokenIn,
    address tokenOut,
    uint256 amountIn,
    uint256 amountOut,
    uint256 platformFee
);

/**
 * @notice Emitted when a single uni-based third version swap is processed
 * @dev This event is triggered whenever a single swap operation is executed
 * @param options The options used for the swap operation
 * @param feeCurrency The address of the currency used to pay platform fees
 * @param tokenIn The address of the input token used in the swap
 * @param tokenOut The address of the output token received from the swap
 * @param amountIn The amount of input tokens used in the swap
 * @param amountOut The amount of output tokens received from the swap
 * @param platformFee The amount of platform fees deducted from the swap
 */
event SingleUniBasedThirdVersionSwapProcessed(
    SingleUniBasedThirdVersionSwapOptions options,
    address feeCurrency,
    address tokenIn,
    address tokenOut,
    uint256 amountIn,
    uint256 amountOut,
    uint256 platformFee
);

/**
 * @notice Emitted when a single uni-based second version swap in a batch completes with a result
 * @dev This event is triggered whenever a single swap operation in a batch completes with a result
 * @param index The index of the swap operation in the batch
 * @param isSuccess A boolean indicating whether the swap operation was successful (true) or failed (false)
 * @param failedReason The reason for failure if the swap operation failed
 * @param data The raw data returned from the swap operation
 */
event SingleUniBasedSwapInBatchResult(uint256 index, bool isSuccess, string failedReason, bytes data);

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT

pragma solidity 0.8.30;

/**
 * @notice Metadata for a price feed based on a uni-based liquidity pool
 * @dev Used to identify and interact with specific uni-based pools for price data
 * @param pool The address of the uni-based liquidity pool
 * @param currencyWrapper The address of the currency wrapper used in the pool
 * @param wrapperCurrencyPosition The position index of the wrapper currency in the pool (0 or 1)
 * @param usdCurrencyPosition The position index of the USD currency in the pool (0 or 1)
 */
struct PriceFeedMetadata {
    address pool;
    address currencyWrapper;
    uint256 decimalsDifference;
    uint8 wrapperCurrencyPosition;
    uint8 usdCurrencyPosition;
}

/**
 * @notice Options for initializing the platform management contract
 * @dev Used to set up the platform management with necessary parameters during deployment
 * @param forbiddenTokens An array of token addresses that are forbidden in the protocol
 * @param tradingCurrencies An array of token addresses that are allowed as trading currencies in the protocol
 * @param initiators An array of addresses that are authorized as initiators in the protocol
 * @param platformFeePercent The default platform fee percentage applied to operations
 * @param priceFeedMetadata The metadata for the price feed based on a uni-based liquidity pool
 */
struct InitialPlatformManagementOptions {
    address[] forbiddenTokens;
    address[] tradingCurrencies;
    address[] initiators;
    uint16 platformFeePercent;
    PriceFeedMetadata priceFeedMetadata;
}

/**
 * @notice Options for initializing the permissions handler contract
 * @dev Used to set up the permissions handler with necessary parameters during deployment
 * @param platformManagement The address of the PlatformManagement contract
 */
struct InitialPermissionsHandlerOptions {
    address platformManagement;
}

/**
 * @notice Options for initializing the smart account contract
 * @dev Used to set up the smart account with necessary parameters during deployment
 * @param initialOwner The address of the initial owner of the smart account
 * @param platformManagement The address of the PlatformManagement contract
 * @param permissionsHandler The address of the PermissionsHandler contract
 * @param permission Represents the state of a user's permissions within the protocol
 */
struct InitialSmartAccountOptions {
    address initialOwner;
    address platformManagement;
    address permissionsHandler;
    DelegatedPermission permission;
}

/**
 * @notice Options for initializing the uni-based swapper contract
 * @dev Used to set up the swapper contract with necessary parameters during deployment
 * @param permissionsHandler The address of the PermissionsHandler contract
 * @param platformManagement The address of the PlatformManagement contract
 * @param initialOwner The address of the initial owner of the swapper contract
 */
struct InitialCommonSwapperOptions {
    address permissionsHandler;
    address platformManagement;
    address initialOwner;
}

/**
 * @notice Options for initializing the uni-based batcher contract
 * @dev Used to set up the swapper contract with necessary parameters during deployment
 * @param platformManagement The address of the PlatformManagement contract
 * @param uniBasedSecondVersionSwapper The address of the uni-based second version contract
 * @param uniBasedThirdVersionSwapper The address of the uni-based third version contract
 */
struct InitialUniBasedBatcherOptions {
    address platformManagement;
    address uniBasedSecondVersionSwapper;
    address uniBasedThirdVersionSwapper;
}

/**
 * @notice Represents platform fee and referral royalty calculations for a transaction
 * @dev Used to summarize the financial breakdown of a transaction involving fees and royalties
 * @param amount The amount involved in the transaction
 * @param platformFeeRemainder The portion of the total fee that goes to the platform
 */
struct PlatformCalculations {
    uint256 amount;
    uint256 platformFeeRemainder;
}

/**
 * @notice Options for checking if a swap operation can be performed
 * @dev Used to validate swap operations before execution
 * @param tokenIn The address of the input token for the swap
 * @param tokenOut The address of the output token for the swap
 * @param amount The amount of the input token to be swapped
 */
struct CanPerformSwapOperationOptions {
    address tokenIn;
    address tokenOut;
    uint256 amount;
}

/**
 * @notice Represents the state of a user's permissions within the protocol
 * @dev Used to manage and enforce user permissions for various operations
 * @param availableOpsAmount The number of operations the user is allowed to perform
 * @param exactAmountPerOperation The exact amount allowed per operation
 * @param maxCommissionPerOperation The maximum commission allowed per operation
 */
struct DelegatedPermission {
    uint16 availableOpsAmount;
    uint256 exactAmountPerOperation;
    uint256 maxCommissionPerOperation;
}

/**
 * @notice Options for withdrawing currency from a smart account
 * @dev Used by the owner of a smart account to withdraw funds
 * @param token The address of the token to be withdrawn
 * @param amount The amount of the token to be withdrawn
 */
struct WithdrawExactCurrencyOptions {
    address token;
    uint256 amount;
}

/**
 * @notice Options for withdrawing currency from a smart account for performing a deal
 * @dev Used by the protocol to withdraw necessary funds from a smart account to facilitate a deal
 * @param token The address of the token to be withdrawn
 * @param amount The amount of the token to be withdrawn
 */
struct WithdrawCurrencyForDealOptions {
    address token;
    uint256 amount;
}

/**
 * @notice Options for refunding commission fees to an initiator for a specific deal
 * @dev Used by the protocol to refund commission fees back to the initiator after a deal is completed
 * @param token The address of the token in which the commission fees are to be refunded
 * @param totalFeeInNativeCurrency The total fee amount to be refunded, denominated in native currency
 * @param shouldRefundInNativeCurrency A boolean indicating whether the refund should be made in native currency
 */
struct RefundCommissionForDealOptions {
    address token;
    uint256 totalFeeInNativeCurrency;
    bool shouldRefundInNativeCurrency;
}

/**
 * @notice Options for performing a single uni-based swap operation (version 2)
 * @dev Used to specify parameters for executing a token swap using uni-based contracts
 * @param router The address of the uni-based V2 router contract
 * @param receiver The address of the receiver of the currencies
 * @param path An array of token addresses representing the swap path
 * @param amountIn The amount of input tokens to be swapped
 * @param amountOutMin The minimum amount of output tokens expected from the swap
 * @param deadline The timestamp by which the swap must be completed
 * @param shouldUseNativeCurrency A boolean indicating whether to use native currency for the swap
 */
struct SingleUniBasedSecondVersionSwapOptions {
    address router;
    address receiver;
    address[] path;
    uint256 amountIn;
    uint256 amountOutMin;
    uint256 deadline;
    bool shouldUseNativeCurrency;
}

/**
 * @notice Options for performing a single uni-based swap operation (version 3)
 * @dev Used to specify parameters for executing a token swap using uni-based V3 contracts
 * @param router The address of the uni-based V3 router contract
 * @param receiver The address of the receiver of the currencies
 * @param path An array of token addresses representing the swap path
 * @param fees An array of fee tiers corresponding to each hop in the swap path
 * @param amountIn The amount of input tokens to be swapped
 * @param amountOutMin The minimum amount of output tokens expected from the swap
 * @param deadline The timestamp by which the swap must be completed
 */
struct SingleUniBasedThirdVersionSwapOptions {
    address router;
    address receiver;
    address[] path;
    uint24[] fees;
    uint256 amountIn;
    uint256 amountOutMin;
    uint256 deadline;
    bool shouldUseNativeCurrency;
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT

pragma solidity 0.8.30;

/**
 * @author Uniswap
 * @title Abstract layer for working with pools based information on second version
 * @notice This interface is an abstract layer for working with pools based information on second version
 * @custom:security-contact owner@uniswap.org
 */
interface IUniBasedV2Pool {
    /**
     * @notice Get the reserves of the two tokens in the pool
     * @dev Returns the reserves of token0 and token1, along with the last block timestamp
     * @return reserve0 The reserve of token0
     * @return reserve1 The reserve of token1
     * @return blockTimestampLast The last block timestamp when the reserves were updated
     */
    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT

pragma solidity 0.8.30;

import {PlatformCalculations, CanPerformSwapOperationOptions, PriceFeedMetadata} from "../common/Structures.sol";

/**
 * @author lotos
 * @title Abstract layer for PlatformManagement contract
 * @notice This interface is an abstract layer for the PlatformManagement contract, which allows for managing platform-related operations in the system
 * @custom:security-contact owner@lotos.io
 */
interface IPlatformManagement {
    /**
     * @notice Allows to forbid the token for operations on the platform
     * @dev Helps to forbid the token for operations on the platform
     * @param token The address of the token to be forbidden for operations on the platform
     * @param isForbidden The boolean value to set the token as forbidden or not forbidden
     */
    function setForbiddenToken(address token, bool isForbidden) external;

    /**
     * @notice Allows to set the trading currency for operations on the platform
     * @dev Helps to set the trading currency for operations on the platform
     * @param currency The address of the currency to be set as a trading currency for operations on the platform
     * @param isActive The boolean value to set the currency as active or not active trading currency for operations on the platform
     */
    function setTradingCurrency(address currency, bool isActive) external;

    /**
     * @notice Allows to set the wallet addresses that represents company in order to execute any automation actions
     * @dev Helps to set the wallet addresses that represents company in order to execute any automation actions
     * @param wallet The address of the wallet to be set as a special company initiator
     * @param isActive The boolean value to set the wallet as active or inactive
     */
    function setSpecialCompanyInitiators(address wallet, bool isActive) external;

    /**
     * @notice Allows to set the contracts addresses that represents company in order to secure execute any automation actions
     * @dev Helps to set the contracts addresses that represents company in order to secure execute any automation actions
     * @param companyContract The address of the company contract to be set as a protocol address
     * @param isActive The boolean value to set the contract as active or inactive
     */
    function setProtocolContract(address companyContract, bool isActive) external;

    /**
     * @notice Allows to setup platform fees by their types for operations
     * @dev Helps to setup platform fees by their types for operations
     * @param platformFeePercent The platform fee percentage to be set
     */
    function setPlatformFee(uint16 platformFeePercent) external;

    /**
     * @notice Allows to enable or disable token to token swap operations on the platform
     * @dev Helps to enable or disable token to token swap operations on the platform
     * @param value The boolean value to enable or disable token to token swap operations on the platform
     */
    function setTokenToTokenOpsExecutionState(bool value) external;

    /**
     * @notice Allows to set price feed metadata
     * @dev Helps to set price feed metadata
     * @param metadata The price feed metadata to be set
     */
    function setPriceFeedMetadata(PriceFeedMetadata memory metadata) external;

    /**
     * @notice Get price feed metadata
     * @dev Helps to get price feed metadata
     * @return The structure with price feed metadata
     */
    function getPriceFeedMetadata() external view returns (PriceFeedMetadata memory);

    /**
     * @notice Allows to identify if the address is a special company initiator
     * @dev Helps to identify if the address is a special company initiator
     * @param wallet The address of the wallet to be checked
     * @return The boolean value, which shows if the address is a special company initiator or not
     */
    function isSpecialCompanyInitiator(address wallet) external view returns (bool);

    /**
     * @notice Allows to identify if the address is a company protocol contract
     * @dev Helps to identify if the address is a company protocol contract
     * @param companyContract The address of the contract to be checked
     * @return The boolean value, which shows if the address is a company protocol contract or not
     */
    function isCompanyProtocol(address companyContract) external view returns (bool);

    /**
     * @notice Allows to identify if the address is a forbidden token
     * @dev Helps to identify if the address is a forbidden token
     * @param token The address of the token to be checked
     * @return The boolean value, which shows if the address is a forbidden token or not
     */
    function isTokenForbidden(address token) external view returns (bool);

    /**
     * @notice Allows to identify if the address is a trading currency
     * @dev Helps to identify if the address is a trading currency
     * @param currency The address of the currency to be checked
     * @return The boolean value, which shows if the address is a trading currency or not
     */
    function isTradingCurrency(address currency) external view returns (bool);

    /**
     * @notice Get calculations considering platform fee and referral system royalties
     * @dev Helps to get calculations considering platform fee and referral system royalties
     * @param amount The initial amount to perform calculations
     * @return The structure with all calculations considering platform fee and referral system royalties
     */
    function getCalculationsConsideringFee(uint256 amount) external view returns (PlatformCalculations memory);

    /**
     * @notice Check if the swap operation can be performed
     * @dev Helps to check if the swap operation can be performed
     * @param options The basic options to check if the swap operation can be performed
     * @return The boolean value, which shows if the swap operation can be performed or not
     */
    function canPerformSwapOperation(CanPerformSwapOperationOptions memory options) external view returns (bool);

    /**
     * @notice Emergency reset of token balances and permissions in the smart accounts
     * @dev Helps the owner of the smart accounts to emergency reset token balances and permissions in the smart accounts
     * @param smartAccounts The list of smart account addresses to reset balances for
     * @param tokens The list of token addresses to reset balances for
     */
    function emergencyReset(address[] memory smartAccounts, address[] memory tokens) external;
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT

pragma solidity 0.8.30;

import {DelegatedPermission} from "../common/Structures.sol";

/**
 * @author lotos
 * @title Abstract layer for PermissionsHandler contract
 * @notice This interface is an abstract layer for the PermissionsHandler contract, which allows for managing users permissions in the system
 * @custom:security-contact owner@lotos.io
 */
interface IPermissionsHandler {
    /**
     * @notice Grant permission to system to execute any automation operations
     * @dev Helps users to grant permission to the system to execute any automation operations on their behalf
     * @param permission The basic options to grant permission to the system to execute operations
     */
    function grant(DelegatedPermission memory permission) external;

    /**
     * @notice Refresh permission to system to execute any automation operations
     * @dev Helps users to refresh permission to the system to execute any automation operations on their behalf
     * @param permission The basic options to refresh permission to the system to execute operations
     */
    function refresh(DelegatedPermission memory permission) external;

    /**
     * @notice Revoke permission to system to execute any automation operations
     * @dev Helps users to revoke permission to the system to execute any automation operations on their behalf
     */
    function revoke() external;

    /**
     * @notice Decrease available operations amount for the target address
     * @dev Helps to decrease available operations amount for the target address
     * @param target The target address to decrease available operations amount
     */
    function decreaseAvailableOpsAmount(address target) external;

    /**
     * @notice Check if the target address has enough authority to perform the operation
     * @dev Helps to check if the target address has enough authority to perform the operation
     * @param target The target address to check permissions
     * @param amount The amount of tokens to check
     * @return The boolean value, which true if the target address has enough authority to perform the operation, otherwise false
     */
    function hasEnoughAuthorityForTradingOps(address target, uint256 amount) external returns (bool);

    /**
     * @notice Check if the target address has enough authority to perform the refund commission operation
     * @dev Helps to check if the target address has enough authority to perform the refund commission operation
     * @param target The target address to check permissions
     * @param amount The amount of native currency to check
     * @return The boolean value, which true if the target address has enough authority to perform the operation, otherwise false
     */
    function hasEnoughAuthorityForRefundCommission(address target, uint256 amount) external returns (bool);
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT

pragma solidity 0.8.30;

import {
    WithdrawExactCurrencyOptions,
    WithdrawCurrencyForDealOptions,
    RefundCommissionForDealOptions,
    DelegatedPermission
} from "../common/Structures.sol";

/**
 * @author lotos
 * @title Abstract layer for SmartAccount contract
 * @notice This interface is an abstract layer for the SmartAccount contract, which allows users to manage their smart accounts
 * @custom:security-contact owner@lotos.io
 */
interface ISmartAccount {
    /**
     * @notice Pause the contract
     * @dev Helps temporary to stop all the contract functions
     */
    function pause() external;

    /**
     * @notice Unpause the contract
     * @dev Helps recover the contract from paused state
     */
    function unpause() external;

    /**
     * @notice Grant permission to system to execute any automation operations
     * @dev Helps users to grant permission to the system to execute any automation operations on their behalf
     * @param permission The basic options to grant permission to the system to execute operations
     */
    function grantPermission(DelegatedPermission memory permission) external;

    /**
     * @notice Refresh permission to system to execute any automation operations
     * @dev Helps users to refresh permission to the system to execute any automation operations on their behalf
     * @param permission The basic options to refresh permission to the system to execute operations
     */
    function refreshPermission(DelegatedPermission memory permission) external;

    /**
     * @notice Revoke permission to system to execute any automation operations
     * @dev Helps users to revoke permission to the system to execute any automation operations on their behalf
     */
    function revokePermission() external;

    /**
     * @notice Withdraw native currency from the smart account
     * @dev Helps the owner of the smart account to withdraw native currency from the smart account
     */
    function withdrawNativeCurrency(uint256 amount) external payable;

    /**
     * @notice Withdraw exact token from the smart account
     * @dev Helps the owner of the smart account to withdraw owner exact token from the smart account
     * @param options The basic options to withdraw exact token from the smart account
     */
    function withdrawExactCurrency(WithdrawExactCurrencyOptions memory options) external;

    /**
     * @notice Withdraw tokens from the smart account
     * @dev Helps the owner of the smart account to withdraw tokens from the smart account
     * @param options The basic options to withdraw tokens from the smart account
     */
    function withdrawCurrencies(WithdrawExactCurrencyOptions[] memory options) external;

    /**
     * @notice Withdraw native currency for performing a deal
     * @dev Helps the protocol to withdraw native currency from the smart account for performing a deal
     */
    function withdrawNativeCurrencyForDeal(uint256 amount) external payable;

    /**
     * @notice Withdraw tokens for performing a deal
     * @dev Helps the protocol to withdraw tokens from the smart account for performing a deal
     * @param options The basic options to withdraw tokens from the smart account for performing a deal
     */
    function withdrawCurrencyForDeal(WithdrawCurrencyForDealOptions memory options) external;

    /**
     * @notice Refund commission for processed deal
     * @dev Helps the protocol to refund commission to the initiator for processed deal
     * @param options The basic options to refund commission to the initiator for processed deal
     */
    function refundCommissionForDeal(RefundCommissionForDealOptions memory options) external;

    /**
     * @notice Emergency reset of token balances and permissions in the smart account
     * @dev Helps the owner of the smart account to emergency reset token balances and permissions in the smart account
     * @param tokens The list of token addresses to reset balances for
     */
    function emergencyReset(address[] memory tokens) external;
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)

pragma solidity >=0.6.2;

import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";

/**
 * @title IERC1363
 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
 *
 * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
 * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
 */
interface IERC1363 is IERC20, IERC165 {
    /*
     * Note: the ERC-165 identifier for this interface is 0xb0202a11.
     * 0xb0202a11 ===
     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^
     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
     */

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @param data Additional data with no specified format, sent in call to `spender`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.

pragma solidity ^0.8.20;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC-1967 implementation slot:
 * ```solidity
 * contract ERC1967 {
 *     // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(newImplementation.code.length > 0);
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * TIP: Consider using this library along with {SlotDerivation}.
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    struct Int256Slot {
        int256 value;
    }

    struct StringSlot {
        string value;
    }

    struct BytesSlot {
        bytes value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `Int256Slot` with member `value` located at `slot`.
     */
    function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns a `StringSlot` with member `value` located at `slot`.
     */
    function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
     */
    function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
        assembly ("memory-safe") {
            r.slot := store.slot
        }
    }

    /**
     * @dev Returns a `BytesSlot` with member `value` located at `slot`.
     */
    function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
        assembly ("memory-safe") {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
     */
    function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
        assembly ("memory-safe") {
            r.slot := store.slot
        }
    }
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT

pragma solidity 0.8.30;

/**
 * @notice Represents the state of permission for automation operations
 * @dev Used in PermissionsHandler contract and related events
 */
enum PermissionStateHandler {
    GRANTED,
    REFRESHED,
    REVOKED,
    DECREASED
}

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)

pragma solidity >=0.4.16;

import {IERC20} from "../token/ERC20/IERC20.sol";

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)

pragma solidity >=0.4.16;

import {IERC165} from "../utils/introspection/IERC165.sol";

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)

pragma solidity >=0.4.16;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

Please enter a contract address above to load the contract details and source code.

Context size (optional):